From 34e007f2b8e44ca4d72a3362c3286219a1ac8824 Mon Sep 17 00:00:00 2001 From: Amish Naidu Date: Mon, 8 Oct 2018 20:54:36 +0530 Subject: [PATCH] Port 'Allow ignoring prefixes when sorting playlist' to master (#6166) * Allow ignoring prefixes when sorting playlist This introduces new configuration options which allow you to ignore prefixes while sorting the playlist on album, artist and titles. Prefixes are configurable, default are "a" and "the". * Change QStringLiteral to QString for compatbility with Qt 4.8 --- src/playlist/playlist.cpp | 60 +++++++++++++++++++++++++------- src/playlist/playlist.h | 5 ++- src/ui/behavioursettingspage.cpp | 8 +++++ src/ui/behavioursettingspage.ui | 23 ++++++++++++ 4 files changed, 82 insertions(+), 14 deletions(-) diff --git a/src/playlist/playlist.cpp b/src/playlist/playlist.cpp index 817ad5351..0b6496721 100644 --- a/src/playlist/playlist.cpp +++ b/src/playlist/playlist.cpp @@ -90,6 +90,8 @@ const char* Playlist::kSettingsGroup = "Playlist"; const char* Playlist::kPathType = "path_type"; const char* Playlist::kWriteMetadata = "write_metadata"; +const char* Playlist::kSortIgnorePrefix = "sort_ignore_prefix"; +const char* Playlist::kSortIgnorePrefixList = "sort_ignore_prefix_list"; const int Playlist::kUndoStackSize = 20; const int Playlist::kUndoItemLimit = 500; @@ -97,6 +99,17 @@ const int Playlist::kUndoItemLimit = 500; const qint64 Playlist::kMinScrobblePointNsecs = 31ll * kNsecPerSec; const qint64 Playlist::kMaxScrobblePointNsecs = 240ll * kNsecPerSec; +namespace { +QString removePrefix(const QString& a, const QStringList& prefixes) { + for (const QString& prefix : prefixes) { + if (a.startsWith(prefix)) { + return a.mid(prefix.size()); + } + } + return a; +} +} // namespace + Playlist::Playlist(PlaylistBackend* backend, TaskManager* task_manager, LibraryBackend* library, int id, const QString& special_type, bool favorite, QObject* parent) @@ -1247,14 +1260,16 @@ QMimeData* Playlist::mimeData(const QModelIndexList& indexes) const { bool Playlist::CompareItems(int column, Qt::SortOrder order, shared_ptr _a, - shared_ptr _b) { + shared_ptr _b, + const QStringList& prefixes) { shared_ptr a = order == Qt::AscendingOrder ? _a : _b; shared_ptr b = order == Qt::AscendingOrder ? _b : _a; #define cmp(field) return a->Metadata().field() < b->Metadata().field() #define strcmp(field) \ - return QString::localeAwareCompare(a->Metadata().field().toLower(), \ - b->Metadata().field().toLower()) < 0; + return QString::localeAwareCompare( \ + removePrefix(a->Metadata().field().toLower(), prefixes), \ + removePrefix(b->Metadata().field().toLower(), prefixes)) < 0; switch (column) { case Column_Title: @@ -1432,25 +1447,44 @@ void Playlist::sort(int column, Qt::SortOrder order) { if (dynamic_playlist_ && current_item_index_.isValid()) begin += current_item_index_.row() + 1; + QSettings s; + s.beginGroup(Playlist::kSettingsGroup); + QStringList prefixes; + if ((column == Column_Album || column == Column_Artist || + column == Column_Title) && + s.value(Playlist::kSortIgnorePrefix, false).toBool()) { + prefixes = s.value(Playlist::kSortIgnorePrefixList, QString()) + .toString() + .split(','); + for (QString& prefix : prefixes) { + prefix = prefix.trimmed() + ' '; + } + } + s.endGroup(); + if (column == Column_Album) { // When sorting by album, also take into account discs and tracks. - qStableSort(begin, new_items.end(), std::bind(&Playlist::CompareItems, - Column_Track, order, _1, _2)); qStableSort(begin, new_items.end(), - std::bind(&Playlist::CompareItems, Column_Disc, order, _1, _2)); - qStableSort(begin, new_items.end(), std::bind(&Playlist::CompareItems, - Column_Album, order, _1, _2)); + std::bind(&Playlist::CompareItems, Column_Track, order, _1, _2, + prefixes)); + qStableSort(begin, new_items.end(), + std::bind(&Playlist::CompareItems, Column_Disc, order, _1, _2, + prefixes)); + qStableSort(begin, new_items.end(), + std::bind(&Playlist::CompareItems, Column_Album, order, _1, _2, + prefixes)); } else if (column == Column_Filename) { // When sorting by full paths we also expect a hierarchical order. This // returns a breath-first ordering of paths. - qStableSort( - begin, new_items.end(), - std::bind(&Playlist::CompareItems, Column_Filename, order, _1, _2)); + qStableSort(begin, new_items.end(), + std::bind(&Playlist::CompareItems, Column_Filename, order, _1, + _2, prefixes)); qStableSort(begin, new_items.end(), std::bind(&Playlist::ComparePathDepths, order, _1, _2)); } else { - qStableSort(begin, new_items.end(), - std::bind(&Playlist::CompareItems, column, order, _1, _2)); + qStableSort( + begin, new_items.end(), + std::bind(&Playlist::CompareItems, column, order, _1, _2, prefixes)); } undo_stack_->push( diff --git a/src/playlist/playlist.h b/src/playlist/playlist.h index ed2041040..0899238e6 100644 --- a/src/playlist/playlist.h +++ b/src/playlist/playlist.h @@ -37,6 +37,7 @@ class TaskManager; class QSortFilterProxyModel; class QUndoStack; +class QStringList; namespace PlaylistUndoCommands { class InsertItems; @@ -157,6 +158,8 @@ class Playlist : public QAbstractListModel { static const char* kPathType; static const char* kWriteMetadata; + static const char* kSortIgnorePrefix; + static const char* kSortIgnorePrefixList; static const int kUndoStackSize; static const int kUndoItemLimit; @@ -165,7 +168,7 @@ class Playlist : public QAbstractListModel { static const qint64 kMaxScrobblePointNsecs; static bool CompareItems(int column, Qt::SortOrder order, PlaylistItemPtr a, - PlaylistItemPtr b); + PlaylistItemPtr b, const QStringList& prefixes = {}); static QString column_name(Column column); static QString abbreviated_column_name(Column column); diff --git a/src/ui/behavioursettingspage.cpp b/src/ui/behavioursettingspage.cpp index 740fbe91d..d1cfe589d 100644 --- a/src/ui/behavioursettingspage.cpp +++ b/src/ui/behavioursettingspage.cpp @@ -203,6 +203,11 @@ void BehaviourSettingsPage::Load() { } ui_->b_write_metadata->setChecked( s.value(Playlist::kWriteMetadata, true).toBool()); + + ui_->sort_ignore_prefix->setChecked( + s.value(Playlist::kSortIgnorePrefix, true).toBool()); + ui_->sort_ignore_prefix_list->setText( + s.value(Playlist::kSortIgnorePrefixList, QString("a, the")).toString()); s.endGroup(); s.beginGroup(PlaylistTabBar::kSettingsGroup); @@ -283,6 +288,9 @@ void BehaviourSettingsPage::Save() { s.setValue("click_edit_inline", ui_->b_click_edit_inline_->isChecked()); s.setValue(Playlist::kPathType, static_cast(path)); s.setValue(Playlist::kWriteMetadata, ui_->b_write_metadata->isChecked()); + s.setValue(Playlist::kSortIgnorePrefix, ui_->sort_ignore_prefix->isChecked()); + s.setValue(Playlist::kSortIgnorePrefixList, + ui_->sort_ignore_prefix_list->text()); s.endGroup(); s.beginGroup(PlaylistTabBar::kSettingsGroup); diff --git a/src/ui/behavioursettingspage.ui b/src/ui/behavioursettingspage.ui index 2307a2d90..88b42e77a 100644 --- a/src/ui/behavioursettingspage.ui +++ b/src/ui/behavioursettingspage.ui @@ -405,6 +405,29 @@ + + + + When sorting artists, albums and titles + + + + + + Ignore prefix word(s) + + + + + + + Comma seperated list of prefix words to ignore when sorting + + + + + +