aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto')
-rw-r--r--tests/auto/bic/README13
-rw-r--r--tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp18
-rw-r--r--tests/auto/qml/qqmlecmascript/data/nans.qml5
-rw-r--r--tests/auto/qml/qqmlecmascript/testtypes.h3
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp24
-rw-r--r--tests/auto/qml/qqmllanguage/data/invalidAlias.13.errors.txt1
-rw-r--r--tests/auto/qml/qqmllanguage/data/invalidAlias.13.qml10
-rw-r--r--tests/auto/qml/qqmllanguage/data/invalidAliasComponent.qml5
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp9
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/moduleWithStaticPlugin/qmldir2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/moduleWithWaitingPlugin/qmldir2
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp119
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.pro8
-rw-r--r--tests/auto/quick/pointerhandlers/qquickdraghandler/data/simpleTapAndDragHandlers.qml112
-rw-r--r--tests/auto/quick/pointerhandlers/qquickdraghandler/qquickdraghandler.pro8
-rw-r--r--tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp85
-rw-r--r--tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp15
-rw-r--r--tests/auto/quick/pointerhandlers/qquicktaphandler/data/buttonOverrideHandler.qml1
-rw-r--r--tests/auto/quick/qquickimage/tst_qquickimage.cpp4
-rw-r--r--tests/auto/quick/qquickloader/data/itemLoaderItemWindow.qml27
-rw-r--r--tests/auto/quick/qquickloader/data/itemLoaderWindow.qml22
-rw-r--r--tests/auto/quick/qquickloader/tst_qquickloader.cpp86
-rw-r--r--tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp12
-rw-r--r--tests/auto/quick/qquickwindow/tst_qquickwindow.cpp114
-rw-r--r--tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp119
25 files changed, 803 insertions, 21 deletions
diff --git a/tests/auto/bic/README b/tests/auto/bic/README
new file mode 100644
index 0000000000..2bde3dd9b9
--- /dev/null
+++ b/tests/auto/bic/README
@@ -0,0 +1,13 @@
+This directory contains test data to be used by tst_bic to check that we don't
+introduce binary incompatible changes between releases. The bic test is run
+after every successful integration on Linux only. This data is generated after
+each minor release. The generated BC files contain virtual tables, and the bic
+test checks new content against the old data.
+
+See the following README for an explanation of how to generate this data:
+
+http://code.qt.io/cgit/qt/qtqa.git/tree/tests/postbuild/bic/README
+
+The test itself can be found here:
+
+http://code.qt.io/cgit/qt/qtqa.git/tree/tests/postbuild/bic
diff --git a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
index a7b02f3cca..2f5ff0022e 100644
--- a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
+++ b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
@@ -33,6 +33,7 @@
#include <QProcess>
#include <QLibraryInfo>
#include <QSysInfo>
+#include <private/qqmlcomponent_p.h>
class tst_qmlcachegen: public QObject
{
@@ -118,6 +119,16 @@ void tst_qmlcachegen::loadGeneratedFile()
const QString cacheFilePath = testFilePath + QLatin1Char('c');
QVERIFY(QFile::exists(cacheFilePath));
+
+ {
+ QFile cache(cacheFilePath);
+ QVERIFY(cache.open(QIODevice::ReadOnly));
+ const QV4::CompiledData::Unit *cacheUnit = reinterpret_cast<const QV4::CompiledData::Unit *>(cache.map(/*offset*/0, sizeof(QV4::CompiledData::Unit)));
+ QVERIFY(cacheUnit);
+ QVERIFY(cacheUnit->flags & QV4::CompiledData::Unit::StaticData);
+ QVERIFY(cacheUnit->flags & QV4::CompiledData::Unit::PendingTypeCompilation);
+ }
+
QVERIFY(QFile::remove(testFilePath));
QQmlEngine engine;
@@ -125,6 +136,13 @@ void tst_qmlcachegen::loadGeneratedFile()
QScopedPointer<QObject> obj(component.create());
QVERIFY(!obj.isNull());
QCOMPARE(obj->property("value").toInt(), 42);
+
+ auto componentPrivate = QQmlComponentPrivate::get(&component);
+ QVERIFY(componentPrivate);
+ auto compilationUnit = componentPrivate->compilationUnit;
+ QVERIFY(compilationUnit);
+ QVERIFY(compilationUnit->data);
+ QVERIFY(!(compilationUnit->data->flags & QV4::CompiledData::Unit::StaticData));
}
void tst_qmlcachegen::translationExpressionSupport()
diff --git a/tests/auto/qml/qqmlecmascript/data/nans.qml b/tests/auto/qml/qqmlecmascript/data/nans.qml
new file mode 100644
index 0000000000..ece69f2d79
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/nans.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+QtObject {
+ property var prop: undefined
+}
diff --git a/tests/auto/qml/qqmlecmascript/testtypes.h b/tests/auto/qml/qqmlecmascript/testtypes.h
index 2db35d0219..8d89df31db 100644
--- a/tests/auto/qml/qqmlecmascript/testtypes.h
+++ b/tests/auto/qml/qqmlecmascript/testtypes.h
@@ -1663,7 +1663,8 @@ class SingletonWithEnum : public QObject
Q_ENUMS(TestEnum)
public:
enum TestEnum {
- TestValue = 42
+ TestValue = 42,
+ TestValue_MinusOne = -1
};
};
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index f48cb2743c..b7d5db9914 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -348,6 +348,7 @@ private slots:
void forInIterator();
void localForInIterator();
void shadowedFunctionName();
+ void anotherNaN();
private:
// static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
@@ -7922,6 +7923,15 @@ void tst_qqmlecmascript::singletonWithEnum()
QVariant prop = obj->property("testValue");
QCOMPARE(prop.type(), QVariant::Int);
QCOMPARE(prop.toInt(), int(SingletonWithEnum::TestValue));
+
+ {
+ QQmlExpression expr(qmlContext(obj.data()), obj.data(), "SingletonWithEnum.TestValue_MinusOne");
+ bool valueUndefined = false;
+ QVariant result = expr.evaluate(&valueUndefined);
+ QVERIFY2(!expr.hasError(), qPrintable(expr.error().toString()));
+ QVERIFY(!valueUndefined);
+ QCOMPARE(result.toInt(), -1);
+ }
}
void tst_qqmlecmascript::lazyBindingEvaluation()
@@ -8369,6 +8379,20 @@ void tst_qqmlecmascript::qtbug_60547()
QCOMPARE(object->property("counter"), QVariant(int(1)));
}
+void tst_qqmlecmascript::anotherNaN()
+{
+ QQmlComponent component(&engine, testFileUrl("nans.qml"));
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY2(!object.isNull(), qPrintable(component.errorString()));
+ object->setProperty("prop", std::numeric_limits<double>::quiet_NaN()); // don't crash
+
+ std::uint64_t anotherNaN = 0xFFFFFF01000000F7ul;
+ double d;
+ std::memcpy(&d, &anotherNaN, sizeof(d));
+ QVERIFY(std::isnan(d));
+ object->setProperty("prop", d); // don't crash
+}
+
void tst_qqmlecmascript::delayLoadingArgs()
{
QJSEngine engine;
diff --git a/tests/auto/qml/qqmllanguage/data/invalidAlias.13.errors.txt b/tests/auto/qml/qqmllanguage/data/invalidAlias.13.errors.txt
new file mode 100644
index 0000000000..234753ad59
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/invalidAlias.13.errors.txt
@@ -0,0 +1 @@
+6:5:Invalid alias target
diff --git a/tests/auto/qml/qqmllanguage/data/invalidAlias.13.qml b/tests/auto/qml/qqmllanguage/data/invalidAlias.13.qml
new file mode 100644
index 0000000000..4050c0a7ad
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/invalidAlias.13.qml
@@ -0,0 +1,10 @@
+import QtQml 2.0
+
+QtObject {
+ property alias dataValue: dataVal
+
+ invalidAliasComponent {
+ id: dataVal
+ strValue: "value2"
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/invalidAliasComponent.qml b/tests/auto/qml/qqmllanguage/data/invalidAliasComponent.qml
new file mode 100644
index 0000000000..a45b1806a3
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/invalidAliasComponent.qml
@@ -0,0 +1,5 @@
+import QtQml 2.0
+
+QtObject {
+ property string strValue: "value1"
+}
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index dfc6509732..03d53b755d 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -279,6 +279,8 @@ private slots:
void accessDeletedObject();
+ void lowercaseTypeNames();
+
private:
QQmlEngine engine;
QStringList defaultImportPathList;
@@ -521,6 +523,7 @@ void tst_qqmllanguage::errors_data()
QTest::newRow("invalidAlias.10") << "invalidAlias.10.qml" << "invalidAlias.10.errors.txt" << false;
QTest::newRow("invalidAlias.11") << "invalidAlias.11.qml" << "invalidAlias.11.errors.txt" << false;
QTest::newRow("invalidAlias.12") << "invalidAlias.12.qml" << "invalidAlias.12.errors.txt" << false;
+ QTest::newRow("invalidAlias.13") << "invalidAlias.13.qml" << "invalidAlias.13.errors.txt" << false;
QTest::newRow("invalidAttachedProperty.1") << "invalidAttachedProperty.1.qml" << "invalidAttachedProperty.1.errors.txt" << false;
QTest::newRow("invalidAttachedProperty.2") << "invalidAttachedProperty.2.qml" << "invalidAttachedProperty.2.errors.txt" << false;
@@ -4902,6 +4905,12 @@ void tst_qqmllanguage::accessDeletedObject()
QVERIFY(!o.isNull());
}
+void tst_qqmllanguage::lowercaseTypeNames()
+{
+ QCOMPARE(qmlRegisterType<QObject>("Test", 1, 0, "lowerCaseTypeName"), -1);
+ QCOMPARE(qmlRegisterSingletonType<QObject>("Test", 1, 0, "lowerCaseTypeName", nullptr), -1);
+}
+
QTEST_MAIN(tst_qqmllanguage)
#include "tst_qqmllanguage.moc"
diff --git a/tests/auto/qml/qqmlmoduleplugin/moduleWithStaticPlugin/qmldir b/tests/auto/qml/qqmlmoduleplugin/moduleWithStaticPlugin/qmldir
new file mode 100644
index 0000000000..104c4bf673
--- /dev/null
+++ b/tests/auto/qml/qqmlmoduleplugin/moduleWithStaticPlugin/qmldir
@@ -0,0 +1,2 @@
+module moduleWithStaticPlugin
+plugin secondStaticPlugin
diff --git a/tests/auto/qml/qqmlmoduleplugin/moduleWithWaitingPlugin/qmldir b/tests/auto/qml/qqmlmoduleplugin/moduleWithWaitingPlugin/qmldir
new file mode 100644
index 0000000000..45a02b2ffe
--- /dev/null
+++ b/tests/auto/qml/qqmlmoduleplugin/moduleWithWaitingPlugin/qmldir
@@ -0,0 +1,2 @@
+module moduleWithWaitingPlugin
+plugin pluginThatWaits
diff --git a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp
index edfbf57e76..85e4918b61 100644
--- a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp
@@ -29,6 +29,9 @@
#include <qdir.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
+#include <QtQml/qqmlextensionplugin.h>
+#include <QtCore/qjsondocument.h>
+#include <QtCore/qjsonarray.h>
#include <QDebug>
#if defined(Q_OS_MAC)
@@ -73,12 +76,80 @@ private slots:
void importsChildPlugin();
void importsChildPlugin2();
void importsChildPlugin21();
+ void parallelPluginImport();
private:
QString m_importsDirectory;
QString m_dataImportsDirectory;
};
+class PluginThatWaits : public QQmlExtensionPlugin
+{
+public:
+ static QByteArray metaData;
+
+ static QMutex initializeEngineEntered;
+ static QWaitCondition waitingForInitializeEngineEntry;
+ static QMutex leavingInitializeEngine;
+ static QWaitCondition waitingForInitializeEngineLeave;
+
+ void registerTypes(const char *uri) override
+ {
+ qmlRegisterModule(uri, 1, 0);
+ }
+
+ void initializeEngine(QQmlEngine *engine, const char *uri) override
+ {
+ initializeEngineEntered.lock();
+ leavingInitializeEngine.lock();
+ waitingForInitializeEngineEntry.wakeOne();
+ initializeEngineEntered.unlock();
+ waitingForInitializeEngineLeave.wait(&leavingInitializeEngine);
+ leavingInitializeEngine.unlock();
+ }
+};
+QByteArray PluginThatWaits::metaData;
+QMutex PluginThatWaits::initializeEngineEntered;
+QWaitCondition PluginThatWaits::waitingForInitializeEngineEntry;
+QMutex PluginThatWaits::leavingInitializeEngine;
+QWaitCondition PluginThatWaits::waitingForInitializeEngineLeave;
+
+class SecondStaticPlugin : public QQmlExtensionPlugin
+{
+public:
+ static QByteArray metaData;
+
+ void registerTypes(const char *uri) override
+ {
+ qmlRegisterModule(uri, 1, 0);
+ }
+};
+QByteArray SecondStaticPlugin::metaData;
+
+template <typename PluginType>
+void registerStaticPlugin(const char *uri)
+{
+ QStaticPlugin plugin;
+ plugin.instance = []() {
+ static PluginType plugin;
+ return static_cast<QObject*>(&plugin);
+ };
+
+ QJsonObject md;
+ md.insert(QStringLiteral("IID"), QQmlExtensionInterface_iid);
+ QJsonArray uris;
+ uris.append(uri);
+ md.insert(QStringLiteral("uri"), uris);
+
+ PluginType::metaData.append(QLatin1String("QTMETADATA "));
+ PluginType::metaData.append(QJsonDocument(md).toBinaryData());
+
+ plugin.rawMetaData = []() {
+ return PluginType::metaData.constData();
+ };
+ qRegisterStaticPluginFunction(plugin);
+};
+
void tst_qqmlmoduleplugin::initTestCase()
{
QQmlDataTest::initTestCase();
@@ -88,6 +159,9 @@ void tst_qqmlmoduleplugin::initTestCase()
m_dataImportsDirectory = directory() + QStringLiteral("/imports");
QVERIFY2(QFileInfo(m_dataImportsDirectory).isDir(),
qPrintable(QString::fromLatin1("Imports directory '%1' does not exist.").arg(m_dataImportsDirectory)));
+
+ registerStaticPlugin<PluginThatWaits>("moduleWithWaitingPlugin");
+ registerStaticPlugin<SecondStaticPlugin>("moduleWithStaticPlugin");
}
#define VERIFY_ERRORS(errorfile) \
@@ -629,6 +703,51 @@ void tst_qqmlmoduleplugin::importsChildPlugin21()
delete object;
}
+void tst_qqmlmoduleplugin::parallelPluginImport()
+{
+ QMutexLocker locker(&PluginThatWaits::initializeEngineEntered);
+
+ QThread worker;
+ QObject::connect(&worker, &QThread::started, [&worker](){
+ // Engines in separate threads are tricky, but as long as we do not create a graphical
+ // object and move objects created by the engines across thread boundaries, this is safe.
+ // At the same time this allows us to place the engine's loader thread into the position
+ // where, without the fix for this bug, the global lock is acquired.
+ QQmlEngine engineInThread;
+
+ QQmlComponent component(&engineInThread);
+ component.setData("import moduleWithWaitingPlugin 1.0\nimport QtQml 2.0\nQtObject {}",
+ QUrl());
+
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+
+ worker.quit();
+ });
+ worker.start();
+
+ PluginThatWaits::waitingForInitializeEngineEntry.wait(&PluginThatWaits::initializeEngineEntered);
+
+ {
+ // After acquiring this lock, the engine in the other thread as well as its type loader
+ // thread are blocked. However they should not hold the global plugin lock
+ // qmlEnginePluginsWithRegisteredTypes()->mutex in qqmllimports.cpp, allowing for the load
+ // of a component in a different engine with its own plugin to proceed.
+ QMutexLocker continuationLock(&PluginThatWaits::leavingInitializeEngine);
+
+ QQmlEngine secondEngine;
+ QQmlComponent secondComponent(&secondEngine);
+ secondComponent.setData("import moduleWithStaticPlugin 1.0\nimport QtQml 2.0\nQtObject {}",
+ QUrl());
+ QScopedPointer<QObject> o(secondComponent.create());
+ QVERIFY(!o.isNull());
+
+ PluginThatWaits::waitingForInitializeEngineLeave.wakeOne();
+ }
+
+ worker.wait();
+}
+
QTEST_MAIN(tst_qqmlmoduleplugin)
#include "tst_qqmlmoduleplugin.moc"
diff --git a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.pro b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.pro
index 43bd112415..118ca26ee9 100644
--- a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.pro
+++ b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.pro
@@ -10,4 +10,12 @@ include (../../shared/util.pri)
TESTDATA = data/* imports/* $$OUT_PWD/imports/*
+waitingPlugin.files = moduleWithWaitingPlugin
+waitingPlugin.prefix = /qt-project.org/imports/
+RESOURCES += waitingPlugin
+
+staticPlugin.files = moduleWithStaticPlugin
+staticPlugin.prefix = /qt-project.org/imports/
+RESOURCES += staticPlugin
+
QT += core-private gui-private qml-private network testlib
diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/simpleTapAndDragHandlers.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/simpleTapAndDragHandlers.qml
new file mode 100644
index 0000000000..adb8332213
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/simpleTapAndDragHandlers.qml
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the manual tests of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.8
+import Qt.labs.handlers 1.0
+
+Rectangle {
+ id: root
+ width: 900
+ height: 850
+ objectName: "root"
+ color: "#222222"
+
+ Row {
+ objectName: "row"
+ anchors.fill: parent
+ spacing: 10
+ Rectangle {
+ width: 50
+ height: 50
+ color: "aqua"
+ objectName: "dragAndTap"
+ DragHandler {
+ objectName: "drag"
+ }
+ TapHandler {
+ objectName: "tap"
+ gesturePolicy: TapHandler.DragThreshold
+ }
+ }
+ Rectangle {
+ width: 50
+ height: 50
+ color: "aqua"
+ objectName: "tapAndDrag"
+ TapHandler {
+ objectName: "tap"
+ gesturePolicy: TapHandler.DragThreshold
+ }
+ DragHandler {
+ objectName: "drag"
+ }
+ }
+
+ Rectangle {
+ color: "aqua"
+ width: 50
+ height: 50
+ objectName: "dragAndTapNotSiblings"
+ DragHandler {
+ objectName: "drag"
+ }
+ Rectangle {
+ color: "blue"
+ width: 30
+ height: 30
+ anchors.centerIn: parent
+ TapHandler {
+ objectName: "tap"
+ gesturePolicy: TapHandler.DragThreshold
+ }
+ }
+ }
+ Rectangle {
+ color: "aqua"
+ width: 50
+ height: 50
+ objectName: "tapAndDragNotSiblings"
+ TapHandler {
+ objectName: "tap"
+ gesturePolicy: TapHandler.DragThreshold
+ }
+ Rectangle {
+ color: "blue"
+ x: 10
+ y: 10
+ width: 30
+ height: 30
+ DragHandler {
+ objectName: "drag"
+ }
+ }
+ }
+
+
+ }
+}
diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/qquickdraghandler.pro b/tests/auto/quick/pointerhandlers/qquickdraghandler/qquickdraghandler.pro
index b50fe5ca6f..42c4e46c4f 100644
--- a/tests/auto/quick/pointerhandlers/qquickdraghandler/qquickdraghandler.pro
+++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/qquickdraghandler.pro
@@ -12,4 +12,10 @@ include (../../shared/util.pri)
TESTDATA = data/*
-# OTHER_FILES += data/foo.qml
+OTHER_FILES += data/DragAnywhereSlider.qml \
+ data/FlashAnimation.qml \
+ data/Slider.qml \
+ data/draggables.qml \
+ data/grabberstate.qml \
+ data/multipleSliders.qml \
+ data/reparenting.qml \
diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp
index 8dc035949e..f827b82205 100644
--- a/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp
+++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
@@ -58,9 +58,12 @@ private slots:
void touchDragMulti();
void touchDragMultiSliders_data();
void touchDragMultiSliders();
+ void touchPassiveGrabbers_data();
+ void touchPassiveGrabbers();
private:
void createView(QScopedPointer<QQuickView> &window, const char *fileName);
+ QSet<QQuickPointerHandler *> passiveGrabbers(QQuickWindow *window, int pointId = 0);
QTouchDevice *touchDevice;
};
@@ -77,6 +80,24 @@ void tst_DragHandler::createView(QScopedPointer<QQuickView> &window, const char
QVERIFY(window->rootObject() != 0);
}
+QSet<QQuickPointerHandler*> tst_DragHandler::passiveGrabbers(QQuickWindow *window, int pointId /*= 0*/)
+{
+ QSet<QQuickPointerHandler*> result;
+ QQuickWindowPrivate *winp = QQuickWindowPrivate::get(window);
+ if (QQuickPointerDevice* device = QQuickPointerDevice::touchDevice(touchDevice)) {
+ QQuickPointerEvent *pointerEvent = winp->pointerEventInstance(device);
+ for (int i = 0; i < pointerEvent->pointCount(); ++i) {
+ QQuickEventPoint *eventPoint = pointerEvent->point(i);
+ QVector<QPointer <QQuickPointerHandler> > passives = eventPoint->passiveGrabbers();
+ if (!pointId || eventPoint->pointId() == pointId) {
+ for (auto it = passives.constBegin(); it != passives.constEnd(); ++it)
+ result << it->data();
+ }
+ }
+ }
+ return result;
+}
+
void tst_DragHandler::initTestCase()
{
// This test assumes that we don't get synthesized mouse events from QGuiApplication
@@ -398,6 +419,68 @@ void tst_DragHandler::touchDragMultiSliders()
touch.commit();
}
+void tst_DragHandler::touchPassiveGrabbers_data()
+{
+ QTest::addColumn<QString>("itemName");
+ QTest::addColumn<QStringList>("expectedPassiveGrabberNames");
+
+ QTest::newRow("Drag And Tap") << "dragAndTap" << QStringList({"drag", "tap"});
+ QTest::newRow("Tap And Drag") << "tapAndDrag" << QStringList({"tap", "drag"});
+ QTest::newRow("Drag And Tap (not siblings)") << "dragAndTapNotSiblings" << QStringList({"drag", "tap"});
+ QTest::newRow("Tap And Drag (not siblings)") << "tapAndDragNotSiblings" << QStringList({"tap", "drag"});
+}
+
+void tst_DragHandler::touchPassiveGrabbers()
+{
+ QFETCH(QString, itemName);
+ QFETCH(QStringList, expectedPassiveGrabberNames);
+
+ QScopedPointer<QQuickView> windowPtr;
+ createView(windowPtr, "simpleTapAndDragHandlers.qml");
+ QQuickView * window = windowPtr.data();
+
+ QQuickItem *row2 = window->rootObject()->findChild<QQuickItem*>(itemName);
+ QSet<QQuickPointerHandler *> expectedPassiveGrabbers;
+ for (QString objectName : expectedPassiveGrabberNames)
+ expectedPassiveGrabbers << row2->findChild<QQuickPointerHandler*>(objectName);
+
+ QPointF p1 = row2->mapToScene(row2->clipRect().center());
+ QTest::QTouchEventSequence touch = QTest::touchEvent(window, touchDevice);
+ touch.press(1, p1.toPoint()).commit();
+ QQuickTouchUtils::flush(window);
+
+ QCOMPARE(passiveGrabbers(window), expectedPassiveGrabbers);
+
+ QQuickDragHandler *dragHandler = nullptr;
+ for (QQuickPointerHandler *handler: expectedPassiveGrabbers) {
+ QCOMPARE(static_cast<QQuickSinglePointHandler *>(handler)->point().scenePressPosition(), p1);
+ QQuickDragHandler *dh = qmlobject_cast<QQuickDragHandler *>(handler);
+ if (dh)
+ dragHandler = dh;
+ }
+ QVERIFY(dragHandler);
+ QPointF initialPos = dragHandler->target()->position();
+
+ p1 += QPointF(50, 50);
+ touch.move(1, p1.toPoint()).commit();
+ QQuickTouchUtils::flush(window);
+ QTRY_VERIFY(dragHandler->active());
+
+ p1 += QPointF(50, 50);
+ touch.move(1, p1.toPoint()).commit();
+ QQuickTouchUtils::flush(window);
+ QPointF movementDelta = dragHandler->target()->position() - initialPos;
+ qCDebug(lcPointerTests) << "DragHandler moved the target by" << movementDelta;
+ QVERIFY(movementDelta.x() >= 100);
+ QVERIFY(movementDelta.y() >= 100);
+
+ QTest::qWait(500);
+
+ touch.release(1, p1.toPoint());
+ touch.commit();
+ QQuickTouchUtils::flush(window);
+}
+
QTEST_MAIN(tst_DragHandler)
#include "tst_qquickdraghandler.moc"
diff --git a/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp
index cc39dd54f7..d38ae3190e 100644
--- a/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp
+++ b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
@@ -504,17 +504,18 @@ void tst_PointerHandlers::mouseEventDelivery()
eventItem1->grabPointer = true;
p1 = QPoint(20, 20);
QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1);
- QTRY_COMPARE(eventItem1->eventList.size(), 2);
+ QTRY_COMPARE(eventItem1->eventList.size(), 3);
QCOMPARE_EVENT(0, Event::HandlerDestination, QEvent::None, Qt::TouchPointPressed, QQuickEventPoint::GrabExclusive);
QCOMPARE_EVENT(1, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointPressed, QQuickEventPoint::GrabExclusive);
+ QCOMPARE_EVENT(2, Event::MouseDestination, QEvent::MouseButtonPress, Qt::TouchPointPressed, 0);
p1 += QPoint(10, 0);
QTest::mouseMove(window, p1);
- QCOMPARE(eventItem1->eventList.size(), 3);
- QCOMPARE_EVENT(2, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointMoved, QQuickEventPoint::GrabExclusive);
+ QCOMPARE(eventItem1->eventList.size(), 4);
+ QCOMPARE_EVENT(3, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointMoved, QQuickEventPoint::GrabExclusive);
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
- QCOMPARE(eventItem1->eventList.size(), 5);
- QCOMPARE_EVENT(3, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointReleased, QQuickEventPoint::GrabExclusive);
- QCOMPARE_EVENT(4, Event::HandlerDestination, QEvent::None, Qt::TouchPointReleased, QQuickEventPoint::UngrabExclusive);
+ QCOMPARE(eventItem1->eventList.size(), 6);
+ QCOMPARE_EVENT(4, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointReleased, QQuickEventPoint::GrabExclusive);
+ QCOMPARE_EVENT(5, Event::HandlerDestination, QEvent::None, Qt::TouchPointReleased, QQuickEventPoint::UngrabExclusive);
eventItem1->eventList.clear();
}
diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/data/buttonOverrideHandler.qml b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/buttonOverrideHandler.qml
index 14a8d67300..219d4a70a8 100644
--- a/tests/auto/quick/pointerhandlers/qquicktaphandler/data/buttonOverrideHandler.qml
+++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/buttonOverrideHandler.qml
@@ -38,6 +38,7 @@ Item {
label: "Overridden"
x: 10; y: 10; width: parent.width - 20; height: 40
TapHandler {
+ gesturePolicy: TapHandler.ReleaseWithinBounds
objectName: "override"
onTapped: button.tapped()
}
diff --git a/tests/auto/quick/qquickimage/tst_qquickimage.cpp b/tests/auto/quick/qquickimage/tst_qquickimage.cpp
index 256e667980..f61b490307 100644
--- a/tests/auto/quick/qquickimage/tst_qquickimage.cpp
+++ b/tests/auto/quick/qquickimage/tst_qquickimage.cpp
@@ -404,11 +404,11 @@ void tst_qquickimage::svg()
component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
QVERIFY(obj != 0);
- QCOMPARE(int(obj->width()), 212); // round down: highdpi can give back fractional values
+ QCOMPARE(obj->width(), 300.0);
QCOMPARE(obj->height(), 300.0);
obj->setSourceSize(QSize(200,200));
- QCOMPARE(int(obj->width()), 141); // round down: highdpi can give back fractional values
+ QCOMPARE(obj->width(), 200.0);
QCOMPARE(obj->height(), 200.0);
delete obj;
}
diff --git a/tests/auto/quick/qquickloader/data/itemLoaderItemWindow.qml b/tests/auto/quick/qquickloader/data/itemLoaderItemWindow.qml
new file mode 100644
index 0000000000..d4c5daecab
--- /dev/null
+++ b/tests/auto/quick/qquickloader/data/itemLoaderItemWindow.qml
@@ -0,0 +1,27 @@
+import QtQuick 2.0
+import QtQuick.Window 2.1
+
+Item {
+ width: 400
+ height: 400
+ objectName: "root Item"
+
+ Loader {
+ sourceComponent: Rectangle {
+ objectName: "yellow rectangle"
+ x: 50; y: 50; width: 300; height: 300
+ color: "yellow"
+ Window {
+ objectName: "red transient Window"
+ width: 100
+ height: 100
+ visible: true // makes it harder, because it wants to become visible before root has a window
+ color: "red"
+ title: "red"
+ flags: Qt.Dialog
+ onVisibilityChanged: console.log("visibility " + visibility)
+ onVisibleChanged: console.log("visible " + visible)
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickloader/data/itemLoaderWindow.qml b/tests/auto/quick/qquickloader/data/itemLoaderWindow.qml
new file mode 100644
index 0000000000..69421448e0
--- /dev/null
+++ b/tests/auto/quick/qquickloader/data/itemLoaderWindow.qml
@@ -0,0 +1,22 @@
+import QtQuick 2.0
+import QtQuick.Window 2.1
+
+Item {
+ width: 400
+ height: 400
+ objectName: "root Item"
+
+ Loader {
+ sourceComponent: Window {
+ objectName: "red transient Window"
+ width: 100
+ height: 100
+ visible: true // makes it harder, because it wants to become visible before root has a window
+ color: "red"
+ title: "red"
+ flags: Qt.Dialog
+ onVisibilityChanged: console.log("visibility " + visibility)
+ onVisibleChanged: console.log("visible " + visible)
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickloader/tst_qquickloader.cpp b/tests/auto/quick/qquickloader/tst_qquickloader.cpp
index e557b592ee..65493f52e2 100644
--- a/tests/auto/quick/qquickloader/tst_qquickloader.cpp
+++ b/tests/auto/quick/qquickloader/tst_qquickloader.cpp
@@ -32,11 +32,15 @@
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
#include <QtQml/qqmlincubator.h>
+#include <QtQuick/qquickview.h>
#include <private/qquickloader_p.h>
+#include <private/qquickwindowmodule_p.h>
#include "testhttpserver.h"
#include "../../shared/util.h"
#include "../shared/geometrytestutil.h"
+Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests")
+
class SlowComponent : public QQmlComponent
{
Q_OBJECT
@@ -112,6 +116,8 @@ private slots:
void parented();
void sizeBound();
void QTBUG_30183();
+ void transientWindow();
+ void nestedTransientWindow();
void sourceComponentGarbageCollection();
@@ -1159,6 +1165,86 @@ void tst_QQuickLoader::QTBUG_30183()
QCOMPARE(rect->height(), 120.0);
}
+void tst_QQuickLoader::transientWindow() // QTBUG-52944
+{
+ QQuickView view;
+ view.setSource(testFileUrl("itemLoaderWindow.qml"));
+ QQuickItem *root = qobject_cast<QQuickItem*>(view.rootObject());
+ QVERIFY(root);
+ QQuickLoader *loader = root->findChild<QQuickLoader *>();
+ QVERIFY(loader);
+ QTRY_COMPARE(loader->status(), QQuickLoader::Ready);
+ QQuickWindowQmlImpl *loadedWindow = qobject_cast<QQuickWindowQmlImpl *>(loader->item());
+ QVERIFY(loadedWindow);
+ QCOMPARE(loadedWindow->visibility(), QWindow::Hidden);
+
+ QElapsedTimer timer;
+ qint64 viewVisibleTime = -1;
+ qint64 loadedWindowVisibleTime = -1;
+ connect(&view, &QWindow::visibleChanged,
+ [&viewVisibleTime, &timer]() { viewVisibleTime = timer.elapsed(); } );
+ connect(loadedWindow, &QQuickWindowQmlImpl::visibilityChanged,
+ [&loadedWindowVisibleTime, &timer]() { loadedWindowVisibleTime = timer.elapsed(); } );
+ timer.start();
+ view.show();
+
+ QTest::qWaitForWindowExposed(&view);
+ QTRY_VERIFY(loadedWindowVisibleTime >= 0);
+ QVERIFY(viewVisibleTime >= 0);
+
+ // now that we're sure they are both visible, which one became visible first?
+ qCDebug(lcTests) << "transient Window became visible" << (loadedWindowVisibleTime - viewVisibleTime) << "ms after the root Item";
+ QVERIFY((loadedWindowVisibleTime - viewVisibleTime) >= 0);
+
+ QWindowList windows = QGuiApplication::topLevelWindows();
+ QTRY_COMPARE(windows.size(), 2);
+
+ // TODO Ideally we would now close the outer window and make sure the transient window closes too.
+ // It works during manual testing because of QWindowPrivate::maybeQuitOnLastWindowClosed()
+ // but quitting an autotest doesn't make sense.
+}
+
+void tst_QQuickLoader::nestedTransientWindow() // QTBUG-52944
+{
+ QQuickView view;
+ view.setSource(testFileUrl("itemLoaderItemWindow.qml"));
+ QQuickItem *root = qobject_cast<QQuickItem*>(view.rootObject());
+ QVERIFY(root);
+ QQuickLoader *loader = root->findChild<QQuickLoader *>();
+ QVERIFY(loader);
+ QTRY_COMPARE(loader->status(), QQuickLoader::Ready);
+ QQuickItem *loadedItem = qobject_cast<QQuickItem *>(loader->item());
+ QVERIFY(loadedItem);
+ QQuickWindowQmlImpl *loadedWindow = loadedItem->findChild<QQuickWindowQmlImpl *>();
+ QVERIFY(loadedWindow);
+ QCOMPARE(loadedWindow->visibility(), QWindow::Hidden);
+
+ QElapsedTimer timer;
+ qint64 viewVisibleTime = -1;
+ qint64 loadedWindowVisibleTime = -1;
+ connect(&view, &QWindow::visibleChanged,
+ [&viewVisibleTime, &timer]() { viewVisibleTime = timer.elapsed(); } );
+ connect(loadedWindow, &QQuickWindowQmlImpl::visibilityChanged,
+ [&loadedWindowVisibleTime, &timer]() { loadedWindowVisibleTime = timer.elapsed(); } );
+ timer.start();
+ view.show();
+
+ QTest::qWaitForWindowExposed(&view);
+ QTRY_VERIFY(loadedWindowVisibleTime >= 0);
+ QVERIFY(viewVisibleTime >= 0);
+
+ // now that we're sure they are both visible, which one became visible first?
+ qCDebug(lcTests) << "transient Window became visible" << (loadedWindowVisibleTime - viewVisibleTime) << "ms after the root Item";
+ QVERIFY((loadedWindowVisibleTime - viewVisibleTime) >= 0);
+
+ QWindowList windows = QGuiApplication::topLevelWindows();
+ QTRY_COMPARE(windows.size(), 2);
+
+ // TODO Ideally we would now close the outer window and make sure the transient window closes too.
+ // It works during manual testing because of QWindowPrivate::maybeQuitOnLastWindowClosed()
+ // but quitting an autotest doesn't make sense.
+}
+
void tst_QQuickLoader::sourceComponentGarbageCollection()
{
QQmlEngine engine;
diff --git a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
index 39a8909617..06b76d129c 100644
--- a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
+++ b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
@@ -6143,9 +6143,17 @@ void tst_qquicktextinput::keypress_inputMask_withValidator_data()
KeyList keys;
// inserting '1111.11' then two backspaces
keys << Qt::Key_Home << "1111.11" << Qt::Key_Backspace << Qt::Key_Backspace;
- QTest::newRow("backspaceWithRegExp") << QString("9999.99;_") << 0.0 << 0.0 << 0
+ QTest::newRow("backspaceWithRegExp") << QString("9999;_") << 0.0 << 0.0 << 0
<< QString("/^[-]?((\\.\\d+)|(\\d+(\\.\\d+)?))$/")
- << keys << QString("1111.") << QString("1111.__");
+ << keys << QString("11") << QString("11__");
+ }
+ {
+ KeyList keys;
+ // inserting '99' - QTBUG-64616
+ keys << Qt::Key_Home << "99";
+ QTest::newRow("invalidTextWithRegExp") << QString("X9;_") << 0.0 << 0.0 << 0
+ << QString("/[+-][0+9]/")
+ << keys << QString("") << QString("__");
}
}
diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
index 666f80fce1..fe9e8bb1fa 100644
--- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
+++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
@@ -292,6 +292,70 @@ protected:
}
};
+class MouseRecordingWindow : public QQuickWindow
+{
+public:
+ explicit MouseRecordingWindow(QWindow *parent = nullptr) : QQuickWindow(parent) { }
+
+protected:
+ void mousePressEvent(QMouseEvent *event) override {
+ qCDebug(lcTests) << event;
+ m_mouseEvents << *event;
+ QQuickWindow::mousePressEvent(event);
+ }
+ void mouseMoveEvent(QMouseEvent *event) override {
+ qCDebug(lcTests) << event;
+ m_mouseEvents << *event;
+ QQuickWindow::mouseMoveEvent(event);
+ }
+ void mouseReleaseEvent(QMouseEvent *event) override {
+ qCDebug(lcTests) << event;
+ m_mouseEvents << *event;
+ QQuickWindow::mouseReleaseEvent(event);
+ }
+
+public:
+ QList<QMouseEvent> m_mouseEvents;
+};
+
+class MouseRecordingItem : public QQuickItem
+{
+public:
+ MouseRecordingItem(bool acceptTouch, QQuickItem *parent = nullptr)
+ : QQuickItem(parent)
+ , m_acceptTouch(acceptTouch)
+ {
+ setSize(QSizeF(300, 300));
+ setAcceptedMouseButtons(Qt::LeftButton);
+ }
+
+protected:
+ void touchEvent(QTouchEvent* event) override {
+ event->setAccepted(m_acceptTouch);
+ m_touchEvents << *event;
+ qCDebug(lcTests) << "accepted?" << event->isAccepted() << event;
+ }
+ void mousePressEvent(QMouseEvent *event) override {
+ qCDebug(lcTests) << event;
+ m_mouseEvents << *event;
+ }
+ void mouseMoveEvent(QMouseEvent *event) override {
+ qCDebug(lcTests) << event;
+ m_mouseEvents << *event;
+ }
+ void mouseReleaseEvent(QMouseEvent *event) override {
+ qCDebug(lcTests) << event;
+ m_mouseEvents << *event;
+ }
+
+public:
+ QList<QMouseEvent> m_mouseEvents;
+ QList<QTouchEvent> m_touchEvents;
+
+private:
+ bool m_acceptTouch;
+};
+
class tst_qquickwindow : public QQmlDataTest
{
Q_OBJECT
@@ -330,6 +394,8 @@ private slots:
void mergeTouchPointLists();
void mouseFromTouch_basic();
+ void synthMouseFromTouch_data();
+ void synthMouseFromTouch();
void clearWindow();
@@ -705,9 +771,8 @@ void tst_qquickwindow::touchEvent_propagation()
// single touch to top item, should be received by middle item
QTest::touchEvent(window, touchDevice).press(0, pointInTopItem, window);
- QTest::qWait(50);
+ QTRY_COMPARE(middleItem->lastEvent.touchPoints.count(), 1);
QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
- QCOMPARE(middleItem->lastEvent.touchPoints.count(), 1);
QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
COMPARE_TOUCH_DATA(middleItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed,
makeTouchPoint(middleItem, middleItem->mapFromItem(topItem, pos))));
@@ -716,9 +781,8 @@ void tst_qquickwindow::touchEvent_propagation()
// touch top and middle items, middle item should get both events
QTest::touchEvent(window, touchDevice).press(0, pointInTopItem, window)
.press(1, pointInMiddleItem, window);
- QTest::qWait(50);
+ QTRY_COMPARE(middleItem->lastEvent.touchPoints.count(), 2);
QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
- QCOMPARE(middleItem->lastEvent.touchPoints.count(), 2);
QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
COMPARE_TOUCH_DATA(middleItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed,
(QList<QTouchEvent::TouchPoint>() << makeTouchPoint(middleItem, middleItem->mapFromItem(topItem, pos))
@@ -736,10 +800,9 @@ void tst_qquickwindow::touchEvent_propagation()
// touch top and middle items, bottom item should get all events
QTest::touchEvent(window, touchDevice).press(0, pointInTopItem, window)
.press(1, pointInMiddleItem, window);
- QTest::qWait(50);
+ QTRY_COMPARE(bottomItem->lastEvent.touchPoints.count(), 2);
QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
- QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 2);
COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed,
(QList<QTouchEvent::TouchPoint>() << makeTouchPoint(bottomItem, bottomItem->mapFromItem(topItem, pos))
<< makeTouchPoint(bottomItem, bottomItem->mapFromItem(middleItem, pos)) )));
@@ -1132,6 +1195,45 @@ void tst_qquickwindow::mouseFromTouch_basic()
delete item;
}
+void tst_qquickwindow::synthMouseFromTouch_data()
+{
+ QTest::addColumn<bool>("synthMouse"); // AA_SynthesizeMouseForUnhandledTouchEvents
+ QTest::addColumn<bool>("acceptTouch"); // QQuickItem::touchEvent: setAccepted()
+
+ QTest::newRow("no synth, accept") << false << true; // suitable for touch-capable UIs
+ QTest::newRow("no synth, don't accept") << false << false;
+ QTest::newRow("synth and accept") << true << true;
+ QTest::newRow("synth, don't accept") << true << false; // the default
+}
+
+void tst_qquickwindow::synthMouseFromTouch()
+{
+ QFETCH(bool, synthMouse);
+ QFETCH(bool, acceptTouch);
+
+ QCoreApplication::setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, synthMouse);
+ QScopedPointer<MouseRecordingWindow> window(new MouseRecordingWindow);
+ QScopedPointer<MouseRecordingItem> item(new MouseRecordingItem(acceptTouch, nullptr));
+ item->setParentItem(window->contentItem());
+ window->resize(250, 250);
+ window->setPosition(100, 100);
+ window->setTitle(QTest::currentTestFunction());
+ window->show();
+ QVERIFY(QTest::qWaitForWindowActive(window.data()));
+
+ QPoint p1 = QPoint(20, 20);
+ QPoint p2 = QPoint(30, 30);
+ QTest::touchEvent(window.data(), touchDevice).press(0, p1, window.data());
+ QTest::touchEvent(window.data(), touchDevice).move(0, p2, window.data());
+ QTest::touchEvent(window.data(), touchDevice).release(0, p2, window.data());
+
+ QCOMPARE(item->m_touchEvents.count(), 3);
+ QCOMPARE(item->m_mouseEvents.count(), acceptTouch ? 0 : 3);
+ QCOMPARE(window->m_mouseEvents.count(), 0);
+ for (const QMouseEvent &ev : item->m_mouseEvents)
+ QCOMPARE(ev.source(), Qt::MouseEventSynthesizedByQt);
+}
+
void tst_qquickwindow::clearWindow()
{
QQuickWindow *window = new QQuickWindow;
diff --git a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp
index 978608def2..51755c8502 100644
--- a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp
+++ b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp
@@ -27,6 +27,7 @@
****************************************************************************/
#include <qtest.h>
+#include <qtesttouch.h>
#include <QtTest/QSignalSpy>
#include <QtQml/qqmlcomponent.h>
#include <QtQml/qqmlcontext.h>
@@ -38,11 +39,81 @@
#include <QtCore/QDebug>
#include <QtQml/qqmlengine.h>
+#include <QtCore/QLoggingCategory>
+
#include <QtWidgets/QBoxLayout>
#include <QtWidgets/QLabel>
#include <QtQuickWidgets/QQuickWidget>
+Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests")
+
+class MouseRecordingQQWidget : public QQuickWidget
+{
+public:
+ explicit MouseRecordingQQWidget(QWidget *parent = nullptr) : QQuickWidget(parent) {
+ setAttribute(Qt::WA_AcceptTouchEvents);
+ }
+
+protected:
+ void mousePressEvent(QMouseEvent *event) override {
+ qCDebug(lcTests) << event;
+ m_mouseEvents << *event;
+ QQuickWidget::mousePressEvent(event);
+ }
+ void mouseMoveEvent(QMouseEvent *event) override {
+ qCDebug(lcTests) << event;
+ m_mouseEvents << *event;
+ QQuickWidget::mouseMoveEvent(event);
+ }
+ void mouseReleaseEvent(QMouseEvent *event) override {
+ qCDebug(lcTests) << event;
+ m_mouseEvents << *event;
+ QQuickWidget::mouseReleaseEvent(event);
+ }
+
+public:
+ QList<QMouseEvent> m_mouseEvents;
+};
+
+class MouseRecordingItem : public QQuickItem
+{
+public:
+ MouseRecordingItem(bool acceptTouch, QQuickItem *parent = nullptr)
+ : QQuickItem(parent)
+ , m_acceptTouch(acceptTouch)
+ {
+ setSize(QSizeF(300, 300));
+ setAcceptedMouseButtons(Qt::LeftButton);
+ }
+
+protected:
+ void touchEvent(QTouchEvent* event) override {
+ event->setAccepted(m_acceptTouch);
+ m_touchEvents << *event;
+ qCDebug(lcTests) << "accepted?" << event->isAccepted() << event;
+ }
+ void mousePressEvent(QMouseEvent *event) override {
+ qCDebug(lcTests) << event;
+ m_mouseEvents << *event;
+ }
+ void mouseMoveEvent(QMouseEvent *event) override {
+ qCDebug(lcTests) << event;
+ m_mouseEvents << *event;
+ }
+ void mouseReleaseEvent(QMouseEvent *event) override {
+ qCDebug(lcTests) << event;
+ m_mouseEvents << *event;
+ }
+
+public:
+ QList<QMouseEvent> m_mouseEvents;
+ QList<QTouchEvent> m_touchEvents;
+
+private:
+ bool m_acceptTouch;
+};
+
class tst_qquickwidget : public QQmlDataTest
{
Q_OBJECT
@@ -67,8 +138,12 @@ private slots:
void shortcuts();
void enterLeave();
void mouseEventWindowPos();
-};
+ void synthMouseFromTouch_data();
+ void synthMouseFromTouch();
+private:
+ QTouchDevice *device = QTest::createTouchDevice();
+};
tst_qquickwidget::tst_qquickwidget()
{
@@ -503,6 +578,48 @@ void tst_qquickwidget::mouseEventWindowPos()
QTRY_VERIFY(rootItem->property("wasMoved").toBool());
}
+void tst_qquickwidget::synthMouseFromTouch_data()
+{
+ QTest::addColumn<bool>("synthMouse"); // AA_SynthesizeMouseForUnhandledTouchEvents
+ QTest::addColumn<bool>("acceptTouch"); // QQuickItem::touchEvent: setAccepted()
+
+ QTest::newRow("no synth, accept") << false << true; // suitable for touch-capable UIs
+ QTest::newRow("no synth, don't accept") << false << false;
+ QTest::newRow("synth and accept") << true << true;
+ QTest::newRow("synth, don't accept") << true << false; // the default
+}
+
+void tst_qquickwidget::synthMouseFromTouch()
+{
+ QFETCH(bool, synthMouse);
+ QFETCH(bool, acceptTouch);
+
+ QCoreApplication::setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, synthMouse);
+ QWidget window;
+ window.setAttribute(Qt::WA_AcceptTouchEvents);
+ QScopedPointer<MouseRecordingQQWidget> childView(new MouseRecordingQQWidget(&window));
+ MouseRecordingItem *item = new MouseRecordingItem(acceptTouch, nullptr);
+ childView->setContent(QUrl(), nullptr, item);
+ window.resize(300, 300);
+ childView->resize(300, 300);
+ window.show();
+ QVERIFY(QTest::qWaitForWindowActive(&window));
+ QVERIFY(childView->quickWindow()->isVisible());
+ QVERIFY(item->isVisible());
+
+ QPoint p1 = QPoint(20, 20);
+ QPoint p2 = QPoint(30, 30);
+ QTest::touchEvent(&window, device).press(0, p1, &window);
+ QTest::touchEvent(&window, device).move(0, p2, &window);
+ QTest::touchEvent(&window, device).release(0, p2, &window);
+
+ QCOMPARE(item->m_touchEvents.count(), 3);
+ QCOMPARE(item->m_mouseEvents.count(), acceptTouch ? 0 : 3);
+ QCOMPARE(childView->m_mouseEvents.count(), 0);
+ for (const QMouseEvent &ev : item->m_mouseEvents)
+ QCOMPARE(ev.source(), Qt::MouseEventSynthesizedByQt);
+}
+
QTEST_MAIN(tst_qquickwidget)
#include "tst_qquickwidget.moc"