diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/PropertyEditorPane.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/PropertyEditorPane.qml index 192c53cc5ce..74c66c39f35 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/PropertyEditorPane.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/PropertyEditorPane.qml @@ -57,8 +57,17 @@ Rectangle { HeaderBackground{} } + PropertyEditorToolBar { + id: toolbar + + anchors.top: dockedHeaderLoader.bottom + width: parent.width + + onToolBarAction: action => handleToolBarAction(action) + } + MouseArea { - anchors.fill: parent + anchors.fill: mainScrollView onClicked: itemPane.forceActiveFocus() } @@ -111,7 +120,7 @@ Rectangle { clip: true anchors { - top: dockedHeaderLoader.bottom + top: toolbar.bottom bottom: itemPane.bottom left: itemPane.left right: itemPane.right diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/PropertyEditorToolBar.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/PropertyEditorToolBar.qml new file mode 100644 index 00000000000..bd8abf16d49 --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/PropertyEditorToolBar.qml @@ -0,0 +1,32 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import HelperWidgets as HelperWidgets +import StudioTheme as StudioTheme +import PropertyToolBarAction + +Rectangle { + id: root + + signal toolBarAction(int action) + + color: StudioTheme.Values.themeToolbarBackground + height: StudioTheme.Values.toolbarHeight + + HelperWidgets.AbstractButton { + id: lockButton + + anchors.right: parent.right + anchors.rightMargin: StudioTheme.Values.toolbarHorizontalMargin + anchors.verticalCenter: parent.verticalCenter + buttonIcon: lockButton.checked ? StudioTheme.Constants.lockOn : StudioTheme.Constants.lockOff + checkable: true + checked: isSelectionLocked ?? false + enabled: !(hasMultiSelection ?? false) + style: StudioTheme.Values.viewBarButtonStyle + tooltip: qsTr("Lock current node") + + onClicked: root.toolBarAction(lockButton.checked ? ToolBarAction.SelectionLock : ToolBarAction.SelectionUnlock) + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/qmldir b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/qmldir index f363bab3bda..29675dfde5b 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/qmldir +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/qmldir @@ -54,6 +54,7 @@ OriginIndicator 2.0 OriginIndicator.qml OriginSelector 2.0 OriginSelector.qml PopupLabel 2.0 PopupLabel.qml PropertyEditorPane 2.0 PropertyEditorPane.qml +PropertyEditorToolBar 2.0 PropertyEditorToolBar.qml PropertyLabel 2.0 PropertyLabel.qml PaddingSection 2.0 PaddingSection.qml RoundedPanel 2.0 RoundedPanel.qml diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp index de87cb89af6..331f6ad269b 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp @@ -443,6 +443,20 @@ void PropertyEditorContextObject::setHasMultiSelection(bool b) emit hasMultiSelectionChanged(); } +bool PropertyEditorContextObject::isSelectionLocked() const +{ + return m_isSelectionLocked; +} + +void PropertyEditorContextObject::setIsSelectionLocked(bool lock) +{ + if (lock == m_isSelectionLocked) + return; + + m_isSelectionLocked = lock; + emit isSelectionLockedChanged(); +} + void PropertyEditorContextObject::setInsightEnabled(bool value) { if (value != m_insightEnabled) { @@ -696,6 +710,11 @@ QPoint PropertyEditorContextObject::globalPos(const QPoint &point) const return point; } +void PropertyEditorContextObject::handleToolBarAction(int action) +{ + emit toolBarAction(action); +} + void EasingCurveEditor::registerDeclarativeType() { qmlRegisterType("HelperWidgets", 2, 0, "EasingCurveEditor"); diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h index c2c5f876e8a..ff20e5b7105 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h @@ -49,6 +49,8 @@ class PropertyEditorContextObject : public QObject Q_PROPERTY(bool hasMultiSelection READ hasMultiSelection WRITE setHasMultiSelection NOTIFY hasMultiSelectionChanged) + Q_PROPERTY(bool isSelectionLocked READ isSelectionLocked WRITE setIsSelectionLocked NOTIFY isSelectionLockedChanged) + Q_PROPERTY(bool insightEnabled MEMBER m_insightEnabled NOTIFY insightEnabledChanged) Q_PROPERTY(QStringList insightCategories MEMBER m_insightCategories NOTIFY insightCategoriesChanged) @@ -100,6 +102,11 @@ public: Q_INVOKABLE QRect screenRect() const; Q_INVOKABLE QPoint globalPos(const QPoint &point) const; + Q_INVOKABLE void handleToolBarAction(int action); + + enum ToolBarAction { SelectionLock, SelectionUnlock }; + Q_ENUM(ToolBarAction) + QString activeDragSuffix() const; void setActiveDragSuffix(const QString &suffix); @@ -140,6 +147,9 @@ public: void setSelectedNode(const ModelNode &node); + void setIsSelectionLocked(bool lock); + bool isSelectionLocked() const; + signals: void specificsUrlChanged(); void specificQmlDataChanged(); @@ -161,9 +171,11 @@ signals: void hasMaterialLibraryChanged(); void has3DModelSelectionChanged(); void isQt6ProjectChanged(); + void isSelectionLockedChanged(); void insightEnabledChanged(); void insightCategoriesChanged(); + void toolBarAction(int action); public slots: @@ -223,6 +235,7 @@ private: QString m_activeDragSuffix; bool m_hasMultiSelection = false; + bool m_isSelectionLocked = false; bool m_insightEnabled = false; QStringList m_insightCategories; diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp index e6ef39d5864..27d20dcc98f 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp @@ -66,7 +66,6 @@ PropertyEditorView::PropertyEditorView(AsynchronousImageCache &imageCache, : AbstractView(externalDependencies) , m_imageCache(imageCache) , m_updateShortcut(nullptr) - , m_timerId(0) , m_stackedWidget(new PropertyEditorWidget()) , m_qmlBackEndForCurrentType(nullptr) , m_propertyComponentGenerator{PropertyEditorQmlBackend::propertyEditorResourcesPath(), model()} @@ -117,15 +116,15 @@ void PropertyEditorView::changeValue(const QString &name) PropertyEditorValue *value = m_qmlBackEndForCurrentType->propertyValueForName(QString::fromUtf8(propertyName)); const QString newId = value->value().toString(); - if (newId == m_selectedNode.id()) + if (newId == activeNode().id()) return; if (QmlDesigner::ModelNode::isValidId(newId) && !hasId(newId)) { executeInTransaction("PropertyEditorView::changeId", - [this, newId] { m_selectedNode.setIdWithRefactoring(newId); }); + [&] { activeNode().setIdWithRefactoring(newId); }); } else { m_locked = true; - value->setValue(m_selectedNode.id()); + value->setValue(activeNode().id()); m_locked = false; QString errMsg = QmlDesigner::ModelNode::getIdValidityErrorMessage(newId); if (!errMsg.isEmpty()) @@ -148,7 +147,7 @@ void PropertyEditorView::changeValue(const QString &name) return; } - const NodeMetaInfo metaInfo = QmlObjectNode(m_selectedNode).modelNode().metaInfo(); + const NodeMetaInfo metaInfo = QmlObjectNode(activeNode()).modelNode().metaInfo(); QVariant castedValue; @@ -230,7 +229,7 @@ void PropertyEditorView::changeExpression(const QString &propertyName) PropertyName underscoreName(name); underscoreName.replace('.', '_'); - QmlObjectNode qmlObjectNode{m_selectedNode}; + QmlObjectNode qmlObjectNode{activeNode()}; PropertyEditorValue *value = m_qmlBackEndForCurrentType->propertyValueForName( QString::fromUtf8(underscoreName)); @@ -259,7 +258,7 @@ void PropertyEditorView::exportPropertyAsAlias(const QString &name) return; executeInTransaction("PropertyEditorView::exportPropertyAsAlias", - [this, name]() { generateAliasForProperty(m_selectedNode, name); }); + [&]() { generateAliasForProperty(activeNode(), name); }); } void PropertyEditorView::removeAliasExport(const QString &name) @@ -274,7 +273,7 @@ void PropertyEditorView::removeAliasExport(const QString &name) return; executeInTransaction("PropertyEditorView::exportPropertyAsAlias", - [this, name]() { removeAliasForProperty(m_selectedNode, name); }); + [&]() { removeAliasForProperty(activeNode(), name); }); } bool PropertyEditorView::locked() const @@ -431,19 +430,13 @@ void PropertyEditorView::resetView() if (model() == nullptr) return; - setSelelectedModelNode(); + setActiveNodeToSelection(); m_locked = true; if (debug) qDebug() << "________________ RELOADING PROPERTY EDITOR QML _______________________"; - if (m_timerId) - killTimer(m_timerId); - - if (m_selectedNode.isValid() && model() != m_selectedNode.model()) - m_selectedNode = ModelNode(); - setupQmlBackend(); if (m_qmlBackEndForCurrentType) { @@ -453,12 +446,20 @@ void PropertyEditorView::resetView() m_locked = false; - if (m_timerId) - m_timerId = 0; - updateSize(); } +void PropertyEditorView::setIsSelectionLocked(bool locked) +{ + m_isSelectionLocked = locked; + if (m_qmlBackEndForCurrentType) + m_qmlBackEndForCurrentType->contextObject()->setIsSelectionLocked(locked); + + // Show current selection on unlock + if (!m_locked && !m_isSelectionLocked) + select(); +} + namespace { #ifndef QDS_USE_PROJECTSTORAGE @@ -597,13 +598,27 @@ void setupWidget(PropertyEditorQmlBackend *currentQmlBackend, } // namespace +void PropertyEditorView::handleToolBarAction(int action) +{ + switch (action) { + case PropertyEditorContextObject::SelectionLock: { + setIsSelectionLocked(true); + break; + } + case PropertyEditorContextObject::SelectionUnlock: { + setIsSelectionLocked(false); + break; + } + } +} + void PropertyEditorView::setupQmlBackend() { #ifdef QDS_USE_PROJECTSTORAGE - const NodeMetaInfo commonAncestor = PropertyEditorQmlBackend::findCommonAncestor(m_selectedNode); + const NodeMetaInfo commonAncestor = PropertyEditorQmlBackend::findCommonAncestor(activeNode()); auto selfAndPrototypes = commonAncestor.selfAndPrototypes(); - bool isEditableComponent = m_selectedNode.isComponent() - && !QmlItemNode(m_selectedNode).isEffectItem(); + bool isEditableComponent = activeNode().isComponent() + && !QmlItemNode(activeNode()).isEffectItem(); auto specificQmlData = m_propertyEditorComponentGenerator.create(selfAndPrototypes, isEditableComponent); auto [panePath, specificsPath] = findPaneAndSpecificsPath(selfAndPrototypes, model()->pathCache()); @@ -614,7 +629,7 @@ void PropertyEditorView::setupQmlBackend() m_stackedWidget, this); setupCurrentQmlBackend(currentQmlBackend, - m_selectedNode, + activeNode(), QUrl::fromLocalFile(QString{specificsPath}), currentStateNode(), this, @@ -626,7 +641,7 @@ void PropertyEditorView::setupQmlBackend() setupInsight(rootModelNode(), currentQmlBackend); #else - const NodeMetaInfo commonAncestor = PropertyEditorQmlBackend::findCommonAncestor(m_selectedNode); + const NodeMetaInfo commonAncestor = PropertyEditorQmlBackend::findCommonAncestor(activeNode()); // qmlFileUrl is panel url. and specifics is its metainfo const auto [qmlFileUrl, specificsClassMetaInfo] = PropertyEditorQmlBackend::getQmlUrlForMetaInfo( @@ -638,7 +653,7 @@ void PropertyEditorView::setupQmlBackend() if (qmlFileUrl.toLocalFile().endsWith("TexturePane.qml")) qmlSpecificsFile = QUrl{}; - QString specificQmlData = getSpecificQmlData(commonAncestor, m_selectedNode, diffClassMetaInfo); + QString specificQmlData = getSpecificQmlData(commonAncestor, activeNode(), diffClassMetaInfo); PropertyEditorQmlBackend *currentQmlBackend = getQmlBackend(m_qmlBackendHash, qmlFileUrl, @@ -647,7 +662,7 @@ void PropertyEditorView::setupQmlBackend() this); setupCurrentQmlBackend(currentQmlBackend, - m_selectedNode, + activeNode(), qmlSpecificsFile, currentStateNode(), this, @@ -660,7 +675,9 @@ void PropertyEditorView::setupQmlBackend() setupInsight(rootModelNode(), currentQmlBackend); #endif // QDS_USE_PROJECTSTORAGE - m_dynamicPropertiesModel->setSelectedNode(m_selectedNode); + m_dynamicPropertiesModel->setSelectedNode(activeNode()); + + QObject::connect(m_qmlBackEndForCurrentType->contextObject(), SIGNAL(toolBarAction(int)), this, SLOT(handleToolBarAction(int))); } void PropertyEditorView::commitVariantValueToModel(PropertyNameView propertyName, const QVariant &value) @@ -669,7 +686,8 @@ void PropertyEditorView::commitVariantValueToModel(PropertyNameView propertyName try { RewriterTransaction transaction = beginRewriterTransaction("PropertyEditorView::commitVariantValueToMode"); - for (const ModelNode &node : m_selectedNode.view()->selectedModelNodes()) { + const QList nodes = currentNodes(); + for (const ModelNode &node : nodes) { if (auto qmlObjectNode = QmlObjectNode(node)) qmlObjectNode.setVariantProperty(propertyName, value); } @@ -689,14 +707,13 @@ void PropertyEditorView::commitAuxValueToModel(PropertyNameView propertyName, co name.chop(5); try { + const QList nodes = currentNodes(); if (value.isValid()) { - for (const ModelNode &node : m_selectedNode.view()->selectedModelNodes()) { + for (const ModelNode &node : nodes) node.setAuxiliaryData(AuxiliaryDataType::Document, name, value); - } } else { - for (const ModelNode &node : m_selectedNode.view()->selectedModelNodes()) { + for (const ModelNode &node : nodes) node.removeAuxiliaryData(AuxiliaryDataType::Document, name); - } } } catch (const Exception &e) { @@ -711,7 +728,8 @@ void PropertyEditorView::removePropertyFromModel(PropertyNameView propertyName) try { RewriterTransaction transaction = beginRewriterTransaction("PropertyEditorView::removePropertyFromModel"); - for (const ModelNode &node : m_selectedNode.view()->selectedModelNodes()) { + const QList nodes = currentNodes(); + for (const ModelNode &node : nodes) { if (QmlObjectNode::isValidQmlObjectNode(node)) QmlObjectNode(node).removeProperty(propertyName); } @@ -727,19 +745,62 @@ void PropertyEditorView::removePropertyFromModel(PropertyNameView propertyName) bool PropertyEditorView::noValidSelection() const { QTC_ASSERT(m_qmlBackEndForCurrentType, return true); - return !QmlObjectNode::isValidQmlObjectNode(m_selectedNode); + return !QmlObjectNode::isValidQmlObjectNode(activeNode()); +} + +ModelNode PropertyEditorView::activeNode() const +{ + return m_activeNode; +} + +void PropertyEditorView::setActiveNode(const ModelNode &node) +{ + m_activeNode = node; +} + +QList PropertyEditorView::currentNodes() const +{ + if (m_isSelectionLocked) + return {m_activeNode}; + + return selectedModelNodes(); } void PropertyEditorView::selectedNodesChanged(const QList &, const QList &) { + if (m_isSelectionLocked) + return; + select(); } +bool PropertyEditorView::isNodeOrChildSelected(const ModelNode &node) const +{ + if (activeNode().isValid() && node.isValid()) { + const ModelNodes &nodeList = node.allSubModelNodesAndThisNode(); + return nodeList.contains(activeNode()); + } + return false; +} + +void PropertyEditorView::resetSelectionLocked() +{ + if (m_isSelectionLocked) + setIsSelectionLocked(false); +} + +void PropertyEditorView::resetIfNodeIsRemoved(const ModelNode &removedNode) +{ + if (isNodeOrChildSelected(removedNode)) { + resetSelectionLocked(); + select(); + } +} + void PropertyEditorView::nodeAboutToBeRemoved(const ModelNode &removedNode) { - if (m_selectedNode.isValid() && removedNode.isValid() && m_selectedNode == removedNode) - select(); + resetIfNodeIsRemoved(removedNode); const ModelNodes &allRemovedNodes = removedNode.allSubModelNodesAndThisNode(); @@ -795,10 +856,10 @@ void PropertyEditorView::propertiesRemoved(const QList &proper ModelNode node(property.parentModelNode()); - if (node.isRootNode() && !m_selectedNode.isRootNode()) - m_qmlBackEndForCurrentType->contextObject()->setHasAliasExport(QmlObjectNode(m_selectedNode).isAliasExported()); + if (node.isRootNode() && !activeNode().isRootNode()) + m_qmlBackEndForCurrentType->contextObject()->setHasAliasExport(QmlObjectNode(activeNode()).isAliasExported()); - if (node == m_selectedNode || QmlObjectNode(m_selectedNode).propertyChangeForCurrentState() == node) { + if (node == activeNode() || QmlObjectNode(activeNode()).propertyChangeForCurrentState() == node) { m_locked = true; changed = true; @@ -813,41 +874,41 @@ void PropertyEditorView::propertiesRemoved(const QList &proper if (value) { value->resetValue(); m_qmlBackEndForCurrentType - ->setValue(m_selectedNode, + ->setValue(activeNode(), propertyName, - QmlObjectNode(m_selectedNode).instanceValue(propertyName)); + QmlObjectNode(activeNode()).instanceValue(propertyName)); } m_locked = false; if (propertyIsAttachedLayoutProperty(propertyName)) { - m_qmlBackEndForCurrentType->setValueforLayoutAttachedProperties(m_selectedNode, + m_qmlBackEndForCurrentType->setValueforLayoutAttachedProperties(activeNode(), propertyName); if (propertyName == "Layout.margins") { m_qmlBackEndForCurrentType - ->setValueforLayoutAttachedProperties(m_selectedNode, "Layout.topMargin"); + ->setValueforLayoutAttachedProperties(activeNode(), "Layout.topMargin"); m_qmlBackEndForCurrentType - ->setValueforLayoutAttachedProperties(m_selectedNode, "Layout.bottomMargin"); + ->setValueforLayoutAttachedProperties(activeNode(), "Layout.bottomMargin"); m_qmlBackEndForCurrentType - ->setValueforLayoutAttachedProperties(m_selectedNode, "Layout.leftMargin"); + ->setValueforLayoutAttachedProperties(activeNode(), "Layout.leftMargin"); m_qmlBackEndForCurrentType - ->setValueforLayoutAttachedProperties(m_selectedNode, "Layout.rightMargin"); + ->setValueforLayoutAttachedProperties(activeNode(), "Layout.rightMargin"); } } if (propertyIsAttachedInsightProperty(propertyName)) { - m_qmlBackEndForCurrentType->setValueforInsightAttachedProperties(m_selectedNode, + m_qmlBackEndForCurrentType->setValueforInsightAttachedProperties(activeNode(), propertyName); } if ("width" == propertyName || "height" == propertyName) { - const QmlItemNode qmlItemNode = m_selectedNode; + const QmlItemNode qmlItemNode = activeNode(); if (qmlItemNode.isInLayout()) resetPuppet(); } if (propertyName.contains("anchor")) - m_qmlBackEndForCurrentType->backendAnchorBinding().invalidate(m_selectedNode); + m_qmlBackEndForCurrentType->backendAnchorBinding().invalidate(activeNode()); dynamicPropertiesModel()->dispatchPropertyChanges(property); } @@ -871,8 +932,8 @@ void PropertyEditorView::variantPropertiesChanged(const QList& bool changed = false; - bool selectedNodeIsMaterial = m_selectedNode.metaInfo().isQtQuick3DMaterial(); - bool selectedNodeHasBindingProperties = !m_selectedNode.bindingProperties().isEmpty(); + bool selectedNodeIsMaterial = activeNode().metaInfo().isQtQuick3DMaterial(); + bool selectedNodeHasBindingProperties = !activeNode().bindingProperties().isEmpty(); for (const VariantProperty &property : propertyList) { m_qmlBackEndForCurrentType->handleVariantPropertyChangedInModelNodeProxy(property); @@ -880,20 +941,20 @@ void PropertyEditorView::variantPropertiesChanged(const QList& ModelNode node(property.parentModelNode()); if (propertyIsAttachedLayoutProperty(property.name())) - m_qmlBackEndForCurrentType->setValueforLayoutAttachedProperties(m_selectedNode, + m_qmlBackEndForCurrentType->setValueforLayoutAttachedProperties(activeNode(), property.name()); if (propertyIsAttachedInsightProperty(property.name())) - m_qmlBackEndForCurrentType->setValueforInsightAttachedProperties(m_selectedNode, + m_qmlBackEndForCurrentType->setValueforInsightAttachedProperties(activeNode(), property.name()); - if (node == m_selectedNode || QmlObjectNode(m_selectedNode).propertyChangeForCurrentState() == node) { + if (node == activeNode() || QmlObjectNode(activeNode()).propertyChangeForCurrentState() == node) { if (property.isDynamic()) m_dynamicPropertiesModel->updateItem(property); - if ( QmlObjectNode(m_selectedNode).modelNode().property(property.name()).isBindingProperty()) - setValue(m_selectedNode, property.name(), QmlObjectNode(m_selectedNode).instanceValue(property.name())); + if ( QmlObjectNode(activeNode()).modelNode().property(property.name()).isBindingProperty()) + setValue(activeNode(), property.name(), QmlObjectNode(activeNode()).instanceValue(property.name())); else - setValue(m_selectedNode, property.name(), QmlObjectNode(m_selectedNode).modelValue(property.name())); + setValue(activeNode(), property.name(), QmlObjectNode(activeNode()).modelValue(property.name())); changed = true; } @@ -933,16 +994,16 @@ void PropertyEditorView::bindingPropertiesChanged(const QList & ModelNode node(property.parentModelNode()); if (property.isAliasExport()) - m_qmlBackEndForCurrentType->contextObject()->setHasAliasExport(QmlObjectNode(m_selectedNode).isAliasExported()); + m_qmlBackEndForCurrentType->contextObject()->setHasAliasExport(QmlObjectNode(activeNode()).isAliasExported()); - if (node == m_selectedNode || QmlObjectNode(m_selectedNode).propertyChangeForCurrentState() == node) { + if (node == activeNode() || QmlObjectNode(activeNode()).propertyChangeForCurrentState() == node) { if (property.isDynamic()) m_dynamicPropertiesModel->updateItem(property); if (property.name().contains("anchor")) - m_qmlBackEndForCurrentType->backendAnchorBinding().invalidate(m_selectedNode); + m_qmlBackEndForCurrentType->backendAnchorBinding().invalidate(activeNode()); m_locked = true; - QString exp = QmlObjectNode(m_selectedNode).bindingProperty(property.name()).expression(); + QString exp = QmlObjectNode(activeNode()).bindingProperty(property.name()).expression(); m_qmlBackEndForCurrentType->setExpression(property.name(), exp); m_locked = false; changed = true; @@ -966,7 +1027,7 @@ void PropertyEditorView::auxiliaryDataChanged(const ModelNode &node, QScopeGuard rootGuard([this, node, key, &saved] { if (node.isRootNode()) { if (!saved) - m_qmlBackEndForCurrentType->setValueforAuxiliaryProperties(m_selectedNode, key); + m_qmlBackEndForCurrentType->setValueforAuxiliaryProperties(activeNode(), key); m_qmlBackEndForCurrentType->handleAuxiliaryDataChanges(node, key); } }); @@ -974,7 +1035,7 @@ void PropertyEditorView::auxiliaryDataChanged(const ModelNode &node, if (!node.isSelected()) return; - m_qmlBackEndForCurrentType->setValueforAuxiliaryProperties(m_selectedNode, key); + m_qmlBackEndForCurrentType->setValueforAuxiliaryProperties(activeNode(), key); saved = true; if (key == insightEnabledProperty) @@ -990,10 +1051,10 @@ void PropertyEditorView::instanceInformationsChanged(const QMultiHash informationNameList = informationChangedHash.values(m_selectedNode); + QList informationNameList = informationChangedHash.values(activeNode()); if (informationNameList.contains(Anchor) || informationNameList.contains(HasAnchor)) - m_qmlBackEndForCurrentType->backendAnchorBinding().setup(QmlItemNode(m_selectedNode)); + m_qmlBackEndForCurrentType->backendAnchorBinding().setup(QmlItemNode(activeNode())); m_locked = false; } @@ -1002,7 +1063,7 @@ void PropertyEditorView::nodeIdChanged(const ModelNode &node, const QString &new if (noValidSelection()) return; - if (!QmlObjectNode(m_selectedNode).isValid()) + if (!QmlObjectNode(activeNode()).isValid()) return; m_dynamicPropertiesModel->reset(); @@ -1013,7 +1074,7 @@ void PropertyEditorView::nodeIdChanged(const ModelNode &node, const QString &new else if (oldId == Constants::MATERIAL_LIB_ID) m_qmlBackEndForCurrentType->contextObject()->setHasMaterialLibrary(false); - if (node == m_selectedNode) + if (node == activeNode()) setValue(node, "id", newId); if (node.metaInfo().isQtQuick3DTexture()) m_qmlBackEndForCurrentType->refreshBackendModel(); @@ -1028,11 +1089,11 @@ void PropertyEditorView::select() resetView(); } -void PropertyEditorView::setSelelectedModelNode() +void PropertyEditorView::setActiveNodeToSelection() { - const auto selectedNodeList = selectedModelNodes(); + const auto selectedNodeList = currentNodes(); - m_selectedNode = ModelNode(); + setActiveNode(ModelNode()); if (selectedNodeList.isEmpty()) return; @@ -1040,7 +1101,7 @@ void PropertyEditorView::setSelelectedModelNode() const ModelNode node = selectedNodeList.constFirst(); if (QmlObjectNode(node).isValid()) - m_selectedNode = node; + setActiveNode(node); } bool PropertyEditorView::hasWidget() const @@ -1068,7 +1129,7 @@ void PropertyEditorView::currentStateChanged(const ModelNode &node) void PropertyEditorView::instancePropertyChanged(const QList > &propertyList) { - if (!m_selectedNode.isValid()) + if (!activeNode().isValid()) return; QTC_ASSERT(m_qmlBackEndForCurrentType, return ); @@ -1084,7 +1145,7 @@ void PropertyEditorView::instancePropertyChanged(const QListhandleInstancePropertyChangedInModelNodeProxy(modelNode, propertyName); - if (qmlObjectNode.isValid() && modelNode == m_selectedNode + if (qmlObjectNode.isValid() && modelNode == activeNode() && qmlObjectNode.currentState().isValid()) { const AbstractProperty property = modelNode.property(propertyName); if (!modelNode.hasProperty(propertyName) || property.isBindingProperty()) @@ -1110,7 +1171,7 @@ void PropertyEditorView::rootNodeTypeChanged(const QString &/*type*/, int /*majo void PropertyEditorView::nodeTypeChanged(const ModelNode &node, const TypeName &, int, int) { - if (node == m_selectedNode) + if (node == activeNode()) resetView(); } @@ -1119,8 +1180,8 @@ void PropertyEditorView::nodeReparented(const ModelNode &node, const NodeAbstractProperty & /*oldPropertyParent*/, AbstractView::PropertyChangeFlags /*propertyChange*/) { - if (node == m_selectedNode) - m_qmlBackEndForCurrentType->backendAnchorBinding().setup(QmlItemNode(m_selectedNode)); + if (node == activeNode()) + m_qmlBackEndForCurrentType->backendAnchorBinding().setup(QmlItemNode(activeNode())); const ModelNodes &allNodes = node.allSubModelNodesAndThisNode(); if (Utils::contains(allNodes, model()->qtQuick3DTextureMetaInfo(), &ModelNode::metaInfo)) @@ -1147,7 +1208,7 @@ void PropertyEditorView::modelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap, const QByteArray &requestId) { - if (node != m_selectedNode) + if (node != activeNode()) return; if (m_qmlBackEndForCurrentType) @@ -1156,7 +1217,7 @@ void PropertyEditorView::modelNodePreviewPixmapChanged(const ModelNode &node, void PropertyEditorView::highlightTextureProperties(bool highlight) { - NodeMetaInfo metaInfo = m_selectedNode.metaInfo(); + NodeMetaInfo metaInfo = activeNode().metaInfo(); QTC_ASSERT(metaInfo.isValid(), return); DesignerPropertyMap &propMap = m_qmlBackEndForCurrentType->backendValuesPropertyMap(); diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h index 547a6d2aa7c..f3fd2d60709 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h @@ -107,6 +107,9 @@ public: static void removeAliasForProperty(const ModelNode &modelNode, const QString &propertyName); +public slots: + void handleToolBarAction(int action); + protected: void setValue(const QmlObjectNode &fxObjectNode, PropertyNameView name, const QVariant &value); bool eventFilter(QObject *obj, QEvent *event) override; @@ -116,7 +119,7 @@ private: //functions void updateSize(); void select(); - void setSelelectedModelNode(); + void setActiveNodeToSelection(); void delayedResetView(); void setupQmlBackend(); @@ -128,13 +131,22 @@ private: //functions bool noValidSelection() const; void highlightTextureProperties(bool highlight = true); + ModelNode activeNode() const; + void setActiveNode(const ModelNode &node); + QList currentNodes() const; + + void resetSelectionLocked(); + void setIsSelectionLocked(bool locked); + + bool isNodeOrChildSelected(const ModelNode &node) const; + void resetIfNodeIsRemoved(const ModelNode &removedNode); + static PropertyEditorView *instance(); private: //variables AsynchronousImageCache &m_imageCache; - ModelNode m_selectedNode; + ModelNode m_activeNode; QShortcut *m_updateShortcut; - int m_timerId; PropertyEditorWidget* m_stackedWidget; QString m_qmlDir; QHash m_qmlBackendHash; @@ -143,6 +155,7 @@ private: //variables PropertyEditorComponentGenerator m_propertyEditorComponentGenerator{m_propertyComponentGenerator}; bool m_locked; bool m_textureAboutToBeRemoved = false; + bool m_isSelectionLocked = false; DynamicPropertiesModel *m_dynamicPropertiesModel = nullptr; friend class PropertyEditorDynamicPropertiesProxyModel; diff --git a/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp b/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp index 9e3a397fa90..30e9f6908f6 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp @@ -87,6 +87,7 @@ void Quick2PropertyEditorView::registerQmlTypes() QUrl regExpUrl = QUrl::fromLocalFile(resourcePath + "/RegExpValidator.qml"); qmlRegisterType(regExpUrl, "HelperWidgets", 2, 0, "RegExpValidator"); + qmlRegisterUncreatableType("PropertyToolBarAction", 2, 0, "ToolBarAction", "Enum type"); } }