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
Pick-to: 6.5
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>
This commit is contained in:
Fabian Kosmale 2023-04-14 14:29:19 +02:00
parent 3bd201c4da
commit 82f2ee8027
3 changed files with 56 additions and 2 deletions

View File

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

View File

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

View File

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