aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqmlpropertybinding_p.h
diff options
context:
space:
mode:
authorFabian Kosmale <fabian.kosmale@qt.io>2020-12-15 08:31:22 +0100
committerFabian Kosmale <fabian.kosmale@qt.io>2021-03-15 11:42:15 +0100
commitd64e7c9c6cd172e426b9bb2c5e45fda5e6a5bfb2 (patch)
treeb26471692f35d02351e33adcb31cd80e8cde3926 /src/qml/qml/qqmlpropertybinding_p.h
parent3b39f700fb2b4eeab60ad67a020f469e39c48eab (diff)
QQmlPropertyBinding: handle reset
Bindings are allowed to toggle between a defined state, and undefined which calls the property's reset function. Calls to the reset function must not remove the binding, even when they write to the property. To support this, we put the binding in a special undefined state, in which it is still active (and installed on the property), but does not actually provide its evaluated value to the property. Then, when the binding later becomes defined again, the binding leaves its undefined state and works normally again. Notes: - Calling the reset function during binding evaluation could have all kinds of unwelcome side-effects. We therefore have to suspend binding evaluation before the reset call (and restore that state afterwards). - QObjectCompatProperty expects that we write the current value into the propertyDataPtr. If we do not do this, it will overwrite the current value with the default constructed value of its property. Arguably, we should change the API so that we communicate that nothing has changed; but for now, we have to live with that limitation and read the current value and write it back again. - We currently do not handle the case correctly where a non-resettable property implemented via QObjectCompatProperty gets assigned undefined in a binding. Such a binding is likely unintentional (as the undefined assignment only creates a warning), and thus less of a priority. Nevertheless, a test marked with QEXPECT_FAIL is added for it. Fixes: QTBUG-91001 Change-Id: I7ecaa6c8dc1a1f1b33e67b1af65f552c4ca6ffb1 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'src/qml/qml/qqmlpropertybinding_p.h')
-rw-r--r--src/qml/qml/qqmlpropertybinding_p.h23
1 files changed, 23 insertions, 0 deletions
diff --git a/src/qml/qml/qqmlpropertybinding_p.h b/src/qml/qml/qqmlpropertybinding_p.h
index 7c7fac866a..8417a4410a 100644
--- a/src/qml/qml/qqmlpropertybinding_p.h
+++ b/src/qml/qml/qqmlpropertybinding_p.h
@@ -112,6 +112,17 @@ public:
QV4::ExecutionContext *scope, QObject *target,
QQmlPropertyIndex targetIndex);
+ static bool isUndefined(const QUntypedPropertyBinding &binding)
+ {
+ return isUndefined(QPropertyBindingPrivate::get(binding));
+ }
+
+ static bool isUndefined(const QPropertyBindingPrivate *binding)
+ {
+ if (!(binding && binding->hasCustomVTable()))
+ return false;
+ return static_cast<const QQmlPropertyBinding *>(binding)->isUndefined();
+ }
static bool doEvaluate(QMetaType metaType, QUntypedPropertyData *dataPtr, void *f) {
auto address = static_cast<std::byte*>(f);
@@ -125,17 +136,29 @@ private:
bool evaluate(QMetaType metaType, void *dataPtr);
+ Q_NEVER_INLINE void handleUndefinedAssignment(QQmlEnginePrivate *ep, void *dataPtr);
+
QString createBindingLoopErrorDescription(QJSEnginePrivate *ep);
struct TargetData {
+ enum BoundFunction : bool {
+ WithoutBoundFunction = false,
+ HasBoundFunction = true,
+ };
+ TargetData(QObject *target, QQmlPropertyIndex index, BoundFunction state)
+ : target(target), targetIndex(index), hasBoundFunction(state)
+ {}
QObject *target;
QQmlPropertyIndex targetIndex;
bool hasBoundFunction;
+ bool isUndefined = false;
};
QObject *target();
QQmlPropertyIndex targetIndex();
bool hasBoundFunction();
+ bool isUndefined() const;
+ void setIsUndefined(bool isUndefined);
static void bindingErrorCallback(QPropertyBindingPrivate *);
};