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 26 RandomizePLItemsCommand::RandomizePLItemsCommand(Playlist* playlist, 27 const int32* indices, int32 count) 28 : 29 PLItemsCommand(), 30 fPlaylist(playlist), 31 fItems(count > 0 ? new (nothrow) PlaylistItem*[count] : NULL), 32 fListIndices(count > 0 ? new (nothrow) int32[count] : NULL), 33 fRandomInternalIndices(count > 0 ? new (nothrow) int32[count] : NULL), 34 fCount(count) 35 { 36 if (!indices || !fPlaylist || !fItems || !fListIndices 37 || !fRandomInternalIndices) { 38 // indicate a bad object state 39 delete[] fItems; 40 fItems = NULL; 41 return; 42 } 43 44 memcpy(fListIndices, indices, fCount * sizeof(int32)); 45 memset(fItems, 0, fCount * sizeof(PlaylistItem*)); 46 47 // put the available indices into a "set" 48 BList indexSet; 49 for (int32 i = 0; i < fCount; 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 67 RandomizePLItemsCommand::~RandomizePLItemsCommand() 68 { 69 delete[] fItems; 70 delete[] fListIndices; 71 delete[] fRandomInternalIndices; 72 } 73 74 75 status_t 76 RandomizePLItemsCommand::InitCheck() 77 { 78 if (!fItems) 79 return B_NO_INIT; 80 81 return B_OK; 82 } 83 84 85 status_t 86 RandomizePLItemsCommand::Perform() 87 { 88 return _Sort(true); 89 } 90 91 92 status_t 93 RandomizePLItemsCommand::Undo() 94 { 95 return _Sort(false); 96 } 97 98 99 void 100 RandomizePLItemsCommand::GetName(BString& name) 101 { 102 name << B_TRANSLATE("Randomize Entries"); 103 } 104 105 106 status_t 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