diff options
author | Dominik Holland <dominik.holland@pelagicore.com> | 2018-12-21 11:34:57 +0100 |
---|---|---|
committer | Robert Griebl <robert.griebl@pelagicore.com> | 2019-01-12 12:29:35 +0000 |
commit | 5bca991b07903942fb48450f3e867b5a3c30d1e5 (patch) | |
tree | 386f1ac699be210ccb4fdf1780fa024ae5a09ebd | |
parent | 34e23de0523e0a4250584a74d56cab35ca28f3a7 (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.cpp | 14 | ||||
-rw-r--r-- | src/ivicore/qivisimulationproxy.h | 6 | ||||
-rw-r--r-- | tests/auto/core/qivisimulationengine/tst_qivisimulationengine.cpp | 38 |
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"); |