diff options
author | Fabian Kosmale <fabian.kosmale@qt.io> | 2023-04-14 14:29:19 +0200 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2023-04-19 20:05:46 +0000 |
commit | 35de689c6295c77c1588ebb1d2af6d5e6f23e954 (patch) | |
tree | b275c19327d08fa0b7472540f88fe333c4fdd51b | |
parent | 08cf921344c859e73816a563b3e8dd7954369545 (diff) |
Binding: Reevaluate when before the target changes
...and do not warn about missing properties if when is disabled. Besides
avoiding spurious warnings, this also avoids modifying a property only
to restore its binding/value directly afterwards.
Note that when the binding gets re-enabled, we still trigger the
warning.
Fixes: QTBUG-112860
Change-Id: I5ddd32f2de2dec9da372b08ab4bb5bdb88873e51
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
(cherry picked from commit 82f2ee8027f733cec5961aac27a171cf0b78a70b)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r-- | src/qml/types/qqmlbind.cpp | 21 | ||||
-rw-r--r-- | tests/auto/qml/qqmlbinding/data/whenEvaluatedEarlyEnough.qml | 23 | ||||
-rw-r--r-- | tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp | 14 |
3 files changed, 56 insertions, 2 deletions
diff --git a/src/qml/types/qqmlbind.cpp b/src/qml/types/qqmlbind.cpp index f69462b937..8bfe9d4c4e 100644 --- a/src/qml/types/qqmlbind.cpp +++ b/src/qml/types/qqmlbind.cpp @@ -463,10 +463,26 @@ void QQmlBind::setObject(QObject *obj) eval(); d->when = true; } + /* if "when" and "target" depend on the same property, we might + end up here before we could have updated "when". So reevaluate + when manually here. + */ + const QQmlProperty whenProp(this, QLatin1StringView("when")); + const auto potentialWhenBinding = QQmlAnyBinding::ofProperty(whenProp); + if (auto abstractBinding = potentialWhenBinding.asAbstractBinding()) { + QQmlBinding *binding = static_cast<QQmlBinding *>(abstractBinding); + if (binding->hasValidContext()) { + const auto boolType = QMetaType::fromType<bool>(); + bool when; + binding->evaluate(&when, boolType); + d->when = when; + } + } d->obj = obj; if (d->componentComplete) { setTarget(QQmlProperty(d->obj, d->propName, qmlContext(this))); - d->validate(this); + if (d->when) + d->validate(this); } eval(); } @@ -520,7 +536,8 @@ void QQmlBind::setProperty(const QString &p) d->propName = p; if (d->componentComplete) { setTarget(QQmlProperty(d->obj, d->propName, qmlContext(this))); - d->validate(this); + if (d->when) + d->validate(this); } eval(); } diff --git a/tests/auto/qml/qqmlbinding/data/whenEvaluatedEarlyEnough.qml b/tests/auto/qml/qqmlbinding/data/whenEvaluatedEarlyEnough.qml new file mode 100644 index 0000000000..6245270e14 --- /dev/null +++ b/tests/auto/qml/qqmlbinding/data/whenEvaluatedEarlyEnough.qml @@ -0,0 +1,23 @@ +import QtQuick + +Item { + id: root + property bool toggle: true + property bool forceEnable: false + + Item { + id: item1 + property int i + } + + Item { + id: item2 + } + + Binding { + target: root.toggle ? item1 : item2 + when: root.forceEnable || (root.toggle ? item1 : item2).hasOwnProperty("i") + property: "i" + value: 42 + } +} diff --git a/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp b/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp index a6b734acd7..2d6d47c5b1 100644 --- a/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp +++ b/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp @@ -38,6 +38,7 @@ private slots: void intOverflow(); void generalizedGroupedProperties(); void localSignalHandler(); + void whenEvaluatedEarlyEnough(); private: QQmlEngine engine; @@ -596,6 +597,19 @@ void tst_qqmlbinding::localSignalHandler() QCOMPARE(o->property("output").toString(), QStringLiteral("abc")); } +void tst_qqmlbinding::whenEvaluatedEarlyEnough() +{ + QQmlEngine e; + QQmlComponent c(&e, testFileUrl("whenEvaluatedEarlyEnough.qml")); + QTest::failOnWarning(QRegularExpression(".*")); + std::unique_ptr<QObject> root { c.create() }; + root->setProperty("toggle", false); // should not cause warnings + // until "when" is actually true + QTest::ignoreMessage(QtMsgType::QtWarningMsg, + QRegularExpression(".*QML Binding: Property 'i' does not exist on Item.*")); + root->setProperty("forceEnable", true); +} + QTEST_MAIN(tst_qqmlbinding) #include "tst_qqmlbinding.moc" |