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 <miikka.heikkinen@qt.io>
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
Ali Kianian
2025-03-14 12:16:33 +02:00
parent ba8303b86b
commit fa6325381b
14 changed files with 192 additions and 151 deletions

View File

@@ -23,6 +23,7 @@ Rectangle {
style: StudioTheme.Values.viewBarButtonStyle style: StudioTheme.Values.viewBarButtonStyle
buttonIcon: StudioTheme.Constants.apply_medium buttonIcon: StudioTheme.Constants.apply_medium
tooltip: qsTr("Apply material to selected model.") tooltip: qsTr("Apply material to selected model.")
enabled: has3DModelSelected
onClicked: root.backend.toolBarAction(QmlMaterialNodeProxy.ApplyToSelected) onClicked: root.backend.toolBarAction(QmlMaterialNodeProxy.ApplyToSelected)
} }

View File

@@ -164,7 +164,7 @@ Section {
id: toolTipArea id: toolTipArea
enabled: !modelNodeBackend.multiSelection && anchorBackend.hasParent enabled: !modelNodeBackend.multiSelection && anchorBackend.hasParent
anchors.fill: parent anchors.fill: parent
onClicked: toogleExportAlias() onClicked: toggleExportAlias()
tooltip: qsTr("Exports this component as an alias property of the root component.") tooltip: qsTr("Exports this component as an alias property of the root component.")
} }
} }

View File

@@ -222,7 +222,7 @@ void MaterialEditorQmlBackend::setup(const QmlObjectNode &selectedMaterialNode,
} }
// model node // model node
m_backendModelNode.setup(selectedMaterialNode.modelNode()); m_backendModelNode.setup(selectedMaterialNode);
context()->setContextProperty("modelNodeBackend", &m_backendModelNode); context()->setContextProperty("modelNodeBackend", &m_backendModelNode);
context()->setContextProperty("hasMaterial", QVariant(true)); context()->setContextProperty("hasMaterial", QVariant(true));

View File

@@ -138,7 +138,7 @@ QStringList PropertyEditorContextObject::autoComplete(const QString &text, int p
return {}; return {};
} }
void PropertyEditorContextObject::toogleExportAlias() void PropertyEditorContextObject::toggleExportAlias()
{ {
QTC_ASSERT(m_model && m_model->rewriterView(), return); QTC_ASSERT(m_model && m_model->rewriterView(), return);
@@ -156,13 +156,13 @@ void PropertyEditorContextObject::toogleExportAlias()
PropertyName modelNodeId = selectedNode.id().toUtf8(); PropertyName modelNodeId = selectedNode.id().toUtf8();
ModelNode rootModelNode = rewriterView->rootModelNode(); ModelNode rootModelNode = rewriterView->rootModelNode();
rewriterView->executeInTransaction("PropertyEditorContextObject:toogleExportAlias", [&objectNode, &rootModelNode, modelNodeId](){ rewriterView->executeInTransaction("PropertyEditorContextObject:toggleExportAlias",
if (!objectNode.isAliasExported()) [&objectNode, &rootModelNode, modelNodeId]() {
objectNode.ensureAliasExport(); if (!objectNode.isAliasExported())
else objectNode.ensureAliasExport();
if (rootModelNode.hasProperty(modelNodeId)) else if (rootModelNode.hasProperty(modelNodeId))
rootModelNode.removeProperty(modelNodeId); rootModelNode.removeProperty(modelNodeId);
}); });
} }
} }
@@ -294,7 +294,7 @@ void PropertyEditorContextObject::changeTypeName(const QString &typeName)
try { try {
auto transaction = RewriterTransaction(rewriterView, "PropertyEditorContextObject:changeTypeName"); auto transaction = RewriterTransaction(rewriterView, "PropertyEditorContextObject:changeTypeName");
ModelNodes selectedNodes = rewriterView->selectedModelNodes(); // TODO: replace it by PropertyEditorView::currentNodes() ModelNodes selectedNodes = m_editorNodes;
for (ModelNode &selectedNode : selectedNodes) for (ModelNode &selectedNode : selectedNodes)
changeNodeTypeName(selectedNode); changeNodeTypeName(selectedNode);
@@ -489,9 +489,9 @@ bool PropertyEditorContextObject::hasQuick3DImport() const
return m_hasQuick3DImport; 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) void PropertyEditorContextObject::setHasQuick3DImport(bool value)
@@ -531,18 +531,18 @@ void PropertyEditorContextObject::setIsQt6Project(bool value)
emit isQt6ProjectChanged(); 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; return;
m_has3DModelSelection = value; m_has3DModelSelected = value;
emit has3DModelSelectionChanged(); emit has3DModelSelectedChanged();
} }
void PropertyEditorContextObject::setSpecificsUrl(const QUrl &newSpecificsUrl) void PropertyEditorContextObject::setSpecificsUrl(const QUrl &newSpecificsUrl)

View File

@@ -57,7 +57,7 @@ class PropertyEditorContextObject : public QObject
Q_PROPERTY(bool hasQuick3DImport READ hasQuick3DImport NOTIFY hasQuick3DImportChanged) Q_PROPERTY(bool hasQuick3DImport READ hasQuick3DImport NOTIFY hasQuick3DImportChanged)
Q_PROPERTY(bool hasMaterialLibrary READ hasMaterialLibrary NOTIFY hasMaterialLibraryChanged) Q_PROPERTY(bool hasMaterialLibrary READ hasMaterialLibrary NOTIFY hasMaterialLibraryChanged)
Q_PROPERTY(bool isQt6Project READ isQt6Project NOTIFY isQt6ProjectChanged) 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: public:
PropertyEditorContextObject(QQuickWidget *widget, QObject *parent = nullptr); 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 QStringList autoComplete(const QString &text, int pos, bool explicitComplete, bool filter);
Q_INVOKABLE void toogleExportAlias(); Q_INVOKABLE void toggleExportAlias();
Q_INVOKABLE void goIntoComponent(); Q_INVOKABLE void goIntoComponent();
@@ -142,10 +142,10 @@ public:
bool isQt6Project() const; bool isQt6Project() const;
void setIsQt6Project(bool value); void setIsQt6Project(bool value);
bool has3DModelSelection() const; bool has3DModelSelected() const;
void set3DHasModelSelection(bool value); void setHas3DModelSelected(bool value);
void setSelectedNode(const ModelNode &node); void setEditorNodes(const ModelNodes &nodes);
void setIsSelectionLocked(bool lock); void setIsSelectionLocked(bool lock);
bool isSelectionLocked() const; bool isSelectionLocked() const;
@@ -169,7 +169,7 @@ signals:
void hasMultiSelectionChanged(); void hasMultiSelectionChanged();
void hasQuick3DImportChanged(); void hasQuick3DImportChanged();
void hasMaterialLibraryChanged(); void hasMaterialLibraryChanged();
void has3DModelSelectionChanged(); void has3DModelSelectedChanged();
void isQt6ProjectChanged(); void isQt6ProjectChanged();
void isSelectionLockedChanged(); void isSelectionLockedChanged();
@@ -217,7 +217,7 @@ private:
bool m_hasQuick3DImport = false; bool m_hasQuick3DImport = false;
bool m_hasMaterialLibrary = false; bool m_hasMaterialLibrary = false;
bool m_has3DModelSelection = false; bool m_has3DModelSelected = false;
bool m_isQt6Project = false; bool m_isQt6Project = false;
QQmlComponent *m_qmlComponent; QQmlComponent *m_qmlComponent;
@@ -240,7 +240,7 @@ private:
bool m_insightEnabled = false; bool m_insightEnabled = false;
QStringList m_insightCategories; QStringList m_insightCategories;
ModelNode m_selectedNode; ModelNodes m_editorNodes; // Nodes that are being edited by PropertyEditor
}; };
class EasingCurveEditor : public QObject class EasingCurveEditor : public QObject

View File

@@ -375,6 +375,12 @@ void PropertyEditorQmlBackend::handleModelNodePreviewPixmapChanged(const ModelNo
refreshPreview(); refreshPreview();
} }
void PropertyEditorQmlBackend::handleModelSelectedNodesChanged(PropertyEditorView *propertyEditor)
{
contextObject()->setHas3DModelSelected(!Utils3D::getSelectedModels(propertyEditor).isEmpty());
m_backendTextureNode.updateSelectionDetails();
}
void PropertyEditorQmlBackend::createPropertyEditorValue(const QmlObjectNode &qmlObjectNode, void PropertyEditorQmlBackend::createPropertyEditorValue(const QmlObjectNode &qmlObjectNode,
PropertyNameView name, PropertyNameView name,
const QVariant &value, const QVariant &value,
@@ -566,108 +572,107 @@ void PropertyEditorQmlBackend::updateInstanceImage()
refreshPreview(); 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()) { QmlObjectNode qmlObjectNode(editorNodes.isEmpty() ? ModelNode{} : editorNodes.first());
m_contextObject->setModel(propertyEditor->model()); if (!qmlObjectNode.isValid()) {
qWarning() << "PropertyEditor: invalid node for setup";
return;
}
qCInfo(propertyEditorBenchmark) << Q_FUNC_INFO; m_contextObject->setModel(propertyEditor->model());
QElapsedTimer time; qCInfo(propertyEditorBenchmark) << Q_FUNC_INFO;
if (propertyEditorBenchmark().isInfoEnabled())
time.start();
createPropertyEditorValues(qmlObjectNode, propertyEditor); QElapsedTimer time;
setupLayoutAttachedProperties(qmlObjectNode, propertyEditor); if (propertyEditorBenchmark().isInfoEnabled())
setupInsightAttachedProperties(qmlObjectNode, propertyEditor); time.start();
setupAuxiliaryProperties(qmlObjectNode, propertyEditor);
// model node createPropertyEditorValues(qmlObjectNode, propertyEditor);
m_backendModelNode.setup(qmlObjectNode.modelNode()); setupLayoutAttachedProperties(qmlObjectNode, propertyEditor);
context()->setContextProperty("modelNodeBackend", &m_backendModelNode); setupInsightAttachedProperties(qmlObjectNode, propertyEditor);
setupAuxiliaryProperties(qmlObjectNode, propertyEditor);
m_backendMaterialNode.setup(qmlObjectNode); // model node
m_backendTextureNode.setup(qmlObjectNode); m_backendModelNode.setup(editorNodes);
context()->setContextProperty("modelNodeBackend", &m_backendModelNode);
insertValue(Constants::PROPERTY_EDITOR_CLASSNAME_PROPERTY, m_backendMaterialNode.setup(editorNodes);
m_backendModelNode.simplifiedTypeName(), m_backendTextureNode.setup(qmlObjectNode);
qmlObjectNode.modelNode());
insertValue("id"_L1, m_backendModelNode.nodeId()); insertValue(Constants::PROPERTY_EDITOR_CLASSNAME_PROPERTY,
insertValue("objectName"_L1, m_backendModelNode.nodeObjectName()); m_backendModelNode.simplifiedTypeName(),
qmlObjectNode.modelNode());
QmlItemNode itemNode(qmlObjectNode.modelNode()); insertValue("id"_L1, m_backendModelNode.nodeId());
insertValue("objectName"_L1, m_backendModelNode.nodeObjectName());
// anchors QmlItemNode itemNode(qmlObjectNode.modelNode());
m_backendAnchorBinding.setup(qmlObjectNode.modelNode());
setupContextProperties();
contextObject()->setHasMultiSelection( // anchors
!qmlObjectNode.view()->singleSelectedModelNode().isValid()); 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); qCInfo(propertyEditorBenchmark) << "specifics:" << time.elapsed();
if (!qmlObjectNode.isValid())
return;
context()->setContextProperty(QLatin1String("propertyCount"), contextObject()->setStateName(stateName);
QVariant(qmlObjectNode.modelNode().properties().size()));
QStringList stateNames = qmlObjectNode.allStateNames(); context()->setContextProperty(QLatin1String("propertyCount"),
stateNames.prepend("base state"); QVariant(qmlObjectNode.modelNode().properties().size()));
contextObject()->setAllStateNames(stateNames);
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 #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()->setMajorVersion(-1);
contextObject()->setMinorVersion(-1); contextObject()->setMinorVersion(-1);
contextObject()->setMajorQtQuickVersion(-1); contextObject()->setMajorQtQuickVersion(-1);
contextObject()->setMinorQtQuickVersion(-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() QString PropertyEditorQmlBackend::propertyEditorResourcesPath()
@@ -960,35 +965,6 @@ QString PropertyEditorQmlBackend::resourcesPath(const QString &dir)
return Core::ICore::resourcePath("qmldesigner/" + dir).toUrlishString(); 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<ModelNode> &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() void PropertyEditorQmlBackend::refreshBackendModel()
{ {
m_backendModelNode.refresh(); m_backendModelNode.refresh();
@@ -1064,7 +1040,6 @@ bool PropertyEditorQmlBackend::checkIfUrlExists(const QUrl &url)
void PropertyEditorQmlBackend::emitSelectionToBeChanged() void PropertyEditorQmlBackend::emitSelectionToBeChanged()
{ {
m_backendModelNode.emitSelectionToBeChanged(); m_backendModelNode.emitSelectionToBeChanged();
m_backendTextureNode.updateSelectionDetails();
} }
void PropertyEditorQmlBackend::emitSelectionChanged() void PropertyEditorQmlBackend::emitSelectionChanged()

View File

@@ -40,7 +40,10 @@ public:
class AsynchronousImageCache &imageCache); class AsynchronousImageCache &imageCache);
~PropertyEditorQmlBackend(); ~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 setValue(const QmlObjectNode &fxObjectNode, PropertyNameView name, const QVariant &value);
void setExpression(PropertyNameView propName, const QString &exp); void setExpression(PropertyNameView propName, const QString &exp);
@@ -94,8 +97,7 @@ public:
void handleModelNodePreviewPixmapChanged(const ModelNode &node, void handleModelNodePreviewPixmapChanged(const ModelNode &node,
const QPixmap &pixmap, const QPixmap &pixmap,
const QByteArray &requestId); const QByteArray &requestId);
void handleModelSelectedNodesChanged(PropertyEditorView *propertyEditor);
static NodeMetaInfo findCommonAncestor(const ModelNode &node);
void refreshBackendModel(); void refreshBackendModel();
void refreshPreview(); void refreshPreview();

View File

@@ -61,6 +61,13 @@ static bool propertyIsAttachedInsightProperty(PropertyNameView propertyName)
return propertyName.contains("InsightCategory."); 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, PropertyEditorView::PropertyEditorView(AsynchronousImageCache &imageCache,
ExternalDependenciesInterface &externalDependencies) ExternalDependenciesInterface &externalDependencies)
: AbstractView(externalDependencies) : AbstractView(externalDependencies)
@@ -428,6 +435,26 @@ PropertyEditorView *PropertyEditorView::instance()
return s_instance; return s_instance;
} }
NodeMetaInfo PropertyEditorView::findCommonAncestor(const ModelNode &node)
{
if (!node.isValid())
return node.metaInfo();
const QList<ModelNode> 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() void PropertyEditorView::updateSize()
{ {
if (!m_qmlBackEndForCurrentType) if (!m_qmlBackEndForCurrentType)
@@ -542,7 +569,7 @@ PropertyEditorQmlBackend *getQmlBackend(QHash<QString, PropertyEditorQmlBackend
} }
void setupCurrentQmlBackend(PropertyEditorQmlBackend *currentQmlBackend, void setupCurrentQmlBackend(PropertyEditorQmlBackend *currentQmlBackend,
const ModelNode &selectedNode, const ModelNodes &editorNodes,
const QUrl &qmlSpecificsFile, const QUrl &qmlSpecificsFile,
const QmlModelState &currentState, const QmlModelState &currentState,
PropertyEditorView *propertyEditorView, PropertyEditorView *propertyEditorView,
@@ -551,10 +578,9 @@ void setupCurrentQmlBackend(PropertyEditorQmlBackend *currentQmlBackend,
QString currentStateName = currentState.isBaseState() ? QStringLiteral("invalid state") QString currentStateName = currentState.isBaseState() ? QStringLiteral("invalid state")
: currentState.name(); : currentState.name();
QmlObjectNode qmlObjectNode{selectedNode};
if (specificQmlData.isEmpty()) if (specificQmlData.isEmpty())
currentQmlBackend->contextObject()->setSpecificQmlData(specificQmlData); currentQmlBackend->contextObject()->setSpecificQmlData(specificQmlData);
currentQmlBackend->setup(qmlObjectNode, currentStateName, qmlSpecificsFile, propertyEditorView); currentQmlBackend->setup(editorNodes, currentStateName, qmlSpecificsFile, propertyEditorView);
currentQmlBackend->contextObject()->setSpecificQmlData(specificQmlData); currentQmlBackend->contextObject()->setSpecificQmlData(specificQmlData);
} }
@@ -634,7 +660,7 @@ void PropertyEditorView::handleToolBarAction(int action)
void PropertyEditorView::setupQmlBackend() void PropertyEditorView::setupQmlBackend()
{ {
#ifdef QDS_USE_PROJECTSTORAGE #ifdef QDS_USE_PROJECTSTORAGE
const NodeMetaInfo commonAncestor = PropertyEditorQmlBackend::findCommonAncestor(activeNode()); const NodeMetaInfo commonAncestor = findCommonAncestor(activeNode());
auto selfAndPrototypes = commonAncestor.selfAndPrototypes(); auto selfAndPrototypes = commonAncestor.selfAndPrototypes();
bool isEditableComponent = activeNode().isComponent() bool isEditableComponent = activeNode().isComponent()
&& !QmlItemNode(activeNode()).isEffectItem(); && !QmlItemNode(activeNode()).isEffectItem();
@@ -648,7 +674,7 @@ void PropertyEditorView::setupQmlBackend()
m_stackedWidget, m_stackedWidget,
this); this);
setupCurrentQmlBackend(currentQmlBackend, setupCurrentQmlBackend(currentQmlBackend,
activeNode(), currentNodes(),
QUrl::fromLocalFile(QString{specificsPath}), QUrl::fromLocalFile(QString{specificsPath}),
currentStateNode(), currentStateNode(),
this, this,
@@ -660,7 +686,7 @@ void PropertyEditorView::setupQmlBackend()
setupInsight(rootModelNode(), currentQmlBackend); setupInsight(rootModelNode(), currentQmlBackend);
#else #else
const NodeMetaInfo commonAncestor = PropertyEditorQmlBackend::findCommonAncestor(activeNode()); const NodeMetaInfo commonAncestor = findCommonAncestor(activeNode());
// qmlFileUrl is panel url. and specifics is its metainfo // qmlFileUrl is panel url. and specifics is its metainfo
const auto [qmlFileUrl, specificsClassMetaInfo] = PropertyEditorQmlBackend::getQmlUrlForMetaInfo( const auto [qmlFileUrl, specificsClassMetaInfo] = PropertyEditorQmlBackend::getQmlUrlForMetaInfo(
@@ -681,7 +707,7 @@ void PropertyEditorView::setupQmlBackend()
this); this);
setupCurrentQmlBackend(currentQmlBackend, setupCurrentQmlBackend(currentQmlBackend,
activeNode(), currentNodes(),
qmlSpecificsFile, qmlSpecificsFile,
currentStateNode(), currentStateNode(),
this, this,
@@ -788,10 +814,12 @@ QList<ModelNode> PropertyEditorView::currentNodes() const
void PropertyEditorView::selectedNodesChanged(const QList<ModelNode> &, void PropertyEditorView::selectedNodesChanged(const QList<ModelNode> &,
const QList<ModelNode> &) const QList<ModelNode> &)
{ {
if (m_isSelectionLocked) if (!m_isSelectionLocked)
return; 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 bool PropertyEditorView::isNodeOrChildSelected(const ModelNode &node) const

View File

@@ -143,6 +143,8 @@ private: //functions
static PropertyEditorView *instance(); static PropertyEditorView *instance();
NodeMetaInfo findCommonAncestor(const ModelNode &node);
private: //variables private: //variables
AsynchronousImageCache &m_imageCache; AsynchronousImageCache &m_imageCache;
ModelNode m_activeNode; ModelNode m_activeNode;

View File

@@ -41,11 +41,13 @@ QmlMaterialNodeProxy::QmlMaterialNodeProxy()
QmlMaterialNodeProxy::~QmlMaterialNodeProxy() = default; 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 const QmlObjectNode material = objectNode.metaInfo().isQtQuick3DMaterial() ? objectNode
: QmlObjectNode{}; : QmlObjectNode{};
setMaterialNode(material); setMaterialNode(material);
setEditorNodes(editorNodes);
updatePossibleTypes(); updatePossibleTypes();
updatePreviewModel(); updatePreviewModel();
} }
@@ -55,6 +57,11 @@ ModelNode QmlMaterialNodeProxy::materialNode() const
return m_materialNode; return m_materialNode;
} }
ModelNodes QmlMaterialNodeProxy::editorNodes() const
{
return m_editorNodes;
}
void QmlMaterialNodeProxy::setPossibleTypes(const QStringList &types) void QmlMaterialNodeProxy::setPossibleTypes(const QStringList &types)
{ {
if (types == m_possibleTypes) if (types == m_possibleTypes)
@@ -81,7 +88,7 @@ void QmlMaterialNodeProxy::updatePossibleTypes()
} }
const QString &matType = materialNode().simplifiedTypeName(); 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) { bool allAreBasic = Utils::allOf(selectedNodes, [&](const ModelNode &node) {
return basicTypes.contains(node.simplifiedTypeName()); return basicTypes.contains(node.simplifiedTypeName());
}); });
@@ -275,6 +282,11 @@ void QmlMaterialNodeProxy::setMaterialNode(const QmlObjectNode &material)
emit materialNodeChanged(); emit materialNodeChanged();
} }
void QmlMaterialNodeProxy::setEditorNodes(const ModelNodes &editorNodes)
{
m_editorNodes = editorNodes;
}
bool QmlMaterialNodeProxy::hasQuick3DImport() const bool QmlMaterialNodeProxy::hasQuick3DImport() const
{ {
return materialNode().isValid() && materialNode().model()->hasImport("QtQuick3D"_L1); return materialNode().isValid() && materialNode().model()->hasImport("QtQuick3D"_L1);

View File

@@ -35,11 +35,12 @@ public:
explicit QmlMaterialNodeProxy(); explicit QmlMaterialNodeProxy();
~QmlMaterialNodeProxy() override; ~QmlMaterialNodeProxy() override;
void setup(const QmlObjectNode &objectNode); void setup(const ModelNodes &editorNodes);
QStringList possibleTypes() const { return m_possibleTypes; } QStringList possibleTypes() const { return m_possibleTypes; }
ModelNode materialNode() const; ModelNode materialNode() const;
ModelNodes editorNodes() const;
int possibleTypeIndex() const { return m_possibleTypeIndex; } int possibleTypeIndex() const { return m_possibleTypeIndex; }
@@ -67,15 +68,15 @@ private: // Methods
void updatePossibleTypeIndex(); void updatePossibleTypeIndex();
void updatePreviewModel(); void updatePreviewModel();
void setMaterialNode(const QmlObjectNode &material); void setMaterialNode(const QmlObjectNode &material);
void setEditorNodes(const ModelNodes &editorNodes);
bool hasQuick3DImport() const; bool hasQuick3DImport() const;
AbstractView *materialView() const; AbstractView *materialView() const;
private: private:
bool m_has3DModelSelection = false;
QmlObjectNode m_materialNode; QmlObjectNode m_materialNode;
ModelNodes m_editorNodes;
QStringList m_possibleTypes; QStringList m_possibleTypes;
int m_possibleTypeIndex = -1; int m_possibleTypeIndex = -1;

View File

@@ -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(); m_subselection.clear();
@@ -61,12 +67,22 @@ ModelNode QmlModelNodeProxy::modelNode() const
return m_qmlObjectNode.modelNode(); return m_qmlObjectNode.modelNode();
} }
ModelNodes QmlModelNodeProxy::editorNodes() const
{
return m_editorNodes;
}
ModelNode QmlModelNodeProxy::singleSelectedNode() const
{
return multiSelection() ? ModelNode{} : modelNode();
}
bool QmlModelNodeProxy::multiSelection() const bool QmlModelNodeProxy::multiSelection() const
{ {
if (!m_qmlObjectNode.isValid()) if (!m_qmlObjectNode.isValid())
return false; return false;
return m_qmlObjectNode.view()->selectedModelNodes().size() > 1; return editorNodes().size() > 1;
} }
QString QmlModelNodeProxy::nodeId() const QString QmlModelNodeProxy::nodeId() const

View File

@@ -22,7 +22,8 @@ class QMLDESIGNER_EXPORT QmlModelNodeProxy : public QObject
public: public:
explicit QmlModelNodeProxy(QObject *parent = nullptr); explicit QmlModelNodeProxy(QObject *parent = nullptr);
void setup(const QmlObjectNode &objectNode); void setup(const ModelNode &node);
void setup(const ModelNodes &editorNodes);
static void registerDeclarativeType(); static void registerDeclarativeType();
@@ -33,6 +34,8 @@ public:
QmlObjectNode qmlObjectNode() const; QmlObjectNode qmlObjectNode() const;
ModelNode modelNode() const; ModelNode modelNode() const;
ModelNodes editorNodes() const;
ModelNode singleSelectedNode() const;
bool multiSelection() const; bool multiSelection() const;
@@ -81,6 +84,7 @@ private:
PropertyEditorSubSelectionWrapper *findWrapper(int internalId) const; PropertyEditorSubSelectionWrapper *findWrapper(int internalId) const;
QmlObjectNode m_qmlObjectNode; QmlObjectNode m_qmlObjectNode;
ModelNodes m_editorNodes;
QList<QSharedPointer<PropertyEditorSubSelectionWrapper>> m_subselection; QList<QSharedPointer<PropertyEditorSubSelectionWrapper>> m_subselection;
}; };

View File

@@ -211,7 +211,7 @@ void TextureEditorQmlBackend::setup(const QmlObjectNode &selectedTextureNode, co
} }
// model node // model node
m_backendModelNode.setup(selectedTextureNode.modelNode()); m_backendModelNode.setup(selectedTextureNode);
context()->setContextProperty("modelNodeBackend", &m_backendModelNode); context()->setContextProperty("modelNodeBackend", &m_backendModelNode);
context()->setContextProperty("hasTexture", QVariant(true)); context()->setContextProperty("hasTexture", QVariant(true));