diff options
-rw-r--r-- | src/qml/qml/qqml.cpp | 2 | ||||
-rw-r--r-- | src/qml/qml/qqml.h | 16 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine.cpp | 3 | ||||
-rw-r--r-- | src/qml/qml/qqmlmetatype.cpp | 39 | ||||
-rw-r--r-- | src/qml/qml/qqmlprivate.h | 16 | ||||
-rw-r--r-- | src/qml/qml/qqmltype.cpp | 73 | ||||
-rw-r--r-- | src/qml/qml/qqmltype_p.h | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmltype_p_p.h | 2 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/testtypes.h | 24 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 23 |
10 files changed, 156 insertions, 44 deletions
diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp index 5dd245f2a3..56a0595e0e 100644 --- a/src/qml/qml/qqml.cpp +++ b/src/qml/qml/qqml.cpp @@ -385,6 +385,8 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data) type.qObjectApi, type.instanceMetaObject, type.typeId, + type.extensionObjectCreate, + type.extensionMetaObject, QTypeRevision() }; diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h index 9118b42390..75f7ae5f06 100644 --- a/src/qml/qml/qqml.h +++ b/src/qml/qml/qqml.h @@ -677,7 +677,9 @@ inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versi uri, QTypeRevision::fromVersion(versionMajor, versionMinor), typeName, callback, - nullptr, nullptr, QMetaType(), QTypeRevision::zero() + nullptr, nullptr, QMetaType(), + nullptr, nullptr, + QTypeRevision::zero() }; return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api); @@ -697,6 +699,7 @@ inline int qmlRegisterSingletonType( callback, QQmlPrivate::StaticMetaObject<T>::staticMetaObject(), QQmlPrivate::QmlMetaType<T>::self(), + nullptr, nullptr, QTypeRevision::zero() }; @@ -722,6 +725,7 @@ inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versi callback, QQmlPrivate::StaticMetaObject<T>::staticMetaObject(), QQmlPrivate::QmlMetaType<T>::self(), + nullptr, nullptr, QTypeRevision::zero() }; @@ -808,14 +812,14 @@ struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, false, false> { } }; -template<class T, class Resolved> -struct QmlTypeAndRevisionsRegistration<T, Resolved, void, true, false> { +template<class T, class Resolved, class Extended> +struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, true, false> { static void registerTypeAndRevisions(const char *uri, int versionMajor, QList<int> *qmlTypeIds, - const QMetaObject *) + const QMetaObject *extension) { - QQmlPrivate::qmlRegisterSingletonAndRevisions<Resolved>( + QQmlPrivate::qmlRegisterSingletonAndRevisions<Resolved, Extended>( uri, versionMajor, QQmlPrivate::StaticMetaObject<T>::staticMetaObject(), - qmlTypeIds); + qmlTypeIds, extension); } }; diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 0b4493df79..588ccea11c 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -61,6 +61,7 @@ #include <private/qqmldirparser_p.h> #include <private/qqmlboundsignal_p.h> #include <private/qqmljsdiagnosticmessage_p.h> +#include <private/qqmltype_p_p.h> #include <QtCore/qstandardpaths.h> #include <QtCore/qmetaobject.h> #include <QDebug> @@ -2398,6 +2399,8 @@ QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type) qPrintable(QString::fromUtf8(type.typeName())))); warning(error); } else { + type.createProxy(o); + // if this object can use a property cache, create it now QQmlData::ensurePropertyCache(q, o); } diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index df5c4d89c5..e59ebc97eb 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -152,6 +152,8 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el d->extraData.sd->singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName); d->extraData.sd->singletonInstanceInfo->instanceMetaObject = type.qObjectApi ? type.instanceMetaObject : nullptr; + d->extraData.sd->extFunc = type.extensionObjectCreate; + d->extraData.sd->extMetaObject = type.extensionMetaObject; return d; } @@ -1606,23 +1608,34 @@ QList<QQmlProxyMetaObject::ProxyData> QQmlMetaType::proxyData(const QMetaObject const QQmlMetaTypeDataPtr data; + auto createProxyMetaObject = [&](const QMetaObject *superdataBaseMetaObject, + const QMetaObject *extMetaObject, + QObject *(*extFunc)(QObject *)) { + if (!extMetaObject) + return; + + QMetaObjectBuilder builder; + clone(builder, extMetaObject, superdataBaseMetaObject, baseMetaObject); + builder.setFlags(MetaObjectFlag::DynamicMetaObject); + QMetaObject *mmo = builder.toMetaObject(); + mmo->d.superdata = baseMetaObject; + if (!metaObjects.isEmpty()) + metaObjects.constLast().metaObject->d.superdata = mmo; + else if (lastMetaObject) + lastMetaObject->d.superdata = mmo; + QQmlProxyMetaObject::ProxyData data = { mmo, extFunc, 0, 0 }; + metaObjects << data; + }; + while (mo) { QQmlTypePrivate *t = data->metaObjectToType.value(mo); if (t) { if (t->regType == QQmlType::CppType) { - if (t->extraData.cd->extMetaObject) { - QMetaObjectBuilder builder; - clone(builder, t->extraData.cd->extMetaObject, t->baseMetaObject, baseMetaObject); - builder.setFlags(MetaObjectFlag::DynamicMetaObject); - QMetaObject *mmo = builder.toMetaObject(); - mmo->d.superdata = baseMetaObject; - if (!metaObjects.isEmpty()) - metaObjects.constLast().metaObject->d.superdata = mmo; - else if (lastMetaObject) - lastMetaObject->d.superdata = mmo; - QQmlProxyMetaObject::ProxyData data = { mmo, t->extraData.cd->extFunc, 0, 0 }; - metaObjects << data; - } + createProxyMetaObject(t->baseMetaObject, t->extraData.cd->extMetaObject, + t->extraData.cd->extFunc); + } else if (t->regType == QQmlType::SingletonType) { + createProxyMetaObject(t->baseMetaObject, t->extraData.sd->extMetaObject, + t->extraData.sd->extFunc); } } mo = mo->d.superdata; diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h index 4fcfd65c09..19072f0751 100644 --- a/src/qml/qml/qqmlprivate.h +++ b/src/qml/qml/qqmlprivate.h @@ -526,6 +526,10 @@ namespace QQmlPrivate const QMetaObject *instanceMetaObject; QMetaType typeId; + + QObject *(*extensionObjectCreate)(QObject *); + const QMetaObject *extensionMetaObject; + QTypeRevision revision; }; @@ -540,6 +544,10 @@ namespace QQmlPrivate const QMetaObject *classInfoMetaObject; QMetaType typeId; + + QObject *(*extensionObjectCreate)(QObject *); + const QMetaObject *extensionMetaObject; + QVector<int> *qmlTypeIds; }; @@ -752,10 +760,10 @@ namespace QQmlPrivate } }; - template<typename T> + template<typename T, typename E> void qmlRegisterSingletonAndRevisions(const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject, - QVector<int> *qmlTypeIds) + QVector<int> *qmlTypeIds, const QMetaObject *extension) { RegisterSingletonTypeAndRevisions api = { 0, @@ -769,6 +777,10 @@ namespace QQmlPrivate classInfoMetaObject, QmlMetaType<T>::self(), + + ExtendedType<E>::createParent, + extension ? extension : ExtendedType<E>::staticMetaObject(), + qmlTypeIds }; diff --git a/src/qml/qml/qqmltype.cpp b/src/qml/qml/qqmltype.cpp index e5b3653d2d..811ff668c6 100644 --- a/src/qml/qml/qqmltype.cpp +++ b/src/qml/qml/qqmltype.cpp @@ -78,6 +78,8 @@ QQmlTypePrivate::QQmlTypePrivate(QQmlType::RegistrationType type) case QQmlType::CompositeSingletonType: extraData.sd = new QQmlSingletonTypeData; extraData.sd->singletonInstanceInfo = nullptr; + extraData.sd->extFunc = nullptr; + extraData.sd->extMetaObject = nullptr; break; case QQmlType::InterfaceType: extraData.cd = nullptr; @@ -214,20 +216,27 @@ void QQmlTypePrivate::init() const return; } - if (regType == QQmlType::CppType) { - // Setup extended meta object + auto setupExtendedMetaObject = [&]( + const QMetaObject *extMetaObject, + QObject *(*extFunc)(QObject *)) { + + if (!extMetaObject) + return; + // XXX - very inefficient - if (extraData.cd->extMetaObject) { - QMetaObjectBuilder builder; - QQmlMetaType::clone(builder, extraData.cd->extMetaObject, extraData.cd->extMetaObject, - extraData.cd->extMetaObject); - builder.setFlags(MetaObjectFlag::DynamicMetaObject); - QMetaObject *mmo = builder.toMetaObject(); - mmo->d.superdata = mo; - QQmlProxyMetaObject::ProxyData data = { mmo, extraData.cd->extFunc, 0, 0 }; - metaObjects << data; - } - } + QMetaObjectBuilder builder; + QQmlMetaType::clone(builder, extMetaObject, extMetaObject, extMetaObject); + builder.setFlags(MetaObjectFlag::DynamicMetaObject); + QMetaObject *mmo = builder.toMetaObject(); + mmo->d.superdata = mo; + QQmlProxyMetaObject::ProxyData data = { mmo, extFunc, 0, 0 }; + metaObjects << data; + }; + + if (regType == QQmlType::SingletonType) + setupExtendedMetaObject(extraData.sd->extMetaObject, extraData.sd->extFunc); + else if (regType == QQmlType::CppType) + setupExtendedMetaObject(extraData.cd->extMetaObject, extraData.cd->extFunc); metaObjects.append(QQmlMetaType::proxyData( mo, baseMetaObject, metaObjects.isEmpty() ? nullptr @@ -477,9 +486,7 @@ QObject *QQmlType::create() const d->extraData.cd->newFunc(rv, d->extraData.cd->userdata); - if (rv && !d->metaObjects.isEmpty()) - (void)new QQmlProxyMetaObject(rv, &d->metaObjects); - + createProxy(rv); return rv; } @@ -493,9 +500,7 @@ void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) con QObject *rv = (QObject *)operator new(d->extraData.cd->allocationSize + additionalMemory); d->extraData.cd->newFunc(rv, d->extraData.cd->userdata); - if (rv && !d->metaObjects.isEmpty()) - (void)new QQmlProxyMetaObject(rv, &d->metaObjects); - + createProxy(rv); *out = rv; *memory = ((char *)rv) + d->extraData.cd->allocationSize; } @@ -546,16 +551,32 @@ bool QQmlType::isCreatable() const QQmlType::ExtensionFunc QQmlType::extensionFunction() const { - if (!d || d->regType != CppType) + if (!d) + return nullptr; + + switch (d->regType) { + case CppType: + return d->extraData.cd->extFunc; + case SingletonType: + return d->extraData.sd->extFunc; + default: return nullptr; - return d->extraData.cd->extFunc; + } } const QMetaObject *QQmlType::extensionMetaObject() const { - if (!d || d->regType != CppType) + if (!d) + return nullptr; + + switch (d->regType) { + case CppType: + return d->extraData.cd->extMetaObject; + case SingletonType: + return d->extraData.sd->extMetaObject; + default: return nullptr; - return d->extraData.cd->extMetaObject; + } } bool QQmlType::isExtendedType() const @@ -976,4 +997,10 @@ QString QQmlType::pendingResolutionName() const return d->extraData.id->inlineComponentName; } +void QQmlType::createProxy(QObject *instance) const +{ + if (!d->metaObjects.isEmpty()) + (void)new QQmlProxyMetaObject(instance, &d->metaObjects); +} + QT_END_NAMESPACE diff --git a/src/qml/qml/qqmltype_p.h b/src/qml/qml/qqmltype_p.h index 0655583e1e..cbbfe955cc 100644 --- a/src/qml/qml/qqmltype_p.h +++ b/src/qml/qml/qqmltype_p.h @@ -201,6 +201,8 @@ public: void setPendingResolutionName(const QString &name); QString pendingResolutionName() const; + void createProxy(QObject *instance) const; + private: friend class QQmlTypePrivate; friend size_t qHash(const QQmlType &t, size_t seed); diff --git a/src/qml/qml/qqmltype_p_p.h b/src/qml/qml/qqmltype_p_p.h index 426b9ced37..2a375baa83 100644 --- a/src/qml/qml/qqmltype_p_p.h +++ b/src/qml/qml/qqmltype_p_p.h @@ -131,6 +131,8 @@ public: struct QQmlSingletonTypeData { QQmlType::SingletonInstanceInfo *singletonInstanceInfo; + QObject *(*extFunc)(QObject *); + const QMetaObject *extMetaObject; }; struct QQmlCompositeTypeData diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h index cdcc5faed8..003e9d06ad 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.h +++ b/tests/auto/qml/qqmllanguage/testtypes.h @@ -1583,6 +1583,30 @@ private: FactorySingleton() = default; }; +class ExtendedSingleton : public QObject { + Q_OBJECT + QML_ELEMENT + QML_SINGLETON + QML_EXTENDED(Extension) + + Q_PROPERTY(int foo READ foo CONSTANT) +public: + + int foo() const { return 315; } +}; + +class NamespaceExtendedSingleton : public QObject { + Q_OBJECT + QML_ELEMENT + QML_SINGLETON + QML_EXTENDED_NAMESPACE(ExtensionNamespace) + + Q_PROPERTY(int foo READ foo CONSTANT) +public: + + int foo() const { return 316; } +}; + void registerTypes(); #endif // TESTTYPES_H diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 40a2ee887a..9a9f13ee0a 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -342,6 +342,7 @@ private slots: void registerValueTypes(); void extendedNamespace(); void factorySingleton(); + void extendedSingleton(); private: QQmlEngine engine; @@ -6065,6 +6066,28 @@ void tst_qqmllanguage::factorySingleton() QCOMPARE(obj->property("mine").toInt(), 314); } +void tst_qqmllanguage::extendedSingleton() +{ + QQmlEngine engine; + QQmlComponent c(&engine); + c.setData("import StaticTest\n" + "import QtQml\n" + "QtObject {\n" + " property int a: ExtendedSingleton.foo\n" + " property int b: NamespaceExtendedSingleton.foo\n" + " property int c: ExtendedSingleton.extension\n" + " property int d: NamespaceExtendedSingleton.Bar\n" + "}", QUrl()); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QScopedPointer<QObject> obj(c.create()); + QVERIFY(!obj.isNull()); + + QCOMPARE(obj->property("a").toInt(), 315); + QCOMPARE(obj->property("b").toInt(), 316); + QCOMPARE(obj->property("c").toInt(), 42); + QCOMPARE(obj->property("d").toInt(), 9); +} + QTEST_MAIN(tst_qqmllanguage) #include "tst_qqmllanguage.moc" |