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
parent
1acdcdaa4d
commit
c699daeceb
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Reference in New Issue