Refactor use of sort tags

This commit is contained in:
Jonas Kvinge
2025-08-09 19:08:51 +02:00
parent 65d9b6a9e9
commit c4646531b0
10 changed files with 244 additions and 352 deletions

View File

@@ -1,6 +1,6 @@
/* /*
* Strawberry Music Player * Strawberry Music Player
* Copyright 2018-2024, Jonas Kvinge <jonas@jkvinge.net> * Copyright 2018-2025, Jonas Kvinge <jonas@jkvinge.net>
* *
* Strawberry is free software: you can redistribute it and/or modify * Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -54,6 +54,7 @@
#include "includes/scoped_ptr.h" #include "includes/scoped_ptr.h"
#include "includes/shared_ptr.h" #include "includes/shared_ptr.h"
#include "constants/collectionsettings.h"
#include "core/logging.h" #include "core/logging.h"
#include "core/standardpaths.h" #include "core/standardpaths.h"
#include "core/database.h" #include "core/database.h"
@@ -76,6 +77,7 @@ using namespace std::chrono_literals;
using namespace Qt::Literals::StringLiterals; using namespace Qt::Literals::StringLiterals;
const int CollectionModel::kPrettyCoverSize = 32; const int CollectionModel::kPrettyCoverSize = 32;
namespace { namespace {
constexpr char kPixmapDiskCacheDir[] = "pixmapcache"; constexpr char kPixmapDiskCacheDir[] = "pixmapcache";
constexpr char kVariousArtists[] = QT_TR_NOOP("Various artists"); constexpr char kVariousArtists[] = QT_TR_NOOP("Various artists");
@@ -206,9 +208,10 @@ void CollectionModel::ReloadSettings() {
Settings settings; Settings settings;
settings.beginGroup(CollectionSettings::kSettingsGroup); settings.beginGroup(CollectionSettings::kSettingsGroup);
const bool show_pretty_covers = settings.value(CollectionSettings::kPrettyCovers, true).toBool(); const bool show_pretty_covers = settings.value(CollectionSettings::kPrettyCovers, true).toBool();
const bool show_dividers= settings.value(CollectionSettings::kShowDividers, true).toBool(); const bool show_dividers = settings.value(CollectionSettings::kShowDividers, true).toBool();
const bool show_various_artists = settings.value(CollectionSettings::kVariousArtists, true).toBool(); const bool show_various_artists = settings.value(CollectionSettings::kVariousArtists, true).toBool();
const CollectionSettings::SortBehaviour sort_behaviour = static_cast<CollectionSettings::SortBehaviour>(settings.value(CollectionSettings::kSortBehaviour, static_cast<int>(CollectionSettings::SortBehaviour::AsIs)).toInt()); const bool sort_skip_articles_for_artists = settings.value(CollectionSettings::kSkipArticlesForArtists, true).toBool();
const bool sort_skip_articles_for_albums = settings.value(CollectionSettings::kSkipArticlesForAlbums, false).toBool();
use_disk_cache_ = settings.value(CollectionSettings::kSettingsDiskCacheEnable, false).toBool(); use_disk_cache_ = settings.value(CollectionSettings::kSettingsDiskCacheEnable, false).toBool();
QPixmapCache::setCacheLimit(static_cast<int>(MaximumCacheSize(&settings, CollectionSettings::kSettingsCacheSize, CollectionSettings::kSettingsCacheSizeUnit, CollectionSettings::kSettingsCacheSizeDefault) / 1024)); QPixmapCache::setCacheLimit(static_cast<int>(MaximumCacheSize(&settings, CollectionSettings::kSettingsCacheSize, CollectionSettings::kSettingsCacheSizeUnit, CollectionSettings::kSettingsCacheSizeDefault) / 1024));
@@ -223,11 +226,13 @@ void CollectionModel::ReloadSettings() {
if (show_pretty_covers != options_current_.show_pretty_covers || if (show_pretty_covers != options_current_.show_pretty_covers ||
show_dividers != options_current_.show_dividers || show_dividers != options_current_.show_dividers ||
show_various_artists != options_current_.show_various_artists || show_various_artists != options_current_.show_various_artists ||
sort_behaviour != options_current_.sort_behaviour) { sort_skip_articles_for_artists != options_current_.sort_skip_articles_for_artists ||
sort_skip_articles_for_albums != options_current_.sort_skip_articles_for_albums) {
options_current_.show_pretty_covers = show_pretty_covers; options_current_.show_pretty_covers = show_pretty_covers;
options_current_.show_dividers = show_dividers; options_current_.show_dividers = show_dividers;
options_current_.show_various_artists = show_various_artists; options_current_.show_various_artists = show_various_artists;
options_current_.sort_behaviour = sort_behaviour; options_current_.sort_skip_articles_for_artists = sort_skip_articles_for_artists;
options_current_.sort_skip_articles_for_albums = sort_skip_articles_for_albums;
ScheduleReset(); ScheduleReset();
} }
@@ -695,7 +700,7 @@ CollectionItem *CollectionModel::CreateContainerItem(const GroupBy group_by, con
QString divider_key; QString divider_key;
if (options_active_.show_dividers && container_level == 0) { if (options_active_.show_dividers && container_level == 0) {
divider_key = DividerKey(group_by, song, SortText(group_by, song, options_active_.sort_behaviour)); divider_key = DividerKey(group_by, song, SortText(group_by, song, options_active_.sort_skip_articles_for_artists, options_active_.sort_skip_articles_for_albums));
if (!divider_key.isEmpty()) { if (!divider_key.isEmpty()) {
if (!divider_nodes_.contains(divider_key)) { if (!divider_nodes_.contains(divider_key)) {
CreateDividerItem(divider_key, DividerDisplayText(group_by, divider_key), parent); CreateDividerItem(divider_key, DividerDisplayText(group_by, divider_key), parent);
@@ -708,8 +713,8 @@ CollectionItem *CollectionModel::CreateContainerItem(const GroupBy group_by, con
CollectionItem *item = new CollectionItem(CollectionItem::Type::Container, parent); CollectionItem *item = new CollectionItem(CollectionItem::Type::Container, parent);
item->container_level = container_level; item->container_level = container_level;
item->container_key = container_key; item->container_key = container_key;
item->display_text = DisplayText(group_by, song, options_active_.sort_behaviour); item->display_text = DisplayText(group_by, song);
item->sort_text = SortText(group_by, song, options_active_.sort_behaviour); item->sort_text = SortText(group_by, song, options_active_.sort_skip_articles_for_artists, options_active_.sort_skip_articles_for_albums);
if (!divider_key.isEmpty()) { if (!divider_key.isEmpty()) {
item->sort_text.prepend(divider_key + QLatin1Char(' ')); item->sort_text.prepend(divider_key + QLatin1Char(' '));
} }
@@ -958,15 +963,15 @@ void CollectionModel::AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderR
} }
QString CollectionModel::DisplayText(const GroupBy group_by, const Song &song, const CollectionSettings::SortBehaviour sort_behaviour) { QString CollectionModel::DisplayText(const GroupBy group_by, const Song &song) {
switch (group_by) { switch (group_by) {
case GroupBy::AlbumArtist: case GroupBy::AlbumArtist:
return NameOrSortname(song.effective_albumartist(), song.albumartistsort(), sort_behaviour); return TextOrUnknown(song.effective_albumartist());
case GroupBy::Artist: case GroupBy::Artist:
return NameOrSortname(song.artist(), song.artistsort(), sort_behaviour); return TextOrUnknown(song.artist());
case GroupBy::Album: case GroupBy::Album:
return NameOrSortname(song.album(), song.albumsort(), sort_behaviour); return TextOrUnknown(song.album());
case GroupBy::AlbumDisc: case GroupBy::AlbumDisc:
return PrettyAlbumDisc(song.album(), song.disc()); return PrettyAlbumDisc(song.album(), song.disc());
case GroupBy::YearAlbum: case GroupBy::YearAlbum:
@@ -986,9 +991,9 @@ QString CollectionModel::DisplayText(const GroupBy group_by, const Song &song, c
case GroupBy::Genre: case GroupBy::Genre:
return TextOrUnknown(song.genre()); return TextOrUnknown(song.genre());
case GroupBy::Composer: case GroupBy::Composer:
return NameOrSortname(song.composer(), song.composersort(), sort_behaviour); return TextOrUnknown(song.composer());
case GroupBy::Performer: case GroupBy::Performer:
return NameOrSortname(song.performer(), song.performersort(), sort_behaviour); return TextOrUnknown(song.performer());
case GroupBy::Grouping: case GroupBy::Grouping:
return TextOrUnknown(song.grouping()); return TextOrUnknown(song.grouping());
case GroupBy::FileType: case GroupBy::FileType:
@@ -1010,26 +1015,6 @@ QString CollectionModel::DisplayText(const GroupBy group_by, const Song &song, c
} }
QString CollectionModel::NameOrSortname(const QString &name, const QString &sort_name, const CollectionSettings::SortBehaviour sort_behaviour) {
QString str;
switch (sort_behaviour) {
using namespace CollectionSettings;
case SortBehaviour::AsIs:
case SortBehaviour::SkipArticles:
case SortBehaviour::UseSortTagForSort:
str = name;
break;
case SortBehaviour::UseSortTagForDisplayAndSort:
str = sort_name;
break;
}
return TextOrUnknown(str);
}
QString CollectionModel::TextOrUnknown(const QString &text) { QString CollectionModel::TextOrUnknown(const QString &text) {
if (text.isEmpty()) return tr("Unknown"); if (text.isEmpty()) return tr("Unknown");
@@ -1084,25 +1069,25 @@ QString CollectionModel::PrettyFormat(const Song &song) {
} }
QString CollectionModel::SortText(const GroupBy group_by, const Song &song, const CollectionSettings::SortBehaviour sort_behaviour) { QString CollectionModel::SortText(const GroupBy group_by, const Song &song, const bool sort_skip_articles_for_artists, const bool sort_skip_articles_for_albums) {
switch (group_by) { switch (group_by) {
case GroupBy::AlbumArtist: case GroupBy::AlbumArtist:
return SortTextForName(song.effective_albumartist(), song.albumartistsort(), sort_behaviour); return SortTextForName(song.effective_albumartist_with_sort(), sort_skip_articles_for_artists);
case GroupBy::Artist: case GroupBy::Artist:
return SortTextForName(song.artist(), song.artistsort(), sort_behaviour); return SortTextForName(song.effective_artistsort(), sort_skip_articles_for_artists);
case GroupBy::Album: case GroupBy::Album:
return SortTextForName(song.album(), song.albumsort(), sort_behaviour); return SortTextForName(song.effective_albumsort(), sort_skip_articles_for_albums);
case GroupBy::AlbumDisc: case GroupBy::AlbumDisc:
return song.album() + SortTextForNumber(std::max(0, song.disc())); return SortTextForName(song.effective_albumsort(), sort_skip_articles_for_albums) + SortTextForNumber(std::max(0, song.disc()));
case GroupBy::YearAlbum: case GroupBy::YearAlbum:
return SortTextForNumber(std::max(0, song.year())) + song.grouping() + song.album(); return SortTextForNumber(std::max(0, song.year())) + song.grouping() + SortTextForName(song.effective_albumsort(), sort_skip_articles_for_albums);
case GroupBy::YearAlbumDisc: case GroupBy::YearAlbumDisc:
return SortTextForNumber(std::max(0, song.year())) + song.album() + SortTextForNumber(std::max(0, song.disc())); return SortTextForNumber(std::max(0, song.year())) + SortTextForName(song.effective_albumsort(), sort_skip_articles_for_albums) + SortTextForNumber(std::max(0, song.disc()));
case GroupBy::OriginalYearAlbum: case GroupBy::OriginalYearAlbum:
return SortTextForNumber(std::max(0, song.effective_originalyear())) + song.grouping() + song.album(); return SortTextForNumber(std::max(0, song.effective_originalyear())) + song.grouping() + SortTextForName(song.effective_albumsort(), sort_skip_articles_for_albums);
case GroupBy::OriginalYearAlbumDisc: case GroupBy::OriginalYearAlbumDisc:
return SortTextForNumber(std::max(0, song.effective_originalyear())) + song.album() + SortTextForNumber(std::max(0, song.disc())); return SortTextForNumber(std::max(0, song.effective_originalyear())) + SortTextForName(song.effective_albumsort(), sort_skip_articles_for_albums) + SortTextForNumber(std::max(0, song.disc()));
case GroupBy::Disc: case GroupBy::Disc:
return SortTextForNumber(std::max(0, song.disc())); return SortTextForNumber(std::max(0, song.disc()));
case GroupBy::Year: case GroupBy::Year:
@@ -1110,13 +1095,13 @@ QString CollectionModel::SortText(const GroupBy group_by, const Song &song, cons
case GroupBy::OriginalYear: case GroupBy::OriginalYear:
return SortTextForNumber(std::max(0, song.effective_originalyear())) + QLatin1Char(' '); return SortTextForNumber(std::max(0, song.effective_originalyear())) + QLatin1Char(' ');
case GroupBy::Genre: case GroupBy::Genre:
return SortTextForName(song.genre(), song.genre(), sort_behaviour); return SortText(song.genre());
case GroupBy::Composer: case GroupBy::Composer:
return SortTextForName(song.composer(), song.composersort(), sort_behaviour); return SortTextForName(song.effective_composersort(), sort_skip_articles_for_artists);
case GroupBy::Performer: case GroupBy::Performer:
return SortTextForName(song.performer(), song.performersort(), sort_behaviour); return SortTextForName(song.effective_performersort(), sort_skip_articles_for_artists);
case GroupBy::Grouping: case GroupBy::Grouping:
return SortTextForName(song.grouping(), song.grouping(), sort_behaviour); return SortText(song.grouping());
case GroupBy::FileType: case GroupBy::FileType:
return song.TextForFiletype(); return song.TextForFiletype();
case GroupBy::Format: case GroupBy::Format:
@@ -1151,43 +1136,9 @@ QString CollectionModel::SortText(QString text) {
} }
QString CollectionModel::SortTextSkipArticles(QString name) { QString CollectionModel::SortTextForName(const QString &name, const bool sort_skip_articles) {
name = SortText(name); return sort_skip_articles ? SkipArticles(SortText(name)) : SortText(name);
for (const auto &i : Song::kArticles) {
if (name.startsWith(i)) {
qint64 ilen = i.length();
name = name.right(name.length() - ilen) + ", "_L1 + i.left(ilen - 1);
break;
}
}
return name;
}
QString CollectionModel::SortTextForName(const QString &name, const QString &sort_name, const CollectionSettings::SortBehaviour sort_behaviour) {
QString str;
switch (sort_behaviour) {
using namespace CollectionSettings;
case SortBehaviour::AsIs:
str = SortText(name);
break;
case SortBehaviour::SkipArticles:
str = SortTextSkipArticles(name);
break;
case SortBehaviour::UseSortTagForSort:
str = SortText(sort_name);
break;
case SortBehaviour::UseSortTagForDisplayAndSort:
str = SortText(sort_name);
break;
}
return str;
} }
@@ -1218,6 +1169,20 @@ QString CollectionModel::SortTextForBitrate(const int bitrate) {
} }
QString CollectionModel::SkipArticles(QString name) {
for (const auto &i : Song::kArticles) {
if (name.startsWith(i)) {
qint64 ilen = i.length();
name = name.right(name.length() - ilen) + ", "_L1 + i.left(ilen - 1);
break;
}
}
return name;
}
bool CollectionModel::IsSongTitleDataChanged(const Song &song1, const Song &song2) { bool CollectionModel::IsSongTitleDataChanged(const Song &song1, const Song &song2) {
return song1.url() != song2.url() || return song1.url() != song2.url() ||

View File

@@ -1,6 +1,6 @@
/* /*
* Strawberry Music Player * Strawberry Music Player
* Copyright 2018-2024, Jonas Kvinge <jonas@jkvinge.net> * Copyright 2018-2025, Jonas Kvinge <jonas@jkvinge.net>
* *
* Strawberry is free software: you can redistribute it and/or modify * Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -52,7 +52,6 @@
#include "collectionmodelupdate.h" #include "collectionmodelupdate.h"
#include "collectionfilteroptions.h" #include "collectionfilteroptions.h"
#include "collectionitem.h" #include "collectionitem.h"
#include "constants/collectionsettings.h"
class QTimer; class QTimer;
class Settings; class Settings;
@@ -130,14 +129,16 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
show_dividers(true), show_dividers(true),
show_pretty_covers(true), show_pretty_covers(true),
show_various_artists(true), show_various_artists(true),
sort_behaviour(CollectionSettings::SortBehaviour::SkipArticles), sort_skip_articles_for_artists(false),
sort_skip_articles_for_albums(false),
separate_albums_by_grouping(false) {} separate_albums_by_grouping(false) {}
Grouping group_by; Grouping group_by;
bool show_dividers; bool show_dividers;
bool show_pretty_covers; bool show_pretty_covers;
bool show_various_artists; bool show_various_artists;
CollectionSettings::SortBehaviour sort_behaviour; bool sort_skip_articles_for_artists;
bool sort_skip_articles_for_albums;
bool separate_albums_by_grouping; bool separate_albums_by_grouping;
CollectionFilterOptions filter_options; CollectionFilterOptions filter_options;
}; };
@@ -177,22 +178,21 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
QMimeData *mimeData(const QModelIndexList &indexes) const override; QMimeData *mimeData(const QModelIndexList &indexes) const override;
// Utility functions for manipulating text // Utility functions for manipulating text
static QString DisplayText(const GroupBy group_by, const Song &song, const CollectionSettings::SortBehaviour sort_behaviour); QString DisplayText(const GroupBy group_by, const Song &song);
static QString NameOrSortname(const QString &name, const QString &sort_name, const CollectionSettings::SortBehaviour sort_behaviour);
static QString TextOrUnknown(const QString &text); static QString TextOrUnknown(const QString &text);
static QString PrettyYearAlbum(const int year, const QString &album); static QString PrettyYearAlbum(const int year, const QString &album);
static QString PrettyAlbumDisc(const QString &album, const int disc); static QString PrettyAlbumDisc(const QString &album, const int disc);
static QString PrettyYearAlbumDisc(const int year, const QString &album, const int disc); static QString PrettyYearAlbumDisc(const int year, const QString &album, const int disc);
static QString PrettyDisc(const int disc); static QString PrettyDisc(const int disc);
static QString PrettyFormat(const Song &song); static QString PrettyFormat(const Song &song);
QString SortText(const GroupBy group_by, const Song &song, const CollectionSettings::SortBehaviour sort_behaviour); QString SortText(const GroupBy group_by, const Song &song, const bool sort_skip_articles_for_artists, const bool sort_skip_articles_for_albums);
static QString SortText(QString text); static QString SortText(QString text);
static QString SortTextForName(const QString &name, const QString &sort_name, const CollectionSettings::SortBehaviour sort_behaviour); static QString SortTextForName(const QString &name, const bool sort_skip_articles);
static QString SortTextForNumber(const int number); static QString SortTextForNumber(const int number);
static QString SortTextSkipArticles(QString name);
static QString SortTextForSong(const Song &song); static QString SortTextForSong(const Song &song);
static QString SortTextForYear(const int year); static QString SortTextForYear(const int year);
static QString SortTextForBitrate(const int bitrate); static QString SortTextForBitrate(const int bitrate);
static QString SkipArticles(QString name);
static bool IsSongTitleDataChanged(const Song &song1, const Song &song2); static bool IsSongTitleDataChanged(const Song &song1, const Song &song2);
QString ContainerKey(const GroupBy group_by, const Song &song, bool &has_unique_album_identifier) const; QString ContainerKey(const GroupBy group_by, const Song &song, bool &has_unique_album_identifier) const;

View File

@@ -1,6 +1,6 @@
/* /*
* Strawberry Music Player * Strawberry Music Player
* Copyright 2024, Jonas Kvinge <jonas@jkvinge.net> * Copyright 2024-2025, Jonas Kvinge <jonas@jkvinge.net>
* *
* Strawberry is free software: you can redistribute it and/or modify * Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -24,18 +24,20 @@ namespace CollectionSettings {
constexpr char kSettingsGroup[] = "Collection"; constexpr char kSettingsGroup[] = "Collection";
constexpr char kStartupScan[] = "startup_scan";
constexpr char kMonitor[] = "monitor";
constexpr char kSongTracking[] = "song_tracking";
constexpr char kMarkSongsUnavailable[] = "mark_songs_unavailable";
constexpr char kSongENUR128LoudnessAnalysis[] = "song_ebur128_loudness_analysis";
constexpr char kExpireUnavailableSongs[] = "expire_unavailable_songs";
constexpr char kCoverArtPatterns[] = "cover_art_patterns";
constexpr char kAutoOpen[] = "auto_open"; constexpr char kAutoOpen[] = "auto_open";
constexpr char kShowDividers[] = "show_dividers"; constexpr char kShowDividers[] = "show_dividers";
constexpr char kPrettyCovers[] = "pretty_covers"; constexpr char kPrettyCovers[] = "pretty_covers";
constexpr char kVariousArtists[] = "various_artists"; constexpr char kVariousArtists[] = "various_artists";
constexpr char kSortBehaviour[] = "sort_behaviour"; constexpr char kSkipArticlesForArtists[] = "skip_articles_for_artists";
constexpr char kStartupScan[] = "startup_scan"; constexpr char kSkipArticlesForAlbums[] = "skip_articles_for_albums";
constexpr char kMonitor[] = "monitor"; constexpr char kShowSortText[] = "show_sort_text";
constexpr char kSongTracking[] = "song_tracking";
constexpr char kSongENUR128LoudnessAnalysis[] = "song_ebur128_loudness_analysis";
constexpr char kMarkSongsUnavailable[] = "mark_songs_unavailable";
constexpr char kExpireUnavailableSongs[] = "expire_unavailable_songs";
constexpr char kCoverArtPatterns[] = "cover_art_patterns";
constexpr char kSettingsCacheSize[] = "cache_size"; constexpr char kSettingsCacheSize[] = "cache_size";
constexpr char kSettingsCacheSizeUnit[] = "cache_size_unit"; constexpr char kSettingsCacheSizeUnit[] = "cache_size_unit";
constexpr char kSettingsDiskCacheEnable[] = "disk_cache_enable"; constexpr char kSettingsDiskCacheEnable[] = "disk_cache_enable";
@@ -50,13 +52,6 @@ constexpr char kOverwriteRating[] = "overwrite_rating";
constexpr char kDeleteFiles[] = "delete_files"; constexpr char kDeleteFiles[] = "delete_files";
constexpr char kLastPath[] = "last_path"; constexpr char kLastPath[] = "last_path";
enum class SortBehaviour {
AsIs = 1,
SkipArticles = 2,
UseSortTagForSort = 3,
UseSortTagForDisplayAndSort = 4
};
enum class CacheSizeUnit { enum class CacheSizeUnit {
KB, KB,
MB, MB,

View File

@@ -2,7 +2,7 @@
* Strawberry Music Player * Strawberry Music Player
* This file was part of Clementine. * This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com> * Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2024, Jonas Kvinge <jonas@jkvinge.net> * Copyright 2018-2025, Jonas Kvinge <jonas@jkvinge.net>
* *
* Strawberry is free software: you can redistribute it and/or modify * Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -349,11 +349,6 @@ struct Song::Private : public QSharedData {
bool init_from_file_; // Whether this song was loaded from a file using taglib. bool init_from_file_; // Whether this song was loaded from a file using taglib.
bool suspicious_tags_; // Whether our encoding guesser thinks these tags might be incorrectly encoded. bool suspicious_tags_; // Whether our encoding guesser thinks these tags might be incorrectly encoded.
QString title_sortable_;
QString album_sortable_;
QString artist_sortable_;
QString albumartist_sortable_;
QUrl stream_url_; // Temporary stream URL set by the URL handler. QUrl stream_url_; // Temporary stream URL set by the URL handler.
}; };
@@ -529,23 +524,18 @@ QString *Song::mutable_musicbrainz_work_id() { return &d->musicbrainz_work_id_;
bool Song::init_from_file() const { return d->init_from_file_; } bool Song::init_from_file() const { return d->init_from_file_; }
const QString &Song::title_sortable() const { return d->title_sortable_; }
const QString &Song::album_sortable() const { return d->album_sortable_; }
const QString &Song::artist_sortable() const { return d->artist_sortable_; }
const QString &Song::albumartist_sortable() const { return d->albumartist_sortable_; }
const QUrl &Song::stream_url() const { return d->stream_url_; } const QUrl &Song::stream_url() const { return d->stream_url_; }
void Song::set_id(const int id) { d->id_ = id; } void Song::set_id(const int id) { d->id_ = id; }
void Song::set_valid(const bool v) { d->valid_ = v; } void Song::set_valid(const bool v) { d->valid_ = v; }
void Song::set_title(const QString &v) { d->title_sortable_ = sortable(v); d->title_ = v; } void Song::set_title(const QString &v) { d->title_ = v; }
void Song::set_titlesort(const QString &v) { d->titlesort_ = v; } void Song::set_titlesort(const QString &v) { d->titlesort_ = v; }
void Song::set_album(const QString &v) { d->album_sortable_ = sortable(v); d->album_ = v; } void Song::set_album(const QString &v) { d->album_ = v; }
void Song::set_albumsort(const QString &v) { d->albumsort_ = v; } void Song::set_albumsort(const QString &v) { d->albumsort_ = v; }
void Song::set_artist(const QString &v) { d->artist_sortable_ = sortable(v); d->artist_ = v; } void Song::set_artist(const QString &v) { d->artist_ = v; }
void Song::set_artistsort(const QString &v) { d->artistsort_ = v; } void Song::set_artistsort(const QString &v) { d->artistsort_ = v; }
void Song::set_albumartist(const QString &v) { d->albumartist_sortable_ = sortable(v); d->albumartist_ = v; } void Song::set_albumartist(const QString &v) { d->albumartist_ = v; }
void Song::set_albumartistsort(const QString &v) { d->albumartistsort_ = v; } void Song::set_albumartistsort(const QString &v) { d->albumartistsort_ = v; }
void Song::set_track(const int v) { d->track_ = v; } void Song::set_track(const int v) { d->track_ = v; }
void Song::set_disc(const int v) { d->disc_ = v; } void Song::set_disc(const int v) { d->disc_ = v; }
@@ -624,44 +614,13 @@ void Song::set_init_from_file(const bool v) { d->init_from_file_ = v; }
void Song::set_stream_url(const QUrl &v) { d->stream_url_ = v; } void Song::set_stream_url(const QUrl &v) { d->stream_url_ = v; }
void Song::set_title(const TagLib::String &v) { void Song::set_title(const TagLib::String &v) { d->title_ = TagLibStringToQString(v); }
const QString title = TagLibStringToQString(v);
d->title_sortable_ = sortable(title);
d->title_ = title;
}
void Song::set_titlesort(const TagLib::String &v) { d->titlesort_ = TagLibStringToQString(v); } void Song::set_titlesort(const TagLib::String &v) { d->titlesort_ = TagLibStringToQString(v); }
void Song::set_album(const TagLib::String &v) { d->album_ = TagLibStringToQString(v); }
void Song::set_album(const TagLib::String &v) {
const QString album = TagLibStringToQString(v);
d->album_sortable_ = sortable(album);
d->album_ = album;
}
void Song::set_albumsort(const TagLib::String &v) { d->albumsort_ = TagLibStringToQString(v); } void Song::set_albumsort(const TagLib::String &v) { d->albumsort_ = TagLibStringToQString(v); }
void Song::set_artist(const TagLib::String &v) { d->artist_ = TagLibStringToQString(v); }
void Song::set_artist(const TagLib::String &v) {
const QString artist = TagLibStringToQString(v);
d->artist_sortable_ = sortable(artist);
d->artist_ = artist;
}
void Song::set_artistsort(const TagLib::String &v) { d->artistsort_ = TagLibStringToQString(v); } void Song::set_artistsort(const TagLib::String &v) { d->artistsort_ = TagLibStringToQString(v); }
void Song::set_albumartist(const TagLib::String &v) { d->albumartist_ = TagLibStringToQString(v); }
void Song::set_albumartist(const TagLib::String &v) {
const QString albumartist = TagLibStringToQString(v);
d->albumartist_sortable_ = sortable(albumartist);
d->albumartist_ = albumartist;
}
void Song::set_albumartistsort(const TagLib::String &v) { d->albumartistsort_ = TagLibStringToQString(v); } void Song::set_albumartistsort(const TagLib::String &v) { d->albumartistsort_ = TagLibStringToQString(v); }
void Song::set_genre(const TagLib::String &v) { d->genre_ = TagLibStringToQString(v); } void Song::set_genre(const TagLib::String &v) { d->genre_ = TagLibStringToQString(v); }
void Song::set_composer(const TagLib::String &v) { d->composer_ = TagLibStringToQString(v); } void Song::set_composer(const TagLib::String &v) { d->composer_ = TagLibStringToQString(v); }
@@ -688,12 +647,17 @@ void Song::set_musicbrainz_release_group_id(const TagLib::String &v) { d->musicb
void Song::set_musicbrainz_work_id(const TagLib::String &v) { d->musicbrainz_work_id_ = TagLibStringToQString(v).remove(u' ').replace(u';', u'/'); } void Song::set_musicbrainz_work_id(const TagLib::String &v) { d->musicbrainz_work_id_ = TagLibStringToQString(v).remove(u' ').replace(u';', u'/'); }
const QUrl &Song::effective_url() const { return !d->stream_url_.isEmpty() && d->stream_url_.isValid() ? d->stream_url_ : d->url_; } const QUrl &Song::effective_url() const { return !d->stream_url_.isEmpty() && d->stream_url_.isValid() ? d->stream_url_ : d->url_; }
const QString &Song::effective_titlesort() const { return d->titlesort_.isEmpty() ? d->title_ : d->titlesort_; }
const QString &Song::effective_albumartist() const { return d->albumartist_.isEmpty() ? d->artist_ : d->albumartist_; } const QString &Song::effective_albumartist() const { return d->albumartist_.isEmpty() ? d->artist_ : d->albumartist_; }
const QString &Song::effective_albumartist_sortable() const { return d->albumartist_.isEmpty() ? d->artist_sortable_ : d->albumartist_sortable_; } const QString &Song::effective_albumartistsort_only() const { return d->albumartistsort_.isEmpty() ? d->albumartist_ : d->albumartistsort_; }
const QString &Song::effective_albumartist_with_sort() const { return effective_albumartistsort_only().isEmpty() ? effective_artistsort() : effective_albumartistsort_only(); }
const QString &Song::effective_artistsort() const { return d->artistsort_.isEmpty() ? d->artist_ : d->artistsort_; }
const QString &Song::effective_album() const { return d->album_.isEmpty() ? d->title_ : d->album_; } const QString &Song::effective_album() const { return d->album_.isEmpty() ? d->title_ : d->album_; }
const QString &Song::effective_albumsort() const { return d->albumsort_.isEmpty() ? d->album_ : d->albumsort_; }
const QString &Song::effective_composersort() const { return d->composersort_.isEmpty() ? d->composer_ : d->composersort_; }
const QString &Song::effective_performersort() const { return d->performersort_.isEmpty() ? d->performer_ : d->performersort_; }
int Song::effective_originalyear() const { return d->originalyear_ < 0 ? d->year_ : d->originalyear_; } int Song::effective_originalyear() const { return d->originalyear_ < 0 ? d->year_ : d->originalyear_; }
const QString &Song::playlist_albumartist() const { return is_compilation() ? d->albumartist_ : effective_albumartist(); } const QString &Song::playlist_albumartist() const { return is_compilation() ? effective_albumartistsort_only() : effective_albumartist_with_sort(); }
const QString &Song::playlist_albumartist_sortable() const { return is_compilation() ? d->albumartist_sortable_ : effective_albumartist_sortable(); }
bool Song::is_metadata_good() const { return !d->url_.isEmpty() && !d->artist_.isEmpty() && !d->title_.isEmpty(); } bool Song::is_metadata_good() const { return !d->url_.isEmpty() && !d->artist_.isEmpty() && !d->title_.isEmpty(); }
bool Song::is_local_collection_song() const { return d->source_ == Source::Collection; } bool Song::is_local_collection_song() const { return d->source_ == Source::Collection; }
@@ -853,21 +817,6 @@ bool Song::save_embedded_cover_supported(const FileType filetype) {
} }
QString Song::sortable(const QString &v) {
QString copy = v.toLower();
for (const auto &i : kArticles) {
if (copy.startsWith(i)) {
qint64 ilen = i.length();
return copy.right(copy.length() - ilen) + u", "_s + copy.left(ilen - 1);
}
}
return copy;
}
int Song::ColumnIndex(const QString &field) { int Song::ColumnIndex(const QString &field) {
return static_cast<int>(kRowIdColumns.indexOf(field)); return static_cast<int>(kRowIdColumns.indexOf(field));

View File

@@ -2,7 +2,7 @@
* Strawberry Music Player * Strawberry Music Player
* This file was part of Clementine. * This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com> * Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2024, Jonas Kvinge <jonas@jkvinge.net> * Copyright 2018-2025, Jonas Kvinge <jonas@jkvinge.net>
* *
* Strawberry is free software: you can redistribute it and/or modify * Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -256,11 +256,6 @@ class Song {
bool init_from_file() const; bool init_from_file() const;
const QString &title_sortable() const;
const QString &album_sortable() const;
const QString &artist_sortable() const;
const QString &albumartist_sortable() const;
const QUrl &stream_url() const; const QUrl &stream_url() const;
// Setters // Setters
@@ -385,12 +380,17 @@ class Song {
void set_musicbrainz_work_id(const TagLib::String &v); void set_musicbrainz_work_id(const TagLib::String &v);
const QUrl &effective_url() const; const QUrl &effective_url() const;
const QString &effective_titlesort() const;
const QString &effective_albumartist() const; const QString &effective_albumartist() const;
const QString &effective_albumartist_sortable() const; const QString &effective_albumartistsort_only() const;
const QString &effective_albumartist_with_sort() const;
const QString &effective_artistsort() const;
const QString &effective_album() const; const QString &effective_album() const;
const QString &effective_albumsort() const;
const QString &effective_composersort() const;
const QString &effective_performersort() const;
int effective_originalyear() const; int effective_originalyear() const;
const QString &playlist_albumartist() const; const QString &playlist_albumartist() const;
const QString &playlist_albumartist_sortable() const;
bool is_metadata_good() const; bool is_metadata_good() const;
bool is_local_collection_song() const; bool is_local_collection_song() const;
@@ -555,9 +555,6 @@ class Song {
private: private:
struct Private; struct Private;
static QString sortable(const QString &v);
QSharedDataPointer<Private> d; QSharedDataPointer<Private> d;
}; };

View File

@@ -378,12 +378,12 @@ QVariant Playlist::data(const QModelIndex &idx, const int role) const {
case Column::DateCreated: return song.ctime(); case Column::DateCreated: return song.ctime();
case Column::Comment: case Column::Comment:
if (role == Qt::DisplayRole) return song.comment().simplified(); if (role == Qt::DisplayRole) return song.comment().simplified();
return song.comment(); return song.comment();
case Column::EBUR128IntegratedLoudness: return song.ebur128_integrated_loudness_lufs().has_value() ? song.ebur128_integrated_loudness_lufs().value() : QVariant(); case Column::EBUR128IntegratedLoudness: return song.ebur128_integrated_loudness_lufs().has_value() ? song.ebur128_integrated_loudness_lufs().value() : QVariant();
case Column::EBUR128LoudnessRange: return song.ebur128_loudness_range_lu().has_value() ? song.ebur128_loudness_range_lu().value() : QVariant(); case Column::EBUR128LoudnessRange: return song.ebur128_loudness_range_lu().has_value() ? song.ebur128_loudness_range_lu().value() : QVariant();
case Column::Source: return QVariant::fromValue(song.source()); case Column::Source: return QVariant::fromValue(song.source());
@@ -1346,118 +1346,126 @@ QMimeData *Playlist::mimeData(const QModelIndexList &indexes) const {
} }
namespace {
inline bool CompareStr(const QString &a, const QString &b) {
return QString::localeAwareCompare(a.toLower(), b.toLower()) < 0;
}
template<typename T>
inline bool CompareVal(const T &a, const T &b) {
return a < b;
}
} // namespace
bool Playlist::CompareItems(const Column column, const Qt::SortOrder order, PlaylistItemPtr _a, PlaylistItemPtr _b) { bool Playlist::CompareItems(const Column column, const Qt::SortOrder order, PlaylistItemPtr _a, PlaylistItemPtr _b) {
PlaylistItemPtr a = order == Qt::AscendingOrder ? _a : _b; PlaylistItemPtr a = (order == Qt::AscendingOrder) ? _a : _b;
PlaylistItemPtr b = order == Qt::AscendingOrder ? _b : _a; PlaylistItemPtr b = (order == Qt::AscendingOrder) ? _b : _a;
#define cmp(field) return a->EffectiveMetadata().field() < b->EffectiveMetadata().field() const auto &ma = a->EffectiveMetadata();
#define strcmp(field) return QString::localeAwareCompare(a->EffectiveMetadata().field().toLower(), b->EffectiveMetadata().field().toLower()) < 0; const auto &mb = b->EffectiveMetadata();
switch (column) { switch (column) {
case Column::Title: strcmp(title_sortable); case Column::Title: return CompareStr(ma.effective_titlesort(), mb.effective_titlesort());
case Column::TitleSort: strcmp(titlesort); case Column::TitleSort: return CompareStr(ma.titlesort(), mb.titlesort());
case Column::Artist: strcmp(artist_sortable); case Column::Artist: return CompareStr(ma.effective_artistsort(), mb.effective_artistsort());
case Column::ArtistSort: strcmp(artistsort); case Column::ArtistSort: return CompareStr(ma.artistsort(), mb.artistsort());
case Column::Album: strcmp(album_sortable); case Column::Album: return CompareStr(ma.effective_albumsort(), mb.effective_albumsort());
case Column::AlbumSort: strcmp(albumsort); case Column::AlbumSort: return CompareStr(ma.albumsort(), mb.albumsort());
case Column::Length: cmp(length_nanosec); case Column::Length: return CompareVal(ma.length_nanosec(), mb.length_nanosec());
case Column::Track: cmp(track); case Column::Track: return CompareVal(ma.track(), mb.track());
case Column::Disc: cmp(disc); case Column::Disc: return CompareVal(ma.disc(), mb.disc());
case Column::Year: cmp(year); case Column::Year: return CompareVal(ma.year(), mb.year());
case Column::OriginalYear: cmp(effective_originalyear); case Column::OriginalYear: return CompareVal(ma.effective_originalyear(), mb.effective_originalyear());
case Column::Genre: strcmp(genre); case Column::Genre: return CompareStr(ma.genre(), mb.genre());
case Column::AlbumArtist: strcmp(playlist_albumartist_sortable); case Column::AlbumArtist: return CompareStr(ma.playlist_albumartist(), mb.playlist_albumartist());
case Column::AlbumArtistSort: strcmp(albumartistsort); case Column::AlbumArtistSort: return CompareStr(ma.albumartistsort(), mb.albumartistsort());
case Column::Composer: strcmp(composer); case Column::Composer: return CompareStr(ma.effective_composersort(), mb.effective_composersort());
case Column::ComposerSort: strcmp(composersort); case Column::ComposerSort: return CompareStr(ma.composersort(), mb.composersort());
case Column::Performer: strcmp(performer); case Column::Performer: return CompareStr(ma.effective_performersort(), mb.effective_performersort());
case Column::PerformerSort: strcmp(performersort); case Column::PerformerSort: return CompareStr(ma.performersort(), mb.performersort());
case Column::Grouping: strcmp(grouping); case Column::Grouping: return CompareStr(ma.grouping(), mb.grouping());
case Column::PlayCount: cmp(playcount); case Column::PlayCount: return CompareVal(ma.playcount(), mb.playcount());
case Column::SkipCount: cmp(skipcount); case Column::SkipCount: return CompareVal(ma.skipcount(), mb.skipcount());
case Column::LastPlayed: cmp(lastplayed); case Column::LastPlayed: return CompareVal(ma.lastplayed(), mb.lastplayed());
case Column::Bitrate: cmp(bitrate); case Column::Bitrate: return CompareVal(ma.bitrate(), mb.bitrate());
case Column::Samplerate: cmp(samplerate); case Column::Samplerate: return CompareVal(ma.samplerate(), mb.samplerate());
case Column::Bitdepth: cmp(bitdepth); case Column::Bitdepth: return CompareVal(ma.bitdepth(), mb.bitdepth());
case Column::URL: case Column::URL: return CompareStr(a->OriginalUrl().path(), b->OriginalUrl().path());
return QString::localeAwareCompare(a->OriginalUrl().path(), b->OriginalUrl().path()) < 0; case Column::BaseFilename: return CompareVal(ma.basefilename(), mb.basefilename());
case Column::BaseFilename: cmp(basefilename); case Column::Filesize: return CompareVal(ma.filesize(), mb.filesize());
case Column::Filesize: cmp(filesize); case Column::Filetype: return CompareVal(ma.filetype(), mb.filetype());
case Column::Filetype: cmp(filetype); case Column::DateModified: return CompareVal(ma.mtime(), mb.mtime());
case Column::DateModified: cmp(mtime); case Column::DateCreated: return CompareVal(ma.ctime(), mb.ctime());
case Column::DateCreated: cmp(ctime);
case Column::Comment: strcmp(comment); case Column::Comment: return CompareStr(ma.comment(), mb.comment());
case Column::Source: cmp(source); case Column::Source: return CompareVal(ma.source(), mb.source());
case Column::Rating: cmp(rating); case Column::Rating: return CompareVal(ma.rating(), mb.rating());
case Column::HasCUE: cmp(has_cue); case Column::HasCUE: return CompareVal(ma.has_cue(), mb.has_cue());
case Column::EBUR128IntegratedLoudness: cmp(ebur128_integrated_loudness_lufs); case Column::EBUR128IntegratedLoudness: return CompareVal(ma.ebur128_integrated_loudness_lufs(), mb.ebur128_integrated_loudness_lufs());
case Column::EBUR128LoudnessRange: cmp(ebur128_loudness_range_lu); case Column::EBUR128LoudnessRange: return CompareVal(ma.ebur128_loudness_range_lu(), mb.ebur128_loudness_range_lu());
case Column::Mood: case Column::Mood:
case Column::ColumnCount: case Column::ColumnCount:
break; break;
} }
#undef cmp
#undef strcmp
return false; return false;
} }
QString Playlist::column_name(const Column column) { QString Playlist::column_name(const Column column) {
switch (column) { switch (column) {
case Column::Title: return tr("Title"); case Column::Title: return tr("Title");
case Column::TitleSort: return tr("Title Sort"); case Column::TitleSort: return tr("Title Sort");
case Column::Artist: return tr("Artist"); case Column::Artist: return tr("Artist");
case Column::ArtistSort: return tr("Artist Sort"); case Column::ArtistSort: return tr("Artist Sort");
case Column::Album: return tr("Album"); case Column::Album: return tr("Album");
case Column::AlbumSort: return tr("Album Sort"); case Column::AlbumSort: return tr("Album Sort");
case Column::Track: return tr("Track"); case Column::Track: return tr("Track");
case Column::Disc: return tr("Disc"); case Column::Disc: return tr("Disc");
case Column::Length: return tr("Length"); case Column::Length: return tr("Length");
case Column::Year: return tr("Year"); case Column::Year: return tr("Year");
case Column::OriginalYear: return tr("Original Year"); case Column::OriginalYear: return tr("Original Year");
case Column::Genre: return tr("Genre"); case Column::Genre: return tr("Genre");
case Column::AlbumArtist: return tr("Album Artist"); case Column::AlbumArtist: return tr("Album Artist");
case Column::AlbumArtistSort: return tr("Album Artist Sort"); case Column::AlbumArtistSort: return tr("Album Artist Sort");
case Column::Composer: return tr("Composer"); case Column::Composer: return tr("Composer");
case Column::ComposerSort: return tr("Composer Sort"); case Column::ComposerSort: return tr("Composer Sort");
case Column::Performer: return tr("Performer"); case Column::Performer: return tr("Performer");
case Column::PerformerSort: return tr("Performer Sort"); case Column::PerformerSort: return tr("Performer Sort");
case Column::Grouping: return tr("Grouping"); case Column::Grouping: return tr("Grouping");
case Column::PlayCount: return tr("Play Count"); case Column::PlayCount: return tr("Play Count");
case Column::SkipCount: return tr("Skip Count"); case Column::SkipCount: return tr("Skip Count");
case Column::LastPlayed: return tr("Last Played"); case Column::LastPlayed: return tr("Last Played");
case Column::Samplerate: return tr("Sample Rate"); case Column::Samplerate: return tr("Sample Rate");
case Column::Bitdepth: return tr("Bit Depth"); case Column::Bitdepth: return tr("Bit Depth");
case Column::Bitrate: return tr("Bitrate"); case Column::Bitrate: return tr("Bitrate");
case Column::URL: return tr("URL"); case Column::URL: return tr("URL");
case Column::BaseFilename: return tr("File Name (without path)"); case Column::BaseFilename: return tr("File Name (without path)");
case Column::Filesize: return tr("File Size"); case Column::Filesize: return tr("File Size");
case Column::Filetype: return tr("File Type"); case Column::Filetype: return tr("File Type");
case Column::DateModified: return tr("Date Modified"); case Column::DateModified: return tr("Date Modified");
case Column::DateCreated: return tr("Date Created"); case Column::DateCreated: return tr("Date Created");
case Column::Comment: return tr("Comment"); case Column::Comment: return tr("Comment");
case Column::Source: return tr("Source"); case Column::Source: return tr("Source");
case Column::Mood: return tr("Mood"); case Column::Mood: return tr("Mood");
case Column::Rating: return tr("Rating"); case Column::Rating: return tr("Rating");
case Column::HasCUE: return tr("CUE"); case Column::HasCUE: return tr("CUE");
case Column::EBUR128IntegratedLoudness: return tr("Integrated Loudness"); case Column::EBUR128IntegratedLoudness: return tr("Integrated Loudness");
case Column::EBUR128LoudnessRange: return tr("Loudness Range"); case Column::EBUR128LoudnessRange: return tr("Loudness Range");
case Column::ColumnCount: case Column::ColumnCount:
break; break;

View File

@@ -2,7 +2,7 @@
* Strawberry Music Player * Strawberry Music Player
* This file was part of Clementine. * This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com> * Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2024, Jonas Kvinge <jonas@jkvinge.net> * Copyright 2018-2025, Jonas Kvinge <jonas@jkvinge.net>
* *
* Strawberry is free software: you can redistribute it and/or modify * Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -83,15 +83,9 @@ CollectionSettingsPage::CollectionSettingsPage(SettingsDialog *dialog,
ui_->setupUi(this); ui_->setupUi(this);
ui_->list->setItemDelegate(new NativeSeparatorsDelegate(this)); ui_->list->setItemDelegate(new NativeSeparatorsDelegate(this));
// Icons
setWindowIcon(IconLoader::Load(u"library-music"_s, true, 0, 32)); setWindowIcon(IconLoader::Load(u"library-music"_s, true, 0, 32));
ui_->add_directory->setIcon(IconLoader::Load(u"document-open-folder"_s)); ui_->add_directory->setIcon(IconLoader::Load(u"document-open-folder"_s));
ui_->combobox_sort->setItemData(0, static_cast<int>(SortBehaviour::AsIs));
ui_->combobox_sort->setItemData(1, static_cast<int>(SortBehaviour::SkipArticles));
ui_->combobox_sort->setItemData(2, static_cast<int>(SortBehaviour::UseSortTagForSort));
ui_->combobox_sort->setItemData(3, static_cast<int>(SortBehaviour::UseSortTagForDisplayAndSort));
ui_->combobox_cache_size->addItem(u"KB"_s, static_cast<int>(CacheSizeUnit::KB)); ui_->combobox_cache_size->addItem(u"KB"_s, static_cast<int>(CacheSizeUnit::KB));
ui_->combobox_cache_size->addItem(u"MB"_s, static_cast<int>(CacheSizeUnit::MB)); ui_->combobox_cache_size->addItem(u"MB"_s, static_cast<int>(CacheSizeUnit::MB));
@@ -153,21 +147,24 @@ void CollectionSettingsPage::Load() {
Settings s; Settings s;
s.beginGroup(kSettingsGroup); s.beginGroup(kSettingsGroup);
ui_->auto_open->setChecked(s.value(kAutoOpen, true).toBool());
ui_->show_dividers->setChecked(s.value(kShowDividers, true).toBool());
ui_->pretty_covers->setChecked(s.value(kPrettyCovers, true).toBool());
ui_->various_artists->setChecked(s.value(kVariousArtists, true).toBool());
ui_->combobox_sort->setCurrentIndex(ui_->combobox_sort->findData(s.value(kSortBehaviour, static_cast<int>(SortBehaviour::SkipArticles)).toInt()));
ui_->startup_scan->setChecked(s.value(kStartupScan, true).toBool()); ui_->startup_scan->setChecked(s.value(kStartupScan, true).toBool());
ui_->monitor->setChecked(s.value(kMonitor, true).toBool()); ui_->monitor->setChecked(s.value(kMonitor, true).toBool());
ui_->song_tracking->setChecked(s.value(kSongTracking, false).toBool()); ui_->song_tracking->setChecked(s.value(kSongTracking, false).toBool());
ui_->song_ebur128_loudness_analysis->setChecked(s.value(kSongENUR128LoudnessAnalysis, false).toBool());
ui_->mark_songs_unavailable->setChecked(ui_->song_tracking->isChecked() ? true : s.value(kMarkSongsUnavailable, true).toBool()); ui_->mark_songs_unavailable->setChecked(ui_->song_tracking->isChecked() ? true : s.value(kMarkSongsUnavailable, true).toBool());
ui_->song_ebur128_loudness_analysis->setChecked(s.value(kSongENUR128LoudnessAnalysis, false).toBool());
ui_->expire_unavailable_songs_days->setValue(s.value(kExpireUnavailableSongs, 60).toInt()); ui_->expire_unavailable_songs_days->setValue(s.value(kExpireUnavailableSongs, 60).toInt());
QStringList filters = s.value(kCoverArtPatterns, QStringList() << u"front"_s << u"cover"_s).toStringList(); QStringList filters = s.value(kCoverArtPatterns, QStringList() << u"front"_s << u"cover"_s).toStringList();
ui_->cover_art_patterns->setText(filters.join(u',')); ui_->cover_art_patterns->setText(filters.join(u','));
ui_->auto_open->setChecked(s.value(kAutoOpen, true).toBool());
ui_->show_dividers->setChecked(s.value(kShowDividers, true).toBool());
ui_->pretty_covers->setChecked(s.value(kPrettyCovers, true).toBool());
ui_->various_artists->setChecked(s.value(kVariousArtists, true).toBool());
ui_->checkbox_skip_articles_for_artists->setChecked(s.value(kSkipArticlesForArtists, true).toBool());
ui_->checkbox_skip_articles_for_albums->setChecked(s.value(kSkipArticlesForAlbums, false).toBool());
ui_->spinbox_cache_size->setValue(s.value(kSettingsCacheSize, kSettingsCacheSizeDefault).toInt()); ui_->spinbox_cache_size->setValue(s.value(kSettingsCacheSize, kSettingsCacheSizeDefault).toInt());
ui_->combobox_cache_size->setCurrentIndex(ui_->combobox_cache_size->findData(s.value(kSettingsCacheSizeUnit, static_cast<int>(CacheSizeUnit::MB)).toInt())); ui_->combobox_cache_size->setCurrentIndex(ui_->combobox_cache_size->findData(s.value(kSettingsCacheSizeUnit, static_cast<int>(CacheSizeUnit::MB)).toInt()));
ui_->checkbox_disk_cache->setChecked(s.value(kSettingsDiskCacheEnable, false).toBool()); ui_->checkbox_disk_cache->setChecked(s.value(kSettingsDiskCacheEnable, false).toBool());
@@ -197,24 +194,23 @@ void CollectionSettingsPage::Save() {
Settings s; Settings s;
s.beginGroup(kSettingsGroup); s.beginGroup(kSettingsGroup);
s.setValue(kStartupScan, ui_->startup_scan->isChecked());
s.setValue(kMonitor, ui_->monitor->isChecked());
s.setValue(kSongTracking, ui_->song_tracking->isChecked());
s.setValue(kMarkSongsUnavailable, ui_->song_tracking->isChecked() ? true : ui_->mark_songs_unavailable->isChecked());
s.setValue(kSongENUR128LoudnessAnalysis, ui_->song_ebur128_loudness_analysis->isChecked());
s.setValue(kExpireUnavailableSongs, ui_->expire_unavailable_songs_days->value());
const QString filter_text = ui_->cover_art_patterns->text();
s.setValue(kCoverArtPatterns, filter_text.split(u',', Qt::SkipEmptyParts));
s.setValue(kAutoOpen, ui_->auto_open->isChecked()); s.setValue(kAutoOpen, ui_->auto_open->isChecked());
s.setValue(kShowDividers, ui_->show_dividers->isChecked()); s.setValue(kShowDividers, ui_->show_dividers->isChecked());
s.setValue(kPrettyCovers, ui_->pretty_covers->isChecked()); s.setValue(kPrettyCovers, ui_->pretty_covers->isChecked());
s.setValue(kVariousArtists, ui_->various_artists->isChecked()); s.setValue(kVariousArtists, ui_->various_artists->isChecked());
const SortBehaviour menu_sort = static_cast<SortBehaviour>(ui_->combobox_sort->currentData().toInt()); s.setValue(kSkipArticlesForArtists, ui_->checkbox_skip_articles_for_artists->isChecked());
s.setValue(kSortBehaviour, static_cast<int>(menu_sort)); s.setValue(kSkipArticlesForAlbums, ui_->checkbox_skip_articles_for_albums->isChecked());
s.setValue(kStartupScan, ui_->startup_scan->isChecked());
s.setValue(kMonitor, ui_->monitor->isChecked());
s.setValue(kSongTracking, ui_->song_tracking->isChecked());
s.setValue(kSongENUR128LoudnessAnalysis, ui_->song_ebur128_loudness_analysis->isChecked());
s.setValue(kMarkSongsUnavailable, ui_->song_tracking->isChecked() ? true : ui_->mark_songs_unavailable->isChecked());
s.setValue(kExpireUnavailableSongs, ui_->expire_unavailable_songs_days->value());
QString filter_text = ui_->cover_art_patterns->text();
const QStringList filters = filter_text.split(u',', Qt::SkipEmptyParts);
s.setValue(kCoverArtPatterns, filters);
s.setValue(kSettingsCacheSize, ui_->spinbox_cache_size->value()); s.setValue(kSettingsCacheSize, ui_->spinbox_cache_size->value());
s.setValue(kSettingsCacheSizeUnit, ui_->combobox_cache_size->currentData().toInt()); s.setValue(kSettingsCacheSizeUnit, ui_->combobox_cache_size->currentData().toInt());

View File

@@ -2,7 +2,7 @@
* Strawberry Music Player * Strawberry Music Player
* This file was part of Clementine. * This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com> * Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2024, Jonas Kvinge <jonas@jkvinge.net> * Copyright 2018-2025, Jonas Kvinge <jonas@jkvinge.net>
* *
* Strawberry is free software: you can redistribute it and/or modify * Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>604</width> <width>604</width>
<height>1035</height> <height>1112</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@@ -235,37 +235,18 @@ If there are no matches then it will use the largest image in the directory.</st
</property> </property>
</widget> </widget>
</item> </item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupbox_sort">
<property name="title">
<string>When sorting names like &quot;The Beatles&quot;...</string>
</property>
<layout class="QVBoxLayout" name="layout_sort">
<item> <item>
<widget class="QComboBox" name="combobox_sort"> <widget class="QCheckBox" name="checkbox_skip_articles_for_artists">
<item> <property name="text">
<property name="text"> <string>Skip leading articles (&quot;the&quot;, &quot;a&quot;, &quot;an&quot;) when sorting artists, composers and performers</string>
<string>Sort and show name as is</string> </property>
</property> </widget>
</item> </item>
<item> <item>
<property name="text"> <widget class="QCheckBox" name="checkbox_skip_articles_for_albums">
<string>Skip articles &quot;The, A, An&quot; for sorting but show name as is</string> <property name="text">
</property> <string>Skip leading articles (&quot;the&quot;, &quot;a&quot;, &quot;an&quot;) when sorting albums</string>
</item> </property>
<item>
<property name="text">
<string>Use sort tag for sorting and show name as is</string>
</property>
</item>
<item>
<property name="text">
<string>Use sort tag for sorting and display</string>
</property>
</item>
</widget> </widget>
</item> </item>
</layout> </layout>
@@ -551,7 +532,8 @@ If there are no matches then it will use the largest image in the directory.</st
<tabstop>show_dividers</tabstop> <tabstop>show_dividers</tabstop>
<tabstop>pretty_covers</tabstop> <tabstop>pretty_covers</tabstop>
<tabstop>various_artists</tabstop> <tabstop>various_artists</tabstop>
<tabstop>combobox_sort</tabstop> <tabstop>checkbox_skip_articles_for_artists</tabstop>
<tabstop>checkbox_skip_articles_for_albums</tabstop>
<tabstop>spinbox_cache_size</tabstop> <tabstop>spinbox_cache_size</tabstop>
<tabstop>combobox_cache_size</tabstop> <tabstop>combobox_cache_size</tabstop>
<tabstop>checkbox_disk_cache</tabstop> <tabstop>checkbox_disk_cache</tabstop>

View File

@@ -97,7 +97,7 @@ QStandardItem *StreamingSearchModel::BuildContainers(const Song &s, QStandardIte
} }
else { else {
display_text = CollectionModel::TextOrUnknown(s.effective_albumartist()); display_text = CollectionModel::TextOrUnknown(s.effective_albumartist());
sort_text = CollectionModel::SortTextSkipArticles(s.effective_albumartist()); sort_text = CollectionModel::SortTextForName(s.effective_albumartist_with_sort(), true);
} }
has_artist_icon = true; has_artist_icon = true;
break; break;
@@ -109,60 +109,60 @@ QStandardItem *StreamingSearchModel::BuildContainers(const Song &s, QStandardIte
} }
else { else {
display_text = CollectionModel::TextOrUnknown(s.artist()); display_text = CollectionModel::TextOrUnknown(s.artist());
sort_text = CollectionModel::SortTextSkipArticles(s.artist()); sort_text = CollectionModel::SortTextForName(s.effective_artistsort(), true);
} }
has_artist_icon = true; has_artist_icon = true;
break; break;
case CollectionModel::GroupBy::Album: case CollectionModel::GroupBy::Album:
display_text = CollectionModel::TextOrUnknown(s.album()); display_text = CollectionModel::TextOrUnknown(s.album());
sort_text = CollectionModel::SortTextSkipArticles(s.album()); sort_text = CollectionModel::SortTextForName(s.effective_albumsort(), false);
unique_tag = s.album_id(); unique_tag = s.album_id();
has_album_icon = true; has_album_icon = true;
break; break;
case CollectionModel::GroupBy::AlbumDisc:{ case CollectionModel::GroupBy::AlbumDisc:{
int disc = qMax(0, s.disc()); const int disc = std::max(0, s.disc());
display_text = CollectionModel::PrettyAlbumDisc(s.album(), disc); display_text = CollectionModel::PrettyAlbumDisc(s.album(), disc);
sort_text = s.album() + CollectionModel::SortTextForNumber(disc); sort_text = CollectionModel::SortTextForName(s.effective_albumsort(), false) + CollectionModel::SortTextForNumber(disc);
unique_tag = s.album_id(); unique_tag = s.album_id();
has_album_icon = true; has_album_icon = true;
break; break;
} }
case CollectionModel::GroupBy::YearAlbum:{ case CollectionModel::GroupBy::YearAlbum:{
int year = qMax(0, s.year()); const int year = std::max(0, s.year());
display_text = CollectionModel::PrettyYearAlbum(year, s.album()); display_text = CollectionModel::PrettyYearAlbum(year, s.album());
sort_text = CollectionModel::SortTextForNumber(year) + s.album(); sort_text = CollectionModel::SortTextForNumber(year) + CollectionModel::SortTextForName(s.effective_albumsort(), false);
unique_tag = s.album_id(); unique_tag = s.album_id();
has_album_icon = true; has_album_icon = true;
break; break;
} }
case CollectionModel::GroupBy::YearAlbumDisc:{ case CollectionModel::GroupBy::YearAlbumDisc:{
int year = qMax(0, s.year()); const int year = std::max(0, s.year());
int disc = qMax(0, s.disc()); const int disc = std::max(0, s.disc());
display_text = CollectionModel::PrettyYearAlbumDisc(year, s.album(), disc); display_text = CollectionModel::PrettyYearAlbumDisc(year, s.album(), disc);
sort_text = CollectionModel::SortTextForNumber(year) + s.album() + CollectionModel::SortTextForNumber(disc); sort_text = CollectionModel::SortTextForNumber(year) + CollectionModel::SortTextForName(s.effective_albumsort(), false) + CollectionModel::SortTextForNumber(disc);
unique_tag = s.album_id(); unique_tag = s.album_id();
has_album_icon = true; has_album_icon = true;
break; break;
} }
case CollectionModel::GroupBy::OriginalYearAlbum:{ case CollectionModel::GroupBy::OriginalYearAlbum:{
int year = qMax(0, s.effective_originalyear()); const int year = std::max(0, s.effective_originalyear());
display_text = CollectionModel::PrettyYearAlbum(year, s.album()); display_text = CollectionModel::PrettyYearAlbum(year, s.album());
sort_text = CollectionModel::SortTextForNumber(year) + s.album(); sort_text = CollectionModel::SortTextForNumber(year) + CollectionModel::SortTextForName(s.effective_albumsort(), false);
unique_tag = s.album_id(); unique_tag = s.album_id();
has_album_icon = true; has_album_icon = true;
break; break;
} }
case CollectionModel::GroupBy::OriginalYearAlbumDisc:{ case CollectionModel::GroupBy::OriginalYearAlbumDisc:{
const int year = qMax(0, s.effective_originalyear()); const int year = std::max(0, s.effective_originalyear());
const int disc = qMax(0, s.disc()); const int disc = std::max(0, s.disc());
display_text = CollectionModel::PrettyYearAlbumDisc(year, s.album(), disc); display_text = CollectionModel::PrettyYearAlbumDisc(year, s.album(), disc);
sort_text = CollectionModel::SortTextForNumber(year) + s.album() + CollectionModel::SortTextForNumber(disc); sort_text = CollectionModel::SortTextForNumber(year) + CollectionModel::SortTextForName(s.effective_albumsort(), false) + CollectionModel::SortTextForNumber(disc);
unique_tag = s.album_id(); unique_tag = s.album_id();
has_album_icon = true; has_album_icon = true;
break; break;
@@ -170,7 +170,7 @@ QStandardItem *StreamingSearchModel::BuildContainers(const Song &s, QStandardIte
case CollectionModel::GroupBy::Disc: case CollectionModel::GroupBy::Disc:
display_text = CollectionModel::PrettyDisc(s.disc()); display_text = CollectionModel::PrettyDisc(s.disc());
sort_text = CollectionModel::SortTextSkipArticles(display_text); sort_text = CollectionModel::SortText(display_text);
has_album_icon = true; has_album_icon = true;
break; break;
@@ -190,25 +190,25 @@ QStandardItem *StreamingSearchModel::BuildContainers(const Song &s, QStandardIte
case CollectionModel::GroupBy::Genre: case CollectionModel::GroupBy::Genre:
display_text = CollectionModel::TextOrUnknown(s.genre()); display_text = CollectionModel::TextOrUnknown(s.genre());
sort_text = CollectionModel::SortTextSkipArticles(s.genre()); sort_text = CollectionModel::SortText(s.genre());
has_album_icon = true; has_album_icon = true;
break; break;
case CollectionModel::GroupBy::Composer: case CollectionModel::GroupBy::Composer:
display_text = CollectionModel::TextOrUnknown(s.composer()); display_text = CollectionModel::TextOrUnknown(s.composer());
sort_text = CollectionModel::SortTextSkipArticles(s.composer()); sort_text = CollectionModel::SortTextForName(s.composer(), true);
has_album_icon = true; has_album_icon = true;
break; break;
case CollectionModel::GroupBy::Performer: case CollectionModel::GroupBy::Performer:
display_text = CollectionModel::TextOrUnknown(s.performer()); display_text = CollectionModel::TextOrUnknown(s.performer());
sort_text = CollectionModel::SortTextSkipArticles(s.performer()); sort_text = CollectionModel::SortTextForName(s.performer(), true);
has_album_icon = true; has_album_icon = true;
break; break;
case CollectionModel::GroupBy::Grouping: case CollectionModel::GroupBy::Grouping:
display_text = CollectionModel::TextOrUnknown(s.grouping()); display_text = CollectionModel::TextOrUnknown(s.grouping());
sort_text = CollectionModel::SortTextSkipArticles(s.grouping()); sort_text = CollectionModel::SortText(s.grouping());
has_album_icon = true; has_album_icon = true;
break; break;