diff options
author | Aaron Kennedy <aaron.kennedy@nokia.com> | 2012-04-10 18:11:30 +0100 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-05-04 13:15:01 +0200 |
commit | 6f3bda0dce945a5fc75d8ebad302820fe9979d9b (patch) | |
tree | 6581aad8a7fb21ccbebe09d23c30af0e3236e266 /src/qml/qml/qqmlimport.cpp | |
parent | 44f9412bf789d73dd462292038686f5b07026132 (diff) |
Initial bundle support
Change-Id: I095249f64ecf4ef1e3fbfb164e3d50edffab61e8
Reviewed-by: Roberto Raggi <roberto.raggi@nokia.com>
Diffstat (limited to 'src/qml/qml/qqmlimport.cpp')
-rw-r--r-- | src/qml/qml/qqmlimport.cpp | 969 |
1 files changed, 567 insertions, 402 deletions
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index a8a3ed0a4b..1417e3dff7 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -43,6 +43,7 @@ #include <QtCore/qdebug.h> #include <QtCore/qdir.h> +#include <QtQml/qqmlfile.h> #include <QtCore/qfileinfo.h> #include <QtCore/qpluginloader.h> #include <QtCore/qlibraryinfo.h> @@ -56,11 +57,6 @@ QT_BEGIN_NAMESPACE DEFINE_BOOL_CONFIG_OPTION(qmlImportTrace, QML_IMPORT_TRACE) DEFINE_BOOL_CONFIG_OPTION(qmlCheckTypes, QML_CHECK_TYPES) -static bool greaterThan(const QString &s1, const QString &s2) -{ - return s1 > s2; -} - QString resolveLocalUrl(const QString &url, const QString &relative) { if (relative.contains(QLatin1Char(':'))) { @@ -109,15 +105,13 @@ QString resolveLocalUrl(const QString &url, const QString &relative) } } - - typedef QMap<QString, QString> StringStringMap; Q_GLOBAL_STATIC(StringStringMap, qmlEnginePluginsWithRegisteredTypes); // stores the uri -class QQmlImportedNamespace +class QQmlImportNamespace { public: - struct Data { + struct Import { QString uri; QString url; int majversion; @@ -125,45 +119,58 @@ public: bool isLibrary; QQmlDirComponents qmlDirComponents; QQmlDirScripts qmlDirScripts; - }; - QList<Data> imports; + bool resolveType(QQmlTypeLoader *typeLoader, const QString& type, + int *vmajor, int *vminor, + QQmlType** type_return, QString* url_return, + QString *base = 0, bool *typeRecursionDetected = 0) const; + }; + QList<Import> imports; - bool find_helper(QQmlTypeLoader *typeLoader, const Data &data, const QString& type, int *vmajor, int *vminor, - QQmlType** type_return, QString* url_return, - QString *base = 0, bool *typeRecursionDetected = 0); - bool find(QQmlTypeLoader *typeLoader, const QString& type, int *vmajor, int *vminor, QQmlType** type_return, - QString* url_return, QString *base = 0, QList<QQmlError> *errors = 0); + bool resolveType(QQmlTypeLoader *typeLoader, const QString& type, + int *vmajor, int *vminor, + QQmlType** type_return, QString* url_return, + QString *base = 0, QList<QQmlError> *errors = 0); }; -class QQmlImportsPrivate { +class QQmlImportsPrivate +{ public: QQmlImportsPrivate(QQmlTypeLoader *loader); ~QQmlImportsPrivate(); - bool importExtension(const QString &absoluteFilePath, const QString &uri, - QQmlImportDatabase *database, QQmlDirComponents* components, - QQmlDirScripts *scripts, - QList<QQmlError> *errors); - - QString resolvedUri(const QString &dir_arg, QQmlImportDatabase *database); - QString add(const QQmlDirComponents &qmldircomponentsnetwork, - const QString& uri_arg, const QString& prefix, - int vmaj, int vmin, QQmlScript::Import::Type importType, - QQmlImportDatabase *database, QList<QQmlError> *errors); - bool find(const QString& type, int *vmajor, int *vminor, - QQmlType** type_return, QString* url_return, QList<QQmlError> *errors); + bool addImport(const QQmlDirComponents &qmldircomponentsnetwork, + const QString &importedUri, const QString& prefix, + int vmaj, int vmin, QQmlScript::Import::Type importType, + bool isImplicitImport, QQmlImportDatabase *database, + QString *, QList<QQmlError> *errors); - QQmlImportedNamespace *findNamespace(const QString& type); + bool resolveType(const QString& type, int *vmajor, int *vminor, + QQmlType** type_return, QString* url_return, + QList<QQmlError> *errors); QUrl baseUrl; QString base; int ref; QSet<QString> qmlDirFilesForWhichPluginsHaveBeenLoaded; - QQmlImportedNamespace unqualifiedset; - QHash<QString,QQmlImportedNamespace* > set; + QQmlImportNamespace unqualifiedset; + QHash<QString, QQmlImportNamespace *> set; QQmlTypeLoader *typeLoader; + + static inline QString tr(const char *str) { + return QQmlImportDatabase::tr(str); + } + +private: + static bool locateQmldir(const QString &uri, int vmaj, int vmin, + QQmlImportDatabase *database, + QString *outQmldirFilePath, QString *outUrl); + bool importExtension(const QString &absoluteFilePath, const QString &uri, + QQmlImportDatabase *database, QQmlDirComponents* components, + QQmlDirScripts *scripts, + QString *url, QList<QQmlError> *errors); + QString resolvedUri(const QString &dir_arg, QQmlImportDatabase *database); }; /*! @@ -223,29 +230,30 @@ QUrl QQmlImports::baseUrl() const void QQmlImports::populateCache(QQmlTypeNameCache *cache, QQmlEngine *engine) const { - const QQmlImportedNamespace &set = d->unqualifiedset; + const QQmlImportNamespace &set = d->unqualifiedset; for (int ii = set.imports.count() - 1; ii >= 0; --ii) { - const QQmlImportedNamespace::Data &data = set.imports.at(ii); - QQmlTypeModule *module = QQmlMetaType::typeModule(data.uri, data.majversion); + const QQmlImportNamespace::Import &import = set.imports.at(ii); + QQmlTypeModule *module = QQmlMetaType::typeModule(import.uri, import.majversion); if (module) - cache->m_anonymousImports.append(QQmlTypeModuleVersion(module, data.minversion)); + cache->m_anonymousImports.append(QQmlTypeModuleVersion(module, import.minversion)); } - for (QHash<QString,QQmlImportedNamespace* >::ConstIterator iter = d->set.begin(); + for (QHash<QString, QQmlImportNamespace* >::ConstIterator iter = d->set.begin(); iter != d->set.end(); ++iter) { - const QQmlImportedNamespace &set = *iter.value(); + const QQmlImportNamespace &set = *iter.value(); for (int ii = set.imports.count() - 1; ii >= 0; --ii) { - const QQmlImportedNamespace::Data &data = set.imports.at(ii); - QQmlTypeModule *module = QQmlMetaType::typeModule(data.uri, data.majversion); + const QQmlImportNamespace::Import &import = set.imports.at(ii); + QQmlTypeModule *module = QQmlMetaType::typeModule(import.uri, import.majversion); if (module) { - QQmlTypeNameCache::Import &import = cache->m_namedImports[iter.key()]; - import.modules.append(QQmlTypeModuleVersion(module, data.minversion)); + QQmlTypeNameCache::Import &typeimport = cache->m_namedImports[iter.key()]; + typeimport.modules.append(QQmlTypeModuleVersion(module, import.minversion)); } - QQmlMetaType::ModuleApi moduleApi = QQmlMetaType::moduleApi(data.uri, data.majversion, data.minversion); + QQmlMetaType::ModuleApi moduleApi = QQmlMetaType::moduleApi(import.uri, import.majversion, + import.minversion); if (moduleApi.script || moduleApi.qobject) { QQmlTypeNameCache::Import &import = cache->m_namedImports[iter.key()]; QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine); @@ -259,32 +267,32 @@ QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const { QList<QQmlImports::ScriptReference> scripts; - const QQmlImportedNamespace &set = d->unqualifiedset; + const QQmlImportNamespace &set = d->unqualifiedset; for (int ii = set.imports.count() - 1; ii >= 0; --ii) { - const QQmlImportedNamespace::Data &data = set.imports.at(ii); + const QQmlImportNamespace::Import &import = set.imports.at(ii); - foreach (const QQmlDirParser::Script &script, data.qmlDirScripts) { + foreach (const QQmlDirParser::Script &script, import.qmlDirScripts) { ScriptReference ref; ref.nameSpace = script.nameSpace; - ref.location = QUrl(data.url).resolved(QUrl(script.fileName)); + ref.location = QUrl(import.url).resolved(QUrl(script.fileName)); scripts.append(ref); } } - for (QHash<QString,QQmlImportedNamespace* >::ConstIterator iter = d->set.constBegin(); + for (QHash<QString, QQmlImportNamespace* >::ConstIterator iter = d->set.constBegin(); iter != d->set.constEnd(); ++iter) { - const QQmlImportedNamespace &set = *iter.value(); + const QQmlImportNamespace &set = *iter.value(); for (int ii = set.imports.count() - 1; ii >= 0; --ii) { - const QQmlImportedNamespace::Data &data = set.imports.at(ii); + const QQmlImportNamespace::Import &import = set.imports.at(ii); - foreach (const QQmlDirParser::Script &script, data.qmlDirScripts) { + foreach (const QQmlDirParser::Script &script, import.qmlDirScripts) { ScriptReference ref; ref.nameSpace = script.nameSpace; ref.qualifier = iter.key(); - ref.location = QUrl(data.url).resolved(QUrl(script.fileName)); + ref.location = QUrl(import.url).resolved(QUrl(script.fileName)); scripts.append(ref); } } @@ -298,7 +306,7 @@ QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const The given (namespace qualified) \a type is resolved to either \list - \li a QQmlImportedNamespace stored at \a ns_return, + \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. \endlist @@ -308,27 +316,29 @@ QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const \sa addImport() */ bool QQmlImports::resolveType(const QString& type, - QQmlType** type_return, QString* url_return, int *vmaj, int *vmin, - QQmlImportedNamespace** ns_return, QList<QQmlError> *errors) const + QQmlType** type_return, QString* url_return, int *vmaj, int *vmin, + QQmlImportNamespace** ns_return, QList<QQmlError> *errors) const { - QQmlImportedNamespace* ns = d->findNamespace(type); + QQmlImportNamespace* ns = d->set.value(type); if (ns) { if (ns_return) *ns_return = ns; return true; } if (type_return || url_return) { - if (d->find(type,vmaj,vmin,type_return,url_return, errors)) { + if (d->resolveType(type,vmaj,vmin,type_return,url_return, errors)) { if (qmlImportTrace()) { +#define RESOLVE_TYPE_DEBUG qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) \ + << ")" << "::resolveType: " << type << " => " + if (type_return && *type_return && url_return && !url_return->isEmpty()) - qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) << ")" << "::resolveType: " - << type << " => " << (*type_return)->typeName() << " " << *url_return; + RESOLVE_TYPE_DEBUG << (*type_return)->typeName() << " " << *url_return; if (type_return && *type_return) - qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) << ")" << "::resolveType: " - << type << " => " << (*type_return)->typeName(); + RESOLVE_TYPE_DEBUG << (*type_return)->typeName(); if (url_return && !url_return->isEmpty()) - qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) << ")" << "::resolveType: " - << type << " => " << *url_return; + RESOLVE_TYPE_DEBUG << *url_return; + +#undef RESOLVE_TYPE_DEBUG } return true; } @@ -346,42 +356,40 @@ bool QQmlImports::resolveType(const QString& type, If either return pointer is 0, the corresponding search is not done. */ -bool QQmlImports::resolveType(QQmlImportedNamespace* ns, const QString& type, - QQmlType** type_return, QString* url_return, - int *vmaj, int *vmin) const +bool QQmlImports::resolveType(QQmlImportNamespace* ns, const QString& type, + QQmlType** type_return, QString* url_return, + int *vmaj, int *vmin) const { - return ns->find(d->typeLoader,type,vmaj,vmin,type_return,url_return); + return ns->resolveType(d->typeLoader,type,vmaj,vmin,type_return,url_return); } -bool QQmlImportedNamespace::find_helper(QQmlTypeLoader *typeLoader, const Data &data, const QString& type, int *vmajor, int *vminor, - QQmlType** type_return, QString* url_return, - QString *base, bool *typeRecursionDetected) +bool QQmlImportNamespace::Import::resolveType(QQmlTypeLoader *typeLoader, + const QString& type, int *vmajor, int *vminor, + QQmlType** type_return, QString* url_return, + QString *base, bool *typeRecursionDetected) const { - int vmaj = data.majversion; - int vmin = data.minversion; - - if (vmaj >= 0 && vmin >= 0) { - QString qt = data.uri + QLatin1Char('/') + type; - QQmlType *t = QQmlMetaType::qmlType(qt,vmaj,vmin); + if (majversion >= 0 && minversion >= 0) { + QString qt = uri + QLatin1Char('/') + type; + QQmlType *t = QQmlMetaType::qmlType(qt, majversion, minversion); if (t) { - if (vmajor) *vmajor = vmaj; - if (vminor) *vminor = vmin; + if (vmajor) *vmajor = majversion; + if (vminor) *vminor = minversion; if (type_return) *type_return = t; return true; } } - const QQmlDirComponents &qmldircomponents = data.qmlDirComponents; bool typeWasDeclaredInQmldir = false; - if (!qmldircomponents.isEmpty()) { - foreach (const QQmlDirParser::Component &c, qmldircomponents) { + if (!qmlDirComponents.isEmpty()) { + foreach (const QQmlDirParser::Component &c, qmlDirComponents) { if (c.typeName == type) { typeWasDeclaredInQmldir = true; // importing version -1 means import ALL versions - if ((vmaj == -1) || (c.majorVersion == vmaj && vmin >= c.minorVersion)) { - QString url(data.url + type + QLatin1String(".qml")); - QString candidate = resolveLocalUrl(url, c.fileName); + if ((majversion == -1) || (c.majorVersion == majversion && + minversion >= c.minorVersion)) { + QString candidate = resolveLocalUrl(QString(url + type + QLatin1String(".qml")), + c.fileName); if (c.internal && base) { if (resolveLocalUrl(*base, c.fileName) != candidate) continue; // failed attempt to access an internal type @@ -399,65 +407,205 @@ bool QQmlImportedNamespace::find_helper(QQmlTypeLoader *typeLoader, const Data & } } - if (!typeWasDeclaredInQmldir && !data.isLibrary) { - // XXX search non-files too! (eg. zip files, see QT-524) - QString url(data.url + type + QLatin1String(".qml")); - QString file = QQmlEnginePrivate::urlToLocalFileOrQrc(url); - if (!typeLoader->absoluteFilePath(file).isEmpty()) { - if (base && *base == url) { // no recursion + if (!typeWasDeclaredInQmldir && !isLibrary) { + QString qmlUrl(url + type + QLatin1String(".qml")); + + bool exists = false; + + if (QQmlFile::isBundle(qmlUrl)) { + exists = QQmlFile::bundleFileExists(qmlUrl, typeLoader->engine()); + } else { + QString file = QQmlFile::urlToLocalFileOrQrc(qmlUrl); + exists = !typeLoader->absoluteFilePath(QQmlFile::urlToLocalFileOrQrc(qmlUrl)).isEmpty(); + } + + if (exists) { + if (base && *base == qmlUrl) { // no recursion if (typeRecursionDetected) *typeRecursionDetected = true; } else { if (url_return) - *url_return = url; + *url_return = qmlUrl; return true; } } } + return false; } -QQmlImportsPrivate::QQmlImportsPrivate(QQmlTypeLoader *loader) - : ref(1), typeLoader(loader) +bool QQmlImportsPrivate::resolveType(const QString& type, int *vmajor, int *vminor, + QQmlType** type_return, QString* url_return, + QList<QQmlError> *errors) +{ + QQmlImportNamespace *s = 0; + int slash = type.indexOf(QLatin1Char('/')); + if (slash >= 0) { + QString namespaceName = type.left(slash); + s = set.value(namespaceName); + if (!s) { + if (errors) { + QQmlError error; + error.setDescription(QQmlImportDatabase::tr("- %1 is not a namespace").arg(namespaceName)); + errors->prepend(error); + } + return false; + } + int nslash = type.indexOf(QLatin1Char('/'),slash+1); + if (nslash > 0) { + if (errors) { + QQmlError error; + error.setDescription(QQmlImportDatabase::tr("- nested namespaces not allowed")); + errors->prepend(error); + } + return false; + } + } else { + s = &unqualifiedset; + } + QString unqualifiedtype = slash < 0 ? type : type.mid(slash+1); // common-case opt (QString::mid works fine, but slower) + if (s) { + if (s->resolveType(typeLoader,unqualifiedtype,vmajor,vminor,type_return,url_return, &base, errors)) + return true; + if (s->imports.count() == 1 && !s->imports.at(0).isLibrary && url_return && s != &unqualifiedset) { + // qualified, and only 1 url + *url_return = resolveLocalUrl(s->imports.at(0).url, unqualifiedtype + QLatin1String(".qml")); + return true; + } + } + + return false; +} + +bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QString& type, int *vmajor, + int *vminor, QQmlType** type_return, + QString* url_return, 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, + 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 (errors) { + QString u1 = imports.at(i).url; + QString u2 = imports.at(j).url; + if (base) { + QString b = *base; + int slash = b.lastIndexOf(QLatin1Char('/')); + if (slash >= 0) { + b = b.left(slash+1); + QString l = b.left(slash); + if (u1.startsWith(b)) + u1 = u1.mid(b.count()); + else if (u1 == l) + u1 = QQmlImportDatabase::tr("local directory"); + if (u2.startsWith(b)) + u2 = u2.mid(b.count()); + else if (u2 == l) + u2 = QQmlImportDatabase::tr("local directory"); + } + } + + QQmlError error; + if (u1 != u2) { + error.setDescription(QQmlImportDatabase::tr("is ambiguous. Found in %1 and in %2").arg(u1).arg(u2)); + } else { + error.setDescription(QQmlImportDatabase::tr("is ambiguous. Found in %1 in version %2.%3 and %4.%5") + .arg(u1) + .arg(imports.at(i).majversion).arg(imports.at(i).minversion) + .arg(imports.at(j).majversion).arg(imports.at(j).minversion)); + } + errors->prepend(error); + } + return false; + } + } + } + return true; + } + } + if (errors) { + QQmlError error; + if (typeRecursionDetected) + error.setDescription(QQmlImportDatabase::tr("is instantiated recursively")); + else + error.setDescription(QQmlImportDatabase::tr("is not a type")); + errors->prepend(error); + } + return false; +} + +QQmlImportsPrivate::QQmlImportsPrivate(QQmlTypeLoader *loader) +: ref(1), typeLoader(loader) { } QQmlImportsPrivate::~QQmlImportsPrivate() { - foreach (QQmlImportedNamespace* s, set.values()) + foreach (QQmlImportNamespace* s, set.values()) delete s; } -bool QQmlImportsPrivate::importExtension(const QString &absoluteFilePath, const QString &uri, - QQmlImportDatabase *database, - QQmlDirComponents* components, - QQmlDirScripts* scripts, - QList<QQmlError> *errors) +/*! +Import an extension defined by a qmldir file. + +\a qmldirFilePath is either a raw file path, or a bundle url. + +This call will modify the \a url parameter if importing the extension redirects to +a bundle path. +*/ +bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath, + const QString &uri, + QQmlImportDatabase *database, + QQmlDirComponents* components, + QQmlDirScripts* scripts, + QString *url, + QList<QQmlError> *errors) { - const QQmlDirParser *qmldirParser = typeLoader->qmlDirParser(absoluteFilePath); + // As qmldirFilePath is always local, this method can always return synchronously + const QQmlDirParser *qmldirParser = typeLoader->qmlDirParser(qmldirFilePath, uri, url); if (qmldirParser->hasError()) { if (errors) { + QUrl url; + + if (QQmlFile::isBundle(qmldirFilePath)) + url = QUrl(qmldirFilePath); + else + url = QUrl::fromLocalFile(qmldirFilePath); + const QList<QQmlError> qmldirErrors = qmldirParser->errors(uri); - for (int i = 0; i < qmldirErrors.size(); ++i) - errors->prepend(qmldirErrors.at(i)); + for (int i = 0; i < qmldirErrors.size(); ++i) { + QQmlError error = qmldirErrors.at(i); + error.setUrl(url); + errors->append(error); + } } return false; } if (qmlImportTrace()) qDebug().nospace() << "QQmlImports(" << qPrintable(base) << "::importExtension: " - << "loaded " << absoluteFilePath; + << "loaded " << qmldirFilePath; + + if (!qmlDirFilesForWhichPluginsHaveBeenLoaded.contains(qmldirFilePath)) { + qmlDirFilesForWhichPluginsHaveBeenLoaded.insert(qmldirFilePath); - if (! qmlDirFilesForWhichPluginsHaveBeenLoaded.contains(absoluteFilePath)) { - qmlDirFilesForWhichPluginsHaveBeenLoaded.insert(absoluteFilePath); + QString qmldirPath = qmldirFilePath; - QString qmldirPath = absoluteFilePath; - int slash = absoluteFilePath.lastIndexOf(QLatin1Char('/')); + if (QQmlFile::isBundle(*url)) + qmldirPath = QQmlFile::bundleFileName(*url, typeLoader->engine()); + + int slash = qmldirFilePath.lastIndexOf(QLatin1Char('/')); if (slash > 0) qmldirPath.truncate(slash); - foreach (const QQmlDirParser::Plugin &plugin, qmldirParser->plugins()) { - QString resolvedFilePath = database->resolvePlugin(typeLoader, qmldirPath, plugin.path, plugin.name); + foreach (const QQmlDirParser::Plugin &plugin, qmldirParser->plugins()) { + QString resolvedFilePath = database->resolvePlugin(typeLoader, qmldirPath, + plugin.path, plugin.name); if (!resolvedFilePath.isEmpty()) { if (!database->importPlugin(resolvedFilePath, uri, errors)) { if (errors) { @@ -466,8 +614,8 @@ bool QQmlImportsPrivate::importExtension(const QString &absoluteFilePath, const // The reason is that the lower level may add url and line/column numbering information. QQmlError poppedError = errors->takeFirst(); QQmlError error; - error.setDescription(QQmlImportDatabase::tr("plugin cannot be loaded for module \"%1\": %2").arg(uri).arg(poppedError.description())); - error.setUrl(QUrl::fromLocalFile(absoluteFilePath)); + error.setDescription(tr("plugin cannot be loaded for module \"%1\": %2").arg(uri).arg(poppedError.description())); + error.setUrl(QUrl::fromLocalFile(qmldirFilePath)); errors->prepend(error); } return false; @@ -475,8 +623,8 @@ bool QQmlImportsPrivate::importExtension(const QString &absoluteFilePath, const } else { if (errors) { QQmlError error; - error.setDescription(QQmlImportDatabase::tr("module \"%1\" plugin \"%2\" not found").arg(uri).arg(plugin.name)); - error.setUrl(QUrl::fromLocalFile(absoluteFilePath)); + error.setDescription(tr("module \"%1\" plugin \"%2\" not found").arg(uri).arg(plugin.name)); + error.setUrl(QUrl::fromLocalFile(qmldirFilePath)); errors->prepend(error); } return false; @@ -494,12 +642,16 @@ bool QQmlImportsPrivate::importExtension(const QString &absoluteFilePath, const QString QQmlImportsPrivate::resolvedUri(const QString &dir_arg, QQmlImportDatabase *database) { + struct I { static bool greaterThan(const QString &s1, const QString &s2) { + return s1 > s2; + } }; + QString dir = dir_arg; if (dir.endsWith(QLatin1Char('/')) || dir.endsWith(QLatin1Char('\\'))) dir.chop(1); QStringList paths = database->fileImportPath; - qSort(paths.begin(), paths.end(), greaterThan); // Ensure subdirs preceed their parents. + qSort(paths.begin(), paths.end(), I::greaterThan); // Ensure subdirs preceed their parents. QString stableRelativePath = dir; foreach(const QString &path, paths) { @@ -520,208 +672,285 @@ QString QQmlImportsPrivate::resolvedUri(const QString &dir_arg, QQmlImportDataba } stableRelativePath.replace(QLatin1Char('/'), QLatin1Char('.')); + return stableRelativePath; } -QString QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork, - const QString& uri_arg, const QString& prefix, int vmaj, int vmin, - QQmlScript::Import::Type importType, - QQmlImportDatabase *database, QList<QQmlError> *errors) +/* +Locates the qmldir file for \a uri version \a vmaj.vmin. Returns true if found, +and fills in outQmldirFilePath and outQmldirUrl appropriately. Otherwise returns +false. +*/ +bool QQmlImportsPrivate::locateQmldir(const QString &uri, int vmaj, int vmin, + QQmlImportDatabase *database, + QString *outQmldirFilePath, + QString *outQmldirPathUrl) { - static QLatin1String Slash_qmldir("/qmldir"); - static QLatin1Char Slash('/'); - - QQmlDirComponents qmldircomponents = qmldircomponentsnetwork; - QQmlDirScripts qmldirscripts; - QString uri = uri_arg; - QQmlImportedNamespace *s; - if (prefix.isEmpty()) { - s = &unqualifiedset; - } else { - s = set.value(prefix); - if (!s) - set.insert(prefix,(s=new QQmlImportedNamespace)); + Q_ASSERT(vmaj >= 0 && vmin >= 0); // Versions are always specified for libraries + + // Check cache first + + QQmlImportDatabase::QmldirCache *cacheHead = 0; + { + QQmlImportDatabase::QmldirCache **cachePtr = database->qmldirCache.value(uri); + if (cachePtr) { + cacheHead = *cachePtr; + QQmlImportDatabase::QmldirCache *cache = cacheHead; + while (cache) { + if (cache->versionMajor == vmaj && cache->versionMinor == vmin) { + *outQmldirFilePath = cache->qmldirFilePath; + *outQmldirPathUrl = cache->qmldirPathUrl; + return !cache->qmldirFilePath.isEmpty(); + } + cache = cache->next; + } + } } - QString url = uri; - bool versionFound = false; - if (importType == QQmlScript::Import::Library) { - Q_ASSERT(vmaj >= 0 && vmin >= 0); // Versions are always specified for libraries + static QLatin1Char Slash('/'); + static QLatin1String Slash_qmldir("/qmldir"); - url.replace(QLatin1Char('.'), Slash); - bool found = false; - QString dir; - QString qmldir; + QString url = uri; + url.replace(QLatin1Char('.'), Slash); - // step 1: search for extension with fully encoded version number + // step 0: search for extension with fully encoded version number (eg. MyModule.3.2) + // step 1: search for extension with encoded version major (eg. MyModule.3) + // step 2: search for extension without version number (eg. MyModule) + for (int step = 0; step <= 2; ++step) { foreach (const QString &p, database->fileImportPath) { - dir = p+Slash+url; - - QFileInfo fi(dir+QString(QLatin1String(".%1.%2")).arg(vmaj).arg(vmin)+QLatin1String("/qmldir")); - const QString absoluteFilePath = fi.absoluteFilePath(); + QString dir = p + Slash + url; - if (fi.isFile()) { - found = true; + QString qmldirFile = dir; + if (step == 0) qmldirFile += QString(QLatin1String(".%1.%2")).arg(vmaj).arg(vmin); + else if (step == 1) qmldirFile += QString(QLatin1String(".%1")).arg(vmaj); + qmldirFile += Slash_qmldir; - const QString absolutePath = fi.absolutePath(); + QQmlTypeLoader &typeLoader = QQmlEnginePrivate::get(database->engine)->typeLoader; + QString absoluteFilePath = typeLoader.absoluteFilePath(qmldirFile); + if (!absoluteFilePath.isEmpty()) { + QString absolutePath = absoluteFilePath.left(absoluteFilePath.lastIndexOf(Slash)+1); if (absolutePath.at(0) == QLatin1Char(':')) url = QLatin1String("qrc://") + absolutePath.mid(1); else - url = QUrl::fromLocalFile(fi.absolutePath()).toString(); - uri = resolvedUri(dir, database); - if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, &qmldirscripts, errors)) - return QString(); - break; + url = QUrl::fromLocalFile(absolutePath).toString(); + + QQmlImportDatabase::QmldirCache *cache = new QQmlImportDatabase::QmldirCache; + cache->versionMajor = vmaj; + cache->versionMinor = vmin; + cache->qmldirFilePath = absoluteFilePath; + cache->qmldirPathUrl = url; + cache->next = cacheHead; + database->qmldirCache.insert(uri, cache); + + *outQmldirFilePath = absoluteFilePath; + *outQmldirPathUrl = url; + + return true; } } + } - if (!found) { - // step 2: search for extension with encoded version major - foreach (const QString &p, database->fileImportPath) { - dir = p+Slash+url; - - QFileInfo fi(dir+QString(QLatin1String(".%1")).arg(vmaj)+QLatin1String("/qmldir")); - const QString absoluteFilePath = fi.absoluteFilePath(); - - if (fi.isFile()) { - found = true; - - const QString absolutePath = fi.absolutePath(); - if (absolutePath.at(0) == QLatin1Char(':')) - url = QLatin1String("qrc://") + absolutePath.mid(1); - else - url = QUrl::fromLocalFile(fi.absolutePath()).toString(); - uri = resolvedUri(dir, database); - if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, &qmldirscripts, errors)) - return QString(); - break; - } - } + QQmlImportDatabase::QmldirCache *cache = new QQmlImportDatabase::QmldirCache; + cache->versionMajor = vmaj; + cache->versionMinor = vmin; + cache->next = cacheHead; + database->qmldirCache.insert(uri, cache); + + return false; +} + +bool QQmlImportsPrivate::addImport(const QQmlDirComponents &qmldircomponentsnetwork, + const QString& importedUri, const QString& prefix, + int vmaj, int vmin, QQmlScript::Import::Type importType, + bool isImplicitImport, QQmlImportDatabase *database, + QString *outUrl, QList<QQmlError> *errors) +{ + Q_ASSERT(errors); + Q_ASSERT(importType == QQmlScript::Import::File || importType == QQmlScript::Import::Library); + + static QLatin1String String_qmldir("qmldir"); + static QLatin1String Slash_qmldir("/qmldir"); + static QLatin1Char Slash('/'); + + // The list of components defined by a qmldir file for this import. + QQmlDirComponents qmldircomponents; + // The list of scripts defined by a qmldir file for this import. + QQmlDirScripts qmldirscripts; + // The namespace that this import affects. + QQmlImportNamespace *importSet = 0; + // The uri for this import. For library imports this is the same as importedUri + // specified by the user, but it may be different in the case of file imports. + QString uri; + // The url for the path containing files for this import. + QString url; + + qmldircomponents = qmldircomponentsnetwork; + uri = importedUri; + if (prefix.isEmpty()) { + importSet = &unqualifiedset; + } else { + importSet = set.value(prefix); + if (!importSet) { + importSet = new QQmlImportNamespace; + set.insert(prefix, importSet); } + } + + if (importType == QQmlScript::Import::Library) { + Q_ASSERT(vmaj >= 0 && vmin >= 0); + + QString qmldirFilePath; + + if (locateQmldir(uri, vmaj, vmin, database, &qmldirFilePath, &url)) { + + if (!importExtension(qmldirFilePath, uri, database, &qmldircomponents, + &qmldirscripts, &url, errors)) + return false; - if (!found) { - // step 3: search for extension without version number - - foreach (const QString &p, database->fileImportPath) { - dir = p+Slash+url; - qmldir = dir+Slash_qmldir; - - QString absoluteFilePath = typeLoader->absoluteFilePath(qmldir); - if (!absoluteFilePath.isEmpty()) { - found = true; - QString absolutePath = absoluteFilePath.left(absoluteFilePath.lastIndexOf(Slash)+1); - if (absolutePath.at(0) == QLatin1Char(':')) - url = QLatin1String("qrc://") + absolutePath.mid(1); - else - url = QUrl::fromLocalFile(absolutePath).toString(); - uri = resolvedUri(dir, database); - if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, &qmldirscripts, errors)) - return QString(); - break; - } - } } - if (QQmlMetaType::isModule(uri, vmaj, vmin)) - versionFound = true; + if (!QQmlMetaType::isModule(uri, vmaj, vmin)) { - if (!versionFound && qmldircomponents.isEmpty() && qmldirscripts.isEmpty()) { - if (errors) { - QQmlError error; // we don't set the url or line or column as these will be set by the loader. + if (qmldircomponents.isEmpty() && qmldirscripts.isEmpty()) { + QQmlError error; if (QQmlMetaType::isAnyModule(uri)) - error.setDescription(QQmlImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri_arg).arg(vmaj).arg(vmin)); + error.setDescription(tr("module \"%1\" version %2.%3 is not installed").arg(importedUri).arg(vmaj).arg(vmin)); else - error.setDescription(QQmlImportDatabase::tr("module \"%1\" is not installed").arg(uri_arg)); + error.setDescription(tr("module \"%1\" is not installed").arg(importedUri)); errors->prepend(error); + return false; + } else { + int lowest_min = INT_MAX; + int highest_min = INT_MIN; + typedef QList<QQmlDirParser::Component>::const_iterator ConstIterator; + typedef QList<QQmlDirParser::Script>::const_iterator SConstIterator; + + for (ConstIterator cit = qmldircomponents.constBegin(); + cit != qmldircomponents.constEnd(); ++cit) { + if (cit->majorVersion == vmaj) { + lowest_min = qMin(lowest_min, cit->minorVersion); + highest_min = qMax(highest_min, cit->minorVersion); + } + } + + for (SConstIterator cit = qmldirscripts.constBegin(); + cit != qmldirscripts.constEnd(); ++cit) { + if (cit->majorVersion == vmaj) { + lowest_min = qMin(lowest_min, cit->minorVersion); + highest_min = qMax(highest_min, cit->minorVersion); + } + } + + if (lowest_min > vmin || highest_min < vmin) { + QQmlError error; + error.setDescription(tr("module \"%1\" version %2.%3 is not installed").arg(importedUri).arg(vmaj).arg(vmin)); + errors->prepend(error); + return false; + } } - return QString(); + } } else { - if (importType == QQmlScript::Import::File && qmldircomponents.isEmpty()) { - QString importUrl = resolveLocalUrl(base, uri + Slash_qmldir); - QString localFileOrQrc = QQmlEnginePrivate::urlToLocalFileOrQrc(importUrl); - if (!localFileOrQrc.isEmpty()) { - QString dir = QQmlEnginePrivate::urlToLocalFileOrQrc(resolveLocalUrl(base, uri)); - if (!typeLoader->directoryExists(dir)) { - if (errors) { - QQmlError error; // we don't set the line or column as these will be set by the loader. - error.setDescription(QQmlImportDatabase::tr("\"%1\": no such directory").arg(uri_arg)); - error.setUrl(QUrl(importUrl)); + + Q_ASSERT(importType == QQmlScript::Import::File); + + if (qmldircomponents.isEmpty()) { + + QString qmldirPath = uri; + if (uri.endsWith(Slash)) qmldirPath += String_qmldir; + else qmldirPath += Slash_qmldir; + QString qmldirUrl = resolveLocalUrl(base, qmldirPath); + + if (QQmlFile::isBundle(qmldirUrl)) { + + QString dir = resolveLocalUrl(base, uri); + Q_ASSERT(QQmlFile::isBundle(dir)); + if (!QQmlFile::bundleDirectoryExists(dir, typeLoader->engine())) { + if (!isImplicitImport) { + QQmlError error; + error.setDescription(tr("\"%1\": no such directory").arg(importedUri)); + error.setUrl(QUrl(qmldirUrl)); errors->prepend(error); } - return QString(); // local import dirs must exist + return false; } + + // Transforms the (possible relative) uri into our best guess relative to the + // import paths. uri = resolvedUri(dir, database); + if (uri.endsWith(Slash)) uri.chop(1); - if (!typeLoader->absoluteFilePath(localFileOrQrc).isEmpty()) { - if (!importExtension(localFileOrQrc,uri,database,&qmldircomponents,&qmldirscripts,errors)) - return QString(); + if (QQmlFile::bundleFileExists(qmldirUrl, typeLoader->engine())) { + if (!importExtension(qmldirUrl, uri, database, &qmldircomponents, + &qmldirscripts, &url, errors)) + return false; } - } else { - if (prefix.isEmpty()) { - // directory must at least exist for valid import - QString localFileOrQrc = QQmlEnginePrivate::urlToLocalFileOrQrc(resolveLocalUrl(base, uri)); - if (!typeLoader->directoryExists(localFileOrQrc)) { - if (errors) { - QQmlError error; // we don't set the line or column as these will be set by the loader. - if (localFileOrQrc.isEmpty()) - error.setDescription(QQmlImportDatabase::tr("import \"%1\" has no qmldir and no namespace").arg(uri)); - else - error.setDescription(QQmlImportDatabase::tr("\"%1\": no such directory").arg(uri)); - error.setUrl(QUrl(importUrl)); - errors->prepend(error); - } - return QString(); + + } else if (QQmlFile::isLocalFile(qmldirUrl)) { + + QString localFileOrQrc = QQmlFile::urlToLocalFileOrQrc(qmldirUrl); + Q_ASSERT(!localFileOrQrc.isEmpty()); + + QString dir = QQmlFile::urlToLocalFileOrQrc(resolveLocalUrl(base, uri)); + if (!typeLoader->directoryExists(dir)) { + if (!isImplicitImport) { + QQmlError error; + error.setDescription(tr("\"%1\": no such directory").arg(importedUri)); + error.setUrl(QUrl(qmldirUrl)); + errors->prepend(error); } + return false; } - } - } - url = resolveLocalUrl(base, url); - } + // Transforms the (possible relative) uri into our best guess relative to the + // import paths. + uri = resolvedUri(dir, database); + + if (uri.endsWith(Slash)) + uri.chop(1); + if (!typeLoader->absoluteFilePath(localFileOrQrc).isEmpty()) { + if (!importExtension(localFileOrQrc, uri, database, &qmldircomponents, + &qmldirscripts, &url, errors)) + return false; + } - if (!versionFound && (vmaj > -1) && (vmin > -1) && !qmldircomponents.isEmpty()) { - int lowest_min = INT_MAX; - int highest_min = INT_MIN; + } else if (prefix.isEmpty()) { - QList<QQmlDirParser::Component>::const_iterator cend = qmldircomponents.constEnd(); - for (QList<QQmlDirParser::Component>::const_iterator cit = qmldircomponents.constBegin(); cit != cend; ++cit) { - if (cit->majorVersion == vmaj) { - lowest_min = qMin(lowest_min, cit->minorVersion); - highest_min = qMax(highest_min, cit->minorVersion); - } - } + if (!isImplicitImport) { + QQmlError error; + error.setDescription(tr("import \"%1\" has no qmldir and no namespace").arg(uri)); + error.setUrl(QUrl(qmldirUrl)); + errors->prepend(error); + } + + return false; - if (lowest_min > vmin || highest_min < vmin) { - if (errors) { - QQmlError error; // we don't set the url or line or column information, as these will be set by the loader. - error.setDescription(QQmlImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri_arg).arg(vmaj).arg(vmin)); - errors->prepend(error); } - return QString(); } + + url = resolveLocalUrl(base, importedUri); + if (!url.endsWith(Slash)) + url += Slash; } - if (!url.endsWith(Slash)) - url += Slash; + Q_ASSERT(url.isEmpty() || url.endsWith(Slash)); QMap<QString, QQmlDirParser::Script> scripts; - if (!qmldirscripts.isEmpty()) { // Verify that we haven't imported these scripts already - QList<QQmlImportedNamespace::Data>::const_iterator end = s->imports.constEnd(); - for (QList<QQmlImportedNamespace::Data>::const_iterator it = s->imports.constBegin(); it != end; ++it) { + for (QList<QQmlImportNamespace::Import>::const_iterator it = importSet->imports.constBegin(); + it != importSet->imports.constEnd(); ++it) { if (it->uri == uri) { QQmlError error; - error.setDescription(QQmlImportDatabase::tr("\"%1\" is ambiguous. Found in %2 and in %3").arg(uri).arg(url).arg(it->url)); + error.setDescription(tr("\"%1\" is ambiguous. Found in %2 and in %3").arg(uri).arg(url).arg(it->url)); errors->prepend(error); - return QString(); + return false; } } - QList<QQmlDirParser::Script>::const_iterator send = qmldirscripts.constEnd(); - for (QList<QQmlDirParser::Script>::const_iterator sit = qmldirscripts.constBegin(); sit != send; ++sit) { + for (QList<QQmlDirParser::Script>::const_iterator sit = qmldirscripts.constBegin(); + sit != qmldirscripts.constEnd(); ++sit) { // Only include scripts that match our requested version if (((vmaj == -1) || (sit->majorVersion == vmaj)) && ((vmin == -1) || (sit->minorVersion <= vmin))) { @@ -735,124 +964,80 @@ QString QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork } } - QQmlImportedNamespace::Data data; - data.uri = uri; - data.url = url; - data.majversion = vmaj; - data.minversion = vmin; - data.isLibrary = importType == QQmlScript::Import::Library; - data.qmlDirComponents = qmldircomponents; - data.qmlDirScripts = scripts.values(); + QQmlImportNamespace::Import import; + import.uri = uri; + import.url = url; + import.majversion = vmaj; + import.minversion = vmin; + import.isLibrary = importType == QQmlScript::Import::Library; + import.qmlDirComponents = qmldircomponents; + import.qmlDirScripts = scripts.values(); + + importSet->imports.prepend(import); - s->imports.prepend(data); + if (outUrl) *outUrl = url; - return data.url; + return true; } -bool QQmlImportsPrivate::find(const QString& type, int *vmajor, int *vminor, QQmlType** type_return, - QString* url_return, QList<QQmlError> *errors) +/*! + \internal + + Adds an implicit "." file import. This is equivalent to calling addImport(), but error + messages related to the path or qmldir file not existing are suppressed. +*/ +bool QQmlImports::addImplicitImport(QQmlImportDatabase *importDb, + const QQmlDirComponents &qmldircomponentsnetwork, + QList<QQmlError> *errors) { - QQmlImportedNamespace *s = 0; - int slash = type.indexOf(QLatin1Char('/')); - if (slash >= 0) { - QString namespaceName = type.left(slash); - s = set.value(namespaceName); - if (!s) { - if (errors) { - QQmlError error; - error.setDescription(QQmlImportDatabase::tr("- %1 is not a namespace").arg(namespaceName)); - errors->prepend(error); - } - return false; - } - int nslash = type.indexOf(QLatin1Char('/'),slash+1); - if (nslash > 0) { - if (errors) { - QQmlError error; - error.setDescription(QQmlImportDatabase::tr("- nested namespaces not allowed")); - errors->prepend(error); - } - return false; - } - } else { - s = &unqualifiedset; - } - QString unqualifiedtype = slash < 0 ? type : type.mid(slash+1); // common-case opt (QString::mid works fine, but slower) - if (s) { - if (s->find(typeLoader,unqualifiedtype,vmajor,vminor,type_return,url_return, &base, errors)) - return true; - if (s->imports.count() == 1 && !s->imports.at(0).isLibrary && url_return && s != &unqualifiedset) { - // qualified, and only 1 url - *url_return = resolveLocalUrl(s->imports.at(0).url, unqualifiedtype + QLatin1String(".qml")); - return true; - } - } + Q_ASSERT(errors); - return false; -} + if (qmlImportTrace()) + qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) + << ")::addImplicitImport"; -QQmlImportedNamespace *QQmlImportsPrivate::findNamespace(const QString& type) -{ - return set.value(type); + + return d->addImport(qmldircomponentsnetwork, QLatin1String("."), QString(), -1, -1, + QQmlScript::Import::File, true, importDb, 0, errors); } -bool QQmlImportedNamespace::find(QQmlTypeLoader *typeLoader, const QString& type, int *vmajor, int *vminor, QQmlType** type_return, - QString* url_return, QString *base, QList<QQmlError> *errors) +/*! + \internal + + Adds information to \a imports such that subsequent calls to resolveType() + will resolve types qualified by \a prefix by considering types found at the given \a uri. + + The uri is either a directory (if importType is FileImport), or a URI resolved using paths + added via addImportPath() (if importType is LibraryImport). + + The \a prefix may be empty, in which case the import location is considered for + unqualified types. + + The base URL must already have been set with Import::setBaseUrl(). + + Optionally, the url the import resolved to can be returned by providing the url parameter. + Not all imports will result in an output url being generated, in which case the url will + be set to an empty string. + + Returns true on success, and false on failure. In case of failure, the errors array will + filled appropriately. +*/ +bool QQmlImports::addImport(QQmlImportDatabase *importDb, + const QString& uri, const QString& prefix, int vmaj, int vmin, + QQmlScript::Import::Type importType, + const QQmlDirComponents &qmldircomponentsnetwork, + QString *url, QList<QQmlError> *errors) { - bool typeRecursionDetected = false; - for (int i=0; i<imports.count(); ++i) { - if (find_helper(typeLoader, imports.at(i), type, vmajor, vminor, type_return, url_return, base, &typeRecursionDetected)) { - if (qmlCheckTypes()) { - // check for type clashes - for (int j = i+1; j<imports.count(); ++j) { - if (find_helper(typeLoader, imports.at(j), type, vmajor, vminor, 0, 0, base)) { - if (errors) { - QString u1 = imports.at(i).url; - QString u2 = imports.at(j).url; - if (base) { - QString b = *base; - int slash = b.lastIndexOf(QLatin1Char('/')); - if (slash >= 0) { - b = b.left(slash+1); - QString l = b.left(slash); - if (u1.startsWith(b)) - u1 = u1.mid(b.count()); - else if (u1 == l) - u1 = QQmlImportDatabase::tr("local directory"); - if (u2.startsWith(b)) - u2 = u2.mid(b.count()); - else if (u2 == l) - u2 = QQmlImportDatabase::tr("local directory"); - } - } + Q_ASSERT(errors); - QQmlError error; - if (u1 != u2) { - error.setDescription(QQmlImportDatabase::tr("is ambiguous. Found in %1 and in %2").arg(u1).arg(u2)); - } else { - error.setDescription(QQmlImportDatabase::tr("is ambiguous. Found in %1 in version %2.%3 and %4.%5") - .arg(u1) - .arg(imports.at(i).majversion).arg(imports.at(i).minversion) - .arg(imports.at(j).majversion).arg(imports.at(j).minversion)); - } - errors->prepend(error); - } - return false; - } - } - } - return true; - } - } - if (errors) { - QQmlError error; - if (typeRecursionDetected) - error.setDescription(QQmlImportDatabase::tr("is instantiated recursively")); - else - error.setDescription(QQmlImportDatabase::tr("is not a type")); - errors->prepend(error); - } - return false; + if (qmlImportTrace()) + qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) << ")" << "::addImport: " + << uri << " " << vmaj << '.' << vmin << " " + << (importType==QQmlScript::Import::Library? "Library" : "File") + << " as " << prefix; + + return d->addImport(qmldircomponentsnetwork, uri, prefix, vmaj, vmin, importType, false, + importDb, url, errors); } /*! @@ -890,37 +1075,16 @@ QQmlImportDatabase::QQmlImportDatabase(QQmlEngine *e) QQmlImportDatabase::~QQmlImportDatabase() { -} - -/*! - \internal - - Adds information to \a imports such that subsequent calls to resolveType() - will resolve types qualified by \a prefix by considering types found at the given \a uri. - - The uri is either a directory (if importType is FileImport), or a URI resolved using paths - added via addImportPath() (if importType is LibraryImport). - - The \a prefix may be empty, in which case the import location is considered for - unqualified types. - - Returns the resolved URL of the import on success. - - The base URL must already have been set with Import::setBaseUrl(). -*/ -QString QQmlImports::addImport(QQmlImportDatabase *importDb, - const QString& uri, const QString& prefix, int vmaj, int vmin, - QQmlScript::Import::Type importType, - const QQmlDirComponents &qmldircomponentsnetwork, - QList<QQmlError> *errors) -{ - if (qmlImportTrace()) - qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) << ")" << "::addImport: " - << uri << " " << vmaj << '.' << vmin << " " - << (importType==QQmlScript::Import::Library? "Library" : "File") - << " as " << prefix; - - return d->add(qmldircomponentsnetwork, uri, prefix, vmaj, vmin, importType, importDb, errors); + for (QStringHash<QmldirCache *>::ConstIterator iter = qmldirCache.begin(); + iter != qmldirCache.end(); ++iter) { + + QmldirCache *c = *iter; + while (c) { + QmldirCache *n = c->next; + delete c; + c = n; + } + } } /*! @@ -932,9 +1096,10 @@ QString QQmlImports::addImport(QQmlImportDatabase *importDb, \a qmldirPath is the location of the qmldir file. */ QString QQmlImportDatabase::resolvePlugin(QQmlTypeLoader *typeLoader, - const QString &qmldirPath, const QString &qmldirPluginPath, - const QString &baseName, const QStringList &suffixes, - const QString &prefix) + const QString &qmldirPath, + const QString &qmldirPluginPath, + const QString &baseName, const QStringList &suffixes, + const QString &prefix) { QStringList searchPaths = filePluginPath; bool qmldirPluginPathIsRelative = QDir::isRelativePath(qmldirPluginPath); |