aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqmlimport.cpp
diff options
context:
space:
mode:
authorMatthew Vogt <matthew.vogt@nokia.com>2012-06-29 12:25:20 +1000
committerQt by Nokia <qt-info@nokia.com>2012-07-16 04:46:50 +0200
commit432a48b8f2d9ebaef1bd7be4a168a45524faaf68 (patch)
treede7ff211c9e1b3b2bd0156b464bacbfbea475a1d /src/qml/qml/qqmlimport.cpp
parent9bc216f6fa34484bf582cbc3ccd2bb7b45826bc7 (diff)
Support remote import paths
Probe for installed modules in import path elements which are not local to the machine. Note that all local paths in the import path list will be tried before any remote locations are probed. Task-number: QTBUG-21386 Change-Id: I4f7b9e54e54c1d62a5e7cb7f059ee1e9319ef054 Reviewed-by: Chris Adams <christopher.adams@nokia.com>
Diffstat (limited to 'src/qml/qml/qqmlimport.cpp')
-rw-r--r--src/qml/qml/qqmlimport.cpp929
1 files changed, 578 insertions, 351 deletions
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 5ea45f283f..937d2df3c1 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -58,19 +58,27 @@ QT_BEGIN_NAMESPACE
DEFINE_BOOL_CONFIG_OPTION(qmlImportTrace, QML_IMPORT_TRACE)
DEFINE_BOOL_CONFIG_OPTION(qmlCheckTypes, QML_CHECK_TYPES)
-static QString dotqml_string(QLatin1String(".qml"));
+static const QLatin1Char Dot('.');
+static const QLatin1Char Slash('/');
+static const QLatin1Char Backslash('\\');
+static const QLatin1Char Colon(':');
+static const QLatin1String Slash_qmldir("/qmldir");
+static const QLatin1String String_qmldir("qmldir");
+static const QString dotqml_string(QLatin1String(".qml"));
+
+namespace {
QString resolveLocalUrl(const QString &url, const QString &relative)
{
- if (relative.contains(QLatin1Char(':'))) {
+ if (relative.contains(Colon)) {
// contains a host name
return QUrl(url).resolved(QUrl(relative)).toString();
} else if (relative.isEmpty()) {
return url;
- } else if (relative.at(0) == QLatin1Char('/') || !url.contains(QLatin1Char('/'))) {
+ } else if (relative.at(0) == Slash || !url.contains(Slash)) {
return relative;
} else {
- QString base(url.left(url.lastIndexOf(QLatin1Char('/')) + 1));
+ QString base(url.left(url.lastIndexOf(Slash) + 1));
if (relative == QLatin1String("."))
return base;
@@ -78,16 +86,13 @@ QString resolveLocalUrl(const QString &url, const QString &relative)
base.append(relative);
// Remove any relative directory elements in the path
- const QLatin1Char dot('.');
- const QLatin1Char slash('/');
-
int length = base.length();
int index = 0;
while ((index = base.indexOf(QLatin1String("/."), index)) != -1) {
- if ((length > (index + 2)) && (base.at(index + 2) == dot) &&
- (length == (index + 3) || (base.at(index + 3) == slash))) {
+ if ((length > (index + 2)) && (base.at(index + 2) == Dot) &&
+ (length == (index + 3) || (base.at(index + 3) == Slash))) {
// Either "/../" or "/..<END>"
- int previous = base.lastIndexOf(slash, index - 1);
+ int previous = base.lastIndexOf(Slash, index - 1);
if (previous == -1)
break;
@@ -95,7 +100,7 @@ QString resolveLocalUrl(const QString &url, const QString &relative)
base.remove(previous + 1, removeLength);
length -= removeLength;
index = previous;
- } else if ((length == (index + 2)) || (base.at(index + 2) == slash)) {
+ } else if ((length == (index + 2)) || (base.at(index + 2) == Slash)) {
// Either "/./" or "/.<END>"
base.remove(index, 2);
length -= 2;
@@ -108,6 +113,18 @@ QString resolveLocalUrl(const QString &url, const QString &relative)
}
}
+bool isPathAbsolute(const QString &path)
+{
+#if defined(Q_OS_UNIX)
+ return (path.at(0) == Slash);
+#else
+ QFileInfo fi(path);
+ return fi.isAbsolute();
+#endif
+}
+
+}
+
typedef QMap<QString, QString> StringStringMap;
Q_GLOBAL_STATIC(StringStringMap, qmlEnginePluginsWithRegisteredTypes); // stores the uri
@@ -115,6 +132,7 @@ class QQmlImportNamespace
{
public:
QQmlImportNamespace() : nextNamespace(0) {}
+ ~QQmlImportNamespace() { qDeleteAll(imports); }
struct Import {
QString uri;
@@ -125,12 +143,19 @@ public:
QQmlDirComponents qmlDirComponents;
QQmlDirScripts qmlDirScripts;
+ bool setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoader::QmldirContent *qmldir,
+ QQmlImportNamespace *nameSpace, QList<QQmlError> *errors);
+
+ static QQmlDirScripts getVersionedScripts(const QQmlDirScripts &qmldirscripts, int vmaj, int vmin);
+
bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &type,
int *vmajor, int *vminor,
QQmlType** type_return, QString* url_return,
QString *base = 0, bool *typeRecursionDetected = 0) const;
};
- QList<Import> imports;
+ QList<Import *> imports;
+
+ Import *findImport(const QString &uri);
bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef& type,
int *vmajor, int *vminor,
@@ -150,11 +175,22 @@ public:
QQmlImportsPrivate(QQmlTypeLoader *loader);
~QQmlImportsPrivate();
- 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);
+ QQmlImportNamespace *importNamespace(const QString &prefix) const;
+
+ bool addLibraryImport(const QString& uri, const QString &prefix,
+ int vmaj, int vmin, const QString &qmldirIdentifier, const QString &qmldirUrl, bool incomplete,
+ QQmlImportDatabase *database,
+ QList<QQmlError> *errors);
+
+ bool addFileImport(const QString &uri, const QString &prefix,
+ int vmaj, int vmin,
+ bool isImplicitImport, bool incomplete, QQmlImportDatabase *database,
+ QList<QQmlError> *errors);
+
+ bool updateQmldirContent(const QString &uri, const QString &prefix,
+ const QString &qmldirIdentifier, const QString& qmldirUrl,
+ QQmlImportDatabase *database,
+ QList<QQmlError> *errors);
bool resolveType(const QHashedStringRef &type, int *vmajor, int *vminor,
QQmlType** type_return, QString* url_return,
@@ -164,10 +200,10 @@ public:
QString base;
int ref;
- QQmlImportNamespace unqualifiedset;
+ mutable QQmlImportNamespace unqualifiedset;
- QQmlImportNamespace *findQualifiedNamespace(const QHashedStringRef &);
- QFieldList<QQmlImportNamespace, &QQmlImportNamespace::nextNamespace> qualifiedSets;
+ QQmlImportNamespace *findQualifiedNamespace(const QHashedStringRef &) const;
+ mutable QFieldList<QQmlImportNamespace, &QQmlImportNamespace::nextNamespace> qualifiedSets;
QQmlTypeLoader *typeLoader;
@@ -175,15 +211,27 @@ public:
return QQmlImportDatabase::tr(str);
}
-private:
static bool locateQmldir(const QString &uri, int vmaj, int vmin,
QQmlImportDatabase *database,
QString *outQmldirFilePath, QString *outUrl);
+
+ static bool validateQmldirVersion(const QQmlTypeLoader::QmldirContent *qmldir, const QString &uri, int vmaj, int vmin,
+ QList<QQmlError> *errors);
+
bool importExtension(const QString &absoluteFilePath, const QString &uri,
- QQmlImportDatabase *database, QQmlDirComponents* components,
- QQmlDirScripts *scripts,
- QString *url, QList<QQmlError> *errors);
+ QQmlImportDatabase *database,
+ const QQmlTypeLoader::QmldirContent *qmldir,
+ QList<QQmlError> *errors);
+
+ bool getQmldirContent(const QString &qmldirIdentifier, const QString &uri,
+ const QQmlTypeLoader::QmldirContent **qmldir, QList<QQmlError> *errors);
+
QString resolvedUri(const QString &dir_arg, QQmlImportDatabase *database);
+
+ QQmlImportNamespace::Import *addImportToNamespace(QQmlImportNamespace *nameSpace,
+ const QString &uri, const QString &url,
+ int vmaj, int vmin, QQmlScript::Import::Type type,
+ QList<QQmlError> *errors);
};
/*!
@@ -246,10 +294,10 @@ void QQmlImports::populateCache(QQmlTypeNameCache *cache, QQmlEngine *engine) co
const QQmlImportNamespace &set = d->unqualifiedset;
for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
- const QQmlImportNamespace::Import &import = set.imports.at(ii);
- QQmlTypeModule *module = QQmlMetaType::typeModule(import.uri, import.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, import.minversion));
+ cache->m_anonymousImports.append(QQmlTypeModuleVersion(module, import->minversion));
}
for (QQmlImportNamespace *ns = d->qualifiedSets.first(); ns; ns = d->qualifiedSets.next(ns)) {
@@ -257,15 +305,15 @@ void QQmlImports::populateCache(QQmlTypeNameCache *cache, QQmlEngine *engine) co
const QQmlImportNamespace &set = *ns;
for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
- const QQmlImportNamespace::Import &import = set.imports.at(ii);
- QQmlTypeModule *module = QQmlMetaType::typeModule(import.uri, import.majversion);
+ const QQmlImportNamespace::Import *import = set.imports.at(ii);
+ QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->majversion);
if (module) {
QQmlTypeNameCache::Import &typeimport = cache->m_namedImports[set.prefix];
- typeimport.modules.append(QQmlTypeModuleVersion(module, import.minversion));
+ typeimport.modules.append(QQmlTypeModuleVersion(module, import->minversion));
}
- QQmlMetaType::ModuleApi moduleApi = QQmlMetaType::moduleApi(import.uri, import.majversion,
- import.minversion);
+ QQmlMetaType::ModuleApi moduleApi = QQmlMetaType::moduleApi(import->uri, import->majversion,
+ import->minversion);
if (moduleApi.script || moduleApi.qobject) {
QQmlTypeNameCache::Import &import = cache->m_namedImports[set.prefix];
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
@@ -282,12 +330,12 @@ QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const
const QQmlImportNamespace &set = d->unqualifiedset;
for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
- const QQmlImportNamespace::Import &import = set.imports.at(ii);
+ const QQmlImportNamespace::Import *import = set.imports.at(ii);
- foreach (const QQmlDirParser::Script &script, import.qmlDirScripts) {
+ foreach (const QQmlDirParser::Script &script, import->qmlDirScripts) {
ScriptReference ref;
ref.nameSpace = script.nameSpace;
- ref.location = QUrl(import.url).resolved(QUrl(script.fileName));
+ ref.location = QUrl(import->url).resolved(QUrl(script.fileName));
scripts.append(ref);
}
}
@@ -296,13 +344,13 @@ QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const
const QQmlImportNamespace &set = *ns;
for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
- const QQmlImportNamespace::Import &import = set.imports.at(ii);
+ const QQmlImportNamespace::Import *import = set.imports.at(ii);
- foreach (const QQmlDirParser::Script &script, import.qmlDirScripts) {
+ foreach (const QQmlDirParser::Script &script, import->qmlDirScripts) {
ScriptReference ref;
ref.nameSpace = script.nameSpace;
ref.qualifier = set.prefix;
- ref.location = QUrl(import.url).resolved(QUrl(script.fileName));
+ ref.location = QUrl(import->url).resolved(QUrl(script.fileName));
scripts.append(ref);
}
}
@@ -312,6 +360,31 @@ QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const
}
/*!
+ Form a complete path to a qmldir file, from a base URL, a module URI and version specification.
+*/
+QString QQmlImports::completeQmldirPath(const QString &uri, const QString &base, int vmaj, int vmin,
+ ImportVersion version)
+{
+ QString url = uri;
+ url.replace(Dot, Slash);
+
+ QString dir = base;
+ if (!dir.endsWith(Slash) && !dir.endsWith(Backslash))
+ dir += Slash;
+ dir += url;
+
+ if (version == QQmlImports::FullyVersioned) {
+ // extension with fully encoded version number (eg. MyModule.3.2)
+ dir += QString(QLatin1String(".%1.%2")).arg(vmaj).arg(vmin);
+ } else if (version == QQmlImports::PartiallyVersioned) {
+ // extension with encoded version major (eg. MyModule.3)
+ dir += QString(QLatin1String(".%1")).arg(vmaj);
+ } // else extension without version number (eg. MyModule)
+
+ return dir + Slash_qmldir;
+}
+
+/*!
\internal
The given (namespace qualified) \a type is resolved to either
@@ -323,7 +396,7 @@ QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const
If any return pointer is 0, the corresponding search is not done.
- \sa addImport()
+ \sa addFileImport(), addLibraryImport
*/
bool QQmlImports::resolveType(const QHashedStringRef &type,
QQmlType** type_return, QString* url_return, int *vmaj, int *vmin,
@@ -342,11 +415,11 @@ bool QQmlImports::resolveType(const QHashedStringRef &type,
<< ')' << "::resolveType: " << type.toString() << " => "
if (type_return && *type_return && url_return && !url_return->isEmpty())
- RESOLVE_TYPE_DEBUG << (*type_return)->typeName() << ' ' << *url_return;
+ RESOLVE_TYPE_DEBUG << (*type_return)->typeName() << ' ' << *url_return << " TYPE/URL";
if (type_return && *type_return)
- RESOLVE_TYPE_DEBUG << (*type_return)->typeName();
+ RESOLVE_TYPE_DEBUG << (*type_return)->typeName() << " TYPE";
if (url_return && !url_return->isEmpty())
- RESOLVE_TYPE_DEBUG << *url_return;
+ RESOLVE_TYPE_DEBUG << *url_return << " URL";
#undef RESOLVE_TYPE_DEBUG
}
@@ -356,6 +429,52 @@ bool QQmlImports::resolveType(const QHashedStringRef &type,
return false;
}
+bool QQmlImportNamespace::Import::setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoader::QmldirContent *qmldir, QQmlImportNamespace *nameSpace, QList<QQmlError> *errors)
+{
+ Q_ASSERT(resolvedUrl.endsWith(Slash));
+ url = resolvedUrl;
+
+ qmlDirComponents = qmldir->components();
+
+ const QQmlDirScripts &scripts = qmldir->scripts();
+ if (!scripts.isEmpty()) {
+ // Verify that we haven't imported these scripts already
+ for (QList<QQmlImportNamespace::Import *>::const_iterator it = nameSpace->imports.constBegin();
+ it != nameSpace->imports.constEnd(); ++it) {
+ if ((*it != this) && ((*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));
+ errors->prepend(error);
+ return false;
+ }
+ }
+
+ qmlDirScripts = getVersionedScripts(scripts, majversion, minversion);
+ }
+
+ return true;
+}
+
+QQmlDirScripts QQmlImportNamespace::Import::getVersionedScripts(const QQmlDirScripts &qmldirscripts, int vmaj, int vmin)
+{
+ QMap<QString, QQmlDirParser::Script> versioned;
+
+ 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))) {
+ // Load the highest version that matches
+ QMap<QString, QQmlDirParser::Script>::iterator vit = versioned.find(sit->nameSpace);
+ if (vit == versioned.end() || (vit->minorVersion < sit->minorVersion)) {
+ versioned.insert(sit->nameSpace, *sit);
+ }
+ }
+ }
+
+ return versioned.values();
+}
+
/*!
\internal
@@ -454,7 +573,7 @@ bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor,
QList<QQmlError> *errors)
{
QQmlImportNamespace *s = 0;
- int dot = type.indexOf(QLatin1Char('.'));
+ int dot = type.indexOf(Dot);
if (dot >= 0) {
QHashedStringRef namespaceName(type.constData(), dot);
s = findQualifiedNamespace(namespaceName);
@@ -466,7 +585,7 @@ bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor,
}
return false;
}
- int ndot = type.indexOf(QLatin1Char('.'),dot+1);
+ int ndot = type.indexOf(Dot,dot+1);
if (ndot > 0) {
if (errors) {
QQmlError error;
@@ -482,9 +601,9 @@ bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor,
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) {
+ 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.toString() + QLatin1String(".qml"));
+ *url_return = resolveLocalUrl(s->imports.at(0)->url, unqualifiedtype.toString() + QLatin1String(".qml"));
return true;
}
}
@@ -492,26 +611,36 @@ bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor,
return false;
}
+QQmlImportNamespace::Import *QQmlImportNamespace::findImport(const QString &uri)
+{
+ for (QList<Import *>::iterator it = imports.begin(), end = imports.end(); it != end; ++it) {
+ if ((*it)->uri == uri)
+ return *it;
+ }
+
+ return 0;
+}
+
bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &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,
+ 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)) {
+ 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;
+ QString u1 = import->url;
+ QString u2 = import2->url;
if (base) {
QString b = *base;
- int dot = b.lastIndexOf(QLatin1Char('.'));
+ int dot = b.lastIndexOf(Dot);
if (dot >= 0) {
b = b.left(dot+1);
QString l = b.left(dot);
@@ -532,8 +661,8 @@ bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedS
} 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));
+ .arg(import->majversion).arg(import->minversion)
+ .arg(import2->majversion).arg(import2->minversion));
}
errors->prepend(error);
}
@@ -565,7 +694,7 @@ QQmlImportsPrivate::~QQmlImportsPrivate()
delete ns;
}
-QQmlImportNamespace *QQmlImportsPrivate::findQualifiedNamespace(const QHashedStringRef &prefix)
+QQmlImportNamespace *QQmlImportsPrivate::findQualifiedNamespace(const QHashedStringRef &prefix) const
{
for (QQmlImportNamespace *ns = qualifiedSets.first(); ns; ns = qualifiedSets.next(ns)) {
if (prefix == ns->prefix)
@@ -578,55 +707,28 @@ QQmlImportNamespace *QQmlImportsPrivate::findQualifiedNamespace(const QHashedStr
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,
+ const QQmlTypeLoader::QmldirContent *qmldir,
QList<QQmlError> *errors)
{
- // 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) {
- QQmlError error = qmldirErrors.at(i);
- error.setUrl(url);
- errors->append(error);
- }
- }
- return false;
- }
+ Q_ASSERT(qmldir);
if (qmlImportTrace())
- qDebug().nospace() << "QQmlImports(" << qPrintable(base) << "::importExtension: "
+ qDebug().nospace() << "QQmlImports(" << qPrintable(base) << ")::importExtension: "
<< "loaded " << qmldirFilePath;
if (!database->qmlDirFilesForWhichPluginsHaveBeenLoaded.contains(qmldirFilePath)) {
QString qmldirPath = qmldirFilePath;
- if (QQmlFile::isBundle(*url))
- qmldirPath = QQmlFile::bundleFileName(*url, typeLoader->engine());
-
- int slash = qmldirFilePath.lastIndexOf(QLatin1Char('/'));
+ int slash = qmldirPath.lastIndexOf(Slash);
if (slash > 0)
qmldirPath.truncate(slash);
- foreach (const QQmlDirParser::Plugin &plugin, qmldirParser->plugins()) {
+ foreach (const QQmlDirParser::Plugin &plugin, qmldir->plugins()) {
QString resolvedFilePath = database->resolvePlugin(typeLoader, qmldirPath,
plugin.path, plugin.name);
if (!resolvedFilePath.isEmpty()) {
@@ -657,10 +759,35 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
database->qmlDirFilesForWhichPluginsHaveBeenLoaded.insert(qmldirFilePath);
}
- if (components)
- *components = qmldirParser->components();
- if (scripts)
- *scripts = qmldirParser->scripts();
+ return true;
+}
+
+bool QQmlImportsPrivate::getQmldirContent(const QString &qmldirIdentifier, const QString &uri,
+ const QQmlTypeLoader::QmldirContent **qmldir, QList<QQmlError> *errors)
+{
+ Q_ASSERT(errors);
+ Q_ASSERT(qmldir);
+
+ *qmldir = typeLoader->qmldirContent(qmldirIdentifier, uri);
+ if (*qmldir) {
+ // Ensure that parsing was successful
+ if ((*qmldir)->hasError()) {
+ QUrl url;
+
+ if (QQmlFile::isBundle(qmldirIdentifier))
+ url = QUrl(qmldirIdentifier);
+ else
+ url = QUrl::fromLocalFile(qmldirIdentifier);
+
+ const QList<QQmlError> qmldirErrors = (*qmldir)->errors(uri);
+ for (int i = 0; i < qmldirErrors.size(); ++i) {
+ QQmlError error = qmldirErrors.at(i);
+ error.setUrl(url);
+ errors->append(error);
+ }
+ return false;
+ }
+ }
return true;
}
@@ -672,7 +799,7 @@ QString QQmlImportsPrivate::resolvedUri(const QString &dir_arg, QQmlImportDataba
} };
QString dir = dir_arg;
- if (dir.endsWith(QLatin1Char('/')) || dir.endsWith(QLatin1Char('\\')))
+ if (dir.endsWith(Slash) || dir.endsWith(Backslash))
dir.chop(1);
QStringList paths = database->fileImportPath;
@@ -686,17 +813,17 @@ QString QQmlImportsPrivate::resolvedUri(const QString &dir_arg, QQmlImportDataba
}
}
- stableRelativePath.replace(QLatin1Char('\\'), QLatin1Char('/'));
+ stableRelativePath.replace(Backslash, Slash);
// remove optional versioning in dot notation from uri
- int lastSlash = stableRelativePath.lastIndexOf(QLatin1Char('/'));
+ int lastSlash = stableRelativePath.lastIndexOf(Slash);
if (lastSlash >= 0) {
- int versionDot = stableRelativePath.indexOf(QLatin1Char('.'), lastSlash);
+ int versionDot = stableRelativePath.indexOf(Dot, lastSlash);
if (versionDot >= 0)
stableRelativePath = stableRelativePath.left(versionDot);
}
- stableRelativePath.replace(QLatin1Char('/'), QLatin1Char('.'));
+ stableRelativePath.replace(Slash, Dot);
return stableRelativePath;
}
@@ -706,10 +833,8 @@ 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)
+bool QQmlImportsPrivate::locateQmldir(const QString &uri, int vmaj, int vmin, QQmlImportDatabase *database,
+ QString *outQmldirFilePath, QString *outQmldirPathUrl)
{
Q_ASSERT(vmaj >= 0 && vmin >= 0); // Versions are always specified for libraries
@@ -732,29 +857,20 @@ bool QQmlImportsPrivate::locateQmldir(const QString &uri, int vmaj, int vmin,
}
}
- static QLatin1Char Slash('/');
- static QLatin1String Slash_qmldir("/qmldir");
+ QQmlTypeLoader &typeLoader = QQmlEnginePrivate::get(database->engine)->typeLoader;
- QString url = uri;
- url.replace(QLatin1Char('.'), Slash);
-
- // 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) {
- QString dir = p + Slash + url;
-
- 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;
-
- QQmlTypeLoader &typeLoader = QQmlEnginePrivate::get(database->engine)->typeLoader;
- QString absoluteFilePath = typeLoader.absoluteFilePath(qmldirFile);
+ QStringList localImportPaths = database->importPathList(QQmlImportDatabase::Local);
+
+ // Search local import paths for a matching version
+ for (int version = QQmlImports::FullyVersioned; version <= QQmlImports::Unversioned; ++version) {
+ foreach (const QString &path, localImportPaths) {
+ QString qmldirPath = QQmlImports::completeQmldirPath(uri, path, vmaj, vmin, static_cast<QQmlImports::ImportVersion>(version));
+
+ QString absoluteFilePath = typeLoader.absoluteFilePath(qmldirPath);
if (!absoluteFilePath.isEmpty()) {
+ QString url;
QString absolutePath = absoluteFilePath.left(absoluteFilePath.lastIndexOf(Slash)+1);
- if (absolutePath.at(0) == QLatin1Char(':'))
+ if (absolutePath.at(0) == Colon)
url = QLatin1String("qrc://") + absolutePath.mid(1);
else
url = QUrl::fromLocalFile(absolutePath).toString();
@@ -784,264 +900,328 @@ bool QQmlImportsPrivate::locateQmldir(const QString &uri, int vmaj, int vmin,
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)
+bool QQmlImportsPrivate::validateQmldirVersion(const QQmlTypeLoader::QmldirContent *qmldir, const QString &uri, int vmaj, int vmin,
+ 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;
+ int lowest_min = INT_MAX;
+ int highest_min = INT_MIN;
+
+ typedef QQmlDirComponents::const_iterator ConstIterator;
+ const QQmlDirComponents &components = qmldir->components();
+
+ ConstIterator cend = components.constEnd();
+ for (ConstIterator cit = components.constBegin(); cit != cend; ++cit) {
+ for (ConstIterator cit2 = components.constBegin(); cit2 != cit; ++cit2) {
+ if ((cit2->typeName == cit->typeName) &&
+ (cit2->majorVersion == cit->majorVersion) &&
+ (cit2->minorVersion == cit->minorVersion)) {
+ // This entry clashes with a predecessor
+ QQmlError error;
+ error.setDescription(QQmlImportDatabase::tr("\"%1\" version %2.%3 is already defined in module \"%4\"")
+ .arg(cit->typeName).arg(cit->majorVersion).arg(cit->minorVersion).arg(uri));
+ errors->prepend(error);
+ return false;
+ }
+ }
+
+ if (cit->majorVersion == vmaj) {
+ lowest_min = qMin(lowest_min, cit->minorVersion);
+ highest_min = qMax(highest_min, cit->minorVersion);
+ }
+ }
+
+ typedef QList<QQmlDirParser::Script>::const_iterator SConstIterator;
+ const QQmlDirScripts &scripts = qmldir->scripts();
+
+ SConstIterator send = scripts.constEnd();
+ for (SConstIterator sit = scripts.constBegin(); sit != send; ++sit) {
+ for (SConstIterator sit2 = scripts.constBegin(); sit2 != sit; ++sit2) {
+ if ((sit2->nameSpace == sit->nameSpace) &&
+ (sit2->majorVersion == sit->majorVersion) &&
+ (sit2->minorVersion == sit->minorVersion)) {
+ // This entry clashes with a predecessor
+ QQmlError error;
+ error.setDescription(QQmlImportDatabase::tr("\"%1\" version %2.%3 is already defined in module \"%4\"")
+ .arg(sit->nameSpace).arg(sit->majorVersion).arg(sit->minorVersion).arg(uri));
+ errors->prepend(error);
+ return false;
+ }
+ }
+
+ if (sit->majorVersion == vmaj) {
+ lowest_min = qMin(lowest_min, sit->minorVersion);
+ highest_min = qMax(highest_min, sit->minorVersion);
+ }
+ }
+
+ if (lowest_min > vmin || highest_min < vmin) {
+ QQmlError error;
+ error.setDescription(QQmlImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri).arg(vmaj).arg(vmin));
+ errors->prepend(error);
+ return false;
+ }
+
+ return true;
+}
+
+QQmlImportNamespace *QQmlImportsPrivate::importNamespace(const QString &prefix) const
+{
+ QQmlImportNamespace *nameSpace = 0;
- qmldircomponents = qmldircomponentsnetwork;
- uri = importedUri;
if (prefix.isEmpty()) {
- importSet = &unqualifiedset;
+ nameSpace = &unqualifiedset;
} else {
- importSet = findQualifiedNamespace(prefix);
+ nameSpace = findQualifiedNamespace(prefix);
- if (!importSet) {
- importSet = new QQmlImportNamespace;
- importSet->prefix = prefix;
- qualifiedSets.append(importSet);
+ if (!nameSpace) {
+ nameSpace = new QQmlImportNamespace;
+ nameSpace->prefix = prefix;
+ qualifiedSets.append(nameSpace);
}
}
- if (importType == QQmlScript::Import::Library) {
- Q_ASSERT(vmaj >= 0 && vmin >= 0);
+ return nameSpace;
+}
+
+QQmlImportNamespace::Import *QQmlImportsPrivate::addImportToNamespace(QQmlImportNamespace *nameSpace,
+ const QString &uri, const QString &url, int vmaj, int vmin,
+ QQmlScript::Import::Type type,
+ QList<QQmlError> *errors)
+{
+ Q_ASSERT(nameSpace);
+ Q_ASSERT(errors);
+ Q_ASSERT(url.isEmpty() || url.endsWith(Slash));
+
+ QQmlImportNamespace::Import *import = new QQmlImportNamespace::Import;
+ import->uri = uri;
+ import->url = url;
+ import->majversion = vmaj;
+ import->minversion = vmin;
+ import->isLibrary = (type == QQmlScript::Import::Library);
- QString qmldirFilePath;
+ nameSpace->imports.prepend(import);
+ return import;
+}
+
+bool QQmlImportsPrivate::addLibraryImport(const QString& uri, const QString &prefix,
+ int vmaj, int vmin, const QString &qmldirIdentifier, const QString &qmldirUrl, bool incomplete,
+ QQmlImportDatabase *database,
+ QList<QQmlError> *errors)
+{
+ Q_ASSERT(database);
+ Q_ASSERT(errors);
- if (locateQmldir(uri, vmaj, vmin, database, &qmldirFilePath, &url)) {
+ QQmlImportNamespace *nameSpace = importNamespace(prefix);
+ Q_ASSERT(nameSpace);
- if (!importExtension(qmldirFilePath, uri, database, &qmldircomponents,
- &qmldirscripts, &url, errors))
+ QQmlImportNamespace::Import *inserted = addImportToNamespace(nameSpace, uri, qmldirUrl, vmaj, vmin, QQmlScript::Import::Library, errors);
+ Q_ASSERT(inserted);
+
+ if (!incomplete) {
+ const QQmlTypeLoader::QmldirContent *qmldir = 0;
+
+ if (!qmldirIdentifier.isEmpty()) {
+ if (!getQmldirContent(qmldirIdentifier, uri, &qmldir, errors))
return false;
- }
+ if (qmldir) {
+ if (!importExtension(qmldir->pluginLocation(), uri, database, qmldir, errors))
+ return false;
- if (!QQmlMetaType::isModule(uri, vmaj, vmin)) {
+ if (!inserted->setQmldirContent(qmldirUrl, qmldir, nameSpace, errors))
+ return false;
+ }
+ }
- if (qmldircomponents.isEmpty() && qmldirscripts.isEmpty()) {
+ // Ensure that we are actually providing something
+ if ((vmaj < 0) || (vmin < 0) || !QQmlMetaType::isModule(uri, vmaj, vmin)) {
+ if (inserted->qmlDirComponents.isEmpty() && inserted->qmlDirScripts.isEmpty()) {
QQmlError error;
if (QQmlMetaType::isAnyModule(uri))
- error.setDescription(tr("module \"%1\" version %2.%3 is not installed").arg(importedUri).arg(vmaj).arg(vmin));
+ error.setDescription(tr("module \"%1\" version %2.%3 is not installed").arg(uri).arg(vmaj).arg(vmin));
else
- error.setDescription(tr("module \"%1\" is not installed").arg(importedUri));
+ error.setDescription(tr("module \"%1\" is not installed").arg(uri));
errors->prepend(error);
return false;
- } else {
- int lowest_min = INT_MAX;
- int highest_min = INT_MIN;
- typedef QQmlDirComponents::const_iterator ConstIterator;
- typedef QList<QQmlDirParser::Script>::const_iterator SConstIterator;
-
- ConstIterator cend = qmldircomponents.constEnd();
- for (ConstIterator cit = qmldircomponents.constBegin(); cit != cend; ++cit) {
- for (ConstIterator cit2 = qmldircomponents.constBegin(); cit2 != cit; ++cit2) {
- if ((cit2->typeName == cit->typeName) &&
- (cit2->majorVersion == cit->majorVersion) &&
- (cit2->minorVersion == cit->minorVersion)) {
- // This is entry clashes with a predecessor
- QQmlError error;
- error.setDescription(tr("\"%1\" version %2.%3 is already defined in module \"%4\"")
- .arg(cit->typeName).arg(cit->majorVersion).arg(cit->minorVersion).arg(importedUri));
- errors->prepend(error);
- return false;
- }
- }
+ } else if ((vmaj >= 0) && (vmin >= 0) && qmldir) {
+ // Verify that the qmldir content is valid for this version
+ if (!validateQmldirVersion(qmldir, uri, vmaj, vmin, errors))
+ return false;
+ }
+ }
+ }
- if (cit->majorVersion == vmaj) {
- lowest_min = qMin(lowest_min, cit->minorVersion);
- highest_min = qMax(highest_min, cit->minorVersion);
- }
- }
+ return true;
+}
- SConstIterator send = qmldirscripts.constEnd();
- for (SConstIterator sit = qmldirscripts.constBegin(); sit != send; ++sit) {
- for (SConstIterator sit2 = qmldirscripts.constBegin(); sit2 != sit; ++sit2) {
- if ((sit2->nameSpace == sit->nameSpace) &&
- (sit2->majorVersion == sit->majorVersion) &&
- (sit2->minorVersion == sit->minorVersion)) {
- // This is entry clashes with a predecessor
- QQmlError error;
- error.setDescription(tr("\"%1\" version %2.%3 is already defined in module \"%4\"")
- .arg(sit->nameSpace).arg(sit->majorVersion).arg(sit->minorVersion).arg(importedUri));
- errors->prepend(error);
- return false;
- }
- }
+bool QQmlImportsPrivate::addFileImport(const QString& uri, const QString &prefix,
+ int vmaj, int vmin,
+ bool isImplicitImport, bool incomplete, QQmlImportDatabase *database,
+ QList<QQmlError> *errors)
+{
+ Q_ASSERT(errors);
- if (sit->majorVersion == vmaj) {
- lowest_min = qMin(lowest_min, sit->minorVersion);
- highest_min = qMax(highest_min, sit->minorVersion);
- }
- }
+ QQmlImportNamespace *nameSpace = importNamespace(prefix);
+ Q_ASSERT(nameSpace);
- 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;
- }
- }
+ // The uri for this import. For library imports this is the same as uri
+ // specified by the user, but it may be different in the case of file imports.
+ QString importUri = uri;
+
+ QString qmldirPath = importUri;
+ if (importUri.endsWith(Slash))
+ qmldirPath += String_qmldir;
+ else
+ qmldirPath += Slash_qmldir;
+
+ QString qmldirUrl = resolveLocalUrl(base, qmldirPath);
+
+ QString qmldirIdentifier;
+ if (QQmlFile::isBundle(qmldirUrl)) {
+
+ QString dir = resolveLocalUrl(base, importUri);
+ Q_ASSERT(QQmlFile::isBundle(dir));
+ if (!QQmlFile::bundleDirectoryExists(dir, typeLoader->engine())) {
+ if (!isImplicitImport) {
+ QQmlError error;
+ error.setDescription(tr("\"%1\": no such directory").arg(uri));
+ error.setUrl(QUrl(qmldirUrl));
+ errors->prepend(error);
+ }
+ return false;
}
- } else {
- Q_ASSERT(importType == QQmlScript::Import::File);
+ // Transforms the (possible relative) uri into our best guess relative to the
+ // import paths.
+ importUri = resolvedUri(dir, database);
+ if (importUri.endsWith(Slash))
+ importUri.chop(1);
- if (qmldircomponents.isEmpty()) {
+ if (QQmlFile::bundleFileExists(qmldirUrl, typeLoader->engine()))
+ qmldirIdentifier = qmldirUrl;
- QString qmldirPath = uri;
- if (uri.endsWith(Slash)) qmldirPath += String_qmldir;
- else qmldirPath += Slash_qmldir;
- QString qmldirUrl = resolveLocalUrl(base, qmldirPath);
+ } else if (QQmlFile::isLocalFile(qmldirUrl)) {
- if (QQmlFile::isBundle(qmldirUrl)) {
+ QString localFileOrQrc = QQmlFile::urlToLocalFileOrQrc(qmldirUrl);
+ Q_ASSERT(!localFileOrQrc.isEmpty());
- 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 false;
- }
+ QString dir = QQmlFile::urlToLocalFileOrQrc(resolveLocalUrl(base, importUri));
+ if (!typeLoader->directoryExists(dir)) {
+ if (!isImplicitImport) {
+ QQmlError error;
+ error.setDescription(tr("\"%1\": no such directory").arg(uri));
+ error.setUrl(QUrl(qmldirUrl));
+ errors->prepend(error);
+ }
+ return false;
+ }
- // Transforms the (possible relative) uri into our best guess relative to the
- // import paths.
- uri = resolvedUri(dir, database);
+ // Transforms the (possible relative) uri into our best guess relative to the
+ // import paths.
+ importUri = resolvedUri(dir, database);
+ if (importUri.endsWith(Slash))
+ importUri.chop(1);
- if (uri.endsWith(Slash))
- uri.chop(1);
- if (QQmlFile::bundleFileExists(qmldirUrl, typeLoader->engine())) {
- if (!importExtension(qmldirUrl, uri, database, &qmldircomponents,
- &qmldirscripts, &url, errors))
- return false;
- }
+ if (!typeLoader->absoluteFilePath(localFileOrQrc).isEmpty())
+ qmldirIdentifier = localFileOrQrc;
- } else if (QQmlFile::isLocalFile(qmldirUrl)) {
+ } else if (nameSpace->prefix.isEmpty() && !incomplete) {
- QString localFileOrQrc = QQmlFile::urlToLocalFileOrQrc(qmldirUrl);
- Q_ASSERT(!localFileOrQrc.isEmpty());
+ if (!isImplicitImport) {
+ QQmlError error;
+ error.setDescription(tr("import \"%1\" has no qmldir and no namespace").arg(importUri));
+ error.setUrl(QUrl(qmldirUrl));
+ errors->prepend(error);
+ }
- 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;
- }
+ 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, &url, errors))
- return false;
- }
+ // The url for the path containing files for this import
+ QString url = resolveLocalUrl(base, uri);
+ if (!url.endsWith(Slash) && !url.endsWith(Backslash))
+ url += Slash;
- } else if (prefix.isEmpty()) {
+ QQmlImportNamespace::Import *inserted = addImportToNamespace(nameSpace, importUri, url, vmaj, vmin, QQmlScript::Import::File, errors);
+ Q_ASSERT(inserted);
- if (!isImplicitImport) {
- QQmlError error;
- error.setDescription(tr("import \"%1\" has no qmldir and no namespace").arg(uri));
- error.setUrl(QUrl(qmldirUrl));
- errors->prepend(error);
- }
+ if (!incomplete && !qmldirIdentifier.isEmpty()) {
+ const QQmlTypeLoader::QmldirContent *qmldir = 0;
+ if (!getQmldirContent(qmldirIdentifier, importUri, &qmldir, errors))
+ return false;
+ if (qmldir) {
+ if (!importExtension(qmldir->pluginLocation(), importUri, database, qmldir, errors))
return false;
- }
+ if (!inserted->setQmldirContent(url, qmldir, nameSpace, errors))
+ return false;
}
-
- url = resolveLocalUrl(base, importedUri);
- if (!url.endsWith(Slash))
- url += Slash;
}
- Q_ASSERT(url.isEmpty() || url.endsWith(Slash));
+ return true;
+}
- QMap<QString, QQmlDirParser::Script> scripts;
- if (!qmldirscripts.isEmpty()) {
- // Verify that we haven't imported these scripts already
- for (QList<QQmlImportNamespace::Import>::const_iterator it = importSet->imports.constBegin();
- it != importSet->imports.constEnd(); ++it) {
- if (it->uri == uri) {
- QQmlError error;
- error.setDescription(tr("\"%1\" is ambiguous. Found in %2 and in %3").arg(uri).arg(url).arg(it->url));
- errors->prepend(error);
+bool QQmlImportsPrivate::updateQmldirContent(const QString &uri, const QString &prefix,
+ const QString &qmldirIdentifier, const QString& qmldirUrl,
+ QQmlImportDatabase *database, QList<QQmlError> *errors)
+{
+ QQmlImportNamespace *nameSpace = importNamespace(prefix);
+ Q_ASSERT(nameSpace);
+
+ if (QQmlImportNamespace::Import *import = nameSpace->findImport(uri)) {
+ const QQmlTypeLoader::QmldirContent *qmldir = 0;
+ if (!getQmldirContent(qmldirIdentifier, uri, &qmldir, errors))
+ return false;
+
+ if (qmldir) {
+ if (!importExtension(qmldir->pluginLocation(), uri, database, qmldir, errors))
return false;
- }
- }
- 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))) {
+ if (import->setQmldirContent(qmldirUrl, qmldir, nameSpace, errors)) {
+ // Ensure that we are actually providing something
+ int vmaj = import->majversion;
+ int vmin = import->minversion;
- // Load the highest version that matches
- QMap<QString, QQmlDirParser::Script>::iterator it = scripts.find(sit->nameSpace);
- if (it == scripts.end() || (it->minorVersion < sit->minorVersion)) {
- scripts.insert(sit->nameSpace, *sit);
+ if (import->qmlDirComponents.isEmpty() && import->qmlDirScripts.isEmpty()) {
+ // The implicit import qmldir can be empty
+ if (uri != QLatin1String(".")) {
+ QQmlError error;
+ if (QQmlMetaType::isAnyModule(uri))
+ error.setDescription(tr("module \"%1\" version %2.%3 is not installed").arg(uri).arg(vmaj).arg(vmin));
+ else
+ error.setDescription(tr("module \"%1\" is not installed").arg(uri));
+ errors->prepend(error);
+ return false;
+ }
+ } else if ((vmaj >= 0) && (vmin >= 0)) {
+ // Verify that the qmldir content is valid for this version
+ if (!validateQmldirVersion(qmldir, uri, vmaj, vmin, errors))
+ return false;
}
+ return true;
}
}
}
- 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);
-
- if (outUrl) *outUrl = url;
+ if (errors->isEmpty()) {
+ QQmlError error;
+ error.setDescription(QQmlTypeLoader::tr("Cannot update qmldir content for '%1'").arg(uri));
+ errors->prepend(error);
+ }
- return true;
+ return false;
}
/*!
\internal
- Adds an implicit "." file import. This is equivalent to calling addImport(), but error
+ Adds an implicit "." file import. This is equivalent to calling addFileImport(), 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)
+bool QQmlImports::addImplicitImport(QQmlImportDatabase *importDb, QList<QQmlError> *errors)
{
Q_ASSERT(errors);
@@ -1049,9 +1229,8 @@ bool QQmlImports::addImplicitImport(QQmlImportDatabase *importDb,
qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString())
<< ")::addImplicitImport";
-
- return d->addImport(qmldircomponentsnetwork, QLatin1String("."), QString(), -1, -1,
- QQmlScript::Import::File, true, importDb, 0, errors);
+ bool incomplete = !isLocal(baseUrl());
+ return d->addFileImport(QLatin1String("."), QString(), -1, -1, true, incomplete, importDb, errors);
}
/*!
@@ -1075,24 +1254,66 @@ bool QQmlImports::addImplicitImport(QQmlImportDatabase *importDb,
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 QQmlImports::addFileImport(QQmlImportDatabase *importDb,
+ const QString& uri, const QString& prefix, int vmaj, int vmin,
+ bool incomplete, QList<QQmlError> *errors)
+{
+ Q_ASSERT(importDb);
+ Q_ASSERT(errors);
+
+ if (qmlImportTrace())
+ qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) << ')' << "::addFileImport: "
+ << uri << ' ' << vmaj << '.' << vmin << " as " << prefix;
+
+ return d->addFileImport(uri, prefix, vmaj, vmin, false, incomplete, importDb, errors);
+}
+
+bool QQmlImports::addLibraryImport(QQmlImportDatabase *importDb,
+ const QString &uri, const QString &prefix, int vmaj, int vmin,
+ const QString &qmldirIdentifier, const QString& qmldirUrl, bool incomplete, QList<QQmlError> *errors)
{
+ Q_ASSERT(importDb);
Q_ASSERT(errors);
if (qmlImportTrace())
- qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) << ')' << "::addImport: "
- << uri << ' ' << vmaj << '.' << vmin << ' '
- << (importType==QQmlScript::Import::Library? "Library" : "File")
- << " as " << prefix;
+ qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) << ')' << "::addLibraryImport: "
+ << uri << ' ' << vmaj << '.' << vmin << " as " << prefix;
+
+ return d->addLibraryImport(uri, prefix, vmaj, vmin, qmldirIdentifier, qmldirUrl, incomplete, importDb, errors);
+}
+
+bool QQmlImports::updateQmldirContent(QQmlImportDatabase *importDb,
+ const QString &uri, const QString &prefix,
+ const QString &qmldirIdentifier, const QString& qmldirUrl, QList<QQmlError> *errors)
+{
+ Q_ASSERT(importDb);
+ Q_ASSERT(errors);
+
+ if (qmlImportTrace())
+ qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) << ')' << "::updateQmldirContent: "
+ << uri << " to " << qmldirUrl << " as " << prefix;
+
+ return d->updateQmldirContent(uri, prefix, qmldirIdentifier, qmldirUrl, importDb, errors);
+}
+
+bool QQmlImports::locateQmldir(QQmlImportDatabase *importDb,
+ const QString& uri, int vmaj, int vmin,
+ QString *qmldirFilePath, QString *url)
+{
+ return d->locateQmldir(uri, vmaj, vmin, importDb, qmldirFilePath, url);
+}
- return d->addImport(qmldircomponentsnetwork, uri, prefix, vmaj, vmin, importType, false,
- importDb, url, errors);
+bool QQmlImports::isLocal(const QString &url)
+{
+ return QQmlFile::isBundle(url) || !QQmlFile::urlToLocalFileOrQrc(url).isEmpty();
+}
+
+bool QQmlImports::isLocal(const QUrl &url)
+{
+ return QQmlFile::isBundle(url) || !QQmlFile::urlToLocalFileOrQrc(url).isEmpty();
}
+
/*!
\class QQmlImportDatabase
\brief The QQmlImportDatabase class manages the QML imports for a QQmlEngine.
@@ -1126,16 +1347,7 @@ QQmlImportDatabase::QQmlImportDatabase(QQmlEngine *e)
QQmlImportDatabase::~QQmlImportDatabase()
{
- for (QStringHash<QmldirCache *>::ConstIterator iter = qmldirCache.begin();
- iter != qmldirCache.end(); ++iter) {
-
- QmldirCache *c = *iter;
- while (c) {
- QmldirCache *n = c->next;
- delete c;
- c = n;
- }
- }
+ qmldirCache.clear();
}
/*!
@@ -1162,22 +1374,22 @@ QString QQmlImportDatabase::resolvePlugin(QQmlTypeLoader *typeLoader,
QString resolvedPath;
if (pluginPath == QLatin1String(".")) {
if (qmldirPluginPathIsRelative && !qmldirPluginPath.isEmpty() && qmldirPluginPath != QLatin1String("."))
- resolvedPath = QDir::cleanPath(qmldirPath + QLatin1Char('/') + qmldirPluginPath);
+ resolvedPath = QDir::cleanPath(qmldirPath + Slash + qmldirPluginPath);
else
resolvedPath = qmldirPath;
} else {
if (QDir::isRelativePath(pluginPath))
- resolvedPath = QDir::cleanPath(qmldirPath + QLatin1Char('/') + pluginPath);
+ resolvedPath = QDir::cleanPath(qmldirPath + Slash + pluginPath);
else
resolvedPath = pluginPath;
}
// hack for resources, should probably go away
- if (resolvedPath.startsWith(QLatin1Char(':')))
+ if (resolvedPath.startsWith(Colon))
resolvedPath = QCoreApplication::applicationDirPath();
- if (!resolvedPath.endsWith(QLatin1Char('/')))
- resolvedPath += QLatin1Char('/');
+ if (!resolvedPath.endsWith(Slash))
+ resolvedPath += Slash;
foreach (const QString &suffix, suffixes) {
QString pluginFileName = prefix;
@@ -1320,13 +1532,15 @@ void QQmlImportDatabase::addImportPath(const QString& path)
QUrl url = QUrl(path);
QString cPath;
- if (url.isRelative() || url.scheme() == QLatin1String("file")
- || (url.scheme().length() == 1 && QFile::exists(path)) ) { // windows path
+ if (url.scheme() == QLatin1String("file")) {
+ cPath = QQmlFile::urlToLocalFileOrQrc(url);
+ } else if (url.isRelative() ||
+ (url.scheme().length() == 1 && QFile::exists(path)) ) { // windows path
QDir dir = QDir(path);
cPath = dir.canonicalPath();
} else {
cPath = path;
- cPath.replace(QLatin1Char('\\'), QLatin1Char('/'));
+ cPath.replace(Backslash, Slash);
}
if (!cPath.isEmpty()
@@ -1337,9 +1551,19 @@ void QQmlImportDatabase::addImportPath(const QString& path)
/*!
\internal
*/
-QStringList QQmlImportDatabase::importPathList() const
+QStringList QQmlImportDatabase::importPathList(PathType type) const
{
- return fileImportPath;
+ if (type == LocalOrRemote)
+ return fileImportPath;
+
+ QStringList list;
+ foreach (const QString &path, fileImportPath) {
+ bool localPath = isPathAbsolute(path) || QQmlFile::isLocalFile(path);
+ if (localPath == (type == Local))
+ list.append(path);
+ }
+
+ return list;
}
/*!
@@ -1351,6 +1575,9 @@ void QQmlImportDatabase::setImportPathList(const QStringList &paths)
qDebug().nospace() << "QQmlImportDatabase::setImportPathList: " << paths;
fileImportPath = paths;
+
+ // Our existing cached paths may have been invalidated
+ qmldirCache.clear();
}
/*!
@@ -1370,7 +1597,7 @@ bool QQmlImportDatabase::importPlugin(const QString &filePath, const QString &ur
if (typesRegistered) {
Q_ASSERT_X(qmlEnginePluginsWithRegisteredTypes()->value(absoluteFilePath) == uri,
- "QQmlImportDatabase::importExtension",
+ "QQmlImportDatabase::importPlugin",
"Internal error: Plugin imported previously with different uri");
}