aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
authorAlan Alpert <416365416c@gmail.com>2012-12-16 21:24:14 -0800
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-02-18 12:54:15 +0100
commit4d3a64c5e65a781acb4acf4ba641456da28bd1e4 (patch)
tree10d1374401131a7d22146cdf7029307aea9efe7b /src/qml
parent58471eb3f267dbee728b1c13f87458f2ee509bfa (diff)
Add Composite Types to QQmlType
When a composite type is loaded from a QML file, it now generates a QQmlType entry in QQmlMetaTypeData. Change-Id: I9b127dff7955456aacb25138fa6ea8efb7bb9221 Reviewed-by: Christopher Adams <chris.adams@jollamobile.com> Reviewed-by: Alan Alpert <aalpert@rim.com>
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/doc/src/documents/definetypes.qdoc2
-rw-r--r--src/qml/qml/qqmlcompileddata.cpp2
-rw-r--r--src/qml/qml/qqmlcompiler.cpp47
-rw-r--r--src/qml/qml/qqmlengine.cpp4
-rw-r--r--src/qml/qml/qqmlengine_p.h4
-rw-r--r--src/qml/qml/qqmlimport.cpp107
-rw-r--r--src/qml/qml/qqmlimport_p.h5
-rw-r--r--src/qml/qml/qqmlmetatype.cpp190
-rw-r--r--src/qml/qml/qqmlmetatype_p.h14
-rw-r--r--src/qml/qml/qqmlprivate.h14
-rw-r--r--src/qml/qml/qqmltypeloader.cpp15
11 files changed, 265 insertions, 139 deletions
diff --git a/src/qml/doc/src/documents/definetypes.qdoc b/src/qml/doc/src/documents/definetypes.qdoc
index 97a841ccb8..b9df6a4381 100644
--- a/src/qml/doc/src/documents/definetypes.qdoc
+++ b/src/qml/doc/src/documents/definetypes.qdoc
@@ -34,7 +34,7 @@ One of the core features of QML is that it enables QML object types to be easily
\section1 Defining an Object Type with a QML File
-To create an object type, a QML document should be placed into a text file named as \e <TypeName>.qml where \e <TypeName> is the desired name of the type, beginning with an uppercase letter. This document is then automatically recognized by the engine as a definition of a QML type. Additionally, a type defined in this manner is automatically made available to other QML files within the same directory as the engine searches within the immediate directory when resolving QML type names.
+To create an object type, a QML document should be placed into a text file named as \e <TypeName>.qml where \e <TypeName> is the desired name of the type, which must be comprised of alphanumeric characters or underscores and beginning with an uppercase letter. This document is then automatically recognized by the engine as a definition of a QML type. Additionally, a type defined in this manner is automatically made available to other QML files within the same directory as the engine searches within the immediate directory when resolving QML type names.
For example, below is a document that declares a \l Rectangle with a child \l MouseArea. The document has been saved to file named \c SquareButton.qml:
diff --git a/src/qml/qml/qqmlcompileddata.cpp b/src/qml/qml/qqmlcompileddata.cpp
index 62150b1af1..7279762565 100644
--- a/src/qml/qml/qqmlcompileddata.cpp
+++ b/src/qml/qml/qqmlcompileddata.cpp
@@ -105,7 +105,7 @@ void QQmlCompiledData::destroy()
QQmlCompiledData::~QQmlCompiledData()
{
if (isRegisteredWithEngine)
- QQmlEnginePrivate::get(engine)->unregisterCompositeType(this);
+ QQmlEnginePrivate::get(engine)->unregisterInternalCompositeType(this);
clear();
diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp
index 7a65515634..a5f1cc564f 100644
--- a/src/qml/qml/qqmlcompiler.cpp
+++ b/src/qml/qml/qqmlcompiler.cpp
@@ -815,7 +815,10 @@ bool QQmlCompiler::compile(QQmlEngine *engine,
const QQmlTypeData::TypeReference &tref = resolvedTypes.at(ii);
QQmlScript::TypeReference *parserRef = referencedTypes.at(ii);
- if (tref.type) {
+ if (tref.typeData) { //QML-based type
+ ref.component = tref.typeData->compiledData();
+ ref.component->addref();
+ } else if (tref.type) {//C++-based type
ref.type = tref.type;
if (!ref.type->isCreatable()) {
QString err = ref.type->noCreationReason();
@@ -823,21 +826,18 @@ bool QQmlCompiler::compile(QQmlEngine *engine,
err = tr( "Element is not creatable.");
COMPILE_EXCEPTION(parserRef->firstUse, err);
}
-
+
if (ref.type->containsRevisionedAttributes()) {
QQmlError cacheError;
ref.typePropertyCache = enginePrivate->cache(ref.type,
resolvedTypes.at(ii).minorVersion,
cacheError);
- if (!ref.typePropertyCache)
+ if (!ref.typePropertyCache)
COMPILE_EXCEPTION(parserRef->firstUse, cacheError.description());
ref.typePropertyCache->addref();
}
-
- } else if (tref.typeData) {
- ref.component = tref.typeData->compiledData();
- ref.component->addref();
}
+
out->types << ref;
}
@@ -944,7 +944,7 @@ void QQmlCompiler::compileTree(QQmlScript::Object *tree)
Q_ASSERT(tree->metatype);
if (!tree->synthdata.isEmpty()) {
- enginePrivate->registerCompositeType(output);
+ enginePrivate->registerInternalCompositeType(output);
} else if (output->types.at(tree->type).component) {
output->metaTypeId = output->types.at(tree->type).component->metaTypeId;
output->listMetaTypeId = output->types.at(tree->type).component->listMetaTypeId;
@@ -954,7 +954,7 @@ void QQmlCompiler::compileTree(QQmlScript::Object *tree)
output->listMetaTypeId = output->types.at(tree->type).type->qListTypeId();
}
if (!tree->synthdata.isEmpty())
- enginePrivate->registerCompositeType(output);
+ enginePrivate->registerInternalCompositeType(output);
}
static bool QStringList_contains(const QStringList &list, const QHashedStringRef &string)
@@ -1752,7 +1752,7 @@ bool QQmlCompiler::buildProperty(QQmlScript::Property *prop,
QQmlType *type = 0;
QQmlImportNamespace *typeNamespace = 0;
- unit->imports().resolveType(prop->name(), &type, 0, 0, 0, &typeNamespace);
+ unit->imports().resolveType(prop->name(), &type, 0, 0, &typeNamespace);
if (typeNamespace) {
COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj,
@@ -1874,7 +1874,7 @@ bool QQmlCompiler::buildPropertyInNamespace(QQmlImportNamespace *ns,
// Setup attached property data
QQmlType *type = 0;
- unit->imports().resolveType(ns, prop->name(), &type, 0, 0, 0);
+ unit->imports().resolveType(ns, prop->name(), &type, 0, 0);
if (!type || !type->attachedPropertiesType())
COMPILE_EXCEPTION(prop, tr("Non-existent attached object"));
@@ -2572,10 +2572,12 @@ bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop,
}
QQmlType *type = 0;
- unit->imports().resolveType(typeName, &type, 0, 0, 0, 0);
+ unit->imports().resolveType(typeName, &type, 0, 0, 0);
if (!type && typeName != QLatin1String("Qt"))
return true;
+ if (type && type->isComposite()) //No enums on composite types
+ return true;
int value = 0;
bool ok = false;
@@ -2619,7 +2621,7 @@ int QQmlCompiler::evaluateEnum(const QHashedStringRef &scope, const QByteArray&
if (scope != QLatin1String("Qt")) {
QQmlType *type = 0;
- unit->imports().resolveType(scope, &type, 0, 0, 0, 0);
+ unit->imports().resolveType(scope, &type, 0, 0, 0);
return type ? type->enumValue(QHashedCStringRef(enumValue.constData(), enumValue.length()), ok) : -1;
}
@@ -2636,7 +2638,7 @@ int QQmlCompiler::evaluateEnum(const QHashedStringRef &scope, const QByteArray&
const QMetaObject *QQmlCompiler::resolveType(const QString& name) const
{
QQmlType *qmltype = 0;
- if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0))
+ if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0))
return 0;
if (!qmltype)
return 0;
@@ -3024,12 +3026,11 @@ bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mod
// lazily resolved type
Q_ASSERT(s->parameterTypes.at(i) == Object::DynamicProperty::Custom);
QQmlType *qmltype = 0;
- QString url;
- if (!unit->imports().resolveType(s->parameterTypeNames.at(i).toString(), &qmltype, &url, 0, 0, 0))
+ 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()));
- if (!qmltype) {
- QQmlTypeData *tdata = enginePrivate->typeLoader.getType(QUrl(url));
+ if (qmltype->isComposite()) {
+ QQmlTypeData *tdata = enginePrivate->typeLoader.getType(qmltype->sourceUrl());
Q_ASSERT(tdata);
Q_ASSERT(tdata->isComplete());
@@ -3121,12 +3122,12 @@ bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mod
p->type == Object::DynamicProperty::Custom);
QQmlType *qmltype = 0;
- QString url;
- if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0))
+ if (!unit->imports().resolveType(p->customType.toString(), &qmltype, 0, 0, 0))
COMPILE_EXCEPTION(p, tr("Invalid property type"));
- if (!qmltype) {
- QQmlTypeData *tdata = enginePrivate->typeLoader.getType(QUrl(url));
+ Q_ASSERT(qmltype);
+ if (qmltype->isComposite()) {
+ QQmlTypeData *tdata = enginePrivate->typeLoader.getType(qmltype->sourceUrl());
Q_ASSERT(tdata);
Q_ASSERT(tdata->isComplete());
@@ -3885,7 +3886,7 @@ QQmlType *QQmlCompiler::toQmlType(QQmlScript::Object *from)
type = QQmlMetaType::qmlType(mo);
mo = mo->superClass();
}
- return type;
+ return type;
}
QStringList QQmlCompiler::deferredProperties(QQmlScript::Object *obj)
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 074ea51ce3..b0b6f45fa9 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -2062,7 +2062,7 @@ QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t)
}
}
-void QQmlEnginePrivate::registerCompositeType(QQmlCompiledData *data)
+void QQmlEnginePrivate::registerInternalCompositeType(QQmlCompiledData *data)
{
QByteArray name = data->rootPropertyCache->className();
@@ -2097,7 +2097,7 @@ void QQmlEnginePrivate::registerCompositeType(QQmlCompiledData *data)
m_compositeTypes.insert(ptr_type, data);
}
-void QQmlEnginePrivate::unregisterCompositeType(QQmlCompiledData *data)
+void QQmlEnginePrivate::unregisterInternalCompositeType(QQmlCompiledData *data)
{
int ptr_type = data->metaTypeId;
int lst_type = data->listMetaTypeId;
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index 43bcc0390f..b5af0bb7cd 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -235,8 +235,8 @@ public:
QQmlMetaObject metaObjectForType(int) const;
QQmlPropertyCache *propertyCacheForType(int);
QQmlPropertyCache *rawPropertyCacheForType(int);
- void registerCompositeType(QQmlCompiledData *);
- void unregisterCompositeType(QQmlCompiledData *);
+ void registerInternalCompositeType(QQmlCompiledData *);
+ void unregisterInternalCompositeType(QQmlCompiledData *);
bool isTypeLoaded(const QUrl &url) const;
bool isScriptLoaded(const QUrl &url) const;
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 52d07b23ec..95b59f93f4 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -124,6 +124,39 @@ bool isPathAbsolute(const QString &path)
#endif
}
+// 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)
+{
+ QUrl url(urlString);
+ QQmlType *ret = QQmlMetaType::qmlType(url);
+ if (!ret) { //QQmlType not yet existing for composite 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.toUtf8().constData());
+
+ 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);
+ if (!errors) // Cannot list errors properly, just quit
+ qFatal(QQmlMetaType::typeRegistrationFailures().join('\n').toLatin1().constData());
+ QQmlError error;
+ error.setDescription(QQmlMetaType::typeRegistrationFailures().join('\n'));
+ errors->prepend(error);
+ }
+ return ret;
+
+}
+
}
typedef QMap<QString, QString> StringStringMap;
@@ -150,8 +183,7 @@ public:
static QQmlDirScripts getVersionedScripts(const QQmlDirScripts &qmldirscripts, int vmaj, int vmin);
bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &type,
- int *vmajor, int *vminor,
- QQmlType** type_return, QString* url_return,
+ int *vmajor, int *vminor, QQmlType** type_return,
QString *base = 0, bool *typeRecursionDetected = 0) const;
};
QList<Import *> imports;
@@ -159,8 +191,7 @@ public:
Import *findImport(const QString &uri);
bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef& type,
- int *vmajor, int *vminor,
- QQmlType** type_return, QString* url_return,
+ int *vmajor, int *vminor, QQmlType** type_return,
QString *base = 0, QList<QQmlError> *errors = 0);
// Prefix when used as a qualified import. Otherwise empty.
@@ -194,8 +225,7 @@ public:
QList<QQmlError> *errors);
bool resolveType(const QHashedStringRef &type, int *vmajor, int *vminor,
- QQmlType** type_return, QString* url_return,
- QList<QQmlError> *errors);
+ QQmlType** type_return, QList<QQmlError> *errors);
QUrl baseUrl;
QString base;
@@ -379,9 +409,8 @@ QString QQmlImports::completeQmldirPath(const QString &uri, const QString &base,
The given (namespace qualified) \a type is resolved to either
\list
- \li a QQmlImportNamespace stored at \a ns_return,
- \li a QQmlType stored at \a type_return, or
- \li a component located at \a url_return.
+ \li a QQmlImportNamespace stored at \a ns_return, or
+ \li a QQmlType stored at \a type_return,
\endlist
If any return pointer is 0, the corresponding search is not done.
@@ -389,7 +418,7 @@ QString QQmlImports::completeQmldirPath(const QString &uri, const QString &base,
\sa addFileImport(), addLibraryImport
*/
bool QQmlImports::resolveType(const QHashedStringRef &type,
- QQmlType** type_return, QString* url_return, int *vmaj, int *vmin,
+ QQmlType** type_return, int *vmaj, int *vmin,
QQmlImportNamespace** ns_return, QList<QQmlError> *errors) const
{
QQmlImportNamespace* ns = d->findQualifiedNamespace(type);
@@ -398,19 +427,16 @@ bool QQmlImports::resolveType(const QHashedStringRef &type,
*ns_return = ns;
return true;
}
- if (type_return || url_return) {
- if (d->resolveType(type,vmaj,vmin,type_return,url_return, errors)) {
+ if (type_return) {
+ if (d->resolveType(type,vmaj,vmin,type_return, errors)) {
if (qmlImportTrace()) {
#define RESOLVE_TYPE_DEBUG qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) \
<< ')' << "::resolveType: " << type.toString() << " => "
- if (type_return && *type_return && url_return && !url_return->isEmpty())
- RESOLVE_TYPE_DEBUG << (*type_return)->typeName() << ' ' << *url_return << " TYPE/URL";
- if (type_return && *type_return)
+ 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";
- if (url_return && !url_return->isEmpty())
- RESOLVE_TYPE_DEBUG << *url_return << " URL";
-
#undef RESOLVE_TYPE_DEBUG
}
return true;
@@ -469,23 +495,21 @@ QQmlDirScripts QQmlImportNamespace::Import::getVersionedScripts(const QQmlDirScr
\internal
Searching \e only in the namespace \a ns (previously returned in a call to
- resolveType(), \a type is found and returned to either
- a QQmlType stored at \a type_return, or
- a component located at \a url_return.
+ resolveType(), \a type is found and returned to
+ a QQmlType stored at \a type_return. If the type is from a QML file, the returned
+ type will be a CompositeType.
- If either return pointer is 0, the corresponding search is not done.
+ If the return pointer is 0, the corresponding search is not done.
*/
bool QQmlImports::resolveType(QQmlImportNamespace* ns, const QHashedStringRef &type,
- QQmlType** type_return, QString* url_return,
- int *vmaj, int *vmin) const
+ QQmlType** type_return, int *vmaj, int *vmin) const
{
- return ns->resolveType(d->typeLoader,type,vmaj,vmin,type_return,url_return);
+ return ns->resolveType(d->typeLoader,type,vmaj,vmin,type_return);
}
bool QQmlImportNamespace::Import::resolveType(QQmlTypeLoader *typeLoader,
const QHashedStringRef& type, int *vmajor, int *vminor,
- QQmlType** type_return, QString* url_return,
- QString *base, bool *typeRecursionDetected) const
+ QQmlType** type_return, QString *base, bool *typeRecursionDetected) const
{
if (majversion >= 0 && minversion >= 0) {
QQmlType *t = QQmlMetaType::qmlType(type, uri, majversion, minversion);
@@ -530,9 +554,9 @@ bool QQmlImportNamespace::Import::resolveType(QQmlTypeLoader *typeLoader,
}
if (candidate != end) {
- if (url_return)
- *url_return = componentUrl;
- return true;
+ if (type_return)
+ *type_return = getTypeForUrl(componentUrl, type, 0);
+ return (*type_return != 0);
}
} else if (!isLibrary) {
QString qmlUrl = url + QString::fromRawData(type.constData(), type.length()) + dotqml_string;
@@ -550,9 +574,9 @@ bool QQmlImportNamespace::Import::resolveType(QQmlTypeLoader *typeLoader,
if (typeRecursionDetected)
*typeRecursionDetected = true;
} else {
- if (url_return)
- *url_return = qmlUrl;
- return true;
+ if (type_return)
+ *type_return = getTypeForUrl(qmlUrl, type, 0);
+ return (*type_return) != 0;
}
}
}
@@ -561,8 +585,7 @@ bool QQmlImportNamespace::Import::resolveType(QQmlTypeLoader *typeLoader,
}
bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor, int *vminor,
- QQmlType** type_return, QString* url_return,
- QList<QQmlError> *errors)
+ QQmlType** type_return, QList<QQmlError> *errors)
{
QQmlImportNamespace *s = 0;
int dot = type.indexOf(Dot);
@@ -591,12 +614,12 @@ bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor,
}
QHashedStringRef unqualifiedtype = dot < 0 ? type : QHashedStringRef(type.constData()+dot+1, type.length()-dot-1);
if (s) {
- if (s->resolveType(typeLoader,unqualifiedtype,vmajor,vminor,type_return,url_return, &base, errors))
+ if (s->resolveType(typeLoader,unqualifiedtype,vmajor,vminor,type_return, &base, errors))
return true;
- if (s->imports.count() == 1 && !s->imports.at(0)->isLibrary && url_return && s != &unqualifiedset) {
+ if (s->imports.count() == 1 && !s->imports.at(0)->isLibrary && type_return && s != &unqualifiedset) {
// qualified, and only 1 url
- *url_return = resolveLocalUrl(s->imports.at(0)->url, unqualifiedtype.toString() + QLatin1String(".qml"));
- return true;
+ *type_return = getTypeForUrl(resolveLocalUrl(s->imports.at(0)->url, unqualifiedtype.toString() + QLatin1String(".qml")), type, errors);
+ return (*type_return != 0);
}
}
@@ -615,18 +638,18 @@ QQmlImportNamespace::Import *QQmlImportNamespace::findImport(const QString &uri)
bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &type,
int *vmajor, int *vminor, QQmlType** type_return,
- QString* url_return, QString *base, QList<QQmlError> *errors)
+ QString *base, QList<QQmlError> *errors)
{
bool typeRecursionDetected = false;
for (int i=0; i<imports.count(); ++i) {
const Import *import = imports.at(i);
- if (import->resolveType(typeLoader, type, vmajor, vminor, type_return, url_return,
+ if (import->resolveType(typeLoader, type, vmajor, vminor, type_return,
base, &typeRecursionDetected)) {
if (qmlCheckTypes()) {
// check for type clashes
for (int j = i+1; j<imports.count(); ++j) {
const Import *import2 = imports.at(j);
- if (import2->resolveType(typeLoader, type, vmajor, vminor, 0, 0, base)) {
+ if (import2->resolveType(typeLoader, type, vmajor, vminor, 0, base)) {
if (errors) {
QString u1 = import->url;
QString u2 = import2->url;
diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h
index ad4b3dfee9..140ca6695e 100644
--- a/src/qml/qml/qqmlimport_p.h
+++ b/src/qml/qml/qqmlimport_p.h
@@ -85,14 +85,13 @@ public:
QUrl baseUrl() const;
bool resolveType(const QHashedStringRef &type,
- QQmlType** type_return, QString* url_return,
+ QQmlType** type_return,
int *version_major, int *version_minor,
QQmlImportNamespace** ns_return,
QList<QQmlError> *errors = 0) const;
bool resolveType(QQmlImportNamespace*,
const QHashedStringRef& type,
- QQmlType** type_return, QString* url_return,
- int *version_major, int *version_minor) const;
+ QQmlType** type_return, int *version_major, int *version_minor) const;
bool addImplicitImport(QQmlImportDatabase *importDb, QList<QQmlError> *errors);
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index 2a2d0b3879..372475d85c 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -75,6 +75,8 @@ struct QQmlMetaTypeData
Ids idToType;
typedef QHash<QHashedStringRef,QQmlType *> Names;
Names nameToType;
+ typedef QHash<QUrl, QQmlType *> Files; //For file imported composite types only
+ Files urlToType;
typedef QHash<const QMetaObject *, QQmlType *> MetaObjects;
MetaObjects metaObjectToType;
typedef QHash<int, QQmlMetaType::StringConverter> StringConverters;
@@ -178,9 +180,15 @@ public:
QQmlType::SingletonInstanceInfo *singletonInstanceInfo;
};
+ struct QQmlCompositeTypeData
+ {
+ QUrl url;
+ };
+
union extraData {
QQmlCppTypeData* cd;
QQmlSingletonTypeData* sd;
+ QQmlCompositeTypeData* fd;
} extraData;
const char *iid;
@@ -292,6 +300,9 @@ QQmlTypePrivate::QQmlTypePrivate(QQmlType::RegistrationType type)
case QQmlType::InterfaceType:
extraData.cd = 0;
break;
+ case QQmlType::CompositeType:
+ extraData.fd = new QQmlCompositeTypeData;
+ break;
default: qFatal("QQmlTypePrivate Internal Error.");
}
}
@@ -307,6 +318,9 @@ QQmlTypePrivate::~QQmlTypePrivate()
delete extraData.sd->singletonInstanceInfo;
delete extraData.sd;
break;
+ case QQmlType::CompositeType:
+ delete extraData.fd;
+ break;
default: //Also InterfaceType, because it has no extra data
break;
}
@@ -389,6 +403,19 @@ QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::Reg
d->extraData.cd->extMetaObject = type.extensionMetaObject;
}
+QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::RegisterCompositeType &type)
+: d(new QQmlTypePrivate(CompositeType))
+{
+ d->index = index;
+ d->elementName = elementName;
+
+ d->module = moduleFromUtf8(type.uri);
+ d->version_maj = type.versionMajor;
+ d->version_min = type.versionMinor;
+
+ d->extraData.fd->url = type.url;
+}
+
QQmlType::~QQmlType()
{
delete d;
@@ -751,6 +778,11 @@ bool QQmlType::isInterface() const
return d->regType == InterfaceType;
}
+bool QQmlType::isComposite() const
+{
+ return d->regType == CompositeType;
+}
+
int QQmlType::typeId() const
{
return d->typeId;
@@ -848,6 +880,13 @@ int QQmlType::index() const
return d->index;
}
+QUrl QQmlType::sourceUrl() const
+{
+ if (d->regType != CompositeType)
+ return QUrl();
+ return d->extraData.fd->url;
+}
+
int QQmlType::enumValue(const QHashedStringRef &name, bool *ok) const
{
Q_ASSERT(ok);
@@ -1074,6 +1113,8 @@ QString registrationTypeString(QQmlType::RegistrationType typeType)
typeStr = QStringLiteral("element");
else if (typeType == QQmlType::SingletonType)
typeStr = QStringLiteral("singleton type");
+ else
+ typeStr = QStringLiteral("type");
return typeStr;
}
@@ -1083,7 +1124,7 @@ bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *da
if (!typeName.isEmpty()) {
int typeNameLen = typeName.length();
for (int ii = 0; ii < typeNameLen; ++ii) {
- if (!typeName.at(ii).isLetterOrNumber()) {
+ if (!(typeName.at(ii).isLetterOrNumber() || typeName.at(ii) == '_')) {
QString failure(QCoreApplication::translate("qmlRegisterType", "Invalid QML %1 name \"%2\""));
data->typeRegistrationFailures.append(failure.arg(registrationTypeString(typeType)).arg(typeName));
return false;
@@ -1116,46 +1157,59 @@ bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *da
return true;
}
-int registerType(const QQmlPrivate::RegisterType &type)
+// NOTE: caller must hold a QWriteLocker on "data"
+void addTypeToData(QQmlType* type, QQmlMetaTypeData *data)
{
- QWriteLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
- QString elementName = QString::fromUtf8(type.elementName);
- if (!checkRegistration(QQmlType::CppType, data, type.uri, elementName))
- return -1;
-
- int index = data->types.count();
-
- QQmlType *dtype = new QQmlType(index, elementName, type);
-
- data->types.append(dtype);
- data->idToType.insert(dtype->typeId(), dtype);
- if (dtype->qListTypeId()) data->idToType.insert(dtype->qListTypeId(), dtype);
+ if (!type->elementName().isEmpty())
+ data->nameToType.insertMulti(type->elementName(), type);
- if (!dtype->elementName().isEmpty())
- data->nameToType.insertMulti(dtype->elementName(), dtype);
+ if (type->baseMetaObject())
+ data->metaObjectToType.insertMulti(type->baseMetaObject(), type);
- data->metaObjectToType.insertMulti(dtype->baseMetaObject(), dtype);
+ if (type->typeId()) {
+ data->idToType.insert(type->typeId(), type);
+ if (data->objects.size() <= type->typeId())
+ data->objects.resize(type->typeId() + 16);
+ data->objects.setBit(type->typeId(), true);
+ }
- if (data->objects.size() <= type.typeId)
- data->objects.resize(type.typeId + 16);
- if (data->lists.size() <= type.listId)
- data->lists.resize(type.listId + 16);
- data->objects.setBit(type.typeId, true);
- if (type.listId) data->lists.setBit(type.listId, true);
+ if (type->qListTypeId()) {
+ if (data->lists.size() <= type->qListTypeId())
+ data->lists.resize(type->qListTypeId() + 16);
+ data->lists.setBit(type->qListTypeId(), true);
+ data->idToType.insert(type->qListTypeId(), type);
+ }
- if (!dtype->module().isEmpty()) {
- const QHashedString &mod = dtype->module();
+ if (!type->module().isEmpty()) {
+ const QHashedString &mod = type->module();
- QQmlMetaTypeData::VersionedUri versionedUri(mod, type.versionMajor);
+ QQmlMetaTypeData::VersionedUri versionedUri(mod, type->majorVersion());
QQmlTypeModule *module = data->uriToModule.value(versionedUri);
if (!module) {
module = new QQmlTypeModule;
module->d->uri = versionedUri;
data->uriToModule.insert(versionedUri, module);
}
- module->d->add(dtype);
+ module->d->add(type);
}
+}
+
+int registerType(const QQmlPrivate::RegisterType &type)
+{
+ QWriteLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+ QString elementName = QString::fromUtf8(type.elementName);
+ if (!checkRegistration(QQmlType::CppType, data, type.uri, elementName))
+ return -1;
+
+ int index = data->types.count();
+
+ QQmlType *dtype = new QQmlType(index, elementName, type);
+
+ data->types.append(dtype);
+ addTypeToData(dtype, data);
+ if (!type.typeId)
+ data->idToType.insert(dtype->typeId(), dtype);
return index;
}
@@ -1173,32 +1227,31 @@ int registerSingletonType(const QQmlPrivate::RegisterSingletonType &type)
QQmlType *dtype = new QQmlType(index, typeName, type);
data->types.append(dtype);
- data->idToType.insert(dtype->typeId(), dtype);
+ addTypeToData(dtype, data);
- if (!dtype->elementName().isEmpty())
- data->nameToType.insertMulti(dtype->elementName(), dtype);
+ return index;
+}
- if (dtype->baseMetaObject())
- data->metaObjectToType.insertMulti(dtype->baseMetaObject(), dtype);
+int registerCompositeType(const QQmlPrivate::RegisterCompositeType &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::CompositeType, data, fileImport?0:type.uri, typeName))
+ return -1;
- if (type.typeId) {
- if (data->objects.size() <= type.typeId)
- data->objects.resize(type.typeId + 16);
- data->objects.setBit(type.typeId, true);
- }
+ int index = data->types.count();
- if (!dtype->module().isEmpty()) {
- const QHashedString &mod = dtype->module();
+ QQmlType *dtype = new QQmlType(index, typeName, type);
+ data->types.append(dtype);
+ addTypeToData(dtype, data);
- QQmlMetaTypeData::VersionedUri versionedUri(mod, type.versionMajor);
- QQmlTypeModule *module = data->uriToModule.value(versionedUri);
- if (!module) {
- module = new QQmlTypeModule;
- module->d->uri = versionedUri;
- data->uriToModule.insert(versionedUri, module);
- }
- module->d->add(dtype);
- }
+ if (fileImport)
+ data->urlToType.insertMulti(type.url, dtype);
return index;
}
@@ -1218,6 +1271,8 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data)
return registerAutoParentFunction(*reinterpret_cast<RegisterAutoParent *>(data));
} else if (type == SingletonRegistration) {
return registerSingletonType(*reinterpret_cast<RegisterSingletonType *>(data));
+ } else if (type == CompositeRegistration) {
+ return registerCompositeType(*reinterpret_cast<RegisterCompositeType *>(data));
}
return -1;
}
@@ -1534,7 +1589,7 @@ QQmlType *QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStrin
QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.constFind(name);
while (it != data->nameToType.end() && it.key() == name) {
// XXX version_major<0 just a kludge for QQmlPropertyPrivate::initProperty
- if (version_major < 0 || (*it)->availableInVersion(module, version_major,version_minor))
+ if (version_major < 0 || module.isEmpty() || (*it)->availableInVersion(module, version_major,version_minor))
return (*it);
++it;
}
@@ -1568,7 +1623,7 @@ QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStri
QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.constFind(metaObject);
while (it != data->metaObjectToType.end() && it.key() == metaObject) {
QQmlType *t = *it;
- if (version_major < 0 || t->availableInVersion(module, version_major,version_minor))
+ if (version_major < 0 || module.isEmpty() || t->availableInVersion(module, version_major,version_minor))
return t;
++it;
}
@@ -1593,6 +1648,39 @@ QQmlType *QQmlMetaType::qmlType(int userType)
}
/*!
+ Returns the type (if any) that corresponds to the given \a url in the set of
+ composite types added through file imports.
+
+ Returns null if no such type is registered.
+*/
+QQmlType *QQmlMetaType::qmlType(const QUrl &url)
+{
+ QReadLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+
+ QQmlType *type = data->urlToType.value(url);
+ if (type && type->sourceUrl() == url)
+ return type;
+ else
+ return 0;
+}
+
+/*!
+ Returns the type (if any) with the given \a index in the global type store.
+ This is for use when you just got the index back from a qmlRegister function.
+ Returns null if the index is out of bounds.
+*/
+QQmlType *QQmlMetaType::qmlTypeFromIndex(int idx)
+{
+ QReadLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+
+ if (idx < 0 || idx >= data->types.count())
+ return 0;
+ return data->types[idx];
+}
+
+/*!
Returns the list of registered QML type names.
*/
QList<QString> QQmlMetaType::qmlTypeNames()
diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h
index 8d3aad519e..497afffb5d 100644
--- a/src/qml/qml/qqmlmetatype_p.h
+++ b/src/qml/qml/qqmlmetatype_p.h
@@ -84,6 +84,8 @@ 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 *qmlTypeFromIndex(int);
static QMetaProperty defaultProperty(const QMetaObject *);
static QMetaProperty defaultProperty(QObject *);
@@ -164,6 +166,7 @@ public:
bool isSingleton() const;
bool isInterface() const;
+ bool isComposite() const;
int typeId() const;
int qListTypeId() const;
@@ -206,6 +209,7 @@ public:
QHash<QQmlEngine *, QObject *> qobjectApis;
};
SingletonInstanceInfo *singletonInstanceInfo() const;
+ QUrl sourceUrl() const;
int enumValue(const QHashedStringRef &, bool *ok) const;
int enumValue(const QHashedCStringRef &, bool *ok) const;
@@ -218,17 +222,19 @@ private:
enum RegistrationType {
CppType = 0,
SingletonType = 1,
- InterfaceType = 2
- // In the near future, we should register all types via QQmlType, including Composite types.
+ InterfaceType = 2,
+ CompositeType = 3
};
friend QString registrationTypeString(RegistrationType);
friend bool checkRegistration(RegistrationType, QQmlMetaTypeData *, const char *, const QString &);
friend int registerType(const QQmlPrivate::RegisterType &);
friend int registerSingletonType(const QQmlPrivate::RegisterSingletonType &);
friend int registerInterface(const QQmlPrivate::RegisterInterface &);
+ friend int registerCompositeType(const QQmlPrivate::RegisterCompositeType &);
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();
QQmlTypePrivate *d;
@@ -250,8 +256,8 @@ public:
QList<QQmlType*> singletonTypes(int) const;
private:
- friend int registerType(const QQmlPrivate::RegisterType &);
- friend int registerSingletonType(const QQmlPrivate::RegisterSingletonType &);
+ //Used by register functions and creates the QQmlTypeModule for them
+ friend void addTypeToData(QQmlType* type, QQmlMetaTypeData *data);
friend struct QQmlMetaTypeData;
QQmlTypeModule();
diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h
index 4d345fad23..570435ae81 100644
--- a/src/qml/qml/qqmlprivate.h
+++ b/src/qml/qml/qqmlprivate.h
@@ -57,6 +57,7 @@
#include <QtCore/qglobal.h>
#include <QtCore/qvariant.h>
+#include <QtCore/qurl.h>
QT_BEGIN_NAMESPACE
@@ -251,11 +252,20 @@ namespace QQmlPrivate
// If this is extended ensure "version" is bumped!!!
};
+ struct RegisterCompositeType {
+ const QUrl &url;
+ const char *uri;
+ int versionMajor;
+ int versionMinor;
+ const char *typeName;
+ };
+
enum RegistrationType {
- TypeRegistration = 0,
+ TypeRegistration = 0,
InterfaceRegistration = 1,
AutoParentRegistration = 2,
- SingletonRegistration = 3
+ SingletonRegistration = 3,
+ CompositeRegistration = 4
};
int Q_QML_EXPORT qmlregister(RegistrationType, void *);
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index aa7a2d95c7..5910f60667 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -2135,12 +2135,12 @@ void QQmlTypeData::resolveTypes()
TypeReference ref;
QString url;
- int majorVersion;
- int minorVersion;
+ int majorVersion = -1;
+ int minorVersion = -1;
QQmlImportNamespace *typeNamespace = 0;
QList<QQmlError> errors;
- if (!m_imports.resolveType(parserRef->name, &ref.type, &url, &majorVersion, &minorVersion,
+ if (!m_imports.resolveType(parserRef->name, &ref.type, &majorVersion, &minorVersion,
&typeNamespace, &errors) || typeNamespace) {
// Known to not be a type:
// - known to be a namespace (Namespace {})
@@ -2169,13 +2169,12 @@ void QQmlTypeData::resolveTypes()
return;
}
- if (ref.type) {
- ref.majorVersion = majorVersion;
- ref.minorVersion = minorVersion;
- } else {
- ref.typeData = typeLoader()->getType(QUrl(url));
+ if (ref.type->isComposite()) {
+ ref.typeData = typeLoader()->getType(ref.type->sourceUrl());
addDependency(ref.typeData);
}
+ ref.majorVersion = majorVersion;
+ ref.minorVersion = minorVersion;
Q_ASSERT(parserRef->firstUse);
ref.location = parserRef->firstUse->location.start;