aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqmlimport.cpp
diff options
context:
space:
mode:
authorAaron Kennedy <aaron.kennedy@nokia.com>2012-04-10 18:11:30 +0100
committerQt by Nokia <qt-info@nokia.com>2012-05-04 13:15:01 +0200
commit6f3bda0dce945a5fc75d8ebad302820fe9979d9b (patch)
tree6581aad8a7fb21ccbebe09d23c30af0e3236e266 /src/qml/qml/qqmlimport.cpp
parent44f9412bf789d73dd462292038686f5b07026132 (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.cpp969
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);