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 + + + + + +