aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqmlimport.cpp
diff options
context:
space:
mode:
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");
}