From 73fdeb9c1c70079e54104c93811b5d7ff9e4ee0b Mon Sep 17 00:00:00 2001 From: Richard Weickelt Date: Thu, 31 May 2018 21:41:47 +0200 Subject: Provide API to access singletons associated with a QQmlEngine This patch adds allows C++ code to retrieve the instance of a registered singleton type. Until now this required a deturn via QML expression. Two methods are added to QQmlEngine: A generic one that encapsulates all singleton objects in a QJSValue and a template function for QObject-derived singleton types. An additional convenience function is added to query the QML type id. This function may also be used for other purposes in the future. [ChangeLog][QtQml][QQmlEngine] Added API to access singletons associated with a QQmlEngine. Task-number: QTBUG-39970 Change-Id: I67c132ede35f80b9aaf1c5e5456715cf4f1b0848 Reviewed-by: Simon Hausmann --- src/qml/doc/src/qmlfunctions.qdoc | 22 +++++++++++++ src/qml/qml/qqml.h | 2 ++ src/qml/qml/qqmlengine.cpp | 65 +++++++++++++++++++++++++++++++++++++++ src/qml/qml/qqmlengine.h | 16 ++++++++++ src/qml/qml/qqmlmetatype.cpp | 39 ++++++++++++++++++----- src/qml/qml/qqmlmetatype_p.h | 7 ++++- 6 files changed, 142 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/qml/doc/src/qmlfunctions.qdoc b/src/qml/doc/src/qmlfunctions.qdoc index 6445a003a1..62c0f5d81b 100644 --- a/src/qml/doc/src/qmlfunctions.qdoc +++ b/src/qml/doc/src/qmlfunctions.qdoc @@ -638,3 +638,25 @@ are registered for that version. This is particularly useful for keeping the versions of related modules in sync. */ + +/*! + \since 5.12 + \fn int qmlTypeId(const char* uri, int versionMajor, int versionMinor, const char *qmlName); + \relates QQmlEngine + + Returns the QML type id of a type that was registered with the + name \a qmlName in a particular \a uri and a version specified in \a + versionMajor and \a versionMinor. + + This function returns the same value as the QML type registration functions + such as qmlRegisterType() and qmlRegisterSingletonType(). + + If \a qmlName, \a uri and \a versionMajor match a registered type, but the + specified minor version in \a versionMinor is higher, then the id of the type + with the closest minor version is returned. + + Returns -1 if no matching type was found or one of the given parameters + was invalid. + + \sa qmlRegisterType(), qmlRegisterSingletonType() +*/ diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h index 213f23cd98..2a8e236905 100644 --- a/src/qml/qml/qqml.h +++ b/src/qml/qml/qqml.h @@ -645,6 +645,8 @@ inline int qmlRegisterType(const QUrl &url, const char *uri, int versionMajor, i return QQmlPrivate::qmlregister(QQmlPrivate::CompositeRegistration, &type); } +int Q_QML_EXPORT qmlTypeId(const char *uri, int versionMajor, int versionMinor, const char *qmlName); + QT_END_NAMESPACE QML_DECLARE_TYPE(QObject) diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index d62d91456f..61cf2a8994 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -1373,6 +1373,71 @@ void QQmlEngine::setOutputWarningsToStandardError(bool enabled) d->outputWarningsToMsgLog = enabled; } +/*! + \fn template T QQmlEngine::singletonInstance(int qmlTypeId) + + Returns the instance of a singleton type that was registered under \a qmlTypeId. + + The template argument \e T may be either QJSValue or a pointer to a QObject-derived + type and depends on how the singleton was registered. If no instance of \e T has been + created yet, it is created now. If \a qmlTypeId does not represent a valid singleton + type, either a default constructed QJSValue or a \c nullptr is returned. + + QObject* example: + \code + class MySingleton : public QObject { + Q_OBJECT + static int typeId; + // ... + }; + + // Register with QObject* callback + MySingleton::typeId = qmlRegisterSingletonType(...); + + // Retrieve as QObject* + QQmlEngine engine; + MySingleton* instance = engine.singletonInstance(MySingleton::typeId); + \endcode + + QJSValue example: + \code + // Register with QJSValue callback + int typeId = qmlRegisterSingletonType(...); + + // Retrieve as QJSValue + QQmlEngine engine; + QJSValue instance = engine.singletonInstance(typeId); + \endcode + + It is recommended to store the QML type id during registration, e.g. as a static member + in the singleton class. Otherwise, a costly lookup via qmlTypeId() has to be performed + at run-time. + + \sa qmlRegisterSingletonType(), qmlTypeId() + \since 5.12 +*/ +template<> +QJSValue QQmlEngine::singletonInstance(int qmlTypeId) +{ + QQmlType type = QQmlMetaType::qmlType(qmlTypeId, QQmlMetaType::TypeIdCategory::QmlType); + + if (!type.isValid() || !type.isSingleton()) + return QJSValue(); + + QQmlType::SingletonInstanceInfo* info = type.singletonInstanceInfo(); + info->init(this); + + if (QObject* o = info->qobjectApi(this)) + return this->newQObject(o); + else { + QJSValue value = info->scriptApi(this); + if (!value.isUndefined()) + return value; + } + + return QJSValue(); +} + /*! Refreshes all binding expressions that use strings marked for translation. diff --git a/src/qml/qml/qqmlengine.h b/src/qml/qml/qqmlengine.h index 73ad2754c8..871e6bd9b4 100644 --- a/src/qml/qml/qqmlengine.h +++ b/src/qml/qml/qqmlengine.h @@ -143,6 +143,9 @@ public: bool outputWarningsToStandardError() const; void setOutputWarningsToStandardError(bool); + template + T singletonInstance(int qmlTypeId); + public Q_SLOTS: void retranslate(); @@ -167,6 +170,19 @@ private: Q_DECLARE_PRIVATE(QQmlEngine) }; +template<> +Q_QML_EXPORT QJSValue QQmlEngine::singletonInstance(int qmlTypeId); + +template +T QQmlEngine::singletonInstance(int qmlTypeId) { + QJSValue instance = singletonInstance(qmlTypeId); + if (!instance.isQObject()) + return nullptr; + + QObject *object = instance.toQObject(); + return qobject_cast(object); +} + QT_END_NAMESPACE #endif // QQMLENGINE_H diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 307f9a9ec6..dd027818cd 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -1863,6 +1863,23 @@ void qmlRegisterModule(const char *uri, int versionMajor, int versionMinor) p->maxMinorVersion = qMax(p->maxMinorVersion, versionMinor); } +//From qqml.h +int qmlTypeId(const char *uri, int versionMajor, int versionMinor, const char *qmlName) +{ + QMutexLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + + QQmlTypeModule *module = getTypeModule(QString::fromUtf8(uri), versionMajor, data); + if (!module) + return -1; + + QQmlType type = module->type(QHashedStringRef(qmlName), versionMinor); + if (!type.isValid()) + return -1; + + return type.index(); +} + bool QQmlMetaType::namespaceContainsRegistrations(const QString &uri, int majorVersion) { const QQmlMetaTypeData *data = metaTypeData(); @@ -2242,19 +2259,25 @@ QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStrin } /*! - Returns the type (if any) that corresponds to the QVariant::Type \a userType. - Returns null if no type is registered. + Returns the type (if any) that corresponds to \a typeId. Depending on \a category, the + \a typeId is interpreted either as QVariant::Type or as QML type id returned by one of the + qml type registration functions. Returns null if no type is registered. */ -QQmlType QQmlMetaType::qmlType(int userType) +QQmlType QQmlMetaType::qmlType(int typeId, TypeIdCategory category) { QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); - QQmlTypePrivate *type = data->idToType.value(userType); - if (type && type->typeId == userType) - return QQmlType(type); - else - return QQmlType(); + if (category == TypeIdCategory::MetaType) { + QQmlTypePrivate *type = data->idToType.value(typeId); + if (type && type->typeId == typeId) + return QQmlType(type); + } else if (category == TypeIdCategory::QmlType) { + QQmlType type = data->types.value(typeId); + if (type.isValid()) + return type; + } + return QQmlType(); } /*! diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h index 51bf485a3e..6df439cd7a 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -91,11 +91,16 @@ public: static QList qmlSingletonTypes(); static QList qmlAllTypes(); + enum class TypeIdCategory { + MetaType, + QmlType + }; + static QQmlType qmlType(const QString &qualifiedName, int, int); static QQmlType qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int, int); static QQmlType qmlType(const QMetaObject *); static QQmlType qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor); - static QQmlType qmlType(int); + static QQmlType qmlType(int typeId, TypeIdCategory category = TypeIdCategory::MetaType); static QQmlType qmlType(const QUrl &unNormalizedUrl, bool includeNonFileImports = false); static QQmlPropertyCache *propertyCache(const QMetaObject *metaObject); -- cgit v1.2.3