summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDominik Holland <dominik.holland@qt.io>2023-07-07 17:42:13 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2023-07-17 15:07:27 +0000
commitf846ab8f5174a03ec4667643495e847691909c32 (patch)
tree54a29e034af635a892da52afc728df049dafe73c
parentbbe85b8ac905ab395fd59b9d8de4c00447a3299c (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.cpp47
-rw-r--r--tests/auto/core/qifsimulationengine/tst_qifsimulationengine.cpp40
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");