diff --git a/src/apps/mediaplayer/Jamfile b/src/apps/mediaplayer/Jamfile index 3dae93bf66..b465efd6d4 100644 --- a/src/apps/mediaplayer/Jamfile +++ b/src/apps/mediaplayer/Jamfile @@ -61,6 +61,7 @@ Application MediaPlayer : PlaylistListView.cpp PlaylistObserver.cpp PlaylistWindow.cpp + RandomizePLItemsCommand.cpp RemovePLItemsCommand.cpp # settings diff --git a/src/apps/mediaplayer/MainApp.cpp b/src/apps/mediaplayer/MainApp.cpp index 9be57d73d4..ab746e4641 100644 --- a/src/apps/mediaplayer/MainApp.cpp +++ b/src/apps/mediaplayer/MainApp.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #include "EventQueue.h" @@ -225,6 +226,8 @@ main() { EventQueue::CreateDefault(); + srand(system_time()); + gMainApp = new MainApp; gMainApp->Run(); delete gMainApp; diff --git a/src/apps/mediaplayer/playlist/MovePLItemsCommand.cpp b/src/apps/mediaplayer/playlist/MovePLItemsCommand.cpp index 284d8124a8..554875e458 100644 --- a/src/apps/mediaplayer/playlist/MovePLItemsCommand.cpp +++ b/src/apps/mediaplayer/playlist/MovePLItemsCommand.cpp @@ -43,6 +43,7 @@ MovePLItemsCommand::MovePLItemsCommand(Playlist* playlist, int32 itemsBeforeIndex = 0; for (int32 i = 0; i < fCount; i++) { if (fPlaylist->GetRefAt(fIndices[i], &fRefs[i]) < B_OK) { + // indicate a bad object state delete[] fRefs; fRefs = NULL; return; @@ -64,7 +65,7 @@ MovePLItemsCommand::~MovePLItemsCommand() status_t MovePLItemsCommand::InitCheck() { - if (!fPlaylist || !fRefs || !fIndices) + if (!fRefs) return B_NO_INIT; // analyse the move, don't return B_OK in case diff --git a/src/apps/mediaplayer/playlist/Playlist.h b/src/apps/mediaplayer/playlist/Playlist.h index a5ee9eff23..b8962651c2 100644 --- a/src/apps/mediaplayer/playlist/Playlist.h +++ b/src/apps/mediaplayer/playlist/Playlist.h @@ -52,7 +52,7 @@ public: // list functionality void MakeEmpty(); int32 CountItems() const; - + void Sort(); bool AddRef(const entry_ref& ref); diff --git a/src/apps/mediaplayer/playlist/PlaylistListView.cpp b/src/apps/mediaplayer/playlist/PlaylistListView.cpp index 3e02d81889..e23b1f6273 100644 --- a/src/apps/mediaplayer/playlist/PlaylistListView.cpp +++ b/src/apps/mediaplayer/playlist/PlaylistListView.cpp @@ -26,6 +26,7 @@ #include "PlaybackState.h" #include "Playlist.h" #include "PlaylistObserver.h" +#include "RandomizePLItemsCommand.h" #include "RemovePLItemsCommand.h" using std::nothrow; @@ -375,6 +376,41 @@ PlaylistListView::RefsReceived(BMessage* message, int32 appendIndex) } +void +PlaylistListView::Randomize() +{ + int32 count = CountItems(); + if (count == 0) + return; + + BList indices; + + // add current selection + count = 0; + while (true) { + int32 index = CurrentSelection(count); + if (index < 0) + break; + if (!indices.AddItem((void*)index)) + return; + count++; + } + + // was anything selected? + if (count == 0) { + // no selection, simply add all items + count = CountItems(); + for (int32 i = 0; i < count; i++) { + if (!indices.AddItem((void*)i)) + return; + } + } + + fCommandStack->Perform(new (nothrow) RandomizePLItemsCommand(fPlaylist, + (int32*)indices.Items(), indices.CountItems())); +} + + // #pragma mark - diff --git a/src/apps/mediaplayer/playlist/PlaylistListView.h b/src/apps/mediaplayer/playlist/PlaylistListView.h index 0a4b44ed0c..f7b1201b07 100644 --- a/src/apps/mediaplayer/playlist/PlaylistListView.h +++ b/src/apps/mediaplayer/playlist/PlaylistListView.h @@ -44,6 +44,8 @@ class PlaylistListView : public SimpleListView { void RefsReceived(BMessage* message, int32 appendIndex); + void Randomize(); + private: void _FullSync(); void _AddItem(const entry_ref& ref, int32 index); diff --git a/src/apps/mediaplayer/playlist/PlaylistWindow.cpp b/src/apps/mediaplayer/playlist/PlaylistWindow.cpp index 944392e5ac..410b80884c 100644 --- a/src/apps/mediaplayer/playlist/PlaylistWindow.cpp +++ b/src/apps/mediaplayer/playlist/PlaylistWindow.cpp @@ -31,9 +31,13 @@ #define DEBUG 1 enum { - M_PLAYLIST_OPEN = 'open', - M_PLAYLIST_SAVE = 'save', - M_PLAYLIST_EMPTY = 'emty' + // file + M_PLAYLIST_OPEN = 'open', + M_PLAYLIST_SAVE = 'save', + + // edit + M_PLAYLIST_EMPTY = 'emty', + M_PLAYLIST_RANDOMIZE = 'rand' }; #define SPACE 5 @@ -144,9 +148,14 @@ PlaylistWindow::MessageReceived(BMessage* message) fOpenPanel = new BFilePanel(B_OPEN_PANEL); fOpenPanel->Show(); break; + case M_PLAYLIST_EMPTY: fListView->RemoveAll(); - break; + break; + case M_PLAYLIST_RANDOMIZE: + fListView->Randomize(); + break; + default: BWindow::MessageReceived(message); break; @@ -180,6 +189,8 @@ PlaylistWindow::_CreateMenu(BRect& frame) editMenu->AddSeparatorItem(); editMenu->AddItem(new BMenuItem("Make Empty", new BMessage(M_PLAYLIST_EMPTY), 'N')); + editMenu->AddItem(new BMenuItem("Randomize", + new BMessage(M_PLAYLIST_RANDOMIZE), 'R')); menuBar->AddItem(editMenu); AddChild(menuBar); diff --git a/src/apps/mediaplayer/playlist/RandomizePLItemsCommand.cpp b/src/apps/mediaplayer/playlist/RandomizePLItemsCommand.cpp new file mode 100644 index 0000000000..49db05a835 --- /dev/null +++ b/src/apps/mediaplayer/playlist/RandomizePLItemsCommand.cpp @@ -0,0 +1,135 @@ +/* + * Copyright © 2008 Stephan Aßmus. All rights reserved. + * Distributed under the terms of the MIT License. + */ + +#include "RandomizePLItemsCommand.h" + +#include +#include +#include + +#include + +#include "Playlist.h" + + +using std::nothrow; + + +RandomizePLItemsCommand::RandomizePLItemsCommand(Playlist* playlist, + const int32* indices, int32 count) + : Command() + , fPlaylist(playlist) + , fRefs(count > 0 ? new (nothrow) entry_ref[count] : NULL) + , fListIndices(count > 0 ? new (nothrow) int32[count] : NULL) + , fRandomInternalIndices(count > 0 ? new (nothrow) int32[count] : NULL) + , fCount(count) +{ + if (!indices || !fPlaylist || !fRefs || !fListIndices + || !fRandomInternalIndices) { + // indicate a bad object state + delete[] fRefs; + fRefs = NULL; + return; + } + + memcpy(fListIndices, indices, fCount * sizeof(int32)); + + // put the available indices into a "set" + BList indexSet; + for (int32 i = 0; i < fCount; i++) { + if (fPlaylist->GetRefAt(fListIndices[i], &fRefs[i]) < B_OK + || !indexSet.AddItem((void*)i)) { + // indicate a bad object state + delete[] fRefs; + fRefs = NULL; + return; + } + } + + // remove the indices from the set in random order + for (int32 i = 0; i < fCount; i++) { + int32 randomSetIndex = rand() % indexSet.CountItems(); + fRandomInternalIndices[i] = (int32)indexSet.RemoveItem(randomSetIndex); + } +} + + +RandomizePLItemsCommand::~RandomizePLItemsCommand() +{ + delete[] fRefs; + delete[] fListIndices; + delete[] fRandomInternalIndices; +} + + +status_t +RandomizePLItemsCommand::InitCheck() +{ + if (!fRefs) + return B_NO_INIT; + + return B_OK; +} + + +status_t +RandomizePLItemsCommand::Perform() +{ + return _Sort(true); +} + + +status_t +RandomizePLItemsCommand::Undo() +{ + return _Sort(false); +} + + +void +RandomizePLItemsCommand::GetName(BString& name) +{ + name << "Randomize Entries"; +} + + +status_t +RandomizePLItemsCommand::_Sort(bool random) +{ + BAutolock _(fPlaylist); + + // remember currently playling ref in case we move it + entry_ref currentRef; + bool adjustCurrentRef = fPlaylist->GetRefAt(fPlaylist->CurrentRefIndex(), + ¤tRef) == B_OK; + + // remove refs from playlist + for (int32 i = 0; i < fCount; i++) { + // "- i" to account for the items already removed + fPlaylist->RemoveRef(fListIndices[i] - i, false); + } + + // add refs to playlist at the randomized indices + if (random) { + for (int32 i = 0; i < fCount; i++) { + if (!fPlaylist->AddRef(fRefs[fRandomInternalIndices[i]], + fListIndices[i])) { + return B_NO_MEMORY; + } + } + } else { + for (int32 i = 0; i < fCount; i++) { + if (!fPlaylist->AddRef(fRefs[i], fListIndices[i])) { + return B_NO_MEMORY; + } + } + } + + // take care about currently played ref + if (adjustCurrentRef) + fPlaylist->SetCurrentRefIndex(fPlaylist->IndexOf(currentRef)); + + return B_OK; +} diff --git a/src/apps/mediaplayer/playlist/RandomizePLItemsCommand.h b/src/apps/mediaplayer/playlist/RandomizePLItemsCommand.h new file mode 100644 index 0000000000..63ff18c259 --- /dev/null +++ b/src/apps/mediaplayer/playlist/RandomizePLItemsCommand.h @@ -0,0 +1,39 @@ +/* + * Copyright © 2008 Stephan Aßmus. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef RANDOMIZE_PL_ITEMS_COMMAND_H +#define RANDOMIZE_PL_ITEMS_COMMAND_H + + +#include "Command.h" + +class Playlist; +struct entry_ref; + +class RandomizePLItemsCommand : public Command { + public: + RandomizePLItemsCommand( + Playlist* playlist, + const int32* indices, + int32 count); + virtual ~RandomizePLItemsCommand(); + + virtual status_t InitCheck(); + + virtual status_t Perform(); + virtual status_t Undo(); + + virtual void GetName(BString& name); + + private: + status_t _Sort(bool random); + + Playlist* fPlaylist; + entry_ref* fRefs; + int32* fListIndices; + int32* fRandomInternalIndices; + int32 fCount; +}; + +#endif // RANDOMIZE_PL_ITEMS_COMMAND_H