From fb00835468295925a6945a286406a2eec6bdb67a Mon Sep 17 00:00:00 2001 From: Amish Naidu Date: Fri, 5 Oct 2018 00:30:05 +0530 Subject: [PATCH] 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". --- src/playlist/playlist.cpp | 60 +++++++++++++++++++++++++------- src/playlist/playlist.h | 5 ++- src/ui/behavioursettingspage.cpp | 9 +++++ src/ui/behavioursettingspage.ui | 23 ++++++++++++ 4 files changed, 83 insertions(+), 14 deletions(-) diff --git a/src/playlist/playlist.cpp b/src/playlist/playlist.cpp index 72198910f..e386ead46 100644 --- a/src/playlist/playlist.cpp +++ b/src/playlist/playlist.cpp @@ -89,6 +89,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; @@ -96,6 +98,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) @@ -1246,14 +1259,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: @@ -1431,25 +1446,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 6b6581d80..a2df195ba 100644 --- a/src/ui/behavioursettingspage.cpp +++ b/src/ui/behavioursettingspage.cpp @@ -201,6 +201,12 @@ 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, QStringLiteral("a, the")) + .toString()); s.endGroup(); s.beginGroup(PlaylistTabBar::kSettingsGroup); @@ -281,6 +287,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 + + + + + +