diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2020-02-07 16:22:53 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2020-03-17 14:44:26 +0100 |
commit | f4937a21b61bf2f214d175d77c432c68f25ead21 (patch) | |
tree | a9753103192cf6310913ed3127bf48d80aed8462 /src | |
parent | 1eb20d70619cc896fc283bd6605b257a8750c518 (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.cpp | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmlcontext.cpp | 5 | ||||
-rw-r--r-- | src/qml/qml/qqmldatablob.cpp | 5 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine.cpp | 55 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine.h | 16 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine_p.h | 3 | ||||
-rw-r--r-- | src/qml/qml/qqmlfileselector.cpp | 13 | ||||
-rw-r--r-- | src/qml/qml/qqmlimport.cpp | 17 | ||||
-rw-r--r-- | src/qml/qml/qqmlobjectcreator.cpp | 3 | ||||
-rw-r--r-- | src/qml/qml/qqmltypeloader.cpp | 12 | ||||
-rw-r--r-- | src/quick/items/qquickimagebase.cpp | 5 |
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()); |