forked from qt-creator/qt-creator
QmlDesigner: Fix deleting collections using the keyboard delete key
Fixes: QDS-11735 Change-Id: I188856918da6d478e16383017d808205ee20ee8c Reviewed-by: Qt CI Patch Build Bot <ci_patchbuild_bot@qt.io> Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
committed by
Ali Kianian
parent
e79cab5d99
commit
23e8be1ef4
@@ -98,7 +98,7 @@ Item {
|
|||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
acceptedButtons: Qt.RightButton | Qt.LeftButton
|
acceptedButtons: Qt.RightButton | Qt.LeftButton
|
||||||
onClicked: contextMenuRequested()
|
onClicked: root.contextMenuRequested()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -22,6 +22,10 @@ ListView {
|
|||||||
renameDialog.reject()
|
renameDialog.reject()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function deleteCurrentCollection() {
|
||||||
|
deleteDialog.open()
|
||||||
|
}
|
||||||
|
|
||||||
delegate: CollectionItem {
|
delegate: CollectionItem {
|
||||||
implicitWidth: root.width
|
implicitWidth: root.width
|
||||||
onDeleteItem: root.model.removeRow(index)
|
onDeleteItem: root.model.removeRow(index)
|
||||||
@@ -36,6 +40,10 @@ ListView {
|
|||||||
readonly property bool selected: item ? item.isSelected : false
|
readonly property bool selected: item ? item.isSelected : false
|
||||||
readonly property int index: item ? item.id : -1
|
readonly property int index: item ? item.id : -1
|
||||||
|
|
||||||
|
function updateItem() {
|
||||||
|
currentCollection.item = collectionMenu.clickedItem ?? root.itemAtIndex(root.model.selectedIndex)
|
||||||
|
}
|
||||||
|
|
||||||
function rename(newName) {
|
function rename(newName) {
|
||||||
if (item)
|
if (item)
|
||||||
item.rename(newName)
|
item.rename(newName)
|
||||||
@@ -54,145 +62,56 @@ ListView {
|
|||||||
StudioControls.Menu {
|
StudioControls.Menu {
|
||||||
id: collectionMenu
|
id: collectionMenu
|
||||||
|
|
||||||
|
property CollectionItem clickedItem
|
||||||
|
|
||||||
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
|
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
|
||||||
|
enabled: root.count
|
||||||
|
|
||||||
function openMenu(item) {
|
function openMenu(item) {
|
||||||
currentCollection.item = item
|
collectionMenu.clickedItem = item
|
||||||
popup()
|
currentCollection.updateItem()
|
||||||
|
collectionMenu.popup()
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.MenuItem {
|
onClosed: collectionMenu.clickedItem = null
|
||||||
|
|
||||||
|
Action {
|
||||||
|
id: menuDeleteAction
|
||||||
|
|
||||||
text: qsTr("Delete")
|
text: qsTr("Delete")
|
||||||
shortcut: StandardKey.Delete
|
|
||||||
onTriggered: deleteDialog.open()
|
onTriggered: deleteDialog.open()
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.MenuItem {
|
Action {
|
||||||
|
id: menuRenameAction
|
||||||
|
|
||||||
text: qsTr("Rename")
|
text: qsTr("Rename")
|
||||||
shortcut: StandardKey.Replace
|
|
||||||
onTriggered: renameDialog.open()
|
onTriggered: renameDialog.open()
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.MenuItem {
|
Action {
|
||||||
|
id: menuAssignAction
|
||||||
|
|
||||||
text: qsTr("Assign to the selected node")
|
text: qsTr("Assign to the selected node")
|
||||||
enabled: CollectionEditorBackend.rootView.targetNodeSelected
|
enabled: CollectionEditorBackend.rootView.targetNodeSelected
|
||||||
onTriggered: rootView.assignCollectionToSelectedNode(currentCollection.name)
|
onTriggered: rootView.assignCollectionToSelectedNode(currentCollection.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.Dialog {
|
ConfirmDeleteCollectionDialog {
|
||||||
id: deleteDialog
|
id: deleteDialog
|
||||||
|
|
||||||
title: qsTr("Deleting the model")
|
collectionName: currentCollection.name
|
||||||
clip: true
|
onAboutToShow: currentCollection.updateItem()
|
||||||
|
|
||||||
onAccepted: currentCollection.deleteItem()
|
onAccepted: currentCollection.deleteItem()
|
||||||
|
|
||||||
contentItem: ColumnLayout {
|
|
||||||
id: deleteDialogContent // Keep the id here even if it's not used, because the dialog might lose implicitSize
|
|
||||||
|
|
||||||
width: 300
|
|
||||||
spacing: 2
|
|
||||||
|
|
||||||
Text {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
color: StudioTheme.Values.themeTextColor
|
|
||||||
text: qsTr("Are you sure that you want to delete model \"%1\"?"
|
|
||||||
+ "\nThe model will be deleted permanently.").arg(currentCollection.name)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer {}
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
spacing: StudioTheme.Values.sectionRowSpacing
|
|
||||||
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: 40
|
|
||||||
|
|
||||||
HelperWidgets.Button {
|
|
||||||
text: qsTr("Delete")
|
|
||||||
onClicked: deleteDialog.accept()
|
|
||||||
}
|
|
||||||
|
|
||||||
HelperWidgets.Button {
|
|
||||||
text: qsTr("Cancel")
|
|
||||||
onClicked: deleteDialog.reject()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.Dialog {
|
RenameCollectionDialog {
|
||||||
id: renameDialog
|
id: renameDialog
|
||||||
|
|
||||||
title: qsTr("Rename model")
|
collectionName: currentCollection.name
|
||||||
|
onAboutToShow: currentCollection.updateItem()
|
||||||
onAccepted: {
|
onAccepted: currentCollection.rename(renameDialog.newCollectionName)
|
||||||
if (newNameField.text !== "")
|
|
||||||
currentCollection.rename(newNameField.text)
|
|
||||||
}
|
|
||||||
|
|
||||||
onOpened: {
|
|
||||||
newNameField.text = currentCollection.name
|
|
||||||
}
|
|
||||||
|
|
||||||
contentItem: ColumnLayout {
|
|
||||||
spacing: 2
|
|
||||||
|
|
||||||
Text {
|
|
||||||
text: qsTr("Previous name: " + currentCollection.name)
|
|
||||||
color: StudioTheme.Values.themeTextColor
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer {}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
|
||||||
text: qsTr("New name:")
|
|
||||||
color: StudioTheme.Values.themeTextColor
|
|
||||||
}
|
|
||||||
|
|
||||||
StudioControls.TextField {
|
|
||||||
id: newNameField
|
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
actionIndicator.visible: false
|
|
||||||
translationIndicator.visible: false
|
|
||||||
validator: newNameValidator
|
|
||||||
|
|
||||||
Keys.onEnterPressed: renameDialog.accept()
|
|
||||||
Keys.onReturnPressed: renameDialog.accept()
|
|
||||||
Keys.onEscapePressed: renameDialog.reject()
|
|
||||||
|
|
||||||
onTextChanged: {
|
|
||||||
btnRename.enabled = newNameField.text !== ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer {}
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
|
||||||
spacing: StudioTheme.Values.sectionRowSpacing
|
|
||||||
|
|
||||||
HelperWidgets.Button {
|
|
||||||
id: btnRename
|
|
||||||
|
|
||||||
text: qsTr("Rename")
|
|
||||||
onClicked: renameDialog.accept()
|
|
||||||
}
|
|
||||||
|
|
||||||
HelperWidgets.Button {
|
|
||||||
text: qsTr("Cancel")
|
|
||||||
onClicked: renameDialog.reject()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
@@ -202,14 +121,4 @@ ListView {
|
|||||||
root.closeDialogs()
|
root.closeDialogs()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RegularExpressionValidator {
|
|
||||||
id: newNameValidator
|
|
||||||
regularExpression: /^\w+$/
|
|
||||||
}
|
|
||||||
|
|
||||||
component Spacer: Item {
|
|
||||||
implicitWidth: 1
|
|
||||||
implicitHeight: StudioTheme.Values.columnGap
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -25,7 +25,7 @@ Item {
|
|||||||
|
|
||||||
// called from C++ when using the delete key
|
// called from C++ when using the delete key
|
||||||
function deleteSelectedCollection() {
|
function deleteSelectedCollection() {
|
||||||
print("TODO: deleteSelectedCollection")
|
collectionListView.deleteCurrentCollection()
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeDialogs() {
|
function closeDialogs() {
|
||||||
|
@@ -0,0 +1,57 @@
|
|||||||
|
// Copyright (C) 2024 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import HelperWidgets 2.0 as HelperWidgets
|
||||||
|
import StudioControls 1.0 as StudioControls
|
||||||
|
import StudioTheme as StudioTheme
|
||||||
|
|
||||||
|
StudioControls.Dialog {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property string collectionName
|
||||||
|
|
||||||
|
title: qsTr("Deleting the model")
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
contentItem: ColumnLayout {
|
||||||
|
id: deleteDialogContent // Keep the id here even if it's not used, because the dialog might lose implicitSize
|
||||||
|
|
||||||
|
width: 300
|
||||||
|
spacing: 2
|
||||||
|
|
||||||
|
Text {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
text: qsTr("Are you sure that you want to delete model \"%1\"?"
|
||||||
|
+ "\nThe model will be deleted permanently.").arg(root.collectionName)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Item { // spacer
|
||||||
|
implicitWidth: 1
|
||||||
|
implicitHeight: StudioTheme.Values.columnGap
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
spacing: StudioTheme.Values.sectionRowSpacing
|
||||||
|
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 40
|
||||||
|
|
||||||
|
HelperWidgets.Button {
|
||||||
|
text: qsTr("Delete")
|
||||||
|
onClicked: root.accept()
|
||||||
|
}
|
||||||
|
|
||||||
|
HelperWidgets.Button {
|
||||||
|
text: qsTr("Cancel")
|
||||||
|
onClicked: root.reject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,88 @@
|
|||||||
|
// Copyright (C) 2024 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import HelperWidgets 2.0 as HelperWidgets
|
||||||
|
import StudioControls 1.0 as StudioControls
|
||||||
|
import StudioTheme as StudioTheme
|
||||||
|
|
||||||
|
StudioControls.Dialog {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property string collectionName
|
||||||
|
readonly property alias newCollectionName: newNameField.text
|
||||||
|
readonly property bool isValid: newNameField.text !== ""
|
||||||
|
|
||||||
|
title: qsTr("Rename model")
|
||||||
|
|
||||||
|
onOpened: {
|
||||||
|
newNameField.text = root.collectionName
|
||||||
|
newNameField.forceActiveFocus()
|
||||||
|
}
|
||||||
|
|
||||||
|
function acceptIfVerified() {
|
||||||
|
if (root.isValid)
|
||||||
|
root.accept()
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: ColumnLayout {
|
||||||
|
id: renameDialogContent
|
||||||
|
|
||||||
|
spacing: 2
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: qsTr("Previous name: " + root.collectionName)
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer {}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
||||||
|
text: qsTr("New name:")
|
||||||
|
color: StudioTheme.Values.themeTextColor
|
||||||
|
}
|
||||||
|
|
||||||
|
StudioControls.TextField {
|
||||||
|
id: newNameField
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
actionIndicator.visible: false
|
||||||
|
translationIndicator.visible: false
|
||||||
|
validator: RegularExpressionValidator {
|
||||||
|
regularExpression: /^\w+$/
|
||||||
|
}
|
||||||
|
|
||||||
|
Keys.onEnterPressed: root.acceptIfVerified()
|
||||||
|
Keys.onReturnPressed: root.acceptIfVerified()
|
||||||
|
Keys.onEscapePressed: root.reject()
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer {}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||||
|
spacing: StudioTheme.Values.sectionRowSpacing
|
||||||
|
|
||||||
|
HelperWidgets.Button {
|
||||||
|
text: qsTr("Rename")
|
||||||
|
enabled: root.isValid
|
||||||
|
onClicked: root.acceptIfVerified()
|
||||||
|
}
|
||||||
|
|
||||||
|
HelperWidgets.Button {
|
||||||
|
text: qsTr("Cancel")
|
||||||
|
onClicked: root.reject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component Spacer: Item {
|
||||||
|
implicitWidth: 1
|
||||||
|
implicitHeight: StudioTheme.Values.columnGap
|
||||||
|
}
|
||||||
|
}
|
@@ -9,7 +9,7 @@ import StudioTheme 1.0 as StudioTheme
|
|||||||
T.MenuItem {
|
T.MenuItem {
|
||||||
id: control
|
id: control
|
||||||
|
|
||||||
property alias shortcut: itemAction.shortcut
|
property alias shortcut: shortcutObserver.shortcutWorkaround
|
||||||
|
|
||||||
property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
|
property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
|
||||||
|
|
||||||
@@ -24,9 +24,6 @@ T.MenuItem {
|
|||||||
padding: 0
|
padding: 0
|
||||||
spacing: 0
|
spacing: 0
|
||||||
horizontalPadding: control.style.contextMenuHorizontalPadding
|
horizontalPadding: control.style.contextMenuHorizontalPadding
|
||||||
action: Action {
|
|
||||||
id: itemAction
|
|
||||||
}
|
|
||||||
|
|
||||||
contentItem: Item {
|
contentItem: Item {
|
||||||
Text {
|
Text {
|
||||||
@@ -41,16 +38,23 @@ T.MenuItem {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: shortcutLabel
|
id: shortcutLabel
|
||||||
|
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
text: shortcutObserver.nativeText
|
text: shortcutObserver.nativeText
|
||||||
|
? shortcutObserver.nativeText
|
||||||
|
: control.action
|
||||||
|
? control.action.fakeShortcut ? control.action.fakeShortcut : ""
|
||||||
|
: ""
|
||||||
font: control.font
|
font: control.font
|
||||||
color: textLabel.color
|
color: textLabel.color
|
||||||
|
|
||||||
Shortcut {
|
Shortcut {
|
||||||
id: shortcutObserver
|
id: shortcutObserver
|
||||||
property int shortcutWorkaround: control.shortcut ?? 0
|
|
||||||
|
property int shortcutWorkaround: 0
|
||||||
sequence: shortcutObserver.shortcutWorkaround
|
sequence: shortcutObserver.shortcutWorkaround
|
||||||
|
enabled: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -53,6 +53,7 @@ QString getPreferredCollectionName(const QUrl &url, const QString &collectionNam
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
CollectionWidget::CollectionWidget(CollectionView *view)
|
CollectionWidget::CollectionWidget(CollectionView *view)
|
||||||
: m_view(view)
|
: m_view(view)
|
||||||
, m_listModel(new CollectionListModel)
|
, m_listModel(new CollectionListModel)
|
||||||
@@ -62,11 +63,11 @@ CollectionWidget::CollectionWidget(CollectionView *view)
|
|||||||
{
|
{
|
||||||
setWindowTitle(tr("Model Editor", "Title of model editor widget"));
|
setWindowTitle(tr("Model Editor", "Title of model editor widget"));
|
||||||
|
|
||||||
Core::IContext *icontext = nullptr;
|
|
||||||
Core::Context context(Constants::C_QMLCOLLECTIONEDITOR);
|
Core::Context context(Constants::C_QMLCOLLECTIONEDITOR);
|
||||||
icontext = new Core::IContext(this);
|
m_iContext = new Core::IContext(this);
|
||||||
icontext->setContext(context);
|
m_iContext->setContext(context);
|
||||||
icontext->setWidget(this);
|
m_iContext->setWidget(this);
|
||||||
|
Core::ICore::addContextObject(m_iContext);
|
||||||
|
|
||||||
connect(m_listModel, &CollectionListModel::warning, this, &CollectionWidget::warn);
|
connect(m_listModel, &CollectionListModel::warning, this, &CollectionWidget::warn);
|
||||||
|
|
||||||
|
@@ -71,6 +71,7 @@ private:
|
|||||||
QPointer<CollectionView> m_view;
|
QPointer<CollectionView> m_view;
|
||||||
QPointer<CollectionListModel> m_listModel;
|
QPointer<CollectionListModel> m_listModel;
|
||||||
QPointer<CollectionDetailsModel> m_collectionDetailsModel;
|
QPointer<CollectionDetailsModel> m_collectionDetailsModel;
|
||||||
|
QPointer<Core::IContext> m_iContext;
|
||||||
std::unique_ptr<CollectionDetailsSortFilterModel> m_collectionDetailsSortFilterModel;
|
std::unique_ptr<CollectionDetailsSortFilterModel> m_collectionDetailsSortFilterModel;
|
||||||
QScopedPointer<StudioQuickWidget> m_quickWidget;
|
QScopedPointer<StudioQuickWidget> m_quickWidget;
|
||||||
bool m_targetNodeSelected = false;
|
bool m_targetNodeSelected = false;
|
||||||
|
Reference in New Issue
Block a user