diff options
author | Alan Alpert <aalpert@rim.com> | 2013-02-28 17:03:43 -0800 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-05-07 19:41:26 +0200 |
commit | 223313479bf8ec80158ba0f6cba4dd5e74d92718 (patch) | |
tree | bc39fb195736657dec6a09106ad9609253074d77 /src/qml | |
parent | 40d90b50c555a968f1ae540527199042fbcf1a32 (diff) |
Add a URL interceptor to the QML engine
Allows for custom file handling to a greater extent than the
QNetworkAccessManager.
Change-Id: Ifd3946bf33530c40ca2edeeb9f441f712e4941f6
Reviewed-by: Matthew Vogt <matthew.vogt@qinetic.com.au>
Diffstat (limited to 'src/qml')
-rw-r--r-- | src/qml/qml/qml.pri | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmlabstracturlinterceptor.cpp | 91 | ||||
-rw-r--r-- | src/qml/qml/qqmlabstracturlinterceptor_p.h | 66 | ||||
-rw-r--r-- | src/qml/qml/qqmlcompiler.cpp | 5 | ||||
-rw-r--r-- | src/qml/qml/qqmlcontext.cpp | 16 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine.cpp | 32 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine.h | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine_p.h | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmltypeloader.cpp | 31 | ||||
-rw-r--r-- | src/qml/qml/qqmltypeloader_p.h | 11 |
10 files changed, 240 insertions, 20 deletions
diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri index aafc50db9b..9b2926ec7e 100644 --- a/src/qml/qml/qml.pri +++ b/src/qml/qml/qml.pri @@ -51,6 +51,7 @@ SOURCES += \ $$PWD/qqmlmemoryprofiler.cpp \ $$PWD/qqmlplatform.cpp \ $$PWD/qqmlbinding.cpp \ + $$PWD/qqmlabstracturlinterceptor.cpp \ $$PWD/qqmlapplicationengine.cpp HEADERS += \ @@ -123,6 +124,7 @@ HEADERS += \ $$PWD/qqmlplatform_p.h \ $$PWD/qqmlbinding_p.h \ $$PWD/qqmlextensionplugin_p.h \ + $$PWD/qqmlabstracturlinterceptor_p.h \ $$PWD/qqmlapplicationengine_p.h \ $$PWD/qqmlapplicationengine.h diff --git a/src/qml/qml/qqmlabstracturlinterceptor.cpp b/src/qml/qml/qqmlabstracturlinterceptor.cpp new file mode 100644 index 0000000000..a68d5f7489 --- /dev/null +++ b/src/qml/qml/qqmlabstracturlinterceptor.cpp @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Research In Motion. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt 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 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QQmlAbstractUrlInterceptor + \inmodule QtQml + \brief allows you to control QML file loading. + + \note This class is in an extended validation period and still subject to change. It should be treated as private API for 5.1 + + QQmlAbstractUrlInterceptor is an interface which can be used to alter URLs + before they are used by the QML engine. This is primarily useful for altering + file urls into other file urls, such as selecting different graphical assets + for the current platform. + + Relative URLs are intercepted after being resolved against the file path of the + current QML context. URL interception also occurs after setting the base path for + a loaded QML file. This means that the content loaded for that QML file uses the + intercepted URL, but inside the file the pre-intercepted URL is used for resolving + relative paths. This allows for interception of .qml file loading without needing + all paths (or local types) inside intercepted content to insert a different relative path. + + Compared to setNetworkAccessManagerFactory, QQmlAbstractUrlInterceptor affects all URLs + and paths, including local files and embedded resource files. QQmlAbstractUrlInterceptor + is synchronous, and for asynchronous files must return a url with an asynchronous scheme + (such as http or a custom scheme handled by your own custom QNetworkAccessManager). You + can use a QQmlAbstractUrlInterceptor to change file URLs into networked URLs which are + handled by your own custom QNetworkAccessManager. + + To implement support for a custom networked scheme, see setNetworkAccessManagerFactory. +*/ + +/* + \enum QQmlAbstractUrlInterceptor::DataType + + Specifies where URL interception is taking place place. + + Because QML loads qmldir files for locating types, there are two URLs involved in loading a QML type. The URL of the (possibly implicit) qmldir used for locating the type and the URL of the file which defines the type. Intercepting + both leads to either complex URL replacement or double URL replacements for the same file. + + \value QmldirFile The URL being intercepted is for a Qmldir file. Intercepting this, but not the QmlFile, allows for swapping out entire sub trees. + \value JavaScriptFile The URL being intercepted is an import for a Javascript file. + \value QmlFile The URL being intercepted is for a Qml file. Intercepting this, but not the Qmldir file, leaves the base dir of a QML file untouched and acts like replacing the file with another file. + \value UrlString The URL being intercepted is a url property in a QML file, and not being used to load a file through the engine. + +*/ + +/*! + \fn QUrl QQmlAbstractUrlInterceptor::intercept(const QUrl& url, DataType type) + + A pure virtual function where you can intercept the url. The returned value is taken as the + new value for the url. The type of url being intercepted is given by the type variable. +*/ diff --git a/src/qml/qml/qqmlabstracturlinterceptor_p.h b/src/qml/qml/qqmlabstracturlinterceptor_p.h new file mode 100644 index 0000000000..186d59e301 --- /dev/null +++ b/src/qml/qml/qqmlabstracturlinterceptor_p.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Research In Motion. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt 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 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +//Private API for 5.1 (at least) +#ifndef QQMLABSTRACTURLINTERCEPTOR_H +#define QQMLABSTRACTURLINTERCEPTOR_H + +#include <QtCore/qurl.h> + +QT_BEGIN_NAMESPACE + +class Q_QML_EXPORT QQmlAbstractUrlInterceptor +{ + Q_FLAGS(InterceptionPoint) +public: + enum DataType { //Matches QQmlDataBlob::Type + QmlFile = 0, + JavaScriptFile = 1, + QmldirFile = 2, + UrlString = 0x1000 + }; + + QQmlAbstractUrlInterceptor() {} + virtual ~QQmlAbstractUrlInterceptor() {} + virtual QUrl intercept(const QUrl &path, DataType type) = 0; +}; + +QT_END_NAMESPACE +#endif diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp index 6951c8c387..7b27a4c314 100644 --- a/src/qml/qml/qqmlcompiler.cpp +++ b/src/qml/qml/qqmlcompiler.cpp @@ -60,6 +60,7 @@ #include "qqmlscriptstring.h" #include "qqmlglobal_p.h" #include "qqmlbinding_p.h" +#include "qqmlabstracturlinterceptor_p.h" #include <private/qv4compiler_p.h> #include <QDebug> @@ -517,6 +518,10 @@ void QQmlCompiler::genLiteralAssignment(QQmlScript::Property *prop, // Encoded dir-separators defeat QUrl processing - decode them first string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive); QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string)); + // Apply URL interceptor + if (engine->urlInterceptor()) + u = engine->urlInterceptor()->intercept(u, + QQmlAbstractUrlInterceptor::UrlString); instr.propertyIndex = prop->index; instr.value = output->indexForUrl(u); output->addInstruction(instr); diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp index e0a16d1f44..7fa2472335 100644 --- a/src/qml/qml/qqmlcontext.cpp +++ b/src/qml/qml/qqmlcontext.cpp @@ -48,6 +48,7 @@ #include "qqmlengine_p.h" #include "qqmlengine.h" #include "qqmlinfo.h" +#include "qqmlabstracturlinterceptor_p.h" #include <private/qv4bindings_p.h> #include <private/qv8bindings_p.h> @@ -431,6 +432,7 @@ QUrl QQmlContextData::resolvedUrl(const QUrl &src) { QQmlContextData *ctxt = this; + QUrl resolved; if (src.isRelative() && !src.isEmpty()) { if (ctxt) { while(ctxt) { @@ -441,14 +443,20 @@ QUrl QQmlContextData::resolvedUrl(const QUrl &src) } if (ctxt) - return ctxt->url.resolved(src); + resolved = ctxt->url.resolved(src); else if (engine) - return engine->baseUrl().resolved(src); + resolved = engine->baseUrl().resolved(src); } - return QUrl(); } else { - return src; + resolved = src; } + + if (resolved.isEmpty()) //relative but no ctxt + return resolved; + + if (engine && engine->urlInterceptor()) + resolved = engine->urlInterceptor()->intercept(resolved, QQmlAbstractUrlInterceptor::UrlString); + return resolved; } diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 1c3aff6892..9d2ad8c4c3 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -66,6 +66,7 @@ #include <private/qv8debugservice_p.h> #include <private/qdebugmessageservice_p.h> #include "qqmlincubator.h" +#include "qqmlabstracturlinterceptor_p.h" #include <private/qv8profilerservice_p.h> #include <private/qqmlboundsignal_p.h> @@ -509,7 +510,7 @@ QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e) outputWarningsToStdErr(true), sharedContext(0), sharedScope(0), cleanup(0), erroredBindings(0), inProgressCreations(0), workerScriptEngine(0), activeVME(0), - networkAccessManager(0), networkAccessManagerFactory(0), + networkAccessManager(0), networkAccessManagerFactory(0), urlInterceptor(0), scarceResourcesRefCount(0), typeLoader(e), importDatabase(e), uniqueId(1), incubatorCount(0), incubationController(0), mutex(QMutex::Recursive) { @@ -925,6 +926,35 @@ QQmlContext *QQmlEngine::rootContext() const } /*! + \internal + This API is private for 5.1 + + Sets the \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. +*/ +void QQmlEngine::setUrlInterceptor(QQmlAbstractUrlInterceptor *urlInterceptor) +{ + Q_D(QQmlEngine); + d->urlInterceptor = urlInterceptor; +} + +/*! + \internal + This API is private for 5.1 + + Returns the current QQmlAbstractUrlInterceptor. It must not be modified outside + the GUI thread. +*/ +QQmlAbstractUrlInterceptor *QQmlEngine::urlInterceptor() const +{ + Q_D(const QQmlEngine); + return d->urlInterceptor; +} + + +/*! Sets the \a factory to use for creating QNetworkAccessManager(s). QNetworkAccessManager is used for all network access by QML. By diff --git a/src/qml/qml/qqmlengine.h b/src/qml/qml/qqmlengine.h index 45826a4a67..ab25e06235 100644 --- a/src/qml/qml/qqmlengine.h +++ b/src/qml/qml/qqmlengine.h @@ -51,6 +51,7 @@ QT_BEGIN_NAMESPACE +class QQmlAbstractUrlInterceptor; class Q_QML_EXPORT QQmlImageProviderBase { @@ -119,6 +120,9 @@ public: QNetworkAccessManager *networkAccessManager() const; + void setUrlInterceptor(QQmlAbstractUrlInterceptor* urlInterceptor); + QQmlAbstractUrlInterceptor* urlInterceptor() const; + void addImageProvider(const QString &id, QQmlImageProviderBase *); QQmlImageProviderBase *imageProvider(const QString &id) const; void removeImageProvider(const QString &id); diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index b5af0bb7cd..b745d6a963 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -173,6 +173,8 @@ public: QHash<QString,QSharedPointer<QQmlImageProviderBase> > imageProviders; + QQmlAbstractUrlInterceptor* urlInterceptor; + // Scarce resources are "exceptionally high cost" QVariant types where allowing the // normal JavaScript GC to clean them up is likely to lead to out-of-memory or other // out-of-resource situations. When such a resource is passed into JavaScript we diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index bbce8e625e..8d8503f344 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qqmltypeloader_p.h" +#include "qqmlabstracturlinterceptor_p.h" #include <private/qqmlengine_p.h> #include <private/qqmlglobal_p.h> @@ -250,6 +251,23 @@ QQmlDataBlob::~QQmlDataBlob() } /*! + Sets the manager, and does stuff like selection which needs access to the manager. + Must be called before loading can occur. +*/ +void QQmlDataBlob::startLoading(QQmlDataLoader *manager) +{ + Q_ASSERT(status() == QQmlDataBlob::Null); + Q_ASSERT(m_manager == 0); + m_data.setStatus(QQmlDataBlob::Loading); + m_manager = manager; + + //Set here because we need to get the engine from the manager + if (manager && manager->engine() && manager->engine()->urlInterceptor()) + m_url = manager->engine()->urlInterceptor()->intercept(m_url, + (QQmlAbstractUrlInterceptor::DataType)m_type); +} + +/*! Returns the type provided to the constructor. */ QQmlDataBlob::Type QQmlDataBlob::type() const @@ -892,12 +910,7 @@ void QQmlDataLoader::load(QQmlDataBlob *blob, Mode mode) qWarning("QQmlDataLoader::load(%s): %s thread", qPrintable(blob->m_url.toString()), m_thread->isThisThread()?"Compile":"Engine"); #endif - - Q_ASSERT(blob->status() == QQmlDataBlob::Null); - Q_ASSERT(blob->m_manager == 0); - - blob->m_data.setStatus(QQmlDataBlob::Loading); - blob->m_manager = this; + blob->startLoading(this); if (m_thread->isThisThread()) { unlock(); @@ -930,11 +943,7 @@ void QQmlDataLoader::loadWithStaticData(QQmlDataBlob *blob, const QByteArray &da m_thread->isThisThread()?"Compile":"Engine"); #endif - Q_ASSERT(blob->status() == QQmlDataBlob::Null); - Q_ASSERT(blob->m_manager == 0); - - blob->m_data.setStatus(QQmlDataBlob::Loading); - blob->m_manager = this; + blob->startLoading(this); if (m_thread->isThisThread()) { unlock(); diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index 68b8f33f88..1bd07661f7 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -68,6 +68,7 @@ #include <private/qqmldirparser_p.h> #include <private/qqmlbundle_p.h> #include <private/qflagpointer_p.h> +#include <private/qqmlabstracturlinterceptor_p.h> QT_BEGIN_NAMESPACE @@ -92,15 +93,17 @@ public: Error // Error }; - enum Type { - QmlFile, - JavaScriptFile, - QmldirFile + enum Type { //Matched in QQmlAbstractUrlInterceptor + QmlFile = QQmlAbstractUrlInterceptor::QmlFile, + JavaScriptFile = QQmlAbstractUrlInterceptor::JavaScriptFile, + QmldirFile = QQmlAbstractUrlInterceptor::QmldirFile }; QQmlDataBlob(const QUrl &, Type); virtual ~QQmlDataBlob(); + void startLoading(QQmlDataLoader* manager); + Type type() const; Status status() const; |