Fix extra hover enter events being sent by QSGCanvas
authorCaio Marcelo de Oliveira Filho <caio.oliveira@openbossa.org>
Mon, 29 Aug 2011 13:08:45 +0000 (10:08 -0300)
committerQt by Nokia <qt-info@nokia.com>
Wed, 31 Aug 2011 01:23:03 +0000 (03:23 +0200)
This fixes two issues: when one item is entered it is getting the
enter event twice. When we are moving from two items that share the
same parent, the parent is getting enter event -- which shouldn't
happen.

Change-Id: If0fe6d64d1f7cfb8679ce11edda7c02dc3783f9a
Reviewed-on: http://codereview.qt.nokia.com/3860
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Alan Alpert <alan.alpert@nokia.com>

src/declarative/items/qsgcanvas.cpp
tests/auto/declarative/qsgitem/tst_qsgitem.cpp

index e62031a..23b2b43 100644 (file)
@@ -1251,38 +1251,36 @@ bool QSGCanvasPrivate::deliverHoverEvent(QSGItem *item, const QPointF &scenePos,
                 //move
                 accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
             } else {
-                QList<QSGItem*> parents;
+                QList<QSGItem *> itemsToHover;
                 QSGItem* parent = item;
-                parents << item;
+                itemsToHover << item;
                 while ((parent = parent->parentItem()))
-                    parents << parent;
+                    itemsToHover << parent;
 
-                //exit from previous (excepting ancestors)
-                while (!hoverItems.isEmpty() && !parents.contains(hoverItems[0])){
+                // Leaving from previous hovered items until we reach the item or one of its ancestors.
+                while (!hoverItems.isEmpty() && !itemsToHover.contains(hoverItems[0])) {
                     sendHoverEvent(QEvent::HoverLeave, hoverItems[0], scenePos, lastScenePos, modifiers, accepted);
                     hoverItems.removeFirst();
                 }
 
                 if (!hoverItems.isEmpty() && hoverItems[0] == item){//Not entering a new Item
+                    // ### Shouldn't we send moves for the parent items as well?
                     accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
                 } else {
-                    //enter any ancestors that also wish to be hovered and aren't
+                    // Enter items that are not entered yet.
                     int startIdx = -1;
                     if (!hoverItems.isEmpty())
-                        startIdx = parents.indexOf(hoverItems[0]);
+                        startIdx = itemsToHover.indexOf(hoverItems[0]) - 1;
                     if (startIdx == -1)
-                        startIdx = parents.count() - 1;
+                        startIdx = itemsToHover.count() - 1;
 
                     for (int i = startIdx; i >= 0; i--) {
-                        if (QSGItemPrivate::get(parents[i])->hoverEnabled) {
-                            hoverItems.prepend(parents[i]);
-                            sendHoverEvent(QEvent::HoverEnter, parents[i], scenePos, lastScenePos, modifiers, accepted);
+                        QSGItem *itemToHover = itemsToHover[i];
+                        if (QSGItemPrivate::get(itemToHover)->hoverEnabled) {
+                            hoverItems.prepend(itemToHover);
+                            sendHoverEvent(QEvent::HoverEnter, itemToHover, scenePos, lastScenePos, modifiers, accepted);
                         }
                     }
-
-                    //enter new item
-                    hoverItems.prepend(item);
-                    accepted = sendHoverEvent(QEvent::HoverEnter, item, scenePos, lastScenePos, modifiers, accepted);
                 }
             }
             return true;
index 7a612c4..5c3b9db 100644 (file)
@@ -127,6 +127,7 @@ private slots:
 
     void wheelEvent_data();
     void wheelEvent();
+    void hoverEventInParent();
 
 private:
     void ensureFocus(QWidget *w) {
@@ -894,6 +895,89 @@ void tst_qsgitem::wheelEvent()
     delete canvas;
 }
 
+class HoverItem : public QSGItem
+{
+Q_OBJECT
+public:
+    HoverItem(QSGItem *parent = 0)
+        : QSGItem(parent), hoverEnterCount(0), hoverMoveCount(0), hoverLeaveCount(0)
+    { }
+    void resetCounters() {
+        hoverEnterCount = 0;
+        hoverMoveCount = 0;
+        hoverLeaveCount = 0;
+    }
+    int hoverEnterCount;
+    int hoverMoveCount;
+    int hoverLeaveCount;
+protected:
+    virtual void hoverEnterEvent(QHoverEvent *event) {
+        event->accept();
+        ++hoverEnterCount;
+    }
+    virtual void hoverMoveEvent(QHoverEvent *event) {
+        event->accept();
+        ++hoverMoveCount;
+    }
+    virtual void hoverLeaveEvent(QHoverEvent *event) {
+        event->accept();
+        ++hoverLeaveCount;
+    }
+};
+
+// ### For some unknown reason QTest::mouseMove() isn't working correctly.
+static void sendMouseMove(QObject *object, const QPoint &position)
+{
+    QMouseEvent moveEvent(QEvent::MouseMove, position, Qt::NoButton, Qt::NoButton, 0);
+    QApplication::sendEvent(object, &moveEvent);
+}
+
+void tst_qsgitem::hoverEventInParent()
+{
+    QSGCanvas *canvas = new QSGCanvas();
+    canvas->resize(200, 200);
+    canvas->show();
+
+    HoverItem *parentItem = new HoverItem(canvas->rootItem());
+    parentItem->setSize(QSizeF(200, 200));
+    parentItem->setAcceptHoverEvents(true);
+
+    HoverItem *leftItem = new HoverItem(parentItem);
+    leftItem->setSize(QSizeF(100, 200));
+    leftItem->setAcceptHoverEvents(true);
+
+    HoverItem *rightItem = new HoverItem(parentItem);
+    rightItem->setSize(QSizeF(100, 200));
+    rightItem->setPos(QPointF(100, 0));
+    rightItem->setAcceptHoverEvents(true);
+
+    const QPoint insideLeft(50, 100);
+    const QPoint insideRight(150, 100);
+
+    sendMouseMove(canvas, insideLeft);
+    parentItem->resetCounters();
+    leftItem->resetCounters();
+    rightItem->resetCounters();
+
+    sendMouseMove(canvas, insideRight);
+    QCOMPARE(parentItem->hoverEnterCount, 0);
+    QCOMPARE(parentItem->hoverLeaveCount, 0);
+    QCOMPARE(leftItem->hoverEnterCount, 0);
+    QCOMPARE(leftItem->hoverLeaveCount, 1);
+    QCOMPARE(rightItem->hoverEnterCount, 1);
+    QCOMPARE(rightItem->hoverLeaveCount, 0);
+
+    sendMouseMove(canvas, insideLeft);
+    QCOMPARE(parentItem->hoverEnterCount, 0);
+    QCOMPARE(parentItem->hoverLeaveCount, 0);
+    QCOMPARE(leftItem->hoverEnterCount, 1);
+    QCOMPARE(leftItem->hoverLeaveCount, 1);
+    QCOMPARE(rightItem->hoverEnterCount, 1);
+    QCOMPARE(rightItem->hoverLeaveCount, 1);
+
+    delete canvas;
+}
+
 QTEST_MAIN(tst_qsgitem)
 
 #include "tst_qsgitem.moc"