diff options
author | Gabriel de Dietrich <gabriel.dietrich-de@nokia.com> | 2009-10-23 07:14:39 (GMT) |
---|---|---|
committer | Gabriel de Dietrich <gabriel.dietrich-de@nokia.com> | 2009-10-26 09:24:57 (GMT) |
commit | 319482a6b33ce1bd365457054aca49a51d885e07 (patch) | |
tree | 84f80d837f8628f6f88bc7cb2f4228970d72b630 | |
parent | b14338cce8cb13003a4943d134502e085f36ab08 (diff) | |
download | Qt-319482a6b33ce1bd365457054aca49a51d885e07.zip Qt-319482a6b33ce1bd365457054aca49a51d885e07.tar.gz Qt-319482a6b33ce1bd365457054aca49a51d885e07.tar.bz2 |
Drag and drop in QListWidget would not preserve the selection
Now, when dropping items, these will remain selected, and in the same visual
order as when dragged.
Auto-test included for the items moving part. For the rest, it's a
drag-and-drop thing.
Reviewed-by: Olivier
-rw-r--r-- | src/gui/itemviews/qlistwidget.cpp | 31 | ||||
-rw-r--r-- | src/gui/itemviews/qlistwidget_p.h | 3 | ||||
-rw-r--r-- | tests/auto/qlistwidget/tst_qlistwidget.cpp | 59 |
3 files changed, 80 insertions, 13 deletions
diff --git a/src/gui/itemviews/qlistwidget.cpp b/src/gui/itemviews/qlistwidget.cpp index a978d0f..5dd1d76 100644 --- a/src/gui/itemviews/qlistwidget.cpp +++ b/src/gui/itemviews/qlistwidget.cpp @@ -169,6 +169,20 @@ QListWidgetItem *QListModel::take(int row) return item; } +void QListModel::move(int srcRow, int dstRow) +{ + if (srcRow == dstRow + || srcRow < 0 || srcRow >= items.count() + || dstRow < 0 || dstRow >= items.count()) + return; + + beginMoveRows(QModelIndex(), srcRow, srcRow, QModelIndex(), dstRow); + if (srcRow < dstRow) + --dstRow; + items.move(srcRow, dstRow); + endMoveRows(); +} + int QListModel::rowCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : items.count(); @@ -1804,22 +1818,15 @@ void QListWidget::dropEvent(QDropEvent *event) { if (persIndexes.contains(topIndex)) return; + qSort(persIndexes); // The dropped items will remain in the same visual order. QPersistentModelIndex dropRow = model()->index(row, col, topIndex); - QList<QListWidgetItem *> taken; - for (int i = 0; i < persIndexes.count(); ++i) - taken.append(takeItem(persIndexes.at(i).row())); - - // insert them back in at their new positions + int r = row == -1 ? count() : (dropRow.row() >= 0 ? dropRow.row() : row); for (int i = 0; i < persIndexes.count(); ++i) { - // Either at a specific point or appended - if (row == -1) { - insertItem(count(), taken.takeFirst()); - } else { - int r = dropRow.row() >= 0 ? dropRow.row() : row; - insertItem(qMin(r, count()), taken.takeFirst()); - } + 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(); diff --git a/src/gui/itemviews/qlistwidget_p.h b/src/gui/itemviews/qlistwidget_p.h index 69cfa26..b5f28e3 100644 --- a/src/gui/itemviews/qlistwidget_p.h +++ b/src/gui/itemviews/qlistwidget_p.h @@ -77,7 +77,7 @@ public: { return *i2 < *i1; } }; -class QListModel : public QAbstractListModel +class Q_AUTOTEST_EXPORT QListModel : public QAbstractListModel { Q_OBJECT public: @@ -90,6 +90,7 @@ public: void insert(int row, const QStringList &items); void remove(QListWidgetItem *item); QListWidgetItem *take(int row); + void move(int srcRow, int dstRow); int rowCount(const QModelIndex &parent = QModelIndex()) const; diff --git a/tests/auto/qlistwidget/tst_qlistwidget.cpp b/tests/auto/qlistwidget/tst_qlistwidget.cpp index e825c8f..5c6ed54 100644 --- a/tests/auto/qlistwidget/tst_qlistwidget.cpp +++ b/tests/auto/qlistwidget/tst_qlistwidget.cpp @@ -46,6 +46,7 @@ #include <qlist.h> #include <qlistwidget.h> +#include <private/qlistwidget_p.h> //TESTED_CLASS= //TESTED_FILES= @@ -95,6 +96,8 @@ private slots: void insertItem(); void insertItems_data(); void insertItems(); + void moveItemsPriv_data(); + void moveItemsPriv(); void itemAssignment(); void item_data(); @@ -849,6 +852,62 @@ void tst_QListWidget::removeItems() } +void tst_QListWidget::moveItemsPriv_data() +{ + QTest::addColumn<int>("rowCount"); + QTest::addColumn<int>("srcRow"); + QTest::addColumn<int>("dstRow"); + QTest::addColumn<bool>("shouldHaveSignaled"); + + QTest::newRow("Empty") << 0 << 0 << 0 << false; + QTest::newRow("Overflow src") << 5 << 5 << 2 << false; + QTest::newRow("Underflow src") << 5 << -1 << 2 << false; + QTest::newRow("Overflow dst") << 5 << 2 << 5 << false; + QTest::newRow("Underflow dst") << 5 << 2 << -1 << false; + QTest::newRow("Same place") << 5 << 2 << 2 << false; + QTest::newRow("Up") << 5 << 4 << 2 << true; + QTest::newRow("Down") << 5 << 2 << 4 << true; +} + +void tst_QListWidget::moveItemsPriv() +{ + QFETCH(int, rowCount); + QFETCH(int, srcRow); + QFETCH(int, dstRow); + QFETCH(bool, shouldHaveSignaled); + + for (int r = 0; r < rowCount; ++r) + new QListWidgetItem(QString::number(r), testWidget); + + QListModel *model = dynamic_cast<QListModel *>(testWidget->model()); + QVERIFY(model); + QSignalSpy beginMoveSpy(model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))); + QSignalSpy movedSpy(model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int))); + model->move(srcRow, dstRow); + + if (shouldHaveSignaled) { + if (srcRow < dstRow) + QCOMPARE(testWidget->item(dstRow - 1)->text(), QString::number(srcRow)); + else + QCOMPARE(testWidget->item(dstRow)->text(), QString::number(srcRow)); + + QCOMPARE(beginMoveSpy.count(), 1); + const QList<QVariant> &beginMoveArgs = beginMoveSpy.takeFirst(); + QCOMPARE(beginMoveArgs.at(1).toInt(), srcRow); + QCOMPARE(beginMoveArgs.at(2).toInt(), srcRow); + QCOMPARE(beginMoveArgs.at(4).toInt(), dstRow); + + QCOMPARE(movedSpy.count(), 1); + const QList<QVariant> &movedArgs = movedSpy.takeFirst(); + QCOMPARE(movedArgs.at(1).toInt(), srcRow); + QCOMPARE(movedArgs.at(2).toInt(), srcRow); + QCOMPARE(movedArgs.at(4).toInt(), dstRow); + } else { + QCOMPARE(beginMoveSpy.count(), 0); + QCOMPARE(movedSpy.count(), 0); + } +} + void tst_QListWidget::itemStreaming_data() { QTest::addColumn<QString>("text"); |