QDir: use QCollator when doing locale-aware sorting
And don't use toLower() as QString::compare() and QCollator::compare() can compare case-insensitively. Change-Id: I999d787cb77e10a101da75d1bf0a5baf096a5c9b Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
eb60e94020
commit
b5a54d488c
@ -22,6 +22,7 @@
|
|||||||
#include <qstringbuilder.h>
|
#include <qstringbuilder.h>
|
||||||
|
|
||||||
#ifndef QT_BOOTSTRAPPED
|
#ifndef QT_BOOTSTRAPPED
|
||||||
|
# include <qcollator.h>
|
||||||
# include "qreadwritelock.h"
|
# include "qreadwritelock.h"
|
||||||
# include "qmutex.h"
|
# include "qmutex.h"
|
||||||
#endif
|
#endif
|
||||||
@ -199,10 +200,8 @@ struct QDirSortItem
|
|||||||
// A dir e.g. "dirA.bar" doesn't have actually have an extension/suffix, when
|
// A dir e.g. "dirA.bar" doesn't have actually have an extension/suffix, when
|
||||||
// sorting by type such "suffix" should be ignored but that would complicate
|
// sorting by type such "suffix" should be ignored but that would complicate
|
||||||
// the code and uses can change the behavior by setting DirsFirst/DirsLast
|
// the code and uses can change the behavior by setting DirsFirst/DirsLast
|
||||||
if (sort.testAnyFlag(QDir::Type)) {
|
if (sort.testAnyFlag(QDir::Type))
|
||||||
const bool ic = sort.testAnyFlag(QDir::IgnoreCase);
|
suffix_cache = item.suffix();
|
||||||
suffix_cache = ic ? item.suffix().toLower() : item.suffix();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mutable QString filename_cache;
|
mutable QString filename_cache;
|
||||||
@ -210,13 +209,39 @@ struct QDirSortItem
|
|||||||
QFileInfo item;
|
QFileInfo item;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class QDirSortItemComparator
|
class QDirSortItemComparator
|
||||||
{
|
{
|
||||||
QDir::SortFlags qt_cmp_si_sort_flags;
|
QDir::SortFlags qt_cmp_si_sort_flags;
|
||||||
|
|
||||||
|
#ifndef QT_BOOTSTRAPPED
|
||||||
|
QCollator *collator = nullptr;
|
||||||
|
#endif
|
||||||
public:
|
public:
|
||||||
QDirSortItemComparator(QDir::SortFlags flags) : qt_cmp_si_sort_flags(flags) {}
|
#ifndef QT_BOOTSTRAPPED
|
||||||
|
QDirSortItemComparator(QDir::SortFlags flags, QCollator *coll = nullptr)
|
||||||
|
: qt_cmp_si_sort_flags(flags), collator(coll)
|
||||||
|
{
|
||||||
|
Q_ASSERT(!qt_cmp_si_sort_flags.testAnyFlag(QDir::LocaleAware) || collator);
|
||||||
|
|
||||||
|
if (collator && qt_cmp_si_sort_flags.testAnyFlag(QDir::IgnoreCase))
|
||||||
|
collator->setCaseSensitivity(Qt::CaseInsensitive);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
QDirSortItemComparator(QDir::SortFlags flags)
|
||||||
|
: qt_cmp_si_sort_flags(flags)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
bool operator()(const QDirSortItem &, const QDirSortItem &) const;
|
bool operator()(const QDirSortItem &, const QDirSortItem &) const;
|
||||||
|
|
||||||
|
int compareStrings(const QString &a, const QString &b, Qt::CaseSensitivity cs) const
|
||||||
|
{
|
||||||
|
#ifndef QT_BOOTSTRAPPED
|
||||||
|
if (collator)
|
||||||
|
return collator->compare(a, b);
|
||||||
|
#endif
|
||||||
|
return a.compare(b, cs);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
bool QDirSortItemComparator::operator()(const QDirSortItem &n1, const QDirSortItem &n2) const
|
bool QDirSortItemComparator::operator()(const QDirSortItem &n1, const QDirSortItem &n2) const
|
||||||
@ -229,6 +254,9 @@ bool QDirSortItemComparator::operator()(const QDirSortItem &n1, const QDirSortIt
|
|||||||
if ((qt_cmp_si_sort_flags & QDir::DirsLast) && (f1->item.isDir() != f2->item.isDir()))
|
if ((qt_cmp_si_sort_flags & QDir::DirsLast) && (f1->item.isDir() != f2->item.isDir()))
|
||||||
return !f1->item.isDir();
|
return !f1->item.isDir();
|
||||||
|
|
||||||
|
const bool ic = qt_cmp_si_sort_flags.testAnyFlag(QDir::IgnoreCase);
|
||||||
|
const auto qtcase = ic ? Qt::CaseInsensitive : Qt::CaseSensitive;
|
||||||
|
|
||||||
qint64 r = 0;
|
qint64 r = 0;
|
||||||
int sortBy = ((qt_cmp_si_sort_flags & QDir::SortByMask)
|
int sortBy = ((qt_cmp_si_sort_flags & QDir::SortByMask)
|
||||||
| (qt_cmp_si_sort_flags & QDir::Type)).toInt();
|
| (qt_cmp_si_sort_flags & QDir::Type)).toInt();
|
||||||
@ -243,11 +271,8 @@ bool QDirSortItemComparator::operator()(const QDirSortItem &n1, const QDirSortIt
|
|||||||
case QDir::Size:
|
case QDir::Size:
|
||||||
r = f2->item.size() - f1->item.size();
|
r = f2->item.size() - f1->item.size();
|
||||||
break;
|
break;
|
||||||
case QDir::Type: {
|
case QDir::Type:
|
||||||
r = qt_cmp_si_sort_flags & QDir::LocaleAware
|
r = compareStrings(f1->suffix_cache, f2->suffix_cache, qtcase);
|
||||||
? f1->suffix_cache.localeAwareCompare(f2->suffix_cache)
|
|
||||||
: f1->suffix_cache.compare(f2->suffix_cache);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
;
|
;
|
||||||
@ -255,18 +280,13 @@ bool QDirSortItemComparator::operator()(const QDirSortItem &n1, const QDirSortIt
|
|||||||
|
|
||||||
if (r == 0 && sortBy != QDir::Unsorted) {
|
if (r == 0 && sortBy != QDir::Unsorted) {
|
||||||
// Still not sorted - sort by name
|
// Still not sorted - sort by name
|
||||||
bool ic = qt_cmp_si_sort_flags.testAnyFlag(QDir::IgnoreCase);
|
|
||||||
|
|
||||||
if (f1->filename_cache.isNull())
|
if (f1->filename_cache.isNull())
|
||||||
f1->filename_cache = ic ? f1->item.fileName().toLower()
|
f1->filename_cache = f1->item.fileName();
|
||||||
: f1->item.fileName();
|
|
||||||
if (f2->filename_cache.isNull())
|
if (f2->filename_cache.isNull())
|
||||||
f2->filename_cache = ic ? f2->item.fileName().toLower()
|
f2->filename_cache = f2->item.fileName();
|
||||||
: f2->item.fileName();
|
|
||||||
|
|
||||||
r = qt_cmp_si_sort_flags & QDir::LocaleAware
|
r = compareStrings(f1->filename_cache, f2->filename_cache, qtcase);
|
||||||
? f1->filename_cache.localeAwareCompare(f2->filename_cache)
|
|
||||||
: f1->filename_cache.compare(f2->filename_cache);
|
|
||||||
}
|
}
|
||||||
if (qt_cmp_si_sort_flags & QDir::Reversed)
|
if (qt_cmp_si_sort_flags & QDir::Reversed)
|
||||||
return r > 0;
|
return r > 0;
|
||||||
@ -297,7 +317,17 @@ inline void QDirPrivate::sortFileList(QDir::SortFlags sort, const QFileInfoList
|
|||||||
for (qsizetype i = 0; i < n; ++i)
|
for (qsizetype i = 0; i < n; ++i)
|
||||||
si[i] = QDirSortItem{l.at(i), sort};
|
si[i] = QDirSortItem{l.at(i), sort};
|
||||||
|
|
||||||
|
#ifndef QT_BOOTSTRAPPED
|
||||||
|
if (sort.testAnyFlag(QDir::LocaleAware)) {
|
||||||
|
QCollator coll;
|
||||||
|
std::sort(si.data(), si.data() + n, QDirSortItemComparator(sort, &coll));
|
||||||
|
} else {
|
||||||
std::sort(si.data(), si.data() + n, QDirSortItemComparator(sort));
|
std::sort(si.data(), si.data() + n, QDirSortItemComparator(sort));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
std::sort(si.data(), si.data() + n, QDirSortItemComparator(sort));
|
||||||
|
#endif // QT_BOOTSTRAPPED
|
||||||
|
|
||||||
// put them back in the list(s)
|
// put them back in the list(s)
|
||||||
for (qsizetype i = 0; i < n; ++i) {
|
for (qsizetype i = 0; i < n; ++i) {
|
||||||
if (infos)
|
if (infos)
|
||||||
|
@ -793,6 +793,12 @@ void tst_QDir::entryListWithTestFiles_data()
|
|||||||
QTest::newRow("QDir::AllEntries") << (m_dataPath + "/entrylist/") << QStringList("*")
|
QTest::newRow("QDir::AllEntries") << (m_dataPath + "/entrylist/") << QStringList("*")
|
||||||
<< int(QDir::AllEntries) << int(QDir::Name)
|
<< int(QDir::AllEntries) << int(QDir::Name)
|
||||||
<< filterLinks(QString(".,..,directory,file,linktodirectory.lnk,linktofile.lnk,writable").split(','));
|
<< filterLinks(QString(".,..,directory,file,linktodirectory.lnk,linktofile.lnk,writable").split(','));
|
||||||
|
// Tests an assert in QDirSortItemComparator, when QDir::LocaleAware is set
|
||||||
|
// a QCollator is used
|
||||||
|
QTest::newRow("QDir::AllEntries")
|
||||||
|
<< (m_dataPath + "/entrylist/") << QStringList("*")
|
||||||
|
<< int(QDir::AllEntries) << int(QDir::Name | QDir::LocaleAware)
|
||||||
|
<< filterLinks(QString(".,..,directory,file,linktodirectory.lnk,linktofile.lnk,writable").split(','));
|
||||||
QTest::newRow("QDir::Files") << (m_dataPath + "/entrylist/") << QStringList("*")
|
QTest::newRow("QDir::Files") << (m_dataPath + "/entrylist/") << QStringList("*")
|
||||||
<< int(QDir::Files) << int(QDir::Name)
|
<< int(QDir::Files) << int(QDir::Name)
|
||||||
<< filterLinks(QString("file,linktofile.lnk,writable").split(','));
|
<< filterLinks(QString("file,linktofile.lnk,writable").split(','));
|
||||||
|
Loading…
Reference in New Issue
Block a user