QTableView: implement moving rows by drag-n-drop
This is only available when calling setDragDropOverwriteMode(false) so this makes no difference in most applications (see implementation of QAbstractItemView::position). QTableWidget::dropEvent() was assuming we were dropping onto items without checking that this was the case, this is fixed here, and QTableView::dropEvent() is added to handle moving rows, with very similar code to QListView::dropEvent(). Task-number: QTBUG-13873 Task-number: QTBUG-101475 Change-Id: I96e75da2c0abf6f568edba461735905dee5cb84f Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io> (cherry picked from commit 8e63cf282cb248ddd7fbc908766091659b3a0b22) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>bb10
parent
679ae93507
commit
a9e464119a
|
|
@ -3115,6 +3115,68 @@ void QTableView::timerEvent(QTimerEvent *event)
|
|||
QAbstractItemView::timerEvent(event);
|
||||
}
|
||||
|
||||
#if QT_CONFIG(draganddrop)
|
||||
/*! \reimp */
|
||||
void QTableView::dropEvent(QDropEvent *event)
|
||||
{
|
||||
Q_D(QTableView);
|
||||
if (event->source() == this && (event->dropAction() == Qt::MoveAction ||
|
||||
dragDropMode() == QAbstractItemView::InternalMove)) {
|
||||
QModelIndex topIndex;
|
||||
int col = -1;
|
||||
int row = -1;
|
||||
// check whether a subclass has already accepted the event, ie. moved the data
|
||||
if (!event->isAccepted() && d->dropOn(event, &row, &col, &topIndex) && !topIndex.isValid() && col != -1) {
|
||||
// Drop between items (reordering) - can only happen with setDragDropOverwriteMode(false)
|
||||
const QModelIndexList indexes = selectedIndexes();
|
||||
QList<QPersistentModelIndex> persIndexes;
|
||||
persIndexes.reserve(indexes.size());
|
||||
|
||||
bool topIndexDropped = false;
|
||||
for (const auto &index : indexes) {
|
||||
// Reorder entire rows
|
||||
QPersistentModelIndex firstColIndex = index.siblingAtColumn(0);
|
||||
if (!persIndexes.contains(firstColIndex))
|
||||
persIndexes.append(firstColIndex);
|
||||
if (index.row() == topIndex.row()) {
|
||||
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);
|
||||
bool dataMoved = false;
|
||||
for (int i = 0; i < persIndexes.size(); ++i) {
|
||||
const QPersistentModelIndex &pIndex = persIndexes.at(i);
|
||||
// only generate a move when not same row or behind itself
|
||||
if (r != pIndex.row() && r != pIndex.row() + 1) {
|
||||
// try to move (preserves selection)
|
||||
dataMoved |= model()->moveRow(QModelIndex(), pIndex.row(), QModelIndex(), r);
|
||||
if (!dataMoved) // can't move - abort and let QAbstractItemView handle this
|
||||
break;
|
||||
} else {
|
||||
// move onto itself is blocked, don't delete anything
|
||||
dataMoved = true;
|
||||
}
|
||||
r = pIndex.row() + 1; // Dropped items are inserted contiguously and in the right order.
|
||||
}
|
||||
if (dataMoved)
|
||||
event->accept();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!event->isAccepted()) {
|
||||
// moveRows not implemented, fall back to default
|
||||
QAbstractItemView::dropEvent(event);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
This slot is called to change the index of the given \a row in the
|
||||
table view. The old index is specified by \a oldIndex, and the new
|
||||
|
|
|
|||
|
|
@ -114,6 +114,10 @@ protected:
|
|||
|
||||
void timerEvent(QTimerEvent *event) override;
|
||||
|
||||
#if QT_CONFIG(draganddrop)
|
||||
void dropEvent(QDropEvent *event) override;
|
||||
#endif
|
||||
|
||||
int horizontalOffset() const override;
|
||||
int verticalOffset() const override;
|
||||
QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) override;
|
||||
|
|
|
|||
|
|
@ -2722,7 +2722,8 @@ void QTableWidget::dropEvent(QDropEvent *event) {
|
|||
int col = -1;
|
||||
int row = -1;
|
||||
// check whether a subclass has already accepted the event, ie. moved the data
|
||||
if (!event->isAccepted() && d->dropOn(event, &row, &col, &topIndex)) {
|
||||
if (!event->isAccepted() && d->dropOn(event, &row, &col, &topIndex) && row == -1 && col == -1) {
|
||||
// Drop onto item
|
||||
const QModelIndexList indexes = selectedIndexes();
|
||||
int top = INT_MAX;
|
||||
int left = INT_MAX;
|
||||
|
|
@ -2730,7 +2731,6 @@ void QTableWidget::dropEvent(QDropEvent *event) {
|
|||
top = qMin(index.row(), top);
|
||||
left = qMin(index.column(), left);
|
||||
}
|
||||
|
||||
QList<QTableWidgetItem *> taken;
|
||||
const int indexesCount = indexes.size();
|
||||
taken.reserve(indexesCount);
|
||||
|
|
@ -2745,7 +2745,7 @@ void QTableWidget::dropEvent(QDropEvent *event) {
|
|||
|
||||
event->accept();
|
||||
}
|
||||
// either we or a subclass accepted the move event, so assume that the data was
|
||||
// either we or a subclass accepted the drop event, so assume that the data was
|
||||
// moved and that QAbstractItemView shouldn't remove the source when QDrag::exec returns
|
||||
if (event->isAccepted())
|
||||
d->dropEventMoved = true;
|
||||
|
|
|
|||
Loading…
Reference in New Issue