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 "RemovePLItemsCommand.h"
7
8#include <new>
9#include <stdio.h>
10
11#include <Alert.h>
12#include <Autolock.h>
13#include <Catalog.h>
14#include <Locale.h>
15
16#include "Playlist.h"
17
18
19#undef B_TRANSLATION_CONTEXT
20#define B_TRANSLATION_CONTEXT "MediaPlayer-RemovePLItemsCmd"
21
22
23using std::nothrow;
24
25
26RemovePLItemsCommand::RemovePLItemsCommand(Playlist* playlist,
27		 BList indices, bool moveFilesToTrash)
28	:
29	PLItemsCommand(),
30	fPlaylist(playlist),
31	fCount(indices.CountItems()),
32	fItems(fCount > 0 ? new (nothrow) PlaylistItem*[fCount] : NULL),
33	fIndices(fCount > 0 ? new (nothrow) int32[fCount] : NULL),
34	fMoveFilesToTrash(moveFilesToTrash),
35	fMoveErrorShown(false),
36	fItemsRemoved(false)
37{
38	if (indices.IsEmpty()) {
39		// indicate a bad object state
40		delete[] fItems;
41		fItems = NULL;
42		return;
43	}
44
45	memset(fItems, 0, fCount * sizeof(PlaylistItem*));
46
47	// init original entry indices
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			delete[] fItems;
53			fItems = NULL;
54			return;
55		}
56	}
57}
58
59
60RemovePLItemsCommand::~RemovePLItemsCommand()
61{
62	_CleanUp(fItems, fCount, fItemsRemoved);
63	delete[] fIndices;
64}
65
66
67status_t
68RemovePLItemsCommand::InitCheck()
69{
70	if (!fPlaylist || !fItems || !fIndices)
71		return B_NO_INIT;
72	return B_OK;
73}
74
75
76status_t
77RemovePLItemsCommand::Perform()
78{
79	BAutolock _(fPlaylist);
80
81	fItemsRemoved = true;
82
83	int32 lastRemovedIndex = -1;
84
85	// remove refs from playlist
86	for (int32 i = 0; i < fCount; i++) {
87		// "- i" to account for the items already removed
88		lastRemovedIndex = fIndices[i] - i;
89		fPlaylist->RemoveItem(lastRemovedIndex);
90	}
91
92	// in case we removed the currently playing file
93	if (fPlaylist->CurrentItemIndex() == -1)
94		fPlaylist->SetCurrentItemIndex(lastRemovedIndex);
95
96	if (fMoveFilesToTrash) {
97		BString errorFiles;
98		status_t moveError = B_OK;
99		bool errorOnAllFiles = true;
100		for (int32 i = 0; i < fCount; i++) {
101			status_t err = fItems[i]->MoveIntoTrash();
102			if (err != B_OK) {
103				moveError = err;
104				if (errorFiles.Length() > 0)
105					errorFiles << ' ';
106				errorFiles << fItems[i]->Name();
107			} else
108				errorOnAllFiles = false;
109		}
110		// Show an error alert if necessary
111		if (!fMoveErrorShown && moveError != B_OK) {
112			fMoveErrorShown = true;
113			BString message;
114			if (errorOnAllFiles)
115				message <<
116					B_TRANSLATE("All files could not be moved into Trash.");
117			else
118				message <<
119					B_TRANSLATE("Some files could not be moved into Trash.");
120			message << "\n\n" << B_TRANSLATE("Error: ") << strerror(moveError);
121			BAlert* alert = new BAlert(B_TRANSLATE("Move into trash error"),
122				message.String(), B_TRANSLATE("OK"), NULL, NULL,
123				B_WIDTH_AS_USUAL, B_WARNING_ALERT);
124			alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
125			alert->Go(NULL);
126		}
127	}
128
129	return B_OK;
130}
131
132
133status_t
134RemovePLItemsCommand::Undo()
135{
136	BAutolock _(fPlaylist);
137
138	fItemsRemoved = false;
139
140	if (fMoveFilesToTrash) {
141		for (int32 i = 0; i < fCount; i++) {
142			fItems[i]->RestoreFromTrash();
143		}
144	}
145
146	// remember currently playling item in case we move it
147	PlaylistItem* current = fPlaylist->ItemAt(fPlaylist->CurrentItemIndex());
148
149	// add items to playlist at remembered indices
150	status_t ret = B_OK;
151	for (int32 i = 0; i < fCount; i++) {
152		if (!fPlaylist->AddItem(fItems[i], fIndices[i])) {
153			ret = B_NO_MEMORY;
154			break;
155		}
156	}
157	if (ret < B_OK)
158		return ret;
159
160	// take care about currently played ref
161	if (current != NULL)
162		fPlaylist->SetCurrentItemIndex(fPlaylist->IndexOf(current), false);
163
164	return B_OK;
165}
166
167
168void
169RemovePLItemsCommand::GetName(BString& name)
170{
171	if (fMoveFilesToTrash) {
172		if (fCount > 1)
173			name << B_TRANSLATE("Remove Entries into Trash");
174		else
175			name << B_TRANSLATE("Remove Entry into Trash");
176	}
177	else
178	{
179		if (fCount > 1)
180			name << B_TRANSLATE("Remove Entries");
181		else
182			name << B_TRANSLATE("Remove Entry");
183	}
184}
185