diff options
-rw-r--r-- | examples/quick/demos/photosurface/photosurface.qml | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmlimport.cpp | 31 | ||||
-rw-r--r-- | src/qml/qml/qqmlimport_p.h | 1 | ||||
-rw-r--r-- | src/qml/qml/qqmltypeloader.cpp | 48 | ||||
-rw-r--r-- | src/quick/items/qquickflickable.cpp | 16 | ||||
-rw-r--r-- | src/quick/items/qquickitemsmodule.cpp | 3 | ||||
-rw-r--r-- | src/quick/items/qquickmultipointtoucharea.cpp | 37 | ||||
-rw-r--r-- | src/quick/items/qquickopenglshadereffect.cpp | 2 | ||||
-rw-r--r-- | src/quick/util/qquickanimatorcontroller.cpp | 4 | ||||
-rw-r--r-- | src/quick/util/qquickshortcut.cpp | 3 | ||||
-rw-r--r-- | tests/auto/qml/qqmltypeloader/data/Intercept.qml | 41 | ||||
-rw-r--r-- | tests/auto/qml/qqmltypeloader/data/test_intercept.qml | 53 | ||||
-rw-r--r-- | tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp | 201 | ||||
-rw-r--r-- | tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp | 6 | ||||
-rw-r--r-- | tests/auto/quick/qquicklistview/tst_qquicklistview.cpp | 17 | ||||
-rw-r--r-- | tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp | 8 | ||||
-rw-r--r-- | tests/auto/quick/quick.pro | 2 |
17 files changed, 435 insertions, 42 deletions
diff --git a/examples/quick/demos/photosurface/photosurface.qml b/examples/quick/demos/photosurface/photosurface.qml index 8057bb8400..5d1445d776 100644 --- a/examples/quick/demos/photosurface/photosurface.qml +++ b/examples/quick/demos/photosurface/photosurface.qml @@ -181,7 +181,7 @@ Window { radius: 2 antialiasing: true height: flick.height * (flick.height / flick.contentHeight) - (width - anchors.margins) * 2 - y: flick.contentY * (flick.height / flick.contentHeight) + y: (flick.contentY - flick.originY) * (flick.height / flick.contentHeight) NumberAnimation on opacity { id: vfade; to: 0; duration: 500 } onYChanged: { opacity = 1.0; scrollFadeTimer.restart() } } @@ -197,7 +197,7 @@ Window { radius: 2 antialiasing: true width: flick.width * (flick.width / flick.contentWidth) - (height - anchors.margins) * 2 - x: flick.contentX * (flick.width / flick.contentWidth) + x: (flick.contentX - flick.originY) * (flick.width / flick.contentWidth) NumberAnimation on opacity { id: hfade; to: 0; duration: 500 } onXChanged: { opacity = 1.0; scrollFadeTimer.restart() } } diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index 4e3b25070f..c8d17c4b8e 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -1266,11 +1266,20 @@ bool QQmlImportsPrivate::locateQmldir(const QString &uri, int vmaj, int vmin, QQ QQmlTypeLoader &typeLoader = QQmlEnginePrivate::get(database->engine)->typeLoader; - QStringList localImportPaths = database->importPathList(QQmlImportDatabase::Local); + // Interceptor might redirect remote files to local ones. + QQmlAbstractUrlInterceptor *interceptor = typeLoader.engine()->urlInterceptor(); + QStringList localImportPaths = database->importPathList( + interceptor ? QQmlImportDatabase::LocalOrRemote : QQmlImportDatabase::Local); // Search local import paths for a matching version const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(uri, localImportPaths, vmaj, vmin); - for (const QString &qmldirPath : qmlDirPaths) { + for (QString qmldirPath : qmlDirPaths) { + if (interceptor) { + qmldirPath = QQmlFile::urlToLocalFileOrQrc( + interceptor->intercept(QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath), + QQmlAbstractUrlInterceptor::QmldirFile)); + } + QString absoluteFilePath = typeLoader.absoluteFilePath(qmldirPath); if (!absoluteFilePath.isEmpty()) { QString url; @@ -1479,6 +1488,10 @@ 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(); + } QString qmldirIdentifier; if (QQmlFile::isLocalFile(qmldirUrl)) { @@ -1564,8 +1577,8 @@ bool QQmlImportsPrivate::updateQmldirContent(const QString &uri, const QString & if (import->setQmldirContent(qmldirUrl, qmldir, nameSpace, errors)) { if (import->qmlDirComponents.isEmpty() && import->qmlDirScripts.isEmpty()) { - // The implicit import qmldir can be empty - if (uri != QLatin1String(".")) { + // The implicit import qmldir can be empty, and plugins have no extra versions + if (uri != QLatin1String(".") && !QQmlMetaType::isModule(uri, vmaj, vmin)) { QQmlError error; if (QQmlMetaType::isAnyModule(uri)) error.setDescription(QQmlImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri).arg(vmaj).arg(vmin)); @@ -1693,6 +1706,16 @@ bool QQmlImports::isLocal(const QUrl &url) return !QQmlFile::urlToLocalFileOrQrc(url).isEmpty(); } +QUrl QQmlImports::urlFromLocalFileOrQrcOrUrl(const QString &file) +{ + QUrl url(QLatin1String(file.at(0) == Colon ? "qrc" : "") + file); + + // We don't support single character schemes as those conflict with windows drive letters. + if (url.scheme().length() < 2) + return QUrl::fromLocalFile(file); + return url; +} + void QQmlImports::setDesignerSupportRequired(bool b) { designerSupportRequired = b; diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h index 1bdd287690..9cb5340c68 100644 --- a/src/qml/qml/qqmlimport_p.h +++ b/src/qml/qml/qqmlimport_p.h @@ -184,6 +184,7 @@ public: static bool isLocal(const QString &url); static bool isLocal(const QUrl &url); + static QUrl urlFromLocalFileOrQrcOrUrl(const QString &); static void setDesignerSupportRequired(bool b); diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 842cf74887..f3077f673b 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -1436,8 +1436,13 @@ bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QL // We haven't yet resolved this import m_unresolvedImports.insert(import, 0); - // Query any network import paths for this library - QStringList remotePathList = importDatabase->importPathList(QQmlImportDatabase::Remote); + QQmlAbstractUrlInterceptor *interceptor = typeLoader()->engine()->urlInterceptor(); + + // Query any network import paths for this library. + // Interceptor might redirect local paths. + QStringList remotePathList = importDatabase->importPathList( + interceptor ? QQmlImportDatabase::LocalOrRemote + : QQmlImportDatabase::Remote); if (!remotePathList.isEmpty()) { // Add this library and request the possible locations for it if (!m_importCache.addLibraryImport(importDatabase, importUri, importQualifier, import->majorVersion, @@ -1448,8 +1453,18 @@ bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QL int priority = 0; const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(importUri, remotePathList, import->majorVersion, import->minorVersion); for (const QString &qmldirPath : qmlDirPaths) { - if (!fetchQmldir(QUrl(qmldirPath), import, ++priority, errors)) + if (interceptor) { + QUrl url = interceptor->intercept( + QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath), + QQmlAbstractUrlInterceptor::QmldirFile); + if (!QQmlFile::isLocalFile(url) + && !fetchQmldir(url, import, ++priority, errors)) { + return false; + } + } else if (!fetchQmldir(QUrl(qmldirPath), import, ++priority, errors)) { return false; + } + } } } @@ -1872,19 +1887,22 @@ It can also be a remote path for a remote directory import, but it will have bee */ const QQmlTypeLoaderQmldirContent *QQmlTypeLoader::qmldirContent(const QString &filePathIn) { - QUrl url(filePathIn); //May already contain http scheme - if (url.scheme() == QLatin1String("http") || url.scheme() == QLatin1String("https")) - return *(m_importQmlDirCache.value(filePathIn)); //Can't load the remote here, but should be cached - else - url = QUrl::fromLocalFile(filePathIn); - if (engine() && engine()->urlInterceptor()) - url = engine()->urlInterceptor()->intercept(url, QQmlAbstractUrlInterceptor::QmldirFile); - Q_ASSERT(url.scheme() == QLatin1String("file")); QString filePath; - if (url.scheme() == QLatin1String("file")) - filePath = url.toLocalFile(); - else - filePath = url.path(); + + // Try to guess if filePathIn is already a URL. This is necessarily fragile, because + // - paths can contain ':', which might make them appear as URLs with schemes. + // - windows drive letters appear as schemes (thus "< 2" below). + // - a "file:" URL is equivalent to the respective file, but will be treated differently. + // Yet, this heuristic is the best we can do until we pass more structured information here, + // for example a QUrl also for local files. + QUrl url(filePathIn); + if (url.scheme().length() < 2) { + filePath = filePathIn; + } else { + filePath = QQmlFile::urlToLocalFileOrQrc(url); + if (filePath.isEmpty()) // Can't load the remote here, but should be cached + return *(m_importQmlDirCache.value(filePathIn)); + } QQmlTypeLoaderQmldirContent *qmldir; QQmlTypeLoaderQmldirContent **val = m_importQmlDirCache.value(filePath); diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index e0f8b6de00..3662827973 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -734,7 +734,19 @@ QQuickFlickable::~QQuickFlickable() These properties hold the surface coordinate currently at the top-left corner of the Flickable. For example, if you flick an image up 100 pixels, - \c contentY will be 100. + \c contentY will increase by 100. + + \note If you flick back to the origin (the top-left corner), after the + rebound animation, \c contentX will settle to the same value as \c originX, + and \c contentY to \c originY. These are usually (0,0), however ListView + and GridView may have an arbitrary origin due to delegate size variation, + or item insertion/removal outside the visible region. So if you want to + implement something like a vertical scrollbar, one way is to use + \c {y: (contentY - originY) * (height / contentHeight)} + for the position; another way is to use the normalized values in + \l {QtQuick::Flickable::visibleArea}{visibleArea}. + + \sa originX, originY */ qreal QQuickFlickable::contentX() const { @@ -2153,6 +2165,8 @@ void QQuickFlickable::setRightMargin(qreal m) This is usually (0,0), however ListView and GridView may have an arbitrary origin due to delegate size variation, or item insertion/removal outside the visible region. + + \sa contentX, contentY */ qreal QQuickFlickable::originY() const diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index 5f6d44b54d..489b1cbd03 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -287,7 +287,8 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) qmlRegisterType<QQuickMultiPointTouchArea>("QtQuick", 2, 0, "MultiPointTouchArea"); qmlRegisterType<QQuickTouchPoint>("QtQuick", 2, 0, "TouchPoint"); - qmlRegisterType<QQuickGrabGestureEvent>(); + qmlRegisterUncreatableType<QQuickGrabGestureEvent>(uri,major,minor, "GestureEvent", + QQuickMouseEvent::tr("GestureEvent is only available in the context of handling the gestureStarted signal from MultiPointTouchArea")); #if QT_CONFIG(accessibility) qmlRegisterUncreatableType<QQuickAccessibleAttached>("QtQuick", 2, 0, "Accessible",QQuickAccessibleAttached::tr("Accessible is only available via attached properties")); diff --git a/src/quick/items/qquickmultipointtoucharea.cpp b/src/quick/items/qquickmultipointtoucharea.cpp index d4c447a384..8866ca2be5 100644 --- a/src/quick/items/qquickmultipointtoucharea.cpp +++ b/src/quick/items/qquickmultipointtoucharea.cpp @@ -285,6 +285,43 @@ void QQuickTouchPoint::setUniqueId(const QPointingDeviceUniqueId &id) emit uniqueIdChanged(); } + +/*! + \qmltype GestureEvent + \instantiates QQuickGrabGestureEvent + \inqmlmodule QtQuick + \ingroup qtquick-input-events + \brief The parameter given with the gestureStarted signal + + The GestureEvent object has the current touch points, which you may choose + to interpret as a gesture, and an invokable method to grab the involved + points exclusively. +*/ + +/*! + \qmlproperty real QtQuick::GestureEvent::dragThreshold + + This property holds the system setting for the distance a finger must move + before it is interpreted as a drag. It comes from + QStyleHints::startDragDistance(). +*/ + +/*! + \qmlproperty list<TouchPoint> QtQuick::GestureEvent::touchPoints + + This property holds the set of current touch points. +*/ + +/*! + \qmlmethod QtQuick::GestureEvent::grab() + + Acquires an exclusive grab of the mouse and all the \l touchPoints, and + calls \l {QQuickItem::setKeepTouchGrab()}{setKeepTouchGrab()} and + \l {QQuickItem::setKeepMouseGrab()}{setKeepMouseGrab()} so that any + parent Item that \l {QQuickItem::filtersChildMouseEvents()}{filters} its + children's events will not be allowed to take over the grabs. +*/ + /*! \qmltype MultiPointTouchArea \instantiates QQuickMultiPointTouchArea diff --git a/src/quick/items/qquickopenglshadereffect.cpp b/src/quick/items/qquickopenglshadereffect.cpp index 4fcfe04b55..193478484e 100644 --- a/src/quick/items/qquickopenglshadereffect.cpp +++ b/src/quick/items/qquickopenglshadereffect.cpp @@ -890,7 +890,7 @@ QSGNode *QQuickOpenGLShaderEffect::handleUpdatePaintNode(QSGNode *oldNode, QQuic bool geometryUsesTextureSubRect = false; if (m_supportsAtlasTextures && material->textureProviders.size() == 1) { QSGTextureProvider *provider = material->textureProviders.at(0); - if (provider->texture()) { + if (provider && provider->texture()) { srcRect = provider->texture()->normalizedTextureSubRect(); geometryUsesTextureSubRect = true; } diff --git a/src/quick/util/qquickanimatorcontroller.cpp b/src/quick/util/qquickanimatorcontroller.cpp index 3f7347c01d..5cf8051922 100644 --- a/src/quick/util/qquickanimatorcontroller.cpp +++ b/src/quick/util/qquickanimatorcontroller.cpp @@ -123,8 +123,10 @@ static void qquickanimator_sync_before_start(QAbstractAnimationJob *job) void QQuickAnimatorController::beforeNodeSync() { - for (const QSharedPointer<QAbstractAnimationJob> &toStop : qAsConst(m_rootsPendingStop)) + for (const QSharedPointer<QAbstractAnimationJob> &toStop : qAsConst(m_rootsPendingStop)) { toStop->stop(); + m_animationRoots.remove(toStop.data()); + } m_rootsPendingStop.clear(); diff --git a/src/quick/util/qquickshortcut.cpp b/src/quick/util/qquickshortcut.cpp index 2fe4962b1a..58f7fc8439 100644 --- a/src/quick/util/qquickshortcut.cpp +++ b/src/quick/util/qquickshortcut.cpp @@ -41,6 +41,7 @@ #include <QtQuick/qquickitem.h> #include <QtQuick/qquickwindow.h> +#include <QtQuick/qquickrendercontrol.h> #include <QtQuick/private/qtquickglobal_p.h> #include <QtGui/private/qguiapplication_p.h> @@ -102,6 +103,8 @@ static bool qQuickShortcutContextMatcher(QObject *obj, Qt::ShortcutContext conte if (QQuickItem *item = qobject_cast<QQuickItem *>(obj)) obj = item->window(); } + if (QWindow *renderWindow = QQuickRenderControl::renderWindowFor(qobject_cast<QQuickWindow *>(obj))) + obj = renderWindow; return obj && obj == QGuiApplication::focusWindow(); default: return false; diff --git a/tests/auto/qml/qqmltypeloader/data/Intercept.qml b/tests/auto/qml/qqmltypeloader/data/Intercept.qml new file mode 100644 index 0000000000..b557b4b941 --- /dev/null +++ b/tests/auto/qml/qqmltypeloader/data/Intercept.qml @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** 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-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import Fast 1.0 + +Item { + Rectangle { + color: "red" + width: 100 + height: 100 + } + Fast { + + } +} diff --git a/tests/auto/qml/qqmltypeloader/data/test_intercept.qml b/tests/auto/qml/qqmltypeloader/data/test_intercept.qml new file mode 100644 index 0000000000..0d64cb7e28 --- /dev/null +++ b/tests/auto/qml/qqmltypeloader/data/test_intercept.qml @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** 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-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +ListView { + width: 400 + height: 500 + model: 2 + + id: test + property int created: 0 + property int loaded: 0 + + delegate: Loader { + width: ListView.view.width + height: 100 + asynchronous: true + source: index == 0 ? "Intercept.qml" : "GenericView.qml" + + onLoaded: { + test.loaded++ + } + Component.onCompleted: { + test.created++ + } + } +} diff --git a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp index 68b450ab26..5ab729042f 100644 --- a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp +++ b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp @@ -28,6 +28,7 @@ #include <QtTest/QtTest> #include <QtQml/qqmlengine.h> +#include <QtQml/qqmlnetworkaccessmanagerfactory.h> #include <QtQuick/qquickview.h> #include <QtQuick/qquickitem.h> #include <QtQml/private/qqmlengine_p.h> @@ -45,6 +46,7 @@ private slots: void trimCache2(); void keepSingleton(); void keepRegistrations(); + void intercept(); }; void tst_QQMLTypeLoader::testLoadComplete() @@ -70,7 +72,7 @@ void tst_QQMLTypeLoader::loadComponentSynchronously() QTest::ignoreMessage(QtWarningMsg, QRegularExpression( QLatin1String(".*nonprotocol::1:1: QtObject is not a type.*"))); QQmlComponent component(&engine, testFileUrl("load_synchronous.qml")); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o); } @@ -111,7 +113,7 @@ void tst_QQMLTypeLoader::trimCache() void tst_QQMLTypeLoader::trimCache2() { - QQuickView *window = new QQuickView(); + QScopedPointer<QQuickView> window(new QQuickView()); window->setSource(testFileUrl("trim_cache2.qml")); QQmlTypeLoader &loader = QQmlEnginePrivate::get(window->engine())->typeLoader; // in theory if gc has already run this could be false @@ -192,6 +194,201 @@ void tst_QQMLTypeLoader::keepRegistrations() verifyTypes(true, false); // qmlRegisterType creates an undeletable type. } +class NetworkReply : public QNetworkReply +{ +public: + NetworkReply() + { + open(QIODevice::ReadOnly); + } + + void setData(const QByteArray &data) + { + if (isFinished()) + return; + m_buffer = data; + emit readyRead(); + setFinished(true); + emit finished(); + } + + void fail() + { + if (isFinished()) + return; + m_buffer.clear(); + setError(ContentNotFoundError, "content not found"); + emit error(ContentNotFoundError); + setFinished(true); + emit finished(); + } + + qint64 bytesAvailable() const override + { + return m_buffer.size(); + } + + qint64 readData(char *data, qint64 maxlen) override + { + if (m_buffer.length() < maxlen) + maxlen = m_buffer.length(); + std::memcpy(data, m_buffer.data(), maxlen); + m_buffer.remove(0, maxlen); + return maxlen; + } + + void abort() override + { + if (isFinished()) + return; + m_buffer.clear(); + setFinished(true); + emit finished(); + } + +private: + QByteArray m_buffer; +}; + +class NetworkAccessManager : public QNetworkAccessManager +{ + Q_OBJECT +public: + + NetworkAccessManager(QObject *parent) : QNetworkAccessManager(parent) + { + } + + QNetworkReply *createRequest(Operation op, const QNetworkRequest &request, + QIODevice *outgoingData) override + { + QUrl url = request.url(); + QString scheme = url.scheme(); + if (op != GetOperation || !scheme.endsWith("+debug")) + return QNetworkAccessManager::createRequest(op, request, outgoingData); + + scheme.chop(sizeof("+debug") - 1); + url.setScheme(scheme); + + NetworkReply *reply = new NetworkReply; + QString filename = QQmlFile::urlToLocalFileOrQrc(url); + QTimer::singleShot(10, reply, [this, reply, filename]() { + if (filename.isEmpty()) { + reply->fail(); + } else { + QFile file(filename); + if (file.open(QIODevice::ReadOnly)) { + emit loaded(filename); + reply->setData(transformQmldir(filename, file.readAll())); + } else + reply->fail(); + } + }); + return reply; + } + + QByteArray transformQmldir(const QString &filename, const QByteArray &content) + { + if (!filename.endsWith("/qmldir")) + return content; + + // Make qmldir plugin paths absolute, so that we don't try to load them over the network + QByteArray result; + QByteArray path = filename.toUtf8(); + path.chop(sizeof("qmldir") - 1); + for (QByteArray line : content.split('\n')) { + if (line.isEmpty()) + continue; + QList<QByteArray> segments = line.split(' '); + if (segments.startsWith("plugin")) { + if (segments.length() == 2) { + segments.append(path); + } else if (segments.length() == 3) { + if (!segments[2].startsWith('/')) + segments[2] = path + segments[2]; + } else { + // Invalid plugin declaration. Ignore + } + result.append(segments.join(' ')); + } else { + result.append(line); + } + result.append('\n'); + } + return result; + } + +signals: + void loaded(const QString &filename); +}; + +class NetworkAccessManagerFactory : public QQmlNetworkAccessManagerFactory +{ +public: + QStringList loadedFiles; + + QNetworkAccessManager *create(QObject *parent) override + { + NetworkAccessManager *manager = new NetworkAccessManager(parent); + QObject::connect(manager, &NetworkAccessManager::loaded, [this](const QString &filename) { + loadedFiles.append(filename); + }); + return manager; + } +}; + +class UrlInterceptor : public QQmlAbstractUrlInterceptor +{ +public: + QUrl intercept(const QUrl &path, DataType type) override + { + Q_UNUSED(type); + if (!QQmlFile::isLocalFile(path)) + return path; + + QUrl result = path; + QString scheme = result.scheme(); + if (!scheme.endsWith("+debug")) + result.setScheme(scheme + "+debug"); + return result; + } +}; + +void tst_QQMLTypeLoader::intercept() +{ + qmlClearTypeRegistrations(); + + QQmlEngine engine; + engine.addImportPath(dataDirectory()); + engine.addImportPath(QT_TESTCASE_BUILDDIR); + + UrlInterceptor interceptor; + NetworkAccessManagerFactory factory; + + engine.setUrlInterceptor(&interceptor); + engine.setNetworkAccessManagerFactory(&factory); + + QQmlComponent component(&engine, testFileUrl("test_intercept.qml")); + + QVERIFY(component.status() != QQmlComponent::Ready); + QTRY_VERIFY2(component.status() == QQmlComponent::Ready, + component.errorString().toUtf8().constData()); + + QScopedPointer<QObject> o(component.create()); + QVERIFY(o.data()); + + QTRY_COMPARE(o->property("created").toInt(), 2); + QTRY_COMPARE(o->property("loaded").toInt(), 2); + + QVERIFY(factory.loadedFiles.length() >= 6); + QVERIFY(factory.loadedFiles.contains(dataDirectory() + "/test_intercept.qml")); + QVERIFY(factory.loadedFiles.contains(dataDirectory() + "/Intercept.qml")); + QVERIFY(factory.loadedFiles.contains(dataDirectory() + "/Fast/qmldir")); + QVERIFY(factory.loadedFiles.contains(dataDirectory() + "/Fast/Fast.qml")); + QVERIFY(factory.loadedFiles.contains(dataDirectory() + "/GenericView.qml")); + QVERIFY(factory.loadedFiles.contains(QLatin1String(QT_TESTCASE_BUILDDIR) + "/Slow/qmldir")); +} + QTEST_MAIN(tst_QQMLTypeLoader) #include "tst_qqmltypeloader.moc" diff --git a/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp b/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp index d4922599be..363064aa31 100644 --- a/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp +++ b/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp @@ -192,7 +192,8 @@ void tst_QQuickFramebufferObject::testThatStuffWorks() item->setMsaa(msaa); view.show(); - QTest::qWaitForWindowExposed(&view); + view.requestActivate(); + QTest::qWaitForWindowActive(&view); QImage result = view.grabWindow(); @@ -231,7 +232,8 @@ void tst_QQuickFramebufferObject::testInvalidate() item->setTextureSize(QSize(200, 200)); view.show(); - QTest::qWaitForWindowExposed(&view); + view.requestActivate(); + QTest::qWaitForWindowActive(&view); QCOMPARE(frameInfo.fboSize, QSize(200, 200)); diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp index c08d5d31b4..f06a118976 100644 --- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp +++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp @@ -8658,9 +8658,9 @@ void tst_QQuickListView::QTBUG_34576_velocityZero() QVERIFY(QTest::qWaitForWindowExposed(window)); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QVERIFY(listview); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QVERIFY(contentItem); QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); QSignalSpy horizontalVelocitySpy(listview, SIGNAL(horizontalVelocityChanged())); @@ -8672,20 +8672,21 @@ void tst_QQuickListView::QTBUG_34576_velocityZero() window->rootObject()->setProperty("horizontalVelocityZeroCount", QVariant(0)); listview->setCurrentIndex(2); QTRY_COMPARE(window->rootObject()->property("current").toInt(), 2); - QTRY_COMPARE(horizontalVelocitySpy.count(), 0); - QTRY_COMPARE(window->rootObject()->property("horizontalVelocityZeroCount").toInt(), 0); + QCOMPARE(horizontalVelocitySpy.count(), 0); + QCOMPARE(window->rootObject()->property("horizontalVelocityZeroCount").toInt(), 0); + + QSignalSpy currentIndexChangedSpy(listview, SIGNAL(currentIndexChanged())); // click button which increases currentIndex QTest::mousePress(window, Qt::LeftButton, 0, QPoint(295,215)); QTest::mouseRelease(window, Qt::LeftButton, 0, QPoint(295,215)); // verify that currentIndexChanged is triggered - QVERIFY(horizontalVelocitySpy.wait()); + QTRY_VERIFY(currentIndexChangedSpy.count() > 0); - // set currentIndex to item out of view to cause listview scroll + // since we have set currentIndex to an item out of view, the listview will scroll QTRY_COMPARE(window->rootObject()->property("current").toInt(), 3); - QTRY_COMPARE(horizontalVelocitySpy.count() > 0, true); - QVERIFY(horizontalVelocitySpy.wait(1000)); + QTRY_VERIFY(horizontalVelocitySpy.count() > 0); // velocity should be always > 0.0 QTRY_COMPARE(window->rootObject()->property("horizontalVelocityZeroCount").toInt(), 0); diff --git a/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp b/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp index fe33dbd4d8..1731253da6 100644 --- a/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp +++ b/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp @@ -52,8 +52,8 @@ public: int signalsConnected = 0; protected: - void connectNotify(const QMetaMethod &) { ++signalsConnected; } - void disconnectNotify(const QMetaMethod &) { --signalsConnected; } + void connectNotify(const QMetaMethod &) override { ++signalsConnected; } + void disconnectNotify(const QMetaMethod &) override { --signalsConnected; } signals: void dummyChanged(); @@ -257,7 +257,7 @@ void tst_qquickshadereffect::lookThroughShaderCode() QQmlComponent component(&engine); component.setData("import QtQuick 2.0\nimport ShaderEffectTest 1.0\nTestShaderEffect {}", QUrl()); QScopedPointer<TestShaderEffect> item(qobject_cast<TestShaderEffect*>(component.create())); - QCOMPARE(item->signalsConnected, 1); + QCOMPARE(item->signalsConnected, 0); QString expected; if ((presenceFlags & VertexPresent) == 0) @@ -274,7 +274,7 @@ void tst_qquickshadereffect::lookThroughShaderCode() QCOMPARE(item->parseLog(), expected); // If the uniform was successfully parsed, the notify signal has been connected to an update slot. - QCOMPARE(item->signalsConnected, (presenceFlags & SourcePresent) ? 2 : 1); + QCOMPARE(item->signalsConnected, (presenceFlags & SourcePresent) ? 1 : 0); } void tst_qquickshadereffect::deleteSourceItem() diff --git a/tests/auto/quick/quick.pro b/tests/auto/quick/quick.pro index 00be8240e5..4c1c667489 100644 --- a/tests/auto/quick/quick.pro +++ b/tests/auto/quick/quick.pro @@ -46,7 +46,7 @@ PRIVATETESTS += \ # This test requires the xmlpatterns module !qtHaveModule(xmlpatterns): PRIVATETESTS -= qquickxmllistmodel -QUICKTESTS = \ +QUICKTESTS += \ qquickaccessible \ qquickanchors \ qquickanimatedimage \ |