Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 66 additions & 9 deletions src/playlist/playlist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ constexpr qint64 kMaxScrobblePointNsecs = 240LL * kNsecPerSec;

constexpr int kMaxPlayedIndexes = 100;

const PlaylistItemPtr empty_item;

} // namespace

Playlist::Playlist(const SharedPtr<TaskManager> task_manager,
Expand Down Expand Up @@ -961,12 +963,12 @@ bool Playlist::dropMimeData(const QMimeData *data, Qt::DropAction action, const

}

void Playlist::InsertUrls(const QList<QUrl> &urls, const int pos, const bool play_now, const bool enqueue, const bool enqueue_next) {
void Playlist::InsertUrls(const QList<QUrl> &urls, const int pos, const bool play_now, const bool enqueue, const bool enqueue_next, const bool emit_signal) {

SongLoaderInserter *inserter = new SongLoaderInserter(task_manager_, tagreader_client_, url_handlers_, collection_backend_);
QObject::connect(inserter, &SongLoaderInserter::Error, this, &Playlist::Error);

inserter->Load(this, pos, play_now, enqueue, enqueue_next, urls);
inserter->Load(this, pos, play_now, enqueue, enqueue_next, emit_signal, urls);

}

Expand Down Expand Up @@ -1145,7 +1147,7 @@ void Playlist::MoveItemsWithoutUndo(int start, const QList<int> &dest_rows) {

}

void Playlist::InsertItems(const PlaylistItemPtrList &itemsIn, const int pos, const bool play_now, const bool enqueue, const bool enqueue_next) {
void Playlist::InsertItems(const PlaylistItemPtrList &itemsIn, const int pos, const bool play_now, const bool enqueue, const bool enqueue_next, const bool emit_signal) {

if (itemsIn.isEmpty()) {
return;
Expand All @@ -1157,23 +1159,34 @@ void Playlist::InsertItems(const PlaylistItemPtrList &itemsIn, const int pos, co

if (items.count() > kUndoItemLimit) {
// Too big to keep in the undo stack. Also clear the stack because it might have been invalidated.
InsertItemsWithoutUndo(items, pos, enqueue, enqueue_next);
InsertItemsWithoutUndo(items, pos, enqueue, enqueue_next, emit_signal);
undo_stack_->clear();
}
else {
undo_stack_->push(new PlaylistUndoCommandInsertItems(this, items, pos, enqueue, enqueue_next));
undo_stack_->push(new PlaylistUndoCommandInsertItems(this, items, pos, enqueue, enqueue_next, emit_signal));
}

if (play_now) Q_EMIT PlayRequested(index(start, 0), AutoScroll::Maybe);

}

void Playlist::InsertItemsWithoutUndo(const PlaylistItemPtrList &items, const int pos, const bool enqueue, const bool enqueue_next) {
void Playlist::InsertItemsWithoutUndo(const PlaylistItemPtrList &items, const int pos, const bool enqueue, const bool enqueue_next, const bool emit_signal) {

if (items.isEmpty()) return;

QUuid after_track_id;
const int start = pos == -1 ? static_cast<int>(items_.count()) : pos;
const int end = start + static_cast<int>(items.count()) - 1;
QList<QUuid> tracks_id_added;

if (items_.length() > 0) {
if (static_cast<unsigned int>(pos) < items_.length()) {
after_track_id = items_[pos]->uuid();
}
else {
after_track_id = items_[items_.length() - 1]->uuid();
}
}

bool has_generated_uuids = false;
beginInsertRows(QModelIndex(), start, end);
Expand All @@ -1182,6 +1195,8 @@ void Playlist::InsertItemsWithoutUndo(const PlaylistItemPtrList &items, const in
items_.insert(i, item);
virtual_items_ << static_cast<int>(virtual_items_.count());

tracks_id_added << item->uuid();

if (Song::IsLinkedCollectionSource(item->source())) {
const int id = item->EffectiveMetadata().id();
if (id != -1) {
Expand All @@ -1202,6 +1217,8 @@ void Playlist::InsertItemsWithoutUndo(const PlaylistItemPtrList &items, const in
}
endInsertRows();

if (emit_signal) Q_EMIT PlaylistItemsAdded(id_, tracks_id_added, after_track_id);

if (enqueue) {
QModelIndexList indexes;
for (int i = start; i <= end; ++i) {
Expand Down Expand Up @@ -1241,7 +1258,7 @@ void Playlist::InsertSongs(const SongList &songs, const int pos, const bool play
InsertSongItems<SongPlaylistItem>(songs, pos, play_now, enqueue, enqueue_next);
}

void Playlist::InsertSongsOrCollectionItems(const SongList &songs, const QString &playlist_name, const int pos, const bool play_now, const bool enqueue, const bool enqueue_next) {
void Playlist::InsertSongsOrCollectionItems(const SongList &songs, const QString &playlist_name, const int pos, const bool play_now, const bool enqueue, const bool enqueue_next, const bool emit_signal) {

if (!playlist_name.isEmpty()) {
Q_EMIT Rename(id_, playlist_name);
Expand All @@ -1253,7 +1270,7 @@ void Playlist::InsertSongsOrCollectionItems(const SongList &songs, const QString
items << PlaylistItem::NewFromSong(song);
}

InsertItems(items, pos, play_now, enqueue, enqueue_next);
InsertItems(items, pos, play_now, enqueue, enqueue_next, emit_signal);

}

Expand Down Expand Up @@ -1783,6 +1800,18 @@ bool Playlist::removeRows(const int row, const int count, const QModelIndex &par

}

bool Playlist::removeRowSignal(const int row) {

if (row < 0 || row >= items_.size()) {
return false;
}

undo_stack_->push(new PlaylistUndoCommandRemoveItems(this, row, 1, true));

return true;

}

bool Playlist::removeRows(QList<int> &rows) {

if (rows.isEmpty()) {
Expand Down Expand Up @@ -1812,7 +1841,7 @@ bool Playlist::removeRows(QList<int> &rows) {

}

PlaylistItemPtrList Playlist::RemoveItemsWithoutUndo(const int row, const int count) {
PlaylistItemPtrList Playlist::RemoveItemsWithoutUndo(const int row, const int count, const bool emit_signal) {

if (row < 0 || row >= items_.size() || row + count > items_.size()) {
return PlaylistItemPtrList();
Expand All @@ -1821,17 +1850,21 @@ PlaylistItemPtrList Playlist::RemoveItemsWithoutUndo(const int row, const int co
// Remove items
beginRemoveRows(QModelIndex(), row, row + count - 1);
PlaylistItemPtrList items;
QList<QUuid> tracks_id_removed;
items.reserve(count);
for (int i = 0; i < count; ++i) {
PlaylistItemPtr item(items_.takeAt(row));
items << item;
tracks_id_removed << item->uuid();
const int id = item->EffectiveMetadata().id();
const int source_id = item->EffectiveMetadata().source_id();
if (id != -1 && collection_items_[source_id].contains(id, item)) {
collection_items_[source_id].remove(id, item);
}
}

if (emit_signal) Q_EMIT PlaylistItemsRemoved(id_, tracks_id_removed);

// Update virtual items
for (int i = row; i < items_.count() + count; ++i) {
Q_ASSERT(virtual_items_.count(i) == 1);
Expand Down Expand Up @@ -1912,6 +1945,30 @@ bool Playlist::stop_after_current() const {

}

const PlaylistItemPtr &Playlist::find_item_id(const QUuid &id) const {

for (const PlaylistItemPtr &item : items_) {
if (item->uuid() == id) {
return item;
}
}
return empty_item;

}

int Playlist::find_pos_id(const QUuid &id) const {

int pos_found = 0;
for (const PlaylistItemPtr &item : items_) {
if (item->uuid() == id) {
return pos_found;
}
++pos_found;
}
return -1;

}

PlaylistItemPtr Playlist::current_item() const {

// QList[] runs in constant time, so no need to cache current_item
Expand Down
19 changes: 14 additions & 5 deletions src/playlist/playlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ class Playlist : public QAbstractListModel {
QString special_type() const { return special_type_; }
void set_special_type(const QString &v) { special_type_ = v; }

const PlaylistItemPtr &find_item_id(const QUuid &id) const;
int find_pos_id(const QUuid &id) const;
const PlaylistItemPtr &item_at(const int index) const { return items_[index]; }
bool has_item_at(const int index) const { return index >= 0 && index < rowCount(); }

Expand Down Expand Up @@ -233,10 +235,10 @@ class Playlist : public QAbstractListModel {
void UpdateScrobblePoint(const qint64 seek_point_nanosec = 0);

// Changing the playlist
void InsertItems(const PlaylistItemPtrList &itemsIn, const int pos = -1, const bool play_now = false, const bool enqueue = false, const bool enqueue_next = false);
void InsertItems(const PlaylistItemPtrList &itemsIn, const int pos = -1, const bool play_now = false, const bool enqueue = false, const bool enqueue_next = false, const bool emit_signal = false);
void InsertCollectionItems(const SongList &songs, const int pos = -1, const bool play_now = false, const bool enqueue = false, const bool enqueue_next = false);
void InsertSongs(const SongList &songs, const int pos = -1, const bool play_now = false, const bool enqueue = false, const bool enqueue_next = false);
void InsertSongsOrCollectionItems(const SongList &songs, const QString &playlist_name = QString(), const int pos = -1, const bool play_now = false, const bool enqueue = false, const bool enqueue_next = false);
void InsertSongsOrCollectionItems(const SongList &songs, const QString &playlist_name = QString(), const int pos = -1, const bool play_now = false, const bool enqueue = false, const bool enqueue_next = false, const bool emit_signal = false);
void InsertSmartPlaylist(PlaylistGeneratorPtr gen, const int pos = -1, const bool play_now = false, const bool enqueue = false, const bool enqueue_next = false);
void InsertStreamingItems(StreamingServicePtr service, const SongList &songs, const int pos = -1, const bool play_now = false, const bool enqueue = false, const bool enqueue_next = false);
void InsertRadioItems(const SongList &songs, const int pos = -1, const bool play_now = false, const bool enqueue = false, const bool enqueue_next = false);
Expand All @@ -263,6 +265,7 @@ class Playlist : public QAbstractListModel {
#endif

// QAbstractListModel
PlaylistItemPtrList items() const { return items_; }
int rowCount(const QModelIndex& = QModelIndex()) const override { return items_.count(); }
int columnCount(const QModelIndex& = QModelIndex()) const override { return static_cast<int>(ColumnCount); }
QVariant data(const QModelIndex &idx, const int role = Qt::DisplayRole) const override;
Expand All @@ -275,6 +278,7 @@ class Playlist : public QAbstractListModel {
bool dropMimeData(const QMimeData *data, Qt::DropAction action, const int row, const int column, const QModelIndex &parent_index) override;
void sort(const int column_number, const Qt::SortOrder order) override;
bool removeRows(const int row, const int count, const QModelIndex &parent = QModelIndex()) override;
bool removeRowSignal(const int row);

static Columns ChangedColumns(const Song &metadata1, const Song &metadata2);
static bool MinorMetadataChange(const Song &old_metadata, const Song &new_metadata);
Expand Down Expand Up @@ -309,7 +313,7 @@ class Playlist : public QAbstractListModel {

void SetColumnAlignment(const ColumnAlignmentMap &alignment);

void InsertUrls(const QList<QUrl> &urls, const int pos = -1, const bool play_now = false, const bool enqueue = false, const bool enqueue_next = false);
void InsertUrls(const QList<QUrl> &urls, const int pos = -1, const bool play_now = false, const bool enqueue = false, const bool enqueue_next = false, const bool emit_signal = false);
// Removes items with given indices from the playlist. This operation is not undoable.
void RemoveItemsWithoutUndo(const QList<int> &indicesIn);

Expand All @@ -328,6 +332,11 @@ class Playlist : public QAbstractListModel {
void PlayRequested(const QModelIndex idx, const Playlist::AutoScroll autoscroll);
void MaybeAutoscroll(const Playlist::AutoScroll autoscroll);

// Signal for tracks added to playlist, mainly used by mpris
void PlaylistItemsAdded(const int playlist_id, const QList<QUuid> &tracks_id, const QUuid after_track_id);
// Signal for tracks removed from playlist, mainly used by mpris
void PlaylistItemsRemoved(const int playlist_id, const QList<QUuid> &tracks_id);

// Signals that the underlying list of items was changed, meaning that something was added to it, removed from it or the ordering changed.
void PlaylistChanged();
void DynamicModeChanged(bool dynamic);
Expand All @@ -349,8 +358,8 @@ class Playlist : public QAbstractListModel {
void InsertSongItems(const SongList &songs, const int pos, const bool play_now, const bool enqueue, const bool enqueue_next = false);

// Modify the playlist without changing the undo stack. These are used by our friends in PlaylistUndoCommands
void InsertItemsWithoutUndo(const PlaylistItemPtrList &items, const int pos, const bool enqueue = false, const bool enqueue_next = false);
PlaylistItemPtrList RemoveItemsWithoutUndo(const int row, const int count);
void InsertItemsWithoutUndo(const PlaylistItemPtrList &items, const int pos, const bool enqueue = false, const bool enqueue_next = false, const bool emit_signal = false);
PlaylistItemPtrList RemoveItemsWithoutUndo(const int row, const int count, const bool emit_signal = false);
void MoveItemsWithoutUndo(const QList<int> &source_rows, int pos);
void MoveItemWithoutUndo(const int source, const int dest);
void MoveItemsWithoutUndo(int start, const QList<int> &dest_rows);
Expand Down
6 changes: 4 additions & 2 deletions src/playlist/playlistmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@ Playlist *PlaylistManager::AddPlaylist(const int id, const QString &name, const

QObject::connect(ret, &Playlist::CurrentSongChanged, this, &PlaylistManager::CurrentSongChanged);
QObject::connect(ret, &Playlist::CurrentSongMetadataChanged, this, &PlaylistManager::CurrentSongMetadataChanged);
QObject::connect(ret, &Playlist::PlaylistItemsAdded, this, &PlaylistManager::PlaylistItemsAdded);
QObject::connect(ret, &Playlist::PlaylistItemsRemoved, this, &PlaylistManager::PlaylistItemsRemoved);
QObject::connect(ret, &Playlist::PlaylistChanged, this, &PlaylistManager::OneOfPlaylistsChanged);
QObject::connect(ret, &Playlist::PlaylistChanged, this, &PlaylistManager::UpdateSummaryText);
QObject::connect(ret, &Playlist::EditingFinished, this, &PlaylistManager::EditingFinished);
Expand Down Expand Up @@ -499,11 +501,11 @@ void PlaylistManager::SongChangeRequestProcessed(const QUrl &url, const bool val

}

void PlaylistManager::InsertUrls(const int id, const QList<QUrl> &urls, const int pos, const bool play_now, const bool enqueue) {
void PlaylistManager::InsertUrls(const int id, const QList<QUrl> &urls, const int pos, const bool play_now, const bool enqueue, const bool emit_signal) {

Q_ASSERT(playlists_.contains(id));

playlists_.constFind(id)->p->InsertUrls(urls, pos, play_now, enqueue);
playlists_.constFind(id)->p->InsertUrls(urls, pos, play_now, enqueue, emit_signal);

}

Expand Down
2 changes: 1 addition & 1 deletion src/playlist/playlistmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ class PlaylistManager : public PlaylistManagerInterface {

void SongChangeRequestProcessed(const QUrl &url, const bool valid) override;

void InsertUrls(const int id, const QList<QUrl> &urls, const int pos = -1, const bool play_now = false, const bool enqueue = false);
void InsertUrls(const int id, const QList<QUrl> &urls, const int pos = -1, const bool play_now = false, const bool enqueue = false, const bool emit_signal = false);
void InsertSongs(const int id, const SongList &songs, const int pos = -1, const bool play_now = false, const bool enqueue = false);
// Removes items with given indices from the playlist. This operation is not undoable.
void RemoveItemsWithoutUndo(const int id, const QList<int> &indices);
Expand Down
2 changes: 2 additions & 0 deletions src/playlist/playlistmanagerinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ class PlaylistManagerInterface : public QObject {
// Forwarded from individual playlists
void CurrentSongChanged(const Song &song);
void CurrentSongMetadataChanged(const Song &song);
void PlaylistItemsAdded(const int playlist_id, const QList<QUuid> &tracks_id, const QUuid after_track_id);
void PlaylistItemsRemoved(const int playlist_id, const QList<QUuid> &tracks_id);

// Signals that one of manager's playlists has changed (new items, new ordering etc.) - the argument shows which.
void PlaylistChanged(Playlist *playlist);
Expand Down
7 changes: 4 additions & 3 deletions src/playlist/playlistundocommandinsertitems.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,20 @@
#include "playlistundocommandinsertitems.h"
#include "playlist.h"

PlaylistUndoCommandInsertItems::PlaylistUndoCommandInsertItems(Playlist *playlist, const PlaylistItemPtrList &items, const int pos, const bool enqueue, const bool enqueue_next)
PlaylistUndoCommandInsertItems::PlaylistUndoCommandInsertItems(Playlist *playlist, const PlaylistItemPtrList &items, const int pos, const bool enqueue, const bool enqueue_next, const bool emit_signal)
: PlaylistUndoCommandBase(playlist),
items_(items),
pos_(pos),
enqueue_(enqueue),
enqueue_next_(enqueue_next) {
enqueue_next_(enqueue_next),
emit_signal_(emit_signal) {

setText(QObject::tr("add %n songs", "", static_cast<int>(items_.count())));

}

void PlaylistUndoCommandInsertItems::redo() {
playlist_->InsertItemsWithoutUndo(items_, pos_, enqueue_, enqueue_next_);
playlist_->InsertItemsWithoutUndo(items_, pos_, enqueue_, enqueue_next_, emit_signal_);
}

void PlaylistUndoCommandInsertItems::undo() {
Expand Down
3 changes: 2 additions & 1 deletion src/playlist/playlistundocommandinsertitems.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

class PlaylistUndoCommandInsertItems : public PlaylistUndoCommandBase {
public:
explicit PlaylistUndoCommandInsertItems(Playlist *playlist, const PlaylistItemPtrList &items, const int pos, const bool enqueue = false, const bool enqueue_next = false);
explicit PlaylistUndoCommandInsertItems(Playlist *playlist, const PlaylistItemPtrList &items, const int pos, const bool enqueue = false, const bool enqueue_next = false, const bool emit_signal = false);

void undo() override;
void redo() override;
Expand All @@ -39,6 +39,7 @@ class PlaylistUndoCommandInsertItems : public PlaylistUndoCommandBase {
int pos_;
bool enqueue_;
bool enqueue_next_;
bool emit_signal_;
};

#endif // PLAYLISTUNDOCOMMANDINSERTITEMS_H
4 changes: 2 additions & 2 deletions src/playlist/playlistundocommandremoveitems.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#include "playlist.h"
#include "playlistundocommandremoveitems.h"

PlaylistUndoCommandRemoveItems::PlaylistUndoCommandRemoveItems(Playlist *playlist, const int pos, const int count) : PlaylistUndoCommandBase(playlist) {
PlaylistUndoCommandRemoveItems::PlaylistUndoCommandRemoveItems(Playlist *playlist, const int pos, const int count, const bool emit_signal) : PlaylistUndoCommandBase(playlist), emit_signal_(emit_signal) {
setText(QObject::tr("remove %n songs", "", count));

ranges_ << Range(pos, count);
Expand All @@ -31,7 +31,7 @@ PlaylistUndoCommandRemoveItems::PlaylistUndoCommandRemoveItems(Playlist *playlis
void PlaylistUndoCommandRemoveItems::redo() {

for (int i = 0; i < ranges_.count(); ++i) {
ranges_[i].items_ = playlist_->RemoveItemsWithoutUndo(ranges_[i].pos_, ranges_[i].count_);
ranges_[i].items_ = playlist_->RemoveItemsWithoutUndo(ranges_[i].pos_, ranges_[i].count_, emit_signal_);
}

}
Expand Down
3 changes: 2 additions & 1 deletion src/playlist/playlistundocommandremoveitems.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

class PlaylistUndoCommandRemoveItems : public PlaylistUndoCommandBase {
public:
explicit PlaylistUndoCommandRemoveItems(Playlist *playlist, const int pos, const int count);
explicit PlaylistUndoCommandRemoveItems(Playlist *playlist, const int pos, const int count, const bool emit_signal = false);

int id() const override { return static_cast<int>(PlaylistUndoCommandBase::Type::RemoveItems); }

Expand All @@ -44,6 +44,7 @@ class PlaylistUndoCommandRemoveItems : public PlaylistUndoCommandBase {
};

QList<Range> ranges_;
bool emit_signal_;
};

#endif // PLAYLISTUNDOCOMMANDREMOVEITEMS_H
5 changes: 3 additions & 2 deletions src/playlist/songloaderinserter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,14 @@ SongLoaderInserter::SongLoaderInserter(const SharedPtr<TaskManager> task_manager

SongLoaderInserter::~SongLoaderInserter() { qDeleteAll(pending_); }

void SongLoaderInserter::Load(Playlist *destination, const int row, const bool play_now, const bool enqueue, const bool enqueue_next, const QList<QUrl> &urls) {
void SongLoaderInserter::Load(Playlist *destination, const int row, const bool play_now, const bool enqueue, const bool enqueue_next, const bool emit_signal, const QList<QUrl> &urls) {

destination_ = destination;
row_ = row;
play_now_ = play_now;
enqueue_ = enqueue;
enqueue_next_ = enqueue_next;
emit_signal_ = emit_signal;

QObject::connect(destination, &Playlist::destroyed, this, &SongLoaderInserter::DestinationDestroyed);
QObject::connect(this, &SongLoaderInserter::PreloadFinished, this, &SongLoaderInserter::InsertSongs);
Expand Down Expand Up @@ -176,7 +177,7 @@ void SongLoaderInserter::InsertSongs() {

// Insert songs (that haven't been completely loaded) to allow user to see and play them while not loaded completely
if (destination_) {
destination_->InsertSongsOrCollectionItems(songs_, playlist_name_, row_, play_now_, enqueue_, enqueue_next_);
destination_->InsertSongsOrCollectionItems(songs_, playlist_name_, row_, play_now_, enqueue_, enqueue_next_, emit_signal_);
}

}
Expand Down
Loading
Loading