Implement QStringListModel::moveRows

Implemented the virtual method moveRows to allow row movement

[ChangeLog][QtCore][QStringListModel] Implemented moveRows

Task-number: QTBUG-69807
Change-Id: I518f48a321bd755ab56f2fe84883d27324cc42ec
Reviewed-by: David Faure <david.faure@kdab.com>
bb10
Luca Beldi 2018-08-22 16:42:45 +01:00
parent c1b15005c6
commit da9aeb3e4e
3 changed files with 138 additions and 0 deletions

View File

@ -249,6 +249,38 @@ bool QStringListModel::removeRows(int row, int count, const QModelIndex &parent)
return true;
}
/*!
\since 5.13
\reimp
*/
bool QStringListModel::moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild)
{
if (sourceRow < 0
|| sourceRow + count - 1 >= rowCount(sourceParent)
|| destinationChild <= 0
|| destinationChild > rowCount(destinationParent)
|| sourceRow == destinationChild - 1
|| count <= 0) {
return false;
}
if (!beginMoveRows(QModelIndex(), sourceRow, sourceRow + count - 1, QModelIndex(), destinationChild))
return false;
/*
QList::move assumes that the second argument is the index where the item will end up to
i.e. the valid range for that argument is from 0 to QList::size()-1
QAbstractItemModel::moveRows when source and destinations have the same parent assumes that
the item will end up being in the row BEFORE the one indicated by destinationChild
i.e. the valid range for that argument is from 1 to QList::size()
For this reason we remove 1 from destinationChild when using it inside QList
*/
destinationChild--;
const int fromRow = destinationChild < sourceRow ? (sourceRow + count - 1) : sourceRow;
while (count--)
lst.move(fromRow, destinationChild);
endMoveRows();
return true;
}
static bool ascendingLessThan(const QPair<QString, int> &s1, const QPair<QString, int> &s2)
{
return s1.first < s2.first;

View File

@ -64,6 +64,7 @@ public:
bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;
bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;
bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild) override;
void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override;

View File

@ -82,8 +82,113 @@ private slots:
void setData_emits_both_roles();
void supportedDragDropActions();
void moveRows();
void moveRows_data();
void moveRowsInvalid_data();
void moveRowsInvalid();
};
void tst_QStringListModel::moveRowsInvalid_data()
{
QTest::addColumn<QStringListModel*>("baseModel");
QTest::addColumn<QModelIndex>("startParent");
QTest::addColumn<int>("startRow");
QTest::addColumn<int>("count");
QTest::addColumn<QModelIndex>("destinationParent");
QTest::addColumn<int>("destination");
QStringListModel* tempModel = new QStringListModel(QStringList{"A", "B", "C", "D", "E", "F"}, this);
QTest::addRow("destination_equal_source") << tempModel << QModelIndex() << 0 << 1 << QModelIndex() << 1;
tempModel = new QStringListModel(QStringList{"A", "B", "C", "D", "E", "F"}, this);
QTest::addRow("count_equal_0") << tempModel << QModelIndex() << 0 << 0 << QModelIndex() << 2;
tempModel = new QStringListModel(QStringList{"A", "B", "C", "D", "E", "F"}, this);
QTest::addRow("move_child") << tempModel << tempModel->index(0, 0) << 0 << 1 << QModelIndex() << 2;
tempModel = new QStringListModel(QStringList{"A", "B", "C", "D", "E", "F"}, this);
QTest::addRow("move_to_child") << tempModel << QModelIndex() << 0 << 1 << tempModel->index(0, 0) << 2;
tempModel = new QStringListModel(QStringList{"A", "B", "C", "D", "E", "F"}, this);
QTest::addRow("negative_count") << tempModel << QModelIndex() << 0 << -1 << QModelIndex() << 2;
tempModel = new QStringListModel(QStringList{"A", "B", "C", "D", "E", "F"}, this);
QTest::addRow("negative_source_row") << tempModel << QModelIndex() << -1 << 1 << QModelIndex() << 2;
tempModel = new QStringListModel(QStringList{"A", "B", "C", "D", "E", "F"}, this);
QTest::addRow("negative_destination_row") << tempModel << QModelIndex() << 0 << 1 << QModelIndex() << -1;
tempModel = new QStringListModel(QStringList{"A", "B", "C", "D", "E", "F"}, this);
QTest::addRow("source_row_equal_rowCount") << tempModel << QModelIndex() << tempModel->rowCount() << 1 << QModelIndex() << 1;
tempModel = new QStringListModel(QStringList{"A", "B", "C", "D", "E", "F"}, this);
QTest::addRow("destination_row_greather_rowCount") << tempModel << QModelIndex() << 0 << 1 << QModelIndex() << tempModel->rowCount() + 1;
tempModel = new QStringListModel(QStringList{"A", "B", "C", "D", "E", "F"}, this);
QTest::addRow("move_row_within_source_range") << tempModel << QModelIndex() << 0 << 3 << QModelIndex() << 2;
tempModel = new QStringListModel(QStringList{"A", "B", "C", "D", "E", "F"}, this);
QTest::addRow("destrination_row_before_0") << tempModel << QModelIndex() << 1 << 1 << QModelIndex() << 0;
}
void tst_QStringListModel::moveRowsInvalid()
{
QFETCH(QStringListModel* const, baseModel);
QFETCH(const QModelIndex, startParent);
QFETCH(const int, startRow);
QFETCH(const int, count);
QFETCH(const QModelIndex, destinationParent);
QFETCH(const int, destination);
QSignalSpy rowMovedSpy(baseModel, &QAbstractItemModel::rowsMoved);
QSignalSpy rowAboutMovedSpy(baseModel, &QAbstractItemModel::rowsAboutToBeMoved);
QVERIFY(rowMovedSpy.isValid());
QVERIFY(rowAboutMovedSpy.isValid());
QVERIFY(!baseModel->moveRows(startParent, startRow, count, destinationParent, destination));
QCOMPARE(rowMovedSpy.size(), 0);
QCOMPARE(rowAboutMovedSpy.size(), 0);
delete baseModel;
}
void tst_QStringListModel::moveRows_data()
{
QTest::addColumn<int>("startRow");
QTest::addColumn<int>("count");
QTest::addColumn<int>("destination");
QTest::addColumn<QStringList>("expected");
QTest::newRow("1_Item_from_top_to_middle") << 0 << 1 << 3 << QStringList{"B", "C", "A", "D", "E", "F"};
QTest::newRow("1_Item_from_top_to_bottom") << 0 << 1 << 6 << QStringList{"B", "C", "D", "E", "F", "A"};
QTest::newRow("1_Item_from_middle_to_top") << 2 << 1 << 1 << QStringList{"C", "A", "B", "D", "E", "F"};
QTest::newRow("1_Item_from_bottom_to_middle") << 5 << 1 << 3 << QStringList{"A", "B", "F", "C", "D", "E"};
QTest::newRow("1_Item_from_bottom to_top") << 5 << 1 << 1 << QStringList{"F", "A", "B", "C", "D", "E"};
QTest::newRow("1_Item_from_middle_to_bottom") << 2 << 1 << 6 << QStringList{"A", "B", "D", "E", "F", "C"};
QTest::newRow("1_Item_from_middle_to_middle before") << 2 << 1 << 1 << QStringList{"C", "A", "B", "D", "E", "F"};
QTest::newRow("1_Item_from_middle_to_middle after") << 2 << 1 << 4 << QStringList{"A", "B", "D", "C", "E", "F"};
QTest::newRow("2_Items_from_top_to_middle") << 0 << 2 << 3 << QStringList{"C", "A", "B", "D", "E", "F"};
QTest::newRow("2_Items_from_top_to_bottom") << 0 << 2 << 6 << QStringList{"C", "D", "E", "F", "A", "B"};
QTest::newRow("2_Items_from_middle_to_top") << 2 << 2 << 1 << QStringList{"C", "D", "A", "B", "E", "F"};
QTest::newRow("2_Items_from_bottom_to_middle") << 4 << 2 << 3 << QStringList{"A", "B", "E", "F", "C", "D"};
QTest::newRow("2_Items_from_bottom_to_top") << 4 << 2 << 1 << QStringList{"E", "F", "A", "B", "C", "D"};
QTest::newRow("2_Items_from_middle_to_bottom") << 2 << 2 << 6 << QStringList{"A", "B", "E", "F", "C", "D"};
QTest::newRow("2_Items_from_middle_to_middle before") << 3 << 2 << 2 << QStringList{"A", "D", "E", "B", "C", "F"};
QTest::newRow("2_Items_from_middle_to_middle after") << 1 << 2 << 5 << QStringList{"A", "D", "E", "B", "C", "F"};
}
void tst_QStringListModel::moveRows()
{
QFETCH(const int, startRow);
QFETCH(const int, count);
QFETCH(const int, destination);
QFETCH(const QStringList, expected);
QStringListModel baseModel(QStringList{"A", "B", "C", "D", "E", "F"});
QSignalSpy rowMovedSpy(&baseModel, &QAbstractItemModel::rowsMoved);
QSignalSpy rowAboutMovedSpy(&baseModel, &QAbstractItemModel::rowsAboutToBeMoved);
QVERIFY(baseModel.moveRows(QModelIndex(), startRow, count, QModelIndex(), destination));
QCOMPARE(baseModel.stringList(), expected);
QCOMPARE(rowMovedSpy.size(), 1);
QCOMPARE(rowAboutMovedSpy.size(), 1);
for (const QList<QVariant> &signalArgs : {rowMovedSpy.takeFirst(), rowAboutMovedSpy.takeFirst()}){
QVERIFY(!signalArgs.at(0).value<QModelIndex>().isValid());
QCOMPARE(signalArgs.at(1).toInt(), startRow);
QCOMPARE(signalArgs.at(2).toInt(), startRow + count - 1);
QVERIFY(!signalArgs.at(3).value<QModelIndex>().isValid());
QCOMPARE(signalArgs.at(4).toInt(), destination);
}
}
void tst_QStringListModel::rowsAboutToBeRemoved_rowsRemoved_data()
{
QTest::addColumn<QStringList>("input");