From 58662eb6265aaecf77ab134c849ef6368908cab3 Mon Sep 17 00:00:00 2001 From: Rafal Stawarski Date: Tue, 11 Mar 2025 12:16:11 +0100 Subject: [PATCH] DynamicPropertiesModel: handle instance property changes Instance property changes are now taken into account for dynamic properties. This avoids situations where the property value is cleared unintentionally. Task-number: QDS-13513 Change-Id: I2b52ae2db721bf09b2310ba7c5bd4b3e0de3fab2 Reviewed-by: Thomas Hartmann --- .../dynamicpropertiesitem.cpp | 6 +- .../connectioneditor/dynamicpropertiesitem.h | 3 +- .../dynamicpropertiesmodel.cpp | 15 +++++ .../connectioneditor/dynamicpropertiesmodel.h | 2 + .../dynamicpropertiesproxymodel.cpp | 66 +++++++++++-------- .../propertyeditor/propertyeditorview.cpp | 2 + 6 files changed, 66 insertions(+), 28 deletions(-) diff --git a/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesitem.cpp b/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesitem.cpp index 1694231630c..94bd7e9feaa 100644 --- a/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesitem.cpp +++ b/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesitem.cpp @@ -19,7 +19,8 @@ QHash DynamicPropertiesItem::roleNames() return {{TargetNameRole, "target"}, {PropertyNameRole, "name"}, {PropertyTypeRole, "type"}, - {PropertyValueRole, "value"}}; + {PropertyValueRole, "value"}, + {InstancePropertyValueRole, "instanceValue"}}; } QStringList DynamicPropertiesItem::headerLabels() @@ -58,6 +59,9 @@ void DynamicPropertiesItem::updateProperty(const AbstractProperty &property) setData(property.name().toByteArray(), PropertyNameRole); setData(property.dynamicTypeName(), PropertyTypeRole); + const auto qmlObjectNode = QmlObjectNode(property.parentModelNode()); + setData(qmlObjectNode.instanceValue(property.name()), InstancePropertyValueRole); + if (property.isVariantProperty()) { if (std::optional nodeInState = parentIfNotDefaultState(property)) setData(nodeInState->modelValue(property.name()), PropertyValueRole); diff --git a/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesitem.h b/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesitem.h index 9d95a8d9e4d..f231f69adbd 100644 --- a/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesitem.h +++ b/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesitem.h @@ -18,7 +18,8 @@ public: TargetNameRole, PropertyNameRole, PropertyTypeRole, - PropertyValueRole + PropertyValueRole, + InstancePropertyValueRole }; static QHash roleNames(); diff --git a/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.cpp b/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.cpp index c4307a07182..7606456871d 100644 --- a/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.cpp +++ b/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.cpp @@ -355,6 +355,21 @@ void DynamicPropertiesModel::dispatchPropertyChanges(const AbstractProperty &abs } } +void DynamicPropertiesModel::handleInstancePropertyChanged(const ModelNode &modelNode, + PropertyNameView propertyName) +{ + if (modelNode != singleSelectedNode()) + return; + + QmlObjectNode qmlObjectNode(modelNode); + if (qmlObjectNode.isValid() && qmlObjectNode.currentState().isValid()) { + const AbstractProperty property = modelNode.property(propertyName); + if (property.isDynamic()) { + updateItem(property); + } + } +} + const QList DynamicPropertiesModel::selectedNodes() const { if (m_explicitSelection) diff --git a/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.h b/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.h index c1afecb0cd6..04a98b9c36e 100644 --- a/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.h +++ b/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.h @@ -57,6 +57,8 @@ public: void dispatchPropertyChanges(const AbstractProperty &abstractProperty); + void handleInstancePropertyChanged(const ModelNode &modelNode, PropertyNameView propertyName); + protected: QHash roleNames() const override; diff --git a/src/plugins/qmldesigner/components/propertyeditor/dynamicpropertiesproxymodel.cpp b/src/plugins/qmldesigner/components/propertyeditor/dynamicpropertiesproxymodel.cpp index 8c6f272fa91..4cf0ff9ce3e 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/dynamicpropertiesproxymodel.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/dynamicpropertiesproxymodel.cpp @@ -71,8 +71,10 @@ void DynamicPropertiesProxyModel::initModel(DynamicPropertiesModel *model) connect(m_model, &QAbstractItemModel::rowsInserted, this, &QAbstractItemModel::rowsInserted); - connect(m_model, &QAbstractItemModel::dataChanged, - this, [this](const QModelIndex &topLeft, const QModelIndex &, const QList &) { + connect(m_model, + &QAbstractItemModel::dataChanged, + this, + [this](const QModelIndex &topLeft, const QModelIndex &, const QList &) { emit dataChanged(index(topLeft.row(), 0), index(topLeft.row(), 0), { propertyNameRole, propertyTypeRole, @@ -302,19 +304,28 @@ void DynamicPropertyRow::setupBackendValue() if (node != m_backendValue->modelNode()) m_backendValue->setModelNode(node); - QVariant modelValue = QmlObjectNode{property.parentModelNode()}.modelValue(property.name()); + m_backendValue->setValue({}); - const bool isBound = QmlObjectNode{property.parentModelNode()}.hasBindingProperty(property.name()); + auto qmlObjectNode = QmlObjectNode{property.parentModelNode()}; + auto propertyName = property.name(); - if (modelValue != m_backendValue->value()) { - m_backendValue->setValue({}); - m_backendValue->setValue(modelValue); - } + if (qmlObjectNode.propertyAffectedByCurrentState(propertyName) + && !(qmlObjectNode.hasBindingProperty(propertyName))) { + m_backendValue->setValue(qmlObjectNode.modelValue(propertyName)); + } else + m_backendValue->setValue(qmlObjectNode.instanceValue(propertyName)); - if (isBound) { - QString expression = QmlObjectNode{property.parentModelNode()}.expression(property.name()); - if (m_backendValue->expression() != expression) - m_backendValue->setExpression(expression); + if (qmlObjectNode.currentState().isBaseState() + && qmlObjectNode.modelNode().property(propertyName).isBindingProperty()) { + m_backendValue->setExpression( + qmlObjectNode.modelNode().bindingProperty(propertyName).expression()); + } else { + if (qmlObjectNode.hasBindingProperty(propertyName) + && !qmlObjectNode.expression(propertyName).isEmpty()) { + m_backendValue->setExpression(qmlObjectNode.expression(propertyName)); + } else { + m_backendValue->setExpression(qmlObjectNode.instanceValue(propertyName).toString()); + } } emit m_backendValue->isBoundChanged(); @@ -342,22 +353,25 @@ void DynamicPropertyRow::commitValue(const QVariant &value) auto view = propertiesModel->view(); RewriterTransaction transaction = view->beginRewriterTransaction(__FUNCTION__); + try { - if (property.isBindingProperty()) { - convertBindingToVariantProperty(property.toBindingProperty(), value); - } else if (property.isVariantProperty()) { - VariantProperty variantProperty = property.toVariantProperty(); - QmlObjectNode objectNode = variantProperty.parentModelNode(); - if (QmlModelState::isBaseState(view->currentStateNode()) - && !(objectNode.timelineIsActive() && objectNode.currentTimeline().isRecording())) { - if (variantProperty.value() != value) - variantProperty.setDynamicTypeNameAndValue(variantProperty.dynamicTypeName(), value); - } else { - QTC_CHECK(objectNode.isValid()); - PropertyNameView name = variantProperty.name(); - if (objectNode.isValid() && objectNode.modelValue(name) != value) - objectNode.setVariantProperty(name, value); + QmlObjectNode objectNode = property.parentModelNode(); + if (QmlModelState::isBaseState(view->currentStateNode()) + && !(objectNode.timelineIsActive() && objectNode.currentTimeline().isRecording())) { + if (property.isBindingProperty()) { + convertBindingToVariantProperty(property.toBindingProperty(), value); + } else if (property.isVariantProperty()) { + VariantProperty variantProperty = property.toVariantProperty(); + if (variantProperty.value() != value) { + variantProperty.setDynamicTypeNameAndValue(variantProperty.dynamicTypeName(), + value); + } } + } else { + QTC_CHECK(objectNode.isValid()); + PropertyNameView name = property.name(); + if (objectNode.isValid() && objectNode.modelValue(name) != value) + objectNode.setVariantProperty(name, value); } transaction.commit(); // committing in the try block } catch (Exception &e) { diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp index 09ddc373e7c..e6ef39d5864 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp @@ -1093,6 +1093,8 @@ void PropertyEditorView::instancePropertyChanged(const QListhandleInstancePropertyChanged(modelNode, propertyName); } if (changed)