From 0d10eff3726e5de60298452308cc4b2b7820e10b Mon Sep 17 00:00:00 2001 From: Pan Zhang Date: Thu, 2 Apr 2026 20:08:43 +0800 Subject: kfileitemmodel: sort dotted numeric names naturally Natural sorting already handled plain numeric chunks, but names containing dots between numeric segments were still ordered lexically in important cases. This broke expected ordering for decimal-style names like 0.09 and 0.1, and for version-like names such as v1.2.3 and v1.2.10. Teach KFileItemModel's natural string comparison to recognize dotted numeric chains instead of relying solely on QCollator's numeric mode. Compare two-part numeric chains (e.g. 0.09 vs 0.1) as decimal values, and compare longer chains segment by segment like version numbers, while still treating real file extensions separately so names like 1.09.txt keep working correctly. Add a direct unit test for KFileItemModel::stringCompare covering decimal-style names, version-like dotted numeric names, numeric basenames with extensions, leading-dot names, and the non-natural sorting fallback. BUG: 411707 --- src/tests/kfileitemmodeltest.cpp | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'src/tests/kfileitemmodeltest.cpp') diff --git a/src/tests/kfileitemmodeltest.cpp b/src/tests/kfileitemmodeltest.cpp index 8c1f0d76a..f61bc246f 100644 --- a/src/tests/kfileitemmodeltest.cpp +++ b/src/tests/kfileitemmodeltest.cpp @@ -70,6 +70,8 @@ private Q_SLOTS: void testRemoveFilteredExpandedItems(); void testSorting(); void testNaturalSorting(); + void testStringCompare_data(); + void testStringCompare(); void testIndexForKeyboardSearch(); void testNameFilter(); void testEmptyPath(); @@ -1357,6 +1359,41 @@ void KFileItemModelTest::testNaturalSorting() QCOMPARE(itemsMovedSpy.takeFirst().at(1).value>(), QList() << 4 << 6 << 1 << 2 << 3 << 5); } +void KFileItemModelTest::testStringCompare_data() +{ + QTest::addColumn("left"); + QTest::addColumn("right"); + QTest::addColumn("naturalSorting"); + QTest::addColumn("expectedResult"); + + QTest::newRow("decimal") << QStringLiteral("0.09") << QStringLiteral("0.1") << true << -1; + QTest::newRow("version-patch") << QStringLiteral("v1.2.3") << QStringLiteral("v1.2.10") << true << -1; + QTest::newRow("version-patch-reversed") << QStringLiteral("v1.2.10") << QStringLiteral("v1.2.3") << true << 1; + QTest::newRow("version-minor") << QStringLiteral("v1.2.10") << QStringLiteral("v1.10.1") << true << -1; + QTest::newRow("numeric-basename-before-extension") << QStringLiteral("1.09.txt") << QStringLiteral("1.1.txt") << true << -1; + QTest::newRow("leading-dot-is-not-decimal") << QStringLiteral(".1") << QStringLiteral(".09") << true << -1; + QTest::newRow("natural-sorting-disabled") << QStringLiteral("v1.2.10") << QStringLiteral("v1.2.3") << false << -1; +} + +void KFileItemModelTest::testStringCompare() +{ + QFETCH(QString, left); + QFETCH(QString, right); + QFETCH(bool, naturalSorting); + QFETCH(int, expectedResult); + + QCollator collator; + collator.setNumericMode(true); + + m_model->m_naturalSorting = naturalSorting; + + const int result = m_model->stringCompare(left, right, collator); + QCOMPARE(result < 0 ? -1 : result > 0 ? 1 : 0, expectedResult); + + const int reverseResult = m_model->stringCompare(right, left, collator); + QCOMPARE(reverseResult < 0 ? -1 : reverseResult > 0 ? 1 : 0, -expectedResult); +} + void KFileItemModelTest::testIndexForKeyboardSearch() { QSignalSpy itemsInsertedSpy(m_model, &KFileItemModel::itemsInserted); -- cgit v1.3