From 11a5ee821b99da7c58da4cb2251c8686e2d615cf Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 11 Jul 2014 20:01:53 +0200 Subject: PlaylistEdit: postpone UpdateQueuedSong() when adding multiple songs Implement a "bulk" edit mode that postpones both UpdateQueuedSong() and OnModified(). This way, the playlist version gets incremented only once. More importantly: when adding multiple songs to a queue that consists of only one song, the first song that got added will always be played next. By postponing this choice, all newly added songs get a chance to become the next song. Fixes the second (and last) part of Mantis ticket 0004005. --- src/BulkEdit.hxx | 41 ++++++++++++++++++++++++++++++++++++++++ src/Playlist.cxx | 6 ++++++ src/Playlist.hxx | 19 ++++++++++++++++++- src/PlaylistEdit.cxx | 35 ++++++++++++++++++++++++++++++++++ src/command/DatabaseCommands.cxx | 3 +++ src/command/PlaylistCommands.cxx | 3 +++ src/command/QueueCommands.cxx | 3 +++ 7 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 src/BulkEdit.hxx (limited to 'src') diff --git a/src/BulkEdit.hxx b/src/BulkEdit.hxx new file mode 100644 index 000000000..422dc4f38 --- /dev/null +++ b/src/BulkEdit.hxx @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2003-2014 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_BULK_EDIT_HXX +#define MPD_BULK_EDIT_HXX + +#include "Partition.hxx" + +/** + * Begin a "bulk edit" and commit it automatically. + */ +class ScopeBulkEdit { + Partition &partition; + +public: + ScopeBulkEdit(Partition &_partition):partition(_partition) { + partition.playlist.BeginBulk(); + } + + ~ScopeBulkEdit() { + partition.playlist.CommitBulk(partition.pc); + } +}; + +#endif diff --git a/src/Playlist.cxx b/src/Playlist.cxx index ac2cc494b..526f35298 100644 --- a/src/Playlist.cxx +++ b/src/Playlist.cxx @@ -103,6 +103,12 @@ playlist::UpdateQueuedSong(PlayerControl &pc, const Song *prev) if (!playing) return; + if (prev == nullptr && bulk_edit) + /* postponed until CommitBulk() to avoid always + queueing the first song that is being added (in + random mode) */ + return; + assert(!queue.IsEmpty()); assert((queued < 0) == (prev == nullptr)); diff --git a/src/Playlist.hxx b/src/Playlist.hxx index 7d7e9b154..b660ecb40 100644 --- a/src/Playlist.hxx +++ b/src/Playlist.hxx @@ -45,6 +45,18 @@ struct playlist { */ bool stop_on_error; + /** + * If true, then a bulk edit has been initiated by + * BeginBulk(), and UpdateQueuedSong() and OnModified() will + * be postponed until CommitBulk() + */ + bool bulk_edit; + + /** + * Has the queue been modified during bulk edit mode? + */ + bool bulk_modified; + /** * Number of errors since playback was started. If this * number exceeds the length of the playlist, MPD gives up, @@ -69,7 +81,9 @@ struct playlist { int queued; playlist(unsigned max_length) - :queue(max_length), playing(false), current(-1), queued(-1) { + :queue(max_length), playing(false), + bulk_edit(false), + current(-1), queued(-1) { } ~playlist() { @@ -126,6 +140,9 @@ protected: void UpdateQueuedSong(PlayerControl &pc, const Song *prev); public: + void BeginBulk(); + void CommitBulk(PlayerControl &pc); + void Clear(PlayerControl &pc); /** diff --git a/src/PlaylistEdit.cxx b/src/PlaylistEdit.cxx index 3eea2491e..0dffd3d80 100644 --- a/src/PlaylistEdit.cxx +++ b/src/PlaylistEdit.cxx @@ -40,6 +40,12 @@ void playlist::OnModified() { + if (bulk_edit) { + /* postponed to CommitBulk() */ + bulk_modified = true; + return; + } + queue.IncrementVersion(); idle_add(IDLE_PLAYLIST); @@ -56,6 +62,35 @@ playlist::Clear(PlayerControl &pc) OnModified(); } +void +playlist::BeginBulk() +{ + assert(!bulk_edit); + + bulk_edit = true; + bulk_modified = false; +} + +void +playlist::CommitBulk(PlayerControl &pc) +{ + assert(bulk_edit); + + bulk_edit = false; + if (!bulk_modified) + return; + + if (queued < 0) + /* if no song was queued, UpdateQueuedSong() is being + ignored in "bulk" edit mode; now that we have + shuffled all new songs, we can pick a random one + (instead of always picking the first one that was + added) */ + UpdateQueuedSong(pc, nullptr); + + OnModified(); +} + PlaylistResult playlist::AppendFile(PlayerControl &pc, const char *path_utf8, unsigned *added_id) diff --git a/src/command/DatabaseCommands.cxx b/src/command/DatabaseCommands.cxx index b86cbdae7..a7d2467b8 100644 --- a/src/command/DatabaseCommands.cxx +++ b/src/command/DatabaseCommands.cxx @@ -30,6 +30,7 @@ #include "util/Error.hxx" #include "SongFilter.hxx" #include "protocol/Result.hxx" +#include "BulkEdit.hxx" #include #include @@ -92,6 +93,8 @@ handle_match_add(Client &client, int argc, char *argv[], bool fold_case) return CommandResult::ERROR; } + const ScopeBulkEdit bulk_edit(client.partition); + const DatabaseSelection selection("", true, &filter); Error error; return AddFromDatabase(client.partition, selection, error) diff --git a/src/command/PlaylistCommands.cxx b/src/command/PlaylistCommands.cxx index d178fa097..c4441293e 100644 --- a/src/command/PlaylistCommands.cxx +++ b/src/command/PlaylistCommands.cxx @@ -26,6 +26,7 @@ #include "PlaylistFile.hxx" #include "PlaylistVector.hxx" #include "PlaylistQueue.hxx" +#include "BulkEdit.hxx" #include "TimePrint.hxx" #include "Client.hxx" #include "protocol/ArgParser.hxx" @@ -67,6 +68,8 @@ handle_load(Client &client, int argc, char *argv[]) } else if (!check_range(client, &start_index, &end_index, argv[2])) return CommandResult::ERROR; + const ScopeBulkEdit bulk_edit(client.partition); + const PlaylistResult result = playlist_open_into_queue(argv[1], start_index, end_index, diff --git a/src/command/QueueCommands.cxx b/src/command/QueueCommands.cxx index a20b24132..a987e1bc9 100644 --- a/src/command/QueueCommands.cxx +++ b/src/command/QueueCommands.cxx @@ -28,6 +28,7 @@ #include "ClientFile.hxx" #include "Client.hxx" #include "Partition.hxx" +#include "BulkEdit.hxx" #include "protocol/ArgParser.hxx" #include "protocol/Result.hxx" #include "ls.hxx" @@ -73,6 +74,8 @@ handle_add(Client &client, gcc_unused int argc, char *argv[]) return print_playlist_result(client, result); } + const ScopeBulkEdit bulk_edit(client.partition); + const DatabaseSelection selection(uri, true); Error error; return AddFromDatabase(client.partition, selection, error) -- cgit v1.2.3