mirror of
https://github.com/clementine-player/Clementine
synced 2025-01-21 14:16:03 +01:00
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".
This commit is contained in:
parent
58108dd0d0
commit
fb00835468
@ -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<PlaylistItem> _a,
|
||||
shared_ptr<PlaylistItem> _b) {
|
||||
shared_ptr<PlaylistItem> _b,
|
||||
const QStringList& prefixes) {
|
||||
shared_ptr<PlaylistItem> a = order == Qt::AscendingOrder ? _a : _b;
|
||||
shared_ptr<PlaylistItem> 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(
|
||||
|
@ -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);
|
||||
|
@ -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<int>(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);
|
||||
|
@ -405,6 +405,29 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_sort_ignore">
|
||||
<property name="title">
|
||||
<string>When sorting artists, albums and titles</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="sort_ignore_prefix">
|
||||
<property name="text">
|
||||
<string>Ignore prefix word(s)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="sort_ignore_prefix_list">
|
||||
<property name="toolTip">
|
||||
<string>Comma seperated list of prefix words to ignore when sorting</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
|
Loading…
Reference in New Issue
Block a user