X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/cdec9bd2f1707a197021d84c29c0436de4fcace7..e57f6215659ee36877c7c36c9e3fcba0ba5d03a0:/src/kitemviews/kfileitemmodel.cpp diff --git a/src/kitemviews/kfileitemmodel.cpp b/src/kitemviews/kfileitemmodel.cpp index 3a60834af..4386bca16 100644 --- a/src/kitemviews/kfileitemmodel.cpp +++ b/src/kitemviews/kfileitemmodel.cpp @@ -20,6 +20,9 @@ #include #include +#ifndef QT_NO_ACCESSIBILITY +#include +#endif #include #include #include @@ -332,16 +335,32 @@ QMimeData *KFileItemModel::createMimeData(const KItemSet &indexes) const return data; } +namespace +{ +QString removeMarks(const QString &original) +{ + const auto normalized = original.normalized(QString::NormalizationForm_D); + QString res; + for (auto ch : normalized) { + if (!ch.isMark()) { + res.append(ch); + } + } + return res; +} +} + int KFileItemModel::indexForKeyboardSearch(const QString &text, int startFromIndex) const { + const auto noMarkText = removeMarks(text); startFromIndex = qMax(0, startFromIndex); for (int i = startFromIndex; i < count(); ++i) { - if (fileItem(i).text().startsWith(text, Qt::CaseInsensitive)) { + if (removeMarks(fileItem(i).text()).startsWith(noMarkText, Qt::CaseInsensitive)) { return i; } } for (int i = 0; i < startFromIndex; ++i) { - if (fileItem(i).text().startsWith(text, Qt::CaseInsensitive)) { + if (removeMarks(fileItem(i).text()).startsWith(noMarkText, Qt::CaseInsensitive)) { return i; } } @@ -2246,7 +2265,24 @@ int KFileItemModel::stringCompare(const QString &a, const QString &b, const QCol QMutexLocker collatorLock(s_collatorMutex()); if (m_naturalSorting) { - return collator.compare(a, b); + // Split extension, taking into account it can be empty + constexpr QString::SectionFlags flags = QString::SectionSkipEmpty | QString::SectionIncludeLeadingSep; + + // Sort by baseName first + const QString aBaseName = a.section('.', 0, 0, flags); + const QString bBaseName = b.section('.', 0, 0, flags); + + const int res = collator.compare(aBaseName, bBaseName); + if (res != 0 || (aBaseName.length() == a.length() && bBaseName.length() == b.length())) { + return res; + } + + // sliced() has undefined behavior when pos < 0 or pos > size(). + Q_ASSERT(aBaseName.length() <= a.length() && aBaseName.length() >= 0); + Q_ASSERT(bBaseName.length() <= b.length() && bBaseName.length() >= 0); + + // baseNames were equal, sort by extension + return collator.compare(a.sliced(aBaseName.length()), b.sliced(bBaseName.length())); } const int result = QString::compare(a, b, collator.caseSensitivity()); @@ -2450,7 +2486,7 @@ QList> KFileItemModel::timeRoleGroups(const std::function= 2 && count % 2 == 0) { newGroupValue = locale.toString(fileTime, translatedFormat); newGroupValue = i18nc( "Can be used to script translation of " @@ -2482,7 +2518,7 @@ QList> KFileItemModel::timeRoleGroups(const std::function= 2 && count % 2 == 0) { newGroupValue = locale.toString(fileTime, translatedFormat); newGroupValue = i18nc( "Can be used to script translation of " @@ -2503,7 +2539,7 @@ QList> KFileItemModel::timeRoleGroups(const std::function= 2 && count % 2 == 0) { newGroupValue = locale.toString(fileTime, translatedFormat); newGroupValue = i18nc( "Can be used to script translation of " @@ -2524,7 +2560,7 @@ QList> KFileItemModel::timeRoleGroups(const std::function= 2 && count % 2 == 0) { newGroupValue = locale.toString(fileTime, translatedFormat); newGroupValue = i18nc( "Can be used to script translation of " @@ -2545,7 +2581,7 @@ QList> KFileItemModel::timeRoleGroups(const std::function= 2 && count % 2 == 0) { newGroupValue = locale.toString(fileTime, translatedFormat); newGroupValue = i18nc( "Can be used to script translation of "