diff options
-rw-r--r-- | src/qml/qml/qqmlproperty.cpp | 10 | ||||
-rw-r--r-- | src/qml/qml/qqmlpropertycache.cpp | 2 | ||||
-rw-r--r-- | src/qml/qml/v8/qv8engine.cpp | 2 | ||||
-rw-r--r-- | tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp | 21 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 1 | ||||
-rw-r--r-- | tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp | 58 |
6 files changed, 87 insertions, 7 deletions
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index d1ecfdc52d..cf1b5ffd18 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -1611,10 +1611,14 @@ QQmlMetaObject QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engi { if (engine) { return engine->rawMetaObjectForType(userType); - } else { - QQmlType *type = QQmlMetaType::qmlType(userType); - return QQmlMetaObject(type?type->baseMetaObject():0); } + QQmlType *type = QQmlMetaType::qmlType(userType); + if (type) + return QQmlMetaObject(type->baseMetaObject()); + QMetaType metaType(userType); + if ((metaType.flags() & QMetaType::PointerToQObject) && metaType.metaObject()) + return metaType.metaObject(); + return QQmlMetaObject((QObject*)0); } /*! diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index 6d44b61aee..a1385e06fc 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -124,7 +124,7 @@ static QQmlPropertyData::Flags flagsForPropertyType(int propType, QQmlEngine *en engine ? QQmlEnginePrivate::get(engine)->typeCategory(propType) : QQmlMetaType::typeCategory(propType); - if (cat == QQmlMetaType::Object) + if (cat == QQmlMetaType::Object || QMetaType::typeFlags(propType) & QMetaType::PointerToQObject) flags |= QQmlPropertyData::IsQObjectDerived; else if (cat == QQmlMetaType::List) flags |= QQmlPropertyData::IsQList; diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp index 117fea272c..6737c14b17 100644 --- a/src/qml/qml/v8/qv8engine.cpp +++ b/src/qml/qml/v8/qv8engine.cpp @@ -310,6 +310,8 @@ QV4::Value QV8Engine::fromVariant(const QVariant &variant) a->arrayData[ii].value = QV4::QObjectWrapper::wrap(m_v4Engine, list.at(ii)); a->setArrayLengthUnchecked(list.count()); return QV4::Value::fromObject(a); + } else if (QMetaType::typeFlags(type) & QMetaType::PointerToQObject) { + return QV4::QObjectWrapper::wrap(m_v4Engine, *reinterpret_cast<QObject* const *>(ptr)); } bool objOk; 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<MyQObject*>()); + QVariant v = p.read(); + QVERIFY(v.canConvert(QMetaType::QObjectStar)); + QVERIFY(qvariant_cast<QObject *>(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<QObject*>(), newObject); + QCOMPARE(data.value<MyQObject*>(), newObject); + // Incompatible types can not be written. + QCOMPARE(p.write(QVariant::fromValue(new MyQmlObject(this))), false); + QVariant newData = p.read(); + QCOMPARE(newData.value<QObject*>(), newObject); + QCOMPARE(newData.value<MyQObject*>(), newObject); + } } void tst_qqmlproperty::reset() |