From d02131e743597b9bd3070d986c61a1c91ea8317a Mon Sep 17 00:00:00 2001 From: Matt Vogt Date: Thu, 29 Nov 2012 08:35:00 +1000 Subject: Fix mouse event distribution for Flickable with pressDelay If an item responds to mouse events but does not accept them, it can prevent the events from being processed by the correct item further up the parent chain. For example, a text item inside a mouse area can wrongly consume a press event, so that the following release event does not yield a click when processed by the mouse area. Rather than speculatively assigning the mouse grab to items during event filter processing, change Flickable to retain the grab for the duration of the pressDelay and to release it during replay of the press event. Change-Id: Ied12b9643838a984c7026978047465c2830e55e4 Reviewed-by: Martin Jones --- .../qquickflickable/data/nestedPressDelay.qml | 4 +- .../auto/quick/qquickflickable/data/pressDelay.qml | 32 ++++++++++++ .../quick/qquickflickable/tst_qquickflickable.cpp | 61 ++++++++++++++-------- 3 files changed, 74 insertions(+), 23 deletions(-) create mode 100644 tests/auto/quick/qquickflickable/data/pressDelay.qml (limited to 'tests') diff --git a/tests/auto/quick/qquickflickable/data/nestedPressDelay.qml b/tests/auto/quick/qquickflickable/data/nestedPressDelay.qml index 557b7c4117..742656641f 100644 --- a/tests/auto/quick/qquickflickable/data/nestedPressDelay.qml +++ b/tests/auto/quick/qquickflickable/data/nestedPressDelay.qml @@ -7,7 +7,7 @@ Flickable { contentWidth: 480 contentHeight: 320 flickableDirection: Flickable.HorizontalFlick - pressDelay: 50 + pressDelay: 10000 Rectangle { x: 20 y: 20 @@ -20,7 +20,7 @@ Flickable { flickableDirection: Flickable.HorizontalFlick contentWidth: 1480 contentHeight: 400 - pressDelay: 10000 + pressDelay: 50 Rectangle { y: 100 x: 80 diff --git a/tests/auto/quick/qquickflickable/data/pressDelay.qml b/tests/auto/quick/qquickflickable/data/pressDelay.qml new file mode 100644 index 0000000000..18a5840504 --- /dev/null +++ b/tests/auto/quick/qquickflickable/data/pressDelay.qml @@ -0,0 +1,32 @@ +import QtQuick 2.0 + +Flickable { + flickableDirection: Flickable.VerticalFlick + width: 480 + height: 320 + contentWidth: 480 + contentHeight: 400 + pressDelay: 100 + + MouseArea { + id: ma + objectName: "mouseArea" + y: 100 + anchors.horizontalCenter: parent.horizontalCenter + width: 240 + height: 100 + + Rectangle { + anchors.fill: parent + color: parent.pressed ? 'blue' : 'green' + + Text { + anchors.fill: parent + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + text: 'Hello' + } + } + } +} + diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp index ceed276305..66071e65d4 100644 --- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp +++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp @@ -346,9 +346,13 @@ void tst_qquickflickable::flickDeceleration() void tst_qquickflickable::pressDelay() { - QQmlComponent component(&engine); - component.setData("import QtQuick 2.0; Flickable { pressDelay: 100; }", QUrl::fromLocalFile("")); - QQuickFlickable *flickable = qobject_cast(component.create()); + QScopedPointer window(new QQuickView); + window->setSource(testFileUrl("pressDelay.qml")); + window->show(); + window->requestActivate(); + QVERIFY(window->rootObject() != 0); + + QQuickFlickable *flickable = qobject_cast(window->rootObject()); QSignalSpy spy(flickable, SIGNAL(pressDelayChanged())); QVERIFY(flickable); @@ -360,13 +364,28 @@ void tst_qquickflickable::pressDelay() flickable->setPressDelay(200); QCOMPARE(spy.count(),1); - delete flickable; + QQuickItem *mouseArea = window->rootObject()->findChild("mouseArea"); + QSignalSpy clickedSpy(mouseArea, SIGNAL(clicked(QQuickMouseEvent*))); + + QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(150, 150)); + + // The press should not occur immediately + QVERIFY(mouseArea->property("pressed").toBool() == false); + + // But, it should occur eventually + QTRY_VERIFY(mouseArea->property("pressed").toBool() == true); + + QCOMPARE(clickedSpy.count(),0); + + // On release the clicked signal should be emitted + QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(150, 150)); + QCOMPARE(clickedSpy.count(),1); } // QTBUG-17361 void tst_qquickflickable::nestedPressDelay() { - QQuickView *window = new QQuickView; + QScopedPointer window(new QQuickView); window->setSource(testFileUrl("nestedPressDelay.qml")); window->show(); window->requestActivate(); @@ -378,46 +397,46 @@ void tst_qquickflickable::nestedPressDelay() QQuickFlickable *inner = window->rootObject()->findChild("innerFlickable"); QVERIFY(inner != 0); - QTest::mousePress(window, Qt::LeftButton, 0, QPoint(150, 150)); + QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(150, 150)); // the MouseArea is not pressed immediately QVERIFY(outer->property("pressed").toBool() == false); + QVERIFY(inner->property("pressed").toBool() == false); - // The outer pressDelay will prevail (50ms, vs. 10sec) + // The inner pressDelay will prevail (50ms, vs. 10sec) // QTRY_VERIFY() has 5sec timeout, so will timeout well within 10sec. QTRY_VERIFY(outer->property("pressed").toBool() == true); - QTest::mouseRelease(window, Qt::LeftButton, 0, QPoint(150, 150)); + QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(150, 150)); // Dragging inner Flickable should work - QTest::mousePress(window, Qt::LeftButton, 0, QPoint(80, 150)); + QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(80, 150)); // the MouseArea is not pressed immediately QVERIFY(outer->property("pressed").toBool() == false); + QVERIFY(inner->property("pressed").toBool() == false); - QTest::mouseMove(window, QPoint(60, 150)); - QTest::mouseMove(window, QPoint(40, 150)); - QTest::mouseMove(window, QPoint(20, 150)); + QTest::mouseMove(window.data(), QPoint(60, 150)); + QTest::mouseMove(window.data(), QPoint(40, 150)); + QTest::mouseMove(window.data(), QPoint(20, 150)); - QVERIFY(outer->property("moving").toBool() == false); QVERIFY(inner->property("moving").toBool() == true); + QVERIFY(outer->property("moving").toBool() == false); - QTest::mouseRelease(window, Qt::LeftButton, 0, QPoint(20, 150)); + QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(20, 150)); // Dragging the MouseArea in the inner Flickable should move the inner Flickable - QTest::mousePress(window, Qt::LeftButton, 0, QPoint(150, 150)); + QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(150, 150)); // the MouseArea is not pressed immediately QVERIFY(outer->property("pressed").toBool() == false); - QTest::mouseMove(window, QPoint(130, 150)); - QTest::mouseMove(window, QPoint(110, 150)); - QTest::mouseMove(window, QPoint(90, 150)); + QTest::mouseMove(window.data(), QPoint(130, 150)); + QTest::mouseMove(window.data(), QPoint(110, 150)); + QTest::mouseMove(window.data(), QPoint(90, 150)); QVERIFY(outer->property("moving").toBool() == false); QVERIFY(inner->property("moving").toBool() == true); - QTest::mouseRelease(window, Qt::LeftButton, 0, QPoint(90, 150)); - - delete window; + QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(90, 150)); } void tst_qquickflickable::flickableDirection() -- cgit v1.2.3