QListWidget/View: Update the selection when moving items within the view

The code for doing that existed in the QListWidget::dropEvent override,
and was only using standard itemview APIs to adjust the selection model.
There is no reason why dropping items internally in a QListView
should not do the exact same thing.

As part of moving the code from QListWidget to QListView, replace QList
with QVector, and other minor optimizations.

[ChangeLog][QtWidgets][QListView] Moving selected items within a list
view by drag'n'drop will maintain the selection of those items.

Change-Id: Ie24bec38234839dcb2f0b0ee0302cc59ca101631
Fixes: QTBUG-83084
Pick-to: 5.15
Reviewed-by: Jan Arve Sæther <jan-arve.saether@qt.io>
This commit is contained in:
Volker Hilsheimer 2020-04-22 18:55:13 +02:00
parent 20cdf807b1
commit fd894fd68e
2 changed files with 45 additions and 42 deletions

View File

@ -909,10 +909,50 @@ void QListView::dragLeaveEvent(QDragLeaveEvent *e)
/*!
\reimp
*/
void QListView::dropEvent(QDropEvent *e)
void QListView::dropEvent(QDropEvent *event)
{
if (!d_func()->commonListView->filterDropEvent(e))
QAbstractItemView::dropEvent(e);
Q_D(QListView);
if (event->source() == this && (event->dropAction() == Qt::MoveAction ||
dragDropMode() == QAbstractItemView::InternalMove)) {
QModelIndex topIndex;
bool topIndexDropped = false;
int col = -1;
int row = -1;
if (d->dropOn(event, &row, &col, &topIndex)) {
const QVector<QModelIndex> selIndexes = selectedIndexes();
QVector<QPersistentModelIndex> persIndexes;
persIndexes.reserve(selIndexes.count());
for (const auto &index : selIndexes) {
persIndexes.append(index);
if (index == topIndex) {
topIndexDropped = true;
break;
}
}
if (!topIndexDropped) {
std::sort(persIndexes.begin(), persIndexes.end()); // The dropped items will remain in the same visual order.
QPersistentModelIndex dropRow = model()->index(row, col, topIndex);
int r = row == -1 ? model()->rowCount() : (dropRow.row() >= 0 ? dropRow.row() : row);
for (int i = 0; i < persIndexes.count(); ++i) {
const QPersistentModelIndex &pIndex = persIndexes.at(i);
model()->moveRow(QModelIndex(), pIndex.row(), QModelIndex(), r);
r = pIndex.row() + 1; // Dropped items are inserted contiguously and in the right order.
}
event->accept();
// Don't want QAbstractItemView to delete it because it was "moved" we already did it
event->setDropAction(Qt::CopyAction);
}
}
}
if (!d->commonListView->filterDropEvent(event))
QAbstractItemView::dropEvent(event);
}
/*!

View File

@ -1875,45 +1875,8 @@ bool QListWidget::dropMimeData(int index, const QMimeData *data, Qt::DropAction
}
/*! \reimp */
void QListWidget::dropEvent(QDropEvent *event) {
Q_D(QListWidget);
if (event->source() == this && d->movement != Static) {
QListView::dropEvent(event);
return;
}
if (event->source() == this && (event->dropAction() == Qt::MoveAction ||
dragDropMode() == QAbstractItemView::InternalMove)) {
QModelIndex topIndex;
int col = -1;
int row = -1;
if (d->dropOn(event, &row, &col, &topIndex)) {
QList<QModelIndex> selIndexes = selectedIndexes();
QList<QPersistentModelIndex> persIndexes;
const int selIndexesCount = selIndexes.count();
persIndexes.reserve(selIndexesCount);
for (int i = 0; i < selIndexesCount; i++)
persIndexes.append(selIndexes.at(i));
if (persIndexes.contains(topIndex))
return;
std::sort(persIndexes.begin(), persIndexes.end()); // The dropped items will remain in the same visual order.
QPersistentModelIndex dropRow = model()->index(row, col, topIndex);
int r = row == -1 ? count() : (dropRow.row() >= 0 ? dropRow.row() : row);
for (int i = 0; i < persIndexes.count(); ++i) {
const QPersistentModelIndex &pIndex = persIndexes.at(i);
d->listModel()->move(pIndex.row(), r);
r = pIndex.row() + 1; // Dropped items are inserted contiguously and in the right order.
}
event->accept();
// Don't want QAbstractItemView to delete it because it was "moved" we already did it
event->setDropAction(Qt::CopyAction);
}
}
void QListWidget::dropEvent(QDropEvent *event)
{
QListView::dropEvent(event);
}