QListView: do not delete item on internal move

When an internal DnD occoures in IconMode, the item is moved to it's new
place but the logic in filterStartDrag() has no clue about the fact that
an internal move happend. Therefore the item gets deleted. Fix it by
changing the event's drop action to Qt::CopyAction to avoid the deletion
as it is done within QListWidget DnD code.

[ChangeLog][QtWidgets][QListView] Do not delete item on internal move.

Task-number: QTBUG-67440
Change-Id: I873d3c9fa76e107e108d9af0dcf8cecd1e18a18f
Reviewed-by: Thorbjørn Lund Martsum <tmartsum@gmail.com>
bb10
Christian Ehrlicher 2018-04-07 08:59:06 +02:00
parent 1acdcdaa4d
commit c699daeceb
2 changed files with 53 additions and 0 deletions

View File

@ -2815,6 +2815,8 @@ bool QIconModeViewBase::filterStartDrag(Qt::DropActions supportedActions)
drag->setHotSpot(dd->pressedPosition - rect.topLeft());
Qt::DropAction action = drag->exec(supportedActions, dd->defaultDropAction);
draggedItems.clear();
// for internal moves the action was set to Qt::CopyAction in
// filterDropEvent() to avoid the deletion here
if (action == Qt::MoveAction)
dd->clearOrRemove();
}
@ -2851,6 +2853,8 @@ bool QIconModeViewBase::filterDropEvent(QDropEvent *e)
dd->stopAutoScroll();
draggedItems.clear();
dd->emitIndexesMoved(indexes);
// do not delete item on internal move, see filterStartDrag()
e->setDropAction(Qt::CopyAction);
e->accept(); // we have handled the event
// if the size has not grown, we need to check if it has shrinked
if (contentsSize != contents) {

View File

@ -150,6 +150,7 @@ private slots:
void taskQTBUG_51086_skippingIndexesInSelectedIndexes();
void taskQTBUG_47694_indexOutOfBoundBatchLayout();
void itemAlignment();
void internalDragDropMove();
};
// Testing get/set functions
@ -2577,5 +2578,53 @@ void tst_QListView::itemAlignment()
QVERIFY(w.visualRect(item1->index()).width() < w.visualRect(item2->index()).width());
}
void tst_QListView::internalDragDropMove()
{
const QString platform(QGuiApplication::platformName().toLower());
if (platform != QLatin1String("xcb"))
QSKIP("Need a window system with proper DnD support via injected mouse events");
// on an internal move, the item was deleted which should not happen
// see QTBUG-67440
class QListViewWithPublicStartDrag : public QListView
{
public:
using QListView::startDrag;
};
QStandardItemModel data(0, 1);
QPixmap pixmap(32, 32);
for (int i = 0; i < 10; ++i) {
pixmap.fill(Qt::GlobalColor(i + 1));
data.appendRow(new QStandardItem(QIcon(pixmap), QString::number(i)));
}
QItemSelectionModel selections(&data);
QListViewWithPublicStartDrag list;
list.setWindowTitle(QTest::currentTestFunction());
list.setViewMode(QListView::IconMode);
list.setDefaultDropAction(Qt::MoveAction);
list.setModel(&data);
list.setSelectionModel(&selections);
list.resize(300, 300);
list.show();
selections.select(data.index(1, 0), QItemSelectionModel::Select);
QVERIFY(QTest::qWaitForWindowExposed(&list));
// execute as soon as the eventloop is running again
// which is the case inside list.startDrag()
QTimer::singleShot(0, [&list]()
{
const QPoint pos = list.rect().center();
QMouseEvent mouseMove(QEvent::MouseMove, pos, list.mapToGlobal(pos), Qt::NoButton, 0, 0);
QApplication::sendEvent(&list, &mouseMove);
QMouseEvent mouseRelease(QEvent::MouseButtonRelease, pos, list.mapToGlobal(pos), Qt::LeftButton, 0, 0);
QApplication::sendEvent(&list, &mouseRelease);
});
const int expectedCount = data.rowCount();
list.startDrag(Qt::MoveAction|Qt::CopyAction);
QCOMPARE(expectedCount, data.rowCount());
}
QTEST_MAIN(tst_QListView)
#include "tst_qlistview.moc"