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
This commit is contained in:
Amish Naidu 2018-10-08 20:54:36 +05:30 committed by John Maguire
parent 7c1d0517d1
commit 34e007f2b8
4 changed files with 82 additions and 14 deletions

View File

@ -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<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:
@ -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(

View File

@ -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);

View File

@ -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<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);

View File

@ -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">