diff options
Diffstat (limited to 'tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp')
-rw-r--r-- | tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp | 291 |
1 files changed, 231 insertions, 60 deletions
diff --git a/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp index 6b0f574178..1120cb54c2 100644 --- a/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp +++ b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** 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. -** -** $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$ -** -****************************************************************************/ +// Copyright (C) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QtTest/QtTest> @@ -33,10 +8,13 @@ #include <QtGui/private/qpointingdevice_p.h> #include <QtQuick/private/qquickpointerhandler_p.h> #include <QtQuick/qquickitem.h> +#include <QtQuick/private/qquickitem_p.h> #include <QtQuick/qquickview.h> +#include <QtQml/private/qqmlglobal_p.h> // qmlobject_cast -#include "../../../shared/util.h" -#include "../../shared/viewtestutil.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> +#include <QtQuickTestUtils/private/viewtestutils_p.h> +#include <QQmlComponent> Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests") @@ -103,45 +81,45 @@ public: return (accept && (state != QEventPoint::State::Released)) ? (int)QPointingDevice::GrabExclusive : (int)NoGrab; } - void touchEvent(QTouchEvent *event) + void touchEvent(QTouchEvent *event) override { qCDebug(lcPointerTests) << event << "will accept?" << acceptTouch; for (auto &tp : event->points()) eventList.append(Event(Event::TouchDestination, event->type(), tp.state(), grabTransition(acceptTouch, tp.state()), tp.position(), tp.scenePosition())); event->setAccepted(acceptTouch); } - void mousePressEvent(QMouseEvent *event) + void mousePressEvent(QMouseEvent *event) override { qCDebug(lcPointerTests) << event << "will accept?" << acceptMouse; eventList.append(Event(Event::MouseDestination, event->type(), QEventPoint::State::Pressed, grabTransition(acceptMouse, QEventPoint::State::Pressed), event->position().toPoint(), event->scenePosition())); event->setAccepted(acceptMouse); } - void mouseMoveEvent(QMouseEvent *event) + void mouseMoveEvent(QMouseEvent *event) override { qCDebug(lcPointerTests) << event << "will accept?" << acceptMouse; eventList.append(Event(Event::MouseDestination, event->type(), QEventPoint::State::Updated, grabTransition(acceptMouse, QEventPoint::State::Updated), event->position().toPoint(), event->scenePosition())); event->setAccepted(acceptMouse); } - void mouseReleaseEvent(QMouseEvent *event) + void mouseReleaseEvent(QMouseEvent *event) override { qCDebug(lcPointerTests) << event << "will accept?" << acceptMouse; eventList.append(Event(Event::MouseDestination, event->type(), QEventPoint::State::Released, grabTransition(acceptMouse, QEventPoint::State::Released), event->position().toPoint(), event->scenePosition())); event->setAccepted(acceptMouse); } - void mouseDoubleClickEvent(QMouseEvent *event) + void mouseDoubleClickEvent(QMouseEvent *event) override { qCDebug(lcPointerTests) << event << "will accept?" << acceptMouse; eventList.append(Event(Event::MouseDestination, event->type(), QEventPoint::State::Pressed, grabTransition(acceptMouse, QEventPoint::State::Pressed), event->position().toPoint(), event->scenePosition())); event->setAccepted(acceptMouse); } - void mouseUngrabEvent() + void mouseUngrabEvent() override { qCDebug(lcPointerTests); eventList.append(Event(Event::MouseDestination, QEvent::UngrabMouse, QEventPoint::State::Released, QPointingDevice::UngrabExclusive, QPoint(0,0), QPoint(0,0))); } - bool event(QEvent *event) + bool event(QEvent *event) override { qCDebug(lcPointerTests) << event; return QQuickItem::event(event); @@ -154,7 +132,7 @@ public: bool acceptTouch; bool filterTouch; // when used as event filter - bool eventFilter(QObject *o, QEvent *event) + bool eventFilter(QObject *o, QEvent *event) override { qCDebug(lcPointerTests) << event << o; if (event->type() == QEvent::TouchBegin || @@ -184,7 +162,11 @@ public: class EventHandler : public QQuickPointerHandler { + Q_OBJECT public: + EventHandler(QQuickItem *parent = nullptr) : + QQuickPointerHandler(parent) {} + void handlePointerEventImpl(QPointerEvent *event) override { QQuickPointerHandler::handlePointerEventImpl(event); @@ -233,7 +215,8 @@ class tst_PointerHandlers : public QQmlDataTest Q_OBJECT public: tst_PointerHandlers() - : touchDevice(QTest::createTouchDevice()) + : QQmlDataTest(QT_QMLTEST_DATADIR) + , touchDevice(QTest::createTouchDevice()) {} private slots: @@ -247,9 +230,14 @@ private slots: void dynamicCreation(); void handlerInWindow(); void dynamicCreationInWindow(); + void cppConstruction(); + void reparenting(); + void grabberSceneChange_data(); + void grabberSceneChange(); + void clip(); protected: - bool eventFilter(QObject *, QEvent *event) + bool eventFilter(QObject *, QEvent *event) override { QEventPoint::State tpState; switch (event->type()) { @@ -284,8 +272,8 @@ void tst_PointerHandlers::createView(QScopedPointer<QQuickView> &window, const c // window->setGeometry(0,0,240,320); window->setSource(testFileUrl(fileName)); QTRY_COMPARE(window->status(), QQuickView::Ready); - QQuickViewTestUtil::centerOnScreen(window.data()); - QQuickViewTestUtil::moveMouseAway(window.data()); + QQuickViewTestUtils::centerOnScreen(window.data()); + QQuickViewTestUtils::moveMouseAway(window.data()); window->show(); QVERIFY(QTest::qWaitForWindowActive(window.data())); @@ -335,11 +323,11 @@ void tst_PointerHandlers::touchEventDelivery() QTest::touchEvent(window, touchDevice).move(0, p1, window); QQuickTouchUtils::flush(window); qCDebug(lcPointerTests) << "events after touch move" << eventItem1->eventList; - QCOMPARE(eventItem1->eventList.size(), 2); // no grabs -> no updates + QCOMPARE(eventItem1->eventList.size(), 3); // no grabs -> only the handler gets the update QTest::touchEvent(window, touchDevice).release(0, p1, window); QQuickTouchUtils::flush(window); qCDebug(lcPointerTests) << "events after touch release" << eventItem1->eventList; - QCOMPARE(eventItem1->eventList.size(), 3); + QCOMPARE(eventItem1->eventList.size(), 4); QCOMPARE_EVENT(eventItem1->eventList.size() - 1, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Released, NoGrab); eventItem1->eventList.clear(); @@ -390,12 +378,12 @@ void tst_PointerHandlers::touchEventDelivery() QTest::touchEvent(window, touchDevice).move(0, p1, window); QQuickTouchUtils::flush(window); qCDebug(lcPointerTests) << "events after touch move" << eventItem1->eventList; - QCOMPARE(eventItem1->eventList.size(), 2); + QCOMPARE(eventItem1->eventList.size(), 3); QTest::touchEvent(window, touchDevice).release(0, p1, window); QQuickTouchUtils::flush(window); qCDebug(lcPointerTests) << "events after touch release" << eventItem1->eventList; - QCOMPARE(eventItem1->eventList.size(), 3); - QCOMPARE_EVENT(2, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Released, NoGrab); + QCOMPARE(eventItem1->eventList.size(), 4); + QCOMPARE_EVENT(3, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Released, NoGrab); eventItem1->eventList.clear(); // wait to avoid getting a double click event @@ -417,11 +405,11 @@ void tst_PointerHandlers::touchEventDelivery() QTest::touchEvent(window, touchDevice).move(0, p1, window); QQuickTouchUtils::flush(window); qCDebug(lcPointerTests) << "events after touch move" << eventItem1->eventList; - QCOMPARE(eventItem1->eventList.size(), 2); + QCOMPARE(eventItem1->eventList.size(), 3); QTest::touchEvent(window, touchDevice).release(0, p1, window); QQuickTouchUtils::flush(window); qCDebug(lcPointerTests) << "events after touch release" << eventItem1->eventList; - QCOMPARE(eventItem1->eventList.size(), 3); + QCOMPARE(eventItem1->eventList.size(), 4); eventItem1->eventList.clear(); // wait to avoid getting a double click event @@ -485,18 +473,24 @@ void tst_PointerHandlers::mouseEventDelivery() EventItem *eventItem1 = window->rootObject()->findChild<EventItem*>("eventItem1"); QVERIFY(eventItem1); + EventHandler *handler = window->rootObject()->findChild<EventHandler*>("eventHandler"); + QVERIFY(handler); + QCOMPARE(handler->parentItem(), eventItem1); + QCOMPARE(handler->target(), eventItem1); + QVERIFY(QQuickItemPrivate::get(eventItem1)->extra->resourcesList.contains(handler)); + // Do not accept anything QPoint p1 = QPoint(20, 20); QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); qCDebug(lcPointerTests) << "events after mouse press" << eventItem1->eventList; - QCOMPARE(eventItem1->eventList.size(), 2); + QCOMPARE(eventItem1->eventList.size(), 3); // handler: hover; handler: press; item: press p1 += QPoint(10, 0); QTest::mouseMove(window, p1); qCDebug(lcPointerTests) << "events after mouse move" << eventItem1->eventList; - QCOMPARE(eventItem1->eventList.size(), 2); + QCOMPARE(eventItem1->eventList.size(), 4); // handler: hover QTest::mouseRelease(window, Qt::LeftButton); qCDebug(lcPointerTests) << "events after mouse release" << eventItem1->eventList; - QCOMPARE(eventItem1->eventList.size(), 2); + QCOMPARE(eventItem1->eventList.size(), 4); eventItem1->eventList.clear(); // wait to avoid getting a double click event @@ -509,9 +503,9 @@ void tst_PointerHandlers::mouseEventDelivery() p1 = QPoint(20, 20); QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); qCDebug(lcPointerTests) << "events after mouse press" << eventItem1->eventList; - QCOMPARE(eventItem1->eventList.size(), 2); - QCOMPARE_EVENT(0, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Pressed, NoGrab); - QCOMPARE_EVENT(1, Event::MouseDestination, QEvent::MouseButtonPress, QEventPoint::State::Pressed, QPointingDevice::GrabExclusive); + QCOMPARE(eventItem1->eventList.size(), 3); + QCOMPARE_EVENT(1, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Pressed, NoGrab); + QCOMPARE_EVENT(2, Event::MouseDestination, QEvent::MouseButtonPress, QEventPoint::State::Pressed, QPointingDevice::GrabExclusive); QCOMPARE(window->mouseGrabberItem(), eventItem1); QPointF localPos = eventItem1->mapFromScene(p1); @@ -524,11 +518,11 @@ void tst_PointerHandlers::mouseEventDelivery() p1 += QPoint(10, 0); QTest::mouseMove(window, p1); qCDebug(lcPointerTests) << "events after mouse move" << eventItem1->eventList; - QCOMPARE(eventItem1->eventList.size(), 4); - QCOMPARE_EVENT(3, Event::MouseDestination, QEvent::MouseMove, QEventPoint::State::Updated, QPointingDevice::GrabExclusive); + QCOMPARE(eventItem1->eventList.size(), 5); + QCOMPARE_EVENT(4, Event::MouseDestination, QEvent::MouseMove, QEventPoint::State::Updated, QPointingDevice::GrabExclusive); QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); qCDebug(lcPointerTests) << "events after mouse release" << eventItem1->eventList; - QCOMPARE(eventItem1->eventList.size(), 7); + QCOMPARE(eventItem1->eventList.size(), 8); QCOMPARE_EVENT(eventItem1->eventList.size() - 2, Event::MouseDestination, QEvent::MouseButtonRelease, QEventPoint::State::Released, NoGrab); QCOMPARE_EVENT(eventItem1->eventList.size() - 1, Event::MouseDestination, QEvent::UngrabMouse, QEventPoint::State::Released, QPointingDevice::UngrabExclusive); eventItem1->eventList.clear(); @@ -631,12 +625,14 @@ void tst_PointerHandlers::dynamicCreation() QCOMPARE(handler->parentItem(), eventItem1); QCOMPARE(handler->target(), eventItem1); + QVERIFY(QQuickItemPrivate::get(eventItem1)->extra->resourcesList.contains(handler)); QPoint p1(20, 20); QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); - QTRY_COMPARE(eventItem1->eventList.size(), 2); - QCOMPARE_EVENT(0, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Pressed, NoGrab); - QCOMPARE_EVENT(1, Event::MouseDestination, QEvent::MouseButtonPress, QEventPoint::State::Pressed, NoGrab); + QTRY_COMPARE(eventItem1->eventList.size(), 3); + QCOMPARE_EVENT(0, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Updated, NoGrab); + QCOMPARE_EVENT(1, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Pressed, NoGrab); + QCOMPARE_EVENT(2, Event::MouseDestination, QEvent::MouseButtonPress, QEventPoint::State::Pressed, NoGrab); QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); } @@ -688,6 +684,181 @@ void tst_PointerHandlers::dynamicCreationInWindow() QTRY_COMPARE(handler->releaseEventCount, 1); } +void tst_PointerHandlers::cppConstruction() +{ + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "itemOnly.qml"); + QQuickView * window = windowPtr.data(); + + EventItem *eventItem1 = window->rootObject()->findChild<EventItem*>("eventItem1"); + QVERIFY(eventItem1); + QQuickItemPrivate *eventItemPriv = QQuickItemPrivate::get(eventItem1); + // tell the handler to grab on press + eventItem1->grabPointer = true; + + EventHandler handler(eventItem1); + QCOMPARE(handler.parentItem(), eventItem1); + QCOMPARE(handler.target(), eventItem1); + QCOMPARE(eventItemPriv->extra->pointerHandlers.first(), &handler); + QVERIFY(eventItemPriv->extra->resourcesList.contains(&handler)); + + // the handler and then eventItem1 sees each event + QPoint p1 = QPoint(20, 20); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QCOMPARE(handler.pressEventCount, 1); + qCDebug(lcPointerTests) << "events after mouse press" << eventItem1->eventList; + QCOMPARE(eventItem1->eventList.size(), 3); + QTest::mouseRelease(window, Qt::LeftButton); + QCOMPARE(handler.releaseEventCount, 1); + qCDebug(lcPointerTests) << "events after mouse release" << eventItem1->eventList; + QCOMPARE(eventItem1->eventList.size(), 7); + + // wait to avoid getting a double click event + QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); +} + +void tst_PointerHandlers::reparenting() +{ + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "reparenting.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *topItem = window->rootObject()->findChild<QQuickItem*>("top"); + QVERIFY(topItem); + QQuickItem *bottomItem = window->rootObject()->findChild<QQuickItem*>("bottom"); + QVERIFY(bottomItem); + EventHandler *handler = window->rootObject()->findChild<EventHandler*>("eventHandler"); + QVERIFY(handler); + topItem->setAcceptedMouseButtons(Qt::RightButton); + + for (int i = 1; i < 5; ++i) { + QQuickItem *expectedParentItem = (i % 2 ? topItem : bottomItem); + QQuickItem *unexpectedParentItem = (i % 2 ? bottomItem : topItem); + qCDebug(lcPointerTests) << "initial parent" << handler->parentItem() << "waiting for" << expectedParentItem; + QTRY_COMPARE(handler->parentItem(), expectedParentItem); + QCOMPARE(handler->target(), expectedParentItem); + QVERIFY(QQuickItemPrivate::get(expectedParentItem)->extra.isAllocated()); + QVERIFY(QQuickItemPrivate::get(expectedParentItem)->extra->resourcesList.contains(handler)); + if (QQuickItemPrivate::get(unexpectedParentItem)->extra.isAllocated()) + QVERIFY(!QQuickItemPrivate::get(unexpectedParentItem)->extra->resourcesList.contains(handler)); + QCOMPARE(expectedParentItem->acceptedMouseButtons(), Qt::AllButtons); + QCOMPARE(unexpectedParentItem->acceptedMouseButtons(), unexpectedParentItem == topItem ? Qt::RightButton : Qt::NoButton); + + QPoint pt = expectedParentItem->mapToScene(expectedParentItem->boundingRect().center()).toPoint(); + qCDebug(lcPointerTests) << "click @" << pt; + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, pt); + QTRY_COMPARE(handler->pressEventCount, i); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, pt); + QTRY_COMPARE(handler->releaseEventCount, i); + } +} + +/*! + Verify that removing an item that has a grabbing handler from the scene + does not result in crashes in our event dispatching code. The item's window() + pointer will be nullptr, so the handler must have released the grab, or never + gotten the grab, depending on when the item gets removed. + + See QTBUG-114475. +*/ +void tst_PointerHandlers::grabberSceneChange_data() +{ + QTest::addColumn<bool>("useTimer"); + QTest::addColumn<int>("grabChangedCount"); + + QTest::addRow("Immediately") << false << 0; + QTest::addRow("Delayed") << true << 2; +} + +void tst_PointerHandlers::grabberSceneChange() +{ + QFETCH(const bool, useTimer); + QFETCH(const int, grabChangedCount); + + QQmlEngine engine; + QQmlComponent component(&engine); + component.loadUrl(testFileUrl("grabberSceneChange.qml")); + QQuickWindow *window = qobject_cast<QQuickWindow*>(component.create()); + QScopedPointer<QQuickWindow> cleanup(window); + QVERIFY(window); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + window->setProperty("useTimer", useTimer); + + QQuickItem *container = window->findChild<QQuickItem *>("container"); + + QPoint p1 = QPoint(window->width() / 2, window->height() / 2); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + // The container gets removed from this window, either immediately on + // press, or through a timer. + QTRY_COMPARE(container->parentItem(), nullptr); + + QEXPECT_FAIL("Delayed", + "PointerHandlers don't release their grab when item is removed", Continue); + QCOMPARE(window->property("grabChangedCounter").toInt(), grabChangedCount); + + // this should not crash + QTest::mouseMove(window, p1 + QPoint(5, 5)); +} + +void tst_PointerHandlers::clip() +{ + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "clip.qml"); + QQuickView * window = windowPtr.data(); + QVERIFY(window); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + EventHandler *handler = window->contentItem()->findChild<EventHandler*>("eventHandler"); + EventHandler *circleHandler = window->contentItem()->findChild<EventHandler*>("circle eventHandler"); + + QCOMPARE(handler->pressEventCount, 0); + QCOMPARE(circleHandler->pressEventCount, 0); + QCOMPARE(handler->releaseEventCount, 0); + QCOMPARE(circleHandler->releaseEventCount, 0); + + const QPoint rectPt = QPoint(1, 1); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, rectPt); + QCOMPARE(handler->pressEventCount, 1); + QCOMPARE(circleHandler->pressEventCount, 0); + + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, rectPt); + QCOMPARE(handler->releaseEventCount, 1); + QCOMPARE(circleHandler->releaseEventCount, 0); + + + handler->pressEventCount = 0; + circleHandler->pressEventCount = 0; + handler->releaseEventCount = 0; + circleHandler->releaseEventCount = 0; + + const QPoint rectAndCirclePt = QPoint(49 ,49); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, rectAndCirclePt); + QCOMPARE(handler->pressEventCount, 1); + QCOMPARE(circleHandler->pressEventCount, 1); + + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, rectAndCirclePt); + QCOMPARE(handler->releaseEventCount, 1); + QCOMPARE(circleHandler->releaseEventCount, 1); + + + handler->pressEventCount = 0; + circleHandler->pressEventCount = 0; + handler->releaseEventCount = 0; + circleHandler->releaseEventCount = 0; + + const QPoint circlePt = QPoint(51 ,51); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, circlePt); + QCOMPARE(handler->pressEventCount, 0); + QCOMPARE(circleHandler->pressEventCount, 1); + + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, circlePt); + QCOMPARE(handler->releaseEventCount, 0); + QCOMPARE(circleHandler->releaseEventCount, 1); +} + QTEST_MAIN(tst_PointerHandlers) #include "tst_qquickpointerhandler.moc" |