aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto
diff options
context:
space:
mode:
authorTarja Sundqvist <tarja.sundqvist@qt.io>2025-12-15 16:14:22 +0200
committerTarja Sundqvist <tarja.sundqvist@qt.io>2025-12-15 16:14:22 +0200
commitb58ec3b086518da5aa573f99426235854c23e35f (patch)
tree861a9935d8f1cdba2fdca546836a351736dbddbf /tests/auto
parent4826f86e274f1b29bd769e6790824f9e62a40f62 (diff)
parent22032227d16c39211e2ebceef97d21f4d89c7c87 (diff)
Merge tag 'v6.5.8-lts-lgpl' into 6.56.5
Qt 6.5.8-lts-lgpl release
Diffstat (limited to 'tests/auto')
-rw-r--r--tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp40
-rw-r--r--tests/auto/qml/qjsengine/tst_qjsengine.cpp13
-rw-r--r--tests/auto/qml/qmllint/data/Enumerei/Main.qml22
-rw-r--r--tests/auto/qml/qmllint/data/Enumerei/plugins.qmltypes44
-rw-r--r--tests/auto/qml/qmllint/data/Enumerei/qmldir3
-rw-r--r--tests/auto/qml/qmllint/data/enumValid.qml11
-rw-r--r--tests/auto/qml/qmllint/tst_qmllint.cpp1
-rw-r--r--tests/auto/qml/qmltyperegistrar/CMakeLists.txt1
-rw-r--r--tests/auto/qml/qmltyperegistrar/brokenEnums.json57
-rw-r--r--tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp54
-rw-r--r--tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h10
-rw-r--r--tests/auto/qml/qqmlcomponent/lifecyclewatcher.h25
-rw-r--r--tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp50
-rw-r--r--tests/auto/qml/qqmldelegatemodel/data/proxyModelWithDelayedSourceModelInListView.qml30
-rw-r--r--tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp73
-rw-r--r--tests/auto/qml/qqmlengine/tst_qqmlengine.cpp37
-rw-r--r--tests/auto/qml/qqmlimport/tst_qqmlimport.cpp10
-rw-r--r--tests/auto/qml/qqmllanguage/data/TextItem.qml7
-rw-r--r--tests/auto/qml/qqmllanguage/data/Wrap.qml6
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.cpp4
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp15
-rw-r--r--tests/auto/qml/qqmltypeloader/data/SlowImporter/A.qml2
-rw-r--r--tests/auto/qml/qqmltypeloader/data/SlowImporter/qmldir2
-rw-r--r--tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp61
-rw-r--r--tests/auto/qml/qv4mm/data/forInOnProxyMarksTarget.qml23
-rw-r--r--tests/auto/qml/qv4mm/tst_qv4mm.cpp28
-rw-r--r--tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp12
-rw-r--r--tests/auto/quick/pointerhandlers/qquickpinchhandler/tst_qquickpinchhandler.cpp96
-rw-r--r--tests/auto/quick/qquickflickable/data/nestedSameDirection.qml61
-rw-r--r--tests/auto/quick/qquickflickable/tst_qquickflickable.cpp216
-rw-r--r--tests/auto/quick/qquickgridview/tst_qquickgridview.cpp26
-rw-r--r--tests/auto/quick/qquickitem2/tst_qquickitem.cpp9
-rw-r--r--tests/auto/quick/qquicklistview/tst_qquicklistview.cpp59
-rw-r--r--tests/auto/quick/qquickmousearea/data/hoverPosition.qml15
-rw-r--r--tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp42
-rw-r--r--tests/auto/quick/qquickpathview/tst_qquickpathview.cpp24
-rw-r--r--tests/auto/quick/qquickwindow/tst_qquickwindow.cpp31
-rw-r--r--tests/auto/quickcontrols/controls/data/tst_swipeview.qml59
-rw-r--r--tests/auto/quickcontrols/controls/material/CMakeLists.txt3
-rw-r--r--tests/auto/quickcontrols/qquickmaterialstyle/data/tst_material.qml11
-rw-r--r--tests/auto/quickcontrols/qquickmenu/data/mousePropagationWithinPopup.qml33
-rw-r--r--tests/auto/quickcontrols/qquickmenu/tst_qquickmenu.cpp52
-rw-r--r--tests/auto/quickcontrols/qquickpopup/data/parentToOverlay.qml41
-rw-r--r--tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp49
-rw-r--r--tests/auto/quickwidgets/qquickwidget/data/overlayGeometry.qml24
-rw-r--r--tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp54
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, &timestamp, &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.