1/*
2 * Copyright 2007-2009 Stephan A��mus <superstippi@gmx.de>.
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
5
6#include "MovePLItemsCommand.h"
7
8#include <new>
9#include <stdio.h>
10
11#include <Autolock.h>
12#include <Catalog.h>
13#include <Locale.h>
14
15#include "Playlist.h"
16
17
18#undef B_TRANSLATION_CONTEXT
19#define B_TRANSLATION_CONTEXT "MediaPlayer-MovePLItemsCmd"
20
21
22using std::nothrow;
23
24
25MovePLItemsCommand::MovePLItemsCommand(Playlist* playlist,
26		 BList indices, int32 toIndex)
27	:
28	PLItemsCommand(),
29	fPlaylist(playlist),
30	fCount(indices.CountItems()),
31	fItems(fCount > 0 ? new (nothrow) PlaylistItem*[fCount] : NULL),
32	fIndices(fCount > 0 ? new (nothrow) int32[fCount] : NULL),
33	fToIndex(toIndex)
34{
35	if (indices.IsEmpty()) {
36		// indicate a bad object state
37		delete[] fItems;
38		fItems = NULL;
39		return;
40	}
41
42	memset(fItems, 0, sizeof(PlaylistItem*) * fCount);
43
44	// init original entry indices and
45	// adjust toIndex compensating for items that
46	// are removed before that index
47	int32 itemsBeforeIndex = 0;
48	for (int32 i = 0; i < fCount; i++) {
49		fIndices[i] = (int32)(addr_t)indices.ItemAt(i);
50		fItems[i] = fPlaylist->ItemAt(fIndices[i]);
51		if (fItems[i] == NULL) {
52			// indicate a bad object state
53			delete[] fItems;
54			fItems = NULL;
55			return;
56		}
57		if (fIndices[i] < fToIndex)
58			itemsBeforeIndex++;
59	}
60	fToIndex -= itemsBeforeIndex;
61}
62
63
64MovePLItemsCommand::~MovePLItemsCommand()
65{
66	delete[] fItems;
67	delete[] fIndices;
68}
69
70
71status_t
72MovePLItemsCommand::InitCheck()
73{
74	if (!fItems)
75		return B_NO_INIT;
76
77	// analyse the move, don't return B_OK in case
78	// the container state does not change...
79
80	int32 index = fIndices[0];
81		// NOTE: fIndices == NULL if fCount < 1
82
83	if (index != fToIndex) {
84		// a change is guaranteed
85		return B_OK;
86	}
87
88	// the insertion index is the same as the index of the first
89	// moved item, a change only occures if the indices of the
90	// moved items is not contiguous
91	bool isContiguous = true;
92	for (int32 i = 1; i < fCount; i++) {
93		if (fIndices[i] != index + 1) {
94			isContiguous = false;
95			break;
96		}
97		index = fIndices[i];
98	}
99	if (isContiguous) {
100		// the container state will not change because of the move
101		return B_ERROR;
102	}
103
104	return B_OK;
105}
106
107
108status_t
109MovePLItemsCommand::Perform()
110{
111	BAutolock _(fPlaylist);
112
113	status_t ret = B_OK;
114
115	// remember currently playling item in case we move it
116	PlaylistItem* current = fPlaylist->ItemAt(fPlaylist->CurrentItemIndex());
117
118	// remove refs from playlist
119	for (int32 i = 0; i < fCount; i++) {
120		// "- i" to account for the items already removed
121		fPlaylist->RemoveItem(fIndices[i] - i, false);
122	}
123
124	// add refs to playlist at the insertion index
125	int32 index = fToIndex;
126	for (int32 i = 0; i < fCount; i++) {
127		if (!fPlaylist->AddItem(fItems[i], index++)) {
128			ret = B_NO_MEMORY;
129			break;
130		}
131	}
132	if (ret < B_OK)
133		return ret;
134
135	// take care about currently played item
136	if (current != NULL)
137		fPlaylist->SetCurrentItemIndex(fPlaylist->IndexOf(current), false);
138
139	return B_OK;
140}
141
142
143status_t
144MovePLItemsCommand::Undo()
145{
146	BAutolock _(fPlaylist);
147
148	status_t ret = B_OK;
149
150	// remember currently playling item in case we move it
151	PlaylistItem* current = fPlaylist->ItemAt(fPlaylist->CurrentItemIndex());
152
153	// remove refs from playlist
154	int32 index = fToIndex;
155	for (int32 i = 0; i < fCount; i++) {
156		fPlaylist->RemoveItem(index++, false);
157	}
158
159	// add ref to playlist at remembered indices
160	for (int32 i = 0; i < fCount; i++) {
161		if (!fPlaylist->AddItem(fItems[i], fIndices[i])) {
162			ret = B_NO_MEMORY;
163			break;
164		}
165	}
166	if (ret < B_OK)
167		return ret;
168
169	// take care about currently played item
170	if (current != NULL)
171		fPlaylist->SetCurrentItemIndex(fPlaylist->IndexOf(current), false);
172
173	return B_OK;
174}
175
176
177void
178MovePLItemsCommand::GetName(BString& name)
179{
180	if (fCount > 1)
181		name << B_TRANSLATE("Move Entries");
182	else
183		name << B_TRANSLATE("Move Entry");
184}
185