aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/qml/qqml.cpp2
-rw-r--r--src/qml/qml/qqml.h16
-rw-r--r--src/qml/qml/qqmlengine.cpp3
-rw-r--r--src/qml/qml/qqmlmetatype.cpp39
-rw-r--r--src/qml/qml/qqmlprivate.h16
-rw-r--r--src/qml/qml/qqmltype.cpp73
-rw-r--r--src/qml/qml/qqmltype_p.h2
-rw-r--r--src/qml/qml/qqmltype_p_p.h2
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.h24
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp23
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"