From 13208bf5a7c91a6406195139f1068f173ccdac94 Mon Sep 17 00:00:00 2001 From: Jeffrey Middleton Date: Thu, 26 Mar 2009 22:02:56 +0100 Subject: queue/playlist/command: move range The move command now accepts a range for the first argument, in the same form as other range commands, e.g. move 15:17 3. The first song in the range is placed at the destination position. Note that as with other range commands, the range is inclusive on the left only; this example would move only songs 15 and 16, not 17. [mk: fixed signed/unsigned warnings; use G_MAXUINT instead of UINT_MAX] --- doc/protocol.xml | 10 +++++++--- src/command.c | 8 +++++--- src/playlist.h | 2 +- src/playlist_edit.c | 31 ++++++++++++++++++------------- src/queue.c | 42 ++++++++++++++++++++++++++++++++++++++++++ src/queue.h | 6 ++++++ 6 files changed, 79 insertions(+), 20 deletions(-) diff --git a/doc/protocol.xml b/doc/protocol.xml index 409f9ca0e..8f5b4b9e8 100644 --- a/doc/protocol.xml +++ b/doc/protocol.xml @@ -634,14 +634,18 @@ OK move - FROM + + FROM + START:END + TO - Moves the song at FROM to - TO in the playlist. + Moves the song at FROM or range of songs + at START:END to TO + in the playlist. diff --git a/src/command.c b/src/command.c index 7603f669c..1b8c45f26 100644 --- a/src/command.c +++ b/src/command.c @@ -1181,14 +1181,16 @@ handle_list(struct client *client, int argc, char *argv[]) static enum command_return handle_move(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) { - int from, to; + unsigned start, end; + int to; enum playlist_result result; - if (!check_int(client, &from, argv[1], check_integer, argv[1])) + if (!check_range(client, &start, &end, + argv[1], need_range)) return COMMAND_RETURN_ERROR; if (!check_int(client, &to, argv[2], check_integer, argv[2])) return COMMAND_RETURN_ERROR; - result = moveSongInPlaylist(&g_playlist, from, to); + result = moveSongRangeInPlaylist(&g_playlist, start, end, to); return print_playlist_result(client, result); } diff --git a/src/playlist.h b/src/playlist.h index efe13b0b8..41befe455 100644 --- a/src/playlist.h +++ b/src/playlist.h @@ -158,7 +158,7 @@ void deleteASongFromPlaylist(struct playlist *playlist, const struct song *song); enum playlist_result -moveSongInPlaylist(struct playlist *playlist, unsigned from, int to); +moveSongRangeInPlaylist(struct playlist *playlist, unsigned start, unsigned end, int to); enum playlist_result moveSongInPlaylistById(struct playlist *playlist, unsigned id, int to); diff --git a/src/playlist_edit.c b/src/playlist_edit.c index 8580a5030..b83dc0933 100644 --- a/src/playlist_edit.c +++ b/src/playlist_edit.c @@ -290,19 +290,21 @@ deleteASongFromPlaylist(struct playlist *playlist, const struct song *song) } enum playlist_result -moveSongInPlaylist(struct playlist *playlist, unsigned from, int to) +moveSongRangeInPlaylist(struct playlist *playlist, unsigned start, unsigned end, int to) { const struct song *queued; int currentSong; - if (!queue_valid_position(&playlist->queue, from)) + if (!queue_valid_position(&playlist->queue, start) || + !queue_valid_position(&playlist->queue, end - 1)) return PLAYLIST_RESULT_BAD_RANGE; - if ((to >= 0 && to >= (int)queue_length(&playlist->queue)) || + if ((to >= 0 && to + end - start - 1 >= queue_length(&playlist->queue)) || (to < 0 && abs(to) > (int)queue_length(&playlist->queue))) return PLAYLIST_RESULT_BAD_RANGE; - if ((int)from == to) /* no-op */ + if ((int)start == to) + /* nothing happens */ return PLAYLIST_RESULT_SUCCESS; queued = playlist_get_queued_song(playlist); @@ -316,24 +318,27 @@ moveSongInPlaylist(struct playlist *playlist, unsigned from, int to) playlist->current) : -1; if (to < 0 && playlist->current >= 0) { - if ((unsigned)currentSong == from) + if (start <= (unsigned)currentSong && (unsigned)currentSong <= end) /* no-op, can't be moved to offset of itself */ return PLAYLIST_RESULT_SUCCESS; to = (currentSong + abs(to)) % queue_length(&playlist->queue); + if (start < (unsigned)to) + to--; } - queue_move(&playlist->queue, from, to); + queue_move_range(&playlist->queue, start, end, to); if (!playlist->queue.random) { /* update current/queued */ - if (playlist->current == (int)from) - playlist->current = to; - else if (playlist->current > (int)from && + if ((int)start <= playlist->current && + (unsigned)playlist->current < end) + playlist->current += to - start; + else if (playlist->current >= (int)end && playlist->current <= to) { - playlist->current--; + playlist->current -= end - start; } else if (playlist->current >= to && - playlist->current < (int)from) { - playlist->current++; + playlist->current < (int)start) { + playlist->current += end - start; } } @@ -351,7 +356,7 @@ moveSongInPlaylistById(struct playlist *playlist, unsigned id1, int to) if (song < 0) return PLAYLIST_RESULT_NO_SUCH_SONG; - return moveSongInPlaylist(playlist, song, to); + return moveSongRangeInPlaylist(playlist, song, song+1, to); } void shufflePlaylist(struct playlist *playlist, unsigned start, unsigned end) diff --git a/src/queue.c b/src/queue.c index 581e5c566..b9486cfe5 100644 --- a/src/queue.c +++ b/src/queue.c @@ -172,6 +172,48 @@ queue_move(struct queue *queue, unsigned from, unsigned to) } } +void +queue_move_range(struct queue *queue, unsigned start, unsigned end, unsigned to) +{ + struct queue_item items[end - start]; + // Copy the original block [start,end-1] + for (unsigned i = start; i < end; i++) + items[i - start] = queue->items[i]; + + // If to > start, we need to move to-start items to start, starting from end + for (unsigned i = end; i < end + to - start; i++) + queue_move_song_to(queue, i, start + i - end); + + // If to < start, we need to move start-to items to newend (= end + to - start), starting from to + // This is the same as moving items from start-1 to to (decreasing), with start-1 going to end-1 + // We have to iterate in this order to avoid writing over something we haven't yet moved + for (unsigned i = start - 1; i >= to && i != G_MAXUINT; i--) + queue_move_song_to(queue, i, i + end - start); + + // Copy the original block back in, starting at to. + for (unsigned i = start; i< end; i++) + { + queue->idToPosition[items[i-start].id] = to + i - start; + queue->items[to + i - start] = items[i-start]; + queue->items[to + i - start].version = queue->version; + } + + if (queue->random) { + // Update the positions in the queue. + // Note that the ranges for these cases are the same as the ranges of + // the loops above. + for (unsigned i = 0; i < queue->length; i++) { + if (queue->order[i] >= end && queue->order[i] < to + end - start) + queue->order[i] -= end - start; + else if (queue->order[i] < start && + queue->order[i] >= to) + queue->order[i] += end - start; + else if (start <= queue->order[i] && queue->order[i] < end) + queue->order[i] += to - start; + } + } +} + void queue_delete(struct queue *queue, unsigned position) { diff --git a/src/queue.h b/src/queue.h index 402c6bd26..7f46c2e19 100644 --- a/src/queue.h +++ b/src/queue.h @@ -291,6 +291,12 @@ queue_swap_order(struct queue *queue, unsigned order1, unsigned order2) void queue_move(struct queue *queue, unsigned from, unsigned to); +/** + * Moves a range of songs to a new position. + */ +void +queue_move_range(struct queue *queue, unsigned start, unsigned end, unsigned to); + /** * Removes a song from the playlist. */ -- cgit v1.2.3