diff options
author | Liang Qi <liang.qi@qt.io> | 2018-02-12 13:26:55 +0100 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2018-02-12 16:31:13 +0100 |
commit | 4d525de33e2ee55e69bb6c90fc11049a0f8b36b5 (patch) | |
tree | c9808baeabb1121f488a7b59ffff314cc62d80e8 /tests/auto/quick | |
parent | 47cd9da96371ccd495f6caabe1c6853258210ebb (diff) | |
parent | 3e3c6717ba634825a65069541500c40645a808ee (diff) |
Merge remote-tracking branch 'origin/5.10' into 5.11
Conflicts:
src/imports/shapes/qquickshape.cpp
src/imports/shapes/qquickshape_p_p.h
src/qml/compiler/qqmlpropertycachecreator_p.h
src/qml/jsruntime/qv4value_p.h
src/quick/items/qquickloader_p.h
tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
tools/qmlprofiler/qmlprofilerapplication.cpp
Change-Id: Iafc66ae84bf78630ed72a986acb678e9d19e3a69
Diffstat (limited to 'tests/auto/quick')
11 files changed, 467 insertions, 19 deletions
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; |