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