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