summaryrefslogtreecommitdiffstats
path: root/tests/auto/widgets/itemviews
diff options
context:
space:
mode:
authorWladimir Leuschner <wladimir.leuschner@qt.io>2023-04-28 14:10:05 +0300
committerWladimir Leuschner <wladimir.leuschner@qt.io>2023-09-26 16:45:11 +0000
commitcf6bccbcf50340c75dfcc13117137b173a5c00be (patch)
tree4b8007ea9c197fa4c3126a4c8e568833062b816a /tests/auto/widgets/itemviews
parent5863568c53fd993de3dd83301f07ef6c2dce48f5 (diff)
Ensure stable sort in QListWidget
QlistWidgets with sorting enabled do not sort stable. A re-sort is triggered when any Qt::ItemDataRole is changed and not only when Qt::DisplayRole is changed. Due to an unstable optimization, the changed element gets inserted at the beginning of their respective "equivalence group". This patch disables the optimization and ensures stable sorting with std::stable_sort. Sorting is only performed, if the subset of changed items in the range [begin, end] is not already sorted in the whole list. For this purpose, it is assumed that the list has already been sorted before begin and after end. This assumption minimizes the subset to check. Limits / side effect: The patch focuses on the most common use case, which is a single item being changed. Replacing the optimization by std:stable_sort can potentially slow down the sorting performance of large data sets. Task-number: QTBUG-113123 Pick-to: 6.5 6.6 Change-Id: Ib2bd08f21422eb7d6aeff7cdd6a91be7114ebcba Reviewed-by: Axel Spoerl <axel.spoerl@qt.io>
Diffstat (limited to 'tests/auto/widgets/itemviews')
-rw-r--r--tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp60
1 files changed, 60 insertions, 0 deletions
diff --git a/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp b/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp
index 07973d7225..f017e0e06b 100644
--- a/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp
+++ b/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp
@@ -75,6 +75,8 @@ private slots:
void sortItems();
void sortHiddenItems();
void sortHiddenItems_data();
+ void sortCheckStability_data();
+ void sortCheckStability();
void closeEditor();
void setData_data();
void setData();
@@ -1131,6 +1133,64 @@ void tst_QListWidget::sortHiddenItems()
delete tw;
}
+void tst_QListWidget::sortCheckStability_data() {
+ QTest::addColumn<Qt::SortOrder>("order");
+ QTest::addColumn<QVariantList>("initialList");
+ QTest::addColumn<QVariantList>("expectedList");
+
+ QTest::newRow("ascending strings")
+ << Qt::AscendingOrder
+ << QVariantList{ QString("a"), QString("b"), QString("b"), QString("a")}
+ << QVariantList{ QString("a"), QString("a"), QString("b"), QString("b")};
+
+ QTest::newRow("descending strings")
+ << Qt::DescendingOrder
+ << QVariantList{ QString("a"), QString("b"), QString("b"), QString("a")}
+ << QVariantList{ QString("b"), QString("b"), QString("a"), QString("a")};
+
+ QTest::newRow("ascending numbers")
+ << Qt::AscendingOrder
+ << QVariantList{ 1, 2, 2, 1}
+ << QVariantList{ 1, 1, 2, 2};
+
+ QTest::newRow("descending numbers")
+ << Qt::DescendingOrder
+ << QVariantList{ 1, 2, 2, 1}
+ << QVariantList{ 2, 2, 1, 1};
+}
+
+void tst_QListWidget::sortCheckStability() {
+ QFETCH(Qt::SortOrder, order);
+ QFETCH(const QVariantList, initialList);
+ QFETCH(const QVariantList, expectedList);
+
+ for (const QVariant &data : initialList) {
+ QListWidgetItem *item = new QListWidgetItem(testWidget);
+ item->setData(Qt::DisplayRole, data);
+ }
+
+ QAbstractItemModel *model = testWidget->model();
+ QList<QPersistentModelIndex> persistent;
+ for (int j = 0; j < model->rowCount(QModelIndex()); ++j)
+ persistent << model->index(j, 0, QModelIndex());
+
+ testWidget->sortItems(order);
+
+ QCOMPARE(testWidget->count(), expectedList.size());
+ for (int i = 0; i < testWidget->count(); ++i)
+ QCOMPARE(testWidget->item(i)->text(), expectedList.at(i).toString());
+
+ QVector<QListWidgetItem*> itemOrder(testWidget->count());
+ for (int i = 0; i < testWidget->count(); ++i)
+ itemOrder[i] = testWidget->item(i);
+
+ qobject_cast<QListModel*>(testWidget->model())->ensureSorted(0, order, 1, 1);
+ testWidget->sortItems(order);
+
+ for (int i = 0; i < testWidget->count(); ++i)
+ QCOMPARE(itemOrder[i],testWidget->item(i));
+}
+
class TestListWidget : public QListWidget
{
Q_OBJECT