diff options
-rw-r--r-- | src/qml/doc/src/qmlfunctions.qdoc | 24 | ||||
-rw-r--r-- | src/qml/qml/qqmlmetatype.cpp | 12 | ||||
-rw-r--r-- | src/qml/qml/qqmltypewrapper.cpp | 13 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/data/singletonTest18.qml | 9 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/testtypes.cpp | 9 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 26 |
6 files changed, 62 insertions, 31 deletions
diff --git a/src/qml/doc/src/qmlfunctions.qdoc b/src/qml/doc/src/qmlfunctions.qdoc index 55ca040af6..6445a003a1 100644 --- a/src/qml/doc/src/qmlfunctions.qdoc +++ b/src/qml/doc/src/qmlfunctions.qdoc @@ -538,30 +538,6 @@ } \endqml - Since singleton types do not have an associated QQmlContext object, then within the functions of a QObject-derived - type that is registered as a singleton type implementation the QML context and engine information is not available. - The QQmlEngine::contextForObject() function returns NULL when supplied with a pointer to an QObject that - implements a singleton type. - - Extending the above example: - - \code - class SingletonTypeExample : public QObject - { - ... - - Q_INVOKABLE void doSomethingElse() - { - // QML Engine/Context information is not accessible here: - Q_ASSERT(QQmlEngine::contextForObject(this) == 0); - Q_ASSERT(qmlContext(this) == 0); - Q_ASSERT(qmlEngine(this) == 0); - } - - ... - } - \endcode - \sa {Choosing the Correct Integration Method Between C++ and QML} */ diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 0429df6185..307f9a9ec6 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -264,7 +264,14 @@ void QQmlMetaTypeData::registerType(QQmlTypePrivate *priv) void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e) { if (scriptCallback && scriptApi(e).isUndefined()) { - setScriptApi(e, scriptCallback(e, e)); + QJSValue value = scriptCallback(e, e); + if (value.isQObject()) { + QObject *o = value.toQObject(); + // even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj) + // should behave identically to QML singleton types. + e->setContextForObject(o, new QQmlContext(e->rootContext(), e)); + } + setScriptApi(e, value); } else if (qobjectCallback && !qobjectApi(e)) { QObject *o = qobjectCallback(e, e); setQObjectApi(e, o); @@ -273,6 +280,9 @@ void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e) } // if this object can use a property cache, create it now QQmlData::ensurePropertyCache(e, o); + // even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj) + // should behave identically to QML singleton types. + e->setContextForObject(o, new QQmlContext(e->rootContext(), e)); } else if (!url.isEmpty() && !qobjectApi(e)) { QQmlComponent component(e, url, QQmlComponent::PreferSynchronous); QObject *o = component.beginCreate(e->rootContext()); diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index 26f035705c..7270cffb00 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -95,12 +95,17 @@ QObject* QQmlTypeWrapper::singletonObject() const QVariant QQmlTypeWrapper::toVariant() const { - QObject *qobjectSingleton = singletonObject(); - if (qobjectSingleton) + // Only Singleton type wrappers can be converted to a variant. + if (!isSingleton()) + return QVariant(); + + QQmlEngine *e = engine()->qmlEngine(); + QQmlType::SingletonInstanceInfo *siinfo = d()->type().singletonInstanceInfo(); + siinfo->init(e); + if (QObject *qobjectSingleton = siinfo->qobjectApi(e)) return QVariant::fromValue<QObject*>(qobjectSingleton); - // only QObject Singleton Type can be converted to a variant. - return QVariant(); + return QVariant::fromValue<QJSValue>(siinfo->scriptApi(e)); } diff --git a/tests/auto/qml/qqmllanguage/data/singletonTest18.qml b/tests/auto/qml/qqmllanguage/data/singletonTest18.qml new file mode 100644 index 0000000000..7616c23531 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/singletonTest18.qml @@ -0,0 +1,9 @@ +import QtQuick 2.0 +import "singleton" +import Test 1.0 + +Item { + property var qmlSingleton: SingletonType + property var jsSingleton: MyQJSValueQObjectSingleton + property var cppSingleton: MyTypeObjectSingleton +} diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp index 0eb4f26878..7e247b1906 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.cpp +++ b/tests/auto/qml/qqmllanguage/testtypes.cpp @@ -35,6 +35,14 @@ static QObject *myTypeObjectSingleton(QQmlEngine *engine, QJSEngine *scriptEngin return new MyTypeObject(); } +static QJSValue myQJSValueQObjectSingleton(QQmlEngine *engine, QJSEngine *scriptEngine) +{ + Q_UNUSED(engine) + + QJSValue value = scriptEngine->newQObject(new MyTypeObject()); + return value; +} + void registerTypes() { qmlRegisterInterface<MyInterface>("MyInterface"); @@ -101,6 +109,7 @@ void registerTypes() qmlRegisterType<MyCompositeBaseType>("Test", 1, 0, "MyCompositeBaseType"); qmlRegisterSingletonType<MyTypeObjectSingleton>("Test", 1, 0, "MyTypeObjectSingleton", myTypeObjectSingleton); + qmlRegisterSingletonType("Test", 1, 0, "MyQJSValueQObjectSingleton", myQJSValueQObjectSingleton); qmlRegisterType<MyArrayBufferTestClass>("Test", 1, 0, "MyArrayBufferTestClass"); diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 400c28928a..39f973f3fd 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -246,6 +246,8 @@ private slots: void compositeSingletonRegistered(); void compositeSingletonCircular(); + void singletonsHaveContextAndEngine(); + void customParserBindingScopes(); void customParserEvaluateEnum(); void customParserProperties(); @@ -3923,11 +3925,13 @@ void tst_qqmllanguage::getSingletonInstance(QObject* o, const char* propertyName return; QVariant variant = o->property(propertyName); - QVERIFY(variant.userType() == qMetaTypeId<QObject *>()); + QVERIFY(variant.isValid()); QObject *singleton = nullptr; - if (variant.canConvert<QObject*>()) + if (variant.userType() == qMetaTypeId<QObject *>()) singleton = variant.value<QObject*>(); + else if (variant.userType() == qMetaTypeId<QJSValue>()) + singleton = variant.value<QJSValue>().toQObject(); QVERIFY(singleton != nullptr); *result = singleton; @@ -4232,6 +4236,24 @@ void tst_qqmllanguage::compositeSingletonCircular() QCOMPARE(o->property("value").toInt(), 2); } +void tst_qqmllanguage::singletonsHaveContextAndEngine() +{ + QObject *qmlSingleton = nullptr; + getSingletonInstance(engine, "singletonTest18.qml", "qmlSingleton", &qmlSingleton); + QVERIFY(qmlContext(qmlSingleton)); + QCOMPARE(qmlEngine(qmlSingleton), &engine); + + QObject *jsSingleton = nullptr; + getSingletonInstance(engine, "singletonTest18.qml", "jsSingleton", &jsSingleton); + QVERIFY(qmlContext(jsSingleton)); + QCOMPARE(qmlEngine(jsSingleton), &engine); + + QObject *cppSingleton = nullptr; + getSingletonInstance(engine, "singletonTest18.qml", "cppSingleton", &cppSingleton); + QVERIFY(qmlContext(cppSingleton)); + QCOMPARE(qmlEngine(cppSingleton), &engine); +} + void tst_qqmllanguage::customParserBindingScopes() { QQmlComponent component(&engine, testFile("customParserBindingScopes.qml")); |