diff options
author | Dominik Holland <dominik.holland@qt.io> | 2023-07-07 17:42:13 +0200 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2023-07-17 15:07:27 +0000 |
commit | f846ab8f5174a03ec4667643495e847691909c32 (patch) | |
tree | 54a29e034af635a892da52afc728df049dafe73c | |
parent | bbe85b8ac905ab395fd59b9d8de4c00447a3299c (diff) |
Fix signal handling in the QIfSimulationProxy
Forwarding the signal emitted in the QML simulation to the actual
instance didn't work correctly in all circumstances.
Change-Id: I3300200bf4c3354e06903cc7265dced2c7de4e83
Reviewed-by: Robert Griebl <robert.griebl@qt.io>
(cherry picked from commit 92ecb5ceeccbec54c80c014ea77f2c9d378ec4ac)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r-- | src/interfaceframework/qifsimulationproxy.cpp | 47 | ||||
-rw-r--r-- | tests/auto/core/qifsimulationengine/tst_qifsimulationengine.cpp | 40 |
2 files changed, 82 insertions, 5 deletions
diff --git a/src/interfaceframework/qifsimulationproxy.cpp b/src/interfaceframework/qifsimulationproxy.cpp index 62a56cde..e02ec597 100644 --- a/src/interfaceframework/qifsimulationproxy.cpp +++ b/src/interfaceframework/qifsimulationproxy.cpp @@ -62,15 +62,52 @@ int QIfSimulationProxyBase::qt_metacall(QMetaObject::Call call, int methodId, vo } if (call == QMetaObject::InvokeMetaMethod) { - // When a forwarded signal from the registered instance gets in. Directly call the signal here as well - if (sender() == m_instance) { + // The qt_metacall is only used for the dynamic calling of methods and signatures + // e.g. a signal or method called from QML + // But it is also called by QObject::activate when a signal is emitted. In case the signal + // is connected, the slot is called directly and qt_metacall is NOT called. + // QObject::activate will call qt_metacall for all signatures for the signal which are not + // connected. + // If qt_metacall gets called and the call is from our proxied instance, the signal name + // matches and the signal arguments match as well (either completely or just partially) + // The call got forwarded from the QObject::activate of the proxied instance. In this + // case we don't forward the call again to the proxied instance, but handle it ourself. + auto tryHandleCall = [=]() + { + if (sender() != m_instance) + return false; + + QMetaMethod senderSignal = sender()->metaObject()->method(senderSignalIndex()); + QMetaMethod receiverMethod = m_staticMetaObject->method(methodId); + + if (senderSignal.name() != receiverMethod.name()) + return false; + + if (senderSignal.parameterCount() < receiverMethod.parameterCount()) + return false; + + for (int pI = 0; pI < receiverMethod.parameterCount(); pI++) { + if (senderSignal.parameterMetaType(pI) != receiverMethod.parameterMetaType(pI)) + return false; + } + +// qDebug() << "HANDLE CALL" << methodId << m_staticMetaObject->method(methodId).name() << sender() << m_instance; // The static MetaObject uses local ids, so we need to subtract the offset QMetaObject::activate(this, m_staticMetaObject, methodId - m_staticMetaObject->methodOffset(), a); + return true; + }; + + if (tryHandleCall()) { return 0; + } else { + // Forward the signal to the proxied instance. + + // As we don't derive from the MetaObject of m_instance, we need to use the methodMap to + // translate our methodId to the methodId for m_instance +// qDebug() << "FORWARD CALL" << methodId << m_staticMetaObject->method(methodId).name() << sender() << m_instance; + int ret = m_instance->qt_metacall(call, m_methodMap.key(methodId), a); + return ret; } - // As we don't derive from the MetaObject of m_instance, we need to use the methodMap to - // translate our methodId to the methodId for m_instance - return m_instance->qt_metacall(call, m_methodMap.key(methodId), a); } return m_instance->qt_metacall(call, methodId, a); } diff --git a/tests/auto/core/qifsimulationengine/tst_qifsimulationengine.cpp b/tests/auto/core/qifsimulationengine/tst_qifsimulationengine.cpp index fce1776e..ab78c1c5 100644 --- a/tests/auto/core/qifsimulationengine/tst_qifsimulationengine.cpp +++ b/tests/auto/core/qifsimulationengine/tst_qifsimulationengine.cpp @@ -174,6 +174,8 @@ signals: void simpleFunctionCalled(); void functionWithArgumentsCalled(int intArgument, const QString &stringArgument); void functionWithReturnValueCalled(int intArgument); + void somethingHappened(const QString &string = QString()); + void otherSignal(const QString &string); public: int m_callCounter = 0; @@ -240,6 +242,7 @@ private Q_SLOTS: void testPropertyWriteDerived_data(); void testPropertyWriteDerived(); void testAnimations(); + void testSignals(); void testFunctionCalls_data(); void testFunctionCalls(); @@ -641,6 +644,43 @@ void tst_QIfSimulationEngine::testAnimations() QVERIFY2(spy.count() >= 2, qPrintable(QStringLiteral("Emitted signals: ") + QString::number(spy.count()))); } +void tst_QIfSimulationEngine::testSignals() +{ + QIfSimulationEngine engine; + + SimpleAPI testObject; + engine.registerSimulationInstance<SimpleAPI>(&testObject, "TestAPI", 1, 0, "SimpleAPI"); + + QByteArray qml ("import QtQuick; \n\ + import TestAPI; \n\ + Item { \n\ + SimpleAPI { \n\ + onTestPropertyChanged: { \n\ + somethingHappened('test') \n\ + otherSignal('test') \n\ + } \n\ + } \n\ + }"); + + QQmlComponent component(&engine); + component.setData(qml, QUrl()); + QScopedPointer<QObject> obj(component.create()); + QVERIFY2(obj, qPrintable(component.errorString())); + + QSignalSpy somethingHappenedSpy(&testObject, SIGNAL(somethingHappened(QString))); + QSignalSpy otherSignalSpy(&testObject, SIGNAL(otherSignal(QString))); + + QVERIFY(somethingHappenedSpy.isValid()); + QVERIFY(otherSignalSpy.isValid()); + testObject.setTestProperty(123); + QCOMPARE(somethingHappenedSpy.count(), 1); + QCOMPARE(somethingHappenedSpy.at(0).count(), 1); + QCOMPARE(somethingHappenedSpy.at(0).at(0).toString(), QString("test")); + QCOMPARE(otherSignalSpy.count(), 1); + QCOMPARE(otherSignalSpy.at(0).count(), 1); + QCOMPARE(otherSignalSpy.at(0).at(0).toString(), QString("test")); +} + void tst_QIfSimulationEngine::testFunctionCalls_data() { QTest::addColumn<QByteArray>("function"); |