aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/doc/snippets/code/src_qml_qqmlengine.cpp7
-rw-r--r--src/qml/qml/qqmlcomponent.cpp45
-rw-r--r--src/qml/qml/qqmlengine.cpp72
-rw-r--r--src/qml/qml/qqmlengine.h12
-rw-r--r--src/qml/qml/qqmlengine_p.h20
-rw-r--r--tests/auto/qml/qqmlengine/CMakeLists.txt14
-rw-r--r--tests/auto/qml/qqmlengine/declarativelyregistered.cpp8
-rw-r--r--tests/auto/qml/qqmlengine/declarativelyregistered.h20
-rw-r--r--tests/auto/qml/qqmlengine/tst_qqmlengine.cpp21
9 files changed, 174 insertions, 45 deletions
diff --git a/src/qml/doc/snippets/code/src_qml_qqmlengine.cpp b/src/qml/doc/snippets/code/src_qml_qqmlengine.cpp
index 7057718b52..ff4cf634a0 100644
--- a/src/qml/doc/snippets/code/src_qml_qqmlengine.cpp
+++ b/src/qml/doc/snippets/code/src_qml_qqmlengine.cpp
@@ -42,3 +42,10 @@ void wrapper4(int typeId) {
QJSValue instance = engine.singletonInstance<QJSValue>(typeId);
//! [4]
}
+
+void wrapper5() {
+///! [5]
+ QQmlEngine engine;
+ MySingleton *singleton = engine.singletonInstance<MySingleton *>("mymodule", "MySingleton");
+///! [5]
+}
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index 7b9c96b6d6..e615332402 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -1238,51 +1238,6 @@ QQmlComponentAttached *QQmlComponent::qmlAttachedProperties(QObject *obj)
return a;
}
-struct LoadHelper final : QQmlTypeLoader::Blob
-{
- LoadHelper(QQmlTypeLoader *loader, QAnyStringView uri)
- : QQmlTypeLoader::Blob({}, QQmlDataBlob::QmlFile, loader)
- , m_uri(uri.toString())
-
- {
- auto import = std::make_shared<PendingImport>();
- import->uri = uri.toString();
- QList<QQmlError> errorList;
- Blob::addImport(import, &errorList);
- }
-
- struct ResolveTypeResult
- {
- enum Status { NoSuchModule, ModuleFound } status;
- QQmlType type;
- };
-
- ResolveTypeResult resolveType(QAnyStringView typeName)
- {
- QQmlType type;
- QQmlTypeModule *module = QQmlMetaType::typeModule(m_uri, QTypeRevision{});
- if (!module)
- return {ResolveTypeResult::NoSuchModule, type};
- type = module->type(typeName.toString(), {});
- if (type.isValid())
- return {ResolveTypeResult::ModuleFound, type};
- QTypeRevision versionReturn;
- QList<QQmlError> errors;
- QQmlImportNamespace *ns_return = nullptr;
- m_importCache->resolveType(typeName.toString(), &type, &versionReturn,
- &ns_return,
- &errors);
- return {ResolveTypeResult::ModuleFound, type};
- }
-
-protected:
- void dataReceived(const SourceCodeData &) override { Q_UNREACHABLE(); }
- void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *) override { Q_UNREACHABLE(); }
-
-private:
- QString m_uri;
-};
-
/*!
Load the QQmlComponent for \a typeName in the module \a uri.
If the type is implemented via a QML file, \a mode is used to
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index bd33650d9a..ae56c7ea2a 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -999,6 +999,48 @@ QJSValue QQmlEngine::singletonInstance<QJSValue>(int qmlTypeId)
return d->singletonInstance<QJSValue>(type);
}
+
+/*!
+ \fn template<typename T> T QQmlEngine::singletonInstance(QAnyStringView uri, QAnyStringView typeName)
+
+ \overload
+ Returns the instance of a singleton type named \a typeName from the module specified by \a uri.
+
+ This method can be used as an alternative to calling qmlTypeId followed by the id based overload of
+ singletonInstance. This is convenient when one only needs to do a one time setup of a
+ singleton; if repeated access to the singleton is required, caching its typeId will allow
+ faster subsequent access via the
+ \l {QQmlEngine::singletonInstance(int qmlTypeId)}{type-id based overload}.
+
+ 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 typeName does not represent a valid singleton
+ type, either a default constructed QJSValue or a \c nullptr is returned.
+
+ \snippet code/src_qml_qqmlengine.cpp 5
+
+ \sa QML_SINGLETON, qmlRegisterSingletonType(), qmlTypeId()
+ \since 6.5
+*/
+template<>
+QJSValue QQmlEngine::singletonInstance<QJSValue>(QAnyStringView uri, QAnyStringView typeName)
+{
+ Q_D(QQmlEngine);
+
+ auto loadHelper = QQml::makeRefPointer<LoadHelper>(&d->typeLoader, uri);
+
+ auto [moduleStatus, type] = loadHelper->resolveType(typeName);
+
+ if (moduleStatus == LoadHelper::ResolveTypeResult::NoSuchModule)
+ return {};
+ if (!type.isValid())
+ return {};
+ if (!type.isSingleton())
+ return {};
+
+ return d->singletonInstance<QJSValue>(type);
+}
+
/*!
Refreshes all binding expressions that use strings marked for translation.
@@ -1976,8 +2018,38 @@ bool QQml_isFileCaseCorrect(const QString &fileName, int lengthIn /* = -1 */)
void hasJsOwnershipIndicator(QQmlGuardImpl *) {};
+LoadHelper::LoadHelper(QQmlTypeLoader *loader, QAnyStringView uri)
+ : QQmlTypeLoader::Blob({}, QQmlDataBlob::QmlFile, loader)
+ , m_uri(uri.toString())
+
+{
+ auto import = std::make_shared<PendingImport>();
+ import->uri = uri.toString();
+ QList<QQmlError> errorList;
+ Blob::addImport(import, &errorList);
+}
+
+LoadHelper::ResolveTypeResult LoadHelper::resolveType(QAnyStringView typeName)
+{
+ QQmlType type;
+ QQmlTypeModule *module = QQmlMetaType::typeModule(m_uri, QTypeRevision{});
+ if (!module)
+ return {ResolveTypeResult::NoSuchModule, type};
+ type = module->type(typeName.toString(), {});
+ if (type.isValid())
+ return {ResolveTypeResult::ModuleFound, type};
+ QTypeRevision versionReturn;
+ QList<QQmlError> errors;
+ QQmlImportNamespace *ns_return = nullptr;
+ m_importCache->resolveType(typeName.toString(), &type, &versionReturn,
+ &ns_return,
+ &errors);
+ return {ResolveTypeResult::ModuleFound, type};
+}
+
QT_END_NAMESPACE
#include "moc_qqmlengine_p.cpp"
#include "moc_qqmlengine.cpp"
+
diff --git a/src/qml/qml/qqmlengine.h b/src/qml/qml/qqmlengine.h
index 7f225f57f5..a8b19e41c6 100644
--- a/src/qml/qml/qqmlengine.h
+++ b/src/qml/qml/qqmlengine.h
@@ -126,6 +126,9 @@ public:
template<typename T>
T singletonInstance(int qmlTypeId);
+ template<typename T>
+ T singletonInstance(QAnyStringView moduleName, QAnyStringView typeName);
+
void captureProperty(QObject *object, const QMetaProperty &property) const;
public Q_SLOTS:
@@ -160,6 +163,15 @@ T QQmlEngine::singletonInstance(int qmlTypeId) {
return qobject_cast<T>(singletonInstance<QJSValue>(qmlTypeId).toQObject());
}
+template<>
+Q_QML_EXPORT QJSValue QQmlEngine::singletonInstance<QJSValue>(QAnyStringView uri, QAnyStringView typeName);
+
+template<typename T>
+T QQmlEngine::singletonInstance(QAnyStringView uri, QAnyStringView typeName)
+{
+ return qobject_cast<T>(singletonInstance<QJSValue>(uri, typeName).toQObject());
+}
+
QT_END_NAMESPACE
#endif // QQMLENGINE_H
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index 6d27d7759c..366d34c366 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -378,6 +378,26 @@ T QQmlEnginePrivate::singletonInstance(const QQmlType &type) {
return qobject_cast<T>(singletonInstance<QJSValue>(type).toQObject());
}
+struct LoadHelper final : QQmlTypeLoader::Blob
+{
+ LoadHelper(QQmlTypeLoader *loader, QAnyStringView uri);
+
+ struct ResolveTypeResult
+ {
+ enum Status { NoSuchModule, ModuleFound } status;
+ QQmlType type;
+ };
+
+ ResolveTypeResult resolveType(QAnyStringView typeName);
+
+protected:
+ void dataReceived(const SourceCodeData &) final { Q_UNREACHABLE(); }
+ void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *) final { Q_UNREACHABLE(); }
+
+private:
+ QString m_uri;
+};
+
QT_END_NAMESPACE
diff --git a/tests/auto/qml/qqmlengine/CMakeLists.txt b/tests/auto/qml/qqmlengine/CMakeLists.txt
index a2eb1abc29..a799a20dcd 100644
--- a/tests/auto/qml/qqmlengine/CMakeLists.txt
+++ b/tests/auto/qml/qqmlengine/CMakeLists.txt
@@ -26,6 +26,20 @@ qt_internal_add_test(tst_qqmlengine
TESTDATA ${test_data}
)
+
+qt_add_library(tst_qqmlengine_qml STATIC)
+qt_autogen_tools_initial_setup(tst_qqmlengine_qml)
+qt_add_qml_module(tst_qqmlengine_qml
+ URI OnlyDeclarative
+ VERSION 1.0
+ SOURCES
+ "declarativelyregistered.h"
+ "declarativelyregistered.cpp"
+)
+
+qt_autogen_tools_initial_setup(tst_qqmlengine_qmlplugin)
+target_link_libraries(tst_qqmlengine PRIVATE tst_qqmlengine_qmlplugin)
+
# Resources:
set(qmake_immediate_resource_files
"data/qrcurls.js"
diff --git a/tests/auto/qml/qqmlengine/declarativelyregistered.cpp b/tests/auto/qml/qqmlengine/declarativelyregistered.cpp
new file mode 100644
index 0000000000..9893fa0311
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/declarativelyregistered.cpp
@@ -0,0 +1,8 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "declarativelyregistered.h"
+
+PurelyDeclarativeSingleton::PurelyDeclarativeSingleton(QObject *parent) : QObject(parent) {};
+
+#include "moc_declarativelyregistered.cpp"
diff --git a/tests/auto/qml/qqmlengine/declarativelyregistered.h b/tests/auto/qml/qqmlengine/declarativelyregistered.h
new file mode 100644
index 0000000000..98f7250d76
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/declarativelyregistered.h
@@ -0,0 +1,20 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef DECLARATIVELYREGISTERED_H
+#define DECLARATIVELYREGISTERED_H
+
+#include <QtCore/qobject.h>
+#include <QtQml/qqmlregistration.h>
+
+class PurelyDeclarativeSingleton : public QObject
+{
+ Q_OBJECT
+ QML_SINGLETON
+ QML_ELEMENT
+public:
+ PurelyDeclarativeSingleton(QObject *parent = nullptr);
+};
+
+
+#endif
diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
index 991af073fb..895513d822 100644
--- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
+++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
@@ -16,12 +16,17 @@
#include <QQmlExpression>
#include <QQmlIncubationController>
#include <QTemporaryDir>
+ #include <QQmlEngineExtensionPlugin>
#include <private/qqmlengine_p.h>
#include <private/qqmltypedata_p.h>
#include <private/qqmlcomponentattached_p.h>
#include <QQmlAbstractUrlInterceptor>
#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include "declarativelyregistered.h"
+
+Q_IMPORT_QML_PLUGIN(OnlyDeclarativePlugin)
+
class tst_qqmlengine : public QQmlDataTest
{
Q_OBJECT
@@ -1148,6 +1153,8 @@ void tst_qqmlengine::singletonInstance()
QObject *instance = value.toQObject();
QVERIFY(instance);
QCOMPARE(instance->metaObject()->className(), "CppSingleton");
+
+ QCOMPARE(engine.singletonInstance<CppSingleton *>("Test", "CppSingleton"), instance);
}
{
@@ -1219,6 +1226,20 @@ void tst_qqmlengine::singletonInstance()
QVERIFY(!noSinglePtr);
}
+ // test the case where we haven't loaded the module yet
+ {
+ auto singleton = engine.singletonInstance<PurelyDeclarativeSingleton *>("OnlyDeclarative", "PurelyDeclarativeSingleton");
+ QVERIFY(singleton);
+ // requesting the singleton twice yields the same result
+ auto again = engine.singletonInstance<PurelyDeclarativeSingleton *>("OnlyDeclarative", "PurelyDeclarativeSingleton");
+ QCOMPARE(again, singleton);
+
+ // different engines -> different singletons
+ QQmlEngine engine2;
+ auto differentEngine = engine2.singletonInstance<PurelyDeclarativeSingleton *>("OnlyDeclarative", "PurelyDeclarativeSingleton");
+ QCOMPARE_NE(differentEngine, singleton);
+ }
+
{
// Invalid types
QJSValue value;