Update individual playlist columns, use enum class

This commit is contained in:
Jonas Kvinge
2024-06-20 22:52:27 +02:00
parent 5816d0bb12
commit 9f9c46e370
24 changed files with 670 additions and 541 deletions

View File

@@ -2,7 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018-2021, Jonas Kvinge <jonas@jkvinge.net>
* Copyright 2018-2024, Jonas Kvinge <jonas@jkvinge.net>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -97,25 +97,27 @@
using std::make_shared;
using namespace std::chrono_literals;
const char *Playlist::kSettingsGroup = "Playlist";
const char *Playlist::kCddaMimeType = "x-content/audio-cdda";
const char *Playlist::kRowsMimetype = "application/x-strawberry-playlist-rows";
const char *Playlist::kPlayNowMimetype = "application/x-strawberry-play-now";
const int Playlist::kInvalidSongPriority = 200;
const QRgb Playlist::kInvalidSongColor = qRgb(0xC0, 0xC0, 0xC0);
const int Playlist::kDynamicHistoryPriority = 100;
const QRgb Playlist::kDynamicHistoryColor = qRgb(0x80, 0x80, 0x80);
const char *Playlist::kSettingsGroup = "Playlist";
const int Playlist::kUndoStackSize = 20;
const int Playlist::kUndoItemLimit = 500;
const qint64 Playlist::kMinScrobblePointNsecs = 31LL * kNsecPerSec;
const qint64 Playlist::kMaxScrobblePointNsecs = 240LL * kNsecPerSec;
namespace {
const int Playlist::kMaxPlayedIndexes = 100;
constexpr int kInvalidSongPriority = 200;
constexpr QRgb kInvalidSongColor = qRgb(0xC0, 0xC0, 0xC0);
constexpr int kDynamicHistoryPriority = 100;
constexpr QRgb kDynamicHistoryColor = qRgb(0x80, 0x80, 0x80);
constexpr qint64 kMinScrobblePointNsecs = 31LL * kNsecPerSec;
constexpr qint64 kMaxScrobblePointNsecs = 240LL * kNsecPerSec;
constexpr int kMaxPlayedIndexes = 100;
} // namespace
Playlist::Playlist(SharedPtr<PlaylistBackend> backend, SharedPtr<TaskManager> task_manager, SharedPtr<CollectionBackend> collection_backend, const int id, const QString &special_type, const bool favorite, QObject *parent)
: QAbstractListModel(parent),
@@ -137,9 +139,8 @@ Playlist::Playlist(SharedPtr<PlaylistBackend> backend, SharedPtr<TaskManager> ta
cancel_restore_(false),
scrobbled_(false),
scrobble_point_(-1),
editing_(-1),
auto_sort_(false),
sort_column_(Column_Title),
sort_column_(Column::Title),
sort_order_(Qt::AscendingOrder) {
undo_stack_->setUndoLimit(kUndoStackSize);
@@ -186,7 +187,7 @@ void Playlist::InsertSongItems(const SongList &songs, const int pos, const bool
}
QVariant Playlist::headerData(int section, Qt::Orientation, int role) const {
QVariant Playlist::headerData(const int section, Qt::Orientation, const int role) const {
if (role != Qt::DisplayRole && role != Qt::ToolTipRole) return QVariant();
@@ -197,68 +198,69 @@ QVariant Playlist::headerData(int section, Qt::Orientation, int role) const {
}
bool Playlist::column_is_editable(Playlist::Column column) {
bool Playlist::column_is_editable(const Playlist::Column column) {
switch (column) {
case Column_Title:
case Column_Artist:
case Column_Album:
case Column_AlbumArtist:
case Column_Composer:
case Column_Performer:
case Column_Grouping:
case Column_Track:
case Column_Disc:
case Column_Year:
case Column_Genre:
case Column_Comment:
case Column::Title:
case Column::Artist:
case Column::Album:
case Column::AlbumArtist:
case Column::Composer:
case Column::Performer:
case Column::Grouping:
case Column::Track:
case Column::Disc:
case Column::Year:
case Column::Genre:
case Column::Comment:
return true;
default:
break;
}
return false;
}
bool Playlist::set_column_value(Song &song, Playlist::Column column, const QVariant &value) {
bool Playlist::set_column_value(Song &song, const Playlist::Column column, const QVariant &value) {
if (!song.IsEditable()) return false;
switch (column) {
case Column_Title:
case Column::Title:
song.set_title(value.toString());
break;
case Column_Artist:
case Column::Artist:
song.set_artist(value.toString());
break;
case Column_Album:
case Column::Album:
song.set_album(value.toString());
break;
case Column_AlbumArtist:
case Column::AlbumArtist:
song.set_albumartist(value.toString());
break;
case Column_Composer:
case Column::Composer:
song.set_composer(value.toString());
break;
case Column_Performer:
case Column::Performer:
song.set_performer(value.toString());
break;
case Column_Grouping:
case Column::Grouping:
song.set_grouping(value.toString());
break;
case Column_Track:
case Column::Track:
song.set_track(value.toInt());
break;
case Column_Disc:
case Column::Disc:
song.set_disc(value.toInt());
break;
case Column_Year:
case Column::Year:
song.set_year(value.toInt());
break;
case Column_Genre:
case Column::Genre:
song.set_genre(value.toString());
break;
case Column_Comment:
case Column::Comment:
song.set_comment(value.toString());
break;
default:
@@ -269,7 +271,7 @@ bool Playlist::set_column_value(Song &song, Playlist::Column column, const QVari
}
QVariant Playlist::data(const QModelIndex &idx, int role) const {
QVariant Playlist::data(const QModelIndex &idx, const int role) const {
if (!idx.isValid()) {
return QVariant();
@@ -289,7 +291,7 @@ QVariant Playlist::data(const QModelIndex &idx, int role) const {
return queue_->PositionOf(idx);
case Role_CanSetRating:
return idx.column() == Column_Rating && items_[idx.row()]->IsLocalCollectionItem() && items_[idx.row()]->Metadata().id() != -1;
return static_cast<Column>(idx.column()) == Column::Rating && items_[idx.row()]->IsLocalCollectionItem() && items_[idx.row()]->Metadata().id() != -1;
case Qt::EditRole:
case Qt::ToolTipRole:
@@ -298,51 +300,53 @@ QVariant Playlist::data(const QModelIndex &idx, int role) const {
Song song = item->Metadata();
// Don't forget to change Playlist::CompareItems when adding new columns
switch (idx.column()) {
case Column_Title: return song.PrettyTitle();
case Column_Artist: return song.artist();
case Column_Album: return song.album();
case Column_Length: return song.length_nanosec();
case Column_Track: return song.track();
case Column_Disc: return song.disc();
case Column_Year: return song.year();
case Column_OriginalYear: return song.effective_originalyear();
case Column_Genre: return song.genre();
case Column_AlbumArtist: return song.playlist_albumartist();
case Column_Composer: return song.composer();
case Column_Performer: return song.performer();
case Column_Grouping: return song.grouping();
switch (static_cast<Column>(idx.column())) {
case Column::Title: return song.PrettyTitle();
case Column::Artist: return song.artist();
case Column::Album: return song.album();
case Column::Length: return song.length_nanosec();
case Column::Track: return song.track();
case Column::Disc: return song.disc();
case Column::Year: return song.year();
case Column::OriginalYear: return song.effective_originalyear();
case Column::Genre: return song.genre();
case Column::AlbumArtist: return song.playlist_albumartist();
case Column::Composer: return song.composer();
case Column::Performer: return song.performer();
case Column::Grouping: return song.grouping();
case Column_PlayCount: return song.playcount();
case Column_SkipCount: return song.skipcount();
case Column_LastPlayed: return song.lastplayed();
case Column::PlayCount: return song.playcount();
case Column::SkipCount: return song.skipcount();
case Column::LastPlayed: return song.lastplayed();
case Column_Samplerate: return song.samplerate();
case Column_Bitdepth: return song.bitdepth();
case Column_Bitrate: return song.bitrate();
case Column::Samplerate: return song.samplerate();
case Column::Bitdepth: return song.bitdepth();
case Column::Bitrate: return song.bitrate();
case Column_Filename: return song.effective_stream_url();
case Column_BaseFilename: return song.basefilename();
case Column_Filesize: return song.filesize();
case Column_Filetype: return QVariant::fromValue(song.filetype());
case Column_DateModified: return song.mtime();
case Column_DateCreated: return song.ctime();
case Column::Filename: return song.effective_stream_url();
case Column::BaseFilename: return song.basefilename();
case Column::Filesize: return song.filesize();
case Column::Filetype: return QVariant::fromValue(song.filetype());
case Column::DateModified: return song.mtime();
case Column::DateCreated: return song.ctime();
case Column_Comment:
case Column::Comment:
if (role == Qt::DisplayRole) return song.comment().simplified();
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());
case Column_Rating: return song.rating();
case Column::Rating: return song.rating();
case Column_HasCUE: return song.has_cue();
case Column::HasCUE: return song.has_cue();
default: break;
case Column::Mood:
case Column::ColumnCount:
break;
}
@@ -394,11 +398,11 @@ QVariant Playlist::data(const QModelIndex &idx, int role) const {
#ifdef HAVE_MOODBAR
void Playlist::MoodbarUpdated(const QModelIndex &idx) {
emit dataChanged(idx.sibling(idx.row(), Column_Mood), idx.sibling(idx.row(), Column_Mood));
emit dataChanged(idx.sibling(idx.row(), static_cast<int>(Column::Mood)), idx.sibling(idx.row(), static_cast<int>(Column::Mood)));
}
#endif
bool Playlist::setData(const QModelIndex &idx, const QVariant &value, int role) {
bool Playlist::setData(const QModelIndex &idx, const QVariant &value, const int role) {
Q_UNUSED(role);
@@ -461,15 +465,14 @@ void Playlist::ItemReloadComplete(const QPersistentModelIndex &idx, const Song &
if (idx.isValid()) {
PlaylistItemPtr item = item_at(idx.row());
if (item) {
ItemChanged(idx.row(), ChangedColumns(old_metadata, item->Metadata()));
if (idx.row() == current_row()) {
const bool minor = old_metadata.title() == item->Metadata().title() &&
old_metadata.albumartist() == item->Metadata().albumartist() &&
old_metadata.artist() == item->Metadata().artist() &&
old_metadata.album() == item->Metadata().album();
InformOfCurrentSongChange(AutoScroll::Never, minor);
}
else {
emit dataChanged(index(idx.row(), 0), index(idx.row(), ColumnCount - 1));
if (MinorMetadataChange(old_metadata, item->Metadata())) {
emit CurrentSongMetadataChanged(item->Metadata());
}
else {
emit CurrentSongChanged(item->Metadata());
}
}
if (metadata_edit) {
emit EditingFinished(id_, idx);
@@ -701,7 +704,8 @@ void Playlist::set_current_row(const int i, const AutoScroll autoscroll, const b
}
if (current_item_index_.isValid() && !is_stopping) {
InformOfCurrentSongChange(autoscroll, false);
InformOfCurrentSongChange(false);
emit MaybeAutoscroll(autoscroll);
}
// The structure of a dynamic playlist is as follows:
@@ -782,7 +786,7 @@ Qt::DropActions Playlist::supportedDropActions() const {
return Qt::MoveAction | Qt::CopyAction | Qt::LinkAction;
}
bool Playlist::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int, const QModelIndex&) {
bool Playlist::dropMimeData(const QMimeData *data, Qt::DropAction action, const int row, int, const QModelIndex&) {
if (action == Qt::IgnoreAction) return false;
@@ -1134,7 +1138,7 @@ void Playlist::InsertItemsWithoutUndo(const PlaylistItemPtrList &items, const in
}
if (auto_sort_) {
sort(sort_column_, sort_order_);
sort(static_cast<int>(sort_column_), sort_order_);
}
ReshuffleIndices();
@@ -1299,7 +1303,7 @@ QMimeData *Playlist::mimeData(const QModelIndexList &indexes) const {
}
bool Playlist::CompareItems(const int 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 b = order == Qt::AscendingOrder ? _b : _a;
@@ -1308,47 +1312,48 @@ bool Playlist::CompareItems(const int column, const Qt::SortOrder order, Playlis
#define strcmp(field) return QString::localeAwareCompare(a->Metadata().field().toLower(), b->Metadata().field().toLower()) < 0;
switch (column) {
case Column::Title: strcmp(title_sortable);
case Column::Artist: strcmp(artist_sortable);
case Column::Album: strcmp(album_sortable);
case Column::Length: cmp(length_nanosec);
case Column::Track: cmp(track);
case Column::Disc: cmp(disc);
case Column::Year: cmp(year);
case Column::OriginalYear: cmp(effective_originalyear);
case Column::Genre: strcmp(genre);
case Column::AlbumArtist: strcmp(playlist_albumartist_sortable);
case Column::Composer: strcmp(composer);
case Column::Performer: strcmp(performer);
case Column::Grouping: strcmp(grouping);
case Column_Title: strcmp(title_sortable);
case Column_Artist: strcmp(artist_sortable);
case Column_Album: strcmp(album_sortable);
case Column_Length: cmp(length_nanosec);
case Column_Track: cmp(track);
case Column_Disc: cmp(disc);
case Column_Year: cmp(year);
case Column_OriginalYear: cmp(effective_originalyear);
case Column_Genre: strcmp(genre);
case Column_AlbumArtist: strcmp(playlist_albumartist_sortable);
case Column_Composer: strcmp(composer);
case Column_Performer: strcmp(performer);
case Column_Grouping: strcmp(grouping);
case Column::PlayCount: cmp(playcount);
case Column::SkipCount: cmp(skipcount);
case Column::LastPlayed: cmp(lastplayed);
case Column_PlayCount: cmp(playcount);
case Column_SkipCount: cmp(skipcount);
case Column_LastPlayed: cmp(lastplayed);
case Column_Bitrate: cmp(bitrate);
case Column_Samplerate: cmp(samplerate);
case Column_Bitdepth: cmp(bitdepth);
case Column_Filename:
case Column::Bitrate: cmp(bitrate);
case Column::Samplerate: cmp(samplerate);
case Column::Bitdepth: cmp(bitdepth);
case Column::Filename:
return (QString::localeAwareCompare(a->Url().path().toLower(), b->Url().path().toLower()) < 0);
case Column_BaseFilename: cmp(basefilename);
case Column_Filesize: cmp(filesize);
case Column_Filetype: cmp(filetype);
case Column_DateModified: cmp(mtime);
case Column_DateCreated: cmp(ctime);
case Column::BaseFilename: cmp(basefilename);
case Column::Filesize: cmp(filesize);
case Column::Filetype: cmp(filetype);
case Column::DateModified: cmp(mtime);
case Column::DateCreated: cmp(ctime);
case Column_Comment: strcmp(comment);
case Column_Source: cmp(source);
case Column::Comment: strcmp(comment);
case Column::Source: cmp(source);
case Column_Rating: cmp(rating);
case Column::Rating: cmp(rating);
case Column_HasCUE: cmp(has_cue);
case Column::HasCUE: cmp(has_cue);
case Column_EBUR128IntegratedLoudness: cmp(ebur128_integrated_loudness_lufs);
case Column_EBUR128LoudnessRange: cmp(ebur128_loudness_range_lu);
case Column::EBUR128IntegratedLoudness: cmp(ebur128_integrated_loudness_lufs);
case Column::EBUR128LoudnessRange: cmp(ebur128_loudness_range_lu);
default: qLog(Error) << "No such column" << column;
case Column::Mood:
case Column::ColumnCount:
break;
}
#undef cmp
@@ -1370,49 +1375,51 @@ bool Playlist::ComparePathDepths(const Qt::SortOrder order, PlaylistItemPtr _a,
}
QString Playlist::column_name(Column column) {
QString Playlist::column_name(const Column column) {
switch (column) {
case Column_Title: return tr("Title");
case Column_Artist: return tr("Artist");
case Column_Album: return tr("Album");
case Column_Track: return tr("Track");
case Column_Disc: return tr("Disc");
case Column_Length: return tr("Length");
case Column_Year: return tr("Year");
case Column_OriginalYear: return tr("Original Year");
case Column_Genre: return tr("Genre");
case Column_AlbumArtist: return tr("Album Artist");
case Column_Composer: return tr("Composer");
case Column_Performer: return tr("Performer");
case Column_Grouping: return tr("Grouping");
case Column::Title: return tr("Title");
case Column::Artist: return tr("Artist");
case Column::Album: return tr("Album");
case Column::Track: return tr("Track");
case Column::Disc: return tr("Disc");
case Column::Length: return tr("Length");
case Column::Year: return tr("Year");
case Column::OriginalYear: return tr("Original Year");
case Column::Genre: return tr("Genre");
case Column::AlbumArtist: return tr("Album Artist");
case Column::Composer: return tr("Composer");
case Column::Performer: return tr("Performer");
case Column::Grouping: return tr("Grouping");
case Column_PlayCount: return tr("Play Count");
case Column_SkipCount: return tr("Skip Count");
case Column_LastPlayed: return tr("Last Played");
case Column::PlayCount: return tr("Play Count");
case Column::SkipCount: return tr("Skip Count");
case Column::LastPlayed: return tr("Last Played");
case Column_Samplerate: return tr("Sample Rate");
case Column_Bitdepth: return tr("Bit Depth");
case Column_Bitrate: return tr("Bitrate");
case Column::Samplerate: return tr("Sample Rate");
case Column::Bitdepth: return tr("Bit Depth");
case Column::Bitrate: return tr("Bitrate");
case Column_Filename: return tr("File Name");
case Column_BaseFilename: return tr("File Name (without path)");
case Column_Filesize: return tr("File Size");
case Column_Filetype: return tr("File Type");
case Column_DateModified: return tr("Date Modified");
case Column_DateCreated: return tr("Date Created");
case Column::Filename: return tr("File Name");
case Column::BaseFilename: return tr("File Name (without path)");
case Column::Filesize: return tr("File Size");
case Column::Filetype: return tr("File Type");
case Column::DateModified: return tr("Date Modified");
case Column::DateCreated: return tr("Date Created");
case Column_Comment: return tr("Comment");
case Column_Source: return tr("Source");
case Column_Mood: return tr("Mood");
case Column_Rating: return tr("Rating");
case Column_HasCUE: return tr("CUE");
case Column::Comment: return tr("Comment");
case Column::Source: return tr("Source");
case Column::Mood: return tr("Mood");
case Column::Rating: return tr("Rating");
case Column::HasCUE: return tr("CUE");
case Column_EBUR128IntegratedLoudness: return tr("Integrated Loudness");
case Column_EBUR128LoudnessRange: return tr("Loudness Range");
case Column::EBUR128IntegratedLoudness: return tr("Integrated Loudness");
case Column::EBUR128LoudnessRange: return tr("Loudness Range");
default: qLog(Error) << "No such column" << column;;
case Column::ColumnCount:
break;
}
return QLatin1String("");
}
@@ -1422,21 +1429,24 @@ QString Playlist::abbreviated_column_name(const Column column) {
const QString &column_name = Playlist::column_name(column);
switch (column) {
case Column_Disc:
case Column_PlayCount:
case Column_SkipCount:
case Column_Track:
case Column::Disc:
case Column::PlayCount:
case Column::SkipCount:
case Column::Track:
return QStringLiteral("%1#").arg(column_name[0]);
default:
return column_name;
}
return QLatin1String("");
}
void Playlist::sort(int column, Qt::SortOrder order) {
void Playlist::sort(const int column_number, const Qt::SortOrder order) {
sort_column_ = column;
const Column column = static_cast<Column>(column_number);
sort_column_ = static_cast<Column>(column);
sort_order_ = order;
if (ignore_sorting_) return;
@@ -1447,15 +1457,15 @@ void Playlist::sort(int column, Qt::SortOrder order) {
if (dynamic_playlist_ && current_item_index_.isValid())
begin += current_item_index_.row() + 1;
if (column == Column_Album) {
if (column == Column::Album) {
// When sorting by album, also take into account discs and tracks.
std::stable_sort(begin, new_items.end(), std::bind(&Playlist::CompareItems, Column_Track, order, std::placeholders::_1, std::placeholders::_2));
std::stable_sort(begin, new_items.end(), std::bind(&Playlist::CompareItems, Column_Disc, order, std::placeholders::_1, std::placeholders::_2));
std::stable_sort(begin, new_items.end(), std::bind(&Playlist::CompareItems, Column_Album, order, std::placeholders::_1, std::placeholders::_2));
std::stable_sort(begin, new_items.end(), std::bind(&Playlist::CompareItems, Column::Track, order, std::placeholders::_1, std::placeholders::_2));
std::stable_sort(begin, new_items.end(), std::bind(&Playlist::CompareItems, Column::Disc, order, std::placeholders::_1, std::placeholders::_2));
std::stable_sort(begin, new_items.end(), std::bind(&Playlist::CompareItems, Column::Album, order, std::placeholders::_1, std::placeholders::_2));
}
else if (column == Column_Filename) {
else if (column == Column::Filename) {
// When sorting by full paths we also expect a hierarchical order. This returns a breath-first ordering of paths.
std::stable_sort(begin, new_items.end(), std::bind(&Playlist::CompareItems, Column_Filename, order, std::placeholders::_1, std::placeholders::_2));
std::stable_sort(begin, new_items.end(), std::bind(&Playlist::CompareItems, Column::Filename, order, std::placeholders::_1, std::placeholders::_2));
std::stable_sort(begin, new_items.end(), std::bind(&Playlist::ComparePathDepths, order, std::placeholders::_1, std::placeholders::_2));
}
else {
@@ -1635,7 +1645,7 @@ void Playlist::ItemsLoaded() {
}
static bool DescendingIntLessThan(int a, int b) { return a > b; }
static bool DescendingIntLessThan(const int a, const int b) { return a > b; }
void Playlist::RemoveItemsWithoutUndo(const QList<int> &indicesIn) {
@@ -1658,7 +1668,7 @@ void Playlist::RemoveItemsWithoutUndo(const QList<int> &indicesIn) {
}
bool Playlist::removeRows(int row, int count, const QModelIndex &parent) {
bool Playlist::removeRows(const int row, const int count, const QModelIndex &parent) {
Q_UNUSED(parent);
@@ -1784,25 +1794,19 @@ void Playlist::StopAfter(const int row) {
}
void Playlist::SetStreamMetadata(const QUrl &url, const Song &song, const bool minor) {
if (!current_item() || current_item()->Url() != url) return;
bool update_scrobble_point = song.length_nanosec() != current_item_metadata().length_nanosec();
current_item()->SetTemporaryMetadata(song);
if (update_scrobble_point) UpdateScrobblePoint();
InformOfCurrentSongChange(AutoScroll::Never, minor);
}
void Playlist::ClearStreamMetadata() {
if (!current_item()) return;
if (!current_item() || !current_item_index_.isValid()) return;
const Song old_metadata = current_item()->Metadata();
current_item()->ClearTemporaryMetadata();
UpdateScrobblePoint();
const Song &new_metadata = current_item()->Metadata();
emit dataChanged(index(current_item_index_.row(), 0), index(current_item_index_.row(), ColumnCount - 1));
ItemChanged(current_row(), ChangedColumns(old_metadata, new_metadata));
if (old_metadata.length_nanosec() != new_metadata.length_nanosec()) {
UpdateScrobblePoint();
}
}
@@ -2077,10 +2081,10 @@ PlaylistItemPtrList Playlist::collection_items_by_id(const int id) const {
return collection_items_by_id_.values(id);
}
void Playlist::TracksAboutToBeDequeued(const QModelIndex&, int begin, int end) {
void Playlist::TracksAboutToBeDequeued(const QModelIndex&, const int begin, const int end) {
for (int i = begin; i <= end; ++i) {
temp_dequeue_change_indexes_ << queue_->mapToSource(queue_->index(i, Column_Title));
temp_dequeue_change_indexes_ << queue_->mapToSource(queue_->index(i, static_cast<int>(Column::Title)));
}
}
@@ -2097,8 +2101,8 @@ void Playlist::TracksDequeued() {
void Playlist::TracksEnqueued(const QModelIndex&, const int begin, const int end) {
const QModelIndex &b = queue_->mapToSource(queue_->index(begin, Column_Title));
const QModelIndex &e = queue_->mapToSource(queue_->index(end, Column_Title));
const QModelIndex &b = queue_->mapToSource(queue_->index(begin, static_cast<int>(Column::Title)));
const QModelIndex &e = queue_->mapToSource(queue_->index(end, static_cast<int>(Column::Title)));
emit dataChanged(b, e);
}
@@ -2106,47 +2110,193 @@ void Playlist::TracksEnqueued(const QModelIndex&, const int begin, const int end
void Playlist::QueueLayoutChanged() {
for (int i = 0; i < queue_->rowCount(); ++i) {
const QModelIndex &idx = queue_->mapToSource(queue_->index(i, Column_Title));
const QModelIndex &idx = queue_->mapToSource(queue_->index(i, static_cast<int>(Column::Title)));
emit dataChanged(idx, idx);
}
}
void Playlist::ItemChanged(const int row) {
Playlist::Columns Playlist::ChangedColumns(const Song &metadata1, const Song &metadata2) {
QModelIndex idx = index(row, ColumnCount - 1);
if (idx.isValid()) {
emit dataChanged(index(row, 0), index(row, ColumnCount - 1));
Columns columns;
if (metadata1.title() != metadata2.title()) {
columns << Column::Title;
}
if (metadata1.artist() != metadata2.artist()) {
columns << Column::Artist;
}
if (metadata1.album() != metadata2.album()) {
columns << Column::Album;
}
if (metadata1.effective_albumartist() != metadata2.effective_albumartist()) {
columns << Column::AlbumArtist;
}
if (metadata1.performer() != metadata2.performer()) {
columns << Column::Performer;
}
if (metadata1.composer() != metadata2.composer()) {
columns << Column::Composer;
}
if (metadata1.year() != metadata2.year()) {
columns << Column::Year;
}
if (metadata1.originalyear() != metadata2.originalyear()) {
columns << Column::OriginalYear;
}
if (metadata1.track() != metadata2.track()) {
columns << Column::Track;
}
if (metadata1.disc() != metadata2.disc()) {
columns << Column::Disc;
}
if (metadata1.length_nanosec() != metadata2.length_nanosec()) {
columns << Column::Length;
}
if (metadata1.genre() != metadata2.genre()) {
columns << Column::Genre;
}
if (metadata1.samplerate() != metadata2.samplerate()) {
columns << Column::Samplerate;
}
if (metadata1.bitdepth() != metadata2.bitdepth()) {
columns << Column::Bitdepth;
}
if (metadata1.bitrate() != metadata2.bitrate()) {
columns << Column::Bitrate;
}
if (metadata1.url() != metadata2.url()) {
columns << Column::Filename;
columns << Column::BaseFilename;
}
if (metadata1.filesize() != metadata2.filesize()) {
columns << Column::Filesize;
}
if (metadata1.filetype() != metadata2.filetype()) {
columns << Column::Filetype;
}
if (metadata1.ctime() != metadata2.ctime()) {
columns << Column::DateCreated;
}
if (metadata1.mtime() != metadata2.mtime()) {
columns << Column::DateModified;
}
if (metadata1.playcount() != metadata2.playcount()) {
columns << Column::PlayCount;
}
if (metadata1.skipcount() != metadata2.skipcount()) {
columns << Column::SkipCount;
}
if (metadata1.lastplayed() != metadata2.lastplayed()) {
columns << Column::LastPlayed;
}
if (metadata1.comment() != metadata2.comment()) {
columns << Column::Comment;
}
if (metadata1.grouping() != metadata2.grouping()) {
columns << Column::Grouping;
}
if (metadata1.source() != metadata2.source()) {
columns << Column::Source;
}
if (metadata1.rating() != metadata2.rating()) {
columns << Column::Rating;
}
if (metadata1.has_cue() != metadata2.has_cue()) {
columns << Column::HasCUE;
}
if (metadata1.ebur128_integrated_loudness_lufs() != metadata2.ebur128_integrated_loudness_lufs()) {
columns << Column::EBUR128IntegratedLoudness;
}
if (metadata1.ebur128_loudness_range_lu() != metadata2.ebur128_loudness_range_lu()) {
columns << Column::EBUR128LoudnessRange;
}
return columns;
}
bool Playlist::MinorMetadataChange(const Song &old_metadata, const Song &new_metadata) {
return new_metadata.title() == old_metadata.title() &&
new_metadata.albumartist() == old_metadata.albumartist() &&
new_metadata.artist() == old_metadata.artist() &&
new_metadata.album() == old_metadata.album();
}
void Playlist::UpdateItemMetadata(PlaylistItemPtr item, const Song &new_metadata, const bool temporary) {
if (!items_.contains(item)) {
return;
}
for (int row = static_cast<int>(items_.indexOf(item, 0)); row != -1; row = static_cast<int>(items_.indexOf(item, row + 1))) {
UpdateItemMetadata(row, item, new_metadata, temporary);
}
}
void Playlist::ItemChanged(PlaylistItemPtr item) {
void Playlist::UpdateItemMetadata(const int row, PlaylistItemPtr item, const Song &new_metadata, const bool temporary) {
for (int row = 0; row < items_.count(); ++row) {
if (items_[row] == item) {
ItemChanged(row);
const Song old_metadata = item->Metadata();
const Columns columns = ChangedColumns(old_metadata, new_metadata);
if (columns.isEmpty()) return;
if (temporary) {
item->SetTemporaryMetadata(new_metadata);
}
else {
item->SetMetadata(new_metadata);
if (item->HasTemporaryMetadata()) {
item->UpdateTemporaryMetadata(new_metadata);
}
}
ItemChanged(row, columns);
if (row == current_row()) {
InformOfCurrentSongChange(MinorMetadataChange(old_metadata, new_metadata));
if (new_metadata.length_nanosec() != old_metadata.length_nanosec()) {
UpdateScrobblePoint();
}
}
}
void Playlist::InformOfCurrentSongChange(const AutoScroll autoscroll, const bool minor) {
void Playlist::ItemChanged(const int row, const Columns columns) {
// If the song is invalid, we won't play it - there's no point in informing anybody about the change
const Song metadata(current_item_metadata());
if (metadata.is_valid()) {
if (minor) {
emit SongMetadataChanged(metadata);
if (editing_ != current_item_index_.row()) {
emit dataChanged(index(current_item_index_.row(), 0), index(current_item_index_.row(), ColumnCount - 1));
if (columns.count() > 5) {
const QModelIndex idx_column_first = index(row, 0);
const QModelIndex idx_column_last = index(row, ColumnCount - 1);
if (idx_column_first.isValid() && idx_column_last.isValid()) {
emit dataChanged(index(row, 0), index(row, ColumnCount - 1));
}
}
else {
for (const Column &column : columns) {
const QModelIndex idx = index(row, static_cast<int>(column));
if (idx.isValid()) {
emit dataChanged(idx, idx);
}
}
else {
emit CurrentSongChanged(metadata);
emit MaybeAutoscroll(autoscroll);
emit dataChanged(index(current_item_index_.row(), 0), index(current_item_index_.row(), ColumnCount - 1));
}
}
}
void Playlist::InformOfCurrentSongChange(const bool minor) {
const Song &metadata = current_item_metadata();
if (!metadata.is_valid()) {
return;
}
if (minor) {
emit CurrentSongMetadataChanged(metadata);
}
else {
emit CurrentSongChanged(metadata);
}
}