diff options
author | Maximilian Goldstein <max.goldstein@qt.io> | 2021-01-19 17:54:45 +0100 |
---|---|---|
committer | Maximilian Goldstein <max.goldstein@qt.io> | 2021-01-20 12:07:34 +0100 |
commit | bf573ad295fbc1eee9379bfaafcded293c4b81f4 (patch) | |
tree | 330a69b72e7de269753c4563c8d59bac5a533d3d | |
parent | e9997bc96911923355af2e1dd081cc039a2b2b8f (diff) |
QML_SINGLETON: Handle local create() functions with foreign types
Previously only the foreign type was searched for a create method.
Now the wrapping type can also contain it.
Change-Id: I05fb9e0c0a54c14530eb9adcae5a44df5c208be3
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
-rw-r--r-- | src/qml/qml/qqml.h | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmlprivate.h | 53 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/data/foreignSingleton.qml | 6 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/testtypes.h | 31 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 11 |
5 files changed, 82 insertions, 21 deletions
diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h index bac8039251..61eb5e1ffe 100644 --- a/src/qml/qml/qqml.h +++ b/src/qml/qml/qqml.h @@ -841,7 +841,7 @@ struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, true, false, false static void registerTypeAndRevisions(const char *uri, int versionMajor, QList<int> *qmlTypeIds, const QMetaObject *extension) { - QQmlPrivate::qmlRegisterSingletonAndRevisions<Resolved, Extended>( + QQmlPrivate::qmlRegisterSingletonAndRevisions<Resolved, Extended, T>( uri, versionMajor, QQmlPrivate::StaticMetaObject<T>::staticMetaObject(), qmlTypeIds, extension); } diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h index ce83b33eaa..1b994b88e1 100644 --- a/src/qml/qml/qqmlprivate.h +++ b/src/qml/qml/qqmlprivate.h @@ -149,30 +149,33 @@ namespace QQmlPrivate { None, Constructor, - Factory + Factory, + FactoryWrapper }; - template<typename T, typename = std::void_t<>> + template<typename T, typename WrapperT = T, typename = std::void_t<>> struct HasSingletonFactory { static constexpr bool value = false; }; - template<typename T> - struct HasSingletonFactory<T, std::void_t<decltype(T::create( - static_cast<QQmlEngine *>(nullptr), - static_cast<QJSEngine *>(nullptr)))>> + template<typename T, typename WrapperT> + struct HasSingletonFactory<T, WrapperT, std::void_t<decltype(WrapperT::create( + static_cast<QQmlEngine *>(nullptr), + static_cast<QJSEngine *>(nullptr)))>> { static constexpr bool value = std::is_same_v< - decltype(T::create(static_cast<QQmlEngine *>(nullptr), + decltype(WrapperT::create(static_cast<QQmlEngine *>(nullptr), static_cast<QJSEngine *>(nullptr))), T *>; }; - template<typename T> + template<typename T, typename WrapperT> constexpr ConstructionMode constructionMode() { if constexpr (!std::is_base_of<QObject, T>::value) return ConstructionMode::None; + if constexpr (!std::is_same_v<T, WrapperT> && HasSingletonFactory<T, WrapperT>::value) + return ConstructionMode::FactoryWrapper; if constexpr (std::is_default_constructible<T>::value) return ConstructionMode::Constructor; if constexpr (HasSingletonFactory<T>::value) @@ -184,7 +187,7 @@ namespace QQmlPrivate template<typename T> void createInto(void *memory, void *) { new (memory) QQmlElement<T>; } - template<typename T, ConstructionMode Mode> + template<typename T, typename WrapperT, ConstructionMode Mode> QObject *createSingletonInstance(QQmlEngine *q, QJSEngine *j) { Q_UNUSED(q); @@ -193,6 +196,8 @@ namespace QQmlPrivate return new T; else if constexpr (Mode == ConstructionMode::Factory) return T::create(q, j); + else if constexpr (Mode == ConstructionMode::FactoryWrapper) + return WrapperT::create(q, j); else return nullptr; } @@ -205,31 +210,39 @@ namespace QQmlPrivate using CreateParentFunction = QObject *(*)(QObject *); using CreateValueTypeFunction = QVariant (*)(const QJSValue &); - template<typename T, ConstructionMode Mode = constructionMode<T>()> + template<typename T, typename WrapperT = T, ConstructionMode Mode = constructionMode<T, WrapperT>()> struct Constructors; - template<typename T> - struct Constructors<T, ConstructionMode::Constructor> + template<typename T, typename WrapperT> + struct Constructors<T, WrapperT, ConstructionMode::Constructor> { static constexpr CreateIntoFunction createInto = QQmlPrivate::createInto<T>; static constexpr CreateSingletonFunction createSingletonInstance - = QQmlPrivate::createSingletonInstance<T, ConstructionMode::Constructor>; + = QQmlPrivate::createSingletonInstance<T, WrapperT, ConstructionMode::Constructor>; }; - template<typename T> - struct Constructors<T, ConstructionMode::None> + template<typename T, typename WrapperT> + struct Constructors<T, WrapperT, ConstructionMode::None> { static constexpr CreateIntoFunction createInto = nullptr; static constexpr CreateSingletonFunction createSingletonInstance = nullptr; }; - template<typename T> - struct Constructors<T, ConstructionMode::Factory> + template<typename T, typename WrapperT> + struct Constructors<T, WrapperT, ConstructionMode::Factory> { static constexpr CreateIntoFunction createInto = nullptr; static constexpr CreateSingletonFunction createSingletonInstance - = QQmlPrivate::createSingletonInstance<T, ConstructionMode::Factory>; + = QQmlPrivate::createSingletonInstance<T, WrapperT, ConstructionMode::Factory>; + }; + + template<typename T, typename WrapperT> + struct Constructors<T, WrapperT, ConstructionMode::FactoryWrapper> + { + static constexpr CreateIntoFunction createInto = nullptr; + static constexpr CreateSingletonFunction createSingletonInstance + = QQmlPrivate::createSingletonInstance<T, WrapperT, ConstructionMode::FactoryWrapper>; }; template<typename T, @@ -805,7 +818,7 @@ namespace QQmlPrivate } }; - template<typename T, typename E> + template<typename T, typename E, typename WrapperT = T> void qmlRegisterSingletonAndRevisions(const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject, QVector<int> *qmlTypeIds, const QMetaObject *extension) @@ -816,7 +829,7 @@ namespace QQmlPrivate uri, QTypeRevision::fromMajorVersion(versionMajor), - Constructors<T>::createSingletonInstance, + Constructors<T, WrapperT>::createSingletonInstance, StaticMetaObject<T>::staticMetaObject(), classInfoMetaObject, diff --git a/tests/auto/qml/qqmllanguage/data/foreignSingleton.qml b/tests/auto/qml/qqmllanguage/data/foreignSingleton.qml new file mode 100644 index 0000000000..1649df6a25 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/foreignSingleton.qml @@ -0,0 +1,6 @@ +import QtQml 2.0 +import StaticTest 1.0 + +QtObject { + property int number: ForeignSingleton.number +} diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h index 003e9d06ad..758b9e2f62 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.h +++ b/tests/auto/qml/qqmllanguage/testtypes.h @@ -1607,6 +1607,37 @@ public: int foo() const { return 316; } }; +class ForeignSingleton : public QObject { + Q_OBJECT + Q_PROPERTY(int number READ number WRITE setnumber NOTIFY numberchanged) +public: + ForeignSingleton(QObject *parent = nullptr) : QObject(parent) {}; + int number() { return m_number; } + void setnumber(int number) { m_number = number; } + static ForeignSingleton *obtain() { return new ForeignSingleton; } +signals: + void numberchanged(); +private: + int m_number = 0; +}; + +class WrapperSingleton : public QObject { + Q_OBJECT + QML_NAMED_ELEMENT(ForeignSingleton) + QML_FOREIGN(ForeignSingleton) + QML_SINGLETON + +public: + static ForeignSingleton* create(QQmlEngine *, QJSEngine *) { + ForeignSingleton *singleton = ForeignSingleton::obtain(); + singleton->setnumber(42); + return singleton; + } + +private: + WrapperSingleton() = default; +}; + void registerTypes(); #endif // TESTTYPES_H diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 4f4ee45f68..454ae59ad3 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -313,6 +313,7 @@ private slots: void typeWrapperToVariant(); void extendedForeignTypes(); + void foreignTypeSingletons(); void inlineComponent(); void inlineComponent_data(); @@ -5496,6 +5497,16 @@ void tst_qqmllanguage::extendedForeignTypes() QCOMPARE(o->property("foreignExtendedObjectName").toString(), QLatin1String("foreignExtended")); } +void tst_qqmllanguage::foreignTypeSingletons() { + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("foreignSingleton.qml")); + VERIFY_ERRORS(0); + QScopedPointer<QObject> o(component.create()); + QVERIFY(!o.isNull()); + + QCOMPARE(o->property("number").toInt(), 42); +} + void tst_qqmllanguage::selfReference() { QQmlEngine engine; |