aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqmlmetatype.cpp
diff options
context:
space:
mode:
authorAntti Piira <apiira@blackberry.com>2013-08-22 12:08:37 -0700
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-21 01:20:55 +0200
commit200a869441562d62e7fc0867599097e0599f0411 (patch)
tree982dc3c5a9c22bdea24a21054dd2b434fcea1147 /src/qml/qml/qqmlmetatype.cpp
parentb365471f0abc79f08bf0d852aea3be0a601c6901 (diff)
Add Singleton support for QML
This introduces Singleton support for QML (Composite Singleton). For now, the Singleton support is only availabe for QML types in modules or (remote and local) directories with qmldir file. However, in the future this support may be expanded to arbitrary QML file imports without by leaving out the qmldir requirement. You define a QML type as a Singleton with the following two steps: 1. By adding a pragma Singleton to a type's QML file: pragma Singleton The pragma and import statements can be mixed and their order does not matter. Singleton is the only supported pragma for now. Others will generate errors. 2. By specifying a qmldir file for the directory of your imported type and prepending the type with "singleton" keyword as follows: singleton TestTypeSingleton TestTypeSingleton.qml Alternatively you may specify a qmldir file for a module and specify your type as a singleton as follows: singleton TestTypeSingleton 1.0 TestTypeSingleton.qml Composite Singletons may be included in a module and may be used with a local namespace qualifier when imported with: "import xxx as NameSpace" A singleton instance is created at first use and stored into the QmlEngine (one instance per engine) and eventually released by the engine's destructor. CompositeSingletonType has a dual nature and will return true to both isComposite() and isSingleton() calls. In most cases its enough to check for just isComposite() or isSingleton(). However, there is a isCompositeSingleton() available as well. I used "qlalr --no-debug --no-lines --qt qqmljs.g" to generate the qqmljsparser and qqmljsgrammar files from qqmljs.g. Unit tests are included. Change-Id: I91b303612c5e132143b325b9a8f982e9355bc90e Reviewed-by: Alan Alpert (Personal) <416365416c@gmail.com>
Diffstat (limited to 'src/qml/qml/qqmlmetatype.cpp')
-rw-r--r--src/qml/qml/qqmlmetatype.cpp87
1 files changed, 77 insertions, 10 deletions
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index f9583e7a59..342d1dc69c 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -63,6 +63,7 @@
#include <qvector.h>
#include <ctype.h>
+#include "qqmlcomponent.h"
QT_BEGIN_NAMESPACE
@@ -77,6 +78,10 @@ struct QQmlMetaTypeData
Names nameToType;
typedef QHash<QUrl, QQmlType *> Files; //For file imported composite types only
Files urlToType;
+ Files urlToNonFileImportType; // For non-file imported composite and composite
+ // singleton types. This way we can locate any
+ // of them by url, even if it was registered as
+ // a module via qmlRegisterCompositeType.
typedef QHash<const QMetaObject *, QQmlType *> MetaObjects;
MetaObjects metaObjectToType;
typedef QHash<int, QQmlMetaType::StringConverter> StringConverters;
@@ -225,6 +230,10 @@ void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e)
setScriptApi(e, scriptCallback(e, e));
} else if (qobjectCallback && !qobjectApi(e)) {
setQObjectApi(e, qobjectCallback(e, e));
+ } else if (!url.isEmpty() && !qobjectApi(e)) {
+ QQmlComponent component(e, url, QQmlComponent::PreferSynchronous);
+ QObject *o = component.create();
+ setQObjectApi(e, o);
}
v4->popContext();
}
@@ -279,6 +288,7 @@ QQmlTypePrivate::QQmlTypePrivate(QQmlType::RegistrationType type)
extraData.cd->propertyValueInterceptorCast = -1;
break;
case QQmlType::SingletonType:
+ case QQmlType::CompositeSingletonType:
extraData.sd = new QQmlSingletonTypeData;
extraData.sd->singletonInstanceInfo = 0;
break;
@@ -300,6 +310,7 @@ QQmlTypePrivate::~QQmlTypePrivate()
delete extraData.cd;
break;
case QQmlType::SingletonType:
+ case QQmlType::CompositeSingletonType:
delete extraData.sd->singletonInstanceInfo;
delete extraData.sd;
break;
@@ -351,6 +362,22 @@ QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::Reg
= (type.qobjectApi && type.version >= 1) ? type.instanceMetaObject : 0;
}
+QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::RegisterCompositeSingletonType &type)
+ : d(new QQmlTypePrivate(CompositeSingletonType))
+{
+ d->elementName = elementName;
+ d->module = QString::fromUtf8(type.uri);
+
+ d->version_maj = type.versionMajor;
+ d->version_min = type.versionMinor;
+
+ d->index = index;
+
+ d->extraData.sd->singletonInstanceInfo = new SingletonInstanceInfo;
+ d->extraData.sd->singletonInstanceInfo->url = type.url;
+ d->extraData.sd->singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName);
+}
+
QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::RegisterType &type)
: d(new QQmlTypePrivate(CppType))
{
@@ -650,7 +677,7 @@ void QQmlTypePrivate::insertEnums(const QMetaObject *metaObject) const
QByteArray QQmlType::typeName() const
{
- if (d->regType == SingletonType)
+ if (d->regType == SingletonType || d->regType == CompositeSingletonType)
return d->extraData.sd->singletonInstanceInfo->typeName.toUtf8();
else if (d->baseMetaObject)
return d->baseMetaObject->className();
@@ -710,7 +737,7 @@ void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) con
QQmlType::SingletonInstanceInfo *QQmlType::singletonInstanceInfo() const
{
- if (d->regType != SingletonType)
+ if (d->regType != SingletonType && d->regType != CompositeSingletonType)
return 0;
return d->extraData.sd->singletonInstanceInfo;
}
@@ -757,7 +784,7 @@ bool QQmlType::isExtendedType() const
bool QQmlType::isSingleton() const
{
- return d->regType == SingletonType;
+ return d->regType == SingletonType || d->regType == CompositeSingletonType;
}
bool QQmlType::isInterface() const
@@ -767,7 +794,12 @@ bool QQmlType::isInterface() const
bool QQmlType::isComposite() const
{
- return d->regType == CompositeType;
+ return d->regType == CompositeType || d->regType == CompositeSingletonType;
+}
+
+bool QQmlType::isCompositeSingleton() const
+{
+ return d->regType == CompositeSingletonType;
}
int QQmlType::typeId() const
@@ -869,9 +901,12 @@ int QQmlType::index() const
QUrl QQmlType::sourceUrl() const
{
- if (d->regType != CompositeType)
+ if (d->regType == CompositeType)
+ return d->extraData.fd->url;
+ else if (d->regType == CompositeSingletonType)
+ return d->extraData.sd->singletonInstanceInfo->url;
+ else
return QUrl();
- return d->extraData.fd->url;
}
int QQmlType::enumValue(const QHashedStringRef &name, bool *ok) const
@@ -1006,7 +1041,6 @@ QList<QQmlType*> QQmlTypeModule::singletonTypes(int minor) const
return retn;
}
-
QQmlTypeModuleVersion::QQmlTypeModuleVersion()
: m_module(0), m_minor(0)
{
@@ -1070,6 +1104,7 @@ void qmlClearTypeRegistrations() // Declared in qqml.h
data->idToType.clear();
data->nameToType.clear();
data->urlToType.clear();
+ data->urlToNonFileImportType.clear();
data->metaObjectToType.clear();
data->uriToModule.clear();
@@ -1123,6 +1158,8 @@ QString registrationTypeString(QQmlType::RegistrationType typeType)
typeStr = QStringLiteral("element");
else if (typeType == QQmlType::SingletonType)
typeStr = QStringLiteral("singleton type");
+ else if (typeType == QQmlType::CompositeSingletonType)
+ typeStr = QStringLiteral("composite singleton type");
else
typeStr = QStringLiteral("type");
return typeStr;
@@ -1254,6 +1291,31 @@ int registerSingletonType(const QQmlPrivate::RegisterSingletonType &type)
return index;
}
+int registerCompositeSingletonType(const QQmlPrivate::RegisterCompositeSingletonType &type)
+{
+ // Assumes URL is absolute and valid. Checking of user input should happen before the URL enters type.
+ QWriteLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+ QString typeName = QString::fromUtf8(type.typeName);
+ bool fileImport = false;
+ if (*(type.uri) == '\0')
+ fileImport = true;
+ if (!checkRegistration(QQmlType::CompositeSingletonType, data, fileImport ? 0 : type.uri, typeName))
+ return -1;
+
+ int index = data->types.count();
+
+ QQmlType *dtype = new QQmlType(index, typeName, type);
+
+ data->types.append(dtype);
+ addTypeToData(dtype, data);
+
+ QQmlMetaTypeData::Files *files = fileImport ? &(data->urlToType) : &(data->urlToNonFileImportType);
+ files->insertMulti(type.url, dtype);
+
+ return index;
+}
+
int registerCompositeType(const QQmlPrivate::RegisterCompositeType &type)
{
// Assumes URL is absolute and valid. Checking of user input should happen before the URL enters type.
@@ -1272,8 +1334,8 @@ int registerCompositeType(const QQmlPrivate::RegisterCompositeType &type)
data->types.append(dtype);
addTypeToData(dtype, data);
- if (fileImport)
- data->urlToType.insertMulti(type.url, dtype);
+ QQmlMetaTypeData::Files *files = fileImport ? &(data->urlToType) : &(data->urlToNonFileImportType);
+ files->insertMulti(type.url, dtype);
return index;
}
@@ -1295,6 +1357,8 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data)
return registerSingletonType(*reinterpret_cast<RegisterSingletonType *>(data));
} else if (type == CompositeRegistration) {
return registerCompositeType(*reinterpret_cast<RegisterCompositeType *>(data));
+ } else if (type == CompositeSingletonRegistration) {
+ return registerCompositeSingletonType(*reinterpret_cast<RegisterCompositeSingletonType *>(data));
}
return -1;
}
@@ -1708,12 +1772,15 @@ QQmlType *QQmlMetaType::qmlType(int userType)
Returns null if no such type is registered.
*/
-QQmlType *QQmlMetaType::qmlType(const QUrl &url)
+QQmlType *QQmlMetaType::qmlType(const QUrl &url, bool includeNonFileImports /* = false */)
{
QReadLocker lock(metaTypeDataLock());
QQmlMetaTypeData *data = metaTypeData();
QQmlType *type = data->urlToType.value(url);
+ if (!type && includeNonFileImports)
+ type = data->urlToNonFileImportType.value(url);
+
if (type && type->sourceUrl() == url)
return type;
else