xref: /haiku/src/apps/mediaplayer/playlist/RandomizePLItemsCommand.cpp (revision 4c8cf0257e2eacda6d7b210cf5ab835e903dc28b)
1 /*
2  * Copyright © 2008-2009 Stephan Aßmus <superstippi@gmx.de>
3  * All rights reserved. Distributed under the terms of the MIT License.
4  */
5 
6 #include "RandomizePLItemsCommand.h"
7 
8 #include <new>
9 #include <stdio.h>
10 #include <stdlib.h>
11 
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-RandomizePLItemsCmd"
21 
22 
23 using std::nothrow;
24 
25 
RandomizePLItemsCommand(Playlist * playlist,BList indices)26 RandomizePLItemsCommand::RandomizePLItemsCommand(Playlist* playlist,
27 		 BList indices)
28 	:
29 	PLItemsCommand(),
30 	fPlaylist(playlist),
31 	fCount(indices.CountItems()),
32 	fItems(fCount > 0 ? new (nothrow) PlaylistItem*[fCount] : NULL),
33 	fListIndices(fCount > 0 ? new (nothrow) int32[fCount] : NULL),
34 	fRandomInternalIndices(fCount > 0 ? new (nothrow) int32[fCount] : NULL)
35 {
36 	if (indices.IsEmpty() || !fPlaylist || !fItems || !fListIndices
37 			|| !fRandomInternalIndices) {
38 		// indicate a bad object state
39 		delete[] fItems;
40 		fItems = NULL;
41 		return;
42 	}
43 
44 	memset(fItems, 0, fCount * sizeof(PlaylistItem*));
45 
46 	// put the available indices into a "set"
47 	BList indexSet;
48 	for (int32 i = 0; i < fCount; i++) {
49 		fListIndices[i] = (int32)(addr_t)indices.ItemAt(i);
50 		fItems[i] = fPlaylist->ItemAt(fListIndices[i]);
51 		if (fItems[i] == NULL || !indexSet.AddItem((void*)(addr_t)i)) {
52 			// indicate a bad object state
53 			delete[] fItems;
54 			fItems = NULL;
55 			return;
56 		}
57 	}
58 
59 	// remove the indices from the set in random order
60 	for (int32 i = 0; i < fCount; i++) {
61 		int32 randomSetIndex = rand() % indexSet.CountItems();
62 		fRandomInternalIndices[i] = (int32)(addr_t)indexSet.RemoveItem(randomSetIndex);
63 	}
64 }
65 
66 
~RandomizePLItemsCommand()67 RandomizePLItemsCommand::~RandomizePLItemsCommand()
68 {
69 	delete[] fItems;
70 	delete[] fListIndices;
71 	delete[] fRandomInternalIndices;
72 }
73 
74 
75 status_t
InitCheck()76 RandomizePLItemsCommand::InitCheck()
77 {
78 	if (!fItems)
79 		return B_NO_INIT;
80 
81 	return B_OK;
82 }
83 
84 
85 status_t
Perform()86 RandomizePLItemsCommand::Perform()
87 {
88 	return _Sort(true);
89 }
90 
91 
92 status_t
Undo()93 RandomizePLItemsCommand::Undo()
94 {
95 	return _Sort(false);
96 }
97 
98 
99 void
GetName(BString & name)100 RandomizePLItemsCommand::GetName(BString& name)
101 {
102 	name << B_TRANSLATE("Randomize Entries");
103 }
104 
105 
106 status_t
_Sort(bool random)107 RandomizePLItemsCommand::_Sort(bool random)
108 {
109 	BAutolock _(fPlaylist);
110 
111 	// remember currently playling item in case we move it
112 	PlaylistItem* current = fPlaylist->ItemAt(fPlaylist->CurrentItemIndex());
113 
114 	// remove refs from playlist
115 	for (int32 i = 0; i < fCount; i++) {
116 		// "- i" to account for the items already removed
117 		fPlaylist->RemoveItem(fListIndices[i] - i, false);
118 	}
119 
120 	// add refs to playlist at the randomized indices
121 	if (random) {
122 		for (int32 i = 0; i < fCount; i++) {
123 			if (!fPlaylist->AddItem(fItems[fRandomInternalIndices[i]],
124 					fListIndices[i])) {
125 				return B_NO_MEMORY;
126 			}
127 		}
128 	} else {
129 		for (int32 i = 0; i < fCount; i++) {
130 			if (!fPlaylist->AddItem(fItems[i], fListIndices[i])) {
131 				return B_NO_MEMORY;
132 			}
133 		}
134 	}
135 
136 	// take care about currently played item
137 	if (current != NULL)
138 		fPlaylist->SetCurrentItemIndex(fPlaylist->IndexOf(current), false);
139 
140 	return B_OK;
141 }
142