aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqmlimport.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/qqmlimport.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/qqmlimport.cpp')
-rw-r--r--src/qml/qml/qqmlimport.cpp101
1 files changed, 85 insertions, 16 deletions
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index e970ffec59..3caaa02e3b 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -129,25 +129,36 @@ bool isPathAbsolute(const QString &path)
}
// If the type does not already exist as a file import, add the type and return the new type
-QQmlType *getTypeForUrl(const QString &urlString, const QHashedStringRef& typeName, QList<QQmlError> *errors)
+QQmlType *getTypeForUrl(const QString &urlString, const QHashedStringRef& typeName, bool isCompositeSingleton, QList<QQmlError> *errors)
{
QUrl url(urlString);
QQmlType *ret = QQmlMetaType::qmlType(url);
- if (!ret) { //QQmlType not yet existing for composite type
+ if (!ret) { //QQmlType not yet existing for composite or composite singleton type
int dot = typeName.indexOf(QLatin1Char('.'));
QHashedStringRef unqualifiedtype = dot < 0 ? typeName : QHashedStringRef(typeName.constData() + dot + 1, typeName.length() - dot - 1);
//XXX: The constData of the string ref is pointing somewhere unsafe in qmlregister, so we need to create a temporary copy
QByteArray buf(unqualifiedtype.toString().toUtf8());
- QQmlPrivate::RegisterCompositeType reg = {
- url,
- "", //Empty URI indicates loaded via file imports
- -1,
- -1,
- buf.constData()
- };
- ret = QQmlMetaType::qmlTypeFromIndex(QQmlPrivate::qmlregister(QQmlPrivate::CompositeRegistration, &reg));
+ if (isCompositeSingleton) {
+ QQmlPrivate::RegisterCompositeSingletonType reg = {
+ url,
+ "", //Empty URI indicates loaded via file imports
+ -1,
+ -1,
+ buf.constData()
+ };
+ ret = QQmlMetaType::qmlTypeFromIndex(QQmlPrivate::qmlregister(QQmlPrivate::CompositeSingletonRegistration, &reg));
+ } else {
+ QQmlPrivate::RegisterCompositeType reg = {
+ url,
+ "", //Empty URI indicates loaded via file imports
+ -1,
+ -1,
+ buf.constData()
+ };
+ ret = QQmlMetaType::qmlTypeFromIndex(QQmlPrivate::qmlregister(QQmlPrivate::CompositeRegistration, &reg));
+ }
}
if (!ret) {//Usually when a type name is "found" but invalid
//qDebug() << ret << urlString << QQmlMetaType::qmlType(url);
@@ -158,10 +169,9 @@ QQmlType *getTypeForUrl(const QString &urlString, const QHashedStringRef& typeNa
errors->prepend(error);
}
return ret;
-
}
-}
+} // namespace
struct RegisteredPlugin {
QString uri;
@@ -362,6 +372,61 @@ void QQmlImports::populateCache(QQmlTypeNameCache *cache) const
}
}
+// We need to exclude the entry for the current baseUrl. This can happen for example
+// when handling qmldir files on the remote dir case and the current type is marked as
+// singleton.
+bool excludeBaseUrl(const QString &importUrl, const QString &fileName, const QString baseUrl)
+{
+ if (importUrl.isEmpty())
+ return false;
+
+ if (baseUrl.startsWith(importUrl))
+ {
+ QString typeUrl(importUrl);
+ typeUrl.append(fileName);
+ if (typeUrl == baseUrl)
+ return false;
+ }
+
+ return true;
+}
+
+void findCompositeSingletons(const QQmlImportNamespace &set, QList<QQmlImports::CompositeSingletonReference> &resultList, QUrl baseUrl)
+{
+ typedef QQmlDirComponents::const_iterator ConstIterator;
+
+ for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
+ const QQmlImportNamespace::Import *import = set.imports.at(ii);
+
+ const QQmlDirComponents &components = import->qmlDirComponents;
+
+ ConstIterator cend = components.constEnd();
+ for (ConstIterator cit = components.constBegin(); cit != cend; ++cit) {
+ if (cit->singleton && excludeBaseUrl(import->url, cit->fileName, baseUrl.toString())) {
+ QQmlImports::CompositeSingletonReference ref;
+ ref.typeName = cit->typeName;
+ ref.prefix = set.prefix;
+ resultList.append(ref);
+ }
+ }
+ }
+}
+
+QList<QQmlImports::CompositeSingletonReference> QQmlImports::resolvedCompositeSingletons() const
+{
+ QList<QQmlImports::CompositeSingletonReference> compositeSingletons;
+
+ const QQmlImportNamespace &set = d->unqualifiedset;
+ findCompositeSingletons(set, compositeSingletons, baseUrl());
+
+ for (QQmlImportNamespace *ns = d->qualifiedSets.first(); ns; ns = d->qualifiedSets.next(ns)) {
+ const QQmlImportNamespace &set = *ns;
+ findCompositeSingletons(set, compositeSingletons, baseUrl());
+ }
+
+ return compositeSingletons;
+}
+
QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const
{
QList<QQmlImports::ScriptReference> scripts;
@@ -452,7 +517,9 @@ bool QQmlImports::resolveType(const QHashedStringRef &type,
#define RESOLVE_TYPE_DEBUG qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) \
<< ')' << "::resolveType: " << type.toString() << " => "
- if (type_return && *type_return && (*type_return)->isComposite())
+ if (type_return && *type_return && (*type_return)->isCompositeSingleton())
+ RESOLVE_TYPE_DEBUG << (*type_return)->typeName() << ' ' << (*type_return)->sourceUrl() << " TYPE/URL-SINGLETON";
+ else if (type_return && *type_return && (*type_return)->isComposite())
RESOLVE_TYPE_DEBUG << (*type_return)->typeName() << ' ' << (*type_return)->sourceUrl() << " TYPE/URL";
else if (type_return && *type_return)
RESOLVE_TYPE_DEBUG << (*type_return)->typeName() << " TYPE";
@@ -544,6 +611,7 @@ bool QQmlImportNamespace::Import::resolveType(QQmlTypeLoader *typeLoader,
QQmlDirComponents::ConstIterator it = qmlDirComponents.find(type), end = qmlDirComponents.end();
if (it != end) {
QString componentUrl;
+ bool isCompositeSingleton = false;
QQmlDirComponents::ConstIterator candidate = end;
for ( ; it != end && it.key() == type; ++it) {
const QQmlDirParser::Component &c = *it;
@@ -568,13 +636,14 @@ bool QQmlImportNamespace::Import::resolveType(QQmlTypeLoader *typeLoader,
// This is our best candidate so far
candidate = it;
+ isCompositeSingleton = c.singleton;
}
}
}
if (candidate != end) {
if (type_return)
- *type_return = getTypeForUrl(componentUrl, type, 0);
+ *type_return = getTypeForUrl(componentUrl, type, isCompositeSingleton, 0);
return (*type_return != 0);
}
} else if (!isLibrary) {
@@ -594,7 +663,7 @@ bool QQmlImportNamespace::Import::resolveType(QQmlTypeLoader *typeLoader,
*typeRecursionDetected = true;
} else {
if (type_return)
- *type_return = getTypeForUrl(qmlUrl, type, 0);
+ *type_return = getTypeForUrl(qmlUrl, type, false, 0);
return (*type_return) != 0;
}
}
@@ -637,7 +706,7 @@ bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor,
return true;
if (s->imports.count() == 1 && !s->imports.at(0)->isLibrary && type_return && s != &unqualifiedset) {
// qualified, and only 1 url
- *type_return = getTypeForUrl(resolveLocalUrl(s->imports.at(0)->url, unqualifiedtype.toString() + QLatin1String(".qml")), type, errors);
+ *type_return = getTypeForUrl(resolveLocalUrl(s->imports.at(0)->url, unqualifiedtype.toString() + QLatin1String(".qml")), type, false, errors);
return (*type_return != 0);
}
}