aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Alpert <aalpert@rim.com>2013-02-28 17:03:43 -0800
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-05-07 19:41:26 +0200
commit223313479bf8ec80158ba0f6cba4dd5e74d92718 (patch)
treebc39fb195736657dec6a09106ad9609253074d77
parent40d90b50c555a968f1ae540527199042fbcf1a32 (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>
-rw-r--r--src/qml/qml/qml.pri2
-rw-r--r--src/qml/qml/qqmlabstracturlinterceptor.cpp91
-rw-r--r--src/qml/qml/qqmlabstracturlinterceptor_p.h66
-rw-r--r--src/qml/qml/qqmlcompiler.cpp5
-rw-r--r--src/qml/qml/qqmlcontext.cpp16
-rw-r--r--src/qml/qml/qqmlengine.cpp32
-rw-r--r--src/qml/qml/qqmlengine.h4
-rw-r--r--src/qml/qml/qqmlengine_p.h2
-rw-r--r--src/qml/qml/qqmltypeloader.cpp31
-rw-r--r--src/qml/qml/qqmltypeloader_p.h11
-rw-r--r--tests/auto/qml/qqmlengine/data/interception/qmldir/Intercepted.qml5
-rw-r--r--tests/auto/qml/qqmlengine/data/interception/qmldir/intercepted.js1
-rw-r--r--tests/auto/qml/qqmlengine/data/interception/qmldir/intercepted/Intercepted.qml6
-rw-r--r--tests/auto/qml/qqmlengine/data/interception/qmldir/intercepted/Intercepted2.qml5
-rw-r--r--tests/auto/qml/qqmlengine/data/interception/qmldir/intercepted/intercepted.js1
-rw-r--r--tests/auto/qml/qqmlengine/data/interception/qmldir/intercepted/urlInterceptor.qml11
-rw-r--r--tests/auto/qml/qqmlengine/data/interception/qmldir/urlInterceptor.qml12
-rw-r--r--tests/auto/qml/qqmlengine/data/interception/strings/Intercepted.qml5
-rw-r--r--tests/auto/qml/qqmlengine/data/interception/strings/intercepted.js1
-rw-r--r--tests/auto/qml/qqmlengine/data/interception/strings/intercepted/Intercepted.qml5
-rw-r--r--tests/auto/qml/qqmlengine/data/interception/strings/intercepted/intercepted.js1
-rw-r--r--tests/auto/qml/qqmlengine/data/interception/strings/intercepted/urlInterceptor.qml11
-rw-r--r--tests/auto/qml/qqmlengine/data/interception/strings/urlInterceptor.qml11
-rw-r--r--tests/auto/qml/qqmlengine/data/interception/types/Intercepted.qml5
-rw-r--r--tests/auto/qml/qqmlengine/data/interception/types/Intercepted2.qml5
-rw-r--r--tests/auto/qml/qqmlengine/data/interception/types/intercepted.js1
-rw-r--r--tests/auto/qml/qqmlengine/data/interception/types/intercepted/Intercepted.qml6
-rw-r--r--tests/auto/qml/qqmlengine/data/interception/types/intercepted/Intercepted2.qml5
-rw-r--r--tests/auto/qml/qqmlengine/data/interception/types/intercepted/intercepted.js1
-rw-r--r--tests/auto/qml/qqmlengine/data/interception/types/intercepted/urlInterceptor.qml11
-rw-r--r--tests/auto/qml/qqmlengine/data/interception/types/urlInterceptor.qml11
-rw-r--r--tests/auto/qml/qqmlengine/tst_qqmlengine.cpp96
32 files changed, 456 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;
diff --git a/tests/auto/qml/qqmlengine/data/interception/qmldir/Intercepted.qml b/tests/auto/qml/qqmlengine/data/interception/qmldir/Intercepted.qml
new file mode 100644
index 0000000000..0331a01ad4
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/interception/qmldir/Intercepted.qml
@@ -0,0 +1,5 @@
+import QtQml 2.0
+
+QtObject {
+ property string myStr: "intercepted"
+}
diff --git a/tests/auto/qml/qqmlengine/data/interception/qmldir/intercepted.js b/tests/auto/qml/qqmlengine/data/interception/qmldir/intercepted.js
new file mode 100644
index 0000000000..6f54ebcdc5
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/interception/qmldir/intercepted.js
@@ -0,0 +1 @@
+var myStr = "base file"
diff --git a/tests/auto/qml/qqmlengine/data/interception/qmldir/intercepted/Intercepted.qml b/tests/auto/qml/qqmlengine/data/interception/qmldir/intercepted/Intercepted.qml
new file mode 100644
index 0000000000..ef5c28f87b
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/interception/qmldir/intercepted/Intercepted.qml
@@ -0,0 +1,6 @@
+import QtQml 2.0
+
+QtObject {
+ property string myStr: "intercepted"
+ property Intercepted2 compilationIsTest: Intercepted2{}
+}
diff --git a/tests/auto/qml/qqmlengine/data/interception/qmldir/intercepted/Intercepted2.qml b/tests/auto/qml/qqmlengine/data/interception/qmldir/intercepted/Intercepted2.qml
new file mode 100644
index 0000000000..0331a01ad4
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/interception/qmldir/intercepted/Intercepted2.qml
@@ -0,0 +1,5 @@
+import QtQml 2.0
+
+QtObject {
+ property string myStr: "intercepted"
+}
diff --git a/tests/auto/qml/qqmlengine/data/interception/qmldir/intercepted/intercepted.js b/tests/auto/qml/qqmlengine/data/interception/qmldir/intercepted/intercepted.js
new file mode 100644
index 0000000000..6eeee6e72f
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/interception/qmldir/intercepted/intercepted.js
@@ -0,0 +1 @@
+var myStr = "intercepted"
diff --git a/tests/auto/qml/qqmlengine/data/interception/qmldir/intercepted/urlInterceptor.qml b/tests/auto/qml/qqmlengine/data/interception/qmldir/intercepted/urlInterceptor.qml
new file mode 100644
index 0000000000..bd4aee056a
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/interception/qmldir/intercepted/urlInterceptor.qml
@@ -0,0 +1,11 @@
+import QtQml 2.0
+import "intercepted.js" as Script
+
+QtObject {
+ property url filePath: "FailsTest"
+ property url resolvedUrl: Qt.resolvedUrl("FailsTest");
+ property url absoluteUrl: Qt.resolvedUrl("file:///FailsTest");
+ property string childString: child.myStr
+ property string scriptString: Script.myStr
+ property Intercepted child: Intercepted {}
+}
diff --git a/tests/auto/qml/qqmlengine/data/interception/qmldir/urlInterceptor.qml b/tests/auto/qml/qqmlengine/data/interception/qmldir/urlInterceptor.qml
new file mode 100644
index 0000000000..22a09e5522
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/interception/qmldir/urlInterceptor.qml
@@ -0,0 +1,12 @@
+import QtQml 2.0
+import "."
+import "intercepted.js" as Script
+
+QtObject {
+ property url filePath: "doesNotExist.file"
+ property url resolvedUrl: Qt.resolvedUrl("doesNotExist.file");
+ property url absoluteUrl: Qt.resolvedUrl("file:///doesNotExist.file");
+ property string childString: child.myStr
+ property string scriptString: Script.myStr
+ property Intercepted child: Intercepted {}
+}
diff --git a/tests/auto/qml/qqmlengine/data/interception/strings/Intercepted.qml b/tests/auto/qml/qqmlengine/data/interception/strings/Intercepted.qml
new file mode 100644
index 0000000000..449207e0e3
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/interception/strings/Intercepted.qml
@@ -0,0 +1,5 @@
+import QtQml 2.0
+
+QtObject {
+ property string myStr: "base file"
+}
diff --git a/tests/auto/qml/qqmlengine/data/interception/strings/intercepted.js b/tests/auto/qml/qqmlengine/data/interception/strings/intercepted.js
new file mode 100644
index 0000000000..6f54ebcdc5
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/interception/strings/intercepted.js
@@ -0,0 +1 @@
+var myStr = "base file"
diff --git a/tests/auto/qml/qqmlengine/data/interception/strings/intercepted/Intercepted.qml b/tests/auto/qml/qqmlengine/data/interception/strings/intercepted/Intercepted.qml
new file mode 100644
index 0000000000..0331a01ad4
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/interception/strings/intercepted/Intercepted.qml
@@ -0,0 +1,5 @@
+import QtQml 2.0
+
+QtObject {
+ property string myStr: "intercepted"
+}
diff --git a/tests/auto/qml/qqmlengine/data/interception/strings/intercepted/intercepted.js b/tests/auto/qml/qqmlengine/data/interception/strings/intercepted/intercepted.js
new file mode 100644
index 0000000000..6eeee6e72f
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/interception/strings/intercepted/intercepted.js
@@ -0,0 +1 @@
+var myStr = "intercepted"
diff --git a/tests/auto/qml/qqmlengine/data/interception/strings/intercepted/urlInterceptor.qml b/tests/auto/qml/qqmlengine/data/interception/strings/intercepted/urlInterceptor.qml
new file mode 100644
index 0000000000..bd4aee056a
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/interception/strings/intercepted/urlInterceptor.qml
@@ -0,0 +1,11 @@
+import QtQml 2.0
+import "intercepted.js" as Script
+
+QtObject {
+ property url filePath: "FailsTest"
+ property url resolvedUrl: Qt.resolvedUrl("FailsTest");
+ property url absoluteUrl: Qt.resolvedUrl("file:///FailsTest");
+ property string childString: child.myStr
+ property string scriptString: Script.myStr
+ property Intercepted child: Intercepted {}
+}
diff --git a/tests/auto/qml/qqmlengine/data/interception/strings/urlInterceptor.qml b/tests/auto/qml/qqmlengine/data/interception/strings/urlInterceptor.qml
new file mode 100644
index 0000000000..be86195bd8
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/interception/strings/urlInterceptor.qml
@@ -0,0 +1,11 @@
+import QtQml 2.0
+import "intercepted.js" as Script
+
+QtObject {
+ property url filePath: "doesNotExist.file"
+ property url resolvedUrl: Qt.resolvedUrl("doesNotExist.file");
+ property url absoluteUrl: Qt.resolvedUrl("file:///doesNotExist.file");
+ property string childString: child.myStr
+ property string scriptString: Script.myStr
+ property Intercepted child: Intercepted {}
+}
diff --git a/tests/auto/qml/qqmlengine/data/interception/types/Intercepted.qml b/tests/auto/qml/qqmlengine/data/interception/types/Intercepted.qml
new file mode 100644
index 0000000000..449207e0e3
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/interception/types/Intercepted.qml
@@ -0,0 +1,5 @@
+import QtQml 2.0
+
+QtObject {
+ property string myStr: "base file"
+}
diff --git a/tests/auto/qml/qqmlengine/data/interception/types/Intercepted2.qml b/tests/auto/qml/qqmlengine/data/interception/types/Intercepted2.qml
new file mode 100644
index 0000000000..0331a01ad4
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/interception/types/Intercepted2.qml
@@ -0,0 +1,5 @@
+import QtQml 2.0
+
+QtObject {
+ property string myStr: "intercepted"
+}
diff --git a/tests/auto/qml/qqmlengine/data/interception/types/intercepted.js b/tests/auto/qml/qqmlengine/data/interception/types/intercepted.js
new file mode 100644
index 0000000000..6f54ebcdc5
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/interception/types/intercepted.js
@@ -0,0 +1 @@
+var myStr = "base file"
diff --git a/tests/auto/qml/qqmlengine/data/interception/types/intercepted/Intercepted.qml b/tests/auto/qml/qqmlengine/data/interception/types/intercepted/Intercepted.qml
new file mode 100644
index 0000000000..ef5c28f87b
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/interception/types/intercepted/Intercepted.qml
@@ -0,0 +1,6 @@
+import QtQml 2.0
+
+QtObject {
+ property string myStr: "intercepted"
+ property Intercepted2 compilationIsTest: Intercepted2{}
+}
diff --git a/tests/auto/qml/qqmlengine/data/interception/types/intercepted/Intercepted2.qml b/tests/auto/qml/qqmlengine/data/interception/types/intercepted/Intercepted2.qml
new file mode 100644
index 0000000000..0331a01ad4
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/interception/types/intercepted/Intercepted2.qml
@@ -0,0 +1,5 @@
+import QtQml 2.0
+
+QtObject {
+ property string myStr: "intercepted"
+}
diff --git a/tests/auto/qml/qqmlengine/data/interception/types/intercepted/intercepted.js b/tests/auto/qml/qqmlengine/data/interception/types/intercepted/intercepted.js
new file mode 100644
index 0000000000..6eeee6e72f
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/interception/types/intercepted/intercepted.js
@@ -0,0 +1 @@
+var myStr = "intercepted"
diff --git a/tests/auto/qml/qqmlengine/data/interception/types/intercepted/urlInterceptor.qml b/tests/auto/qml/qqmlengine/data/interception/types/intercepted/urlInterceptor.qml
new file mode 100644
index 0000000000..be86195bd8
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/interception/types/intercepted/urlInterceptor.qml
@@ -0,0 +1,11 @@
+import QtQml 2.0
+import "intercepted.js" as Script
+
+QtObject {
+ property url filePath: "doesNotExist.file"
+ property url resolvedUrl: Qt.resolvedUrl("doesNotExist.file");
+ property url absoluteUrl: Qt.resolvedUrl("file:///doesNotExist.file");
+ property string childString: child.myStr
+ property string scriptString: Script.myStr
+ property Intercepted child: Intercepted {}
+}
diff --git a/tests/auto/qml/qqmlengine/data/interception/types/urlInterceptor.qml b/tests/auto/qml/qqmlengine/data/interception/types/urlInterceptor.qml
new file mode 100644
index 0000000000..bd4aee056a
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/interception/types/urlInterceptor.qml
@@ -0,0 +1,11 @@
+import QtQml 2.0
+import "intercepted.js" as Script
+
+QtObject {
+ property url filePath: "FailsTest"
+ property url resolvedUrl: Qt.resolvedUrl("FailsTest");
+ property url absoluteUrl: Qt.resolvedUrl("file:///FailsTest");
+ property string childString: child.myStr
+ property string scriptString: Script.myStr
+ property Intercepted child: Intercepted {}
+}
diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
index 9177ff58f7..d604118b58 100644
--- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
+++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
@@ -54,6 +54,7 @@
#include <QQmlExpression>
#include <QQmlIncubationController>
#include <private/qqmlengine_p.h>
+#include <private/qqmlabstracturlinterceptor_p.h>
class tst_qqmlengine : public QQmlDataTest
{
@@ -79,6 +80,8 @@ private slots:
void multipleEngines();
void qtqmlModule_data();
void qtqmlModule();
+ void urlInterceptor_data();
+ void urlInterceptor();
public slots:
QObject *createAQObjectForOwnershipTest ()
@@ -674,6 +677,99 @@ void tst_qqmlengine::qtqmlModule()
}
}
+class CustomSelector : public QQmlAbstractUrlInterceptor
+{
+public:
+ virtual QUrl intercept(const QUrl &url, QQmlAbstractUrlInterceptor::DataType d)
+ {
+ if (url.scheme() != QStringLiteral("file"))
+ return url;
+ if (!m_interceptionPoints.contains(d))
+ return url;
+
+ QString alteredPath = url.path();
+ int a = alteredPath.lastIndexOf('/');
+ if (a < 0)
+ a = 0;
+ alteredPath.insert(a, QStringLiteral("/intercepted"));
+
+ QUrl ret = url;
+ ret.setPath(alteredPath);
+ return ret;
+ }
+ QList<QQmlAbstractUrlInterceptor::DataType> m_interceptionPoints;
+};
+
+Q_DECLARE_METATYPE(QList<QQmlAbstractUrlInterceptor::DataType>);
+void tst_qqmlengine::urlInterceptor_data()
+{
+ QTest::addColumn<QUrl>("testFile");
+ QTest::addColumn<QList<QQmlAbstractUrlInterceptor::DataType> >("interceptionPoint");
+ QTest::addColumn<QString>("expectedFilePath");
+ QTest::addColumn<QString>("expectedChildString");
+ QTest::addColumn<QString>("expectedScriptString");
+ QTest::addColumn<QString>("expectedResolvedUrl");
+ QTest::addColumn<QString>("expectedAbsoluteUrl");
+
+ QTest::newRow("InterceptTypes")
+ << testFileUrl("interception/types/urlInterceptor.qml")
+ << (QList<QQmlAbstractUrlInterceptor::DataType>() << QQmlAbstractUrlInterceptor::QmlFile << QQmlAbstractUrlInterceptor::JavaScriptFile << QQmlAbstractUrlInterceptor::UrlString)
+ << testFileUrl("interception/types/intercepted/doesNotExist.file").toString()
+ << QStringLiteral("intercepted")
+ << QStringLiteral("intercepted")
+ << testFileUrl("interception/types/intercepted/doesNotExist.file").toString()
+ << QStringLiteral("file:///intercepted/doesNotExist.file");
+
+ QTest::newRow("InterceptQmlDir")
+ << testFileUrl("interception/qmldir/urlInterceptor.qml")
+ << (QList<QQmlAbstractUrlInterceptor::DataType>() << QQmlAbstractUrlInterceptor::QmldirFile << QQmlAbstractUrlInterceptor::UrlString)
+ << testFileUrl("interception/qmldir/intercepted/doesNotExist.file").toString()
+ << QStringLiteral("intercepted")
+ << QStringLiteral("base file")
+ << testFileUrl("interception/qmldir/intercepted/doesNotExist.file").toString()
+ << QStringLiteral("file:///intercepted/doesNotExist.file");
+
+ QTest::newRow("InterceptStrings")
+ << testFileUrl("interception/strings/urlInterceptor.qml")
+ << (QList<QQmlAbstractUrlInterceptor::DataType>() << QQmlAbstractUrlInterceptor::UrlString)
+ << testFileUrl("interception/strings/intercepted/doesNotExist.file").toString()
+ << QStringLiteral("base file")
+ << QStringLiteral("base file")
+ << testFileUrl("interception/strings/intercepted/doesNotExist.file").toString()
+ << QStringLiteral("file:///intercepted/doesNotExist.file");
+}
+
+void tst_qqmlengine::urlInterceptor()
+{
+
+ QFETCH(QUrl, testFile);
+ QFETCH(QList<QQmlAbstractUrlInterceptor::DataType>, interceptionPoint);
+ QFETCH(QString, expectedFilePath);
+ QFETCH(QString, expectedChildString);
+ QFETCH(QString, expectedScriptString);
+ QFETCH(QString, expectedResolvedUrl);
+ QFETCH(QString, expectedAbsoluteUrl);
+
+ QQmlEngine e;
+ CustomSelector cs;
+ cs.m_interceptionPoints = interceptionPoint;
+ e.setUrlInterceptor(&cs);
+ QQmlComponent c(&e, testFile); //Note that this can get intercepted too
+ QObject *o = c.create();
+ if (!o)
+ qDebug() << c.errorString();
+ QVERIFY(o);
+ //Test a URL as a property initialization
+ QCOMPARE(o->property("filePath").toString(), expectedFilePath);
+ //Test a URL as a Type location
+ QCOMPARE(o->property("childString").toString(), expectedChildString);
+ //Test a URL as a Script location
+ QCOMPARE(o->property("scriptString").toString(), expectedScriptString);
+ //Test a URL as a resolveUrl() call
+ QCOMPARE(o->property("resolvedUrl").toString(), expectedResolvedUrl);
+ QCOMPARE(o->property("absoluteUrl").toString(), expectedAbsoluteUrl);
+}
+
QTEST_MAIN(tst_qqmlengine)
#include "tst_qqmlengine.moc"