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.cpp207
1 files changed, 139 insertions, 68 deletions
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index c4e0c7b778..b51c78b8d4 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
@@ -79,12 +85,11 @@ QString resolveLocalUrl(const QString &url, const QString &relative)
} else if (relative.at(0) == Slash || !url.contains(Slash)) {
return relative;
} else {
- QString base(url.left(url.lastIndexOf(Slash) + 1));
-
+ const QStringRef baseRef = url.leftRef(url.lastIndexOf(Slash) + 1);
if (relative == QLatin1String("."))
- return base;
+ return baseRef.toString();
- base.append(relative);
+ QString base = baseRef + relative;
// Remove any relative directory elements in the path
int length = base.length();
@@ -297,7 +302,7 @@ public:
int vmaj, int vmin, QV4::CompiledData::Import::ImportType type,
QList<QQmlError> *errors, bool lowPrecedence = false);
#ifndef QT_NO_LIBRARY
- bool populatePluginPairVector(QVector<StaticPluginPair> &result, const QString &uri,
+ bool populatePluginPairVector(QVector<StaticPluginPair> &result, const QString &uri, const QStringList &versionUris,
const QString &qmldirPath, QList<QQmlError> *errors);
#endif
};
@@ -477,20 +482,58 @@ QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const
return scripts;
}
+static QString joinStringRefs(const QVector<QStringRef> &refs, const QChar &sep)
+{
+ QString str;
+ for (auto it = refs.cbegin(); it != refs.cend(); ++it) {
+ if (it != refs.cbegin())
+ str += sep;
+ str += *it;
+ }
+ return str;
+}
+
/*!
- Form a complete path to a qmldir file, from a base URL, a module URI and version specification.
+ Forms complete paths to a qmldir file, from a base URL, a module URI and version specification.
+
+ For example, QtQml.Models 2.0:
+ - base/QtQml/Models.2.0/qmldir
+ - base/QtQml.2.0/Models/qmldir
+ - base/QtQml/Models.2/qmldir
+ - base/QtQml.2/Models/qmldir
+ - base/QtQml/Models/qmldir
*/
-QString QQmlImports::completeQmldirPath(const QString &uri, const QString &base, int vmaj, int vmin,
- ImportVersion version)
+QStringList QQmlImports::completeQmldirPaths(const QString &uri, const QStringList &basePaths, int vmaj, int vmin)
{
- QString url = uri;
- url.replace(Dot, Slash);
+ const QVector<QStringRef> parts = uri.splitRef(Dot, QString::SkipEmptyParts);
+
+ QStringList qmlDirPathsPaths;
+ // fully & partially versioned parts + 1 unversioned for each base path
+ qmlDirPathsPaths.reserve(basePaths.count() * (2 * parts.count() + 1));
- QString dir = base;
- if (!dir.endsWith(Slash) && !dir.endsWith(Backslash))
- dir += Slash;
+ for (int version = FullyVersioned; version <= Unversioned; ++version) {
+ const QString ver = versionString(vmaj, vmin, static_cast<QQmlImports::ImportVersion>(version));
- return dir + url + versionString(vmaj, vmin, version) + Slash_qmldir;
+ for (const QString &path : basePaths) {
+ QString dir = path;
+ if (!dir.endsWith(Slash) && !dir.endsWith(Backslash))
+ dir += Slash;
+
+ // append to the end
+ qmlDirPathsPaths += dir + joinStringRefs(parts, Slash) + ver + Slash_qmldir;
+
+ if (version != Unversioned) {
+ // insert in the middle
+ for (int index = parts.count() - 2; index >= 0; --index) {
+ qmlDirPathsPaths += dir + joinStringRefs(parts.mid(0, index + 1), Slash)
+ + ver + Slash
+ + joinStringRefs(parts.mid(index + 1), Slash) + Slash_qmldir;
+ }
+ }
+ }
+ }
+
+ return qmlDirPathsPaths;
}
QString QQmlImports::versionString(int vmaj, int vmin, ImportVersion version)
@@ -771,11 +814,11 @@ bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedS
QString u1 = import->url;
QString u2 = import2->url;
if (base) {
- QString b = *base;
+ QStringRef b(base);
int dot = b.lastIndexOf(Dot);
if (dot >= 0) {
b = b.left(dot+1);
- QString l = b.left(dot);
+ QStringRef l = b.left(dot);
if (u1.startsWith(b))
u1 = u1.mid(b.count());
else if (u1 == l)
@@ -835,14 +878,34 @@ QQmlImportNamespace *QQmlImportsPrivate::findQualifiedNamespace(const QHashedStr
return 0;
}
+/*!
+ Returns the list of possible versioned URI combinations. For example, if \a uri is
+ QtQml.Models, \a vmaj is 2, and \a vmin is 0, this method returns the following:
+ [QtQml.Models.2.0, QtQml.2.0.Models, QtQml.Models.2, QtQml.2.Models, QtQml.Models]
+ */
+static QStringList versionUriList(const QString &uri, int vmaj, int vmin)
+{
+ QStringList result;
+ for (int version = QQmlImports::FullyVersioned; version <= QQmlImports::Unversioned; ++version) {
+ int index = uri.length();
+ do {
+ QString versionUri = uri;
+ versionUri.insert(index, QQmlImports::versionString(vmaj, vmin, static_cast<QQmlImports::ImportVersion>(version)));
+ result += versionUri;
+
+ index = uri.lastIndexOf(Dot, index - 1);
+ } while (index > 0 && version != QQmlImports::Unversioned);
+ }
+ return result;
+}
#ifndef QT_NO_LIBRARY
/*!
- Get all static plugins that are QML plugins and has a meta data URI that begins with \a uri.
- Note that if e.g uri == "a", and different plugins have meta data "a", "a.2.1", "a.b.c", all
- will be added to the result. So the result needs further version matching by the caller.
+ Get all static plugins that are QML plugins and has a meta data URI that matches with one of
+ \a versionUris, which is a list of all possible versioned URI combinations - see versionUriList()
+ above.
*/
-bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &result, const QString &uri,
+bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &result, const QString &uri, const QStringList &versionUris,
const QString &qmldirPath, QList<QQmlError> *errors)
{
static QVector<QStaticPlugin> plugins;
@@ -871,7 +934,7 @@ bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &res
}
// A plugin can be set up to handle multiple URIs, so go through the list:
foreach (const QJsonValue &metaTagUri, metaTagsUriList) {
- if (metaTagUri.toString().startsWith(uri)) {
+ if (versionUris.contains(metaTagUri.toString())) {
result.append(qMakePair(plugin, metaTagsUriList));
break;
}
@@ -882,6 +945,11 @@ bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &res
}
#endif
+static inline QString msgCannotLoadPlugin(const QString &uri, const QString &why)
+{
+ return QQmlImportDatabase::tr("plugin cannot be loaded for module \"%1\": %2").arg(uri, why);
+}
+
/*!
Import an extension defined by a qmldir file.
@@ -943,7 +1011,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
// The reason is that the lower level may add url and line/column numbering information.
QQmlError poppedError = errors->takeFirst();
QQmlError error;
- error.setDescription(QQmlImportDatabase::tr("plugin cannot be loaded for module \"%1\": %2").arg(uri).arg(poppedError.description()));
+ error.setDescription(msgCannotLoadPlugin(uri, poppedError.description()));
error.setUrl(QUrl::fromLocalFile(qmldirFilePath));
errors->prepend(error);
}
@@ -959,14 +1027,13 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
// versioned to unversioned, we need to compare with differnt version strings. If a module
// has several plugins, they must all have the same version. Start by populating pluginPairs
// with relevant plugins to cut the list short early on:
+ const QStringList versionUris = versionUriList(uri, vmaj, vmin);
QVector<StaticPluginPair> pluginPairs;
- if (!populatePluginPairVector(pluginPairs, uri, qmldirFilePath, errors))
+ if (!populatePluginPairVector(pluginPairs, uri, versionUris, qmldirFilePath, errors))
return false;
const QString basePath = QFileInfo(qmldirPath).absoluteFilePath();
- for (int version = QQmlImports::FullyVersioned; version <= QQmlImports::Unversioned && staticPluginsFound == 0; ++version) {
- QString versionUri = uri + QQmlImports::versionString(vmaj, vmin, static_cast<QQmlImports::ImportVersion>(version));
-
+ for (const QString &versionUri : versionUris) {
foreach (const StaticPluginPair &pair, pluginPairs) {
foreach (const QJsonValue &metaTagUri, pair.second) {
if (versionUri == metaTagUri.toString()) {
@@ -987,6 +1054,8 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
}
}
}
+ if (staticPluginsFound > 0)
+ break;
}
}
@@ -1007,13 +1076,18 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
}
#else
- Q_UNUSED(qmldirFilePath);
- Q_UNUSED(uri);
Q_UNUSED(vmaj);
Q_UNUSED(vmin);
Q_UNUSED(database);
Q_UNUSED(qmldir);
- Q_UNUSED(errors);
+
+ if (errors) {
+ QQmlError error;
+ error.setDescription(msgCannotLoadPlugin(uri, QQmlImportDatabase::tr("library loading is disabled")));
+ error.setUrl(QUrl::fromLocalFile(qmldirFilePath));
+ errors->prepend(error);
+ }
+
return false;
#endif // QT_NO_LIBRARY
return true;
@@ -1114,32 +1188,29 @@ bool QQmlImportsPrivate::locateQmldir(const QString &uri, int vmaj, int vmin, QQ
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) == Colon)
- url = QLatin1String("qrc://") + absolutePath.mid(1);
- else
- url = QUrl::fromLocalFile(absolutePath).toString();
+ const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(uri, localImportPaths, vmaj, vmin);
+ for (const QString &qmldirPath : qmlDirPaths) {
+ QString absoluteFilePath = typeLoader.absoluteFilePath(qmldirPath);
+ if (!absoluteFilePath.isEmpty()) {
+ QString url;
+ const QStringRef absolutePath = absoluteFilePath.leftRef(absoluteFilePath.lastIndexOf(Slash) + 1);
+ if (absolutePath.at(0) == Colon)
+ url = QLatin1String("qrc://") + absolutePath.mid(1);
+ else
+ url = QUrl::fromLocalFile(absolutePath.toString()).toString();
- QQmlImportDatabase::QmldirCache *cache = new QQmlImportDatabase::QmldirCache;
- cache->versionMajor = vmaj;
- cache->versionMinor = vmin;
- cache->qmldirFilePath = absoluteFilePath;
- cache->qmldirPathUrl = url;
- cache->next = cacheHead;
- database->qmldirCache.insert(uri, cache);
+ QQmlImportDatabase::QmldirCache *cache = new QQmlImportDatabase::QmldirCache;
+ cache->versionMajor = vmaj;
+ cache->versionMinor = vmin;
+ cache->qmldirFilePath = absoluteFilePath;
+ cache->qmldirPathUrl = url;
+ cache->next = cacheHead;
+ database->qmldirCache.insert(uri, cache);
- *outQmldirFilePath = absoluteFilePath;
- *outQmldirPathUrl = url;
+ *outQmldirFilePath = absoluteFilePath;
+ *outQmldirPathUrl = url;
- return true;
- }
+ return true;
}
}
@@ -1562,8 +1633,7 @@ QQmlImportDatabase::QQmlImportDatabase(QQmlEngine *e)
: engine(e)
{
filePluginPath << QLatin1String(".");
-
- // Search order is applicationDirPath(), $QML2_IMPORT_PATH, QLibraryInfo::Qml2ImportsPath
+ // Search order is applicationDirPath(), qrc:/qt-project.org/imports, $QML2_IMPORT_PATH, QLibraryInfo::Qml2ImportsPath
QString installImportsPath = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath);
addImportPath(installImportsPath);
@@ -1581,6 +1651,7 @@ QQmlImportDatabase::QQmlImportDatabase(QQmlEngine *e)
addImportPath(paths.at(ii));
}
+ addImportPath(QStringLiteral("qrc:/qt-project.org/imports"));
addImportPath(QCoreApplication::applicationDirPath());
}