From dbdc211da25ffbc64aef9b9ef2c5649b4ac1bc60 Mon Sep 17 00:00:00 2001 From: Craig Drummond Date: Mon, 27 Dec 2021 20:39:51 +0000 Subject: [PATCH] Use QCollator to compare strings. --- ChangeLog | 1 + db/librarydb.cpp | 59 ++++++++++++++++--------------- db/librarydb.h | 5 +-- gui/customactions.cpp | 5 +-- gui/interfacesettings.cpp | 2 +- gui/main.cpp | 2 ++ models/devicesmodel.cpp | 3 +- models/localbrowsemodel.cpp | 3 +- models/musiclibraryitemalbum.cpp | 4 +-- models/musiclibraryitemartist.cpp | 4 +-- models/playlistsproxymodel.h | 3 +- models/playqueuemodel.cpp | 12 +++---- mpd-interface/mpdconnection.h | 3 +- mpd-interface/output.h | 3 +- mpd-interface/partition.h | 3 +- mpd-interface/song.cpp | 18 ++++++---- playlists/smartplaylistspage.cpp | 10 +++--- support/utils.cpp | 12 +++++++ support/utils.h | 1 + 19 files changed, 92 insertions(+), 61 deletions(-) diff --git a/ChangeLog b/ChangeLog index 88f84ef67..1214a298b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -38,6 +38,7 @@ 27. Remove superfluous blank space from the top of the cover tooltip. 28. Fix looking for cover-art with MPD's new cue track file listing. 29. Add Grouping tag support to playlists and queue. +30. Use QCollator to compare strings. 2.4.2 ----- diff --git a/db/librarydb.cpp b/db/librarydb.cpp index 8b3986f3c..883b6be41 100644 --- a/db/librarydb.cpp +++ b/db/librarydb.cpp @@ -22,6 +22,7 @@ */ #include "librarydb.h" +#include "support/utils.h" #include #include #include @@ -70,14 +71,14 @@ static bool albumsSortAlArYr(const LibraryDb::Album &a, const LibraryDb::Album & { const QString &an=a.sort.isEmpty() ? a.name : a.sort; const QString &bn=b.sort.isEmpty() ? b.name : b.sort; - int cmp=an.localeAwareCompare(bn); + int cmp=Utils::compare(an, bn); if (cmp!=0) { return cmp<0; } const QString &aa=a.artistSort.isEmpty() ? a.artist : a.artistSort; const QString &ba=b.artistSort.isEmpty() ? b.artist : b.artistSort; - cmp=aa.localeAwareCompare(ba); + cmp=Utils::compare(aa, ba); if (cmp!=0) { return cmp<0; } @@ -88,14 +89,14 @@ static bool albumsSortArAlYr(const LibraryDb::Album &a, const LibraryDb::Album & { const QString &aa=a.artistSort.isEmpty() ? a.artist : a.artistSort; const QString &ba=b.artistSort.isEmpty() ? b.artist : b.artistSort; - int cmp=aa.localeAwareCompare(ba); + int cmp=Utils::compare(aa, ba); if (cmp!=0) { return cmp<0; } const QString &an=a.sort.isEmpty() ? a.name : a.sort; const QString &bn=b.sort.isEmpty() ? b.name : b.sort; - cmp=an.localeAwareCompare(bn); + cmp=Utils::compare(an, bn); if (cmp!=0) { return cmp<0; } @@ -107,7 +108,7 @@ static bool albumsSortAlYrAr(const LibraryDb::Album &a, const LibraryDb::Album & { const QString &an=a.sort.isEmpty() ? a.name : a.sort; const QString &bn=b.sort.isEmpty() ? b.name : b.sort; - int cmp=an.localeAwareCompare(bn); + int cmp=Utils::compare(an, bn); if (cmp!=0) { return cmp<0; } @@ -118,14 +119,14 @@ static bool albumsSortAlYrAr(const LibraryDb::Album &a, const LibraryDb::Album & const QString &aa=a.artistSort.isEmpty() ? a.artist : a.artistSort; const QString &ba=b.artistSort.isEmpty() ? b.artist : b.artistSort; - return aa.localeAwareCompare(ba)<0; + return Utils::compare(aa, ba)<0; } static bool albumsSortArYrAl(const LibraryDb::Album &a, const LibraryDb::Album &b) { const QString &aa=a.artistSort.isEmpty() ? a.artist : a.artistSort; const QString &ba=b.artistSort.isEmpty() ? b.artist : b.artistSort; - int cmp=aa.localeAwareCompare(ba); + int cmp=Utils::compare(aa, ba); if (cmp!=0) { return cmp<0; } @@ -136,7 +137,7 @@ static bool albumsSortArYrAl(const LibraryDb::Album &a, const LibraryDb::Album & const QString &an=a.sort.isEmpty() ? a.name : a.sort; const QString &bn=b.sort.isEmpty() ? b.name : b.sort; - return an.localeAwareCompare(bn)<0; + return Utils::compare(an, bn)<0; } static bool albumsSortYrAlAr(const LibraryDb::Album &a, const LibraryDb::Album &b) @@ -147,14 +148,14 @@ static bool albumsSortYrAlAr(const LibraryDb::Album &a, const LibraryDb::Album & const QString &an=a.sort.isEmpty() ? a.name : a.sort; const QString &bn=b.sort.isEmpty() ? b.name : b.sort; - int cmp=an.localeAwareCompare(bn); + int cmp=Utils::compare(an, bn); if (cmp!=0) { return cmp<0; } const QString &aa=a.artistSort.isEmpty() ? a.artist : a.artistSort; const QString &ba=b.artistSort.isEmpty() ? b.artist : b.artistSort; - return aa.localeAwareCompare(ba)<0; + return Utils::compare(aa, ba)<0; } static bool albumsSortYrArAl(const LibraryDb::Album &a, const LibraryDb::Album &b) @@ -165,14 +166,14 @@ static bool albumsSortYrArAl(const LibraryDb::Album &a, const LibraryDb::Album & const QString &aa=a.artistSort.isEmpty() ? a.artist : a.artistSort; const QString &ba=b.artistSort.isEmpty() ? b.artist : b.artistSort; - int cmp=aa.localeAwareCompare(ba); + int cmp=Utils::compare(aa, ba); if (cmp!=0) { return cmp<0; } const QString &an=a.sort.isEmpty() ? a.name : a.sort; const QString &bn=b.sort.isEmpty() ? b.name : b.sort; - return an.localeAwareCompare(bn)<0; + return Utils::compare(an, bn)<0; } static bool albumsSortModified(const LibraryDb::Album &a, const LibraryDb::Album &b) @@ -186,11 +187,11 @@ static bool albumsSortModified(const LibraryDb::Album &a, const LibraryDb::Album static bool songSort(const Song &a, const Song &b) { if (Song::SingleTracks==a.type && Song::SingleTracks==b.type) { - int cmp=a.title.localeAwareCompare(b.title); + int cmp=Utils::compare(a.title, b.title); if (0!=cmp) { return cmp<0; } - cmp=a.artist.localeAwareCompare(b.artist); + cmp=Utils::compare(a.artist, b.artist); if (0!=cmp) { return cmp<0; } @@ -205,15 +206,15 @@ static bool songSort(const Song &a, const Song &b) if (a.displayYear()!=b.displayYear()) { return a.displayYear() #include #include "mpd-interface/song.h" +#include "support/utils.h" #include class QSqlDatabase; @@ -72,7 +73,7 @@ public: if (constNullGenre==name) { return constNullGenre!=o.name; } - return name.localeAwareCompare(o.name)<0; + return Utils::compare(name, o.name)<0; } }; @@ -89,7 +90,7 @@ public: const QString &field=sort.isEmpty() ? name : sort; const QString &ofield=o.sort.isEmpty() ? o.name : o.sort; - return field.localeAwareCompare(ofield)<0; + return Utils::compare(field, ofield)<0; } }; diff --git a/gui/customactions.cpp b/gui/customactions.cpp index b2c9d42a3..fd0c73624 100644 --- a/gui/customactions.cpp +++ b/gui/customactions.cpp @@ -25,6 +25,7 @@ #include "mainwindow.h" #include "support/globalstatic.h" #include "support/configuration.h" +#include "support/utils.h" #include #include #include @@ -42,12 +43,12 @@ void CustomActions::enableDebug() bool CustomActions::Command::operator<(const Command &o) const { - int c=name.localeAwareCompare(o.name); + int c=Utils::compare(name, o.name); if (c<0) { return true; } if (c==0) { - return cmd.localeAwareCompare(o.cmd)<0; + return Utils::compare(cmd, o.cmd)<0; } return false; } diff --git a/gui/interfacesettings.cpp b/gui/interfacesettings.cpp index d4e31c255..e522be72e 100644 --- a/gui/interfacesettings.cpp +++ b/gui/interfacesettings.cpp @@ -390,7 +390,7 @@ void InterfaceSettings::save() static bool localeAwareCompare(const QString &a, const QString &b) { - return a.localeAwareCompare(b) < 0; + return Utils::compare(a, b) < 0; } static QSet translationCodes(const QString &dir) diff --git a/gui/main.cpp b/gui/main.cpp index 6ea9e6404..420d5ffbb 100644 --- a/gui/main.cpp +++ b/gui/main.cpp @@ -420,6 +420,8 @@ int main(int argc, char *argv[]) loadTranslation("cantata", QDir(local).exists() ? local : CANTATA_SYS_TRANS_DIR, lang); Application::init(); + // Ensure QColator gets initialised... + Utils::compare(QString(), QString()); if (Settings::self()->firstRun()) { InitialSettingsWizard wz; diff --git a/models/devicesmodel.cpp b/models/devicesmodel.cpp index a93ef4f24..d7645514b 100644 --- a/models/devicesmodel.cpp +++ b/models/devicesmodel.cpp @@ -43,6 +43,7 @@ #include "devices/audiocddevice.h" #endif #include "support/globalstatic.h" +#include "support/utils.h" #include #include #include @@ -880,7 +881,7 @@ void DevicesModel::playCd(const QString &dev) static bool lessThan(const QString &left, const QString &right) { - return left.localeAwareCompare(right)<0; + return Utils::compare(left, right)<0; } void DevicesModel::updateItemMenu() diff --git a/models/localbrowsemodel.cpp b/models/localbrowsemodel.cpp index 542f6208a..d27579aa5 100644 --- a/models/localbrowsemodel.cpp +++ b/models/localbrowsemodel.cpp @@ -26,6 +26,7 @@ #include "playqueuemodel.h" #include "widgets/icons.h" #include "gui/stdactions.h" +#include "support/utils.h" FileSystemProxyModel::FileSystemProxyModel(LocalBrowseModel *p) : QSortFilterProxyModel(p) @@ -60,7 +61,7 @@ bool FileSystemProxyModel::lessThan(const QModelIndex &left, const QModelIndex & if (!l.isDir() && r.isDir()) { return false; } - return l.fileName().toLower().localeAwareCompare(r.fileName().toLower())<0; + return Utils::compare(l.fileName(), r.fileName())<0; } LocalBrowseModel::LocalBrowseModel(const QString &name, const QString &title, const QString &descr, const QIcon &icon, QObject *p) diff --git a/models/musiclibraryitemalbum.cpp b/models/musiclibraryitemalbum.cpp index f3a6b09d7..e08199657 100644 --- a/models/musiclibraryitemalbum.cpp +++ b/models/musiclibraryitemalbum.cpp @@ -31,8 +31,8 @@ #include "widgets/icons.h" #ifdef ENABLE_DEVICES_SUPPORT #include "devices/device.h" -#include "support/utils.h" #endif +#include "support/utils.h" static bool dateSort=false; @@ -52,7 +52,7 @@ bool MusicLibraryItemAlbum::lessThan(const MusicLibraryItem *a, const MusicLibra const MusicLibraryItemAlbum *ab=static_cast(b); if (!MusicLibraryItemAlbum::sortByDate() || aa->year()==ab->year()) { - int compare=aa->sortString().localeAwareCompare(ab->sortString()); + int compare=Utils::compare(aa->sortString(), ab->sortString()); return compare==0 ? aa->id().compare(ab->id())<0 : compare<0; } return aa->year()year(); diff --git a/models/musiclibraryitemartist.cpp b/models/musiclibraryitemartist.cpp index 10d517f8f..0e18ea9a5 100644 --- a/models/musiclibraryitemartist.cpp +++ b/models/musiclibraryitemartist.cpp @@ -32,8 +32,8 @@ #include "widgets/icons.h" #ifdef ENABLE_DEVICES_SUPPORT #include "devices/device.h" -#include "support/utils.h" #endif +#include "support/utils.h" bool MusicLibraryItemArtist::lessThan(const MusicLibraryItem *a, const MusicLibraryItem *b) { @@ -43,7 +43,7 @@ bool MusicLibraryItemArtist::lessThan(const MusicLibraryItem *a, const MusicLibr // if (aa->isVarious() != ab->isVarious()) { // return aa->isVarious() > ab->isVarious(); // } - return aa->sortString().localeAwareCompare(ab->sortString())<0; + return Utils::compare(aa->sortString(), ab->sortString())<0; } MusicLibraryItemArtist::MusicLibraryItemArtist(const Song &song, MusicLibraryItemContainer *parent) diff --git a/models/playlistsproxymodel.h b/models/playlistsproxymodel.h index d08cb04e2..315f4600a 100644 --- a/models/playlistsproxymodel.h +++ b/models/playlistsproxymodel.h @@ -27,6 +27,7 @@ #define PLAYLISTSPROXYMODEL_H #include "proxymodel.h" +#include "support/utils.h" class PlaylistsProxyModel : public ProxyModel { @@ -35,7 +36,7 @@ class PlaylistsProxyModel : public ProxyModel public: PlaylistsProxyModel(QObject *parent = nullptr); bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; - static bool compareNames(const QString &l, const QString &r) { return l.localeAwareCompare(r)<0; } + static bool compareNames(const QString &l, const QString &r) { return Utils::compare(l, r)<0; } bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; }; diff --git a/models/playqueuemodel.cpp b/models/playqueuemodel.cpp index fb9dceb64..ea12e831f 100644 --- a/models/playqueuemodel.cpp +++ b/models/playqueuemodel.cpp @@ -1409,7 +1409,7 @@ static bool otherSort(const Song *s1, const Song *s2, quint32 other) { const QString v1=s1->hasExtraField(other) ? s1->extraField(other) : QString(); const QString v2=s2->hasExtraField(other) ? s2->extraField(other) : QString(); - int c=v1.localeAwareCompare(v2); + int c=Utils::compare(v1, v2); return c<0 || (c==0 && (*s1)<(*s2)); } @@ -1432,7 +1432,7 @@ static bool artistSort(const Song *s1, const Song *s2) { const QString v1=s1->hasArtistSort() ? s1->artistSort() : s1->artist; const QString v2=s2->hasArtistSort() ? s2->artistSort() : s2->artist; - int c=v1.localeAwareCompare(v2); + int c=Utils::compare(v1, v2); return c<0 || (c==0 && (*s1)<(*s2)); } @@ -1440,7 +1440,7 @@ static bool albumArtistSort(const Song *s1, const Song *s2) { const QString v1=s1->hasAlbumArtistSort() ? s1->albumArtistSort() : s1->albumArtistOrComposer(); const QString v2=s2->hasAlbumArtistSort() ? s2->albumArtistSort() : s2->albumArtistOrComposer(); - int c=v1.localeAwareCompare(v2); + int c=Utils::compare(v1, v2); return c<0 || (c==0 && (*s1)<(*s2)); } @@ -1448,7 +1448,7 @@ static bool albumSort(const Song *s1, const Song *s2) { const QString v1=s1->hasAlbumSort() ? s1->albumSort() : s1->album; const QString v2=s2->hasAlbumSort() ? s2->albumSort() : s2->album; - int c=v1.localeAwareCompare(v2); + int c=Utils::compare(v1, v2); return c<0 || (c==0 && (*s1)<(*s2)); } @@ -1465,7 +1465,7 @@ static bool yearSort(const Song *s1, const Song *s2) static bool titleSort(const Song *s1, const Song *s2) { - int c=s1->title.localeAwareCompare(s2->title); + int c=Utils::compare(s1->title, s2->title); return c<0 || (c==0 && (*s1)<(*s2)); } @@ -1476,7 +1476,7 @@ static bool trackSort(const Song *s1, const Song *s2) static bool pathSort(const Song *s1, const Song *s2) { - int c=s1->file.localeAwareCompare(s2->file); + int c=Utils::compare(s1->file, s2->file); return c<0 || (c==0 && (*s1)<(*s2)); } diff --git a/mpd-interface/mpdconnection.h b/mpd-interface/mpdconnection.h index 5a30cced1..08dc11565 100644 --- a/mpd-interface/mpdconnection.h +++ b/mpd-interface/mpdconnection.h @@ -42,6 +42,7 @@ #include "playlist.h" #include "stream.h" #include "config.h" +#include "support/utils.h" #include class QTimer; @@ -151,7 +152,7 @@ struct MPDConnectionDetails { MPDConnectionDetails & operator=(const MPDConnectionDetails &o); bool operator==(const MPDConnectionDetails &o) const { return hostname==o.hostname && isLocal()==o.isLocal() && (isLocal() || port==o.port) && password==o.password; } bool operator!=(const MPDConnectionDetails &o) const { return !(*this==o); } - bool operator<(const MPDConnectionDetails &o) const { return name.localeAwareCompare(o.name)<0; } + bool operator<(const MPDConnectionDetails &o) const { return Utils::compare(name, o.name)<0; } static QString configGroupName(const QString &n=QString()) { return n.isEmpty() ? "Connection" : ("Connection-"+n); } void setDirReadable(); diff --git a/mpd-interface/output.h b/mpd-interface/output.h index e13d1c943..174a7a83e 100644 --- a/mpd-interface/output.h +++ b/mpd-interface/output.h @@ -27,6 +27,7 @@ #ifndef OUTPUT_H #define OUTPUT_H +#include "support/utils.h" #include struct Output @@ -45,7 +46,7 @@ struct Output } bool operator<(const Output &o) const { - return name.localeAwareCompare(o.name)<0; + return Utils::compare(name, o.name)<0; } virtual ~Output() { } diff --git a/mpd-interface/partition.h b/mpd-interface/partition.h index 606d393b9..695b428b1 100644 --- a/mpd-interface/partition.h +++ b/mpd-interface/partition.h @@ -24,6 +24,7 @@ #ifndef PARTITION_H #define PARTITION_H +#include "support/utils.h" #include struct Partition @@ -33,7 +34,7 @@ struct Partition ~Partition() = default; bool operator<(const Partition &o) const { - return name.localeAwareCompare(o.name)<0; + return Utils::compare(name, o.name)<0; } QString name; diff --git a/mpd-interface/song.cpp b/mpd-interface/song.cpp index 2b599a956..6b4dea273 100644 --- a/mpd-interface/song.cpp +++ b/mpd-interface/song.cpp @@ -42,6 +42,12 @@ #include #include +#if defined CANTATA_NO_UI_FUNCTIONS +#define COMPARE(A, B) A.localeAwareCompare(B) +#else +#define COMPARE(A, B) Utils::compare(A, B) +#endif + //static const quint8 constOnlineDiscId=0xEE; static const QString constMpdQueue=QLatin1String(".cue/track"); // .cue.track0123 @@ -238,21 +244,21 @@ int Song::compareTo(const Song &o) const // For playlists, we only need to compare filename... if (Playlist!=type) { if (SingleTracks==type) { - int compare=artistSong().localeAwareCompare(artistSong()); + int compare=COMPARE(artistSong(), o.artistSong()); if (0!=compare) { return compare<0; } } - int compare=albumArtistOrComposer().localeAwareCompare(o.albumArtistOrComposer()); + int compare=COMPARE(albumArtistOrComposer(), o.albumArtistOrComposer()); if (0!=compare) { return compare; } - compare=album.localeAwareCompare(o.album); + compare=COMPARE(album, o.album); if (0!=compare) { return compare; } - compare=mbAlbumId().compare(o.mbAlbumId()); + compare=COMPARE(mbAlbumId(), o.mbAlbumId()); if (0!=compare) { return compare; } @@ -277,11 +283,11 @@ int Song::compareTo(const Song &o) const return origYear0 || (c==0 && s10 || (c==0 && s10 || (c==0 && s10 || (c==0 && s10 || (c==0 && s1 #include #endif +#include const QLatin1Char Utils::constDirSep('/'); const QLatin1String Utils::constDirSepStr("/"); @@ -1062,3 +1063,14 @@ void Utils::raiseWindow(QWidget *w) #endif } +int Utils::compare(const QString &a, const QString &b) +{ + static QCollator *collator = nullptr; + if (!collator) { + collator=new QCollator(); + collator->setNumericMode(true); + collator->setIgnorePunctuation(true); + collator->setCaseSensitivity(Qt::CaseInsensitive); + } + return collator->compare(a, b); +} diff --git a/support/utils.h b/support/utils.h index a51b3723d..0a44b5c22 100644 --- a/support/utils.h +++ b/support/utils.h @@ -133,6 +133,7 @@ namespace Utils extern QPainterPath buildPath(const QRectF &r, double radius); extern QColor clampColor(const QColor &col); extern QColor monoIconColor(); + extern int compare(const QString &a, const QString &b); } #endif