aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2020-02-07 16:22:53 +0100
committerUlf Hermann <ulf.hermann@qt.io>2020-03-17 14:44:26 +0100
commitf4937a21b61bf2f214d175d77c432c68f25ead21 (patch)
treea9753103192cf6310913ed3127bf48d80aed8462 /src
parent1eb20d70619cc896fc283bd6605b257a8750c518 (diff)
Allow multiple URL interceptors per engine
We may want to have, for example, a QQmlFileSelector and a component-specific interceptor that chooses a theme or similar. Also, make the API public. We want to propose this as alternative to dynamically registering QML files via qmlRegisterType(QUrl, ...). Change-Id: I4a535d3ea556da6710fde816579ec188b3f57099 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/qml/jsruntime/qv4include.cpp4
-rw-r--r--src/qml/qml/qqmlcontext.cpp5
-rw-r--r--src/qml/qml/qqmldatablob.cpp5
-rw-r--r--src/qml/qml/qqmlengine.cpp55
-rw-r--r--src/qml/qml/qqmlengine.h16
-rw-r--r--src/qml/qml/qqmlengine_p.h3
-rw-r--r--src/qml/qml/qqmlfileselector.cpp13
-rw-r--r--src/qml/qml/qqmlimport.cpp17
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp3
-rw-r--r--src/qml/qml/qqmltypeloader.cpp12
-rw-r--r--src/quick/items/qquickimagebase.cpp5
11 files changed, 87 insertions, 51 deletions
diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp
index 92face6f94..745ffab0cd 100644
--- a/src/qml/jsruntime/qv4include.cpp
+++ b/src/qml/jsruntime/qv4include.cpp
@@ -218,8 +218,8 @@ QV4::ReturnedValue QV4Include::method_include(const QV4::FunctionObject *b, cons
callbackFunction = argv[1];
QUrl url(scope.engine->resolvedUrl(argv[0].toQStringNoThrow()));
- if (scope.engine->qmlEngine() && scope.engine->qmlEngine()->urlInterceptor())
- url = scope.engine->qmlEngine()->urlInterceptor()->intercept(url, QQmlAbstractUrlInterceptor::JavaScriptFile);
+ if (const QQmlEngine *qmlEngine = scope.engine->qmlEngine())
+ url = qmlEngine->interceptUrl(url, QQmlAbstractUrlInterceptor::JavaScriptFile);
QString localFile = QQmlFile::urlToLocalFileOrQrc(url);
diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp
index 9157bb95c3..abd379a320 100644
--- a/src/qml/qml/qqmlcontext.cpp
+++ b/src/qml/qml/qqmlcontext.cpp
@@ -465,9 +465,8 @@ QUrl QQmlContextData::resolvedUrl(const QUrl &src)
if (resolved.isEmpty()) //relative but no ctxt
return resolved;
- if (engine && engine->urlInterceptor())
- resolved = engine->urlInterceptor()->intercept(resolved, QQmlAbstractUrlInterceptor::UrlString);
- return resolved;
+ return engine ? engine->interceptUrl(resolved, QQmlAbstractUrlInterceptor::UrlString)
+ : resolved;
}
diff --git a/src/qml/qml/qqmldatablob.cpp b/src/qml/qml/qqmldatablob.cpp
index c29f207ae3..fb8bd63bf1 100644
--- a/src/qml/qml/qqmldatablob.cpp
+++ b/src/qml/qml/qqmldatablob.cpp
@@ -105,9 +105,8 @@ QQmlDataBlob::QQmlDataBlob(const QUrl &url, Type type, QQmlTypeLoader *manager)
m_inCallback(false), m_isDone(false)
{
//Set here because we need to get the engine from the manager
- if (m_typeLoader->engine() && m_typeLoader->engine()->urlInterceptor())
- m_url = m_typeLoader->engine()->urlInterceptor()->intercept(m_url,
- (QQmlAbstractUrlInterceptor::DataType)m_type);
+ if (const QQmlEngine *qmlEngine = m_typeLoader->engine())
+ m_url = qmlEngine->interceptUrl(m_url, (QQmlAbstractUrlInterceptor::DataType)m_type);
}
/*! \internal */
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 725d2e7c7a..c2f8459fb1 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -626,7 +626,7 @@ QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e)
#if QT_CONFIG(qml_network)
networkAccessManager(nullptr), networkAccessManagerFactory(nullptr),
#endif
- urlInterceptor(nullptr), scarceResourcesRefCount(0), importDatabase(e), typeLoader(e),
+ scarceResourcesRefCount(0), importDatabase(e), typeLoader(e),
uniqueId(1), incubatorCount(0), incubationController(nullptr)
{
}
@@ -1077,32 +1077,62 @@ QQmlContext *QQmlEngine::rootContext() const
return d->rootContext;
}
+#if QT_DEPRECATED_SINCE(6, 0)
/*!
\internal
+ \deprecated
This API is private for 5.1
- Sets the \a urlInterceptor to be used when resolving URLs in QML.
+ Returns the last QQmlAbstractUrlInterceptor. It must not be modified outside
+ the GUI thread.
+*/
+QQmlAbstractUrlInterceptor *QQmlEngine::urlInterceptor() const
+{
+ Q_D(const QQmlEngine);
+ return d->urlInterceptors.last();
+}
+#endif
+
+/*!
+ Adds a \a urlInterceptor to be used when resolving URLs in QML.
This also applies to URLs used for loading script files and QML types.
- This should not be modifed while the engine is loading files, or URL
- selection may be inconsistent.
+ The URL interceptors should not be modifed while the engine is loading files,
+ or URL selection may be inconsistent. Multiple URL interceptors, when given,
+ will be called in the order they were added for each URL.
+
+ QQmlEngine does not take ownership of the interceptor and won't delete it.
*/
-void QQmlEngine::setUrlInterceptor(QQmlAbstractUrlInterceptor *urlInterceptor)
+void QQmlEngine::addUrlInterceptor(QQmlAbstractUrlInterceptor *urlInterceptor)
{
Q_D(QQmlEngine);
- d->urlInterceptor = urlInterceptor;
+ d->urlInterceptors.append(urlInterceptor);
}
/*!
- \internal
- This API is private for 5.1
+ Remove a \a urlInterceptor that was previously added using
+ \l addUrlInterceptor. The URL interceptors should not be modifed while the
+ engine is loading files, or URL selection may be inconsistent.
- Returns the current QQmlAbstractUrlInterceptor. It must not be modified outside
- the GUI thread.
+ This does not delete the interceptor, but merely removes it from the engine.
+ You can re-use it on the same or a different engine afterwards.
*/
-QQmlAbstractUrlInterceptor *QQmlEngine::urlInterceptor() const
+void QQmlEngine::removeUrlInterceptor(QQmlAbstractUrlInterceptor *urlInterceptor)
+{
+ Q_D(QQmlEngine);
+ d->urlInterceptors.removeOne(urlInterceptor);
+}
+
+/*!
+ Run the current URL interceptors on the given \a url of the given \a type and
+ return the result.
+ */
+QUrl QQmlEngine::interceptUrl(const QUrl &url, QQmlAbstractUrlInterceptor::DataType type) const
{
Q_D(const QQmlEngine);
- return d->urlInterceptor;
+ QUrl result = url;
+ for (QQmlAbstractUrlInterceptor *interceptor : d->urlInterceptors)
+ result = interceptor->intercept(result, type);
+ return result;
}
void QQmlEnginePrivate::registerFinalizeCallback(QObject *obj, int index)
@@ -2199,7 +2229,6 @@ void QQmlEngine::addPluginPath(const QString& path)
d->importDatabase.addPluginPath(path);
}
-
/*!
Returns the list of directories where the engine searches for
native plugins for imported modules (referenced in the \c qmldir file).
diff --git a/src/qml/qml/qqmlengine.h b/src/qml/qml/qqmlengine.h
index a686d8a1d9..e301082064 100644
--- a/src/qml/qml/qqmlengine.h
+++ b/src/qml/qml/qqmlengine.h
@@ -46,11 +46,10 @@
#include <QtQml/qjsengine.h>
#include <QtQml/qqml.h>
#include <QtQml/qqmlerror.h>
+#include <QtQml/qqmlabstracturlinterceptor.h>
QT_BEGIN_NAMESPACE
-class QQmlAbstractUrlInterceptor;
-
class Q_QML_EXPORT QQmlImageProviderBase
{
public:
@@ -127,8 +126,17 @@ public:
QNetworkAccessManager *networkAccessManager() const;
#endif
- void setUrlInterceptor(QQmlAbstractUrlInterceptor* urlInterceptor);
- QQmlAbstractUrlInterceptor* urlInterceptor() const;
+#if QT_DEPRECATED_SINCE(6, 0)
+ QT_DEPRECATED void setUrlInterceptor(QQmlAbstractUrlInterceptor* urlInterceptor)
+ {
+ addUrlInterceptor(urlInterceptor);
+ }
+ QT_DEPRECATED QQmlAbstractUrlInterceptor *urlInterceptor() const;
+#endif
+
+ void addUrlInterceptor(QQmlAbstractUrlInterceptor *urlInterceptor);
+ void removeUrlInterceptor(QQmlAbstractUrlInterceptor *urlInterceptor);
+ QUrl interceptUrl(const QUrl &url, QQmlAbstractUrlInterceptor::DataType type) const;
void addImageProvider(const QString &id, QQmlImageProviderBase *);
QQmlImageProviderBase *imageProvider(const QString &id) const;
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index 7b9b293832..fe42d4e347 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -178,8 +178,7 @@ public:
QHash<QString,QSharedPointer<QQmlImageProviderBase> > imageProviders;
QSharedPointer<QQmlImageProviderBase> imageProvider(const QString &providerId) const;
-
- QQmlAbstractUrlInterceptor* urlInterceptor;
+ QList<QQmlAbstractUrlInterceptor *> urlInterceptors;
int scarceResourcesRefCount;
void referenceScarceResources();
diff --git a/src/qml/qml/qqmlfileselector.cpp b/src/qml/qml/qqmlfileselector.cpp
index 396d500eac..1ea2b23153 100644
--- a/src/qml/qml/qqmlfileselector.cpp
+++ b/src/qml/qml/qqmlfileselector.cpp
@@ -42,6 +42,7 @@
#include <qobjectdefs.h>
#include "qqmlfileselector.h"
#include "qqmlfileselector_p.h"
+#include "qqmlengine_p.h"
#include <QDebug>
QT_BEGIN_NAMESPACE
@@ -105,7 +106,7 @@ QQmlFileSelector::QQmlFileSelector(QQmlEngine* engine, QObject* parent)
Q_D(QQmlFileSelector);
d->engine = engine;
interceptorInstances()->insert(d->myInstance.data(), this);
- d->engine->setUrlInterceptor(d->myInstance.data());
+ d->engine->addUrlInterceptor(d->myInstance.data());
}
/*!
@@ -115,7 +116,7 @@ QQmlFileSelector::~QQmlFileSelector()
{
Q_D(QQmlFileSelector);
if (d->engine && QQmlFileSelector::get(d->engine) == this) {
- d->engine->setUrlInterceptor(nullptr);
+ d->engine->removeUrlInterceptor(d->myInstance.data());
d->engine = nullptr;
}
interceptorInstances()->remove(d->myInstance.data());
@@ -185,9 +186,11 @@ void QQmlFileSelector::setExtraSelectors(const QStringList &strings)
QQmlFileSelector* QQmlFileSelector::get(QQmlEngine* engine)
{
//Since I think we still can't use dynamic_cast inside Qt...
- QQmlAbstractUrlInterceptor* current = engine->urlInterceptor();
- if (current && interceptorInstances()->contains(current))
- return interceptorInstances()->value(current);
+ const QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine);
+ for (QQmlAbstractUrlInterceptor *current : enginePrivate->urlInterceptors) {
+ if (interceptorInstances()->contains(current))
+ return interceptorInstances()->value(current);
+ }
return nullptr;
}
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 7f8728f364..43a9435f83 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -1381,20 +1381,21 @@ QQmlImports::LocalQmldirResult QQmlImportsPrivate::locateLocalQmldir(
}
}
- QQmlTypeLoader &typeLoader = QQmlEnginePrivate::get(database->engine)->typeLoader;
+ QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(database->engine);
+ QQmlTypeLoader &typeLoader = enginePrivate->typeLoader;
+ const bool hasInterceptors = !enginePrivate->urlInterceptors.isEmpty();
// Interceptor might redirect remote files to local ones.
- QQmlAbstractUrlInterceptor *interceptor = typeLoader.engine()->urlInterceptor();
QStringList localImportPaths = database->importPathList(
- interceptor ? QQmlImportDatabase::LocalOrRemote : QQmlImportDatabase::Local);
+ hasInterceptors ? QQmlImportDatabase::LocalOrRemote : QQmlImportDatabase::Local);
// Search local import paths for a matching version
const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(
uri, localImportPaths, version);
bool pathTurnedRemote = false;
for (QString qmldirPath : qmlDirPaths) {
- if (interceptor) {
- const QUrl intercepted = interceptor->intercept(
+ if (hasInterceptors) {
+ const QUrl intercepted = database->engine->interceptUrl(
QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath),
QQmlAbstractUrlInterceptor::QmldirFile);
qmldirPath = QQmlFile::urlToLocalFileOrQrc(intercepted);
@@ -1616,10 +1617,8 @@ bool QQmlImportsPrivate::addFileImport(const QString& uri, const QString &prefix
QString qmldirUrl = resolveLocalUrl(base, importUri + (importUri.endsWith(Slash)
? String_qmldir
: Slash_qmldir));
- if (QQmlAbstractUrlInterceptor *interceptor = typeLoader->engine()->urlInterceptor()) {
- qmldirUrl = interceptor->intercept(QUrl(qmldirUrl),
- QQmlAbstractUrlInterceptor::QmldirFile).toString();
- }
+ qmldirUrl = typeLoader->engine()->interceptUrl(
+ QUrl(qmldirUrl), QQmlAbstractUrlInterceptor::QmldirFile).toString();
QString qmldirIdentifier;
if (QQmlFile::isLocalFile(qmldirUrl)) {
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 538a87ff5b..040fa16af8 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -449,8 +449,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
QUrl value = string.isEmpty() ? QUrl() : compilationUnit->finalUrl().resolved(QUrl(string));
// Apply URL interceptor
- if (engine->urlInterceptor())
- value = engine->urlInterceptor()->intercept(value, QQmlAbstractUrlInterceptor::UrlString);
+ value = engine->interceptUrl(value, QQmlAbstractUrlInterceptor::UrlString);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 75dc9d15a5..c8e5054f87 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -625,13 +625,15 @@ bool QQmlTypeLoader::Blob::addImport(QQmlTypeLoader::Blob::PendingImportPtr impo
// We haven't yet resolved this import
m_unresolvedImports << import;
- QQmlAbstractUrlInterceptor *interceptor = typeLoader()->engine()->urlInterceptor();
+ const QQmlEngine *engine = typeLoader()->engine();
+ const bool hasInterceptors
+ = !(QQmlEnginePrivate::get(engine)->urlInterceptors.isEmpty());
// Query any network import paths for this library.
// Interceptor might redirect local paths.
QStringList remotePathList = importDatabase->importPathList(
- interceptor ? QQmlImportDatabase::LocalOrRemote
- : QQmlImportDatabase::Remote);
+ hasInterceptors ? QQmlImportDatabase::LocalOrRemote
+ : QQmlImportDatabase::Remote);
if (!remotePathList.isEmpty()) {
// Add this library and request the possible locations for it
if (!m_importCache.addLibraryImport(
@@ -644,8 +646,8 @@ bool QQmlTypeLoader::Blob::addImport(QQmlTypeLoader::Blob::PendingImportPtr impo
const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(
import->uri, remotePathList, import->version);
for (const QString &qmldirPath : qmlDirPaths) {
- if (interceptor) {
- QUrl url = interceptor->intercept(
+ if (hasInterceptors) {
+ QUrl url = engine->interceptUrl(
QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath),
QQmlAbstractUrlInterceptor::QmldirFile);
if (!QQmlFile::isLocalFile(url)
diff --git a/src/quick/items/qquickimagebase.cpp b/src/quick/items/qquickimagebase.cpp
index 8849c2005c..0e5313db67 100644
--- a/src/quick/items/qquickimagebase.cpp
+++ b/src/quick/items/qquickimagebase.cpp
@@ -298,9 +298,8 @@ void QQuickImageBase::loadPixmap(const QUrl &url, LoadPixmapOptions loadOptions)
options |= QQuickPixmap::Cache;
d->pix.clear(this);
QUrl loadUrl = url;
- QQmlEngine* engine = qmlEngine(this);
- if (engine && engine->urlInterceptor())
- loadUrl = engine->urlInterceptor()->intercept(loadUrl, QQmlAbstractUrlInterceptor::UrlString);
+ if (const QQmlEngine *engine = qmlEngine(this))
+ loadUrl = engine->interceptUrl(loadUrl, QQmlAbstractUrlInterceptor::UrlString);
if (loadOptions & HandleDPR) {
const qreal targetDevicePixelRatio = (window() ? window()->effectiveDevicePixelRatio() : qApp->devicePixelRatio());