diff --git a/src/quick/items/qquickdrag_p.h b/src/quick/items/qquickdrag_p.h index 611ed5df8f..806dbc7602 100644 --- a/src/quick/items/qquickdrag_p.h +++ b/src/quick/items/qquickdrag_p.h @@ -72,9 +72,12 @@ public: void grab(QQuickItem *item) { m_items.insert(new Item(item)); } iterator release(iterator at) { Item *item = *at; at = at.erase(); delete item; return at; } + auto& ignoreList() { return m_ignoreDragItems; } + private: ItemList m_items; + QVarLengthArray m_ignoreDragItems; QObject *m_target; }; diff --git a/src/quick/util/qquickdeliveryagent.cpp b/src/quick/util/qquickdeliveryagent.cpp index a3af6cf4ef..9aecb6d296 100644 --- a/src/quick/util/qquickdeliveryagent.cpp +++ b/src/quick/util/qquickdeliveryagent.cpp @@ -2231,6 +2231,7 @@ void QQuickDeliveryAgentPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QE QDragLeaveEvent leaveEvent; for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem)) QCoreApplication::sendEvent(**grabItem, &leaveEvent); + grabber->ignoreList().clear(); return; } else { QDragMoveEvent *moveEvent = static_cast(event); @@ -2288,6 +2289,8 @@ void QQuickDeliveryAgentPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QE e->modifiers()); QQuickDropEventEx::copyActions(&enterEvent, *e); event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent)); + } else { + grabber->ignoreList().clear(); } } @@ -2301,8 +2304,13 @@ bool QQuickDeliveryAgentPrivate::deliverDragEvent( QPointF p = item->mapFromScene(event->position().toPoint()); bool itemContained = item->contains(p); - if (!itemContained && itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) { - return false; + const int itemIndex = grabber->ignoreList().indexOf(item); + if (!itemContained) { + if (itemIndex >= 0) + grabber->ignoreList().remove(itemIndex); + + if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) + return false; } QDragEnterEvent enterEvent( @@ -2332,15 +2340,19 @@ bool QQuickDeliveryAgentPrivate::deliverDragEvent( } if (event->type() == QEvent::DragMove || itemPrivate->flags & QQuickItem::ItemAcceptsDrops) { - if (event->type() == QEvent::DragEnter && formerTarget) { - QQuickItem *formerTargetItem = qobject_cast(formerTarget); - if (formerTargetItem && currentGrabItems) { - QDragLeaveEvent leaveEvent; - QCoreApplication::sendEvent(formerTarget, &leaveEvent); + if (event->type() == QEvent::DragEnter) { + if (formerTarget) { + QQuickItem *formerTargetItem = qobject_cast(formerTarget); + if (formerTargetItem && currentGrabItems) { + QDragLeaveEvent leaveEvent; + QCoreApplication::sendEvent(formerTarget, &leaveEvent); - // Remove the item from the currentGrabItems so a leave event won't be generated - // later on - currentGrabItems->removeAll(formerTarget); + // Remove the item from the currentGrabItems so a leave event won't be generated + // later on + currentGrabItems->removeAll(formerTarget); + } + } else if (itemIndex >= 0) { + return false; } } @@ -2356,6 +2368,8 @@ bool QQuickDeliveryAgentPrivate::deliverDragEvent( grabber->grab(item); grabber->setTarget(item); return true; + } else if (itemIndex < 0) { + grabber->ignoreList().append(item); } } else { return true; diff --git a/tests/auto/quick/qquickdroparea/data/ignoreRetriggerEvent.qml b/tests/auto/quick/qquickdroparea/data/ignoreRetriggerEvent.qml new file mode 100644 index 0000000000..af25a04ee7 --- /dev/null +++ b/tests/auto/quick/qquickdroparea/data/ignoreRetriggerEvent.qml @@ -0,0 +1,15 @@ +import QtQuick 2.0 + +DropArea { + property int enterEvents: 0 + property int exitEvents: 0 + width: 100; height: 100 + objectName: "dropArea" + onEntered: function (drag) { ++enterEvents; drag.accepted = false } + onExited: {++exitEvents} + Item { + objectName: "dragItem" + x: 50; y: 50 + width: 10; height: 10 + } +} diff --git a/tests/auto/quick/qquickdroparea/tst_qquickdroparea.cpp b/tests/auto/quick/qquickdroparea/tst_qquickdroparea.cpp index 7d01207e58..fb036b6fad 100644 --- a/tests/auto/quick/qquickdroparea/tst_qquickdroparea.cpp +++ b/tests/auto/quick/qquickdroparea/tst_qquickdroparea.cpp @@ -45,6 +45,9 @@ public: private slots: void containsDrag_internal(); void containsDrag_external(); + + void ignoreRetriggerEvent(); + void keys_internal(); void keys_external(); void source_internal(); @@ -807,6 +810,32 @@ void tst_QQuickDropArea::competingDrags() QCOMPARE(evaluate(dropArea1, "statuslol"), QStringLiteral("parent")); } +void tst_QQuickDropArea::ignoreRetriggerEvent() +{ + QQuickView window; + QByteArray errorMessage; + QVERIFY2(QQuickTest::initView(window, testFileUrl("ignoreRetriggerEvent.qml"), true, &errorMessage), errorMessage.constData()); + + QQuickItem *dropArea = window.rootObject(); + QVERIFY(dropArea); + QQuickItem *dragItem = dropArea->findChild("dragItem"); + QVERIFY(dragItem); + + evaluate(dragItem, "Drag.active = true"); + // Drag the item within the drop area + dragItem->setPosition(QPointF(25, 25)); + QCoreApplication::processEvents(); + dragItem->setPosition(QPointF(50, 50)); + QCoreApplication::processEvents(); + dragItem->setPosition(QPointF(75, 75)); + QCoreApplication::processEvents(); + + QCOMPARE(evaluate(dropArea, "containsDrag"), false); + QCOMPARE(evaluate(dropArea, "enterEvents"), 1); + QCOMPARE(evaluate(dropArea, "exitEvents"), 0); +} + + void tst_QQuickDropArea::simultaneousDrags() { QQuickWindow window;