diff options
author | Alan Alpert <416365416c@gmail.com> | 2012-12-16 21:24:14 -0800 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-02-18 12:54:15 +0100 |
commit | 4d3a64c5e65a781acb4acf4ba641456da28bd1e4 (patch) | |
tree | 10d1374401131a7d22146cdf7029307aea9efe7b /src/qml/qml | |
parent | 58471eb3f267dbee728b1c13f87458f2ee509bfa (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.cpp | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmlcompiler.cpp | 47 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine.cpp | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine_p.h | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmlimport.cpp | 107 | ||||
-rw-r--r-- | src/qml/qml/qqmlimport_p.h | 5 | ||||
-rw-r--r-- | src/qml/qml/qqmlmetatype.cpp | 190 | ||||
-rw-r--r-- | src/qml/qml/qqmlmetatype_p.h | 14 | ||||
-rw-r--r-- | src/qml/qml/qqmlprivate.h | 14 | ||||
-rw-r--r-- | src/qml/qml/qqmltypeloader.cpp | 15 |
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, ®)); + } + 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; |