diff options
| author | Tarja Sundqvist <tarja.sundqvist@qt.io> | 2025-12-15 16:14:22 +0200 |
|---|---|---|
| committer | Tarja Sundqvist <tarja.sundqvist@qt.io> | 2025-12-15 16:14:22 +0200 |
| commit | b58ec3b086518da5aa573f99426235854c23e35f (patch) | |
| tree | 861a9935d8f1cdba2fdca546836a351736dbddbf /tests/auto | |
| parent | 4826f86e274f1b29bd769e6790824f9e62a40f62 (diff) | |
| parent | 22032227d16c39211e2ebceef97d21f4d89c7c87 (diff) | |
Merge tag 'v6.5.8-lts-lgpl' into 6.56.5
Qt 6.5.8-lts-lgpl release
Diffstat (limited to 'tests/auto')
46 files changed, 1360 insertions, 186 deletions
diff --git a/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp b/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp index 0c4fd568a9..802adaee14 100644 --- a/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp +++ b/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp @@ -26,6 +26,8 @@ public: private: ConnectResult startQmlProcess(const QString &qmlFile); void serveRequest(const QString &path); + void serveFile(const QString &path, const QByteArray &contents); + QList<QQmlDebugClient *> createClients() override; void verifyProcessOutputContains(const QString &string) const; @@ -42,6 +44,7 @@ private slots: void connect(); void load(); + void loadFromQrc(); void rerun(); void blacklist(); void error(); @@ -70,8 +73,7 @@ void tst_QQmlPreview::serveRequest(const QString &path) } else { QFile file(path); if (file.open(QIODevice::ReadOnly)) { - m_files.append(path); - m_client->sendFile(path, file.readAll()); + serveFile(path, file.readAll()); } else { m_filesNotFound.append(path); m_client->sendError(path); @@ -79,6 +81,12 @@ void tst_QQmlPreview::serveRequest(const QString &path) } } +void tst_QQmlPreview::serveFile(const QString &path, const QByteArray &contents) +{ + m_files.append(path); + m_client->sendFile(path, contents); +} + QList<QQmlDebugClient *> tst_QQmlPreview::createClients() { m_client = new QQmlPreviewClient(m_connection); @@ -162,6 +170,34 @@ void tst_QQmlPreview::load() QVERIFY(m_serviceErrors.isEmpty()); } +void tst_QQmlPreview::loadFromQrc() +{ + // One of the configuration files built into the "qml" executable. + const QString fromQrc(":/qt-project.org/imports/QmlRuntime/Config/default.qml"); + + QCOMPARE(QQmlDebugTest::connectTo( + QLibraryInfo::path(QLibraryInfo::BinariesPath) + "/qml", + QStringLiteral("QmlPreview"), fromQrc, true), + ConnectSuccess); + + QVERIFY(m_client); + QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled); + + serveFile(fromQrc, R"( + import QtQuick + Item { + Component.onCompleted: console.log("default.qml replaced") + } + )"); + + m_client->triggerLoad(QUrl("qrc" + fromQrc)); + verifyProcessOutputContains("default.qml replaced"); + + m_process->stop(); + QTRY_COMPARE(m_client->state(), QQmlDebugClient::NotConnected); + QVERIFY(m_serviceErrors.isEmpty()); +} + void tst_QQmlPreview::rerun() { const QString file("window.qml"); diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp index f9bd5c28aa..00854ccb43 100644 --- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp +++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp @@ -319,6 +319,8 @@ private slots: void consoleLogSequence(); + void multiMatchingRegularExpression(); + public: Q_INVOKABLE QJSValue throwingCppMethod1(); Q_INVOKABLE void throwingCppMethod2(); @@ -6415,6 +6417,17 @@ void tst_QJSEngine::consoleLogSequence() QCOMPARE(stringListFetchCount, 1); } +void tst_QJSEngine::multiMatchingRegularExpression() +{ + QJSEngine engine; + const QJSValue result = engine.evaluate(R"( + "33312345.897".replace(/\./g, ",").replace(/\B(?=(\d{3})+(?!\d))/g, ".") + )"); + + QVERIFY(result.isString()); + QCOMPARE(result.toString(), "33.312.345,897"_L1); +} + QTEST_MAIN(tst_QJSEngine) #include "tst_qjsengine.moc" diff --git a/tests/auto/qml/qmllint/data/Enumerei/Main.qml b/tests/auto/qml/qmllint/data/Enumerei/Main.qml new file mode 100644 index 0000000000..61c27e4670 --- /dev/null +++ b/tests/auto/qml/qmllint/data/Enumerei/Main.qml @@ -0,0 +1,22 @@ +import QtQml 2.15 +import qtbug127308 + +QtObject { + Component.onCompleted: { + console.log("Unscoped access:") + try { console.log("EnumTester::Scoped", EnumTester.S1, EnumTester.S2 ); } catch (a) { console.log("EnumTester::Scoped", a) } + try { console.log("EnumTester::Unscoped", EnumTester.U1, EnumTester.U2 ); } catch (b) { console.log("EnumTester::Unscoped", b) } + try { console.log("EnumTesterScoped::Scoped", EnumTesterScoped.S1, EnumTesterScoped.S2 ); } catch (c) { console.log("EnumTesterScoped::Scoped", c) } + try { console.log("EnumTesterScoped::Unscoped", EnumTesterScoped.U1, EnumTesterScoped.U2 ); } catch (d) { console.log("EnumTesterScoped::Unscoped", d) } + try { console.log("EnumTesterUnscoped::Scoped", EnumTesterUnscoped.S1, EnumTesterUnscoped.S2 ); } catch (e) { console.log("EnumTesterUnscoped::Scoped", e) } + try { console.log("EnumTesterUnscoped::Unscoped", EnumTesterUnscoped.U1, EnumTesterUnscoped.U2 ); } catch (f) { console.log("EnumTesterUnscoped::Unscoped", f) } + console.log() + console.log("Scoped access:") + try { console.log("EnumTester::Scoped", EnumTester.Scoped.S1, EnumTester.Scoped.S2 ); } catch (g) { console.log("EnumTester::Scoped", g) } + try { console.log("EnumTester::Unscoped", EnumTester.Unscoped.U1, EnumTester.Unscoped.U2 ); } catch (h) { console.log("EnumTester::Unscoped", h) } + try { console.log("EnumTesterScoped::Scoped", EnumTesterScoped.Scoped.S1, EnumTesterScoped.Scoped.S2 ); } catch (i) { console.log("EnumTesterScoped::Scoped", i) } + try { console.log("EnumTesterScoped::Unscoped", EnumTesterScoped.Unscoped.U1, EnumTesterScoped.Unscoped.U2 ); } catch (j) { console.log("EnumTesterScoped::Unscoped", j) } + try { console.log("EnumTesterUnscoped::Scoped", EnumTesterUnscoped.Scoped.S1, EnumTesterUnscoped.Scoped.S2 ); } catch (k) { console.log("EnumTesterUnscoped::Scoped", k) } + try { console.log("EnumTesterUnscoped::Unscoped", EnumTesterUnscoped.Unscoped.U1, EnumTesterUnscoped.Unscoped.U2 ); } catch (l) { console.log("EnumTesterUnscoped::Unscoped", l) } + } +} diff --git a/tests/auto/qml/qmllint/data/Enumerei/plugins.qmltypes b/tests/auto/qml/qmllint/data/Enumerei/plugins.qmltypes new file mode 100644 index 0000000000..212215362a --- /dev/null +++ b/tests/auto/qml/qmllint/data/Enumerei/plugins.qmltypes @@ -0,0 +1,44 @@ +import QtQuick.tooling 1.2 + +// This file describes the plugin-supplied types contained in the library. +// It is used for QML tooling purposes only. +// +// This file was auto-generated by qmltyperegistrar. + +Module { + Component { + file: "main.h" + name: "EnumTester" + accessSemantics: "reference" + prototype: "QObject" + exports: ["Enumerei/EnumTester 1.0"] + exportMetaObjectRevisions: [256] + Enum { + name: "Unscoped" + values: ["U1", "U2"] + } + Enum { + name: "Scoped" + isScoped: true + values: ["S1", "S2"] + } + } + Component { + file: "main.h" + name: "EnumTesterScoped" + accessSemantics: "reference" + prototype: "QObject" + exports: ["Enumerei/EnumTesterScoped 1.0"] + enforcesScopedEnums: true + exportMetaObjectRevisions: [256] + Enum { + name: "Unscoped" + values: ["U1", "U2"] + } + Enum { + name: "Scoped" + isScoped: true + values: ["S1", "S2"] + } + } +} diff --git a/tests/auto/qml/qmllint/data/Enumerei/qmldir b/tests/auto/qml/qmllint/data/Enumerei/qmldir new file mode 100644 index 0000000000..aa031dd7e8 --- /dev/null +++ b/tests/auto/qml/qmllint/data/Enumerei/qmldir @@ -0,0 +1,3 @@ +module Enumerei +typeinfo plugins.qmltypes + diff --git a/tests/auto/qml/qmllint/data/enumValid.qml b/tests/auto/qml/qmllint/data/enumValid.qml new file mode 100644 index 0000000000..32971df070 --- /dev/null +++ b/tests/auto/qml/qmllint/data/enumValid.qml @@ -0,0 +1,11 @@ +import QtQml +import Enumerei + +QtObject { + property int a: EnumTester.S2 + property int b: EnumTester.U2 + property int c: EnumTesterScoped.U2 + + property int d: EnumTester.Scoped.S2 + property int e: EnumTesterScoped.Scoped.S2 +} diff --git a/tests/auto/qml/qmllint/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp index 56e31dba8f..690a3a272a 100644 --- a/tests/auto/qml/qmllint/tst_qmllint.cpp +++ b/tests/auto/qml/qmllint/tst_qmllint.cpp @@ -1288,6 +1288,7 @@ void TestQmllint::cleanQmlCode_data() QTest::newRow("listConversion") << QStringLiteral("listConversion.qml"); QTest::newRow("groupedAttachedLayout") << QStringLiteral("groupedAttachedLayout.qml"); QTest::newRow("constInvokable") << QStringLiteral("useConstInvokable.qml"); + QTest::newRow("scopedAndUnscopedEnums") << QStringLiteral("enumValid.qml"); } void TestQmllint::cleanQmlCode() diff --git a/tests/auto/qml/qmltyperegistrar/CMakeLists.txt b/tests/auto/qml/qmltyperegistrar/CMakeLists.txt index c36bc7bff8..ab89394fc8 100644 --- a/tests/auto/qml/qmltyperegistrar/CMakeLists.txt +++ b/tests/auto/qml/qmltyperegistrar/CMakeLists.txt @@ -91,6 +91,7 @@ qt_internal_add_resource(tst_qmltyperegistrar "resources" PREFIX "/" FILES + brokenEnums.json duplicatedExports.json ) diff --git a/tests/auto/qml/qmltyperegistrar/brokenEnums.json b/tests/auto/qml/qmltyperegistrar/brokenEnums.json new file mode 100644 index 0000000000..e54a58f9b7 --- /dev/null +++ b/tests/auto/qml/qmltyperegistrar/brokenEnums.json @@ -0,0 +1,57 @@ +[ + { + "classes": [ + { + "className": "QObject", + "object": true, + "qualifiedClassName": "QObject" + }, + { + "classInfos": [ + { + "name": "QML.Element", + "value": "auto" + }, + { + "name": "RegisterEnumClassesUnscoped", + "value": "true" + } + ], + "className": "EnumsExplicitlyUnscoped", + "lineNumber": 878, + "object": true, + "qualifiedClassName": "EnumsExplicitlyUnscoped", + "superClasses": [ + { + "access": "public", + "name": "QObject" + } + ] + }, + { + "classInfos": [ + { + "name": "QML.Element", + "value": "auto" + }, + { + "name": "RegisterEnumClassesUnscoped", + "value": "horst" + } + ], + "className": "EnumScopingConfused", + "lineNumber": 885, + "object": true, + "qualifiedClassName": "EnumScopingConfused", + "superClasses": [ + { + "access": "public", + "name": "QObject" + } + ] + } + ], + "inputFile": "tst_qmltyperegistrar.h", + "outputRevision": 68 + } +] diff --git a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp index 980e3503a2..c2e4ef0397 100644 --- a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp +++ b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp @@ -417,6 +417,47 @@ void tst_qmltyperegistrar::duplicateExportWarnings() r.write(output); } +void tst_qmltyperegistrar::enumWarnings() +{ + QmlTypeRegistrar r; + r.setModuleVersions(QTypeRevision::fromVersion(1, 1), {}, false); + QString moduleName = "tstmodule"; + QString targetNamespace = "tstnamespace"; + r.setModuleNameAndNamespace(moduleName, targetNamespace); + + const auto expectWarning = [](const char *message) { + QTest::ignoreMessage(QtWarningMsg, message); + }; + + expectWarning("Warning: tst_qmltyperegistrar.h:: " + "Unrecognized value for RegisterEnumClassesUnscoped: horst"); + expectWarning("Warning: tst_qmltyperegistrar.h:: " + "Setting RegisterEnumClassesUnscoped to true has no effect."); + + QTest::failOnWarning(QRegularExpression(".*")); + + + MetaTypesJsonProcessor processor(true); + + QVERIFY(processor.processTypes({ ":/brokenEnums.json" })); + processor.postProcessTypes(); + processor.postProcessForeignTypes(); + + QVector<QJsonObject> types = processor.types(); + QVector<QJsonObject> typesforeign = processor.foreignTypes(); + r.setTypes(types, typesforeign); + + QString outputData; + QTextStream output(&outputData, QIODeviceBase::ReadWrite); + + r.write(output); + + QTemporaryFile pluginTypes; + QVERIFY(pluginTypes.open()); + + r.generatePluginTypes(pluginTypes.fileName()); +} + void tst_qmltyperegistrar::clonedSignal() { QVERIFY(qmltypesData.contains(R"(Signal { @@ -671,4 +712,17 @@ void tst_qmltyperegistrar::constReturnType() })")); } +void tst_qmltyperegistrar::enumsExplicitlyScoped() +{ + QVERIFY(qmltypesData.contains(R"(Component { + file: "tst_qmltyperegistrar.h" + name: "EnumsExplicitlyScoped" + accessSemantics: "reference" + prototype: "QObject" + exports: ["QmlTypeRegistrarTest/EnumsExplicitlyScoped 1.0"] + enforcesScopedEnums: true + exportMetaObjectRevisions: [256] + })")); +} + QTEST_MAIN(tst_qmltyperegistrar) diff --git a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h index 15d2a92f8e..fdca40632b 100644 --- a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h +++ b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h @@ -565,6 +565,13 @@ public: Q_INVOKABLE const QObject *getObject() { return nullptr; } }; +class EnumsExplicitlyScoped : public QObject +{ + Q_OBJECT + QML_ELEMENT + Q_CLASSINFO("RegisterEnumClassesUnscoped", "false") +}; + class tst_qmltyperegistrar : public QObject { Q_OBJECT @@ -619,8 +626,11 @@ private slots: void listSignal(); void foreignNamespaceFromGadget(); + void enumWarnings(); void constReturnType(); + void enumsExplicitlyScoped(); + private: QByteArray qmltypesData; }; diff --git a/tests/auto/qml/qqmlcomponent/lifecyclewatcher.h b/tests/auto/qml/qqmlcomponent/lifecyclewatcher.h index 738fd86942..3d3bdfd562 100644 --- a/tests/auto/qml/qqmlcomponent/lifecyclewatcher.h +++ b/tests/auto/qml/qqmlcomponent/lifecyclewatcher.h @@ -15,10 +15,29 @@ class LifeCycleWatcher : public QObject, public QQmlParserStatus, public QQmlFin QML_ELEMENT Q_INTERFACES(QQmlParserStatus) Q_INTERFACES(QQmlFinalizerHook) + Q_PROPERTY(QString text MEMBER text) public: - void classBegin() override {states.push_back(1); } - void componentComplete() override {states.push_back(2);}; - void componentFinalized() override { states.push_back(3); } + void classBegin() override + { + states.push_back(1); + observedTexts.push_back(text); + } + + void componentComplete() override + { + states.push_back(2); + observedTexts.push_back(text); + } + + void componentFinalized() override + { + states.push_back(3); + observedTexts.push_back(text); + } + + QString text; QList<int> states; + QStringList observedTexts; }; + #endif diff --git a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp index 1ccf7a6f23..59703d5c36 100644 --- a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp +++ b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp @@ -1361,8 +1361,7 @@ void tst_qqmlcomponent::loadFromModule() void tst_qqmlcomponent::loadFromModuleLifecycle() { QQmlEngine engine; - QList<int> loadFromModuleOrder; - QList<int> plainLoadOrder; + const QString text = "text"_L1; const QList<int> expected {1, 2, 3}; { QQmlComponent component(&engine); @@ -1371,19 +1370,58 @@ void tst_qqmlcomponent::loadFromModuleLifecycle() std::unique_ptr<QObject> root{ component.create() }; LifeCycleWatcher *watcher = qobject_cast<LifeCycleWatcher *>(root.get()); QVERIFY(watcher); - loadFromModuleOrder = watcher->states; - QCOMPARE(loadFromModuleOrder, expected); + QCOMPARE(watcher->states, expected); + QCOMPARE(watcher->observedTexts, QStringList(3)); + + const QString loaded = "load from module"_L1; + root.reset(component.createWithInitialProperties(QVariantMap{{text, loaded}})); + watcher = qobject_cast<LifeCycleWatcher *>(root.get()); + QVERIFY(watcher); + QCOMPARE(watcher->states, expected); + QCOMPARE(watcher->observedTexts, QStringList({QString(), loaded, loaded})); } + { QQmlComponent component(&engine); component.setData("import test; LifeCycleWatcher {}", {}); QVERIFY2(component.isReady(), qPrintable(component.errorString())); + std::unique_ptr<QObject> root{ component.create() }; LifeCycleWatcher *watcher = qobject_cast<LifeCycleWatcher *>(root.get()); QVERIFY(watcher); - plainLoadOrder = watcher->states; + QCOMPARE(watcher->states, expected); + QCOMPARE(watcher->observedTexts, QStringList(3)); + + const QString loaded = "load from data"_L1; + root.reset(component.createWithInitialProperties(QVariantMap{{text, loaded}})); + watcher = qobject_cast<LifeCycleWatcher *>(root.get()); + QVERIFY(watcher); + QCOMPARE(watcher->states, expected); + QCOMPARE(watcher->observedTexts, QStringList({QString(), loaded, loaded})); } - QCOMPARE(loadFromModuleOrder, plainLoadOrder); + + { + QQmlComponent component(&engine); + const QString compiled = "inline"_L1; + component.setData("import test; LifeCycleWatcher { text: 'inline' }", {}); + QVERIFY2(component.isReady(), qPrintable(component.errorString())); + + std::unique_ptr<QObject> root{ component.create() }; + LifeCycleWatcher *watcher = qobject_cast<LifeCycleWatcher *>(root.get()); + QVERIFY(watcher); + QCOMPARE(watcher->states, expected); + QCOMPARE(watcher->observedTexts, QStringList({QString(), compiled, compiled})); + + const QString loaded = "overridden"_L1; + std::unique_ptr<QObject> withProperties( + component.createWithInitialProperties(QVariantMap{{text, loaded}})); + watcher = qobject_cast<LifeCycleWatcher *>(withProperties.get()); + QVERIFY(watcher); + QCOMPARE(watcher->states, expected); + QCOMPARE(watcher->observedTexts, QStringList({QString(), loaded, loaded})); + } + + } struct CallVerifyingIncubtor : QQmlIncubator diff --git a/tests/auto/qml/qqmldelegatemodel/data/proxyModelWithDelayedSourceModelInListView.qml b/tests/auto/qml/qqmldelegatemodel/data/proxyModelWithDelayedSourceModelInListView.qml new file mode 100644 index 0000000000..b6733bd38c --- /dev/null +++ b/tests/auto/qml/qqmldelegatemodel/data/proxyModelWithDelayedSourceModelInListView.qml @@ -0,0 +1,30 @@ +import QtQuick +import Test + +Window { + id: root + title: listView.count + + property alias listView: listView + property ProxySourceModel connectionModel: null + + Component { + id: modelComponent + ProxySourceModel {} + } + + ListView { + id: listView + anchors.fill: parent + + delegate: Text { + text: model.Name + } + + model: ProxyModel { + sourceModel: root.connectionModel + } + } + + Component.onCompleted: root.connectionModel = modelComponent.createObject(root) +} diff --git a/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp b/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp index e9c22ca1e6..336d0bd679 100644 --- a/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp +++ b/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include <QtTest/qtest.h> +#include <QtCore/qsortfilterproxymodel.h> #include <QtCore/QConcatenateTablesProxyModel> #include <QtCore/qtimer.h> #include <QtGui/QStandardItemModel> @@ -44,6 +45,7 @@ private slots: void persistedItemsStayInCache(); void doNotUnrefObjectUnderConstruction(); void clearCacheDuringInsertion(); + void proxyModelWithDelayedSourceModelInListView(); }; class BaseAbstractItemModel : public QAbstractItemModel @@ -501,6 +503,77 @@ void tst_QQmlDelegateModel::clearCacheDuringInsertion() QTRY_COMPARE(object->property("testModel").toInt(), 0); } +class ProxySourceModel : public QAbstractListModel +{ + Q_OBJECT + QML_ELEMENT +public: + explicit ProxySourceModel(QObject *parent = nullptr) + : QAbstractListModel(parent) + { + for (int i = 0; i < rows; ++i) { + beginInsertRows(QModelIndex(), i, i); + endInsertRows(); + } + } + + ~ProxySourceModel() override = default; + + int rowCount(const QModelIndex &) const override + { + return rows; + } + + QVariant data(const QModelIndex &, int ) const override + { + return "Hello"; + } + + QHash<int, QByteArray> roleNames() const override + { + QHash<int, QByteArray> roles = QAbstractListModel::roleNames(); + roles[Qt::UserRole + 1] = "Name"; + + return roles; + } + + static const int rows = 1; +}; + +class ProxyModel : public QSortFilterProxyModel +{ + Q_OBJECT + QML_ELEMENT + Q_PROPERTY(QAbstractItemModel *sourceModel READ sourceModel WRITE setSourceModel) + +public: + explicit ProxyModel(QObject *parent = nullptr) + : QSortFilterProxyModel(parent) + { + } + + ~ProxyModel() override = default; +}; + +// Checks that the correct amount of delegates are created when using a proxy +// model whose source model is set after a delay. +void tst_QQmlDelegateModel::proxyModelWithDelayedSourceModelInListView() +{ + qmlRegisterTypesAndRevisions<ProxySourceModel>("Test", 1); + qmlRegisterTypesAndRevisions<ProxyModel>("Test", 1); + + QQuickApplicationHelper helper(this, "proxyModelWithDelayedSourceModelInListView.qml"); + QVERIFY2(helper.ready, helper.failureMessage()); + QQuickWindow *window = helper.window; + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + auto *listView = window->property("listView").value<QQuickListView *>(); + QVERIFY(listView); + const auto delegateModel = QQuickItemViewPrivate::get(listView)->model; + QTRY_COMPARE(listView->count(), 1); +} + QTEST_MAIN(tst_QQmlDelegateModel) #include "tst_qqmldelegatemodel.moc" diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp index b82a1f4174..bf68de0d2f 100644 --- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp +++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp @@ -79,6 +79,7 @@ private slots: void lockedRootObject(); void crossReferencingSingletonsDeletion(); void bindingInstallUseAfterFree(); + void attachedObjectOfUnregistered(); public slots: QObject *createAQObjectForOwnershipTest () @@ -1708,6 +1709,42 @@ void tst_qqmlengine::bindingInstallUseAfterFree() QVERIFY(o); } +class UnregisteredAttached : public QObject +{ + Q_OBJECT +public: + UnregisteredAttached(QObject *parent = nullptr) : QObject(parent) {} +}; + +class Unregistered : public QObject +{ + Q_OBJECT + QML_ATTACHED(UnregisteredAttached) +public: + static UnregisteredAttached *qmlAttachedProperties(QObject *obj) + { + return new UnregisteredAttached(obj); + } +}; + +void tst_qqmlengine::attachedObjectOfUnregistered() +{ + QObject o; + + QObject *a = qmlAttachedPropertiesObject<Unregistered>(&o); + QVERIFY(a); + QVERIFY(qobject_cast<UnregisteredAttached *>(a)); + + QObject *b = qmlAttachedPropertiesObject<Unregistered>(&o); + QCOMPARE(a, b); + + QObject o2; + QObject *c = qmlAttachedPropertiesObject<Unregistered>(&o2); + QVERIFY(c); + QVERIFY(qobject_cast<UnregisteredAttached *>(c)); + QVERIFY(c != a); +} + QTEST_MAIN(tst_qqmlengine) #include "tst_qqmlengine.moc" diff --git a/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp b/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp index 92da003ad4..d57dfe2956 100644 --- a/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp +++ b/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp @@ -40,6 +40,7 @@ private slots: void implicitWithDependencies(); void qualifiedScriptImport(); void invalidImportUrl(); + void sanitizeUNCPath(); }; void tst_QQmlImport::cleanup() @@ -150,6 +151,15 @@ void tst_QQmlImport::invalidImportUrl() ":2 Cannot resolve URL for import \"file://./MyModuleName\"\n")); } +void tst_QQmlImport::sanitizeUNCPath() +{ + QString wildUNCPath = QStringLiteral("//Server2/Sh%re/foO/qmldir"); + QQmlImportDatabase::sanitizeUNCPath(&wildUNCPath); + + // It lowercases the "server" component of the path. The rest is left as-is + QCOMPARE(wildUNCPath, QStringLiteral("//server2/Sh%re/foO/qmldir")); +} + void tst_QQmlImport::testDesignerSupported() { QQuickView *window = new QQuickView(); diff --git a/tests/auto/qml/qqmllanguage/data/TextItem.qml b/tests/auto/qml/qqmllanguage/data/TextItem.qml new file mode 100644 index 0000000000..1f6f171b41 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/TextItem.qml @@ -0,0 +1,7 @@ +import QtQuick + +Text { + property bool testBool: false + font.family: "Ar" + "iallll" + onTestBoolChanged: font.pixelSize = 16; +} diff --git a/tests/auto/qml/qqmllanguage/data/Wrap.qml b/tests/auto/qml/qqmllanguage/data/Wrap.qml new file mode 100644 index 0000000000..365350f16e --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/Wrap.qml @@ -0,0 +1,6 @@ +import QtQuick + +TextItem { + font.pixelSize: height * 0.9 + testBool: true +} diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp index 12fe042c20..c65cbe329d 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.cpp +++ b/tests/auto/qml/qqmllanguage/testtypes.cpp @@ -4,6 +4,10 @@ #include <private/qv4qmlcontext_p.h> +#include <QtQml/qqmlextensionplugin.h> + +Q_IMPORT_QML_PLUGIN(testhelperPlugin) + static QObject *myTypeObjectSingleton(QQmlEngine *engine, QJSEngine *scriptEngine) { Q_UNUSED(engine); diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 7992896506..b7dff336af 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -6222,7 +6222,7 @@ class EnumTester : public QObject public: enum Types { - FIRST = 0, + FIRST = 42, SECOND, THIRD }; @@ -6236,13 +6236,18 @@ void tst_qqmllanguage::qualifiedScopeInCustomParser() QQmlEngine engine; QQmlComponent component(&engine); component.setData("import QtQml.Models 2.12\n" + "import QtQml\n" "import scoped.custom.test 1.0 as BACKEND\n" "ListModel {\n" + " id: root\n" + " property int num: -1\n" " ListElement { text: \"a\"; type: BACKEND.EnumTester.FIRST }\n" + " Component.onCompleted: { root.num = root.get(0).type }\n" "}\n", QUrl()); QVERIFY2(component.isReady(), qPrintable(component.errorString())); QScopedPointer<QObject> obj(component.create()); QVERIFY(!obj.isNull()); + QCOMPARE(obj->property("num").toInt(), 42); } void tst_qqmllanguage::checkUncreatableNoReason() @@ -8262,6 +8267,14 @@ void tst_qqmllanguage::overrideInnerBinding() QCOMPARE(o->property("width").toReal(), 20.0); QCOMPARE(o->property("innerWidth").toReal(), 20.0); + + QQmlComponent c2(&e, testFileUrl("Wrap.qml")); + QVERIFY2(c2.isReady(), qPrintable(c2.errorString())); + o.reset(c2.create()); + QVERIFY(!o.isNull()); + + QFont font = qvariant_cast<QFont>(o->property("font")); + QCOMPARE(font.family(), "Ariallll"); } QTEST_MAIN(tst_qqmllanguage) diff --git a/tests/auto/qml/qqmltypeloader/data/SlowImporter/A.qml b/tests/auto/qml/qqmltypeloader/data/SlowImporter/A.qml new file mode 100644 index 0000000000..421a0918ed --- /dev/null +++ b/tests/auto/qml/qqmltypeloader/data/SlowImporter/A.qml @@ -0,0 +1,2 @@ +import Slow +SlowStuff {} diff --git a/tests/auto/qml/qqmltypeloader/data/SlowImporter/qmldir b/tests/auto/qml/qqmltypeloader/data/SlowImporter/qmldir new file mode 100644 index 0000000000..bf2eff032d --- /dev/null +++ b/tests/auto/qml/qqmltypeloader/data/SlowImporter/qmldir @@ -0,0 +1,2 @@ +module SlowImporter +A 1.0 A.qml diff --git a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp index 717c900c00..cb4610d01b 100644 --- a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp +++ b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp @@ -34,6 +34,7 @@ private slots: void trimCache3(); void keepSingleton(); void keepRegistrations(); + void importAndDestroy(); void intercept(); void redirect(); void qmlSingletonWithinModule(); @@ -48,6 +49,7 @@ private slots: void declarativeCppAndQmlDir(); void signalHandlersAreCompatible(); void loadTypeOnShutdown(); + void floodTypeLoaderEventQueue(); private: void checkSingleton(const QString & dataDirectory); @@ -418,6 +420,49 @@ public: } }; +void tst_QQMLTypeLoader::importAndDestroy() +{ +#if defined Q_OS_ANDROID || defined Q_OS_IOS + QSKIP("Data directory is not in the host file system on Android and iOS"); +#endif + qmlClearTypeRegistrations(); + + QQmlEngine engine; + NetworkAccessManagerFactory factory; + engine.setNetworkAccessManagerFactory(&factory); + QQmlComponent component(&engine); + + // We redirect the import through the network access manager to make it asynchronous. + // Otherwise the type loader will just directly call back into the main thread and we + // won't get a chance to do mischief before initializeEngine gets called for the "Slow" + // module. Note that the "Slow" module needs to be loaded from a "local" URL since plugins + // can only be loaded locally. + + // Detour through testFileUrl to get the path right on windows ('C:' and things like that) + QUrl url = testFileUrl("SlowImporter"); + url.setScheme(url.scheme() + QLatin1String("+debug")); + + component.setData(QString::fromLatin1(R"( + import '%1' + A {} + )").arg(url.toString()).toUtf8(), QUrl()); + + while (!QQmlMetaType::qmlType( + QStringLiteral("SlowStuff"), QStringLiteral("Slow"), QTypeRevision()) + .isValid()) { + // busy wait for type to be registered + QVERIFY2(!component.isError(), qPrintable(component.errorString())); + } + + // Now the type loader thread is likely waiting for the main thread to process the + // initializeEngine callback. We destroy the engine here to trigger the situation where the main + // thread needs to wake the type loader thread one more time to process the isShutdown flag. + // If it fails to do so, the type loader thread waits indefinitely for the main thread and the + // engine dtor in turn waits indefinitely for the type loader thread to terminate. + + // The point of this test is that it _should not_ deadlock here. +} + void tst_QQMLTypeLoader::intercept() { #ifdef Q_OS_ANDROID @@ -768,6 +813,22 @@ void tst_QQMLTypeLoader::loadTypeOnShutdown() QVERIFY(dead2); } +void tst_QQMLTypeLoader::floodTypeLoaderEventQueue() +{ + QQmlEngine engine; + + // Flood the typeloader with useless messages. + for (int i = 0; i < 1000; ++i) { + QQmlComponent c(&engine); + c.setData(QString::fromLatin1(R"( + import "barf:/not/actually/there%1" + SomeElement {} + )").arg(i).toUtf8(), QUrl::fromLocalFile(QString::fromLatin1("foo%1.qml").arg(i))); + QVERIFY(!c.isReady()); + // Should not crash when destrying the QQmlComponent. + } +} + QTEST_MAIN(tst_QQMLTypeLoader) #include "tst_qqmltypeloader.moc" diff --git a/tests/auto/qml/qv4mm/data/forInOnProxyMarksTarget.qml b/tests/auto/qml/qv4mm/data/forInOnProxyMarksTarget.qml new file mode 100644 index 0000000000..23e3820f2c --- /dev/null +++ b/tests/auto/qml/qv4mm/data/forInOnProxyMarksTarget.qml @@ -0,0 +1,23 @@ +import QtQml + +QtObject { + property bool wasInUseBeforeRevoke: false + property bool wasInUseAfterRevoke: false + + Component.onCompleted: { + let handler = {}; + let target = {prop1: 1, prop2: 2}; + + let proxy = Proxy.revocable(target, handler); + wasInUseBeforeRevoke = __inUse(target) + target = null; + + for (var prop in proxy.proxy) { + prop[4] = 10; + proxy.revoke() + gc() + wasInUseAfterRevoke = __inUse() + break + } + } +} diff --git a/tests/auto/qml/qv4mm/tst_qv4mm.cpp b/tests/auto/qml/qv4mm/tst_qv4mm.cpp index e5f8951825..832abfa4a0 100644 --- a/tests/auto/qml/qv4mm/tst_qv4mm.cpp +++ b/tests/auto/qml/qv4mm/tst_qv4mm.cpp @@ -27,6 +27,7 @@ private slots: void accessParentOnDestruction(); void cleanInternalClasses(); void createObjectsOnDestruction(); + void forInOnProxyMarksTarget(); }; tst_qv4mm::tst_qv4mm() @@ -206,6 +207,33 @@ void tst_qv4mm::createObjectsOnDestruction() QCOMPARE(obj->property("ok").toBool(), true); } + +QV4::ReturnedValue method_in_use(const QV4::FunctionObject *, const QV4::Value *, const QV4::Value *argv, int argc) { + static QV4::Value::HeapBasePtr target = nullptr; + + if (argc == 1) { + target = argv[0].heapObject(); + } + + Q_ASSERT(target); + return QV4::Encode(target->inUse()); +} + +void tst_qv4mm::forInOnProxyMarksTarget() { + QQmlEngine engine; + auto *v4 = engine.handle(); + auto globalObject = v4->globalObject; + globalObject->defineDefaultProperty(QStringLiteral("__inUse"), method_in_use); + + QQmlComponent comp(&engine, testFileUrl("forInOnProxyMarksTarget.qml")); + QVERIFY(comp.isReady()); + std::unique_ptr<QObject> root {comp.create()}; + + QVERIFY(root); + QVERIFY(root->property("wasInUseBeforeRevoke").toBool()); + QVERIFY(root->property("wasInUseAfterRevoke").toBool()); +} + QTEST_MAIN(tst_qv4mm) #include "tst_qv4mm.moc" diff --git a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp index ab64f6bb24..7902136835 100644 --- a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp +++ b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp @@ -102,7 +102,7 @@ void tst_MptaInterop::touchDrag() } if (dragStoleGrab) qCDebug(lcPointerTests, "DragHandler stole the grab after %d events", dragStoleGrab); - QVERIFY(dragStoleGrab > 1); + QCOMPARE_GT(dragStoleGrab, 1); touch.release(1, p1).commit(); QQuickTouchUtils::flush(window); @@ -159,7 +159,7 @@ void tst_MptaInterop::touchesThenPinch() QCOMPARE(devPriv->pointById(1)->exclusiveGrabber, mpta); QCOMPARE(devPriv->pointById(2)->exclusiveGrabber, mpta); QCOMPARE(devPriv->pointById(3)->exclusiveGrabber, mpta); - QVERIFY(!pinch->active()); + QCOMPARE(pinch->active(), false); // Start moving: PinchHandler steals the exclusive grab from MPTA as soon as dragThreshold is exceeded int pinchStoleGrab = 0; @@ -182,8 +182,8 @@ void tst_MptaInterop::touchesThenPinch() } } qCDebug(lcPointerTests) << "pinch started after" << pinchStoleGrab << "moves; ended with scale" << pinch->activeScale() << "rot" << pinch->rotation(); - QTRY_VERIFY(pinch->rotation() > 4); - QVERIFY(pinch->activeScale() > 1); + QTRY_COMPARE_GT(pinch->rotation(), 4); + QCOMPARE_GT(pinch->activeScale(), 1); // Press one more point (pinkie finger) QPoint p4 = mpta->mapToScene(QPointF(300, 200)).toPoint(); @@ -251,7 +251,7 @@ void tst_MptaInterop::touchesThenPinch() qCDebug(lcPointerTests) << "drag started after" << dragTookGrab << "moves; ended with translation" << drag->activeTranslation(); QCOMPARE(devPriv->pointById(1)->exclusiveGrabber, drag); - QTRY_VERIFY(drag->activeTranslation().x() > 0); + QTRY_COMPARE_GT(drag->activeTranslation().x(), 0); touch.release(2, p2).commit(); QQuickTouchUtils::flush(window); @@ -309,7 +309,7 @@ void tst_MptaInterop::dragHandlerInParentStealingGrabFromItem() // QTBUG-75025 } if (dragStoleGrab) qCDebug(lcPointerTests, "DragHandler stole the grab after %d events", dragStoleGrab); - QVERIFY(dragStoleGrab > 1); + QCOMPARE_GT(dragStoleGrab, 1); QCOMPARE(handler->active(), true); QCOMPARE(window->rootObject()->property("touchpointPressed").toBool(), false); diff --git a/tests/auto/quick/pointerhandlers/qquickpinchhandler/tst_qquickpinchhandler.cpp b/tests/auto/quick/pointerhandlers/qquickpinchhandler/tst_qquickpinchhandler.cpp index 610d03c440..2bbf232486 100644 --- a/tests/auto/quick/pointerhandlers/qquickpinchhandler/tst_qquickpinchhandler.cpp +++ b/tests/auto/quick/pointerhandlers/qquickpinchhandler/tst_qquickpinchhandler.cpp @@ -215,14 +215,17 @@ void tst_QQuickPinchHandler::scale_data() { QTest::addColumn<QUrl>("qmlfile"); QTest::addColumn<bool>("hasTarget"); - QTest::newRow("targetModifying") << testFileUrl("pinchproperties.qml") << true; - QTest::newRow("nullTarget") << testFileUrl("nullTarget.qml") << false; + QTest::addColumn<bool>("axisEnabled"); + QTest::newRow("targetModifying") << testFileUrl("pinchproperties.qml") << true << true; + QTest::newRow("nullTarget") << testFileUrl("nullTarget.qml") << false << true; + QTest::newRow("axisDiabled") << testFileUrl("pinchproperties.qml") << true << false; } void tst_QQuickPinchHandler::scale() { QFETCH(QUrl, qmlfile); QFETCH(bool, hasTarget); + QFETCH(bool, axisEnabled); QQuickView window; QVERIFY(QQuickTest::showView(window, qmlfile)); @@ -230,6 +233,7 @@ void tst_QQuickPinchHandler::scale() QVERIFY(root != nullptr); auto *pinchHandler = static_cast<PinchHandler *>(root->findChild<QQuickPinchHandler*>()); QVERIFY(pinchHandler != nullptr); + pinchHandler->scaleAxis()->setEnabled(axisEnabled); QQuickItem *blackRect = (hasTarget ? pinchHandler->target() : pinchHandler->parentItem()); QVERIFY(blackRect != nullptr); QSignalSpy grabChangedSpy(pinchHandler, SIGNAL(grabChanged(QPointingDevice::GrabTransition, QEventPoint))); @@ -269,10 +273,13 @@ void tst_QQuickPinchHandler::scale() QCOMPARE(grabChangedSpy.size(), 3); QLineF line(p0, p1); const qreal startLength = line.length(); + // to be redefined below + qreal lastScale = pinchHandler->persistentScale(); + qreal expectedIncrement = 0; // move the same point even further and observe the change in scale for (int i = 0; i < 2; ++i) { - qreal lastScale = pinchHandler->activeScale(); + lastScale = pinchHandler->activeScale(); p1 += pd; pinchSequence.stationary(0).move(1, p1, &window).commit(); QQuickTouchUtils::flush(&window); @@ -282,21 +289,27 @@ void tst_QQuickPinchHandler::scale() qCDebug(lcPointerTests) << "pinchScale" << root->property("pinchScale").toReal() << "expected" << expectedScale << "; target scale" << blackRect->scale() << "increments" << scaleChangedSpy.size() - << "multiplier" << scaleChangedSpy.last().first().toReal(); - QVERIFY(qFloatDistance(root->property("pinchScale").toReal(), expectedScale) < 10); - QVERIFY(qFloatDistance(blackRect->scale(), expectedScale) < 10); + << "multiplier" << (scaleChangedSpy.isEmpty() ? 1 : scaleChangedSpy.last().first().toReal()); + if (axisEnabled) { + QVERIFY(qFloatDistance(root->property("pinchScale").toReal(), expectedScale) < 10); + QVERIFY(qFloatDistance(blackRect->scale(), expectedScale) < 10); + } else { + QCOMPARE(root->property("pinchScale").toInt(), 1); + QCOMPARE(blackRect->scale(), 1); + } QCOMPARE(pinchHandler->persistentScale(), root->property("pinchScale").toReal()); QCOMPARE(pinchHandler->persistentScale(), pinchHandler->activeScale()); // in sync for the first gesture QCOMPARE(pinchHandler->scaleAxis()->persistentValue(), pinchHandler->activeScale()); QCOMPARE(pinchHandler->scaleAxis()->activeValue(), pinchHandler->activeScale()); - const qreal expectedIncrement = pinchHandler->activeScale() / lastScale; - QCOMPARE(scaleChangedSpy.size(), i + 1); - QCOMPARE(scaleChangedSpy.last().first().toReal(), expectedIncrement); + expectedIncrement = pinchHandler->activeScale() / lastScale; + QCOMPARE(scaleChangedSpy.size(), axisEnabled ? i + 1 : 0); + if (axisEnabled) + QCOMPARE(scaleChangedSpy.last().first().toReal(), expectedIncrement); QPointF expectedCentroid = p0 + (p1 - p0) / 2; QCOMPARE(pinchHandler->centroid().scenePosition(), expectedCentroid); } - qreal lastScale = pinchHandler->persistentScale(); + lastScale = pinchHandler->persistentScale(); pinchSequence.release(0, p0, &window).release(1, p1, &window).commit(); QQuickTouchUtils::flush(&window); if (lcPointerTests().isDebugEnabled()) QTest::qWait(500); @@ -326,21 +339,29 @@ void tst_QQuickPinchHandler::scale() pinchSequence.stationary(0).move(1, p1, &window).commit(); QQuickTouchUtils::flush(&window); if (lcPointerTests().isDebugEnabled()) QTest::qWait(500); - QCOMPARE_GT(pinchHandler->persistentScale(), lastScale); + if (axisEnabled) + QCOMPARE_GT(pinchHandler->persistentScale(), lastScale); + else + QCOMPARE(pinchHandler->persistentScale(), 1); line.setP2(p1); qreal expectedActiveScale = line.length() / startLength; qCDebug(lcPointerTests) << i << "activeScale" << pinchHandler->activeScale() << "expected" << expectedActiveScale << "; scale" << pinchHandler->persistentScale() << "increments" << scaleChangedSpy.size() - << "multiplier" << scaleChangedSpy.last().first().toReal(); - QVERIFY(qFloatDistance(pinchHandler->activeScale(), expectedActiveScale) < 10); + << "multiplier" << (scaleChangedSpy.isEmpty() ? 1 : scaleChangedSpy.last().first().toReal()); + if (axisEnabled) { + QVERIFY(qFloatDistance(pinchHandler->activeScale(), expectedActiveScale) < 10); + QCOMPARE_NE(pinchHandler->persistentScale(), pinchHandler->activeScale()); // not in sync anymore + } else { + QCOMPARE(pinchHandler->persistentScale(), pinchHandler->activeScale()); + } QCOMPARE(pinchHandler->persistentScale(), root->property("pinchScale").toReal()); QCOMPARE(pinchHandler->scaleAxis()->persistentValue(), root->property("pinchScale").toReal()); - QCOMPARE_NE(pinchHandler->persistentScale(), pinchHandler->activeScale()); // not in sync anymore QCOMPARE(pinchHandler->scaleAxis()->activeValue(), pinchHandler->activeScale()); - const qreal expectedIncrement = pinchHandler->persistentScale() / lastScale; - QCOMPARE(scaleChangedSpy.size(), i + 3); - QCOMPARE(scaleChangedSpy.last().first().toReal(), expectedIncrement); + expectedIncrement = pinchHandler->persistentScale() / lastScale; + QCOMPARE(scaleChangedSpy.size(), axisEnabled ? i + 3 : 0); + if (axisEnabled) + QCOMPARE(scaleChangedSpy.last().first().toReal(), expectedIncrement); } // scale beyond maximumScale @@ -349,12 +370,13 @@ void tst_QQuickPinchHandler::scale() pinchSequence.stationary(0).move(1, p1, &window).commit(); QQuickTouchUtils::flush(&window); if (lcPointerTests().isDebugEnabled()) QTest::qWait(500); - QCOMPARE(blackRect->scale(), qreal(4)); - QCOMPARE(pinchHandler->persistentScale(), qreal(4)); // limited by maximumScale - QCOMPARE(pinchHandler->scaleAxis()->persistentValue(), 4); - const qreal expectedIncrement = pinchHandler->activeScale() / lastScale; - QCOMPARE(scaleChangedSpy.size(), 5); - QCOMPARE(scaleChangedSpy.last().first().toReal(), expectedIncrement); + QCOMPARE(blackRect->scale(), axisEnabled ? 4 : 1); + QCOMPARE(pinchHandler->persistentScale(), axisEnabled ? 4 : 1); // limited by maximumScale + QCOMPARE(pinchHandler->scaleAxis()->persistentValue(), axisEnabled ? 4 : 1); + expectedIncrement = pinchHandler->activeScale() / lastScale; + QCOMPARE(scaleChangedSpy.size(), axisEnabled ? 5 : 0); + if (axisEnabled) + QCOMPARE(scaleChangedSpy.last().first().toReal(), expectedIncrement); pinchSequence.release(0, p0, &window).release(1, p1, &window).commit(); QQuickTouchUtils::flush(&window); QCOMPARE(pinchHandler->active(), false); @@ -557,19 +579,25 @@ void tst_QQuickPinchHandler::cumulativeNativeGestures_data() QTest::addColumn<const QPointingDevice*>("device"); QTest::addColumn<Qt::NativeGestureType>("gesture"); QTest::addColumn<qreal>("value"); + QTest::addColumn<bool>("scalingEnabled"); + QTest::addColumn<bool>("rotationEnabled"); QTest::addColumn<QList<QPoint>>("expectedTargetTranslations"); const auto *touchpadDevice = touchpad.get(); const auto *mouse = QPointingDevice::primaryPointingDevice(); - QTest::newRow("touchpad: rotate") << touchpadDevice << Qt::RotateNativeGesture << 5.0 + QTest::newRow("touchpad: rotate") << touchpadDevice << Qt::RotateNativeGesture << 5.0 << true << true << QList<QPoint>{{-2, 2}, {-5, 4}, {-7, 6}, {-10, 7}}; - QTest::newRow("touchpad: scale") << touchpadDevice << Qt::ZoomNativeGesture << 0.1 + QTest::newRow("touchpad: scale") << touchpadDevice << Qt::ZoomNativeGesture << 0.1 << true << true + << QList<QPoint>{{3, 3}, {5, 5}, {8, 8}, {12, 12}}; + QTest::newRow("touchpad: rotate disabled") << touchpadDevice << Qt::RotateNativeGesture << 5.0 << true << false + << QList<QPoint>{{-2, 2}, {-5, 4}, {-7, 6}, {-10, 7}}; + QTest::newRow("touchpad: scale disabled") << touchpadDevice << Qt::ZoomNativeGesture << 0.1 << false << true << QList<QPoint>{{3, 3}, {5, 5}, {8, 8}, {12, 12}}; if (mouse->type() == QInputDevice::DeviceType::Mouse) { - QTest::newRow("mouse: rotate") << mouse << Qt::RotateNativeGesture << 5.0 + QTest::newRow("mouse: rotate") << mouse << Qt::RotateNativeGesture << 5.0 << true << true << QList<QPoint>{{-2, 2}, {-5, 4}, {-7, 6}, {-10, 7}}; - QTest::newRow("mouse: scale") << mouse << Qt::ZoomNativeGesture << 0.1 + QTest::newRow("mouse: scale") << mouse << Qt::ZoomNativeGesture << 0.1 << true << true << QList<QPoint>{{3, 3}, {5, 5}, {8, 8}, {12, 12}}; } else { qCWarning(lcPointerTests) << "skipping mouse tests: primary device is not a mouse" << mouse; @@ -581,6 +609,8 @@ void tst_QQuickPinchHandler::cumulativeNativeGestures() QFETCH(const QPointingDevice*, device); QFETCH(Qt::NativeGestureType, gesture); QFETCH(qreal, value); + QFETCH(bool, scalingEnabled); + QFETCH(bool, rotationEnabled); QFETCH(QList<QPoint>, expectedTargetTranslations); QCOMPARE(expectedTargetTranslations.size(), 4); @@ -594,6 +624,8 @@ void tst_QQuickPinchHandler::cumulativeNativeGestures() QVERIFY(root != nullptr); QQuickPinchHandler *pinchHandler = root->findChild<QQuickPinchHandler*>("pinchHandler"); QVERIFY(pinchHandler != nullptr); + pinchHandler->scaleAxis()->setEnabled(scalingEnabled); + pinchHandler->rotationAxis()->setEnabled(rotationEnabled); QQuickItem *target = root->findChild<QQuickItem*>("blackrect"); QVERIFY(target != nullptr); QCOMPARE(pinchHandler->target(), target); @@ -620,6 +652,10 @@ void tst_QQuickPinchHandler::cumulativeNativeGestures() default: break; // PinchHandler doesn't react to the others } + if (!rotationEnabled) + expectedRotation = 0; + if (!scalingEnabled) + expectedScale = 1; qCDebug(lcPointerTests) << i << gesture << "with value" << value << ": scale" << target->scale() << "expected" << expectedScale @@ -641,8 +677,10 @@ void tst_QQuickPinchHandler::cumulativeNativeGestures() qCDebug(lcPointerTests) << "target moved by" << delta << "to" << target->position() << "active trans" << pinchHandler->activeTranslation() << "perst trans" << pinchHandler->persistentTranslation(); - QCOMPARE_NE(target->position(), initialTargetPos); - QCOMPARE(delta.toPoint(), expectedTargetTranslations.at(i - 1)); + if (scalingEnabled && rotationEnabled) { + QCOMPARE_NE(target->position(), initialTargetPos); + QCOMPARE(delta.toPoint(), expectedTargetTranslations.at(i - 1)); + } // The native pinch gesture cannot include a translation component (and // the cursor doesn't move while you are performing the gesture on a touchpad). QCOMPARE(pinchHandler->activeTranslation(), QPointF()); diff --git a/tests/auto/quick/qquickflickable/data/nestedSameDirection.qml b/tests/auto/quick/qquickflickable/data/nestedSameDirection.qml new file mode 100644 index 0000000000..d6574c3a58 --- /dev/null +++ b/tests/auto/quick/qquickflickable/data/nestedSameDirection.qml @@ -0,0 +1,61 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +import QtQuick + +Flickable { + id: root + width: 240 + height: 320 + readonly property real flickableContentHeight: 500 + contentWidth: 800 + contentHeight: flickableContentHeight + Column { + Rectangle { + width: 240 + height: root.flickableContentHeight / parent.children.length + color: "lightsteelblue" + + Flickable { + objectName: "nested1" + anchors.fill: parent + contentWidth: parent.width + contentHeight: flickableContentHeight + + Repeater { + model: 3 + Rectangle { + y: height * index + width: 96 + height: root.flickableContentHeight / 3 + color: Qt.rgba(Math.random() * 0.5, 0.5, 0.2, 1) + border.color: "black" + } + } + } + } + Rectangle { + width: 240 + height: root.flickableContentHeight / parent.children.length + color: "steelblue" + + Flickable { + objectName: "nested2" + anchors.fill: parent + contentWidth: parent.width + contentHeight: flickableContentHeight + + Repeater { + model: 3 + Rectangle { + y: height * index + width: 96 + height: root.flickableContentHeight / 3 + color: Qt.rgba(Math.random() * 0.65, 0.4, 0.3, 1) + border.color: "black" + } + } + } + } + } +} diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp index a9019683c3..4ce2b7e3c6 100644 --- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp +++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp @@ -177,6 +177,7 @@ private slots: void wheel(); void trackpad(); void nestedTrackpad(); + void nestedSameDirectionTrackpad(); void movingAndFlicking(); void movingAndFlicking_data(); void movingAndDragging(); @@ -228,12 +229,14 @@ private slots: void touchCancel(); private: - void flickWithTouch(QQuickWindow *window, const QPoint &from, const QPoint &to); QPointingDevice *touchDevice = QTest::createTouchDevice(); const QPointingDevice *mouseDevice = new QPointingDevice( "test mouse", 1000, QInputDevice::DeviceType::Mouse, QPointingDevice::PointerType::Generic, QInputDevice::Capability::Position | QInputDevice::Capability::Hover | QInputDevice::Capability::Scroll, 1, 5, QString(), QPointingDeviceUniqueId(), this); + QScopedPointer<QPointingDevice> touchpad = QScopedPointer<QPointingDevice>( + QTest::createTouchDevice(QInputDevice::DeviceType::TouchPad, + QInputDevice::Capability::Position | QInputDevice::Capability::PixelScroll)); }; void tst_qquickflickable::initTestCase() @@ -392,6 +395,7 @@ void tst_qquickflickable::boundsBehavior() void tst_qquickflickable::rebound() { + auto device = mouseDevice; QScopedPointer<QQuickView> window(new QQuickView); window->setSource(testFileUrl("rebound.qml")); QTRY_COMPARE(window->status(), QQuickView::Ready); @@ -415,7 +419,7 @@ void tst_qquickflickable::rebound() QSignalSpy hMoveSpy(flickable, SIGNAL(movingHorizontallyChanged())); // flick and test the transition is run - flick(window.data(), QPoint(20,20), QPoint(120,120), 200); + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(20,20), QPoint(120,120), 200); QTRY_COMPARE(window->rootObject()->property("transitionsStarted").toInt(), 2); QCOMPARE(hMoveSpy.size(), 1); @@ -445,8 +449,8 @@ void tst_qquickflickable::rebound() // flick and trigger the transition multiple times // (moving signals are emitted as soon as the first transition starts) - flick(window.data(), QPoint(20,20), QPoint(120,120), 50); // both x and y will bounce back - flick(window.data(), QPoint(20,120), QPoint(120,20), 50); // only x will bounce back + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(20,20), QPoint(120,120), 50); // both x and y will bounce back + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(20,120), QPoint(120,20), 50); // only x will bounce back QVERIFY(flickable->isMoving()); QTRY_VERIFY(window->rootObject()->property("transitionsStarted").toInt() >= 1); @@ -475,7 +479,7 @@ void tst_qquickflickable::rebound() // (i.e. moving but transition->running = false) window->rootObject()->setProperty("transitionEnabled", false); - flick(window.data(), QPoint(20,20), QPoint(120,120), 200); + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(20,20), QPoint(120,120), 200); QCOMPARE(window->rootObject()->property("transitionsStarted").toInt(), 0); QCOMPARE(hMoveSpy.size(), 1); QCOMPARE(vMoveSpy.size(), 1); @@ -628,6 +632,7 @@ void tst_qquickflickable::pressDelay() // QTBUG-17361 void tst_qquickflickable::nestedPressDelay() { + auto device = mouseDevice; QScopedPointer<QQuickView> window(new QQuickView); window->setSource(testFileUrl("nestedPressDelay.qml")); QTRY_COMPARE(window->status(), QQuickView::Ready); @@ -643,7 +648,7 @@ void tst_qquickflickable::nestedPressDelay() QQuickFlickable *inner = window->rootObject()->findChild<QQuickFlickable*>("innerFlickable"); QVERIFY(inner != nullptr); - moveAndPress(window.data(), QPoint(150, 150)); + QQuickTest::pointerMoveAndPress(device, window.data(), 0, QPoint(150, 150)); // the MouseArea is not pressed immediately QVERIFY(!outer->property("pressed").toBool()); QVERIFY(!inner->property("pressed").toBool()); @@ -667,7 +672,7 @@ void tst_qquickflickable::nestedPressDelay() QTRY_VERIFY(!inner->property("moving").toBool()); // Dragging inner Flickable should work - moveAndPress(window.data(), QPoint(80, 150)); + QQuickTest::pointerMoveAndPress(device, window.data(), 0, QPoint(80, 150)); // the MouseArea is not pressed immediately QVERIFY(!outer->property("pressed").toBool()); QVERIFY(!inner->property("pressed").toBool()); @@ -687,7 +692,7 @@ void tst_qquickflickable::nestedPressDelay() QTRY_VERIFY(!inner->property("moving").toBool()); // Dragging the MouseArea in the inner Flickable should move the inner Flickable - moveAndPress(window.data(), QPoint(150, 150)); + QQuickTest::pointerMoveAndPress(device, window.data(), 0, QPoint(150, 150)); // the MouseArea is not pressed immediately QVERIFY(!outer->property("pressed").toBool()); @@ -708,6 +713,7 @@ void tst_qquickflickable::nestedPressDelay() void tst_qquickflickable::filterReplayedPress() { + auto device = mouseDevice; QScopedPointer<QQuickView> window(new QQuickView); window->setSource(testFileUrl("nestedPressDelay.qml")); QTRY_COMPARE(window->status(), QQuickView::Ready); @@ -726,7 +732,7 @@ void tst_qquickflickable::filterReplayedPress() QQuickItem *filteringMouseArea = outer->findChild<QQuickItem *>("filteringMouseArea"); QVERIFY(filteringMouseArea); - moveAndPress(window.data(), QPoint(150, 150)); + QQuickTest::pointerMoveAndPress(device, window.data(), 0, QPoint(150, 150)); // the MouseArea filtering the Flickable is pressed immediately. QCOMPARE(filteringMouseArea->property("pressed").toBool(), true); @@ -751,6 +757,7 @@ void tst_qquickflickable::filterReplayedPress() // QTBUG-37316 void tst_qquickflickable::nestedClickThenFlick() { + auto device = mouseDevice; QScopedPointer<QQuickView> window(new QQuickView); window->setSource(testFileUrl("nestedClickThenFlick.qml")); QTRY_COMPARE(window->status(), QQuickView::Ready); @@ -766,7 +773,7 @@ void tst_qquickflickable::nestedClickThenFlick() QQuickFlickable *inner = window->rootObject()->findChild<QQuickFlickable*>("innerFlickable"); QVERIFY(inner != nullptr); - moveAndPress(window.data(), QPoint(150, 150)); + QQuickTest::pointerMoveAndPress(device, window.data(), 0, QPoint(150, 150)); // the MouseArea is not pressed immediately QVERIFY(!outer->property("pressed").toBool()); @@ -777,7 +784,7 @@ void tst_qquickflickable::nestedClickThenFlick() QVERIFY(!outer->property("pressed").toBool()); // Dragging inner Flickable should work - moveAndPress(window.data(), QPoint(80, 150)); + QQuickTest::pointerMoveAndPress(device, window.data(), 0, QPoint(80, 150)); // the MouseArea is not pressed immediately QVERIFY(!outer->property("pressed").toBool()); @@ -1030,7 +1037,7 @@ void tst_qquickflickable::nestedTrackpad() for (int i = 0; i < 10 && qFuzzyIsNull(innerFlickable->contentX()); ++i) { QWheelEvent event(pos, window.mapToGlobal(pos), QPoint(-10,4), QPoint(-20,8), Qt::NoButton, Qt::NoModifier, i ? Qt::ScrollUpdate : Qt::ScrollBegin, false, - Qt::MouseEventSynthesizedBySystem); + Qt::MouseEventSynthesizedBySystem, touchpad.get()); event.setAccepted(false); event.setTimestamp(timestamp++); QGuiApplication::sendEvent(&window, &event); @@ -1040,7 +1047,7 @@ void tst_qquickflickable::nestedTrackpad() { QWheelEvent event(pos, window.mapToGlobal(pos), QPoint(0,0), QPoint(0,0), Qt::NoButton, Qt::NoModifier, Qt::ScrollEnd, false, - Qt::MouseEventSynthesizedBySystem); + Qt::MouseEventSynthesizedBySystem, touchpad.get()); event.setAccepted(false); event.setTimestamp(timestamp++); QGuiApplication::sendEvent(&window, &event); @@ -1054,7 +1061,7 @@ void tst_qquickflickable::nestedTrackpad() for (int i = 0; i < 10 && qFuzzyIsNull(innerFlickable->contentY()); ++i) { QWheelEvent event(pos, window.mapToGlobal(pos), QPoint(4,-10), QPoint(8,-20), Qt::NoButton, Qt::NoModifier, i ? Qt::ScrollUpdate : Qt::ScrollBegin, false, - Qt::MouseEventSynthesizedBySystem); + Qt::MouseEventSynthesizedBySystem, touchpad.get()); event.setAccepted(false); event.setTimestamp(timestamp++); QGuiApplication::sendEvent(&window, &event); @@ -1064,7 +1071,7 @@ void tst_qquickflickable::nestedTrackpad() { QWheelEvent event(pos, window.mapToGlobal(pos), QPoint(0,0), QPoint(0,0), Qt::NoButton, Qt::NoModifier, Qt::ScrollEnd, false, - Qt::MouseEventSynthesizedBySystem); + Qt::MouseEventSynthesizedBySystem, touchpad.get()); event.setAccepted(false); event.setTimestamp(timestamp++); QGuiApplication::sendEvent(&window, &event); @@ -1072,6 +1079,50 @@ void tst_qquickflickable::nestedTrackpad() QTRY_COMPARE(outerMoveEndSpy.size(), 1); } +void tst_qquickflickable::nestedSameDirectionTrackpad() // QTBUG-124478 +{ + QQuickView window; + QVERIFY(QQuickTest::showView(window, testFileUrl("nestedSameDirection.qml"))); + QQuickFlickable *rootFlickable = qmlobject_cast<QQuickFlickable *>(window.rootObject()); + QVERIFY(rootFlickable); + QQuickFlickable *flickable1 = rootFlickable->findChild<QQuickFlickable *>("nested1"); + QVERIFY(flickable1); + QQuickFlickable *flickable2 = rootFlickable->findChild<QQuickFlickable *>("nested2"); + QVERIFY(flickable2); + + QVERIFY(rootFlickable->isAtYBeginning()); + const QPoint pixelDelta(0, -100); + const QPointF pos(50, 50); + const int interval = 20; + quint64 timestamp = 1000; + + auto sendTrackpadScroll = [pixelDelta, pos, ×tamp, &window, this, + interval](Qt::ScrollPhase phase) { + QWheelEvent ev(pos, window.mapToGlobal(pos), pixelDelta, pixelDelta, Qt::NoButton, + Qt::NoModifier, phase, false, Qt::MouseEventSynthesizedBySystem, + touchpad.get()); + ev.setTimestamp(timestamp); + QGuiApplication::sendEvent(&window, &ev); + timestamp += interval; // for next time + }; + + // Send enough pixelDelta wheel events for flickable1 to reach its end. + sendTrackpadScroll(Qt::ScrollBegin); + + for (int i = 1; i < 50; ++i) { + if (lcTests().isDebugEnabled()) + QTest::qWait(interval); + sendTrackpadScroll(Qt::ScrollUpdate); + } + + // We expect that the rootFlickable has moved, due to receiving some of the + // wheel events that were sent after flickable1 reached its end. + // Then flickable2 began to move as well, after it got under the mouse position. + QTRY_VERIFY(flickable1->isAtYEnd()); + QCOMPARE(rootFlickable->isAtYBeginning(), false); + QCOMPARE(flickable2->isAtYBeginning(), false); +} + void tst_qquickflickable::movingAndFlicking_data() { QTest::addColumn<bool>("verticalEnabled"); @@ -1101,6 +1152,7 @@ void tst_qquickflickable::movingAndFlicking() QFETCH(bool, horizontalEnabled); QFETCH(QPoint, flickToWithoutSnapBack); QFETCH(QPoint, flickToWithSnapBack); + auto device = mouseDevice; const QPoint flickFrom(50, 200); // centre @@ -1129,7 +1181,7 @@ void tst_qquickflickable::movingAndFlicking() QSignalSpy flickEndSpy(flickable, SIGNAL(flickEnded())); // do a flick that keeps the view within the bounds - flick(window.data(), flickFrom, flickToWithoutSnapBack, 200); + QQuickTest::pointerFlick(device, window.data(), 0, flickFrom, flickToWithoutSnapBack, 200); QTRY_VERIFY(flickable->isMoving()); QCOMPARE(flickable->isMovingHorizontally(), horizontalEnabled); @@ -1188,7 +1240,7 @@ void tst_qquickflickable::movingAndFlicking() flickable->setContentX(0); flickable->setContentY(0); QTRY_VERIFY(!flickable->isMoving()); - flick(window.data(), flickFrom, flickToWithSnapBack, 10); + QQuickTest::pointerFlick(device, window.data(), 0, flickFrom, flickToWithSnapBack, 10); QTRY_VERIFY(flickable->isMoving()); QCOMPARE(flickable->isMovingHorizontally(), horizontalEnabled); @@ -1264,6 +1316,7 @@ void tst_qquickflickable::movingAndDragging() QFETCH(bool, horizontalEnabled); QFETCH(QPoint, moveByWithoutSnapBack); QFETCH(QPoint, moveByWithSnapBack); + auto device = mouseDevice; const QPoint moveFrom(50, 200); // centre @@ -1292,7 +1345,7 @@ void tst_qquickflickable::movingAndDragging() QSignalSpy moveEndSpy(flickable, SIGNAL(movementEnded())); // start the drag - moveAndPress(window.data(), moveFrom); + QQuickTest::pointerMoveAndPress(device, window.data(), 0, moveFrom); QTest::mouseMove(window.data(), moveFrom + moveByWithoutSnapBack); QTest::mouseMove(window.data(), moveFrom + moveByWithoutSnapBack*2); QTest::mouseMove(window.data(), moveFrom + moveByWithoutSnapBack*3); @@ -1368,7 +1421,7 @@ void tst_qquickflickable::movingAndDragging() flickable->setContentX(0); flickable->setContentY(0); QTRY_VERIFY(!flickable->isMoving()); - moveAndPress(window.data(), moveFrom); + QQuickTest::pointerMoveAndPress(device, window.data(), 0, moveFrom); QTest::mouseMove(window.data(), moveFrom + moveByWithSnapBack); QTest::mouseMove(window.data(), moveFrom + moveByWithSnapBack*2); QTest::mouseMove(window.data(), moveFrom + moveByWithSnapBack*3); @@ -1439,6 +1492,7 @@ void tst_qquickflickable::movingAndDragging() void tst_qquickflickable::flickOnRelease() { + auto device = mouseDevice; QScopedPointer<QQuickView> window(new QQuickView); window->setSource(testFileUrl("flickable03.qml")); window->show(); @@ -1455,7 +1509,7 @@ void tst_qquickflickable::flickOnRelease() // underlying drivers will hopefully provide a pre-calculated velocity // (based on more data than what the UI gets), thus making this use case // working even with small movements. - moveAndPress(window.data(), QPoint(50, 300)); + QQuickTest::pointerMoveAndPress(device, window.data(), 0, QPoint(50, 300)); QTest::mouseMove(window.data(), QPoint(50, 10), 10); QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(50, 10), 10); @@ -1470,6 +1524,7 @@ void tst_qquickflickable::flickOnRelease() void tst_qquickflickable::pressWhileFlicking() { + auto device = mouseDevice; QScopedPointer<QQuickView> window(new QQuickView); window->setSource(testFileUrl("flickable03.qml")); QTRY_COMPARE(window->status(), QQuickView::Ready); @@ -1493,7 +1548,7 @@ void tst_qquickflickable::pressWhileFlicking() // flick then press while it is still moving // flicking == false, moving == true; - flick(window.data(), QPoint(20,190), QPoint(20, 50), 200); + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(20,190), QPoint(20, 50), 200); QVERIFY(flickable->verticalVelocity() > 0.0); QTRY_VERIFY(flickable->isFlicking()); QVERIFY(flickable->isFlickingVertically()); @@ -1529,6 +1584,7 @@ void tst_qquickflickable::pressWhileFlicking() void tst_qquickflickable::dragWhileFlicking() { + auto device = mouseDevice; QQuickView window; QVERIFY(QQuickTest::showView(window, testFileUrl("flickable03.qml"))); @@ -1545,7 +1601,7 @@ void tst_qquickflickable::dragWhileFlicking() QSignalSpy flickEndSpy(flickable, &QQuickFlickable::flickEnded); // flick first, let it keep moving - flick(&window, QPoint(20,190), QPoint(20, 50), 200); + QQuickTest::pointerFlick(device, &window, 0, QPoint(20,190), QPoint(20, 50), 200); QVERIFY(flickable->verticalVelocity() > 0.0); QTRY_VERIFY(flickable->isFlicking()); QVERIFY(flickable->isFlickingVertically()); @@ -1564,21 +1620,21 @@ void tst_qquickflickable::dragWhileFlicking() // then drag slowly while it's still flicking and moving const int dragStepDelay = 100; - QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(20, 70)); + QQuickTest::pointerPress(device, &window, 0, QPoint(20, 70), Qt::LeftButton, Qt::NoModifier, 500); QTRY_COMPARE(flickable->isFlicking(), false); QCOMPARE(flickable->isFlickingVertically(), false); QVERIFY(flickable->isMoving()); QVERIFY(flickable->isMovingVertically()); for (int y = 70; y > 50; y -= 5) { - QTest::mouseMove(&window, QPoint(20, y), dragStepDelay); + QQuickTest::pointerMove(device, &window, 0, QPoint(20, y), dragStepDelay); QVERIFY(flickable->isMoving()); QVERIFY(flickable->isMovingVertically()); // Flickable's timeline is real-time, so spoofing timestamps isn't enough QTest::qWait(dragStepDelay); } - QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(20, 50), dragStepDelay); + QQuickTest::pointerRelease(device, &window, 0, QPoint(20, 50), Qt::LeftButton, Qt::NoModifier, dragStepDelay); QCOMPARE(flickable->isFlicking(), false); QCOMPARE(flickable->isFlickingVertically(), false); @@ -1597,6 +1653,7 @@ void tst_qquickflickable::dragWhileFlicking() void tst_qquickflickable::disabled() { + auto device = mouseDevice; QScopedPointer<QQuickView> window(new QQuickView); window->setSource(testFileUrl("disabled.qml")); window->show(); @@ -1606,7 +1663,7 @@ void tst_qquickflickable::disabled() QQuickFlickable *flick = window->rootObject()->findChild<QQuickFlickable*>("flickable"); QVERIFY(flick != nullptr); - moveAndPress(window.data(), QPoint(50, 90)); + QQuickTest::pointerMoveAndPress(device, window.data(), 0, QPoint(50, 90)); QTest::mouseMove(window.data(), QPoint(50, 80)); QTest::mouseMove(window.data(), QPoint(50, 70)); @@ -1617,7 +1674,7 @@ void tst_qquickflickable::disabled() QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(50, 60)); // verify that mouse clicks on other elements still work (QTBUG-20584) - moveAndPress(window.data(), QPoint(50, 10)); + QQuickTest::pointerMoveAndPress(device, window.data(), 0, QPoint(50, 10)); QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(50, 10)); QTRY_VERIFY(window->rootObject()->property("clicked").toBool()); @@ -1625,6 +1682,7 @@ void tst_qquickflickable::disabled() void tst_qquickflickable::flickVelocity() { + auto device = mouseDevice; QScopedPointer<QQuickView> window(new QQuickView); window->setSource(testFileUrl("flickable03.qml")); QTRY_COMPARE(window->status(), QQuickView::Ready); @@ -1638,12 +1696,12 @@ void tst_qquickflickable::flickVelocity() QVERIFY(flickable != nullptr); // flick up - flick(window.data(), QPoint(20,190), QPoint(20, 50), 200); + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(20,190), QPoint(20, 50), 200); QVERIFY(flickable->verticalVelocity() > 0.0); QTRY_COMPARE(flickable->verticalVelocity(), 0.0); // flick down - flick(window.data(), QPoint(20,10), QPoint(20, 140), 200); + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(20,10), QPoint(20, 140), 200); QTRY_VERIFY(flickable->verticalVelocity() < 0.0); QTRY_COMPARE(flickable->verticalVelocity(), 0.0); @@ -1656,13 +1714,13 @@ void tst_qquickflickable::flickVelocity() QQuickFlickablePrivate *fp = QQuickFlickablePrivate::get(flickable); bool boosted = false; for (int i = 0; i < 6; ++i) { - flick(window.data(), QPoint(20,390), QPoint(20, 50), 100); + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(20,390), QPoint(20, 50), 100); boosted |= fp->flickBoost > 1.0; } QVERIFY(boosted); // Flick in opposite direction -> boost cancelled. - flick(window.data(), QPoint(20,10), QPoint(20, 340), 200); + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(20,10), QPoint(20, 340), 200); QTRY_VERIFY(flickable->verticalVelocity() < 0.0); QCOMPARE(fp->flickBoost, 1.0); } @@ -1752,6 +1810,7 @@ void tst_qquickflickable::cancelOnHide() void tst_qquickflickable::cancelOnMouseGrab() { + auto device = mouseDevice; QScopedPointer<QQuickView> window(new QQuickView); window->setSource(testFileUrl("cancel.qml")); QTRY_COMPARE(window->status(), QQuickView::Ready); @@ -1764,7 +1823,7 @@ void tst_qquickflickable::cancelOnMouseGrab() QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); QVERIFY(flickable != nullptr); - moveAndPress(window.data(), QPoint(10, 10)); + QQuickTest::pointerMoveAndPress(device, window.data(), 0, QPoint(10, 10)); // drag out of bounds QTest::mouseMove(window.data(), QPoint(50, 50)); QTest::mouseMove(window.data(), QPoint(100, 100)); @@ -1788,11 +1847,12 @@ void tst_qquickflickable::cancelOnMouseGrab() QTRY_VERIFY(!flickable->isMoving()); QTRY_VERIFY(!flickable->isDragging()); - moveAndRelease(window.data(), QPoint(50, 10)); + QQuickTest::pointerMoveAndRelease(device, window.data(), 0, QPoint(50, 10)); } void tst_qquickflickable::clickAndDragWhenTransformed() { + auto device = mouseDevice; QScopedPointer<QQuickView> view(new QQuickView); view->setSource(testFileUrl("transformedFlickable.qml")); QTRY_COMPARE(view->status(), QQuickView::Ready); @@ -1806,12 +1866,12 @@ void tst_qquickflickable::clickAndDragWhenTransformed() QVERIFY(flickable != nullptr); // click outside child rect - moveAndPress(view.data(), QPoint(190, 190)); + QQuickTest::pointerMoveAndPress(device, view.data(), 0, QPoint(190, 190)); QTRY_COMPARE(flickable->property("itemPressed").toBool(), false); QTest::mouseRelease(view.data(), Qt::LeftButton, Qt::NoModifier, QPoint(190, 190)); // click inside child rect - moveAndPress(view.data(), QPoint(200, 200)); + QQuickTest::pointerMoveAndPress(device, view.data(), 0, QPoint(200, 200)); QTRY_COMPARE(flickable->property("itemPressed").toBool(), true); QTest::mouseRelease(view.data(), Qt::LeftButton, Qt::NoModifier, QPoint(200, 200)); @@ -1819,16 +1879,16 @@ void tst_qquickflickable::clickAndDragWhenTransformed() const int threshold = qApp->styleHints()->startDragDistance() * flickable->parentItem()->scale(); // drag outside bounds - moveAndPress(view.data(), QPoint(160, 160)); + QQuickTest::pointerMoveAndPress(device, view.data(), 0, QPoint(160, 160)); QTest::qWait(10); QTest::mouseMove(view.data(), QPoint(160 + threshold * 2, 160)); QTest::mouseMove(view.data(), QPoint(160 + threshold * 3, 160)); QCOMPARE(flickable->isDragging(), false); QCOMPARE(flickable->property("itemPressed").toBool(), false); - moveAndRelease(view.data(), QPoint(180, 160)); + QQuickTest::pointerMoveAndRelease(device, view.data(), 0, QPoint(180, 160)); // drag inside bounds - moveAndPress(view.data(), QPoint(200, 140)); + QQuickTest::pointerMoveAndPress(device, view.data(), 0, QPoint(200, 140)); QCOMPARE(flickable->keepMouseGrab(), false); QTest::qWait(10); // Flickable should get interested in dragging when the drag is beyond the @@ -1842,7 +1902,7 @@ void tst_qquickflickable::clickAndDragWhenTransformed() QTest::mouseMove(view.data(), QPoint(200 + threshold * 2, 140)); QCOMPARE(flickable->isDragging(), true); // it grabs only during the second drag past the threshold QCOMPARE(flickable->property("itemPressed").toBool(), false); - moveAndRelease(view.data(), QPoint(220, 140)); + QQuickTest::pointerMoveAndRelease(device, view.data(), 0, QPoint(220, 140)); } void tst_qquickflickable::flickTwiceUsingTouches() @@ -1860,7 +1920,8 @@ void tst_qquickflickable::flickTwiceUsingTouches() QVERIFY(flickable != nullptr); QCOMPARE(flickable->contentY(), 0.0f); - flickWithTouch(window.data(), QPoint(100, 400), QPoint(100, 240)); + + QQuickTest::pointerFlick(touchDevice, window.data(), 1, QPoint(100, 400), QPoint(100, 240), 100); qreal contentYAfterFirstFlick = flickable->contentY(); qDebug() << "contentYAfterFirstFlick " << contentYAfterFirstFlick; @@ -1868,7 +1929,7 @@ void tst_qquickflickable::flickTwiceUsingTouches() // Wait until view stops moving QTRY_VERIFY(!flickable->isMoving()); - flickWithTouch(window.data(), QPoint(100, 400), QPoint(100, 240)); + QQuickTest::pointerFlick(touchDevice, window.data(), 1, QPoint(100, 400), QPoint(100, 240), 100); // In the original bug, that second flick would cause Flickable to halt immediately qreal contentYAfterSecondFlick = flickable->contentY(); @@ -1876,20 +1937,6 @@ void tst_qquickflickable::flickTwiceUsingTouches() QTRY_VERIFY(contentYAfterSecondFlick > (contentYAfterFirstFlick + 80.0f)); } -void tst_qquickflickable::flickWithTouch(QQuickWindow *window, const QPoint &from, const QPoint &to) -{ - QTest::touchEvent(window, touchDevice).press(0, from, window); - QQuickTouchUtils::flush(window); - - QPoint diff = to - from; - for (int i = 1; i <= 8; ++i) { - QTest::touchEvent(window, touchDevice).move(0, from + i*diff/8, window); - QQuickTouchUtils::flush(window); - } - QTest::touchEvent(window, touchDevice).release(0, to, window); - QQuickTouchUtils::flush(window); -} - void tst_qquickflickable::nestedStopAtBounds_data() { QTest::addColumn<bool>("transpose"); @@ -1927,6 +1974,7 @@ void tst_qquickflickable::nestedStopAtBounds() QFETCH(bool, innerFiltering); QFETCH(int, pressDelay); QFETCH(bool, waitForPressDelay); + auto device = mouseDevice; QQuickView view; view.setSource(testFileUrl("nestedStopAtBounds.qml")); @@ -1971,7 +2019,7 @@ void tst_qquickflickable::nestedStopAtBounds() int &axis = transpose ? position.ry() : position.rx(); // drag toward the aligned boundary. Outer flickable dragged. - moveAndPress(&view, position); + QQuickTest::pointerMoveAndPress(device, &view, 0, position); if (waitForPressDelay) { QVERIFY(innerFiltering); // pressed will never be true if the mouse area isn't enabled. QTRY_VERIFY(mouseArea->pressed()); @@ -1997,7 +2045,7 @@ void tst_qquickflickable::nestedStopAtBounds() outer->setContentY(50); // drag away from the aligned boundary. Inner flickable dragged. - moveAndPress(&view, position); + QQuickTest::pointerMoveAndPress(device, &view, 0, position); axis += invert ? -threshold * 2 : threshold * 2; QTest::mouseMove(&view, position); axis += invert ? -threshold : threshold; @@ -2020,7 +2068,7 @@ void tst_qquickflickable::nestedStopAtBounds() inner->setContentHeight(inner->height() - margin); // Drag inner with equal size and contentSize - moveAndPress(&view, position); + QQuickTest::pointerMoveAndPress(device, &view, 0, position); axis += invert ? -threshold * 2 : threshold * 2; QTest::mouseMove(&view, position); axis += invert ? -threshold : threshold; @@ -2043,7 +2091,7 @@ void tst_qquickflickable::nestedStopAtBounds() inner->setContentHeight(inner->height() - 100); // Drag inner with size greater than contentSize - moveAndPress(&view, position); + QQuickTest::pointerMoveAndPress(device, &view, 0, position); axis += invert ? -threshold * 2 : threshold * 2; QTest::mouseMove(&view, position); axis += invert ? -threshold : threshold; @@ -2081,6 +2129,7 @@ void tst_qquickflickable::stopAtBounds() QFETCH(bool, transpose); QFETCH(bool, invert); QFETCH(bool, pixelAligned); + auto device = mouseDevice; QQuickView view; view.setSource(testFileUrl("stopAtBounds.qml")); @@ -2107,7 +2156,7 @@ void tst_qquickflickable::stopAtBounds() int &axis = transpose ? position.ry() : position.rx(); // drag away from the aligned boundary. View should not move - moveAndPress(&view, position); + QQuickTest::pointerMoveAndPress(device, &view, 0, position); QTest::qWait(10); for (int i = 0; i < 3; ++i) { axis += invert ? -threshold : threshold; @@ -2167,9 +2216,9 @@ void tst_qquickflickable::stopAtBounds() QSignalSpy flickSignal(flickable, SIGNAL(flickingChanged())); if (invert) - flick(&view, QPoint(20,20), QPoint(120,120), 100); + QQuickTest::pointerFlick(device, &view, 0, QPoint(20,20), QPoint(120,120), 100); else - flick(&view, QPoint(120,120), QPoint(20,20), 100); + QQuickTest::pointerFlick(device, &view, 0, QPoint(120,120), QPoint(20,20), 100); QVERIFY(flickSignal.size() > 0); if (transpose) { @@ -2200,7 +2249,7 @@ void tst_qquickflickable::nestedMouseAreaUsingTouch() QVERIFY(flickable != nullptr); QCOMPARE(flickable->contentY(), 50.0f); - flickWithTouch(window.data(), QPoint(100, 300), QPoint(100, 200)); + QQuickTest::pointerFlick(touchDevice, window.data(), 1, QPoint(100, 300), QPoint(100, 200), 100); // flickable should not have moved QCOMPARE(flickable->contentY(), 50.0); @@ -2225,7 +2274,7 @@ void tst_qquickflickable::nestedMouseAreaPropagateComposedEvents() QVERIFY(flickable != nullptr); QCOMPARE(flickable->contentY(), 50.0f); - flickWithTouch(window.data(), QPoint(100, 300), QPoint(100, 200)); + QQuickTest::pointerFlick(touchDevice, window.data(), 1, QPoint(100, 300), QPoint(100, 200), 100); // flickable should have moved QVERIFY(!qFuzzyCompare(flickable->contentY(), 50.0)); @@ -2293,6 +2342,7 @@ void tst_qquickflickable::nestedSliderUsingTouch() // QTBUG-31328 void tst_qquickflickable::pressDelayWithLoader() { + auto device = mouseDevice; QScopedPointer<QQuickView> window(new QQuickView); window->setSource(testFileUrl("pressDelayWithLoader.qml")); QTRY_COMPARE(window->status(), QQuickView::Ready); @@ -2303,7 +2353,7 @@ void tst_qquickflickable::pressDelayWithLoader() QVERIFY(window->rootObject() != nullptr); // do not crash - moveAndPress(window.data(), QPoint(150, 150)); + QQuickTest::pointerMoveAndPress(device, window.data(), 0, QPoint(150, 150)); QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(150, 150)); } @@ -2389,6 +2439,7 @@ void tst_qquickflickable::ratios_smallContent() // QTBUG-48018 void tst_qquickflickable::contentXYNotTruncatedToInt() { + auto device = mouseDevice; QScopedPointer<QQuickView> window(new QQuickView); window->setSource(testFileUrl("contentXY.qml")); QTRY_COMPARE(window->status(), QQuickView::Ready); @@ -2401,7 +2452,7 @@ void tst_qquickflickable::contentXYNotTruncatedToInt() QVERIFY(flickable); flickable->setContentX(1e10); - flick(window.data(), QPoint(200, 100), QPoint(100, 100), 50); + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(200, 100), QPoint(100, 100), 50); // make sure we are not clipped at 2^31 QVERIFY(flickable->contentX() > qreal(1e10)); @@ -2409,6 +2460,7 @@ void tst_qquickflickable::contentXYNotTruncatedToInt() void tst_qquickflickable::keepGrab() { + auto device = mouseDevice; QScopedPointer<QQuickView> window(new QQuickView); window->setSource(testFileUrl("keepGrab.qml")); QTRY_COMPARE(window->status(), QQuickView::Ready); @@ -2425,7 +2477,7 @@ void tst_qquickflickable::keepGrab() ma->setPreventStealing(true); QPoint pos(250, 250); - moveAndPress(window.data(), pos); + QQuickTest::pointerMoveAndPress(device, window.data(), 0, pos); for (int i = 0; i < 6; ++i) { pos += QPoint(10, 10); QTest::mouseMove(window.data(), pos); @@ -2440,7 +2492,7 @@ void tst_qquickflickable::keepGrab() ma->setPreventStealing(false); pos = QPoint(250, 250); - moveAndPress(window.data(), pos); + QQuickTest::pointerMoveAndPress(device, window.data(), 0, pos); for (int i = 0; i < 6; ++i) { pos += QPoint(10, 10); QTest::mouseMove(window.data(), pos); @@ -2460,6 +2512,7 @@ void tst_qquickflickable::overshoot() QFETCH(QQuickFlickable::BoundsBehavior, boundsBehavior); QFETCH(int, boundsMovement); QFETCH(bool, pixelAligned); + auto device = mouseDevice; QScopedPointer<QQuickView> window(new QQuickView); window->setSource(testFileUrl("overshoot.qml")); @@ -2516,7 +2569,7 @@ void tst_qquickflickable::overshoot() QMetaObject::invokeMethod(flickable, "reset"); // flick past the beginning - flick(window.data(), QPoint(10, 10), QPoint(50, 50), 50); + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(10, 10), QPoint(50, 50), 50); QTRY_VERIFY(!flickable->property("flicking").toBool()); if ((boundsMovement == QQuickFlickable::FollowBoundsBehavior) && (boundsBehavior & QQuickFlickable::OvershootBounds)) { @@ -2585,7 +2638,7 @@ void tst_qquickflickable::overshoot() QMetaObject::invokeMethod(flickable, "reset"); // flick past the end - flick(window.data(), QPoint(50, 50), QPoint(10, 10), 50); + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(50, 50), QPoint(10, 10), 50); QTRY_VERIFY(!flickable->property("flicking").toBool()); if ((boundsMovement == QQuickFlickable::FollowBoundsBehavior) && (boundsBehavior & QQuickFlickable::OvershootBounds)) { @@ -2728,6 +2781,7 @@ void tst_qquickflickable::synchronousDrag_data() void tst_qquickflickable::synchronousDrag() { QFETCH(bool, synchronousDrag); + auto device = mouseDevice; QScopedPointer<QQuickView> scopedWindow(new QQuickView); QQuickView *window = scopedWindow.data(); @@ -2752,7 +2806,7 @@ void tst_qquickflickable::synchronousDrag() QCOMPARE(flickable->contentY(), 0.0f); // Drag via mouse - moveAndPress(window, p1); + QQuickTest::pointerMoveAndPress(device, window, 0, p1); QTest::mouseMove(window, p2); QTest::mouseMove(window, p3); QTest::mouseMove(window, p4); @@ -2835,6 +2889,7 @@ void tst_qquickflickable::parallelTouch() // QTBUG-30840 void tst_qquickflickable::ignoreNonLeftMouseButtons() // QTBUG-96909 { QFETCH(Qt::MouseButton, otherButton); + auto device = mouseDevice; const int threshold = qApp->styleHints()->startDragDistance(); QQuickView view; view.setSource(testFileUrl("dragon.qml")); @@ -2845,30 +2900,30 @@ void tst_qquickflickable::ignoreNonLeftMouseButtons() // QTBUG-96909 // Drag with left button QPoint p1(100, 100); - moveAndPress(&view, p1); + QQuickTest::pointerMoveAndPress(device, &view, 0, p1); for (int i = 0; i < 8; ++i) { p1 -= QPoint(threshold, threshold); - QTest::mouseMove(&view, p1, 50); + QQuickTest::pointerMove(device, &view, 0, p1, 50); } QVERIFY(flickable->isDragging()); QCOMPARE(dragSpy.size(), 1); // Press other button too, then release left button: dragging changes to false - QTest::mousePress(&view, otherButton); - QTest::mouseRelease(&view, Qt::LeftButton); + QQuickTest::pointerPress(device, &view, 0, p1, otherButton); + QQuickTest::pointerRelease(device, &view, 0, p1, Qt::LeftButton); QTRY_COMPARE(flickable->isDragging(), false); QCOMPARE(dragSpy.size(), 2); // Drag further with the other button held: Flickable ignores it for (int i = 0; i < 8; ++i) { p1 -= QPoint(threshold, threshold); - QTest::mouseMove(&view, p1, 50); + QQuickTest::pointerMove(device, &view, 0, p1, 50); } QCOMPARE(flickable->isDragging(), false); QCOMPARE(dragSpy.size(), 2); // Release other button: nothing happens - QTest::mouseRelease(&view, otherButton); + QQuickTest::pointerRelease(device, &view, 0, p1, otherButton); QCOMPARE(dragSpy.size(), 2); } @@ -2937,6 +2992,7 @@ void tst_qquickflickable::flickWhenRotated() // QTBUG-99639 QFETCH(qreal, rootRotation); QFETCH(qreal, flickableRotation); QFETCH(qreal, scale); + auto device = mouseDevice; QQuickView window; QVERIFY(QQuickTest::showView(window, testFileUrl("rotatedFlickable.qml"))); @@ -2953,7 +3009,7 @@ void tst_qquickflickable::flickWhenRotated() // QTBUG-99639 // Flick in Y direction in Flickable's coordinate system and check how much it moved const QPointF startPoint = flickable->mapToGlobal(QPoint(20, 180)); const QPointF endPoint = flickable->mapToGlobal(QPoint(20, 40)); - flick(&window, window.mapFromGlobal(startPoint).toPoint(), window.mapFromGlobal(endPoint).toPoint(), 100); + QQuickTest::pointerFlick(device, &window, 0, window.mapFromGlobal(startPoint).toPoint(), window.mapFromGlobal(endPoint).toPoint(), 100); QTRY_VERIFY(flickable->isMoving()); QTRY_VERIFY(!flickable->isMoving()); qCDebug(lcTests) << "flicking from" << startPoint << "to" << endPoint << ": ended at contentY" << flickable->contentY(); @@ -3098,6 +3154,8 @@ void tst_qquickflickable::setContentPositionWhileDragging() // QTBUG-104966 QFETCH(bool, isHorizontal); QFETCH(int, newPos); QFETCH(int, newExtent); + auto device = mouseDevice; + QQuickView window; QVERIFY(QQuickTest::showView(window, testFileUrl("contentPosWhileDragging.qml"))); QQuickViewTestUtils::centerOnScreen(&window); @@ -3118,7 +3176,7 @@ void tst_qquickflickable::setContentPositionWhileDragging() // QTBUG-104966 // Drag the mouse until we have surpassed the mouse drag threshold and a drag is initiated // by checking for flickable->isDragging() QPoint pos = flickableCenterPos; - QQuickViewTestUtils::moveAndPress(&window, pos); + QQuickTest::pointerMoveAndPress(device, &window, 0, pos); int j = 1; QVERIFY(!flickable->isDragging()); while (!flickable->isDragging()) { diff --git a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp index f7f8b24bb3..c17f2e9d0a 100644 --- a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp +++ b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp @@ -4305,6 +4305,7 @@ void tst_QQuickGridView::snapToRow() QFETCH(qreal, snapAlignment); QFETCH(qreal, endExtent); QFETCH(qreal, startExtent); + auto device = QPointingDevice::primaryPointingDevice(); QQuickView *window = getView(); @@ -4327,7 +4328,7 @@ void tst_QQuickGridView::snapToRow() qreal origContentY = gridview->contentY(); qreal origContentX = gridview->contentX(); // confirm that a flick hits an item boundary - flick(window, flickStart, flickEnd, 180); + QQuickTest::pointerFlick(device, window, 0, flickStart, flickEnd, 180); // wait until it's at least one cell further QTRY_VERIFY(qAbs(gridview->contentX() - origContentX) > 80 || @@ -4345,7 +4346,7 @@ void tst_QQuickGridView::snapToRow() // flick to end do { - flick(window, flickStart, flickEnd, 180); + QQuickTest::pointerFlick(device, window, 0, flickStart, flickEnd, 180); QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops } while (flow == QQuickGridView::FlowLeftToRight ? !gridview->isAtYEnd() @@ -4358,7 +4359,7 @@ void tst_QQuickGridView::snapToRow() // flick to start do { - flick(window, flickEnd, flickStart, 180); + QQuickTest::pointerFlick(device, window, 0, flickEnd, flickStart, 180); QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops } while (flow == QQuickGridView::FlowLeftToRight ? !gridview->isAtYBeginning() @@ -4423,6 +4424,7 @@ void tst_QQuickGridView::snapOneRow() QFETCH(qreal, endExtent); QFETCH(qreal, startExtent); QFETCH(qreal, flickSlowdown); + auto device = QPointingDevice::primaryPointingDevice(); qreal flickDuration = 180 * flickSlowdown; @@ -4447,7 +4449,7 @@ void tst_QQuickGridView::snapOneRow() QSignalSpy currentIndexSpy(gridview, SIGNAL(currentIndexChanged())); // confirm that a flick hits next row boundary - flick(window, flickStart, flickEnd, flickDuration); + QQuickTest::pointerFlick(device, window, 0, flickStart, flickEnd, flickDuration); QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops if (flow == QQuickGridView::FlowLeftToRight) QCOMPARE(gridview->contentY(), snapAlignment); @@ -4461,7 +4463,8 @@ void tst_QQuickGridView::snapOneRow() // flick to end do { - flick(window, flickStart, flickEnd, flickDuration); + QQuickTest::pointerFlick(device, window, 0, flickStart, flickEnd, + flickDuration, Qt::LeftButton, Qt::NoModifier, 500); QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops } while (flow == QQuickGridView::FlowLeftToRight ? !gridview->isAtYEnd() @@ -4479,7 +4482,8 @@ void tst_QQuickGridView::snapOneRow() // flick to start do { - flick(window, flickEnd, flickStart, flickDuration); + QQuickTest::pointerFlick(device, window, 0, flickEnd, flickStart, + flickDuration, Qt::LeftButton, Qt::NoModifier, 500); QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops } while (flow == QQuickGridView::FlowLeftToRight ? !gridview->isAtYBeginning() @@ -6701,6 +6705,7 @@ void tst_QQuickGridView::positionViewAtBeginningAfterResizingCells() void tst_QQuickGridView::keyNavigationEnabled() { + auto device = QPointingDevice::primaryPointingDevice(); QScopedPointer<QQuickView> window(createView()); window->setSource(testFileUrl("keyNavigationEnabled.qml")); window->show(); @@ -6723,7 +6728,7 @@ void tst_QQuickGridView::keyNavigationEnabled() QCOMPARE(enabledSpy.size(), 1); QCOMPARE(gridView->isKeyNavigationEnabled(), false); - flick(window.data(), QPoint(200, 175), QPoint(200, 50), 100); + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(200, 175), QPoint(200, 50), 100); QVERIFY(!gridView->isMoving()); QCOMPARE(gridView->contentY(), 0.0); QCOMPARE(gridView->currentIndex(), 0); @@ -6744,7 +6749,7 @@ void tst_QQuickGridView::keyNavigationEnabled() // Setting keyNavigationEnabled to true shouldn't enable mouse interaction. gridView->setKeyNavigationEnabled(true); QCOMPARE(enabledSpy.size(), 4); - flick(window.data(), QPoint(200, 175), QPoint(200, 50), 100); + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(200, 175), QPoint(200, 50), 100); QVERIFY(!gridView->isMoving()); QCOMPARE(gridView->contentY(), 0.0); QCOMPARE(gridView->currentIndex(), 0); @@ -6766,6 +6771,7 @@ void tst_QQuickGridView::keyNavigationEnabled() void tst_QQuickGridView::QTBUG_48870_fastModelUpdates() { + auto device = QPointingDevice::primaryPointingDevice(); StressTestModel model; QScopedPointer<QQuickView> window(createView()); @@ -6793,9 +6799,9 @@ void tst_QQuickGridView::QTBUG_48870_fastModelUpdates() : QString("Found index %1, expected index is %3").arg(item->index).arg(expectedIdx))); if (i % 3 != 0) { if (i & 1) - flick(window.data(), QPoint(100, 200), QPoint(100, 0), 100); + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(100, 200), QPoint(100, 0), 100); else - flick(window.data(), QPoint(100, 200), QPoint(100, 400), 100); + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(100, 200), QPoint(100, 400), 100); } } } diff --git a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp index f6de1b482c..183868af8e 100644 --- a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp +++ b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp @@ -87,6 +87,7 @@ private slots: void mapCoordinates_data(); void mapCoordinatesRect(); void mapCoordinatesRect_data(); + void mapCoordinatesWithFraction(); void propertyChanges(); void nonexistentPropertyConnection(); void transforms(); @@ -2815,6 +2816,14 @@ void tst_QQuickItem::transforms_data() << QTransform(1,0,0,0,1,0,10,20,1) * QTransform(1.5,0,0,0,-2,0,0,0,1); } +void tst_QQuickItem::mapCoordinatesWithFraction() +{ + QQuickItem parent; + QQuickItem child(&parent); + const QPointF result = child.mapToItem(&parent, 1.5, 1.5); + QCOMPARE(result, QPointF(1.5, 1.5)); +} + void tst_QQuickItem::transforms() { QFETCH(QByteArray, qml); diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp index 747478fc9a..c43278c553 100644 --- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp +++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp @@ -2730,6 +2730,7 @@ void tst_QQuickListView::sectionsSnap() QFETCH(QQuickListView::SnapMode, snapMode); QFETCH(QPoint, point); QFETCH(int, duration); + auto device = QPointingDevice::primaryPointingDevice(); QScopedPointer<QQuickView> window(createView()); window->setSource(testFileUrl("sectionSnapping.qml")); @@ -2745,28 +2746,28 @@ void tst_QQuickListView::sectionsSnap() QCOMPARE(listview->contentY(), qreal(-50)); // move down - flick(window.data(), QPoint(100, 100), point, duration); + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(100, 100), point, duration); QTRY_VERIFY(!listview->isMovingVertically()); QCOMPARE(listview->contentY(), qreal(0)); - flick(window.data(), QPoint(100, 100), point, duration); + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(100, 100), point, duration); QTRY_VERIFY(!listview->isMovingVertically()); QCOMPARE(listview->contentY(), qreal(50)); - flick(window.data(), QPoint(100, 100), point, duration); + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(100, 100), point, duration); QTRY_VERIFY(!listview->isMovingVertically()); QCOMPARE(listview->contentY(), qreal(150)); // move back up - flick(window.data(), point, QPoint(100, 100), duration); + QQuickTest::pointerFlick(device, window.data(), 0, point, QPoint(100, 100), duration); QTRY_VERIFY(!listview->isMovingVertically()); QCOMPARE(listview->contentY(), qreal(50)); - flick(window.data(), point, QPoint(100, 100), duration); + QQuickTest::pointerFlick(device, window.data(), 0, point, QPoint(100, 100), duration); QTRY_VERIFY(!listview->isMovingVertically()); QCOMPARE(listview->contentY(), qreal(0)); - flick(window.data(), point, QPoint(100, 100), duration); + QQuickTest::pointerFlick(device, window.data(), 0, point, QPoint(100, 100), duration); QTRY_VERIFY(!listview->isMovingVertically()); QCOMPARE(listview->contentY(), qreal(-50)); } @@ -5166,6 +5167,7 @@ void tst_QQuickListView::marginsResize() QFETCH(QQuickItemView::VerticalLayoutDirection, verticalLayoutDirection); QFETCH(qreal, start); QFETCH(qreal, end); + auto device = QPointingDevice::primaryPointingDevice(); QPoint flickStart(20, 20); QPoint flickEnd(20, 20); @@ -5205,7 +5207,7 @@ void tst_QQuickListView::marginsResize() QTRY_COMPARE(listview->contentX(), end); // flick past the end and check content pos still settles on correct extents - flick(window, flickStart, flickEnd, flickDistance); + QQuickTest::pointerFlick(device, window, 0, flickStart, flickEnd, flickDistance); QTRY_VERIFY(!listview->isMoving()); if (orientation == QQuickListView::Vertical) QTRY_COMPARE(listview->contentY(), end); @@ -5220,7 +5222,7 @@ void tst_QQuickListView::marginsResize() QTRY_COMPARE(listview->contentX(), start); // flick past the beginning and check content pos still settles on correct extents - flick(window, flickEnd, flickStart, flickDistance); + QQuickTest::pointerFlick(device, window, 0, flickEnd, flickStart, flickDistance); QTRY_VERIFY(!listview->isMoving()); if (orientation == QQuickListView::Vertical) QTRY_COMPARE(listview->contentY(), start); @@ -5313,6 +5315,7 @@ void tst_QQuickListView::snapToItem() QFETCH(qreal, snapAlignment); QFETCH(qreal, endExtent); QFETCH(qreal, startExtent); + auto device = QPointingDevice::primaryPointingDevice(); QQuickView *window = getView(); QQuickViewTestUtils::moveMouseAway(window); @@ -5335,7 +5338,7 @@ void tst_QQuickListView::snapToItem() QTRY_VERIFY(contentItem != nullptr); // confirm that a flick hits an item boundary - flick(window, flickStart, flickEnd, 180); + QQuickTest::pointerFlick(device, window, 0, flickStart, flickEnd, 180); QTRY_VERIFY(listview->isMoving() == false); // wait until it stops if (orientation == QQuickListView::Vertical) QCOMPARE(qreal(fmod(listview->contentY(),80.0)), snapAlignment); @@ -5344,7 +5347,7 @@ void tst_QQuickListView::snapToItem() // flick to end do { - flick(window, flickStart, flickEnd, 180); + QQuickTest::pointerFlick(device, window, 0, flickStart, flickEnd, 180); QTRY_VERIFY(listview->isMoving() == false); // wait until it stops } while (orientation == QQuickListView::Vertical ? verticalLayoutDirection == QQuickItemView::TopToBottom ? !listview->isAtYEnd() : !listview->isAtYBeginning() @@ -5357,7 +5360,7 @@ void tst_QQuickListView::snapToItem() // flick to start do { - flick(window, flickEnd, flickStart, 180); + QQuickTest::pointerFlick(device, window, 0, flickEnd, flickStart, 180); QTRY_VERIFY(listview->isMoving() == false); // wait until it stops } while (orientation == QQuickListView::Vertical ? verticalLayoutDirection == QQuickItemView::TopToBottom ? !listview->isAtYBeginning() : !listview->isAtYEnd() @@ -5398,6 +5401,7 @@ void tst_QQuickListView::snapToItemWithSpacing_QTBUG_59852() void tst_QQuickListView::snapToItemWithSectionAtStart() // QTBUG-30768 { + auto device = QPointingDevice::primaryPointingDevice(); QQuickView window; QVERIFY(QQuickTest::showView(window, testFileUrl("snapToItemWithSectionAtStart.qml"))); QQuickListView *listView = qobject_cast<QQuickListView *>(window.rootObject()); @@ -5411,7 +5415,7 @@ void tst_QQuickListView::snapToItemWithSectionAtStart() // QTBUG-30768 const QPoint start = even ? QPoint(20, 100 + i * 5) : QPoint(20, 20 + i * 3); const QPoint end = even ? start - QPoint(0, 50 + i * 10) : start + QPoint(0, 50 + i * 5); - flick(&window, start, end, 180); + QQuickTest::pointerFlick(device, &window, 0, start, end, 180); QTRY_COMPARE(listView->isMoving(), false); // wait until it stops QCOMPARE(int(listView->contentY()) % 30, 0); } @@ -6330,6 +6334,7 @@ void tst_QQuickListView::snapOneItem() QFETCH(qreal, endExtent); QFETCH(qreal, startExtent); QFETCH(qreal, flickSlowdown); + auto device = QPointingDevice::primaryPointingDevice(); qreal flickDuration = 180 * flickSlowdown; @@ -6356,7 +6361,7 @@ void tst_QQuickListView::snapOneItem() QSignalSpy currentIndexSpy(listview, SIGNAL(currentIndexChanged())); // confirm that a flick hits the next item boundary - flick(window, flickStart, flickEnd, flickDuration); + QQuickTest::pointerFlick(device, window, 0, flickStart, flickEnd, flickDuration); QTRY_VERIFY(listview->isMoving() == false); // wait until it stops if (orientation == QQuickListView::Vertical) QCOMPARE(listview->contentY(), snapAlignment); @@ -6370,7 +6375,8 @@ void tst_QQuickListView::snapOneItem() // flick to end do { - flick(window, flickStart, flickEnd, flickDuration); + QQuickTest::pointerFlick(device, window, 0, flickStart, flickEnd, flickDuration, + Qt::LeftButton, Qt::NoModifier, 500); QTRY_VERIFY(listview->isMoving() == false); // wait until it stops } while (orientation == QQuickListView::Vertical ? verticalLayoutDirection == QQuickItemView::TopToBottom ? !listview->isAtYEnd() : !listview->isAtYBeginning() @@ -6388,7 +6394,8 @@ void tst_QQuickListView::snapOneItem() // flick to start do { - flick(window, flickEnd, flickStart, flickDuration); + QQuickTest::pointerFlick(device, window, 0, flickEnd, flickStart, flickDuration, + Qt::LeftButton, Qt::NoModifier, 500); QTRY_VERIFY(listview->isMoving() == false); // wait until it stops } while (orientation == QQuickListView::Vertical ? verticalLayoutDirection == QQuickItemView::TopToBottom ? !listview->isAtYBeginning() : !listview->isAtYEnd() @@ -7968,6 +7975,7 @@ void tst_QQuickListView::matchItemLists(const QVariantList &itemLists, const QLi void tst_QQuickListView::flickBeyondBounds() { + auto device = QPointingDevice::primaryPointingDevice(); QScopedPointer<QQuickView> window(createView()); QQuickVisualTestUtils::moveMouseAway(window.data()); @@ -7984,7 +7992,7 @@ void tst_QQuickListView::flickBeyondBounds() QVERIFY(QQuickTest::qWaitForPolish(listview)); // Flick view up beyond bounds - flick(window.data(), QPoint(10, 10), QPoint(10, -2000), 180); + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(10, 10), QPoint(10, -2000), 180); #ifdef Q_OS_MAC QSKIP("Disabled due to flaky behavior on CI system (QTBUG-44493)"); QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper").count(), 0); @@ -8009,6 +8017,7 @@ void tst_QQuickListView::flickBothDirections() QFETCH(qreal, contentWidth); QFETCH(qreal, contentHeight); QFETCH(QPointF, targetPos); + auto device = QPointingDevice::primaryPointingDevice(); QQuickView *window = getView(); QQuickViewTestUtils::moveMouseAway(window); @@ -8035,7 +8044,7 @@ void tst_QQuickListView::flickBothDirections() listview->setContentHeight(contentHeight); } - flick(window, QPoint(140, 140), QPoint(25, 25), 50); + QQuickTest::pointerFlick(device, window, 0, QPoint(140, 140), QPoint(25, 25), 50); QVERIFY(listview->isMoving()); QTRY_VERIFY(!listview->isMoving()); QCOMPARE(listview->contentX(), targetPos.x()); @@ -8850,6 +8859,7 @@ void tst_QQuickListView::roundingErrors_data() void tst_QQuickListView::QTBUG_38209() { + auto device = QPointingDevice::primaryPointingDevice(); QScopedPointer<QQuickView> window(createView()); window->setSource(testFileUrl("simplelistview.qml")); window->show(); @@ -8859,7 +8869,7 @@ void tst_QQuickListView::QTBUG_38209() QVERIFY(listview); // simulate mouse flick - flick(window.data(), QPoint(200, 200), QPoint(200, 50), 100); + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(200, 200), QPoint(200, 50), 100); QTRY_VERIFY(!listview->isMoving()); qreal contentY = listview->contentY(); @@ -9225,6 +9235,7 @@ void tst_QQuickListView::contentHeightWithDelayRemove() void tst_QQuickListView::QTBUG_48044_currentItemNotVisibleAfterTransition() { + auto device = QPointingDevice::primaryPointingDevice(); QScopedPointer<QQuickView> window(createView()); window->setSource(testFileUrl("qtbug48044.qml")); window->show(); @@ -9239,7 +9250,7 @@ void tst_QQuickListView::QTBUG_48044_currentItemNotVisibleAfterTransition() QTRY_VERIFY(listview->property("transitionsDone").toBool()); // Flick listview to the bottom - flick(window.data(), QPoint(window->width() / 2, 400), QPoint(window->width() / 2, 0), 100); + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(window->width() / 2, 400), QPoint(window->width() / 2, 0), 100); QTRY_VERIFY(!listview->isMoving()); // Expand 3rd header @@ -9260,6 +9271,7 @@ void tst_QQuickListView::QTBUG_48044_currentItemNotVisibleAfterTransition() void tst_QQuickListView::keyNavigationEnabled() { + auto device = QPointingDevice::primaryPointingDevice(); QScopedPointer<QQuickView> window(createView()); window->setSource(testFileUrl("keyNavigationEnabled.qml")); window->show(); @@ -9282,7 +9294,7 @@ void tst_QQuickListView::keyNavigationEnabled() QCOMPARE(enabledSpy.size(), 1); QCOMPARE(listView->isKeyNavigationEnabled(), false); - flick(window.data(), QPoint(200, 200), QPoint(200, 50), 100); + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(200, 200), QPoint(200, 50), 100); QVERIFY(!listView->isMoving()); QCOMPARE(listView->contentY(), 0.0); QCOMPARE(listView->currentIndex(), 0); @@ -9303,7 +9315,7 @@ void tst_QQuickListView::keyNavigationEnabled() // Setting keyNavigationEnabled to true shouldn't enable mouse interaction. listView->setKeyNavigationEnabled(true); QCOMPARE(enabledSpy.size(), 4); - flick(window.data(), QPoint(200, 200), QPoint(200, 50), 100); + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(200, 200), QPoint(200, 50), 100); QVERIFY(!listView->isMoving()); QCOMPARE(listView->contentY(), 0.0); QCOMPARE(listView->currentIndex(), 0); @@ -9369,6 +9381,7 @@ void tst_QQuickListView::QTBUG_61269_appendDuringScrollDown() // AKA QTBUG-62864 void tst_QQuickListView::QTBUG_48870_fastModelUpdates() { + auto device = QPointingDevice::primaryPointingDevice(); StressTestModel model; QScopedPointer<QQuickView> window(createView()); @@ -9396,9 +9409,9 @@ void tst_QQuickListView::QTBUG_48870_fastModelUpdates() : QString("Found index %1, expected index is %3").arg(item->index).arg(expectedIdx))); if (i % 3 != 0) { if (i & 1) - flick(window.data(), QPoint(100, 200), QPoint(100, 0), 100); + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(100, 200), QPoint(100, 0), 100); else - flick(window.data(), QPoint(100, 200), QPoint(100, 400), 100); + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(100, 200), QPoint(100, 400), 100); } } } diff --git a/tests/auto/quick/qquickmousearea/data/hoverPosition.qml b/tests/auto/quick/qquickmousearea/data/hoverPosition.qml index 834f91ff29..01beb9a9af 100644 --- a/tests/auto/quick/qquickmousearea/data/hoverPosition.qml +++ b/tests/auto/quick/qquickmousearea/data/hoverPosition.qml @@ -1,16 +1,15 @@ -import QtQuick 2.0 +import QtQuick Rectangle { - width: 400; height: 400; - - property real mouseX: mousetracker.mouseX - property real mouseY: mousetracker.mouseY + width: 400; height: 400 Rectangle { - width: 100; height: 100; + width: 100; height: 100 + color: mousetracker.containsMouse ? "lightsteelblue" : "beige" + MouseArea { - id: mousetracker; - anchors.fill: parent; + id: mousetracker + anchors.fill: parent hoverEnabled: true } } diff --git a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp index d5b3b75215..56a2ef01ed 100644 --- a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp +++ b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp @@ -143,6 +143,7 @@ private slots: void mask(); void nestedEventDelivery(); void settingHiddenInPressUngrabs(); + void pressAfterHiding(); void negativeZStackingOrder(); void containsMouseAndVisibility(); void containsMouseAndVisibilityMasked(); @@ -1339,16 +1340,25 @@ void tst_QQuickMouseArea::hoverPosition() { QQuickView window; QVERIFY(QQuickTest::showView(window, testFileUrl("hoverPosition.qml"))); - QQuickItem *root = window.rootObject(); - QVERIFY(root); + QQuickMouseArea *mouseArea = window.rootObject()->findChild<QQuickMouseArea*>(); + QVERIFY(mouseArea); - QCOMPARE(root->property("mouseX").toReal(), qreal(0)); - QCOMPARE(root->property("mouseY").toReal(), qreal(0)); + QSignalSpy xChangedSpy(mouseArea, &QQuickMouseArea::mouseXChanged); + QSignalSpy yChangedSpy(mouseArea, &QQuickMouseArea::mouseYChanged); + QSignalSpy positionChangedSpy(mouseArea, &QQuickMouseArea::positionChanged); - QTest::mouseMove(&window,QPoint(10,32)); + // showView() moves the mouse outside; so position is not yet known, and defaults to 0,0 + QCOMPARE(mouseArea->mouseX(), qreal(0)); + QCOMPARE(mouseArea->mouseY(), qreal(0)); - QCOMPARE(root->property("mouseX").toReal(), qreal(10)); - QCOMPARE(root->property("mouseY").toReal(), qreal(32)); + // simulate movement of the mouse inside + QTest::mouseMove(&window, QPoint(10,32)); + + QCOMPARE(xChangedSpy.size(), 1); + QCOMPARE(yChangedSpy.size(), 1); + QCOMPARE(positionChangedSpy.size(), 1); // QTBUG-127122 + QCOMPARE(mouseArea->mouseX(), qreal(10)); + QCOMPARE(mouseArea->mouseY(), qreal(32)); } void tst_QQuickMouseArea::hoverPropagation() @@ -2449,7 +2459,7 @@ void tst_QQuickMouseArea::nestedEventDelivery() // QTBUG-70898 QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(50,150)); } -void tst_QQuickMouseArea::settingHiddenInPressUngrabs() +void tst_QQuickMouseArea::settingHiddenInPressUngrabs() // QTBUG-74987 { // When an item sets itself hidden, while handling pressed, it doesn't receive the grab. // But that in turn means it doesn't see any release events, so we need to make sure it @@ -2486,6 +2496,22 @@ void tst_QQuickMouseArea::settingHiddenInPressUngrabs() QVERIFY(!mouseArea->pressed()); } +void tst_QQuickMouseArea::pressAfterHiding() // QTBUG-128577 +{ + QQuickView window; + QVERIFY(QQuickTest::showView(window, testFileUrl("simple.qml"))); + QQuickItem *root = window.rootObject(); + QVERIFY(root); + QQuickMouseArea *mouseArea = window.rootObject()->findChild<QQuickMouseArea *>(); + QVERIFY(mouseArea); + + mouseArea->setVisible(false); + const QPointF p(100, 100); + QMouseEvent me(QEvent::MouseButtonPress, p, window.mapToGlobal(p), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); + QGuiApplication::sendEvent(mouseArea, &me); + QCOMPARE(mouseArea->pressed(), false); +} + void tst_QQuickMouseArea::negativeZStackingOrder() // QTBUG-83114 { QQuickView window; diff --git a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp index 7d41d907fb..f59beb0dbb 100644 --- a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp +++ b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp @@ -1568,6 +1568,7 @@ void tst_QQuickPathView::mouseDrag() void tst_QQuickPathView::nestedMouseAreaDrag() { + auto device = QPointingDevice::primaryPointingDevice(); QScopedPointer<QQuickView> window(createView()); QQuickVisualTestUtils::moveMouseAway(window.data()); window->setSource(testFileUrl("nestedmousearea.qml")); @@ -1578,16 +1579,17 @@ void tst_QQuickPathView::nestedMouseAreaDrag() QVERIFY(pathview != nullptr); // Dragging the child mouse area should move it and not animate the PathView - flick(window.data(), QPoint(200,200), QPoint(400,200), 200); + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(200,200), QPoint(400,200), 200); QVERIFY(!pathview->isMoving()); // Dragging outside the mouse are should animate the PathView. - flick(window.data(), QPoint(75,75), QPoint(175,75), 200); + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(75,75), QPoint(175,75), 200); QVERIFY(pathview->isMoving()); } void tst_QQuickPathView::flickNClick() // QTBUG-77173 { + auto device = QPointingDevice::primaryPointingDevice(); QScopedPointer<QQuickView> window(createView()); QQuickVisualTestUtils::moveMouseAway(window.data()); window->setSource(testFileUrl("nestedmousearea2.qml")); @@ -1619,7 +1621,7 @@ void tst_QQuickPathView::flickNClick() // QTBUG-77173 flickStartedSpy.clear(); flickEndedSpy.clear(); // Dragging the child mouse area should animate the PathView (MA has no drag target) - flick(window.data(), QPoint(199,199), QPoint(399,199), duration); + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(199,199), QPoint(399,199), duration); QVERIFY(pathview->isMoving()); QCOMPARE(movingChangedSpy.size(), 1); QCOMPARE(draggingSpy.size(), 2); @@ -1924,6 +1926,7 @@ void tst_QQuickPathView::cancelDrag() void tst_QQuickPathView::maximumFlickVelocity() { + auto device = QPointingDevice::primaryPointingDevice(); QScopedPointer<QQuickView> window(createView()); window->setSource(testFileUrl("dragpath.qml")); QQuickVisualTestUtils::moveMouseAway(window.data()); @@ -1934,7 +1937,7 @@ void tst_QQuickPathView::maximumFlickVelocity() QVERIFY(pathview != nullptr); pathview->setMaximumFlickVelocity(700); - flick(window.data(), QPoint(200,10), QPoint(10,10), 180); + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(200,10), QPoint(10,10), 180); QVERIFY(pathview->isMoving()); QVERIFY(pathview->isFlicking()); QTRY_VERIFY_WITH_TIMEOUT(!pathview->isMoving(), 50000); @@ -1943,7 +1946,7 @@ void tst_QQuickPathView::maximumFlickVelocity() pathview->setOffset(0.); pathview->setMaximumFlickVelocity(300); - flick(window.data(), QPoint(200,10), QPoint(10,10), 180); + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(200,10), QPoint(10,10), 180); QVERIFY(pathview->isMoving()); QVERIFY(pathview->isFlicking()); QTRY_VERIFY_WITH_TIMEOUT(!pathview->isMoving(), 50000); @@ -1952,7 +1955,7 @@ void tst_QQuickPathView::maximumFlickVelocity() pathview->setOffset(0.); pathview->setMaximumFlickVelocity(500); - flick(window.data(), QPoint(200,10), QPoint(10,10), 180); + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(200,10), QPoint(10,10), 180); QVERIFY(pathview->isMoving()); QVERIFY(pathview->isFlicking()); QTRY_VERIFY_WITH_TIMEOUT(!pathview->isMoving(), 50000); @@ -1968,6 +1971,7 @@ void tst_QQuickPathView::maximumFlickVelocity() void tst_QQuickPathView::snapToItem() { QFETCH(bool, enforceRange); + auto device = QPointingDevice::primaryPointingDevice(); QScopedPointer<QQuickView> window(createView()); QQuickVisualTestUtils::moveMouseAway(window.data()); @@ -1985,7 +1989,7 @@ void tst_QQuickPathView::snapToItem() QSignalSpy snapModeSpy(pathview, SIGNAL(snapModeChanged())); - flick(window.data(), QPoint(200,10), QPoint(10,10), 180); + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(200,10), QPoint(10,10), 180); QVERIFY(pathview->isMoving()); QTRY_VERIFY_WITH_TIMEOUT(!pathview->isMoving(), 50000); @@ -2010,6 +2014,7 @@ void tst_QQuickPathView::snapToItem_data() void tst_QQuickPathView::snapOneItem() { QFETCH(bool, enforceRange); + auto device = QPointingDevice::primaryPointingDevice(); QScopedPointer<QQuickView> window(createView()); QQuickVisualTestUtils::moveMouseAway(window.data()); @@ -2031,7 +2036,7 @@ void tst_QQuickPathView::snapOneItem() int currentIndex = pathview->currentIndex(); double startOffset = pathview->offset(); - flick(window.data(), QPoint(200,10), QPoint(10,10), 180); + QQuickTest::pointerFlick(device, window.data(), 0, QPoint(200,10), QPoint(10,10), 180); QVERIFY(pathview->isMoving()); QTRY_VERIFY(!pathview->isMoving()); @@ -2857,6 +2862,7 @@ void tst_QQuickPathView::touchMove() void tst_QQuickPathView::mousePressAfterFlick() // QTBUG-115121 { + auto device = QPointingDevice::primaryPointingDevice(); QScopedPointer<QQuickView> window(createView()); QQuickVisualTestUtils::moveMouseAway(window.data()); window->setSource(testFileUrl("mousePressAfterFlick.qml")); @@ -2882,7 +2888,7 @@ void tst_QQuickPathView::mousePressAfterFlick() // QTBUG-115121 // Dragging the child mouse area should animate the PathView (MA has no drag target) QPoint from = QPoint((window->width() / 2), (window->height() * 3 / 4)); QPoint to = QPoint((window->width() / 2), (window->height() / 4)); - flick(window.data(), from, to, 100); + QQuickTest::pointerFlick(device, window.data(), 0, from, to, 100); QVERIFY(pathview->isMoving()); QCOMPARE(flickingSpy.size(), 1); QCOMPARE(flickStartedSpy.size(), 1); diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp index 9e5ba116ad..bb2212f025 100644 --- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp +++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp @@ -550,6 +550,8 @@ private slots: void visibleVsVisibility_data(); void visibleVsVisibility(); + void dataIsNotAList(); + private: QPointingDevice *touchDevice; // TODO make const after fixing QTBUG-107864 const QPointingDevice *touchDeviceWithVelocity; @@ -4138,6 +4140,35 @@ void tst_qquickwindow::visibleVsVisibility() QCOMPARE(window->isVisible(), expectVisible); } +void tst_qquickwindow::dataIsNotAList() +{ + QQuickWindow window; + QObject child; + QQmlListProperty<QObject> data = window.property("data").value<QQmlListProperty<QObject>>(); + + QVERIFY(data.object); + QVERIFY(data.append); + QVERIFY(data.count); + QVERIFY(data.at); + QVERIFY(data.clear); + QVERIFY(data.removeLast); + + // We must not synthesize the replace method on this property. QQuickItem doesn't support it. + QVERIFY(!data.replace); + + QCOMPARE(data.count(&data), 0); + data.append(&data, &child); + QCOMPARE(data.count(&data), 1); + QCOMPARE(data.at(&data, 0), &child); + data.removeLast(&data); + QCOMPARE(data.count(&data), 0); + data.append(&data, &child); + QCOMPARE(data.count(&data), 1); + QCOMPARE(data.at(&data, 0), &child); + data.clear(&data); + QCOMPARE(data.count(&data), 0); +} + QTEST_MAIN(tst_qquickwindow) #include "tst_qquickwindow.moc" diff --git a/tests/auto/quickcontrols/controls/data/tst_swipeview.qml b/tests/auto/quickcontrols/controls/data/tst_swipeview.qml index 694741ce45..69226e57c4 100644 --- a/tests/auto/quickcontrols/controls/data/tst_swipeview.qml +++ b/tests/auto/quickcontrols/controls/data/tst_swipeview.qml @@ -4,6 +4,7 @@ import QtQuick import QtTest import QtQuick.Controls +import QtQuick.Layouts TestCase { id: testCase @@ -694,4 +695,62 @@ TestCase { compare(page4.width, control.contentItem.width) compare(page4.height, control.contentItem.height) } + + Component { + id: zeroSizeSwipeViewWithRepeatersComponent + + Item { + objectName: "rootItem" + anchors.fill: parent + + property alias swipeView: swipeView + property int d + + Timer { + interval: 2 + running: true + repeat: false + onTriggered: d = 2 + } + + SwipeView { + id: swipeView + contentItem.objectName: "swipeViewListView" + + Repeater { + objectName: "swipeViewContentItemRepeater" + model: [ + { + title: d + } + ] + + delegate: GridLayout { + objectName: "gridLayoutDelegate" + + Repeater { + id: repeater + objectName: "delegateRepeater" + model: d + delegate: Item { + objectName: "delegate" + index + + required property int index + } + } + } + } + } + } + } + + // QTBUG-129622 + function test_zeroSizeSwipeViewWithRepeaters() { + let root = createTemporaryObject(zeroSizeSwipeViewWithRepeatersComponent, testCase) + verify(root) + + let swipeView = root.swipeView + tryCompare(root, "d", 2) + // Shouldn't crash when the model is changed. + } } diff --git a/tests/auto/quickcontrols/controls/material/CMakeLists.txt b/tests/auto/quickcontrols/controls/material/CMakeLists.txt index 506509c774..2f14b5253d 100644 --- a/tests/auto/quickcontrols/controls/material/CMakeLists.txt +++ b/tests/auto/quickcontrols/controls/material/CMakeLists.txt @@ -6,7 +6,8 @@ if (NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) cmake_minimum_required(VERSION 3.16) project(tst_material LANGUAGES C CXX ASM) - find_package(Qt6BuildInternals REQUIRED COMPONENTS ShaderTools STANDALONE_TEST) + find_package(Qt6 REQUIRED COMPONENTS ShaderTools) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) endif() ##################################################################### diff --git a/tests/auto/quickcontrols/qquickmaterialstyle/data/tst_material.qml b/tests/auto/quickcontrols/qquickmaterialstyle/data/tst_material.qml index f3dfca54f4..69a2d95ab3 100644 --- a/tests/auto/quickcontrols/qquickmaterialstyle/data/tst_material.qml +++ b/tests/auto/quickcontrols/qquickmaterialstyle/data/tst_material.qml @@ -1314,4 +1314,15 @@ TestCase { let headerItem = window.listView.headerItem compare(headerItem.Material.theme, Material.Dark) } + + // QTBUG-85860 + function test_busyIndicatorRunningChangedQuickly() { + let busyIndicator = createTemporaryObject(busyIndicatorComponent, testCase) + verify(busyIndicator) + + busyIndicator.running = false + busyIndicator.running = true + + tryCompare(busyIndicator.contentItem, "visible", true) + } } diff --git a/tests/auto/quickcontrols/qquickmenu/data/mousePropagationWithinPopup.qml b/tests/auto/quickcontrols/qquickmenu/data/mousePropagationWithinPopup.qml new file mode 100644 index 0000000000..9e419fbf87 --- /dev/null +++ b/tests/auto/quickcontrols/qquickmenu/data/mousePropagationWithinPopup.qml @@ -0,0 +1,33 @@ +import QtQuick +import QtQuick.Controls + +ApplicationWindow { + width: 360 + height: 360 + + property alias popup: popup + property alias nestedMenu: nestedMenu + property alias mouseArea: mouseArea + + Popup { + id: popup + width: 200 + height: 200 + MouseArea { + id: mouseArea + anchors.fill: parent + } + Menu { + id: nestedMenu + width: 100 + height: 100 + MenuItem { + text: "Menu item 1" + } + MenuItem { + text: "Menu item 2" + enabled: false + } + } + } +} diff --git a/tests/auto/quickcontrols/qquickmenu/tst_qquickmenu.cpp b/tests/auto/quickcontrols/qquickmenu/tst_qquickmenu.cpp index f54678b686..bec3a1f27c 100644 --- a/tests/auto/quickcontrols/qquickmenu/tst_qquickmenu.cpp +++ b/tests/auto/quickcontrols/qquickmenu/tst_qquickmenu.cpp @@ -15,6 +15,9 @@ #include <QtQml/qqmlcontext.h> #include <QtQuick/qquickview.h> #include <QtQuick/private/qquickitem_p.h> +#include <QtQuick/private/qquickmousearea_p.h> +#include <QtQuick/private/qquickrectangle_p.h> +#include <QtQuickTest/quicktest.h> #include <QtQuickTestUtils/private/qmlutils_p.h> #include <QtQuickTestUtils/private/visualtestutils_p.h> #include <QtQuickControlsTestUtils/private/controlstestutils_p.h> @@ -91,6 +94,7 @@ private slots: void customMenuCullItems(); void customMenuUseRepeaterAsTheContentItem(); void invalidUrlInImgTag(); + void mousePropagationWithinPopup(); }; tst_QQuickMenu::tst_QQuickMenu() @@ -2322,6 +2326,54 @@ void tst_QQuickMenu::invalidUrlInImgTag() QVERIFY(menuItemFirst); } +void tst_QQuickMenu::mousePropagationWithinPopup() +{ + QQuickControlsApplicationHelper helper(this, QLatin1String("mousePropagationWithinPopup.qml")); + QVERIFY2(helper.ready, helper.failureMessage()); + + QQuickApplicationWindow *window = helper.appWindow; + centerOnScreen(window); + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + QQuickPopup *popup = window->property("popup").value<QQuickPopup*>(); + QVERIFY(popup); + popup->open(); + QTRY_VERIFY(popup->isOpened()); + + QQuickMenu *nestedMenu = window->property("nestedMenu").value<QQuickMenu*>(); + QVERIFY(nestedMenu); + nestedMenu->open(); + QTRY_VERIFY(nestedMenu->isOpened()); + + QQuickMouseArea *mouseArea = window->property("mouseArea").value<QQuickMouseArea *>(); + QVERIFY(mouseArea); + + QSignalSpy clickedSpy(mouseArea, &QQuickMouseArea::clicked); + QQuickMenuItem *menuItem2 = qobject_cast<QQuickMenuItem *>(nestedMenu->itemAt(1)); + QVERIFY(menuItem2); + QVERIFY(!menuItem2->isEnabled()); + + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, mapCenterToWindow(menuItem2)); + QCOMPARE(clickedSpy.size(), 0); + + // Check on the gap area between menu and its item + // Note: Skip verifying this case for the styles (such as Imagine) that doesn't have gap + // between menu and its item + const auto menuItem1 = qobject_cast<QQuickMenuItem *>(nestedMenu->itemAt(0)); + QVERIFY(menuItem1); + const QPointF point = menuItem1->mapToItem(nestedMenu->background(), QPointF(0, 0)); + const bool xAxis = (point.x() + nestedMenu->leftInset()) > 0; + const bool yAxis = (point.y() + nestedMenu->topInset()) > 0; + if (xAxis || yAxis) { + const auto menuItem1Pos = mapCenterToWindow(menuItem1); + QPoint gapPoint(xAxis ? menuItem1Pos.x() - menuItem1->width() / 2 - 1 : menuItem1Pos.x(), + yAxis ? menuItem1Pos.y() : menuItem1Pos.y() - menuItem1->height() / 2 - 1); + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, gapPoint); + QCOMPARE(clickedSpy.size(), 0); + } +} + QTEST_QUICKCONTROLS_MAIN(tst_QQuickMenu) #include "tst_qquickmenu.moc" diff --git a/tests/auto/quickcontrols/qquickpopup/data/parentToOverlay.qml b/tests/auto/quickcontrols/qquickpopup/data/parentToOverlay.qml new file mode 100644 index 0000000000..a5767cfed4 --- /dev/null +++ b/tests/auto/quickcontrols/qquickpopup/data/parentToOverlay.qml @@ -0,0 +1,41 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +import QtQuick +import QtQuick.Controls + +ApplicationWindow { + width: 600 + height: 600 + + property alias button: buttonInPopup + property alias lowerMouseArea: lowerMA + property alias upperMouseArea: upperMA + + MouseArea { + id: lowerMA + anchors.fill: parent + } + + Popup { + anchors.centerIn: Overlay.overlay + width: 400 + height: 400 + modal: true + dim: true + + Button { + id: buttonInPopup + anchors.centerIn: parent + text: "click me" + } + } + + MouseArea { + id: upperMA + parent: Overlay.overlay + anchors.fill: parent + z: 1 + } +} + diff --git a/tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp b/tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp index ee535caa8e..b046be8d44 100644 --- a/tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp +++ b/tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp @@ -103,6 +103,7 @@ private slots: void focusMultiplePopup(); void contentChildrenChange(); void doubleClickInMouseArea(); + void pointerEventsNotBlockedForNonPopupChildrenOfOverlayWithHigherZ(); void resetHoveredStateForItemsWithinPopup(); private: @@ -1282,7 +1283,7 @@ void tst_QQuickPopup::modelessOnModalOnModeless() QQuickPopup *modalPopup = window->property("modalPopup").value<QQuickPopup *>(); QVERIFY(modalPopup); QQuickPopup *tooltip = window->property("tooltip").value<QQuickPopup *>(); - QVERIFY(modalPopup); + QVERIFY(tooltip); modelessPopup->open(); QCOMPARE(modelessPopup->isVisible(), true); @@ -2314,6 +2315,52 @@ void tst_QQuickPopup::doubleClickInMouseArea() QCOMPARE(longPressSpy.count(), 0); } +// The test verifies that press and release events for items that are ancestors of the overlay, +// but not a popup item, are not filtered by modal popups. +void tst_QQuickPopup::pointerEventsNotBlockedForNonPopupChildrenOfOverlayWithHigherZ() +{ + QQuickApplicationHelper helper(this, "parentToOverlay.qml"); + QVERIFY2(helper.ready, helper.failureMessage()); + + QQuickWindow *window = helper.window; + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + auto *popup = window->contentItem()->findChild<QQuickPopup *>(); + QVERIFY(popup); + QQuickMouseArea *lowerMouseArea = window->property("lowerMouseArea").value<QQuickMouseArea *>(); + QVERIFY(lowerMouseArea); + QQuickMouseArea *upperMouseArea = window->property("upperMouseArea").value<QQuickMouseArea *>(); + QVERIFY(upperMouseArea); + QQuickAbstractButton *button = window->property("button").value<QQuickAbstractButton *>(); + QVERIFY(button); + + QSignalSpy lowerMouseAreaSpy(lowerMouseArea, &QQuickMouseArea::clicked); + QSignalSpy upperMouseAreaSpy(upperMouseArea, &QQuickMouseArea::clicked); + QSignalSpy buttonSpy(button, &QQuickAbstractButton::clicked); + + popup->open(); + QTRY_VERIFY(popup->isOpened()); + + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, button->mapToScene(button->boundingRect().center()).toPoint()); + + // The event should have been consumed by the upperMouseArea, + // since it's in the same hierarchy as the popup item, with a higher z. + QTRY_COMPARE(upperMouseAreaSpy.count(), 1); + QCOMPARE(lowerMouseAreaSpy.count(), 0); + QCOMPARE(buttonSpy.count(), 0); + + upperMouseArea->setEnabled(false); + + QVERIFY(clickButton(button)); + // Since the upperMouseArea is disabled, the event should be sent to the button inside the popup. + QCOMPARE(buttonSpy.count(), 1); + QCOMPARE(lowerMouseAreaSpy.count(), 0); + QCOMPARE(upperMouseAreaSpy.count(), 1); + + popup->close(); +} + void tst_QQuickPopup::resetHoveredStateForItemsWithinPopup() { QQuickControlsApplicationHelper helper(this, "resetHoveredForItemsWithinOverlay.qml"); diff --git a/tests/auto/quickwidgets/qquickwidget/data/overlayGeometry.qml b/tests/auto/quickwidgets/qquickwidget/data/overlayGeometry.qml new file mode 100644 index 0000000000..115099ee3a --- /dev/null +++ b/tests/auto/quickwidgets/qquickwidget/data/overlayGeometry.qml @@ -0,0 +1,24 @@ +import QtQuick +import QtQuick.Controls + +Rectangle +{ + objectName: "rectangle" + width: 255 + height: 381 + visible: true + + Popup + { + objectName: "popup" + anchors.centerIn: parent + modal: true + + Rectangle + { + color: "red" + width: 40 + height: 40 + } + } +} diff --git a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp index 73411e5b8a..2733f2d5bf 100644 --- a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp +++ b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp @@ -13,6 +13,8 @@ #include <QtQuick/private/qquickmousearea_p.h> #include <QtQuick/private/qquicktaphandler_p.h> #include <QtQuickTemplates2/private/qquickbutton_p.h> +#include <QtQuickTemplates2/private/qquickoverlay_p.h> +#include <QtQuickTemplates2/private/qquickpopup_p.h> #include <QtQuickTestUtils/private/qmlutils_p.h> #include <QtQuickTestUtils/private/visualtestutils_p.h> #include <QtGui/QWindow> @@ -135,6 +137,8 @@ private slots: void touchMultipleWidgets(); void tabKey(); void resizeOverlay(); + void overlayGeometry_data(); + void overlayGeometry(); void controls(); void focusOnClick(); #if QT_CONFIG(graphicsview) @@ -875,6 +879,56 @@ void tst_qquickwidget::resizeOverlay() QCOMPARE(overlay->height(), rootItem->height()); } +/* + Overlaps with resizeOverlay, but uses a proper + Qt Quick Controls Overlay. +*/ +void tst_qquickwidget::overlayGeometry_data() +{ + QTest::addColumn<QQuickWidget::ResizeMode>("resizeMode"); + + QTest::addRow("SizeRootObjectToView") << QQuickWidget::SizeRootObjectToView; + QTest::addRow("SizeViewToRootObject") << QQuickWidget::SizeViewToRootObject; +} + +void tst_qquickwidget::overlayGeometry() +{ + QFETCH(const QQuickWidget::ResizeMode, resizeMode); + + QWidget window; + + QQuickWidget widget(testFileUrl("overlayGeometry.qml"), &window); + widget.setResizeMode(resizeMode); + + QCOMPARE(widget.status(), QQuickWidget::Ready); + const auto *rootItem = qobject_cast<QQuickItem*>(widget.rootObject()); + QVERIFY(rootItem); + const QSizeF preferredSize = rootItem->size(); + + auto *popup = rootItem->findChild<QQuickPopup *>("popup"); + QVERIFY(popup); + popup->open(); + QTRY_VERIFY(popup->isOpened()); + + const auto *overlay = QQuickOverlay::overlay(widget.quickWindow()); + QVERIFY(overlay); + + QTestPrivate::androidCompatibleShow(&window); + QVERIFY(QTest::qWaitForWindowExposed(&window)); + QCOMPARE(widget.size(), preferredSize.toSize()); + QCOMPARE(overlay->position(), QPointF(0, 0)); + QCOMPARE(overlay->size(), widget.size()); + + widget.resize((preferredSize * 2).toSize()); + QCOMPARE(overlay->position(), QPointF(0, 0)); + QEXPECT_FAIL("SizeViewToRootObject", "QTBUG-115536", Continue); + QCOMPARE(overlay->size(), widget.size()); + + // click outside the popup, make sure it closes + QTest::mouseClick(&widget, Qt::LeftButton, {}, QPoint(10, 10)); + QTRY_VERIFY(!popup->isOpened()); +} + void tst_qquickwidget::controls() { // Smoke test for having some basic Quick Controls in a scene in a QQuickWidget. |
