aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDominik Holland <dominik.holland@pelagicore.com>2018-12-21 11:34:57 +0100
committerRobert Griebl <robert.griebl@pelagicore.com>2019-01-12 12:29:35 +0000
commit5bca991b07903942fb48450f3e867b5a3c30d1e5 (patch)
tree386f1ac699be210ccb4fdf1780fa024ae5a09ebd
parent34e23de0523e0a4250584a74d56cab35ca28f3a7 (diff)
Fix a crash in the QIviSimulationEngine when using animations
The code handles now read and write of properties using the staticMetaObject correctly. Added more internal documentation for it and a autotest. Change-Id: Iddceeebcf5317ddb3a6986d82febc81bd374b575 Fixes: AUTOSUITE-727 Reviewed-by: Robert Griebl <robert.griebl@pelagicore.com>
-rw-r--r--src/ivicore/qivisimulationproxy.cpp14
-rw-r--r--src/ivicore/qivisimulationproxy.h6
-rw-r--r--tests/auto/core/qivisimulationengine/tst_qivisimulationengine.cpp38
3 files changed, 55 insertions, 3 deletions
diff --git a/src/ivicore/qivisimulationproxy.cpp b/src/ivicore/qivisimulationproxy.cpp
index 8800f78..7f2ab00 100644
--- a/src/ivicore/qivisimulationproxy.cpp
+++ b/src/ivicore/qivisimulationproxy.cpp
@@ -82,6 +82,18 @@ int QIviSimulationProxyBase::qt_metacall(QMetaObject::Call call, int methodId, v
if (m_noSimulationEngine)
return -1;
+ // Special handling for the artificial "Base" property.
+ // All other properties are forwarded to the qt_metacall generated by moc which translates the
+ // absolute id's back to relative ones
+ if (call == QMetaObject::ReadProperty || call == QMetaObject::WriteProperty) {
+ int basePropertyIndex = m_staticMetaObject->indexOfProperty("Base");
+ if (methodId == basePropertyIndex) {
+ void *_v = a[0];
+ *reinterpret_cast< QObject**>(_v) = m_instance;
+ return -1;
+ }
+ }
+
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) {
@@ -89,6 +101,8 @@ int QIviSimulationProxyBase::qt_metacall(QMetaObject::Call call, int methodId, v
QMetaObject::activate(this, m_staticMetaObject, methodId - m_staticMetaObject->methodOffset(), a);
return 0;
}
+ // 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/src/ivicore/qivisimulationproxy.h b/src/ivicore/qivisimulationproxy.h
index f441b1c..8e23e9c 100644
--- a/src/ivicore/qivisimulationproxy.h
+++ b/src/ivicore/qivisimulationproxy.h
@@ -152,9 +152,9 @@ namespace qtivi_private {
return;
Q_ASSERT_X(m_instance, "qt_static_metacall()", "QIviSimulationProxy::registerInstance needs to be called first");
// As the class acts as a proxy, forward all calls here to the registered instance
- if (call == QMetaObject::ReadProperty) {
- void *_v = a[0];
- *reinterpret_cast< T**>(_v) = m_instance;
+ // The methodIds start at 0 for the first property of this class. We need to add the
+ // offset to get the absolute property index for the normal qt_metacall
+ if (call == QMetaObject::ReadProperty || call == QMetaObject::WriteProperty) {
obj->qt_metacall(call, methodId + staticMetaObject.propertyOffset(), a);
return;
}
diff --git a/tests/auto/core/qivisimulationengine/tst_qivisimulationengine.cpp b/tests/auto/core/qivisimulationengine/tst_qivisimulationengine.cpp
index a38bc9d..3bd1299 100644
--- a/tests/auto/core/qivisimulationengine/tst_qivisimulationengine.cpp
+++ b/tests/auto/core/qivisimulationengine/tst_qivisimulationengine.cpp
@@ -252,6 +252,7 @@ private Q_SLOTS:
void testPropertyWrite();
void testPropertyWriteDerived_data();
void testPropertyWriteDerived();
+ void testAnimations();
void testFunctionCalls_data();
void testFunctionCalls();
@@ -560,6 +561,43 @@ void tst_QIviSimulationEngine::testPropertyWriteDerived()
QCOMPARE(obj->property("bindingProperty"), value);
}
+//Animations use a different way to access the properties, so we need to test this explicitly
+void tst_QIviSimulationEngine::testAnimations()
+{
+ QIviSimulationEngine engine;
+
+ DerivedClass testObject;
+ engine.registerSimulationInstance<DerivedClass>(&testObject, "TestAPI", 1, 0, "DerivedClass");
+ QSignalSpy spy(&testObject, SIGNAL(propertyInBaseChanged(int)));
+
+ QByteArray qml ("import QtQuick 2.0; \n\
+ import TestAPI 1.0; \n\
+ DerivedClass { \n\
+ id: backend \n\
+ property var animation: SequentialAnimation { \n\
+ NumberAnimation { target: backend; property: \"propertyInBase\"; from: 0; to: 130; duration: 500 } \n\
+ ScriptAction { script: backend.animationDone() } \n\
+ running: true \n\
+ } \n\
+ signal animationDone(); \n\
+ }");
+
+ QQmlComponent component(&engine);
+ component.setData(qml, QUrl());
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY2(obj, qPrintable(component.errorString()));
+
+ //wait until the animation ended
+ QSignalSpy animationSpy(obj.data(), SIGNAL(animationDone()));
+ animationSpy.wait();
+
+ //Check that the animation has reached it's final value
+ QCOMPARE(obj->property("propertyInBase"), 130);
+
+ //we expect at least 10 animation steps
+ QVERIFY2(spy.count() > 10, qPrintable(QStringLiteral("Emitted signals: ") + QString::number(spy.count())));
+}
+
void tst_QIviSimulationEngine::testFunctionCalls_data()
{
QTest::addColumn<QByteArray>("function");