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