Fix PathView stealing mouse grab from its child items.
authorAndrew den Exter <andrew.den.exter@jollamobile.com>
Fri, 27 Sep 2013 04:26:48 +0000 (14:26 +1000)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Mon, 30 Sep 2013 23:50:49 +0000 (01:50 +0200)
Apply the improvements that have been applied to Flickables handling of
child items over time to PathView to bring its behavior back in line.

Task-number: QTBUG-33699
Change-Id: I76a412d75c48f9cf2f12f5f6f1aa01ff62d06364
Reviewed-by: Joona Petrell <joona.petrell@jollamobile.com>
Reviewed-by: Alan Alpert (Personal) <416365416c@gmail.com>
src/quick/items/qquickpathview.cpp
tests/auto/quick/qquickpathview/data/nestedmousearea.qml [new file with mode: 0644]
tests/auto/quick/qquickpathview/tst_qquickpathview.cpp

index 54388ea..823885c 100644 (file)
@@ -1764,37 +1764,48 @@ bool QQuickPathView::sendMouseEvent(QMouseEvent *event)
 
     QQuickWindow *c = window();
     QQuickItem *grabber = c ? c->mouseGrabberItem() : 0;
+    if (grabber == this && d->stealMouse) {
+        // we are already the grabber and we do want the mouse event to ourselves.
+        return true;
+    }
+
+    bool grabberDisabled = grabber && !grabber->isEnabled();
     bool stealThisEvent = d->stealMouse;
-    if ((stealThisEvent || contains(localPos)) && (!grabber || !grabber->keepMouseGrab())) {
-        QMouseEvent mouseEvent(event->type(), localPos, event->windowPos(), event->screenPos(),
-                               event->button(), event->buttons(), event->modifiers());
-        mouseEvent.setAccepted(false);
+    if ((stealThisEvent || contains(localPos)) && (!grabber || !grabber->keepMouseGrab() || grabberDisabled)) {
+        QScopedPointer<QMouseEvent> mouseEvent(QQuickWindowPrivate::cloneMouseEvent(event, &localPos));
+        mouseEvent->setAccepted(false);
 
-        switch (mouseEvent.type()) {
+        switch (mouseEvent->type()) {
         case QEvent::MouseMove:
-            d->handleMouseMoveEvent(&mouseEvent);
+            d->handleMouseMoveEvent(mouseEvent.data());
             break;
         case QEvent::MouseButtonPress:
-            d->handleMousePressEvent(&mouseEvent);
+            d->handleMousePressEvent(mouseEvent.data());
             stealThisEvent = d->stealMouse;   // Update stealThisEvent in case changed by function call above
             break;
         case QEvent::MouseButtonRelease:
-            d->handleMouseReleaseEvent(&mouseEvent);
+            d->handleMouseReleaseEvent(mouseEvent.data());
             break;
         default:
             break;
         }
         grabber = c->mouseGrabberItem();
-        if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this)
+        if ((grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this) || grabberDisabled) {
             grabMouse();
+        }
 
-        return d->stealMouse;
+        const bool filtered = stealThisEvent || grabberDisabled;
+        if (filtered) {
+            event->setAccepted(false);
+        }
+        return filtered;
     } else if (d->timer.isValid()) {
         d->timer.invalidate();
         d->fixOffset();
     }
-    if (event->type() == QEvent::MouseButtonRelease)
+    if (event->type() == QEvent::MouseButtonRelease || (grabber && grabber->keepMouseGrab() && !grabberDisabled)) {
         d->stealMouse = false;
+    }
     return false;
 }
 
diff --git a/tests/auto/quick/qquickpathview/data/nestedmousearea.qml b/tests/auto/quick/qquickpathview/data/nestedmousearea.qml
new file mode 100644 (file)
index 0000000..bdd2865
--- /dev/null
@@ -0,0 +1,36 @@
+import QtQuick 2.0
+
+PathView {
+    width: 400
+    height: 400
+
+    model: 2
+    path: Path {
+        startX: -300
+        startY: 200
+        PathLine {
+            x: 700
+            y: 200
+        }
+    }
+    delegate: Rectangle {
+        width: 300
+        height: 300
+        border.width: 5
+        color: "lightsteelblue"
+
+        Rectangle {
+            x: 100
+            y: 100
+            width: 100
+            height: 100
+
+            color: "yellow"
+
+            MouseArea {
+                drag.target: parent
+                anchors.fill: parent
+            }
+        }
+    }
+}
index 0834977..81d1bbd 100644 (file)
@@ -124,6 +124,7 @@ private slots:
     void visualDataModel();
     void undefinedPath();
     void mouseDrag();
+    void nestedMouseAreaDrag();
     void treeModel();
     void changePreferredHighlight();
     void missingPercent();
@@ -1507,6 +1508,29 @@ void tst_QQuickPathView::mouseDrag()
 
 }
 
+void tst_QQuickPathView::nestedMouseAreaDrag()
+{
+    QScopedPointer<QQuickView> window(createView());
+    QQuickViewTestUtil::moveMouseAway(window.data());
+    window->setSource(testFileUrl("nestedmousearea.qml"));
+    window->show();
+    window->requestActivate();
+    QVERIFY(QTest::qWaitForWindowActive(window.data()));
+    QCOMPARE(window.data(), qGuiApp->focusWindow());
+
+
+    QQuickPathView *pathview = qobject_cast<QQuickPathView*>(window->rootObject());
+    QVERIFY(pathview != 0);
+
+    // Dragging the child mouse area should move it and not animate the PathView
+    flick(window.data(), QPoint(200,200), QPoint(300,200), 200);
+    QVERIFY(!pathview->isMoving());
+
+    // Dragging outside the mouse are should animate the PathView.
+    flick(window.data(), QPoint(75,75), QPoint(175,75), 200);
+    QVERIFY(pathview->isMoving());
+}
+
 void tst_QQuickPathView::treeModel()
 {
     QScopedPointer<QQuickView> window(createView());