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