From 3f62886ac84b31c5c8f90205583dc65e811ad20b Mon Sep 17 00:00:00 2001
From: Martin Jones <martin.jones@nokia.com>
Date: Mon, 5 Mar 2012 15:07:27 +1000
Subject: [PATCH] Handle MouseArea.enabled = false after mouse is pressed.

Currently this leaves the MouseArea in a broken state,
i.e. still in pressed state, and the next press after
it is re-enabled is ignored.

In this case we now allow subsequent mouse move or
release events to continue. Following the release,
no further press will be accepted.

Change-Id: I65a890da90e2166ad568505fffdbd3db6c97165b
Reviewed-by: Andrew den Exter <andrew.den-exter@nokia.com>
---
 src/quick/items/qquickmousearea.cpp           |  12 +-
 .../qquickmousearea/tst_qquickmousearea.cpp   | 105 ++++++++++++++++++
 2 files changed, 111 insertions(+), 6 deletions(-)

diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp
index ec2c980879..ef57242319 100644
--- a/src/quick/items/qquickmousearea.cpp
+++ b/src/quick/items/qquickmousearea.cpp
@@ -697,7 +697,7 @@ void QQuickMouseArea::mousePressEvent(QMouseEvent *event)
 void QQuickMouseArea::mouseMoveEvent(QMouseEvent *event)
 {
     Q_D(QQuickMouseArea);
-    if (!d->absorb) {
+    if (!d->absorb && !d->pressed) {
         QQuickItem::mouseMoveEvent(event);
         return;
     }
@@ -783,7 +783,7 @@ void QQuickMouseArea::mouseReleaseEvent(QMouseEvent *event)
 {
     Q_D(QQuickMouseArea);
     d->stealMouse = false;
-    if (!d->absorb) {
+    if (!d->absorb && !d->pressed) {
         QQuickItem::mouseReleaseEvent(event);
     } else {
         d->saveEvent(event);
@@ -820,7 +820,7 @@ void QQuickMouseArea::mouseDoubleClickEvent(QMouseEvent *event)
 void QQuickMouseArea::hoverEnterEvent(QHoverEvent *event)
 {
     Q_D(QQuickMouseArea);
-    if (!d->absorb) {
+    if (!d->absorb && !d->pressed) {
         QQuickItem::hoverEnterEvent(event);
     } else {
         d->lastPos = event->posF();
@@ -837,7 +837,7 @@ void QQuickMouseArea::hoverEnterEvent(QHoverEvent *event)
 void QQuickMouseArea::hoverMoveEvent(QHoverEvent *event)
 {
     Q_D(QQuickMouseArea);
-    if (!d->absorb) {
+    if (!d->absorb && !d->pressed) {
         QQuickItem::hoverMoveEvent(event);
     } else {
         d->lastPos = event->posF();
@@ -854,7 +854,7 @@ void QQuickMouseArea::hoverMoveEvent(QHoverEvent *event)
 void QQuickMouseArea::hoverLeaveEvent(QHoverEvent *event)
 {
     Q_D(QQuickMouseArea);
-    if (!d->absorb)
+    if (!d->absorb && !d->pressed)
         QQuickItem::hoverLeaveEvent(event);
     else
         setHovered(false);
@@ -935,7 +935,7 @@ bool QQuickMouseArea::sendMouseEvent(QMouseEvent *event)
 bool QQuickMouseArea::childMouseEventFilter(QQuickItem *i, QEvent *e)
 {
     Q_D(QQuickMouseArea);
-    if (!d->absorb || !isVisible() || !d->drag || !d->drag->filterChildren())
+    if (!d->pressed && (!d->absorb || !isVisible() || !d->drag || !d->drag->filterChildren()))
         return QQuickItem::childMouseEventFilter(i, e);
     switch (e->type()) {
     case QEvent::MouseButtonPress:
diff --git a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
index 0fb82a66bc..4375e835aa 100644
--- a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
+++ b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
@@ -72,6 +72,7 @@ private slots:
     void hoverPosition();
     void hoverPropagation();
     void hoverVisible();
+    void disableAfterPress();
 
 private:
     QQuickView *createView();
@@ -801,6 +802,110 @@ void tst_QQuickMouseArea::hoverVisible()
     delete canvas;
 }
 
+void tst_QQuickMouseArea::disableAfterPress()
+{
+    QQuickView *canvas = createView();
+    canvas->setSource(testFileUrl("dragging.qml"));
+    canvas->show();
+    canvas->requestActivateWindow();
+    QTest::qWait(20);
+    QVERIFY(canvas->rootObject() != 0);
+
+    QQuickMouseArea *mouseArea = canvas->rootObject()->findChild<QQuickMouseArea*>("mouseregion");
+    QQuickDrag *drag = mouseArea->drag();
+    QVERIFY(mouseArea != 0);
+    QVERIFY(drag != 0);
+
+    QSignalSpy mousePositionSpy(mouseArea, SIGNAL(positionChanged(QQuickMouseEvent*)));
+    QSignalSpy mousePressSpy(mouseArea, SIGNAL(pressed(QQuickMouseEvent*)));
+    QSignalSpy mouseReleaseSpy(mouseArea, SIGNAL(released(QQuickMouseEvent*)));
+
+    // target
+    QQuickItem *blackRect = canvas->rootObject()->findChild<QQuickItem*>("blackrect");
+    QVERIFY(blackRect != 0);
+    QVERIFY(blackRect == drag->target());
+
+    QVERIFY(!drag->active());
+
+    QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(100,100));
+
+    QTRY_COMPARE(mousePressSpy.count(), 1);
+
+    QVERIFY(!drag->active());
+    QCOMPARE(blackRect->x(), 50.0);
+    QCOMPARE(blackRect->y(), 50.0);
+
+    // First move event triggers drag, second is acted upon.
+    // This is due to possibility of higher stacked area taking precedence.
+
+    QTest::mouseMove(canvas, QPoint(111,111));
+    QTest::qWait(50);
+    QTest::mouseMove(canvas, QPoint(122,122));
+
+    QTRY_COMPARE(mousePositionSpy.count(), 2);
+
+    QVERIFY(drag->active());
+    QCOMPARE(blackRect->x(), 72.0);
+    QCOMPARE(blackRect->y(), 72.0);
+
+    mouseArea->setEnabled(false);
+
+    // move should still be acted upon
+    QTest::mouseMove(canvas, QPoint(133,133));
+    QTest::qWait(50);
+    QTest::mouseMove(canvas, QPoint(144,144));
+
+    QTRY_COMPARE(mousePositionSpy.count(), 4);
+
+    QVERIFY(drag->active());
+    QCOMPARE(blackRect->x(), 94.0);
+    QCOMPARE(blackRect->y(), 94.0);
+
+    QVERIFY(mouseArea->pressed());
+    QVERIFY(mouseArea->hovered());
+
+    QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(144,144));
+
+    QTRY_COMPARE(mouseReleaseSpy.count(), 1);
+
+    QVERIFY(!drag->active());
+    QCOMPARE(blackRect->x(), 94.0);
+    QCOMPARE(blackRect->y(), 94.0);
+
+    QVERIFY(!mouseArea->pressed());
+    QVERIFY(!mouseArea->hovered()); // since hover is not enabled
+
+    // Next press will be ignored
+    blackRect->setX(50);
+    blackRect->setY(50);
+
+    mousePressSpy.clear();
+    mousePositionSpy.clear();
+    mouseReleaseSpy.clear();
+
+    QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(100,100));
+    QTest::qWait(50);
+    QCOMPARE(mousePressSpy.count(), 0);
+
+    QTest::mouseMove(canvas, QPoint(111,111));
+    QTest::qWait(50);
+    QTest::mouseMove(canvas, QPoint(122,122));
+    QTest::qWait(50);
+
+    QCOMPARE(mousePositionSpy.count(), 0);
+
+    QVERIFY(!drag->active());
+    QCOMPARE(blackRect->x(), 50.0);
+    QCOMPARE(blackRect->y(), 50.0);
+
+    QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(122,122));
+    QTest::qWait(50);
+
+    QCOMPARE(mouseReleaseSpy.count(), 0);
+
+    delete canvas;
+}
+
 QTEST_MAIN(tst_QQuickMouseArea)
 
 #include "tst_qquickmousearea.moc"
-- 
GitLab