diff options
-rw-r--r-- | doc/src/qml/qtdeclarative.qdoc | 25 | ||||
-rw-r--r-- | src/imports/localstorage/plugin.cpp | 2 | ||||
-rw-r--r-- | src/qml/qml/qqml.h | 19 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine.cpp | 1 | ||||
-rw-r--r-- | src/qml/qml/qqmlmetatype.cpp | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmlmetatype_p.h | 12 | ||||
-rw-r--r-- | src/qml/qml/qqmlprivate.h | 1 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4irbuilder.cpp | 20 | ||||
-rw-r--r-- | tests/auto/qml/qqmlecmascript/data/moduleapi/qobjectModuleApiLegacy.qml | 13 | ||||
-rw-r--r-- | tests/auto/qml/qqmlecmascript/testtypes.cpp | 17 | ||||
-rw-r--r-- | tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 11 | ||||
-rw-r--r-- | tests/auto/qml/qquickconnection/tst_qquickconnection.cpp | 2 | ||||
-rw-r--r-- | tests/auto/qml/v4/data/moduleApi.qml | 12 | ||||
-rw-r--r-- | tests/auto/qml/v4/tst_v4.cpp | 41 |
14 files changed, 149 insertions, 31 deletions
diff --git a/doc/src/qml/qtdeclarative.qdoc b/doc/src/qml/qtdeclarative.qdoc index 20d1c40d66..48cc898458 100644 --- a/doc/src/qml/qtdeclarative.qdoc +++ b/doc/src/qml/qtdeclarative.qdoc @@ -27,10 +27,10 @@ /*! \module QtQml - \title Qt Declarative Module + \title Qt Qml Module \ingroup modules - \brief The Qt Declarative module provides a declarative framework + \brief The Qt Qml module provides a declarative framework for building highly dynamic, custom user interfaces. To include the definitions of the module's classes, use the @@ -44,10 +44,11 @@ .pro file: \code - QT += declarative + QT += qml \endcode - For more information on the Qt Declarative module, see the + For more information on the Qt Qml module (including the visual + elements which are implemented on top of the Qt Qml module) see the \l{Qt Quick} documentation. */ @@ -278,7 +279,16 @@ */ /*! + \internal \fn int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMinor, QObject *(*callback)(QQmlEngine *, QJSEngine *)) + \deprecated + + Any uses of a module API in a binding where that module API was registered with this + function instead of the template version will result in suboptimal binding generation. + */ + +/*! + \fn template<typename T> int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMinor, QObject *(*callback)(QQmlEngine *, QJSEngine *)) \relates QQmlEngine This function may be used to register a module API provider \a callback in a particular \a uri @@ -289,13 +299,18 @@ A module API may be either a QObject or a QJSValue. Only one module API provider may be registered into any given namespace (combination of \a uri, \a versionMajor and \a versionMinor). - This function should be used to register a module API provider function which returns a QObject as a module API. + This function should be used to register a module API provider function which returns a QObject + of the given type T as a module API. A QObject module API must be imported with a qualifier, and that qualifier may be used as the target in a \l Connections element or otherwise used as any other element id would. One exception to this is that a QObject module API property may not be aliased (because the module API qualifier does not identify an object within the same component as any other item). + \b{NOTE:} A QObject module API instance returned from a module API provider is owned by the QML + engine. For this reason, the module API provider function should \b{not} be implemented as a + singleton factory. + Usage: \code // first, define your QObject which provides the functionality. diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp index 0187d06e6a..4f08e71fd0 100644 --- a/src/imports/localstorage/plugin.cpp +++ b/src/imports/localstorage/plugin.cpp @@ -661,7 +661,7 @@ public: void registerTypes(const char *uri) { Q_ASSERT(QLatin1String(uri) == "QtQuick.LocalStorage"); - qmlRegisterModuleApi(uri, 2, 0, module_api_factory); + qmlRegisterModuleApi<QQuickLocalStorage>(uri, 2, 0, module_api_factory); } }; diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h index 32da2c616e..5b500e0814 100644 --- a/src/qml/qml/qqml.h +++ b/src/qml/qml/qqml.h @@ -421,7 +421,7 @@ inline int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMi uri, versionMajor, versionMinor, - callback, 0 + callback, 0, 0 }; return QQmlPrivate::qmlregister(QQmlPrivate::ModuleApiRegistration, &api); @@ -435,7 +435,22 @@ inline int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMi uri, versionMajor, versionMinor, - 0, callback + 0, callback, 0 // unknown QObject instance type + }; + + return QQmlPrivate::qmlregister(QQmlPrivate::ModuleApiRegistration, &api); +} + +template <typename T> +inline int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMinor, + QObject *(*callback)(QQmlEngine *, QJSEngine *)) +{ + QQmlPrivate::RegisterModuleApi api = { + 1, + + uri, versionMajor, versionMinor, + + 0, callback, &T::staticMetaObject }; return QQmlPrivate::qmlregister(QQmlPrivate::ModuleApiRegistration, &api); diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 489b4f895a..3d09ebb83f 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -1701,6 +1701,7 @@ QQmlEnginePrivate::moduleApiInstance(const QQmlMetaType::ModuleApi &module) a = new QQmlMetaType::ModuleApiInstance; a->scriptCallback = module.script; a->qobjectCallback = module.qobject; + a->instanceMetaObject = module.instanceMetaObject; moduleApiInstances.insert(module, a); } diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 985adbfec7..d4c19f8325 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -913,6 +913,10 @@ int registerModuleApi(const QQmlPrivate::RegisterModuleApi &api) import.minor = api.versionMinor; import.script = api.scriptApi; import.qobject = api.qobjectApi; + import.instanceMetaObject = (api.qobjectApi && api.version >= 1) ? api.instanceMetaObject : 0; // BC with version 0. + + if (import.qobject && !import.instanceMetaObject) // BC - check import.iMO rather than api.iMO. + qWarning() << "qmlRegisterModuleApi(): sub-optimal: use the templated version of this function instead!"; int index = data->moduleApiCount++; diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h index b715d0c8f2..03017cafab 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -115,20 +115,23 @@ public: struct ModuleApiInstance { ModuleApiInstance() - : scriptCallback(0), qobjectCallback(0), qobjectApi(0) {} + : scriptCallback(0), qobjectCallback(0), qobjectApi(0), instanceMetaObject(0) {} QJSValue (*scriptCallback)(QQmlEngine *, QJSEngine *); QObject *(*qobjectCallback)(QQmlEngine *, QJSEngine *); - QJSValue scriptApi; QObject *qobjectApi; + const QMetaObject *instanceMetaObject; + QJSValue scriptApi; + }; struct ModuleApi { inline ModuleApi(); inline bool operator==(const ModuleApi &) const; int major; int minor; - QJSValue (*script)(QQmlEngine *, QJSEngine *); QObject *(*qobject)(QQmlEngine *, QJSEngine *); + const QMetaObject *instanceMetaObject; + QJSValue (*script)(QQmlEngine *, QJSEngine *); }; static ModuleApi moduleApi(const QString &, int, int); static QHash<QString, QList<ModuleApi> > moduleApis(); @@ -247,8 +250,9 @@ QQmlMetaType::ModuleApi::ModuleApi() { major = 0; minor = 0; - script = 0; qobject = 0; + instanceMetaObject = 0; + script = 0; } bool QQmlMetaType::ModuleApi::operator==(const ModuleApi &other) const diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h index b4c6fc3a12..82da62ff45 100644 --- a/src/qml/qml/qqmlprivate.h +++ b/src/qml/qml/qqmlprivate.h @@ -246,6 +246,7 @@ namespace QQmlPrivate QJSValue (*scriptApi)(QQmlEngine *, QJSEngine *); QObject *(*qobjectApi)(QQmlEngine *, QJSEngine *); + const QMetaObject *instanceMetaObject; }; enum RegistrationType { diff --git a/src/qml/qml/v4/qv4irbuilder.cpp b/src/qml/qml/v4/qv4irbuilder.cpp index ea4d1afbbc..453120c6c7 100644 --- a/src/qml/qml/v4/qv4irbuilder.cpp +++ b/src/qml/qml/v4/qv4irbuilder.cpp @@ -428,18 +428,18 @@ bool QV4IRBuilder::visit(AST::IdentifierExpression *ast) if (r.isValid()) { if (r.type) { _expr.code = _block->ATTACH_TYPE(name, r.type, IR::Name::ScopeStorage, line, column); - } /*else if (r.importNamespace) { + } else if (r.importNamespace) { QQmlMetaType::ModuleApiInstance *moduleApi = m_expression->importCache->moduleApi(r.importNamespace); - if (moduleApi) { - if (moduleApi->qobjectCallback) { - moduleApi->qobjectApi = moduleApi->qobjectCallback(QQmlEnginePrivate::get(m_engine), QQmlEnginePrivate::get(m_engine)); - moduleApi->qobjectCallback = 0; - moduleApi->scriptCallback = 0; - } - if (moduleApi->qobjectApi) - _expr.code = _block->MODULE_OBJECT(name, moduleApi->qobjectApi->metaObject(), IR::Name::MemberStorage, line, column); + if (moduleApi && moduleApi->instanceMetaObject) { + // Note: we don't need to check moduleApi->qobjectCallback here, since + // we did that check in registerModuleApi() in qqmlmetatype.cpp. + // We cannot create the QObject Module Api Instance here, + // as we might be running in a loader thread. + // Thus, V4 can only handle bindings which use Module APIs which + // were registered with the templated registration function. + _expr.code = _block->MODULE_OBJECT(name, moduleApi->instanceMetaObject, IR::Name::MemberStorage, line, column); } - }*/ //### we can't create the actual QObject here, as we may be running in a thread (can be reenabled once QTBUG-24894 is handled) + } // We don't support anything else } else { bool found = false; diff --git a/tests/auto/qml/qqmlecmascript/data/moduleapi/qobjectModuleApiLegacy.qml b/tests/auto/qml/qqmlecmascript/data/moduleapi/qobjectModuleApiLegacy.qml new file mode 100644 index 0000000000..e282ad64f2 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/moduleapi/qobjectModuleApiLegacy.qml @@ -0,0 +1,13 @@ +import QtQuick 2.0 + +import Qt.test.legacyModuleApi 1.0 as ModApi // was registered with non-templated function + +QtObject { + property int legacyModulePropertyTest: ModApi.qobjectTestProperty + property int legacyModuleMethodTest + + Component.onCompleted: { + legacyModuleMethodTest = ModApi.qobjectTestMethod(); + } +} + diff --git a/tests/auto/qml/qqmlecmascript/testtypes.cpp b/tests/auto/qml/qqmlecmascript/testtypes.cpp index a79207a1c8..d674fa3eb6 100644 --- a/tests/auto/qml/qqmlecmascript/testtypes.cpp +++ b/tests/auto/qml/qqmlecmascript/testtypes.cpp @@ -187,14 +187,15 @@ void registerTypes() qRegisterMetaType<MyQmlObject::MyType>("MyQmlObject::MyType"); - qmlRegisterModuleApi("Qt.test",1,0,script_api); // register (script) module API for an existing uri which contains elements - qmlRegisterModuleApi("Qt.test",1,0,qobject_api); // register (qobject) for an existing uri for which another module API was previously regd. Should replace! - qmlRegisterModuleApi("Qt.test.scriptApi",1,0,script_api); // register (script) module API for a uri which doesn't contain elements - qmlRegisterModuleApi("Qt.test.scriptApi",2,0,readonly_script_api); // register (script) module API for a uri which doesn't contain elements - will be made read-only - qmlRegisterModuleApi("Qt.test.qobjectApi",1,0,qobject_api); // register (qobject) module API for a uri which doesn't contain elements - qmlRegisterModuleApi("Qt.test.qobjectApi",1,3,qobject_api); // register (qobject) module API for a uri which doesn't contain elements, minor version set - qmlRegisterModuleApi("Qt.test.qobjectApi",2,0,qobject_api); // register (qobject) module API for a uri which doesn't contain elements, major version set - qmlRegisterModuleApi("Qt.test.qobjectApiParented",1,0,qobject_api_engine_parent); // register (parented qobject) module API for a uri which doesn't contain elements + qmlRegisterModuleApi("Qt.test",1,0,script_api); // register (script) module API for an existing uri which contains elements + qmlRegisterModuleApi<testQObjectApi>("Qt.test",1,0,qobject_api); // register (qobject) for an existing uri for which another module API was previously regd. Should replace! + qmlRegisterModuleApi("Qt.test.scriptApi",1,0,script_api); // register (script) module API for a uri which doesn't contain elements + qmlRegisterModuleApi("Qt.test.scriptApi",2,0,readonly_script_api); // register (script) module API for a uri which doesn't contain elements - will be made read-only + qmlRegisterModuleApi<testQObjectApi>("Qt.test.qobjectApi",1,0,qobject_api); // register (qobject) module API for a uri which doesn't contain elements + qmlRegisterModuleApi<testQObjectApi>("Qt.test.qobjectApi",1,3,qobject_api); // register (qobject) module API for a uri which doesn't contain elements, minor version set + qmlRegisterModuleApi<testQObjectApi>("Qt.test.qobjectApi",2,0,qobject_api); // register (qobject) module API for a uri which doesn't contain elements, major version set + qmlRegisterModuleApi<testQObjectApi>("Qt.test.qobjectApiParented",1,0,qobject_api_engine_parent); // register (parented qobject) module API for a uri which doesn't contain elements + qmlRegisterModuleApi("Qt.test.legacyModuleApi", 1, 0, qobject_api); // this registration function doesn't provide type information. qRegisterMetaType<MyQmlObject::MyEnum2>("MyEnum2"); qRegisterMetaType<Qt::MouseButtons>("Qt::MouseButtons"); diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index fa1a6a5920..eaa6d39ea4 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -3372,6 +3372,17 @@ void tst_qqmlecmascript::moduleApi_data() << QVariantList() << QStringList() << QVariantList(); + + QTest::newRow("legacy module api registration") + << testFileUrl("moduleapi/qobjectModuleApiLegacy.qml") + << QString() + << QStringList() // warning doesn't occur in the test, but in registerTypes() + << (QStringList() << "legacyModulePropertyTest" << "legacyModuleMethodTest") + << (QVariantList() << 20 << 2) + << QStringList() + << QVariantList() + << QStringList() + << QVariantList(); } void tst_qqmlecmascript::moduleApi() diff --git a/tests/auto/qml/qquickconnection/tst_qquickconnection.cpp b/tests/auto/qml/qquickconnection/tst_qquickconnection.cpp index ad687dd085..1167281eb0 100644 --- a/tests/auto/qml/qquickconnection/tst_qquickconnection.cpp +++ b/tests/auto/qml/qquickconnection/tst_qquickconnection.cpp @@ -263,7 +263,7 @@ static QObject *module_api_factory(QQmlEngine *engine, QJSEngine *scriptEngine) // QTBUG-20937 void tst_qquickconnection::moduleApiTarget() { - qmlRegisterModuleApi("MyTestModuleApi", 1, 0, module_api_factory); + qmlRegisterModuleApi<MyTestModuleApi>("MyTestModuleApi", 1, 0, module_api_factory); QQmlComponent component(&engine, testFileUrl("moduleapi-target.qml")); QObject *object = component.create(); QVERIFY(object != 0); diff --git a/tests/auto/qml/v4/data/moduleApi.qml b/tests/auto/qml/v4/data/moduleApi.qml new file mode 100644 index 0000000000..9f3bf0ca8c --- /dev/null +++ b/tests/auto/qml/v4/data/moduleApi.qml @@ -0,0 +1,12 @@ +import Qt.test 1.0 as ModApi +import QtQuick 2.0 + +Item { + property int testProp: ModApi.ip + property int testProp2: 2 + + function getRandom() { + testProp2 = ModApi.random(); + // testProp should also have changed. + } +} diff --git a/tests/auto/qml/v4/tst_v4.cpp b/tests/auto/qml/v4/tst_v4.cpp index 8c811f230e..47fa10b595 100644 --- a/tests/auto/qml/v4/tst_v4.cpp +++ b/tests/auto/qml/v4/tst_v4.cpp @@ -81,6 +81,7 @@ private slots: void mathCeil(); void mathMax(); void mathMin(); + void moduleApi(); private: QQmlEngine engine; @@ -589,6 +590,46 @@ void tst_v4::mathMin() delete o; } +class V4ModuleApi : public QObject +{ + Q_OBJECT + Q_PROPERTY(int ip READ ip WRITE setIp NOTIFY ipChanged FINAL) +public: + V4ModuleApi() : m_ip(12) {} + ~V4ModuleApi() {} + + Q_INVOKABLE int random() { static int prng = 3; prng++; m_ip++; emit ipChanged(); return prng; } + + int ip() const { return m_ip; } + void setIp(int v) { m_ip = v; emit ipChanged(); } + +signals: + void ipChanged(); + +private: + int m_ip; +}; + +static QObject *v4_module_api_factory(QQmlEngine*, QJSEngine*) +{ + return new V4ModuleApi; +} + +void tst_v4::moduleApi() +{ + // register module api, providing typeinfo via template + qmlRegisterModuleApi<V4ModuleApi>("Qt.test", 1, 0, v4_module_api_factory); + QQmlComponent component(&engine, testFileUrl("moduleApi.qml")); + QObject *o = component.create(); + QVERIFY(o != 0); + QCOMPARE(o->property("testProp").toInt(), 12); + QCOMPARE(o->property("testProp2").toInt(), 2); + QMetaObject::invokeMethod(o, "getRandom"); + QCOMPARE(o->property("testProp").toInt(), 13); + QCOMPARE(o->property("testProp2").toInt(), 4); + delete o; +} + QTEST_MAIN(tst_v4) #include "tst_v4.moc" |