xref: /haiku/src/apps/mediaplayer/playlist/MovePLItemsCommand.cpp (revision 1deede7388b04dbeec5af85cae7164735ea9e70d)
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 
22 using std::nothrow;
23 
24 
25 MovePLItemsCommand::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 
64 MovePLItemsCommand::~MovePLItemsCommand()
65 {
66 	delete[] fItems;
67 	delete[] fIndices;
68 }
69 
70 
71 status_t
72 MovePLItemsCommand::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 
108 status_t
109 MovePLItemsCommand::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 
143 status_t
144 MovePLItemsCommand::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 
177 void
178 MovePLItemsCommand::GetName(BString& name)
179 {
180 	if (fCount > 1)
181 		name << B_TRANSLATE("Move Entries");
182 	else
183 		name << B_TRANSLATE("Move Entry");
184 }
185