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 <thomas.hartmann@qt.io>
This commit is contained in:
Rafal Stawarski
2025-03-11 11:59:22 +01:00
parent 3793bae6c7
commit e51925e4e1
7 changed files with 75 additions and 24 deletions

View File

@@ -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);
}

View File

@@ -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);
}
}
}
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

View File

@@ -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:

View File

@@ -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<Enumeration>());

View File

@@ -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;

View File

@@ -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();

View File

@@ -166,6 +166,9 @@ public:
QQuickItem *contentItem() const;
bool hasProperty(const PropertyName &name);
void createNewDynamicProperty(const PropertyName &name);
private: // functions
ServerNodeInstance(const QSharedPointer<Internal::ObjectNodeInstance> &abstractInstance);