From 59ed8c355b99df0b949003a438ab850274261aa0 Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Thu, 12 Jan 2012 20:01:15 +0100 Subject: Make it possible to handle pointers to QObject derived in QML. This way, properties of QObject derived types can be read in QML code for example: Q_PROPERTY(MyObject* obj READ obj CONSTANT) Previously, only QObject* types could be read by QML: Q_PROPERTY(QObject* obj READ obj CONSTANT) This meant that multiple properties and methods had to be created for classes which were relevant to both QML and non-QML code. This patch lifts that restriction. As a consequence, we can also remove a Q_EXPECT_FAIL from the qqmllanguage unit test. That test was introduced in commit 92562eacbc3c (Allow signal parameters which are custom QML object-types, 2012-07-13) to document knowledge of the limitation while fixing it as much as possible. Task-number: QTBUG-26662 Change-Id: Ic85fa73c6f3655189438ec509765bae2eab9993a Reviewed-by: Alan Alpert (Personal) <416365416c@gmail.com> Reviewed-by: Simon Hausmann --- tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp | 21 +++++++++ tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 1 - tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp | 58 +++++++++++++++++++++++- 3 files changed, 77 insertions(+), 3 deletions(-) (limited to 'tests') diff --git a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp index e0c20307a8..4f21231184 100644 --- a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp +++ b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp @@ -72,6 +72,7 @@ private slots: void qtbug_22535(); void evalAfterInvalidate(); + void qobjectDerived(); private: QQmlEngine engine; @@ -659,6 +660,26 @@ void tst_qqmlcontext::evalAfterInvalidate() QCoreApplication::processEvents(); } +void tst_qqmlcontext::qobjectDerived() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("refreshExpressions.qml")); + + CountCommand command; + // This test is similar to refreshExpressions, but with the key difference that + // we use the QVariant overload of setContextProperty. That way, we test that + // QVariant knowledge that it contains a QObject derived pointer is used. + engine.rootContext()->setContextProperty("countCommand", QVariant::fromValue(&command)); + + // We use a fresh context here to bypass any root-context optimizations in + // the engine + QQmlContext context(engine.rootContext()); + + QObject *o1 = component.create(&context); + + QCOMPARE(command.count, 2); +} + QTEST_MAIN(tst_qqmlcontext) #include "tst_qqmlcontext.moc" diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 3e2493effe..acb623989a 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -3016,7 +3016,6 @@ void tst_qqmllanguage::signalParameterTypes() QQmlComponent component(&engine, testFileUrl("signalParameterTypes.2.qml")); QObject *obj = component.create(); QVERIFY(obj != 0); - QEXPECT_FAIL("", "Dynamic connections don't enforce type safety - QTBUG-26662", Abort); QVERIFY(obj->property("success").toBool()); delete obj; } diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp index 418e2edf27..27c3fd985e 100644 --- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp +++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp @@ -57,11 +57,24 @@ class MyQmlObject : public QObject { Q_OBJECT public: - MyQmlObject() {} + MyQmlObject(QObject *parent = 0) : QObject(parent) {} }; QML_DECLARE_TYPE(MyQmlObject); +class MyQObject : public QObject +{ + Q_OBJECT +public: + MyQObject(QObject *parent = 0) : QObject(parent), m_i(0) {} + + int inc() { return ++m_i; } + +private: + int m_i; +}; + + class MyAttached : public QObject { Q_OBJECT @@ -316,10 +329,11 @@ class PropertyObject : public QObject Q_PROPERTY(int resettableProperty READ resettableProperty WRITE setResettableProperty RESET resetProperty) Q_PROPERTY(int propertyWithNotify READ propertyWithNotify WRITE setPropertyWithNotify NOTIFY oddlyNamedNotifySignal) Q_PROPERTY(MyQmlObject *qmlObject READ qmlObject) + Q_PROPERTY(MyQObject *qObject READ qObject WRITE setQObject NOTIFY qObjectChanged) Q_CLASSINFO("DefaultProperty", "defaultProperty") public: - PropertyObject() : m_resetProperty(9) {} + PropertyObject() : m_resetProperty(9), m_qObject(0) {} int defaultProperty() { return 10; } QRect rectProperty() { return QRect(10, 10, 1, 209); } @@ -342,9 +356,19 @@ public: MyQmlObject *qmlObject() { return &m_qmlObject; } + MyQObject *qObject() { return m_qObject; } + void setQObject(MyQObject *object) + { + if (m_qObject != object) { + m_qObject = object; + emit qObjectChanged(); + } + } + signals: void clicked(); void oddlyNamedNotifySignal(); + void qObjectChanged(); private: int m_resetProperty; @@ -353,6 +377,7 @@ private: QVariantMap m_variantMap; int m_propertyWithNotify; MyQmlObject m_qmlObject; + MyQObject *m_qObject; }; QML_DECLARE_TYPE(PropertyObject); @@ -1130,6 +1155,18 @@ void tst_qqmlproperty::read() QCOMPARE(p.read(), QVariant()); } + // Object property registered with Qt, but not registered with QML. + { + PropertyObject o; + QQmlProperty p(&o, "qObject"); + QCOMPARE(p.propertyTypeCategory(), QQmlProperty::Object); + + QCOMPARE(p.propertyType(), qMetaTypeId()); + QVariant v = p.read(); + QVERIFY(v.canConvert(QMetaType::QObjectStar)); + QVERIFY(qvariant_cast(v) == o.qObject()); + } + // Object property { PropertyObject o; @@ -1387,6 +1424,23 @@ void tst_qqmlproperty::write() QCOMPARE(p.read(), QVariant(99)); delete object; } + // Writable pointer to QObject derived + { + PropertyObject o; + QQmlProperty p(&o, QString("qObject")); + QCOMPARE(o.qObject(), (QObject*)0); + QObject *newObject = new MyQObject(this); + QCOMPARE(p.write(QVariant::fromValue(newObject)), true); + QCOMPARE(o.qObject(), newObject); + QVariant data = p.read(); + QCOMPARE(data.value(), newObject); + QCOMPARE(data.value(), newObject); + // Incompatible types can not be written. + QCOMPARE(p.write(QVariant::fromValue(new MyQmlObject(this))), false); + QVariant newData = p.read(); + QCOMPARE(newData.value(), newObject); + QCOMPARE(newData.value(), newObject); + } } void tst_qqmlproperty::reset() -- cgit v1.2.3