diff options
Diffstat (limited to 'tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp')
-rw-r--r-- | tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp | 591 |
1 files changed, 591 insertions, 0 deletions
diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp b/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp new file mode 100644 index 0000000000..d7eda5e19c --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp @@ -0,0 +1,591 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module 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$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + +#include <QtGui/qstylehints.h> +#include <QtQuick/qquickview.h> +#include <QtQuick/qquickitem.h> +#include <QtQuick/private/qquickpointerhandler_p.h> +#include <QtQuick/private/qquicktaphandler_p.h> +#include <qpa/qwindowsysteminterface.h> + +#include <private/qquickwindow_p.h> + +#include <QtQml/qqmlengine.h> +#include <QtQml/qqmlproperty.h> + +#include "../../../shared/util.h" +#include "../../shared/viewtestutil.h" + +Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests") + +class tst_TapHandler : public QQmlDataTest +{ + Q_OBJECT +public: + tst_TapHandler() + :touchDevice(QTest::createTouchDevice()) + {} + +private slots: + void initTestCase(); + + void touchGesturePolicyDragThreshold(); + void mouseGesturePolicyDragThreshold(); + void touchGesturePolicyWithinBounds(); + void mouseGesturePolicyWithinBounds(); + void touchGesturePolicyReleaseWithinBounds(); + void mouseGesturePolicyReleaseWithinBounds(); + void touchMultiTap(); + void mouseMultiTap(); + void touchLongPress(); + void mouseLongPress(); + void buttonsMultiTouch(); + +private: + void createView(QScopedPointer<QQuickView> &window, const char *fileName); + QTouchDevice *touchDevice; +}; + +void tst_TapHandler::createView(QScopedPointer<QQuickView> &window, const char *fileName) +{ + window.reset(new QQuickView); + window->setSource(testFileUrl(fileName)); + QTRY_COMPARE(window->status(), QQuickView::Ready); + QQuickViewTestUtil::centerOnScreen(window.data()); + QQuickViewTestUtil::moveMouseAway(window.data()); + + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + QVERIFY(window->rootObject() != 0); +} + +void tst_TapHandler::initTestCase() +{ + // This test assumes that we don't get synthesized mouse events from QGuiApplication + qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, false); + + QQmlDataTest::initTestCase(); +} + +void tst_TapHandler::touchGesturePolicyDragThreshold() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *buttonDragThreshold = window->rootObject()->findChild<QQuickItem*>("DragThreshold"); + QVERIFY(buttonDragThreshold); + QSignalSpy dragThresholdTappedSpy(buttonDragThreshold, SIGNAL(tapped())); + + // DragThreshold button stays pressed while touchpoint stays within dragThreshold, emits tapped on release + QPoint p1 = buttonDragThreshold->mapToScene(QPointF(20, 20)).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(buttonDragThreshold->property("pressed").toBool()); + p1 += QPoint(dragThreshold, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(buttonDragThreshold->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!buttonDragThreshold->property("pressed").toBool()); + QCOMPARE(dragThresholdTappedSpy.count(), 1); + + // DragThreshold button is no longer pressed if touchpoint goes beyond dragThreshold + dragThresholdTappedSpy.clear(); + p1 = buttonDragThreshold->mapToScene(QPointF(20, 20)).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(buttonDragThreshold->property("pressed").toBool()); + p1 += QPoint(dragThreshold, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(buttonDragThreshold->property("pressed").toBool()); + p1 += QPoint(1, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!buttonDragThreshold->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(!buttonDragThreshold->property("pressed").toBool()); + QCOMPARE(dragThresholdTappedSpy.count(), 0); +} + +void tst_TapHandler::mouseGesturePolicyDragThreshold() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *buttonDragThreshold = window->rootObject()->findChild<QQuickItem*>("DragThreshold"); + QVERIFY(buttonDragThreshold); + QSignalSpy dragThresholdTappedSpy(buttonDragThreshold, SIGNAL(tapped())); + + // DragThreshold button stays pressed while mouse stays within dragThreshold, emits tapped on release + QPoint p1 = buttonDragThreshold->mapToScene(QPointF(20, 20)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(buttonDragThreshold->property("pressed").toBool()); + p1 += QPoint(dragThreshold, 0); + QTest::mouseMove(window, p1); + QVERIFY(buttonDragThreshold->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!buttonDragThreshold->property("pressed").toBool()); + QTRY_COMPARE(dragThresholdTappedSpy.count(), 1); + + // DragThreshold button is no longer pressed if mouse goes beyond dragThreshold + dragThresholdTappedSpy.clear(); + p1 = buttonDragThreshold->mapToScene(QPointF(20, 20)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(buttonDragThreshold->property("pressed").toBool()); + p1 += QPoint(dragThreshold, 0); + QTest::mouseMove(window, p1); + QVERIFY(buttonDragThreshold->property("pressed").toBool()); + p1 += QPoint(1, 0); + QTest::mouseMove(window, p1); + QTRY_VERIFY(!buttonDragThreshold->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QVERIFY(!buttonDragThreshold->property("pressed").toBool()); + QCOMPARE(dragThresholdTappedSpy.count(), 0); +} + +void tst_TapHandler::touchGesturePolicyWithinBounds() +{ + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *buttonWithinBounds = window->rootObject()->findChild<QQuickItem*>("WithinBounds"); + QVERIFY(buttonWithinBounds); + QSignalSpy withinBoundsTappedSpy(buttonWithinBounds, SIGNAL(tapped())); + + // WithinBounds button stays pressed while touchpoint stays within bounds, emits tapped on release + QPoint p1 = buttonWithinBounds->mapToScene(QPointF(20, 20)).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(buttonWithinBounds->property("pressed").toBool()); + p1 += QPoint(50, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(buttonWithinBounds->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!buttonWithinBounds->property("pressed").toBool()); + QCOMPARE(withinBoundsTappedSpy.count(), 1); + + // WithinBounds button is no longer pressed if touchpoint leaves bounds + withinBoundsTappedSpy.clear(); + p1 = buttonWithinBounds->mapToScene(QPointF(20, 20)).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(buttonWithinBounds->property("pressed").toBool()); + p1 += QPoint(0, 100); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!buttonWithinBounds->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(!buttonWithinBounds->property("pressed").toBool()); + QCOMPARE(withinBoundsTappedSpy.count(), 0); +} + +void tst_TapHandler::mouseGesturePolicyWithinBounds() +{ + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *buttonWithinBounds = window->rootObject()->findChild<QQuickItem*>("WithinBounds"); + QVERIFY(buttonWithinBounds); + QSignalSpy withinBoundsTappedSpy(buttonWithinBounds, SIGNAL(tapped())); + + // WithinBounds button stays pressed while touchpoint stays within bounds, emits tapped on release + QPoint p1 = buttonWithinBounds->mapToScene(QPointF(20, 20)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(buttonWithinBounds->property("pressed").toBool()); + p1 += QPoint(50, 0); + QTest::mouseMove(window, p1); + QVERIFY(buttonWithinBounds->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!buttonWithinBounds->property("pressed").toBool()); + QCOMPARE(withinBoundsTappedSpy.count(), 1); + + // WithinBounds button is no longer pressed if touchpoint leaves bounds + withinBoundsTappedSpy.clear(); + p1 = buttonWithinBounds->mapToScene(QPointF(20, 20)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(buttonWithinBounds->property("pressed").toBool()); + p1 += QPoint(0, 100); + QTest::mouseMove(window, p1); + QTRY_VERIFY(!buttonWithinBounds->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QVERIFY(!buttonWithinBounds->property("pressed").toBool()); + QCOMPARE(withinBoundsTappedSpy.count(), 0); +} + +void tst_TapHandler::touchGesturePolicyReleaseWithinBounds() +{ + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *buttonReleaseWithinBounds = window->rootObject()->findChild<QQuickItem*>("ReleaseWithinBounds"); + QVERIFY(buttonReleaseWithinBounds); + QSignalSpy releaseWithinBoundsTappedSpy(buttonReleaseWithinBounds, SIGNAL(tapped())); + + // ReleaseWithinBounds button stays pressed while touchpoint wanders anywhere, + // then if it comes back within bounds, emits tapped on release + QPoint p1 = buttonReleaseWithinBounds->mapToScene(QPointF(20, 20)).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + p1 += QPoint(50, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + p1 += QPoint(250, 100); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + p1 = buttonReleaseWithinBounds->mapToScene(QPointF(25, 15)).toPoint(); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!buttonReleaseWithinBounds->property("pressed").toBool()); + QCOMPARE(releaseWithinBoundsTappedSpy.count(), 1); + + // ReleaseWithinBounds button does not emit tapped if released out of bounds + releaseWithinBoundsTappedSpy.clear(); + p1 = buttonReleaseWithinBounds->mapToScene(QPointF(20, 20)).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + p1 += QPoint(0, 100); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!buttonReleaseWithinBounds->property("pressed").toBool()); + QCOMPARE(releaseWithinBoundsTappedSpy.count(), 0); +} + +void tst_TapHandler::mouseGesturePolicyReleaseWithinBounds() +{ + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *buttonReleaseWithinBounds = window->rootObject()->findChild<QQuickItem*>("ReleaseWithinBounds"); + QVERIFY(buttonReleaseWithinBounds); + QSignalSpy releaseWithinBoundsTappedSpy(buttonReleaseWithinBounds, SIGNAL(tapped())); + + // ReleaseWithinBounds button stays pressed while touchpoint wanders anywhere, + // then if it comes back within bounds, emits tapped on release + QPoint p1 = buttonReleaseWithinBounds->mapToScene(QPointF(20, 20)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + p1 += QPoint(50, 0); + QTest::mouseMove(window, p1); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + p1 += QPoint(250, 100); + QTest::mouseMove(window, p1); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + p1 = buttonReleaseWithinBounds->mapToScene(QPointF(25, 15)).toPoint(); + QTest::mouseMove(window, p1); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!buttonReleaseWithinBounds->property("pressed").toBool()); + QCOMPARE(releaseWithinBoundsTappedSpy.count(), 1); + + // ReleaseWithinBounds button does not emit tapped if released out of bounds + releaseWithinBoundsTappedSpy.clear(); + p1 = buttonReleaseWithinBounds->mapToScene(QPointF(20, 20)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + p1 += QPoint(0, 100); + QTest::mouseMove(window, p1); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!buttonReleaseWithinBounds->property("pressed").toBool()); + QCOMPARE(releaseWithinBoundsTappedSpy.count(), 0); +} + +void tst_TapHandler::touchMultiTap() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *button = window->rootObject()->findChild<QQuickItem*>("DragThreshold"); + QVERIFY(button); + QSignalSpy tappedSpy(button, SIGNAL(tapped())); + + // Tap once + QPoint p1 = button->mapToScene(QPointF(2, 2)).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(button->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 1); + + // Tap again in exactly the same place (not likely with touch in the real world) + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(button->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 2); + + // Tap a third time, nearby + p1 += QPoint(dragThreshold, dragThreshold); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(button->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 3); + + // Tap a fourth time, drifting farther away + p1 += QPoint(dragThreshold, dragThreshold); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(button->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 4); +} + +void tst_TapHandler::mouseMultiTap() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *button = window->rootObject()->findChild<QQuickItem*>("DragThreshold"); + QVERIFY(button); + QSignalSpy tappedSpy(button, SIGNAL(tapped())); + + // Tap once + QPoint p1 = button->mapToScene(QPointF(2, 2)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(button->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 1); + + // Tap again in exactly the same place (not likely with touch in the real world) + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(button->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 2); + + // Tap a third time, nearby + p1 += QPoint(dragThreshold, dragThreshold); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(button->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 3); + + // Tap a fourth time, drifting farther away + p1 += QPoint(dragThreshold, dragThreshold); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(button->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 4); +} + +void tst_TapHandler::touchLongPress() +{ + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *button = window->rootObject()->findChild<QQuickItem*>("DragThreshold"); + QVERIFY(button); + QQuickTapHandler *tapHandler = button->findChild<QQuickTapHandler*>("DragThreshold"); + QVERIFY(tapHandler); + QSignalSpy tappedSpy(button, SIGNAL(tapped())); + QSignalSpy longPressThresholdChangedSpy(tapHandler, SIGNAL(longPressThresholdChanged())); + QSignalSpy timeHeldSpy(tapHandler, SIGNAL(timeHeldChanged())); + QSignalSpy longPressedSpy(tapHandler, SIGNAL(longPressed())); + + // Reduce the threshold so that we can get a long press quickly + tapHandler->setLongPressThreshold(0.5); + QCOMPARE(longPressThresholdChangedSpy.count(), 1); + + // Press and hold + QPoint p1 = button->mapToScene(button->clipRect().center()).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(button->property("pressed").toBool()); + QTRY_COMPARE(longPressedSpy.count(), 1); + timeHeldSpy.wait(); // the longer we hold it, the more this will occur + qDebug() << "held" << tapHandler->timeHeld() << "secs; timeHeld updated" << timeHeldSpy.count() << "times"; + QVERIFY(timeHeldSpy.count() > 0); + QVERIFY(tapHandler->timeHeld() > 0.4); // Should be > 0.5 but slow CI and timer granularity can interfere + + // Release and verify that tapped was not emitted + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 0); +} + +void tst_TapHandler::mouseLongPress() +{ + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *button = window->rootObject()->findChild<QQuickItem*>("DragThreshold"); + QVERIFY(button); + QQuickTapHandler *tapHandler = button->findChild<QQuickTapHandler*>("DragThreshold"); + QVERIFY(tapHandler); + QSignalSpy tappedSpy(button, SIGNAL(tapped())); + QSignalSpy longPressThresholdChangedSpy(tapHandler, SIGNAL(longPressThresholdChanged())); + QSignalSpy timeHeldSpy(tapHandler, SIGNAL(timeHeldChanged())); + QSignalSpy longPressedSpy(tapHandler, SIGNAL(longPressed())); + + // Reduce the threshold so that we can get a long press quickly + tapHandler->setLongPressThreshold(0.5); + QCOMPARE(longPressThresholdChangedSpy.count(), 1); + + // Press and hold + QPoint p1 = button->mapToScene(button->clipRect().center()).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(button->property("pressed").toBool()); + QTRY_COMPARE(longPressedSpy.count(), 1); + timeHeldSpy.wait(); // the longer we hold it, the more this will occur + qDebug() << "held" << tapHandler->timeHeld() << "secs; timeHeld updated" << timeHeldSpy.count() << "times"; + QVERIFY(timeHeldSpy.count() > 0); + QVERIFY(tapHandler->timeHeld() > 0.4); // Should be > 0.5 but slow CI and timer granularity can interfere + + // Release and verify that tapped was not emitted + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1, 500); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 0); +} + +void tst_TapHandler::buttonsMultiTouch() +{ + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *buttonDragThreshold = window->rootObject()->findChild<QQuickItem*>("DragThreshold"); + QVERIFY(buttonDragThreshold); + QSignalSpy dragThresholdTappedSpy(buttonDragThreshold, SIGNAL(tapped())); + + QQuickItem *buttonWithinBounds = window->rootObject()->findChild<QQuickItem*>("WithinBounds"); + QVERIFY(buttonWithinBounds); + QSignalSpy withinBoundsTappedSpy(buttonWithinBounds, SIGNAL(tapped())); + + QQuickItem *buttonReleaseWithinBounds = window->rootObject()->findChild<QQuickItem*>("ReleaseWithinBounds"); + QVERIFY(buttonReleaseWithinBounds); + QSignalSpy releaseWithinBoundsTappedSpy(buttonReleaseWithinBounds, SIGNAL(tapped())); + + // can press multiple buttons at the same time + QPoint p1 = buttonDragThreshold->mapToScene(QPointF(20, 20)).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(buttonDragThreshold->property("pressed").toBool()); + QPoint p2 = buttonWithinBounds->mapToScene(QPointF(20, 20)).toPoint(); + QTest::touchEvent(window, touchDevice).stationary(1).press(2, p2, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(buttonWithinBounds->property("pressed").toBool()); + QPoint p3 = buttonReleaseWithinBounds->mapToScene(QPointF(20, 20)).toPoint(); + QTest::touchEvent(window, touchDevice).stationary(1).stationary(2).press(3, p3, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + + // can release top button and press again: others stay pressed the whole time + QTest::touchEvent(window, touchDevice).stationary(2).stationary(3).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!buttonDragThreshold->property("pressed").toBool()); + QCOMPARE(dragThresholdTappedSpy.count(), 1); + QVERIFY(buttonWithinBounds->property("pressed").toBool()); + QCOMPARE(withinBoundsTappedSpy.count(), 0); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + QCOMPARE(releaseWithinBoundsTappedSpy.count(), 0); + QTest::touchEvent(window, touchDevice).stationary(2).stationary(3).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(buttonDragThreshold->property("pressed").toBool()); + QVERIFY(buttonWithinBounds->property("pressed").toBool()); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + + // can release middle button and press again: others stay pressed the whole time + QTest::touchEvent(window, touchDevice).stationary(1).stationary(3).release(2, p2, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!buttonWithinBounds->property("pressed").toBool()); + QCOMPARE(withinBoundsTappedSpy.count(), 1); + QVERIFY(buttonDragThreshold->property("pressed").toBool()); + QCOMPARE(dragThresholdTappedSpy.count(), 1); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + QCOMPARE(releaseWithinBoundsTappedSpy.count(), 0); + QTest::touchEvent(window, touchDevice).stationary(1).stationary(3).press(2, p2, window); + QQuickTouchUtils::flush(window); + QVERIFY(buttonDragThreshold->property("pressed").toBool()); + QVERIFY(buttonWithinBounds->property("pressed").toBool()); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + + // can release bottom button and press again: others stay pressed the whole time + QTest::touchEvent(window, touchDevice).stationary(1).stationary(2).release(3, p3, window); + QQuickTouchUtils::flush(window); + QCOMPARE(releaseWithinBoundsTappedSpy.count(), 1); + QVERIFY(buttonWithinBounds->property("pressed").toBool()); + QCOMPARE(withinBoundsTappedSpy.count(), 1); + QVERIFY(!buttonReleaseWithinBounds->property("pressed").toBool()); + QCOMPARE(dragThresholdTappedSpy.count(), 1); + QTest::touchEvent(window, touchDevice).stationary(1).stationary(2).press(3, p3, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(buttonDragThreshold->property("pressed").toBool()); + QVERIFY(buttonWithinBounds->property("pressed").toBool()); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); +} + +QTEST_MAIN(tst_TapHandler) + +#include "tst_qquicktaphandler.moc" + |