aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/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/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/qml')
-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
10 files changed, 264 insertions, 138 deletions
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;