From e51925e4e16e74c53fd6b2f92f7703a3b16abd49 Mon Sep 17 00:00:00 2001 From: Rafal Stawarski Date: Tue, 11 Mar 2025 11:59:22 +0100 Subject: [PATCH] qmlpuppet: watch changes of new dynamic properties qmlpuppet took into account predefined properties and dynamic properties that were already defined when the instance was created. Dynamic properties created after instance creation where not considered (NodeInstanceSignalSpy wasn't watching them). With a given change, it also monitors changes of dynamic properties that are added to an existing instance, e.g. through the Property Editor. Task-number: QDS-13513 Change-Id: I50ae9c25f358378f17e08d4dd957d78db6b97b98 Reviewed-by: Thomas Hartmann --- .../instances/nodeinstanceserver.cpp | 23 ++++------- .../instances/nodeinstancesignalspy.cpp | 39 +++++++++++++++---- .../instances/nodeinstancesignalspy.h | 8 +++- .../instances/objectnodeinstance.cpp | 10 +++++ .../qmlpuppet/instances/objectnodeinstance.h | 3 ++ .../instances/servernodeinstance.cpp | 13 +++++++ .../qmlpuppet/instances/servernodeinstance.h | 3 ++ 7 files changed, 75 insertions(+), 24 deletions(-) diff --git a/src/tools/qmlpuppet/qmlpuppet/instances/nodeinstanceserver.cpp b/src/tools/qmlpuppet/qmlpuppet/instances/nodeinstanceserver.cpp index dba8c12ca3a..9d8e6e65f8e 100644 --- a/src/tools/qmlpuppet/qmlpuppet/instances/nodeinstanceserver.cpp +++ b/src/tools/qmlpuppet/qmlpuppet/instances/nodeinstanceserver.cpp @@ -916,19 +916,16 @@ void NodeInstanceServer::setInstancePropertyBinding(const PropertyBindingContain const PropertyName name = bindingContainer.name(); const QString expression = bindingContainer.expression(); - if (activeStateInstance().isValid() && !instance.isSubclassOf("QtQuick/PropertyChanges")) { bool stateBindingWasUpdated = activeStateInstance().updateStateBinding(instance, name, expression); if (!stateBindingWasUpdated) { - if (bindingContainer.isDynamic()) - Internal::QmlPrivateGate::createNewDynamicProperty(instance.internalInstance()->object(), engine(), - QString::fromUtf8(name)); + if (bindingContainer.isDynamic() && !instance.hasProperty(name)) + instance.createNewDynamicProperty(name); instance.setPropertyBinding(name, expression); } } else { - if (bindingContainer.isDynamic()) - Internal::QmlPrivateGate::createNewDynamicProperty(instance.internalInstance()->object(), engine(), - QString::fromUtf8(name)); + if (bindingContainer.isDynamic() && !instance.hasProperty(name)) + instance.createNewDynamicProperty(name); instance.setPropertyBinding(name, expression); if (instance.instanceId() == 0 && (name == "width" || name == "height")) @@ -955,17 +952,13 @@ void NodeInstanceServer::setInstancePropertyVariant(const PropertyValueContainer if (activeStateInstance().isValid() && !instance.isSubclassOf("QtQuick/PropertyChanges")) { bool stateValueWasUpdated = activeStateInstance().updateStateVariant(instance, name, value); if (!stateValueWasUpdated) { - if (valueContainer.isDynamic()) { - Internal::QmlPrivateGate::createNewDynamicProperty(instance.internalInstance()->object(), - engine(), QString::fromUtf8(name)); - } + if (valueContainer.isDynamic() && !instance.hasProperty(name)) + instance.createNewDynamicProperty(name); instance.setPropertyVariant(name, value); } } else { // base state - if (valueContainer.isDynamic()) { - Internal::QmlPrivateGate::createNewDynamicProperty(instance.internalInstance()->object(), - engine(), QString::fromUtf8(name)); - } + if (valueContainer.isDynamic() && !instance.hasProperty(name)) + instance.createNewDynamicProperty(name); instance.setPropertyVariant(name, value); } diff --git a/src/tools/qmlpuppet/qmlpuppet/instances/nodeinstancesignalspy.cpp b/src/tools/qmlpuppet/qmlpuppet/instances/nodeinstancesignalspy.cpp index 03165a9c1c5..345ee6a0ca4 100644 --- a/src/tools/qmlpuppet/qmlpuppet/instances/nodeinstancesignalspy.cpp +++ b/src/tools/qmlpuppet/qmlpuppet/instances/nodeinstancesignalspy.cpp @@ -40,16 +40,21 @@ void NodeInstanceSignalSpy::registerObject(QObject *spiedObject) index < spiedObject->metaObject()->propertyCount(); index++) { QMetaProperty metaProperty = spiedObject->metaObject()->property(index); - - if (QmlPrivateGate::isPropertyQObject(metaProperty)) { - registerChildObject(metaProperty, spiedObject); - } else { - registerProperty(metaProperty, spiedObject); - } + registerProperty(metaProperty, spiedObject); } } -void NodeInstanceSignalSpy::registerProperty(const QMetaProperty &metaProperty, QObject *spiedObject, const PropertyName &propertyPrefix) +void NodeInstanceSignalSpy::registerProperty(const QMetaProperty &metaProperty, QObject *spiedObject) +{ + if (QmlPrivateGate::isPropertyQObject(metaProperty)) { + registerChildObject(metaProperty, spiedObject); + } else { + registerSingleProperty(metaProperty, spiedObject); + } +} + +void NodeInstanceSignalSpy::registerSingleProperty( + const QMetaProperty &metaProperty, QObject *spiedObject, const PropertyName &propertyPrefix) { if (metaProperty.isReadable() && metaProperty.isWritable() && metaProperty.hasNotifySignal()) { QMetaMethod metaMethod = metaProperty.notifySignal(); @@ -77,7 +82,7 @@ void NodeInstanceSignalSpy::registerChildObject( index++) { QMetaProperty childMetaProperty = childObject->metaObject()->property(index); - registerProperty( + registerSingleProperty( childMetaProperty, childObject, PropertyName(metaProperty.name()) + '.'); } } @@ -100,5 +105,23 @@ int NodeInstanceSignalSpy::qt_metacall(QMetaObject::Call call, int methodId, voi return QObject::qt_metacall(call, methodId, a); } +void NodeInstanceSignalSpy::registerDynamicProperty( + const PropertyName &propertyName, QObject *spiedObject) +{ + if (!m_registeredObjectList.contains(spiedObject)) { + return; + } + if (m_indexPropertyHash.values().contains(propertyName)) { + return; + } + QQmlProperty qmlProperty( + spiedObject, QString::fromUtf8(propertyName), QQmlEngine::contextForObject(spiedObject)); + if (!qmlProperty.isValid()) { + return; + } + + registerProperty(qmlProperty.property(), spiedObject); +} + } // namespace Internal } // namespace QmlDesigner diff --git a/src/tools/qmlpuppet/qmlpuppet/instances/nodeinstancesignalspy.h b/src/tools/qmlpuppet/qmlpuppet/instances/nodeinstancesignalspy.h index bf704f0cc1f..e97bd515aed 100644 --- a/src/tools/qmlpuppet/qmlpuppet/instances/nodeinstancesignalspy.h +++ b/src/tools/qmlpuppet/qmlpuppet/instances/nodeinstancesignalspy.h @@ -27,9 +27,15 @@ public: int qt_metacall(QMetaObject::Call, int, void **) override; + void registerDynamicProperty(const PropertyName &propertyName, QObject *spiedObject); + protected: void registerObject(QObject *spiedObject); - void registerProperty(const QMetaProperty &metaProperty, QObject *spiedObject, const PropertyName &propertyPrefix = PropertyName()); + void registerProperty(const QMetaProperty &metaProperty, QObject *spiedObject); + void registerSingleProperty( + const QMetaProperty &metaProperty, + QObject *spiedObject, + const PropertyName &propertyPrefix = PropertyName()); void registerChildObject(const QMetaProperty &metaProperty, QObject *spiedObject); private: diff --git a/src/tools/qmlpuppet/qmlpuppet/instances/objectnodeinstance.cpp b/src/tools/qmlpuppet/qmlpuppet/instances/objectnodeinstance.cpp index 1afa8d6d3af..fb9f3cdd411 100644 --- a/src/tools/qmlpuppet/qmlpuppet/instances/objectnodeinstance.cpp +++ b/src/tools/qmlpuppet/qmlpuppet/instances/objectnodeinstance.cpp @@ -113,6 +113,11 @@ void ObjectNodeInstance::initializePropertyWatcher(const ObjectNodeInstance::Poi m_signalSpy.setObjectNodeInstance(objectNodeInstance); } +void ObjectNodeInstance::watchProperty(const PropertyName &name) +{ + m_signalSpy.registerDynamicProperty(name, object()); +} + void ObjectNodeInstance::initialize(const ObjectNodeInstance::Pointer &objectNodeInstance, InstanceContainer::NodeFlags /*flags*/) { @@ -431,6 +436,11 @@ void ObjectNodeInstance::setModifiedFlag(bool b) m_isModified = b; } +void ObjectNodeInstance::handleNewDynamicProperty(const PropertyName &name) +{ + watchProperty(name); +} + QVariant ObjectNodeInstance::convertEnumToValue(const QVariant &value, const PropertyName &name) { Q_ASSERT(value.canConvert()); diff --git a/src/tools/qmlpuppet/qmlpuppet/instances/objectnodeinstance.h b/src/tools/qmlpuppet/qmlpuppet/instances/objectnodeinstance.h index ab16d20729b..d5048686820 100644 --- a/src/tools/qmlpuppet/qmlpuppet/instances/objectnodeinstance.h +++ b/src/tools/qmlpuppet/qmlpuppet/instances/objectnodeinstance.h @@ -189,6 +189,8 @@ public: void setModifiedFlag(bool b); + void handleNewDynamicProperty(const PropertyName &name); + protected: explicit ObjectNodeInstance(QObject *object); void doResetProperty(const PropertyName &propertyName); @@ -201,6 +203,7 @@ protected: static QVariant enumationValue(const Enumeration &enumeration); void initializePropertyWatcher(const ObjectNodeInstance::Pointer &objectNodeInstance); + void watchProperty(const PropertyName &name); void ensureVector3DDotProperties(PropertyNameList &list) const; void ensureValueTypeProperties(PropertyNameList &list) const; diff --git a/src/tools/qmlpuppet/qmlpuppet/instances/servernodeinstance.cpp b/src/tools/qmlpuppet/qmlpuppet/instances/servernodeinstance.cpp index 2796674662a..f945dd64538 100644 --- a/src/tools/qmlpuppet/qmlpuppet/instances/servernodeinstance.cpp +++ b/src/tools/qmlpuppet/qmlpuppet/instances/servernodeinstance.cpp @@ -168,6 +168,19 @@ QQuickItem *ServerNodeInstance::contentItem() const return m_nodeInstance->contentItem(); } +bool ServerNodeInstance::hasProperty(const PropertyName &name) +{ + return propertyNames().contains(name); +} + +void ServerNodeInstance::createNewDynamicProperty(const PropertyName &name) +{ + auto nameStr = QString::fromUtf8(name); + auto *context = QQmlEngine::contextForObject(internalObject()); + Internal::QmlPrivateGate::createNewDynamicProperty(internalObject(), context->engine(), nameStr); + internalInstance()->handleNewDynamicProperty(name); +} + void ServerNodeInstance::updateDirtyNodeRecursive() { m_nodeInstance->updateAllDirtyNodesRecursive(); diff --git a/src/tools/qmlpuppet/qmlpuppet/instances/servernodeinstance.h b/src/tools/qmlpuppet/qmlpuppet/instances/servernodeinstance.h index 49db86ed085..b654cf36df9 100644 --- a/src/tools/qmlpuppet/qmlpuppet/instances/servernodeinstance.h +++ b/src/tools/qmlpuppet/qmlpuppet/instances/servernodeinstance.h @@ -166,6 +166,9 @@ public: QQuickItem *contentItem() const; + bool hasProperty(const PropertyName &name); + void createNewDynamicProperty(const PropertyName &name); + private: // functions ServerNodeInstance(const QSharedPointer &abstractInstance);