diff options
author | Fabian Kosmale <fabian.kosmale@qt.io> | 2019-06-06 09:55:20 +0200 |
---|---|---|
committer | Fabian Kosmale <fabian.kosmale@qt.io> | 2019-06-11 09:18:49 +0200 |
commit | bf8862a3bfa3010986ed638e90d870fbd2a61435 (patch) | |
tree | 3a35d92336bcec3164d2ebef1af10a6c839f6c08 | |
parent | b0829884c8da99a8ca7d9bd933980fef2527638f (diff) |
add std::function overload to qmlRegisterSingletonType
This changes enables passing stateful lambdas to
qmlRegisterSingletonType, which helps when porting away from
setContextProperty.
Unfortunately, we cannot directly add an overload for std::function, as
this causes ambiguity in the overload set when a lambda of the form
auto f = [](QQmlEngine*, QJSEngine*) -> QObject*
is passed to the function (which is what the examples do)
We therefore use a template to support abribtrary callables f, then SFINAE
them out if f is not convertible to the desired std::function, or when
f is convertible to a plain C function pointer, thus removing the
ambiguity
Change-Id: I6ca95ad692d8bb785e420b85bf3d8c1d0007ce17
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
-rw-r--r-- | src/qml/doc/src/qmlfunctions.qdoc | 8 | ||||
-rw-r--r-- | src/qml/qml/qqml.h | 25 | ||||
-rw-r--r-- | src/qml/qml/qqmlmetatype.cpp | 10 | ||||
-rw-r--r-- | src/qml/qml/qqmlprivate.h | 3 | ||||
-rw-r--r-- | src/qml/qml/qqmltype_p.h | 4 | ||||
-rw-r--r-- | tests/auto/qml/qqmlengine/tst_qqmlengine.cpp | 19 |
6 files changed, 62 insertions, 7 deletions
diff --git a/src/qml/doc/src/qmlfunctions.qdoc b/src/qml/doc/src/qmlfunctions.qdoc index 3c80f16c8f..ab54b5fd1d 100644 --- a/src/qml/doc/src/qmlfunctions.qdoc +++ b/src/qml/doc/src/qmlfunctions.qdoc @@ -564,6 +564,14 @@ \sa {Choosing the Correct Integration Method Between C++ and QML} */ + +/*! + \fn int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName, std::function<QObject*(QQmlEngine *, QJSEngine *)> callback) + \relates QQmlEngine + + \overload qmlRegisterSingletonType +*/ + /*! \fn int qmlRegisterSingletonType(const QUrl &url, const char *uri, int versionMajor, int versionMinor, const char *qmlName) \relates QQmlEngine diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h index f84a1b2109..4f3bfb76b0 100644 --- a/src/qml/qml/qqml.h +++ b/src/qml/qml/qqml.h @@ -624,13 +624,13 @@ inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versi uri, versionMajor, versionMinor, typeName, - callback, nullptr, nullptr, 0, 0 + callback, nullptr, nullptr, 0, 0, {} }; return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api); } -enum { QmlCurrentSingletonTypeRegistrationVersion = 2 }; +enum { QmlCurrentSingletonTypeRegistrationVersion = 3 }; template <typename T> inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName, QObject *(*callback)(QQmlEngine *, QJSEngine *)) @@ -642,7 +642,26 @@ inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versi uri, versionMajor, versionMinor, typeName, - nullptr, callback, &T::staticMetaObject, qRegisterNormalizedMetaType<T *>(pointerName.constData()), 0 + nullptr, nullptr, &T::staticMetaObject, qRegisterNormalizedMetaType<T *>(pointerName.constData()), 0, callback + }; + + return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api); +} + +template <typename T, typename F, typename std::enable_if<std::is_convertible<F, std::function<QObject *(QQmlEngine *, QJSEngine *)>>::value + && !std::is_convertible<F, QObject *(*)(QQmlEngine *, QJSEngine *)>::value, void>::type* = nullptr> +inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName, + F&& callback) +{ + + QML_GETTYPENAMES + + QQmlPrivate::RegisterSingletonType api = { + QmlCurrentSingletonTypeRegistrationVersion, + + uri, versionMajor, versionMinor, typeName, + + nullptr, nullptr, &T::staticMetaObject, qRegisterNormalizedMetaType<T *>(pointerName.constData()), 0, callback }; return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api); diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index c6858780a1..a2c2ae47af 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -107,7 +107,7 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el d->version_maj = type.versionMajor; d->version_min = type.versionMinor; - if (type.qobjectApi) { + if (type.qobjectApi || (type.version >= 3 && type.generalizedQobjectApi)) { if (type.version >= 1) // static metaobject added in version 1 d->baseMetaObject = type.instanceMetaObject; if (type.version >= 2) // typeId added in version 2 @@ -118,10 +118,14 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el d->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo; d->extraData.sd->singletonInstanceInfo->scriptCallback = type.scriptApi; - d->extraData.sd->singletonInstanceInfo->qobjectCallback = type.qobjectApi; + if (type.version >= 3) { + d->extraData.sd->singletonInstanceInfo->qobjectCallback = type.generalizedQobjectApi; + } else { + d->extraData.sd->singletonInstanceInfo->qobjectCallback = type.qobjectApi; + } d->extraData.sd->singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName); d->extraData.sd->singletonInstanceInfo->instanceMetaObject - = (type.qobjectApi && type.version >= 1) ? type.instanceMetaObject : nullptr; + = ((type.qobjectApi || (type.version >= 3 && type.generalizedQobjectApi) ) && type.version >= 1) ? type.instanceMetaObject : nullptr; return d; } diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h index ae84803648..a07736c6fc 100644 --- a/src/qml/qml/qqmlprivate.h +++ b/src/qml/qml/qqmlprivate.h @@ -51,6 +51,8 @@ // We mean it. // +#include <functional> + #include <QtQml/qtqmlglobal.h> #include <QtCore/qglobal.h> @@ -276,6 +278,7 @@ namespace QQmlPrivate const QMetaObject *instanceMetaObject; // new in version 1 int typeId; // new in version 2 int revision; // new in version 2 + std::function<QObject*(QQmlEngine *, QJSEngine *)> generalizedQobjectApi; // new in version 3 // If this is extended ensure "version" is bumped!!! }; diff --git a/src/qml/qml/qqmltype_p.h b/src/qml/qml/qqmltype_p.h index 1d65a08c8f..158fefad2c 100644 --- a/src/qml/qml/qqmltype_p.h +++ b/src/qml/qml/qqmltype_p.h @@ -51,6 +51,8 @@ // We mean it. // +#include <functional> + #include <private/qtqmlglobal_p.h> #include <private/qqmlrefcount_p.h> @@ -145,7 +147,7 @@ public: struct Q_QML_PRIVATE_EXPORT SingletonInstanceInfo { QJSValue (*scriptCallback)(QQmlEngine *, QJSEngine *) = nullptr; - QObject *(*qobjectCallback)(QQmlEngine *, QJSEngine *) = nullptr; + std::function<QObject *(QQmlEngine *, QJSEngine *)> qobjectCallback = {}; const QMetaObject *instanceMetaObject = nullptr; QString typeName; QUrl url; // used by composite singletons diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp index 0cb6753020..8d0106b92c 100644 --- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp +++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp @@ -1015,6 +1015,25 @@ void tst_qqmlengine::singletonInstance() } { + int data = 30; + auto id = qmlRegisterSingletonType<CppSingleton>("Qt.test",1,0,"CapturingLambda",[data](QQmlEngine*, QJSEngine*){ // register qobject singleton with capturing lambda + auto o = new CppSingleton; + o->setProperty("data", data); + return o; + }); + QJSValue value = engine.singletonInstance<QJSValue>(id); + QVERIFY(!value.isUndefined()); + QVERIFY(value.isQObject()); + QObject *instance = value.toQObject(); + QVERIFY(instance); + QCOMPARE(instance->metaObject()->className(), "CppSingleton"); + QCOMPARE(instance->property("data"), data); + } + { + qmlRegisterSingletonType<CppSingleton>("Qt.test",1,0,"NotAmbiguous", [](QQmlEngine* qeng, QJSEngine* jeng) -> QObject* {return CppSingleton::create(qeng, jeng);}); // test that overloads for qmlRegisterSingleton are not ambiguous + } + + { // Invalid types QJSValue value; value = engine.singletonInstance<QJSValue>(-4711); |