aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqmlvmemetaobject.cpp
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2022-10-05 17:02:03 +0200
committerUlf Hermann <ulf.hermann@qt.io>2022-10-19 20:32:01 +0200
commita824a6f060ec3a0000d7349649a3ab9e0570ecaa (patch)
tree9574d4f96d52bf0de792bab52d42bd35a08027e6 /src/qml/qml/qqmlvmemetaobject.cpp
parente89a06753c772bd96b3299e03b2f7ad78ffc9fb9 (diff)
Recursively write back value types and sequences
Both types have functionality to write themselves back to the properties they were loaded from on change, but so far we could not nest those writes. [ChangeLog][QtQml] You can now assign to properties of nested value types and to elements of containers from QML functions. You cannot, however, take references of such values and elements. This is in contrast to non-nested value types and the containers themselves. However, passing references of value types and containers around generally leads to very confusing effects. Don't do this. Fixes: QTBUG-99766 Change-Id: I74cb89e5c3d733b0b61e42969d617b2ecc1562f4 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/qml/qml/qqmlvmemetaobject.cpp')
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp26
1 files changed, 24 insertions, 2 deletions
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index 3db088705e..6ba75d78bb 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -19,6 +19,7 @@
#include <private/qv4sequenceobject_p.h>
#include <private/qqmlpropertycachecreator_p.h>
#include <private/qqmlpropertycachemethodarguments_p.h>
+#include <private/qqmlvaluetypewrapper_p.h>
#include <climits> // for CHAR_BIT
@@ -1136,6 +1137,7 @@ void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value)
// automatically released by the engine until no other references to it exist.
if (QV4::VariantObject *v = const_cast<QV4::VariantObject*>(value.as<QV4::VariantObject>())) {
v->addVmePropertyReference();
+ md->set(engine, id, value);
} else if (QV4::QObjectWrapper *wrapper = const_cast<QV4::QObjectWrapper*>(value.as<QV4::QObjectWrapper>())) {
// We need to track this QObject to signal its deletion
valueObject = wrapper->object();
@@ -1145,13 +1147,33 @@ void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value)
guard = new QQmlVMEVariantQObjectPtr();
varObjectGuards.append(guard);
}
+ md->set(engine, id, value);
+ } else if (const QV4::Sequence *sequence = value.as<QV4::Sequence>()) {
+ QV4::Heap::Sequence *p = sequence->d();
+ if (p->enforcesLocation()) {
+ // If the sequence enforces its location, we don't want it to be updated anymore after
+ // being written to a property.
+ md->set(engine, id, QV4::ReferenceObject::detached(p));
+ } else {
+ // Otherwise, make sure the reference carries some value so that we can still call
+ // toVariant() on it (see note in QV4::SequencePrototype::toVariant).
+ if (!p->hasData())
+ QV4::ReferenceObject::readReference(p);
+ md->set(engine, id, p);
+ }
+ } else if (const QV4::QQmlValueTypeWrapper *wrapper = value.as<QV4::QQmlValueTypeWrapper>()) {
+ // If the value type enforces its location, we don't want it to be updated anymore after
+ // being written to a property.
+ QV4::Heap::QQmlValueTypeWrapper *p = wrapper->d();
+ md->set(engine, id, p->enforcesLocation() ? QV4::ReferenceObject::detached(p) : p);
+ } else {
+ md->set(engine, id, value);
}
if (guard)
guard->setGuardedValue(valueObject, this, id);
- // Write the value and emit change signal as appropriate.
- md->set(engine, id, value);
+ // Emit change signal as appropriate.
activate(object, methodOffset() + id, nullptr);
}