Skip to content

Commit

Permalink
Allow ignoring prefixes when sorting playlist
Browse files Browse the repository at this point in the history
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".
  • Loading branch information
amhndu authored and hatstand committed Oct 5, 2018
1 parent 58108dd commit fb00835
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 14 deletions.
60 changes: 47 additions & 13 deletions src/playlist/playlist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,26 @@ 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;

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)
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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(
Expand Down
5 changes: 4 additions & 1 deletion src/playlist/playlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class TaskManager;

class QSortFilterProxyModel;
class QUndoStack;
class QStringList;

namespace PlaylistUndoCommands {
class InsertItems;
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand Down
9 changes: 9 additions & 0 deletions src/ui/behavioursettingspage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
23 changes: 23 additions & 0 deletions src/ui/behavioursettingspage.ui
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand Down

0 comments on commit fb00835

Please sign in to comment.