aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml
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
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')
-rw-r--r--src/qml/qml/qqmlcompiler.cpp14
-rw-r--r--src/qml/qml/qqmldirparser.cpp43
-rw-r--r--src/qml/qml/qqmldirparser_p.h5
-rw-r--r--src/qml/qml/qqmlimport.cpp101
-rw-r--r--src/qml/qml/qqmlimport_p.h8
-rw-r--r--src/qml/qml/qqmlmetatype.cpp87
-rw-r--r--src/qml/qml/qqmlmetatype_p.h11
-rw-r--r--src/qml/qml/qqmlprivate.h11
-rw-r--r--src/qml/qml/qqmlscript.cpp54
-rw-r--r--src/qml/qml/qqmlscript_p.h13
-rw-r--r--src/qml/qml/qqmltypeloader.cpp212
-rw-r--r--src/qml/qml/qqmltypeloader_p.h6
-rw-r--r--src/qml/qml/qqmltypenamecache.cpp35
-rw-r--r--src/qml/qml/qqmltypenamecache_p.h23
14 files changed, 534 insertions, 89 deletions
diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp
index 8a0e015827..08ae37e747 100644
--- a/src/qml/qml/qqmlcompiler.cpp
+++ b/src/qml/qml/qqmlcompiler.cpp
@@ -821,6 +821,10 @@ bool QQmlCompiler::compile(QQmlEngine *engine,
QQmlScript::TypeReference *parserRef = referencedTypes.at(ii);
if (tref.typeData) { //QML-based type
+ if (tref.type->isCompositeSingleton()) {
+ QString err = tr( "Composite Singleton Type %1 is not creatable.").arg(tref.type->qmlTypeName());
+ COMPILE_EXCEPTION(parserRef->firstUse, err);
+ }
ref.component = tref.typeData->compiledData();
ref.component->addref();
} else if (tref.type) {//C++-based type
@@ -886,6 +890,12 @@ void QQmlCompiler::compileTree(QQmlScript::Object *tree)
output->importCache->add(ns);
}
+ // Add any Composite Singletons that were used to the import cache
+ for (int i = 0; i < unit->compositeSingletons().count(); ++i) {
+ output->importCache->add(unit->compositeSingletons().at(i).type->qmlTypeName(),
+ unit->compositeSingletons().at(i).type->sourceUrl(), unit->compositeSingletons().at(i).prefix);
+ }
+
int scriptIndex = 0;
foreach (const QQmlTypeData::ScriptReference &script, unit->resolvedScripts()) {
QString qualifier = script.qualifier;
@@ -2546,7 +2556,7 @@ bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop,
if (!type && typeName != QLatin1String("Qt"))
return true;
- if (type && type->isComposite()) //No enums on composite types
+ if (type && type->isComposite()) //No enums on composite (or composite singleton) types
return true;
int value = 0;
@@ -2984,6 +2994,8 @@ bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mod
if (!unit->imports().resolveType(s->parameterTypeNames.at(i).toString(), &qmltype, 0, 0, 0))
COMPILE_EXCEPTION(s, tr("Invalid signal parameter type: %1").arg(s->parameterTypeNames.at(i).toString()));
+ // We dont mind even if the composite type ends up being composite singleton, here
+ // we just acquire the metaTypeId.
if (qmltype->isComposite()) {
QQmlTypeData *tdata = enginePrivate->typeLoader.getType(qmltype->sourceUrl());
Q_ASSERT(tdata);
diff --git a/src/qml/qml/qqmldirparser.cpp b/src/qml/qml/qqmldirparser.cpp
index 8fcab2e570..b23b760b78 100644
--- a/src/qml/qml/qqmldirparser.cpp
+++ b/src/qml/qml/qqmldirparser.cpp
@@ -116,7 +116,7 @@ bool QQmlDirParser::parse(const QString &source)
if (ch->isNull())
break;
- QString sections[3];
+ QString sections[4];
int sectionCount = 0;
do {
@@ -126,7 +126,7 @@ bool QQmlDirParser::parse(const QString &source)
}
const QChar *start = ch;
scanWord(ch);
- if (sectionCount < 3) {
+ if (sectionCount < 4) {
sections[sectionCount++] = source.mid(start-source.constData(), ch-start);
} else {
reportError(lineNumber, start-lineStart, QLatin1String("unexpected token"));
@@ -167,7 +167,7 @@ bool QQmlDirParser::parse(const QString &source)
_typeNamespace = sections[1];
} else if (sections[0] == QLatin1String("plugin")) {
- if (sectionCount < 2) {
+ if (sectionCount < 2 || sectionCount > 3) {
reportError(lineNumber, 0,
QString::fromUtf8("plugin directive requires one or two arguments, but %1 were provided").arg(sectionCount - 1));
@@ -187,6 +187,43 @@ bool QQmlDirParser::parse(const QString &source)
Component entry(sections[1], sections[2], -1, -1);
entry.internal = true;
_components.insertMulti(entry.typeName, entry);
+ } else if (sections[0] == QLatin1String("singleton")) {
+ if (sectionCount < 3 || sectionCount > 4) {
+ reportError(lineNumber, 0,
+ QString::fromUtf8("singleton types require 2 or 3 arguments, but %1 were provided").arg(sectionCount - 1));
+ continue;
+ } else if (sectionCount == 3) {
+ // handle qmldir directory listing case where singleton is defined in the following pattern:
+ // singleton TestSingletonType TestSingletonType.qml
+ Component entry(sections[1], sections[2], -1, -1);
+ entry.singleton = true;
+ _components.insertMulti(entry.typeName, entry);
+ } else {
+ // handle qmldir module listing case where singleton is defined in the following pattern:
+ // singleton TestSingletonType 2.0 TestSingletonType20.qml
+ const QString &version = sections[2];
+ const int dotIndex = version.indexOf(QLatin1Char('.'));
+
+ if (dotIndex == -1) {
+ reportError(lineNumber, 0, QLatin1String("expected '.'"));
+ } else if (version.indexOf(QLatin1Char('.'), dotIndex + 1) != -1) {
+ reportError(lineNumber, 0, QLatin1String("unexpected '.'"));
+ } else {
+ bool validVersionNumber = false;
+ const int majorVersion = parseInt(QStringRef(&version, 0, dotIndex), &validVersionNumber);
+
+ if (validVersionNumber) {
+ const int minorVersion = parseInt(QStringRef(&version, dotIndex+1, version.length()-dotIndex-1), &validVersionNumber);
+
+ if (validVersionNumber) {
+ const QString &fileName = sections[3];
+ Component entry(sections[1], fileName, majorVersion, minorVersion);
+ entry.singleton = true;
+ _components.insertMulti(entry.typeName, entry);
+ }
+ }
+ }
+ }
} else if (sections[0] == QLatin1String("typeinfo")) {
if (sectionCount != 2) {
reportError(lineNumber, 0,
diff --git a/src/qml/qml/qqmldirparser_p.h b/src/qml/qml/qqmldirparser_p.h
index ddc5dbce16..e3607d1e72 100644
--- a/src/qml/qml/qqmldirparser_p.h
+++ b/src/qml/qml/qqmldirparser_p.h
@@ -93,17 +93,18 @@ public:
struct Component
{
Component()
- : majorVersion(0), minorVersion(0), internal(false) {}
+ : majorVersion(0), minorVersion(0), internal(false), singleton(false) {}
Component(const QString &typeName, const QString &fileName, int majorVersion, int minorVersion)
: typeName(typeName), fileName(fileName), majorVersion(majorVersion), minorVersion(minorVersion),
- internal(false) {}
+ internal(false), singleton(false) {}
QString typeName;
QString fileName;
int majorVersion;
int minorVersion;
bool internal;
+ bool singleton;
};
struct Script
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);
}
}
diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h
index 06b50c09e9..2c3d4a7bca 100644
--- a/src/qml/qml/qqmlimport_p.h
+++ b/src/qml/qml/qqmlimport_p.h
@@ -122,6 +122,14 @@ public:
QList<ScriptReference> resolvedScripts() const;
+ struct CompositeSingletonReference
+ {
+ QString typeName;
+ QString prefix;
+ };
+
+ QList<CompositeSingletonReference> resolvedCompositeSingletons() const;
+
static QString completeQmldirPath(const QString &uri, const QString &base, int vmaj, int vmin,
QQmlImports::ImportVersion version);
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
diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h
index f747049f11..8d6229d82c 100644
--- a/src/qml/qml/qqmlmetatype_p.h
+++ b/src/qml/qml/qqmlmetatype_p.h
@@ -86,7 +86,7 @@ public:
static QQmlType *qmlType(const QMetaObject *);
static QQmlType *qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor);
static QQmlType *qmlType(int);
- static QQmlType *qmlType(const QUrl &url);
+ static QQmlType *qmlType(const QUrl &url, bool includeNonFileImports = false);
static QQmlType *qmlTypeFromIndex(int);
static QMetaProperty defaultProperty(const QMetaObject *);
@@ -169,6 +169,8 @@ public:
bool isSingleton() const;
bool isInterface() const;
bool isComposite() const;
+ bool isCompositeSingleton() const;
+
int typeId() const;
int qListTypeId() const;
@@ -198,6 +200,7 @@ public:
QObject *(*qobjectCallback)(QQmlEngine *, QJSEngine *);
const QMetaObject *instanceMetaObject;
QString typeName;
+ QUrl url; // used by composite singletons
void setQObjectApi(QQmlEngine *, QObject *);
QObject *qobjectApi(QQmlEngine *) const;
@@ -211,6 +214,7 @@ public:
QHash<QQmlEngine *, QObject *> qobjectApis;
};
SingletonInstanceInfo *singletonInstanceInfo() const;
+
QUrl sourceUrl() const;
int enumValue(const QHashedStringRef &, bool *ok) const;
@@ -225,7 +229,8 @@ private:
CppType = 0,
SingletonType = 1,
InterfaceType = 2,
- CompositeType = 3
+ CompositeType = 3,
+ CompositeSingletonType = 4
};
friend QString registrationTypeString(RegistrationType);
friend bool checkRegistration(RegistrationType, QQmlMetaTypeData *, const char *, const QString &, int);
@@ -233,11 +238,13 @@ private:
friend int registerSingletonType(const QQmlPrivate::RegisterSingletonType &);
friend int registerInterface(const QQmlPrivate::RegisterInterface &);
friend int registerCompositeType(const QQmlPrivate::RegisterCompositeType &);
+ friend int registerCompositeSingletonType(const QQmlPrivate::RegisterCompositeSingletonType &);
friend Q_QML_EXPORT void qmlClearTypeRegistrations();
QQmlType(int, const QQmlPrivate::RegisterInterface &);
QQmlType(int, const QString &, const QQmlPrivate::RegisterSingletonType &);
QQmlType(int, const QString &, const QQmlPrivate::RegisterType &);
QQmlType(int, const QString &, const QQmlPrivate::RegisterCompositeType &);
+ QQmlType(int, const QString &, const QQmlPrivate::RegisterCompositeSingletonType &);
~QQmlType();
QQmlTypePrivate *d;
diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h
index b5b11d2c6a..15306cb131 100644
--- a/src/qml/qml/qqmlprivate.h
+++ b/src/qml/qml/qqmlprivate.h
@@ -260,12 +260,21 @@ namespace QQmlPrivate
const char *typeName;
};
+ struct RegisterCompositeSingletonType {
+ QUrl url;
+ const char *uri;
+ int versionMajor;
+ int versionMinor;
+ const char *typeName;
+ };
+
enum RegistrationType {
TypeRegistration = 0,
InterfaceRegistration = 1,
AutoParentRegistration = 2,
SingletonRegistration = 3,
- CompositeRegistration = 4
+ CompositeRegistration = 4,
+ CompositeSingletonRegistration = 5
};
int Q_QML_EXPORT qmlregister(RegistrationType, void *);
diff --git a/src/qml/qml/qqmlscript.cpp b/src/qml/qml/qqmlscript.cpp
index cac362a959..58aad8eb33 100644
--- a/src/qml/qml/qqmlscript.cpp
+++ b/src/qml/qml/qqmlscript.cpp
@@ -517,6 +517,7 @@ protected:
virtual bool visit(AST::UiProgram *node);
virtual bool visit(AST::UiImport *node);
+ virtual bool visit(AST::UiPragma *node);
virtual bool visit(AST::UiObjectDefinition *node);
virtual bool visit(AST::UiPublicMember *node);
virtual bool visit(AST::UiObjectBinding *node);
@@ -794,10 +795,10 @@ LocationSpan ProcessAST::location(AST::SourceLocation start, AST::SourceLocation
return rv;
}
-// UiProgram: UiImportListOpt UiObjectMemberList ;
+// UiProgram: UiHeaderItemListOpt UiObjectMemberList ;
bool ProcessAST::visit(AST::UiProgram *node)
{
- accept(node->imports);
+ accept(node->headers);
accept(node->members->member);
return false;
}
@@ -889,6 +890,41 @@ bool ProcessAST::visit(AST::UiImport *node)
return false;
}
+bool ProcessAST::visit(AST::UiPragma *node)
+{
+ QQmlScript::Pragma pragma;
+
+ // For now the only valid pragma is Singleton, so lets validate the input
+ if (!node->pragmaType->name.isNull())
+ {
+ if (QLatin1String("Singleton") == node->pragmaType->name.toString())
+ {
+ pragma.type = QQmlScript::Pragma::Singleton;
+ } else {
+ QQmlError error;
+ error.setDescription(QCoreApplication::translate("QQmlParser","Pragma requires a valid qualifier"));
+ error.setLine(node->pragmaToken.startLine);
+ error.setColumn(node->pragmaToken.startColumn);
+ _parser->_errors << error;
+ return false;
+ }
+ } else {
+ QQmlError error;
+ error.setDescription(QCoreApplication::translate("QQmlParser","Pragma requires a valid qualifier"));
+ error.setLine(node->pragmaToken.startLine);
+ error.setColumn(node->pragmaToken.startColumn);
+ _parser->_errors << error;
+ return false;
+ }
+
+ AST::SourceLocation startLoc = node->pragmaToken;
+ AST::SourceLocation endLoc = node->semicolonToken;
+ pragma.location = location(startLoc, endLoc);
+ _parser->_pragmas << pragma;
+
+ return false;
+}
+
bool ProcessAST::visit(AST::UiPublicMember *node)
{
static const struct TypeNameToType {
@@ -1364,6 +1400,11 @@ QList<QQmlScript::Import> QQmlScript::Parser::imports() const
return _imports;
}
+QList<QQmlScript::Pragma> QQmlScript::Parser::pragmas() const
+{
+ return _pragmas;
+}
+
QList<QQmlError> QQmlScript::Parser::errors() const
{
return _errors;
@@ -1416,7 +1457,7 @@ QQmlScript::Object::ScriptBlock::Pragmas QQmlScript::Parser::extractPragmas(QStr
token = l.lex();
- if (token != QQmlJSGrammar::T_IDENTIFIER ||
+ if (token != QQmlJSGrammar::T_PRAGMA ||
l.tokenStartLine() != startLine ||
script.mid(l.tokenOffset(), l.tokenLength()) != pragma)
return rv;
@@ -1506,7 +1547,6 @@ QQmlScript::Parser::JavaScriptMetaData QQmlScript::Parser::extractMetaData(QStri
QQmlScript::Object::ScriptBlock::Pragmas &pragmas = rv.pragmas;
- const QString pragma(QLatin1String("pragma"));
const QString js(QLatin1String(".js"));
const QString library(QLatin1String("library"));
@@ -1681,10 +1721,7 @@ QQmlScript::Parser::JavaScriptMetaData QQmlScript::Parser::extractMetaData(QStri
rv.imports << import;
}
-
- } else if (token == QQmlJSGrammar::T_IDENTIFIER &&
- script.mid(l.tokenOffset(), l.tokenLength()) == pragma) {
-
+ } else if (token == QQmlJSGrammar::T_PRAGMA) {
token = l.lex();
CHECK_TOKEN(T_IDENTIFIER);
@@ -1713,6 +1750,7 @@ QQmlScript::Parser::JavaScriptMetaData QQmlScript::Parser::extractMetaData(QStri
void QQmlScript::Parser::clear()
{
+ _pragmas.clear();
_imports.clear();
_refTypes.clear();
_errors.clear();
diff --git a/src/qml/qml/qqmlscript_p.h b/src/qml/qml/qqmlscript_p.h
index 250c71d6ac..790f1b2b81 100644
--- a/src/qml/qml/qqmlscript_p.h
+++ b/src/qml/qml/qqmlscript_p.h
@@ -120,6 +120,17 @@ public:
QQmlScript::LocationSpan location;
};
+class Pragma
+{
+public:
+ Pragma() : type(Singleton) {}
+
+ enum Type { Singleton };
+ Type type;
+
+ QQmlScript::LocationSpan location;
+};
+
class Object;
class TypeReference : public QQmlPool::Class
{
@@ -474,6 +485,7 @@ public:
QQmlScript::Object *tree() const;
QList<Import> imports() const;
+ QList<Pragma> pragmas() const;
void clear();
@@ -505,6 +517,7 @@ public:
QQmlPool _pool;
QQmlScript::Object *root;
QList<Import> _imports;
+ QList<Pragma> _pragmas;
QList<TypeReference*> _refTypes;
QString _scriptFile;
ParserJsASTData *data;
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 27230cd669..842eb53a3b 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -1172,7 +1172,7 @@ void QQmlDataLoader::shutdownThread()
}
QQmlTypeLoader::Blob::Blob(const QUrl &url, QQmlDataBlob::Type type, QQmlTypeLoader *loader)
-: QQmlDataBlob(url, type), m_typeLoader(loader), m_imports(loader)
+ : QQmlDataBlob(url, type), m_typeLoader(loader), m_imports(loader), m_isSingleton(false)
{
}
@@ -1336,6 +1336,51 @@ bool QQmlTypeLoader::Blob::addImport(const QQmlScript::Import &import, QList<QQm
return true;
}
+bool QQmlTypeLoader::Blob::addPragma(const QQmlScript::Pragma &pragma, QList<QQmlError> *errors)
+{
+ Q_ASSERT(errors);
+
+ if (pragma.type == QQmlScript::Pragma::Singleton) {
+ QUrl myUrl = url();
+
+ QQmlType *ret = QQmlMetaType::qmlType(myUrl, true);
+ if (!ret) {
+ QQmlError error;
+ error.setDescription(QQmlTypeLoader::tr("No matching type found, pragma Singleton files cannot be used by QQmlComponent."));
+ error.setUrl(myUrl);
+ error.setLine(pragma.location.start.line);
+ error.setColumn(pragma.location.start.column);
+ errors->prepend(error);
+ return false;
+ }
+
+ if (!ret->isCompositeSingleton()) {
+ QQmlError error;
+ error.setDescription(QQmlTypeLoader::tr("pragma Singleton used with a non composite singleton type %1").arg(ret->qmlTypeName()));
+ error.setUrl(myUrl);
+ error.setLine(pragma.location.start.line);
+ error.setColumn(pragma.location.start.column);
+ errors->prepend(error);
+ return false;
+ }
+ // This flag is used for error checking when a qmldir file marks a type as
+ // composite singleton, but there is no pragma Singleton defined in QML.
+ m_isSingleton = true;
+ } else {
+ QQmlError error;
+ error.setDescription(QLatin1String("Invalid pragma"));
+ error.setUrl(url());
+ error.setLine(pragma.location.start.line);
+ error.setColumn(pragma.location.start.column);
+ errors->prepend(error);
+ return false;
+ }
+
+ return true;
+}
+
+
+
void QQmlTypeLoader::Blob::dependencyError(QQmlDataBlob *blob)
{
if (blob->type() == QQmlDataBlob::QmldirFile) {
@@ -1941,6 +1986,11 @@ const QSet<QString> &QQmlTypeData::namespaces() const
return m_namespaces;
}
+const QList<QQmlTypeData::TypeReference> &QQmlTypeData::compositeSingletons() const
+{
+ return m_compositeSingletons;
+}
+
QQmlCompiledData *QQmlTypeData::compiledData() const
{
return m_compiledData;
@@ -2015,6 +2065,36 @@ void QQmlTypeData::done()
}
// ---
+ // Check all composite singleton type dependencies for errors
+ for (int ii = 0; !isError() && ii < m_compositeSingletons.count(); ++ii) {
+ const TypeReference &type = m_compositeSingletons.at(ii);
+ Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
+ if (type.typeData && type.typeData->isError()) {
+ QString typeName = type.type->qmlTypeName();
+
+ QList<QQmlError> errors = type.typeData->errors();
+ QQmlError error;
+ error.setUrl(finalUrl());
+ error.setLine(type.location.line);
+ error.setColumn(type.location.column);
+ error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
+ errors.prepend(error);
+ setError(errors);
+ }
+ }
+
+ // If the type is CompositeSingleton but there was no pragma Singleton in the
+ // QML file, lets report an error.
+ QQmlType *type = QQmlMetaType::qmlType(url(), true);
+ if (type && type->isCompositeSingleton() && !m_isSingleton) {
+ QString typeName = type->qmlTypeName();
+
+ QQmlError error;
+ error.setDescription(QQmlTypeLoader::tr("qmldir defines type as singleton, but no pragma Singleton found in type %1.").arg(typeName));
+ error.setUrl(finalUrl());
+ setError(error);
+ }
+
// Compile component
if (!isError())
compile();
@@ -2140,6 +2220,14 @@ void QQmlTypeData::dataReceived(const Data &data)
return;
}
}
+
+ foreach (const QQmlScript::Pragma &pragma, scriptParser.pragmas()) {
+ if (!addPragma(pragma, &errors)) {
+ Q_ASSERT(errors.size());
+ setError(errors);
+ return;
+ }
+ }
}
void QQmlTypeData::allDependenciesDone()
@@ -2327,61 +2415,51 @@ void QQmlTypeData::resolveTypes()
m_scripts << ref;
}
- // --- old compiler:
- foreach (QQmlScript::TypeReference *parserRef, scriptParser.referencedTypes()) {
+ // Lets handle resolved composite singleton types
+ foreach (const QQmlImports::CompositeSingletonReference &csRef, m_imports.resolvedCompositeSingletons()) {
TypeReference ref;
+ QQmlScript::TypeReference parserRef;
+ parserRef.name = csRef.typeName;
+ // we are basing our type on the information from qmldir and therefore
+ // do not have a proper location.
+ parserRef.firstUse = NULL;
+
+ if (!csRef.prefix.isEmpty()) {
+ parserRef.name.prepend(csRef.prefix + QLatin1Char('.'));
+ // Add a reference to the enclosing namespace
+ m_namespaces.insert(csRef.prefix);
+ }
int majorVersion = -1;
int minorVersion = -1;
- QQmlImportNamespace *typeNamespace = 0;
- QList<QQmlError> errors;
- bool typeFound = m_imports.resolveType(parserRef->name, &ref.type,
- &majorVersion, &minorVersion, &typeNamespace, &errors);
- if (!typeNamespace && !typeFound && !m_implicitImportLoaded) {
- // Lazy loading of implicit import
- if (loadImplicitImport()) {
- // Try again to find the type
- errors.clear();
- typeFound = m_imports.resolveType(parserRef->name, &ref.type,
- &majorVersion, &minorVersion, &typeNamespace, &errors);
- } else {
- return; //loadImplicitImport() hit an error, and called setError already
- }
+ if (!resolveType(&parserRef, majorVersion, minorVersion, ref))
+ return;
+
+ if (ref.type->isCompositeSingleton()) {
+ ref.typeData = typeLoader()->getType(ref.type->sourceUrl());
+ addDependency(ref.typeData);
+ ref.prefix = csRef.prefix;
+
+ m_compositeSingletons << ref;
}
+ }
- if (!typeFound || typeNamespace) {
- // Known to not be a type:
- // - known to be a namespace (Namespace {})
- // - type with unknown namespace (UnknownNamespace.SomeType {})
- QQmlError error;
- if (typeNamespace) {
- error.setDescription(QQmlTypeLoader::tr("Namespace %1 cannot be used as a type").arg(parserRef->name));
- } else {
- if (errors.size()) {
- error = errors.takeFirst();
- } else {
- // this should not be possible!
- // Description should come from error provided by addImport() function.
- error.setDescription(QQmlTypeLoader::tr("Unreported error adding script import to import database"));
- }
- error.setUrl(m_imports.baseUrl());
- error.setDescription(QQmlTypeLoader::tr("%1 %2").arg(parserRef->name).arg(error.description()));
- }
+ // --- old compiler:
+ foreach (QQmlScript::TypeReference *parserRef, scriptParser.referencedTypes()) {
+ TypeReference ref;
- Q_ASSERT(parserRef->firstUse);
- error.setLine(parserRef->firstUse->location.start.line);
- error.setColumn(parserRef->firstUse->location.start.column);
+ int majorVersion = -1;
+ int minorVersion = -1;
- errors.prepend(error);
- setError(errors);
+ if (!resolveType(parserRef, majorVersion, minorVersion, ref))
return;
- }
if (ref.type->isComposite()) {
ref.typeData = typeLoader()->getType(ref.type->sourceUrl());
addDependency(ref.typeData);
}
+
ref.majorVersion = majorVersion;
ref.minorVersion = minorVersion;
@@ -2466,6 +2544,58 @@ void QQmlTypeData::resolveTypes()
}
}
+bool QQmlTypeData::resolveType(const QQmlScript::TypeReference *parserRef, int &majorVersion, int &minorVersion, TypeReference &ref)
+{
+ QQmlImportNamespace *typeNamespace = 0;
+ QList<QQmlError> errors;
+
+ bool typeFound = m_imports.resolveType(parserRef->name, &ref.type,
+ &majorVersion, &minorVersion, &typeNamespace, &errors);
+ if (!typeNamespace && !typeFound && !m_implicitImportLoaded) {
+ // Lazy loading of implicit import
+ if (loadImplicitImport()) {
+ // Try again to find the type
+ errors.clear();
+ typeFound = m_imports.resolveType(parserRef->name, &ref.type,
+ &majorVersion, &minorVersion, &typeNamespace, &errors);
+ } else {
+ return false; //loadImplicitImport() hit an error, and called setError already
+ }
+ }
+
+ if (!typeFound || typeNamespace) {
+ // Known to not be a type:
+ // - known to be a namespace (Namespace {})
+ // - type with unknown namespace (UnknownNamespace.SomeType {})
+ QQmlError error;
+ if (typeNamespace) {
+ error.setDescription(QQmlTypeLoader::tr("Namespace %1 cannot be used as a type").arg(parserRef->name));
+ } else {
+ if (errors.size()) {
+ error = errors.takeFirst();
+ } else {
+ // this should not be possible!
+ // Description should come from error provided by addImport() function.
+ error.setDescription(QQmlTypeLoader::tr("Unreported error adding script import to import database"));
+ }
+ error.setUrl(m_imports.baseUrl());
+ error.setDescription(QQmlTypeLoader::tr("%1 %2").arg(parserRef->name).arg(error.description()));
+ }
+
+ if (parserRef->firstUse)
+ {
+ error.setLine(parserRef->firstUse->location.start.line);
+ error.setColumn(parserRef->firstUse->location.start.column);
+ }
+
+ errors.prepend(error);
+ setError(errors);
+ return false;
+ }
+
+ return true;
+}
+
void QQmlTypeData::scriptImported(QQmlScriptBlob *blob, const QQmlScript::Location &location, const QString &qualifier, const QString &/*nameSpace*/)
{
ScriptReference ref;
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index fee09d3bdb..a2d07bbe2f 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -279,6 +279,7 @@ public:
protected:
bool addImport(const QQmlScript::Import &import, QList<QQmlError> *errors);
+ bool addPragma(const QQmlScript::Pragma &pragma, QList<QQmlError> *errors);
bool fetchQmldir(const QUrl &url, const QQmlScript::Import *import, int priority, QList<QQmlError> *errors);
bool updateQmldir(QQmlQmldirData *data, const QQmlScript::Import *import, QList<QQmlError> *errors);
@@ -294,6 +295,7 @@ public:
protected:
QQmlTypeLoader *m_typeLoader;
QQmlImports m_imports;
+ bool m_isSingleton;
QHash<const QQmlScript::Import *, int> m_unresolvedImports;
QList<QQmlQmldirData *> m_qmldirs;
};
@@ -401,6 +403,7 @@ public:
int majorVersion;
int minorVersion;
QQmlTypeData *typeData;
+ QString prefix; // used by CompositeSingleton types
};
struct ScriptReference
@@ -425,6 +428,7 @@ public:
const QList<TypeReference> &resolvedTypes() const;
const QList<ScriptReference> &resolvedScripts() const;
const QSet<QString> &namespaces() const;
+ const QList<TypeReference> &compositeSingletons() const;
QQmlCompiledData *compiledData() const;
@@ -447,6 +451,7 @@ protected:
private:
void resolveTypes();
void compile();
+ bool resolveType(const QQmlScript::TypeReference *parserRef, int &majorVersion, int &minorVersion, TypeReference &ref);
virtual void scriptImported(QQmlScriptBlob *blob, const QQmlScript::Location &location, const QString &qualifier, const QString &nameSpace);
@@ -459,6 +464,7 @@ private:
QList<ScriptReference> m_scripts;
QSet<QString> m_namespaces;
+ QList<TypeReference> m_compositeSingletons;
// --- old compiler
QList<TypeReference> m_types;
diff --git a/src/qml/qml/qqmltypenamecache.cpp b/src/qml/qml/qqmltypenamecache.cpp
index 38466aa20d..87764c49ae 100644
--- a/src/qml/qml/qqmltypenamecache.cpp
+++ b/src/qml/qml/qqmltypenamecache.cpp
@@ -53,6 +53,21 @@ QQmlTypeNameCache::~QQmlTypeNameCache()
{
}
+void QQmlTypeNameCache::add(const QHashedString &name, const QUrl &url, const QHashedString &nameSpace)
+{
+ if (nameSpace.length() != 0) {
+ Import *i = m_namedImports.value(nameSpace);
+ Q_ASSERT(i != 0);
+ i->compositeSingletons.insert(name, url);
+ return;
+ }
+
+ if (m_anonymousCompositeSingletons.contains(name))
+ return;
+
+ m_anonymousCompositeSingletons.insert(name, url);
+}
+
void QQmlTypeNameCache::add(const QHashedString &name, int importedScriptIndex, const QHashedString &nameSpace)
{
Import import;
@@ -78,6 +93,9 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name)
if (!result.isValid())
result = typeSearch(m_anonymousImports, name);
+ if (!result.isValid())
+ result = query(m_anonymousCompositeSingletons, name);
+
return result;
}
@@ -88,7 +106,12 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name,
const Import *i = static_cast<const Import *>(importNamespace);
Q_ASSERT(i->scriptIndex == -1);
- return typeSearch(i->modules, name);
+ Result result = result = typeSearch(i->modules, name);
+
+ if (!result.isValid())
+ result = query(i->compositeSingletons, name);
+
+ return result;
}
QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name)
@@ -98,6 +121,9 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name)
if (!result.isValid())
result = typeSearch(m_anonymousImports, name);
+ if (!result.isValid())
+ result = query(m_anonymousCompositeSingletons, name);
+
return result;
}
@@ -114,7 +140,12 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name, cons
return r;
}
- return typeSearch(i->modules, name);
+ Result r = typeSearch(i->modules, name);
+
+ if (!r.isValid())
+ r = query(i->compositeSingletons, name);
+
+ return r;
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypenamecache_p.h b/src/qml/qml/qqmltypenamecache_p.h
index 094bd5c777..6be9aadf29 100644
--- a/src/qml/qml/qqmltypenamecache_p.h
+++ b/src/qml/qml/qqmltypenamecache_p.h
@@ -74,6 +74,7 @@ public:
inline bool isEmpty() const;
void add(const QHashedString &name, int sciptIndex = -1, const QHashedString &nameSpace = QHashedString());
+ void add(const QHashedString &name, const QUrl &url, const QHashedString &nameSpace = QHashedString());
struct Result {
inline Result();
@@ -103,6 +104,9 @@ private:
// Or, imported script
int scriptIndex;
+
+ // Or, imported compositeSingletons
+ QStringHash<QUrl> compositeSingletons;
};
template<typename Key>
@@ -121,6 +125,19 @@ private:
}
template<typename Key>
+ Result query(const QStringHash<QUrl> &urls, Key key)
+ {
+ QUrl *url = urls.value(key);
+ if (url) {
+ QQmlType *type = QQmlMetaType::qmlType(*url);
+ if (type)
+ return Result(type);
+ }
+
+ return Result();
+ }
+
+ template<typename Key>
Result typeSearch(const QVector<QQmlTypeModuleVersion> &modules, Key key)
{
QVector<QQmlTypeModuleVersion>::const_iterator end = modules.constEnd();
@@ -135,8 +152,7 @@ private:
QStringHash<Import> m_namedImports;
QMap<const Import *, QStringHash<Import> > m_namespacedImports;
QVector<QQmlTypeModuleVersion> m_anonymousImports;
-
- QQmlEngine *engine;
+ QStringHash<QUrl> m_anonymousCompositeSingletons;
};
QQmlTypeNameCache::Result::Result()
@@ -176,7 +192,8 @@ QQmlTypeNameCache::Import::Import()
bool QQmlTypeNameCache::isEmpty() const
{
- return m_namedImports.isEmpty() && m_anonymousImports.isEmpty();
+ return m_namedImports.isEmpty() && m_anonymousImports.isEmpty()
+ && m_anonymousCompositeSingletons.isEmpty();
}
QT_END_NAMESPACE