diff options
author | Ivan Solovev <ivan.solovev@qt.io> | 2023-10-04 16:57:41 +0200 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2023-10-06 20:43:26 +0000 |
commit | 2620251a7d4a638d5cc312aa522be00108209603 (patch) | |
tree | f66f41d3818717d6cff6abf6caaed25ab72864e7 | |
parent | 6e73d4e5905d524f370a1341116df47ac7e4c6ac (diff) |
SignalTransition: fix binding loops
This one is a bit special, because the setter assumes that there is a
QML engine handling the object.
As a result, creating a helper object for testing binding loops is a
bit tricky. Do it by having a helper QQmlComponent based on a qml file
with a SignalTransition object as a root element.
Fix the binding loop in the setter in a usual way.
Task-number: QTBUG-116542
Change-Id: Ibd22dee0619a69b52901e9fe2145fcfbd9dcf98c
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
(cherry picked from commit 2d459667f3e9910b63964417969b7aa4583b3ad6)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
(cherry picked from commit 1e3b63eff86a2e93089bef111102eea589d014e1)
-rw-r--r-- | src/statemachineqml/signaltransition.cpp | 7 | ||||
-rw-r--r-- | tests/auto/qml/qqmlstatemachine/data/signaltransitionhelper.qml | 10 | ||||
-rw-r--r-- | tests/auto/qml/qqmlstatemachine/tst_qqmlstatemachine.cpp | 10 |
3 files changed, 22 insertions, 5 deletions
diff --git a/src/statemachineqml/signaltransition.cpp b/src/statemachineqml/signaltransition.cpp index 593e038..d311725 100644 --- a/src/statemachineqml/signaltransition.cpp +++ b/src/statemachineqml/signaltransition.cpp @@ -89,10 +89,9 @@ const QJSValue& SignalTransition::signal() void SignalTransition::setSignal(const QJSValue &signal) { - if (m_signal.value().strictlyEquals(signal)) { - m_signal.removeBindingUnlessInWrapper(); + m_signal.removeBindingUnlessInWrapper(); + if (m_signal.valueBypassingBindings().strictlyEquals(signal)) return; - } QV4::ExecutionEngine *jsEngine = QQmlEngine::contextForObject(this)->engine()->handle(); QV4::Scope scope(jsEngine); @@ -100,7 +99,7 @@ void SignalTransition::setSignal(const QJSValue &signal) QObject *sender; QMetaMethod signalMethod; - m_signal = signal; + m_signal.setValueBypassingBindings(signal); QV4::ScopedValue value(scope, QJSValuePrivate::asReturnedValue(&signal)); // Did we get the "slot" that can be used to invoke the signal? diff --git a/tests/auto/qml/qqmlstatemachine/data/signaltransitionhelper.qml b/tests/auto/qml/qqmlstatemachine/data/signaltransitionhelper.qml new file mode 100644 index 0000000..f915cdb --- /dev/null +++ b/tests/auto/qml/qqmlstatemachine/data/signaltransitionhelper.qml @@ -0,0 +1,10 @@ +// Copyright (C) 2023 The Qt Company +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQml.StateMachine + +SignalTransition { + // Do not crash on SignalTransition without signal + onTriggered: () => {} +} diff --git a/tests/auto/qml/qqmlstatemachine/tst_qqmlstatemachine.cpp b/tests/auto/qml/qqmlstatemachine/tst_qqmlstatemachine.cpp index 81e2fb6..e9f1721 100644 --- a/tests/auto/qml/qqmlstatemachine/tst_qqmlstatemachine.cpp +++ b/tests/auto/qml/qqmlstatemachine/tst_qqmlstatemachine.cpp @@ -116,10 +116,18 @@ void tst_qqmlstatemachine::tst_bindings() QVariant signal2; QMetaObject::invokeMethod(obj.get(), "getSignal1", Q_RETURN_ARG(QVariant, signal1)); QMetaObject::invokeMethod(obj.get(), "getSignal2", Q_RETURN_ARG(QVariant, signal2)); + // The setter needs an active engine, so we use a helper component to create + // a helper instance for testing binding loops. + QQmlComponent helperComponent(&engine, testFileUrl("signaltransitionhelper.qml")); // QJSValue does not implement operator== so we supply own comparator QTestPrivate::testReadWritePropertyBasics<SignalTransition, QJSValue>( *st1, signal1.value<QJSValue>(), signal2.value<QJSValue>(), "signal", - [](QJSValue d1, QJSValue d2) { return d1.strictlyEquals(d2); }); + [](QJSValue d1, QJSValue d2) { return d1.strictlyEquals(d2); }, + [](const QJSValue &val) { return QTest::toString(val); }, + [&helperComponent]() { + return std::unique_ptr<SignalTransition>( + qobject_cast<SignalTransition*>(helperComponent.create())); + }); if (QTest::currentTestFailed()) { qWarning() << "SignalTransition::signal bindable test failed."; return; |