From fa6325381ba2f4f0bf443bc8a45536f551f4f67b Mon Sep 17 00:00:00 2001 From: Ali Kianian Date: Fri, 14 Mar 2025 12:16:33 +0200 Subject: [PATCH] PropertyEditor: Forward currentNodes to backend Since PropertyEditor has introduced `selection locking feature`, it should keep its own selection for the cases that the change should affect multiple nodes. It means that model selected node might be different than the propertyEditor working nodes. Also model selection changes should be notified separately. Change-Id: I692414811369680e16b3e25213bfa4b683576c55 Reviewed-by: Miikka Heikkinen Reviewed-by: Mahmoud Badri --- .../QtQuick3D/Material/Toolbar.qml | 1 + .../HelperWidgets/ComponentSection.qml | 2 +- .../materialeditorqmlbackend.cpp | 2 +- .../propertyeditorcontextobject.cpp | 34 ++-- .../propertyeditorcontextobject.h | 16 +- .../propertyeditorqmlbackend.cpp | 177 ++++++++---------- .../propertyeditor/propertyeditorqmlbackend.h | 8 +- .../propertyeditor/propertyeditorview.cpp | 48 ++++- .../propertyeditor/propertyeditorview.h | 2 + .../propertyeditor/qmlmaterialnodeproxy.cpp | 16 +- .../propertyeditor/qmlmaterialnodeproxy.h | 7 +- .../propertyeditor/qmlmodelnodeproxy.cpp | 22 ++- .../propertyeditor/qmlmodelnodeproxy.h | 6 +- .../textureeditor/textureeditorqmlbackend.cpp | 2 +- 14 files changed, 192 insertions(+), 151 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Material/Toolbar.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Material/Toolbar.qml index b3e5a7e147c..5cb89f91b97 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Material/Toolbar.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Material/Toolbar.qml @@ -23,6 +23,7 @@ Rectangle { style: StudioTheme.Values.viewBarButtonStyle buttonIcon: StudioTheme.Constants.apply_medium tooltip: qsTr("Apply material to selected model.") + enabled: has3DModelSelected onClicked: root.backend.toolBarAction(QmlMaterialNodeProxy.ApplyToSelected) } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComponentSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComponentSection.qml index f3b460e0994..d41b225af75 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComponentSection.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComponentSection.qml @@ -164,7 +164,7 @@ Section { id: toolTipArea enabled: !modelNodeBackend.multiSelection && anchorBackend.hasParent anchors.fill: parent - onClicked: toogleExportAlias() + onClicked: toggleExportAlias() tooltip: qsTr("Exports this component as an alias property of the root component.") } } diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorqmlbackend.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorqmlbackend.cpp index 89fd07b96a8..c71ac819ca7 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorqmlbackend.cpp +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorqmlbackend.cpp @@ -222,7 +222,7 @@ void MaterialEditorQmlBackend::setup(const QmlObjectNode &selectedMaterialNode, } // model node - m_backendModelNode.setup(selectedMaterialNode.modelNode()); + m_backendModelNode.setup(selectedMaterialNode); context()->setContextProperty("modelNodeBackend", &m_backendModelNode); context()->setContextProperty("hasMaterial", QVariant(true)); diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp index df9c8cc8ece..effb5ace520 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp @@ -138,7 +138,7 @@ QStringList PropertyEditorContextObject::autoComplete(const QString &text, int p return {}; } -void PropertyEditorContextObject::toogleExportAlias() +void PropertyEditorContextObject::toggleExportAlias() { QTC_ASSERT(m_model && m_model->rewriterView(), return); @@ -156,13 +156,13 @@ void PropertyEditorContextObject::toogleExportAlias() PropertyName modelNodeId = selectedNode.id().toUtf8(); ModelNode rootModelNode = rewriterView->rootModelNode(); - rewriterView->executeInTransaction("PropertyEditorContextObject:toogleExportAlias", [&objectNode, &rootModelNode, modelNodeId](){ - if (!objectNode.isAliasExported()) - objectNode.ensureAliasExport(); - else - if (rootModelNode.hasProperty(modelNodeId)) - rootModelNode.removeProperty(modelNodeId); - }); + rewriterView->executeInTransaction("PropertyEditorContextObject:toggleExportAlias", + [&objectNode, &rootModelNode, modelNodeId]() { + if (!objectNode.isAliasExported()) + objectNode.ensureAliasExport(); + else if (rootModelNode.hasProperty(modelNodeId)) + rootModelNode.removeProperty(modelNodeId); + }); } } @@ -294,7 +294,7 @@ void PropertyEditorContextObject::changeTypeName(const QString &typeName) try { auto transaction = RewriterTransaction(rewriterView, "PropertyEditorContextObject:changeTypeName"); - ModelNodes selectedNodes = rewriterView->selectedModelNodes(); // TODO: replace it by PropertyEditorView::currentNodes() + ModelNodes selectedNodes = m_editorNodes; for (ModelNode &selectedNode : selectedNodes) changeNodeTypeName(selectedNode); @@ -489,9 +489,9 @@ bool PropertyEditorContextObject::hasQuick3DImport() const return m_hasQuick3DImport; } -void PropertyEditorContextObject::setSelectedNode(const ModelNode &node) +void PropertyEditorContextObject::setEditorNodes(const ModelNodes &nodes) { - m_selectedNode = node; + m_editorNodes = nodes; } void PropertyEditorContextObject::setHasQuick3DImport(bool value) @@ -531,18 +531,18 @@ void PropertyEditorContextObject::setIsQt6Project(bool value) emit isQt6ProjectChanged(); } -bool PropertyEditorContextObject::has3DModelSelection() const +bool PropertyEditorContextObject::has3DModelSelected() const { - return m_has3DModelSelection; + return m_has3DModelSelected; } -void PropertyEditorContextObject::set3DHasModelSelection(bool value) +void PropertyEditorContextObject::setHas3DModelSelected(bool value) { - if (value == m_has3DModelSelection) + if (value == m_has3DModelSelected) return; - m_has3DModelSelection = value; - emit has3DModelSelectionChanged(); + m_has3DModelSelected = value; + emit has3DModelSelectedChanged(); } void PropertyEditorContextObject::setSpecificsUrl(const QUrl &newSpecificsUrl) diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h index ff20e5b7105..650f2bbbae8 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h @@ -57,7 +57,7 @@ class PropertyEditorContextObject : public QObject Q_PROPERTY(bool hasQuick3DImport READ hasQuick3DImport NOTIFY hasQuick3DImportChanged) Q_PROPERTY(bool hasMaterialLibrary READ hasMaterialLibrary NOTIFY hasMaterialLibraryChanged) Q_PROPERTY(bool isQt6Project READ isQt6Project NOTIFY isQt6ProjectChanged) - Q_PROPERTY(bool has3DModelSelection READ has3DModelSelection NOTIFY has3DModelSelectionChanged) + Q_PROPERTY(bool has3DModelSelected READ has3DModelSelected NOTIFY has3DModelSelectedChanged) public: PropertyEditorContextObject(QQuickWidget *widget, QObject *parent = nullptr); @@ -78,7 +78,7 @@ public: Q_INVOKABLE QStringList autoComplete(const QString &text, int pos, bool explicitComplete, bool filter); - Q_INVOKABLE void toogleExportAlias(); + Q_INVOKABLE void toggleExportAlias(); Q_INVOKABLE void goIntoComponent(); @@ -142,10 +142,10 @@ public: bool isQt6Project() const; void setIsQt6Project(bool value); - bool has3DModelSelection() const; - void set3DHasModelSelection(bool value); + bool has3DModelSelected() const; + void setHas3DModelSelected(bool value); - void setSelectedNode(const ModelNode &node); + void setEditorNodes(const ModelNodes &nodes); void setIsSelectionLocked(bool lock); bool isSelectionLocked() const; @@ -169,7 +169,7 @@ signals: void hasMultiSelectionChanged(); void hasQuick3DImportChanged(); void hasMaterialLibraryChanged(); - void has3DModelSelectionChanged(); + void has3DModelSelectedChanged(); void isQt6ProjectChanged(); void isSelectionLockedChanged(); @@ -217,7 +217,7 @@ private: bool m_hasQuick3DImport = false; bool m_hasMaterialLibrary = false; - bool m_has3DModelSelection = false; + bool m_has3DModelSelected = false; bool m_isQt6Project = false; QQmlComponent *m_qmlComponent; @@ -240,7 +240,7 @@ private: bool m_insightEnabled = false; QStringList m_insightCategories; - ModelNode m_selectedNode; + ModelNodes m_editorNodes; // Nodes that are being edited by PropertyEditor }; class EasingCurveEditor : public QObject diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp index 362efce6cf9..410a34be74e 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp @@ -375,6 +375,12 @@ void PropertyEditorQmlBackend::handleModelNodePreviewPixmapChanged(const ModelNo refreshPreview(); } +void PropertyEditorQmlBackend::handleModelSelectedNodesChanged(PropertyEditorView *propertyEditor) +{ + contextObject()->setHas3DModelSelected(!Utils3D::getSelectedModels(propertyEditor).isEmpty()); + m_backendTextureNode.updateSelectionDetails(); +} + void PropertyEditorQmlBackend::createPropertyEditorValue(const QmlObjectNode &qmlObjectNode, PropertyNameView name, const QVariant &value, @@ -566,108 +572,107 @@ void PropertyEditorQmlBackend::updateInstanceImage() refreshPreview(); } -void PropertyEditorQmlBackend::setup(const QmlObjectNode &qmlObjectNode, const QString &stateName, const QUrl &qmlSpecificsFile, PropertyEditorView *propertyEditor) +void PropertyEditorQmlBackend::setup(const ModelNodes &editorNodes, + const QString &stateName, + const QUrl &qmlSpecificsFile, + PropertyEditorView *propertyEditor) { - if (qmlObjectNode.isValid()) { - m_contextObject->setModel(propertyEditor->model()); + QmlObjectNode qmlObjectNode(editorNodes.isEmpty() ? ModelNode{} : editorNodes.first()); + if (!qmlObjectNode.isValid()) { + qWarning() << "PropertyEditor: invalid node for setup"; + return; + } - qCInfo(propertyEditorBenchmark) << Q_FUNC_INFO; + m_contextObject->setModel(propertyEditor->model()); - QElapsedTimer time; - if (propertyEditorBenchmark().isInfoEnabled()) - time.start(); + qCInfo(propertyEditorBenchmark) << Q_FUNC_INFO; - createPropertyEditorValues(qmlObjectNode, propertyEditor); - setupLayoutAttachedProperties(qmlObjectNode, propertyEditor); - setupInsightAttachedProperties(qmlObjectNode, propertyEditor); - setupAuxiliaryProperties(qmlObjectNode, propertyEditor); + QElapsedTimer time; + if (propertyEditorBenchmark().isInfoEnabled()) + time.start(); - // model node - m_backendModelNode.setup(qmlObjectNode.modelNode()); - context()->setContextProperty("modelNodeBackend", &m_backendModelNode); + createPropertyEditorValues(qmlObjectNode, propertyEditor); + setupLayoutAttachedProperties(qmlObjectNode, propertyEditor); + setupInsightAttachedProperties(qmlObjectNode, propertyEditor); + setupAuxiliaryProperties(qmlObjectNode, propertyEditor); - m_backendMaterialNode.setup(qmlObjectNode); - m_backendTextureNode.setup(qmlObjectNode); + // model node + m_backendModelNode.setup(editorNodes); + context()->setContextProperty("modelNodeBackend", &m_backendModelNode); - insertValue(Constants::PROPERTY_EDITOR_CLASSNAME_PROPERTY, - m_backendModelNode.simplifiedTypeName(), - qmlObjectNode.modelNode()); + m_backendMaterialNode.setup(editorNodes); + m_backendTextureNode.setup(qmlObjectNode); - insertValue("id"_L1, m_backendModelNode.nodeId()); - insertValue("objectName"_L1, m_backendModelNode.nodeObjectName()); + insertValue(Constants::PROPERTY_EDITOR_CLASSNAME_PROPERTY, + m_backendModelNode.simplifiedTypeName(), + qmlObjectNode.modelNode()); - QmlItemNode itemNode(qmlObjectNode.modelNode()); + insertValue("id"_L1, m_backendModelNode.nodeId()); + insertValue("objectName"_L1, m_backendModelNode.nodeObjectName()); - // anchors - m_backendAnchorBinding.setup(qmlObjectNode.modelNode()); - setupContextProperties(); + QmlItemNode itemNode(qmlObjectNode.modelNode()); - contextObject()->setHasMultiSelection( - !qmlObjectNode.view()->singleSelectedModelNode().isValid()); + // anchors + m_backendAnchorBinding.setup(qmlObjectNode.modelNode()); + setupContextProperties(); - qCInfo(propertyEditorBenchmark) << "anchors:" << time.elapsed(); + contextObject()->setHasMultiSelection(m_backendModelNode.multiSelection()); - qCInfo(propertyEditorBenchmark) << "context:" << time.elapsed(); + qCInfo(propertyEditorBenchmark) << "anchors:" << time.elapsed(); - contextObject()->setSpecificsUrl(qmlSpecificsFile); + qCInfo(propertyEditorBenchmark) << "context:" << time.elapsed(); - qCInfo(propertyEditorBenchmark) << "specifics:" << time.elapsed(); + contextObject()->setSpecificsUrl(qmlSpecificsFile); - contextObject()->setStateName(stateName); - if (!qmlObjectNode.isValid()) - return; + qCInfo(propertyEditorBenchmark) << "specifics:" << time.elapsed(); - context()->setContextProperty(QLatin1String("propertyCount"), - QVariant(qmlObjectNode.modelNode().properties().size())); + contextObject()->setStateName(stateName); - QStringList stateNames = qmlObjectNode.allStateNames(); - stateNames.prepend("base state"); - contextObject()->setAllStateNames(stateNames); + context()->setContextProperty(QLatin1String("propertyCount"), + QVariant(qmlObjectNode.modelNode().properties().size())); - contextObject()->setIsBaseState(qmlObjectNode.isInBaseState()); + QStringList stateNames = qmlObjectNode.allStateNames(); + stateNames.prepend("base state"); + contextObject()->setAllStateNames(stateNames); - contextObject()->setHasAliasExport(qmlObjectNode.isAliasExported()); + contextObject()->setIsBaseState(qmlObjectNode.isInBaseState()); - contextObject()->setHasActiveTimeline(QmlTimeline::hasActiveTimeline(qmlObjectNode.view())); + contextObject()->setHasAliasExport(qmlObjectNode.isAliasExported()); - contextObject()->setSelectionChanged(false); + contextObject()->setHasActiveTimeline(QmlTimeline::hasActiveTimeline(qmlObjectNode.view())); - contextObject()->setSelectionChanged(false); + contextObject()->setSelectionChanged(false); - NodeMetaInfo metaInfo = qmlObjectNode.modelNode().metaInfo(); + NodeMetaInfo metaInfo = qmlObjectNode.modelNode().metaInfo(); #ifdef QDS_USE_PROJECTSTORAGE + contextObject()->setMajorVersion(-1); + contextObject()->setMinorVersion(-1); + contextObject()->setMajorQtQuickVersion(-1); + contextObject()->setMinorQtQuickVersion(-1); +#else + if (metaInfo.isValid()) { + contextObject()->setMajorVersion(metaInfo.majorVersion()); + contextObject()->setMinorVersion(metaInfo.minorVersion()); + } else { contextObject()->setMajorVersion(-1); contextObject()->setMinorVersion(-1); contextObject()->setMajorQtQuickVersion(-1); contextObject()->setMinorQtQuickVersion(-1); -#else - if (metaInfo.isValid()) { - contextObject()->setMajorVersion(metaInfo.majorVersion()); - contextObject()->setMinorVersion(metaInfo.minorVersion()); - } else { - contextObject()->setMajorVersion(-1); - contextObject()->setMinorVersion(-1); - contextObject()->setMajorQtQuickVersion(-1); - contextObject()->setMinorQtQuickVersion(-1); - } -#endif - contextObject()->setMajorQtQuickVersion(qmlObjectNode.view()->majorQtQuickVersion()); - contextObject()->setMinorQtQuickVersion(qmlObjectNode.view()->minorQtQuickVersion()); - - contextObject()->setHasMaterialLibrary(Utils3D::materialLibraryNode(propertyEditor).isValid()); - contextObject()->setIsQt6Project(propertyEditor->externalDependencies().isQt6Project()); - contextObject()->set3DHasModelSelection(!Utils3D::getSelectedModels(propertyEditor).isEmpty()); - contextObject()->setSelectedNode(qmlObjectNode); - contextObject()->setHasQuick3DImport(propertyEditor->model()->hasImport("QtQuick3D")); - - m_view->instanceImageProvider()->setModelNode(propertyEditor->firstSelectedModelNode()); - updateInstanceImage(); - - qCInfo(propertyEditorBenchmark) << "final:" << time.elapsed(); - } else { - qWarning() << "PropertyEditor: invalid node for setup"; } +#endif + contextObject()->setMajorQtQuickVersion(qmlObjectNode.view()->majorQtQuickVersion()); + contextObject()->setMinorQtQuickVersion(qmlObjectNode.view()->minorQtQuickVersion()); + + contextObject()->setHasMaterialLibrary(Utils3D::materialLibraryNode(propertyEditor).isValid()); + contextObject()->setIsQt6Project(propertyEditor->externalDependencies().isQt6Project()); + contextObject()->setEditorNodes(editorNodes); + contextObject()->setHasQuick3DImport(propertyEditor->model()->hasImport("QtQuick3D")); + + m_view->instanceImageProvider()->setModelNode(m_backendModelNode.singleSelectedNode()); + updateInstanceImage(); + + qCInfo(propertyEditorBenchmark) << "final:" << time.elapsed(); } QString PropertyEditorQmlBackend::propertyEditorResourcesPath() @@ -960,35 +965,6 @@ QString PropertyEditorQmlBackend::resourcesPath(const QString &dir) return Core::ICore::resourcePath("qmldesigner/" + dir).toUrlishString(); } -static NodeMetaInfo findCommonSuperClass(const NodeMetaInfo &first, const NodeMetaInfo &second) -{ - auto commonBase = first.commonBase(second); - - return commonBase.isValid() ? commonBase : first; -} - -NodeMetaInfo PropertyEditorQmlBackend::findCommonAncestor(const ModelNode &node) -{ - if (!node.isValid()) - return node.metaInfo(); - - AbstractView *view = node.view(); - - const QList &selectedNodes = view->selectedModelNodes(); - if (selectedNodes.size() > 1) { - NodeMetaInfo commonClass = node.metaInfo(); - - for (const ModelNode &selectedNode : selectedNodes) { - const NodeMetaInfo &nodeMetaInfo = selectedNode.metaInfo(); - if (nodeMetaInfo.isValid() && !nodeMetaInfo.isBasedOn(commonClass)) - commonClass = findCommonSuperClass(nodeMetaInfo, commonClass); - } - return commonClass; - } - - return node.metaInfo(); -} - void PropertyEditorQmlBackend::refreshBackendModel() { m_backendModelNode.refresh(); @@ -1064,7 +1040,6 @@ bool PropertyEditorQmlBackend::checkIfUrlExists(const QUrl &url) void PropertyEditorQmlBackend::emitSelectionToBeChanged() { m_backendModelNode.emitSelectionToBeChanged(); - m_backendTextureNode.updateSelectionDetails(); } void PropertyEditorQmlBackend::emitSelectionChanged() diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.h index d4304b3d8ab..19abd1d757b 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.h +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.h @@ -40,7 +40,10 @@ public: class AsynchronousImageCache &imageCache); ~PropertyEditorQmlBackend(); - void setup(const QmlObjectNode &fxObjectNode, const QString &stateName, const QUrl &qmlSpecificsFile, PropertyEditorView *propertyEditor); + void setup(const ModelNodes &editorNodes, + const QString &stateName, + const QUrl &qmlSpecificsFile, + PropertyEditorView *propertyEditor); void setValue(const QmlObjectNode &fxObjectNode, PropertyNameView name, const QVariant &value); void setExpression(PropertyNameView propName, const QString &exp); @@ -94,8 +97,7 @@ public: void handleModelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap, const QByteArray &requestId); - - static NodeMetaInfo findCommonAncestor(const ModelNode &node); + void handleModelSelectedNodesChanged(PropertyEditorView *propertyEditor); void refreshBackendModel(); void refreshPreview(); diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp index 86ee06fec7e..6244e1d005c 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp @@ -61,6 +61,13 @@ static bool propertyIsAttachedInsightProperty(PropertyNameView propertyName) return propertyName.contains("InsightCategory."); } +static NodeMetaInfo findCommonSuperClass(const NodeMetaInfo &first, const NodeMetaInfo &second) +{ + auto commonBase = first.commonBase(second); + + return commonBase.isValid() ? commonBase : first; +} + PropertyEditorView::PropertyEditorView(AsynchronousImageCache &imageCache, ExternalDependenciesInterface &externalDependencies) : AbstractView(externalDependencies) @@ -428,6 +435,26 @@ PropertyEditorView *PropertyEditorView::instance() return s_instance; } +NodeMetaInfo PropertyEditorView::findCommonAncestor(const ModelNode &node) +{ + if (!node.isValid()) + return node.metaInfo(); + + const QList allNodes = currentNodes(); + if (allNodes.size() > 1) { + NodeMetaInfo commonClass = node.metaInfo(); + + for (const ModelNode &selectedNode : allNodes) { + const NodeMetaInfo &nodeMetaInfo = selectedNode.metaInfo(); + if (nodeMetaInfo.isValid() && !nodeMetaInfo.isBasedOn(commonClass)) + commonClass = findCommonSuperClass(nodeMetaInfo, commonClass); + } + return commonClass; + } + + return node.metaInfo(); +} + void PropertyEditorView::updateSize() { if (!m_qmlBackEndForCurrentType) @@ -542,7 +569,7 @@ PropertyEditorQmlBackend *getQmlBackend(QHashcontextObject()->setSpecificQmlData(specificQmlData); - currentQmlBackend->setup(qmlObjectNode, currentStateName, qmlSpecificsFile, propertyEditorView); + currentQmlBackend->setup(editorNodes, currentStateName, qmlSpecificsFile, propertyEditorView); currentQmlBackend->contextObject()->setSpecificQmlData(specificQmlData); } @@ -634,7 +660,7 @@ void PropertyEditorView::handleToolBarAction(int action) void PropertyEditorView::setupQmlBackend() { #ifdef QDS_USE_PROJECTSTORAGE - const NodeMetaInfo commonAncestor = PropertyEditorQmlBackend::findCommonAncestor(activeNode()); + const NodeMetaInfo commonAncestor = findCommonAncestor(activeNode()); auto selfAndPrototypes = commonAncestor.selfAndPrototypes(); bool isEditableComponent = activeNode().isComponent() && !QmlItemNode(activeNode()).isEffectItem(); @@ -648,7 +674,7 @@ void PropertyEditorView::setupQmlBackend() m_stackedWidget, this); setupCurrentQmlBackend(currentQmlBackend, - activeNode(), + currentNodes(), QUrl::fromLocalFile(QString{specificsPath}), currentStateNode(), this, @@ -660,7 +686,7 @@ void PropertyEditorView::setupQmlBackend() setupInsight(rootModelNode(), currentQmlBackend); #else - const NodeMetaInfo commonAncestor = PropertyEditorQmlBackend::findCommonAncestor(activeNode()); + const NodeMetaInfo commonAncestor = findCommonAncestor(activeNode()); // qmlFileUrl is panel url. and specifics is its metainfo const auto [qmlFileUrl, specificsClassMetaInfo] = PropertyEditorQmlBackend::getQmlUrlForMetaInfo( @@ -681,7 +707,7 @@ void PropertyEditorView::setupQmlBackend() this); setupCurrentQmlBackend(currentQmlBackend, - activeNode(), + currentNodes(), qmlSpecificsFile, currentStateNode(), this, @@ -788,10 +814,12 @@ QList PropertyEditorView::currentNodes() const void PropertyEditorView::selectedNodesChanged(const QList &, const QList &) { - if (m_isSelectionLocked) - return; + if (!m_isSelectionLocked) + select(); - select(); + // Notify model selection changes to backend regardless of being locked + if (m_qmlBackEndForCurrentType) + m_qmlBackEndForCurrentType->handleModelSelectedNodesChanged(this); } bool PropertyEditorView::isNodeOrChildSelected(const ModelNode &node) const diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h index f3fd2d60709..ee1f6ad5a76 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h @@ -143,6 +143,8 @@ private: //functions static PropertyEditorView *instance(); + NodeMetaInfo findCommonAncestor(const ModelNode &node); + private: //variables AsynchronousImageCache &m_imageCache; ModelNode m_activeNode; diff --git a/src/plugins/qmldesigner/components/propertyeditor/qmlmaterialnodeproxy.cpp b/src/plugins/qmldesigner/components/propertyeditor/qmlmaterialnodeproxy.cpp index d2011e8e087..16ef8604969 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/qmlmaterialnodeproxy.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/qmlmaterialnodeproxy.cpp @@ -41,11 +41,13 @@ QmlMaterialNodeProxy::QmlMaterialNodeProxy() QmlMaterialNodeProxy::~QmlMaterialNodeProxy() = default; -void QmlMaterialNodeProxy::setup(const QmlObjectNode &objectNode) +void QmlMaterialNodeProxy::setup(const ModelNodes &editorNodes) { + QmlObjectNode objectNode = editorNodes.isEmpty() ? ModelNode{} : editorNodes.first(); const QmlObjectNode material = objectNode.metaInfo().isQtQuick3DMaterial() ? objectNode : QmlObjectNode{}; setMaterialNode(material); + setEditorNodes(editorNodes); updatePossibleTypes(); updatePreviewModel(); } @@ -55,6 +57,11 @@ ModelNode QmlMaterialNodeProxy::materialNode() const return m_materialNode; } +ModelNodes QmlMaterialNodeProxy::editorNodes() const +{ + return m_editorNodes; +} + void QmlMaterialNodeProxy::setPossibleTypes(const QStringList &types) { if (types == m_possibleTypes) @@ -81,7 +88,7 @@ void QmlMaterialNodeProxy::updatePossibleTypes() } const QString &matType = materialNode().simplifiedTypeName(); - const ModelNodes selectedNodes = materialView()->selectedModelNodes(); // TODO: replace it by PropertyEditorView::currentNodes() + const ModelNodes selectedNodes = editorNodes(); bool allAreBasic = Utils::allOf(selectedNodes, [&](const ModelNode &node) { return basicTypes.contains(node.simplifiedTypeName()); }); @@ -275,6 +282,11 @@ void QmlMaterialNodeProxy::setMaterialNode(const QmlObjectNode &material) emit materialNodeChanged(); } +void QmlMaterialNodeProxy::setEditorNodes(const ModelNodes &editorNodes) +{ + m_editorNodes = editorNodes; +} + bool QmlMaterialNodeProxy::hasQuick3DImport() const { return materialNode().isValid() && materialNode().model()->hasImport("QtQuick3D"_L1); diff --git a/src/plugins/qmldesigner/components/propertyeditor/qmlmaterialnodeproxy.h b/src/plugins/qmldesigner/components/propertyeditor/qmlmaterialnodeproxy.h index 58bf8935970..b4bd7fb6ddb 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/qmlmaterialnodeproxy.h +++ b/src/plugins/qmldesigner/components/propertyeditor/qmlmaterialnodeproxy.h @@ -35,11 +35,12 @@ public: explicit QmlMaterialNodeProxy(); ~QmlMaterialNodeProxy() override; - void setup(const QmlObjectNode &objectNode); + void setup(const ModelNodes &editorNodes); QStringList possibleTypes() const { return m_possibleTypes; } ModelNode materialNode() const; + ModelNodes editorNodes() const; int possibleTypeIndex() const { return m_possibleTypeIndex; } @@ -67,15 +68,15 @@ private: // Methods void updatePossibleTypeIndex(); void updatePreviewModel(); void setMaterialNode(const QmlObjectNode &material); + void setEditorNodes(const ModelNodes &editorNodes); bool hasQuick3DImport() const; AbstractView *materialView() const; private: - bool m_has3DModelSelection = false; - QmlObjectNode m_materialNode; + ModelNodes m_editorNodes; QStringList m_possibleTypes; int m_possibleTypeIndex = -1; diff --git a/src/plugins/qmldesigner/components/propertyeditor/qmlmodelnodeproxy.cpp b/src/plugins/qmldesigner/components/propertyeditor/qmlmodelnodeproxy.cpp index 1e6fe6a1e3e..07c7537c852 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/qmlmodelnodeproxy.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/qmlmodelnodeproxy.cpp @@ -22,9 +22,15 @@ QmlModelNodeProxy::QmlModelNodeProxy(QObject *parent) : { } -void QmlModelNodeProxy::setup(const QmlObjectNode &objectNode) +void QmlModelNodeProxy::setup(const ModelNode &node) { - m_qmlObjectNode = objectNode; + setup(ModelNodes{node}); +} + +void QmlModelNodeProxy::setup(const ModelNodes &editorNodes) +{ + m_qmlObjectNode = editorNodes.isEmpty() ? ModelNode{} : editorNodes.first(); + m_editorNodes = editorNodes; m_subselection.clear(); @@ -61,12 +67,22 @@ ModelNode QmlModelNodeProxy::modelNode() const return m_qmlObjectNode.modelNode(); } +ModelNodes QmlModelNodeProxy::editorNodes() const +{ + return m_editorNodes; +} + +ModelNode QmlModelNodeProxy::singleSelectedNode() const +{ + return multiSelection() ? ModelNode{} : modelNode(); +} + bool QmlModelNodeProxy::multiSelection() const { if (!m_qmlObjectNode.isValid()) return false; - return m_qmlObjectNode.view()->selectedModelNodes().size() > 1; + return editorNodes().size() > 1; } QString QmlModelNodeProxy::nodeId() const diff --git a/src/plugins/qmldesigner/components/propertyeditor/qmlmodelnodeproxy.h b/src/plugins/qmldesigner/components/propertyeditor/qmlmodelnodeproxy.h index 207594b15b3..c61c9d2bcd0 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/qmlmodelnodeproxy.h +++ b/src/plugins/qmldesigner/components/propertyeditor/qmlmodelnodeproxy.h @@ -22,7 +22,8 @@ class QMLDESIGNER_EXPORT QmlModelNodeProxy : public QObject public: explicit QmlModelNodeProxy(QObject *parent = nullptr); - void setup(const QmlObjectNode &objectNode); + void setup(const ModelNode &node); + void setup(const ModelNodes &editorNodes); static void registerDeclarativeType(); @@ -33,6 +34,8 @@ public: QmlObjectNode qmlObjectNode() const; ModelNode modelNode() const; + ModelNodes editorNodes() const; + ModelNode singleSelectedNode() const; bool multiSelection() const; @@ -81,6 +84,7 @@ private: PropertyEditorSubSelectionWrapper *findWrapper(int internalId) const; QmlObjectNode m_qmlObjectNode; + ModelNodes m_editorNodes; QList> m_subselection; }; diff --git a/src/plugins/qmldesigner/components/textureeditor/textureeditorqmlbackend.cpp b/src/plugins/qmldesigner/components/textureeditor/textureeditorqmlbackend.cpp index af56832ea38..f2b88649694 100644 --- a/src/plugins/qmldesigner/components/textureeditor/textureeditorqmlbackend.cpp +++ b/src/plugins/qmldesigner/components/textureeditor/textureeditorqmlbackend.cpp @@ -211,7 +211,7 @@ void TextureEditorQmlBackend::setup(const QmlObjectNode &selectedTextureNode, co } // model node - m_backendModelNode.setup(selectedTextureNode.modelNode()); + m_backendModelNode.setup(selectedTextureNode); context()->setContextProperty("modelNodeBackend", &m_backendModelNode); context()->setContextProperty("hasTexture", QVariant(true));