* Changed the PlaylistItem interface to be hopefully more flexible. It can

probably still be improved.
* Renamed EntryRefPlaylistItem to just FilePlaylistItem.
* Moved the "move into Trash" and "restore from Trash" implementation into
  FilePlaylistItem. Also added what's needed to allow Tracker to restore the
  entry itself.
* Refactored everything to make Playlist use PlaylistItems instead of
  entry_refs and all that entails...
* The transition to virtualize PlaylistItems is not complete yet in the
  Controller, since it still uses BMediaFile there. But it's much easier to
  change that now.
* Objects which keep a PlaylistItem around do correct reference counting, but
  some commands could be simplified if they were using references as well. It
  still should work correctly, though, if I didn't miss anything. It should also
  fix theoretical situations of encountering out-of-memory while messing with
  the Playlist leading to inconsistent state between Undo/Redo and then leaking
  items because of that.
* Added the discussed change that MediaPlayer checks it's own supported types
  before rejecting a file by super type. (untested)
* When importing playlist items, the currently playling item is better
  maintained during Undo/Redo.
* Some debugging code added in MediaTrackAudioSupplier, no functional changes.
* Fixed a number of coding style issues and automatic whitespace cleanup.



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30834 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus
2009-05-24 12:21:56 +00:00
parent a428058ded
commit c60fcc87e0
33 changed files with 1248 additions and 919 deletions
+24 -28
View File
@@ -51,10 +51,10 @@
using std::nothrow; using std::nothrow;
void void
HandleError(const char *text, status_t err) HandleError(const char *text, status_t err)
{ {
if (err != B_OK) { if (err != B_OK) {
printf("%s. error 0x%08x (%s)\n",text, (int)err, strerror(err)); printf("%s. error 0x%08x (%s)\n",text, (int)err, strerror(err));
fflush(NULL); fflush(NULL);
exit(1); exit(1);
@@ -91,7 +91,7 @@ Controller::Controller()
// but use only if there are multiple players running at all! // but use only if there are multiple players running at all!
fMuted(false), fMuted(false),
fRef(), fItem(NULL),
fMediaFile(NULL), fMediaFile(NULL),
fVideoSupplier(new ProxyVideoSupplier()), fVideoSupplier(new ProxyVideoSupplier()),
@@ -185,11 +185,11 @@ Controller::CreateAudioSupplier()
status_t status_t
Controller::SetTo(const entry_ref &ref) Controller::SetTo(const PlaylistItemRef& item)
{ {
BAutolock _(this); BAutolock _(this);
if (fRef == ref) { if (fItem == item) {
if (InitCheck() == B_OK) { if (InitCheck() == B_OK) {
if (fAutoplay) { if (fAutoplay) {
SetPosition(0.0); SetPosition(0.0);
@@ -199,14 +199,14 @@ Controller::SetTo(const entry_ref &ref)
return B_OK; return B_OK;
} }
fRef = ref; fItem = item;
fAudioSupplier->SetSupplier(NULL, fVideoFrameRate); fAudioSupplier->SetSupplier(NULL, fVideoFrameRate);
fVideoSupplier->SetSupplier(NULL); fVideoSupplier->SetSupplier(NULL);
fAudioTrackList.MakeEmpty(); fAudioTrackList.MakeEmpty();
fVideoTrackList.MakeEmpty(); fVideoTrackList.MakeEmpty();
ObjectDeleter<BMediaFile> oldMediaFileDeleter(fMediaFile); ObjectDeleter<BMediaFile> oldMediaFileDeleter(fMediaFile);
// BMediaFile destructor will call ReleaseAllTracks() // BMediaFile destructor will call ReleaseAllTracks()
fMediaFile = NULL; fMediaFile = NULL;
@@ -224,25 +224,26 @@ Controller::SetTo(const entry_ref &ref)
fDuration = 0; fDuration = 0;
fVideoFrameRate = 25.0; fVideoFrameRate = 25.0;
status_t err; if (fItem.Get() == NULL)
return B_BAD_VALUE;
BMediaFile* mf = new BMediaFile(&ref);
BMediaFile* mf = fItem->CreateMediaFile();
ObjectDeleter<BMediaFile> mediaFileDeleter(mf); ObjectDeleter<BMediaFile> mediaFileDeleter(mf);
err = mf->InitCheck(); status_t err = mf->InitCheck();
if (err != B_OK) { if (err != B_OK) {
printf("Controller::SetTo: initcheck failed\n"); printf("Controller::SetTo: initcheck failed\n");
_NotifyFileChanged(); _NotifyFileChanged();
return err; return err;
} }
int trackcount = mf->CountTracks(); int trackcount = mf->CountTracks();
if (trackcount <= 0) { if (trackcount <= 0) {
printf("Controller::SetTo: trackcount %d\n", trackcount); printf("Controller::SetTo: trackcount %d\n", trackcount);
_NotifyFileChanged(); _NotifyFileChanged();
return B_MEDIA_NO_HANDLER; return B_MEDIA_NO_HANDLER;
} }
for (int i = 0; i < trackcount; i++) { for (int i = 0; i < trackcount; i++) {
BMediaTrack* t = mf->TrackAt(i); BMediaTrack* t = mf->TrackAt(i);
media_format f; media_format f;
@@ -253,13 +254,13 @@ Controller::SetTo(const entry_ref &ref)
mf->ReleaseTrack(t); mf->ReleaseTrack(t);
continue; continue;
} }
if (t->Duration() <= 0) { if (t->Duration() <= 0) {
printf("Controller::SetTo: track index %d has no duration\n",i); printf("Controller::SetTo: track index %d has no duration\n",i);
mf->ReleaseTrack(t); mf->ReleaseTrack(t);
continue; continue;
} }
if (f.IsAudio()) { if (f.IsAudio()) {
if (!fAudioTrackList.AddItem(t)) if (!fAudioTrackList.AddItem(t))
return B_NO_MEMORY; return B_NO_MEMORY;
@@ -395,7 +396,7 @@ Controller::VideoTrackCount()
status_t status_t
Controller::SelectAudioTrack(int n) Controller::SelectAudioTrack(int n)
{ {
BAutolock _(this); BAutolock _(this);
BMediaTrack* track = (BMediaTrack *)fAudioTrackList.ItemAt(n); BMediaTrack* track = (BMediaTrack *)fAudioTrackList.ItemAt(n);
@@ -503,7 +504,7 @@ Controller::Play()
//printf("Controller::Play\n"); //printf("Controller::Play\n");
BAutolock _(this); BAutolock _(this);
StartPlaying(); StartPlaying();
fAutoplay = true; fAutoplay = true;
} }
@@ -602,7 +603,7 @@ Controller::VolumeDown()
void void
Controller::ToggleMute() Controller::ToggleMute()
{ {
if (!Lock()) if (!Lock())
return; return;
@@ -624,7 +625,7 @@ Controller::Volume()
{ {
BAutolock _(this); BAutolock _(this);
return fVolume; return fVolume;
} }
@@ -679,14 +680,9 @@ status_t
Controller::GetLocation(BString* location) Controller::GetLocation(BString* location)
{ {
// you need to hold the data lock // you need to hold the data lock
if (!fMediaFile) if (fItem.Get() == NULL)
return B_NO_INIT; return B_NO_INIT;
BPath path(&fRef); *location = fItem->LocationURI();
status_t ret = path.InitCheck();
if (ret < B_OK)
return ret;
*location = "";
*location << "file://" << path.Path();
return B_OK; return B_OK;
} }
@@ -695,9 +691,9 @@ status_t
Controller::GetName(BString* name) Controller::GetName(BString* name)
{ {
// you need to hold the data lock // you need to hold the data lock
if (!fMediaFile) if (fItem.Get() == NULL)
return B_NO_INIT; return B_NO_INIT;
*name = fRef.name; *name = fItem->Name();
return B_OK; return B_OK;
} }
+10 -8
View File
@@ -31,11 +31,13 @@
#include "ListenerAdapter.h" #include "ListenerAdapter.h"
#include "NodeManager.h" #include "NodeManager.h"
#include "PlaylistItem.h"
class AudioTrackSupplier; class AudioTrackSupplier;
class BBitmap; class BBitmap;
class BMediaFile; class BMediaFile;
class BMediaTrack; class BMediaTrack;
class PlaylistItem;
class ProxyAudioSupplier; class ProxyAudioSupplier;
class ProxyVideoSupplier; class ProxyVideoSupplier;
class SoundOutput; class SoundOutput;
@@ -78,16 +80,16 @@ public:
virtual AudioSupplier* CreateAudioSupplier(); virtual AudioSupplier* CreateAudioSupplier();
// Controller // Controller
status_t SetTo(const entry_ref &ref); status_t SetTo(const PlaylistItemRef& item);
entry_ref Ref() const const PlaylistItem* Item() const
{ return fRef; } { return fItem.Get(); }
void PlayerActivated(bool active); void PlayerActivated(bool active);
void GetSize(int *width, int *height); void GetSize(int *width, int *height);
int AudioTrackCount(); int AudioTrackCount();
int VideoTrackCount(); int VideoTrackCount();
status_t SelectAudioTrack(int n); status_t SelectAudioTrack(int n);
int CurrentAudioTrack(); int CurrentAudioTrack();
status_t SelectVideoTrack(int n); status_t SelectVideoTrack(int n);
@@ -123,7 +125,7 @@ public:
// video view // video view
void SetVideoView(VideoView *view); void SetVideoView(VideoView *view);
bool IsOverlayActive(); bool IsOverlayActive();
// notification support // notification support
@@ -148,7 +150,7 @@ private:
void _NotifyVolumeChanged(float volume) const; void _NotifyVolumeChanged(float volume) const;
void _NotifyMutedChanged(bool muted) const; void _NotifyMutedChanged(bool muted) const;
// overridden from PlaybackManager so that we // overridden from PlaybackManager so that we
// can use our own Listener mechanism // can use our own Listener mechanism
virtual void NotifyPlayModeChanged(int32 mode) const; virtual void NotifyPlayModeChanged(int32 mode) const;
virtual void NotifyLoopModeChanged(int32 mode) const; virtual void NotifyLoopModeChanged(int32 mode) const;
@@ -167,7 +169,7 @@ private:
float fActiveVolume; float fActiveVolume;
bool fMuted; bool fMuted;
entry_ref fRef; PlaylistItemRef fItem;
BMediaFile* fMediaFile; BMediaFile* fMediaFile;
ProxyVideoSupplier* fVideoSupplier; ProxyVideoSupplier* fVideoSupplier;
@@ -194,7 +196,7 @@ private:
bool fLoopMovies; bool fLoopMovies;
bool fLoopSounds; bool fLoopSounds;
uint32 fBackgroundMovieVolumeMode; uint32 fBackgroundMovieVolumeMode;
BList fListeners; BList fListeners;
}; };
+9 -9
View File
@@ -63,18 +63,18 @@ ControllerView::Draw(BRect updateRect)
void void
ControllerView::MessageReceived(BMessage *msg) ControllerView::MessageReceived(BMessage* message)
{ {
switch (msg->what) { switch (message->what) {
case MSG_PLAYLIST_REF_ADDED: case MSG_PLAYLIST_ITEM_ADDED:
case MSG_PLAYLIST_REF_REMOVED: case MSG_PLAYLIST_ITEM_REMOVED:
case MSG_PLAYLIST_REFS_SORTED: case MSG_PLAYLIST_ITEMS_SORTED:
case MSG_PLAYLIST_CURRENT_REF_CHANGED: case MSG_PLAYLIST_CURRENT_ITEM_CHANGED:
_CheckSkippable(); _CheckSkippable();
break; break;
default: default:
TransportControlGroup::MessageReceived(msg); TransportControlGroup::MessageReceived(message);
} }
} }
@@ -123,7 +123,7 @@ void
ControllerView::SkipBackward() ControllerView::SkipBackward()
{ {
BAutolock _(fPlaylist); BAutolock _(fPlaylist);
fPlaylist->SetCurrentRefIndex(fPlaylist->CurrentRefIndex() - 1); fPlaylist->SetCurrentItemIndex(fPlaylist->CurrentItemIndex() - 1);
} }
@@ -131,7 +131,7 @@ void
ControllerView::SkipForward() ControllerView::SkipForward()
{ {
BAutolock _(fPlaylist); BAutolock _(fPlaylist);
fPlaylist->SetCurrentRefIndex(fPlaylist->CurrentRefIndex() + 1); fPlaylist->SetCurrentItemIndex(fPlaylist->CurrentItemIndex() + 1);
} }
+15 -16
View File
@@ -34,6 +34,7 @@
#include "Controller.h" #include "Controller.h"
#include "ControllerObserver.h" #include "ControllerObserver.h"
#include "PlaylistItem.h"
#define NAME "File Info" #define NAME "File Info"
@@ -55,7 +56,7 @@ public:
virtual ~InfoView(); virtual ~InfoView();
virtual void Draw(BRect updateRect); virtual void Draw(BRect updateRect);
status_t SetIcon(const entry_ref& ref); status_t SetIcon(const PlaylistItem* item);
status_t SetIcon(const char* mimeType); status_t SetIcon(const char* mimeType);
void SetGenericIcon(); void SetGenericIcon();
@@ -71,7 +72,7 @@ InfoView::InfoView(BRect frame, const char *name, float divider)
fIconBitmap(NULL) fIconBitmap(NULL)
{ {
BRect rect(0, 0, B_LARGE_ICON - 1, B_LARGE_ICON - 1); BRect rect(0, 0, B_LARGE_ICON - 1, B_LARGE_ICON - 1);
#ifdef HAIKU_TARGET_PLATFORM_HAIKU #ifdef HAIKU_TARGET_PLATFORM_HAIKU
fIconBitmap = new BBitmap(rect, B_RGBA32); fIconBitmap = new BBitmap(rect, B_RGBA32);
#else #else
@@ -106,11 +107,9 @@ InfoView::Draw(BRect updateRect)
status_t status_t
InfoView::SetIcon(const entry_ref& ref) InfoView::SetIcon(const PlaylistItem* item)
{ {
BNode node(&ref); return item->GetIcon(fIconBitmap, B_LARGE_ICON);
BNodeInfo info(&node);
return info.GetTrackerIcon(fIconBitmap, B_LARGE_ICON);
} }
@@ -180,14 +179,14 @@ InfoWin::InfoWin(BPoint leftTop, Controller* controller)
rect.right - 10, rect.right - 10,
20 + fh.ascent + 5), 20 + fh.ascent + 5),
"filename", ""); "filename", "");
AddChild(fFilenameView); AddChild(fFilenameView);
fFilenameView->SetFont(&bigFont); fFilenameView->SetFont(&bigFont);
fFilenameView->SetViewColor(fInfoView->ViewColor()); fFilenameView->SetViewColor(fInfoView->ViewColor());
fFilenameView->SetLowColor(fInfoView->ViewColor()); fFilenameView->SetLowColor(fInfoView->ViewColor());
#ifdef B_BEOS_VERSION_DANO /* maybe we should support that as well ? */ #ifdef B_BEOS_VERSION_DANO /* maybe we should support that as well ? */
fFilenameView->SetTruncation(B_TRUNCATE_END); fFilenameView->SetTruncation(B_TRUNCATE_END);
#endif #endif
rect.top = BASE_HEIGHT; rect.top = BASE_HEIGHT;
BRect lr(rect); BRect lr(rect);
@@ -403,9 +402,9 @@ printf("InfoWin::Update(0x%08lx)\n", which);
bigtime_t v; bigtime_t v;
//s << d << "µs; "; //s << d << "µs; ";
d /= 1000; d /= 1000;
v = d / (3600 * 1000); v = d / (3600 * 1000);
d = d % (3600 * 1000); d = d % (3600 * 1000);
bool hours = v > 0; bool hours = v > 0;
@@ -423,13 +422,13 @@ printf("InfoWin::Update(0x%08lx)\n", which);
s << "\n"; s << "\n";
fContentsView->Insert(s.String()); fContentsView->Insert(s.String());
// TODO: demux/video/audio/... perfs (Kb/s) // TODO: demux/video/audio/... perfs (Kb/s)
fLabelsView->Insert("Display Mode\n"); fLabelsView->Insert("Display Mode\n");
if (fController->IsOverlayActive()) if (fController->IsOverlayActive())
fContentsView->Insert("Overlay\n"); fContentsView->Insert("Overlay\n");
else else
fContentsView->Insert("DrawBitmap\n"); fContentsView->Insert("DrawBitmap\n");
fLabelsView->Insert("\n"); fLabelsView->Insert("\n");
fContentsView->Insert("\n"); fContentsView->Insert("\n");
} }
@@ -441,8 +440,8 @@ printf("InfoWin::Update(0x%08lx)\n", which);
if (which & INFO_FILE) { if (which & INFO_FILE) {
bool iconSet = false; bool iconSet = false;
if (fController->HasFile()) { if (fController->HasFile()) {
entry_ref ref = fController->Ref(); const PlaylistItem* item = fController->Item();
iconSet = fInfoView->SetIcon(ref) == B_OK; iconSet = fInfoView->SetIcon(item) == B_OK;
media_file_format fileFormat; media_file_format fileFormat;
BString s; BString s;
if (fController->GetFileFormatInfo(&fileFormat) == B_OK) { if (fController->GetFileFormatInfo(&fileFormat) == B_OK) {
@@ -470,7 +469,7 @@ printf("InfoWin::Update(0x%08lx)\n", which);
} }
if ((which & INFO_COPYRIGHT) && fController->HasFile()) { if ((which & INFO_COPYRIGHT) && fController->HasFile()) {
BString s; BString s;
if (fController->GetCopyright(&s) == B_OK && s.Length() > 0) { if (fController->GetCopyright(&s) == B_OK && s.Length() > 0) {
fLabelsView->Insert("Copyright\n\n"); fLabelsView->Insert("Copyright\n\n");
@@ -480,6 +479,6 @@ printf("InfoWin::Update(0x%08lx)\n", which);
} }
fController->Unlock(); fController->Unlock();
ResizeToPreferred(); ResizeToPreferred();
} }
+2 -1
View File
@@ -55,7 +55,7 @@ Application MediaPlayer :
# playlist # playlist
CopyPLItemsCommand.cpp CopyPLItemsCommand.cpp
EntryRefPlaylistItem.cpp FilePlaylistItem.cpp
ImportPLItemsCommand.cpp ImportPLItemsCommand.cpp
ListViews.cpp ListViews.cpp
MovePLItemsCommand.cpp MovePLItemsCommand.cpp
@@ -64,6 +64,7 @@ Application MediaPlayer :
PlaylistListView.cpp PlaylistListView.cpp
PlaylistObserver.cpp PlaylistObserver.cpp
PlaylistWindow.cpp PlaylistWindow.cpp
PLItemsCommand.cpp
RandomizePLItemsCommand.cpp RandomizePLItemsCommand.cpp
RemovePLItemsCommand.cpp RemovePLItemsCommand.cpp
+52 -40
View File
@@ -2,7 +2,7 @@
* MainWin.cpp - Media Player for the Haiku Operating System * MainWin.cpp - Media Player for the Haiku Operating System
* *
* Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de> * Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de>
* Copyright (C) 2007-2008 Stephan Aßmus <superstippi@gmx.de> (GPL->MIT ok) * Copyright (C) 2007-2009 Stephan Aßmus <superstippi@gmx.de> (GPL->MIT ok)
* Copyright (C) 2007-2009 Fredrik Modéen <[FirstName]@[LastName].se> (MIT ok) * Copyright (C) 2007-2009 Fredrik Modéen <[FirstName]@[LastName].se> (MIT ok)
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
@@ -20,6 +20,7 @@
* USA. * USA.
* *
*/ */
#include "MainWin.h" #include "MainWin.h"
#include <math.h> #include <math.h>
@@ -45,6 +46,7 @@
#include "ControllerObserver.h" #include "ControllerObserver.h"
#include "MainApp.h" #include "MainApp.h"
#include "PeakView.h" #include "PeakView.h"
#include "PlaylistItem.h"
#include "PlaylistObserver.h" #include "PlaylistObserver.h"
#include "PlaylistWindow.h" #include "PlaylistWindow.h"
#include "Settings.h" #include "Settings.h"
@@ -379,33 +381,35 @@ MainWin::MessageReceived(BMessage *msg)
break; break;
// PlaylistObserver messages // PlaylistObserver messages
case MSG_PLAYLIST_REF_ADDED: { case MSG_PLAYLIST_ITEM_ADDED:
entry_ref ref; {
PlaylistItem* item;
int32 index; int32 index;
if (msg->FindRef("refs", &ref) == B_OK if (msg->FindPointer("item", (void**)&item) == B_OK
&& msg->FindInt32("index", &index) == B_OK) { && msg->FindInt32("index", &index) == B_OK) {
_AddPlaylistItem(ref, index); _AddPlaylistItem(item, index);
} }
break; break;
} }
case MSG_PLAYLIST_REF_REMOVED: { case MSG_PLAYLIST_ITEM_REMOVED:
{
int32 index; int32 index;
if (msg->FindInt32("index", &index) == B_OK) { if (msg->FindInt32("index", &index) == B_OK)
_RemovePlaylistItem(index); _RemovePlaylistItem(index);
}
break; break;
} }
case MSG_PLAYLIST_CURRENT_REF_CHANGED: { case MSG_PLAYLIST_CURRENT_ITEM_CHANGED:
{
BAutolock _(fPlaylist); BAutolock _(fPlaylist);
int32 index; int32 index;
if (msg->FindInt32("index", &index) < B_OK if (msg->FindInt32("index", &index) < B_OK
|| index != fPlaylist->CurrentRefIndex()) || index != fPlaylist->CurrentItemIndex())
break; break;
entry_ref ref; PlaylistItemRef item(fPlaylist->ItemAt(index));
if (fPlaylist->GetRefAt(index, &ref) == B_OK) { if (item.Get() != NULL) {
printf("open ref: %s\n", ref.name); printf("open playlist item: %s\n", item->Name().String());
OpenFile(ref); OpenPlaylistItem(item);
_MarkPlaylistItem(index); _MarkPlaylistItem(index);
} }
break; break;
@@ -416,8 +420,8 @@ MainWin::MessageReceived(BMessage *msg)
{ {
BAutolock _(fPlaylist); BAutolock _(fPlaylist);
bool hadNext = fPlaylist->SetCurrentRefIndex( bool hadNext = fPlaylist->SetCurrentItemIndex(
fPlaylist->CurrentRefIndex() + 1); fPlaylist->CurrentItemIndex() + 1);
if (!hadNext) { if (!hadNext) {
if (fHasVideo) { if (fHasVideo) {
if (fCloseWhenDonePlayingMovie) if (fCloseWhenDonePlayingMovie)
@@ -434,7 +438,8 @@ MainWin::MessageReceived(BMessage *msg)
// notification // notification
// _UpdatePlaylistMenu(); // _UpdatePlaylistMenu();
break; break;
case MSG_CONTROLLER_VIDEO_TRACK_CHANGED: { case MSG_CONTROLLER_VIDEO_TRACK_CHANGED:
{
int32 index; int32 index;
if (msg->FindInt32("index", &index) == B_OK) { if (msg->FindInt32("index", &index) == B_OK) {
BMenuItem* item = fVideoTrackMenu->ItemAt(index); BMenuItem* item = fVideoTrackMenu->ItemAt(index);
@@ -443,7 +448,8 @@ MainWin::MessageReceived(BMessage *msg)
} }
break; break;
} }
case MSG_CONTROLLER_AUDIO_TRACK_CHANGED: { case MSG_CONTROLLER_AUDIO_TRACK_CHANGED:
{
int32 index; int32 index;
if (msg->FindInt32("index", &index) == B_OK) { if (msg->FindInt32("index", &index) == B_OK) {
BMenuItem* item = fAudioTrackMenu->ItemAt(index); BMenuItem* item = fAudioTrackMenu->ItemAt(index);
@@ -452,25 +458,29 @@ MainWin::MessageReceived(BMessage *msg)
} }
break; break;
} }
case MSG_CONTROLLER_PLAYBACK_STATE_CHANGED: { case MSG_CONTROLLER_PLAYBACK_STATE_CHANGED:
{
uint32 state; uint32 state;
if (msg->FindInt32("state", (int32*)&state) == B_OK) if (msg->FindInt32("state", (int32*)&state) == B_OK)
fControls->SetPlaybackState(state); fControls->SetPlaybackState(state);
break; break;
} }
case MSG_CONTROLLER_POSITION_CHANGED: { case MSG_CONTROLLER_POSITION_CHANGED:
{
float position; float position;
if (msg->FindFloat("position", &position) == B_OK) if (msg->FindFloat("position", &position) == B_OK)
fControls->SetPosition(position); fControls->SetPosition(position);
break; break;
} }
case MSG_CONTROLLER_VOLUME_CHANGED: { case MSG_CONTROLLER_VOLUME_CHANGED:
{
float volume; float volume;
if (msg->FindFloat("volume", &volume) == B_OK) if (msg->FindFloat("volume", &volume) == B_OK)
fControls->SetVolume(volume); fControls->SetVolume(volume);
break; break;
} }
case MSG_CONTROLLER_MUTED_CHANGED: { case MSG_CONTROLLER_MUTED_CHANGED:
{
bool muted; bool muted;
if (msg->FindBool("muted", &muted) == B_OK) if (msg->FindBool("muted", &muted) == B_OK)
fControls->SetMuted(muted); fControls->SetMuted(muted);
@@ -481,7 +491,8 @@ MainWin::MessageReceived(BMessage *msg)
case M_FILE_NEWPLAYER: case M_FILE_NEWPLAYER:
gMainApp->NewWindow(); gMainApp->NewWindow();
break; break;
case M_FILE_OPEN: { case M_FILE_OPEN:
{
BMessenger target(this); BMessenger target(this);
BMessage result(B_REFS_RECEIVED); BMessage result(B_REFS_RECEIVED);
BMessage appMessage(M_SHOW_OPEN_PANEL); BMessage appMessage(M_SHOW_OPEN_PANEL);
@@ -499,6 +510,7 @@ MainWin::MessageReceived(BMessage *msg)
ShowPlaylistWindow(); ShowPlaylistWindow();
break; break;
case B_ABOUT_REQUESTED: case B_ABOUT_REQUESTED:
{
BAlert *alert; BAlert *alert;
alert = new BAlert("about", NAME"\n\n Written by Marcus Overhagen " alert = new BAlert("about", NAME"\n\n Written by Marcus Overhagen "
", Stephan Aßmus and Frederik Modéen", "Thanks"); ", Stephan Aßmus and Frederik Modéen", "Thanks");
@@ -510,6 +522,7 @@ MainWin::MessageReceived(BMessage *msg)
alert->Go(NULL); // Asynchronous mode alert->Go(NULL); // Asynchronous mode
} }
break; break;
}
case M_FILE_CLOSE: case M_FILE_CLOSE:
PostMessage(B_QUIT_REQUESTED); PostMessage(B_QUIT_REQUESTED);
break; break;
@@ -664,12 +677,13 @@ MainWin::MessageReceived(BMessage *msg)
break; break;
} }
*/ */
case M_SET_PLAYLIST_POSITION: { case M_SET_PLAYLIST_POSITION:
{
BAutolock _(fPlaylist); BAutolock _(fPlaylist);
int32 index; int32 index;
if (msg->FindInt32("index", &index) == B_OK) if (msg->FindInt32("index", &index) == B_OK)
fPlaylist->SetCurrentRefIndex(index); fPlaylist->SetCurrentItemIndex(index);
break; break;
} }
@@ -731,18 +745,18 @@ MainWin::QuitRequested()
void void
MainWin::OpenFile(const entry_ref &ref) MainWin::OpenPlaylistItem(const PlaylistItemRef& item)
{ {
printf("MainWin::OpenFile\n"); printf("MainWin::OpenPlaylistItem\n");
status_t err = fController->SetTo(ref); status_t err = fController->SetTo(item);
if (err != B_OK) { if (err != B_OK) {
BAutolock _(fPlaylist); BAutolock _(fPlaylist);
if (fPlaylist->CountItems() == 1) { if (fPlaylist->CountItems() == 1) {
// display error if this is the only file we're supposed to play // display error if this is the only file we're supposed to play
BString message; BString message;
message << "The file '"; message << "The file '";
message << ref.name; message << item->Name();
message << "' could not be opened.\n\n"; message << "' could not be opened.\n\n";
if (err == B_MEDIA_NO_HANDLER) { if (err == B_MEDIA_NO_HANDLER) {
@@ -757,7 +771,7 @@ MainWin::OpenFile(const entry_ref &ref)
(new BAlert("error", message.String(), "OK"))->Go(); (new BAlert("error", message.String(), "OK"))->Go();
} else { } else {
// just go to the next file and don't bother user // just go to the next file and don't bother user
fPlaylist->SetCurrentRefIndex(fPlaylist->CurrentRefIndex() + 1); fPlaylist->SetCurrentItemIndex(fPlaylist->CurrentItemIndex() + 1);
} }
fHasFile = false; fHasFile = false;
fHasVideo = false; fHasVideo = false;
@@ -767,7 +781,7 @@ MainWin::OpenFile(const entry_ref &ref)
fHasFile = true; fHasFile = true;
fHasVideo = fController->VideoTrackCount() != 0; fHasVideo = fController->VideoTrackCount() != 0;
fHasAudio = fController->AudioTrackCount() != 0; fHasAudio = fController->AudioTrackCount() != 0;
SetTitle(ref.name); SetTitle(item->Name().String());
} }
_SetupWindow(); _SetupWindow();
} }
@@ -1398,7 +1412,7 @@ MainWin::_KeyDown(BMessage *msg)
BAutolock _(fPlaylist); BAutolock _(fPlaylist);
BMessage removeMessage(M_PLAYLIST_REMOVE_AND_PUT_INTO_TRASH); BMessage removeMessage(M_PLAYLIST_REMOVE_AND_PUT_INTO_TRASH);
removeMessage.AddInt32("playlist index", removeMessage.AddInt32("playlist index",
fPlaylist->CurrentRefIndex()); fPlaylist->CurrentItemIndex());
fPlaylistWindow->PostMessage(&removeMessage); fPlaylistWindow->PostMessage(&removeMessage);
return B_OK; return B_OK;
} }
@@ -1592,26 +1606,24 @@ MainWin::_UpdatePlaylistMenu()
int32 count = fPlaylist->CountItems(); int32 count = fPlaylist->CountItems();
for (int32 i = 0; i < count; i++) { for (int32 i = 0; i < count; i++) {
entry_ref ref; PlaylistItem* item = fPlaylist->ItemAtFast(i);
if (fPlaylist->GetRefAt(i, &ref) < B_OK) _AddPlaylistItem(item, i);
continue;
_AddPlaylistItem(ref, i);
} }
fPlaylistMenu->SetTargetForItems(this); fPlaylistMenu->SetTargetForItems(this);
_MarkPlaylistItem(fPlaylist->CurrentRefIndex()); _MarkPlaylistItem(fPlaylist->CurrentItemIndex());
fPlaylist->Unlock(); fPlaylist->Unlock();
} }
void void
MainWin::_AddPlaylistItem(const entry_ref& ref, int32 index) MainWin::_AddPlaylistItem(PlaylistItem* item, int32 index)
{ {
BMessage* message = new BMessage(M_SET_PLAYLIST_POSITION); BMessage* message = new BMessage(M_SET_PLAYLIST_POSITION);
message->AddInt32("index", index); message->AddInt32("index", index);
BMenuItem* item = new BMenuItem(ref.name, message); BMenuItem* menuItem = new BMenuItem(item->Name().String(), message);
fPlaylistMenu->AddItem(item, index); fPlaylistMenu->AddItem(menuItem, index);
} }
+14 -13
View File
@@ -2,7 +2,7 @@
* MainWin.h - Media Player for the Haiku Operating System * MainWin.h - Media Player for the Haiku Operating System
* *
* Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de> * Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de>
* Copyright (C) 2007 Stephan Aßmus <superstippi@gmx.de> * Copyright (C) 2007-2009 Stephan Aßmus <superstippi@gmx.de> (MIT ok)
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -31,6 +31,7 @@
#include "InfoWin.h" #include "InfoWin.h"
#include "ListenerAdapter.h" #include "ListenerAdapter.h"
#include "Playlist.h" #include "Playlist.h"
#include "PlaylistItem.h"
#include "VideoView.h" #include "VideoView.h"
class ControllerObserver; class ControllerObserver;
@@ -51,18 +52,18 @@ public:
virtual void WindowActivated(bool active); virtual void WindowActivated(bool active);
virtual bool QuitRequested(); virtual bool QuitRequested();
void OpenFile(const entry_ref& ref); void OpenPlaylistItem(const PlaylistItemRef& item);
void ShowFileInfo(); void ShowFileInfo();
void ShowPlaylistWindow(); void ShowPlaylistWindow();
void ShowSettingsWindow(); void ShowSettingsWindow();
void VideoFormatChange(int width, int height, void VideoFormatChange(int width, int height,
float widthScale, float heightScale); float widthScale, float heightScale);
private: private:
void _RefsReceived(BMessage *message); void _RefsReceived(BMessage* message);
void _SetupWindow(); void _SetupWindow();
void _CreateMenu(); void _CreateMenu();
void _SetupTrackMenus(); void _SetupTrackMenus();
@@ -70,7 +71,7 @@ private:
void _ResizeWindow(int percent); void _ResizeWindow(int percent);
void _ResizeVideoView(int x, int y, int width, void _ResizeVideoView(int x, int y, int width,
int height); int height);
void _MouseDown(BMessage* message, void _MouseDown(BMessage* message,
BView* originalHandler); BView* originalHandler);
void _MouseMoved(BMessage* message, void _MouseMoved(BMessage* message,
@@ -78,7 +79,7 @@ private:
void _MouseUp(BMessage* message); void _MouseUp(BMessage* message);
void _ShowContextMenu(const BPoint& screenPoint); void _ShowContextMenu(const BPoint& screenPoint);
status_t _KeyDown(BMessage* message); status_t _KeyDown(BMessage* message);
void _ToggleFullscreen(); void _ToggleFullscreen();
void _ToggleKeepAspectRatio(); void _ToggleKeepAspectRatio();
void _ToggleAlwaysOnTop(); void _ToggleAlwaysOnTop();
@@ -86,10 +87,10 @@ private:
void _ToggleNoMenu(); void _ToggleNoMenu();
void _ToggleNoControls(); void _ToggleNoControls();
void _ToggleNoBorderNoMenu(); void _ToggleNoBorderNoMenu();
void _UpdateControlsEnabledStatus(); void _UpdateControlsEnabledStatus();
void _UpdatePlaylistMenu(); void _UpdatePlaylistMenu();
void _AddPlaylistItem(const entry_ref& ref, void _AddPlaylistItem(PlaylistItem* item,
int32 index); int32 index);
void _RemovePlaylistItem(int32 index); void _RemovePlaylistItem(int32 index);
void _MarkPlaylistItem(int32 index); void _MarkPlaylistItem(int32 index);
@@ -103,7 +104,7 @@ private:
ControllerView* fControls; ControllerView* fControls;
InfoWin* fInfoWin; InfoWin* fInfoWin;
PlaylistWindow* fPlaylistWindow; PlaylistWindow* fPlaylistWindow;
BMenu* fFileMenu; BMenu* fFileMenu;
BMenu* fAudioMenu; BMenu* fAudioMenu;
BMenu* fVideoMenu; BMenu* fVideoMenu;
@@ -112,11 +113,11 @@ private:
BMenu* fSettingsMenu; BMenu* fSettingsMenu;
BMenu* fPlaylistMenu; BMenu* fPlaylistMenu;
BMenu* fDebugMenu; BMenu* fDebugMenu;
bool fHasFile; bool fHasFile;
bool fHasVideo; bool fHasVideo;
bool fHasAudio; bool fHasAudio;
Playlist* fPlaylist; Playlist* fPlaylist;
PlaylistObserver* fPlaylistObserver; PlaylistObserver* fPlaylistObserver;
Controller* fController; Controller* fController;
@@ -1,11 +1,7 @@
/* /*
* Copyright 2007, Haiku. All rights reserved. * Copyright © 2007-2009 Stephan Aßmus <superstippi@gmx.de>.
* Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
*/ */
#include "CopyPLItemsCommand.h" #include "CopyPLItemsCommand.h"
#include <new> #include <new>
@@ -21,24 +17,31 @@ using std::nothrow;
CopyPLItemsCommand::CopyPLItemsCommand(Playlist* playlist, CopyPLItemsCommand::CopyPLItemsCommand(Playlist* playlist,
const int32* indices, int32 count, int32 toIndex) const int32* indices, int32 count, int32 toIndex)
: Command() :
, fPlaylist(playlist) PLItemsCommand(),
, fRefs(count > 0 ? new (nothrow) entry_ref[count] : NULL) fPlaylist(playlist),
, fToIndex(toIndex) fItems(count > 0 ? new (nothrow) PlaylistItem*[count] : NULL),
, fCount(count) fToIndex(toIndex),
fCount(count),
fItemsCopied(false)
{ {
if (!indices || !fPlaylist || !fRefs) { if (!indices || !fPlaylist || !fItems) {
// indicate a bad object state // indicate a bad object state
delete[] fRefs; delete[] fItems;
fRefs = NULL; fItems = NULL;
return; return;
} }
memcpy(fItems, 0, sizeof(PlaylistItem*) * fCount);
// init original entries and // init original entries and
for (int32 i = 0; i < fCount; i++) { for (int32 i = 0; i < fCount; i++) {
if (fPlaylist->GetRefAt(indices[i], &fRefs[i]) < B_OK) { PlaylistItem* item = fPlaylist->ItemAt(indices[i]);
delete[] fRefs; if (item != NULL)
fRefs = NULL; fItems[i] = item->Clone();
if (fItems[i] == NULL) {
// indicate a bad object state
_CleanUp(fItems, fCount, true);
return; return;
} }
} }
@@ -47,14 +50,14 @@ CopyPLItemsCommand::CopyPLItemsCommand(Playlist* playlist,
CopyPLItemsCommand::~CopyPLItemsCommand() CopyPLItemsCommand::~CopyPLItemsCommand()
{ {
delete[] fRefs; _CleanUp(fItems, fCount, !fItemsCopied);
} }
status_t status_t
CopyPLItemsCommand::InitCheck() CopyPLItemsCommand::InitCheck()
{ {
if (!fPlaylist || !fRefs) if (!fPlaylist || !fItems)
return B_NO_INIT; return B_NO_INIT;
return B_OK; return B_OK;
} }
@@ -67,18 +70,17 @@ CopyPLItemsCommand::Perform()
status_t ret = B_OK; status_t ret = B_OK;
fItemsCopied = true;
// add refs to playlist at the insertion index // add refs to playlist at the insertion index
int32 index = fToIndex; int32 index = fToIndex;
for (int32 i = 0; i < fCount; i++) { for (int32 i = 0; i < fCount; i++) {
if (!fPlaylist->AddRef(fRefs[i], index++)) { if (!fPlaylist->AddItem(fItems[i], index++)) {
ret = B_NO_MEMORY; ret = B_NO_MEMORY;
break; break;
} }
} }
if (ret < B_OK) return ret;
return ret;
return B_OK;
} }
@@ -87,20 +89,19 @@ CopyPLItemsCommand::Undo()
{ {
BAutolock _(fPlaylist); BAutolock _(fPlaylist);
// remember currently playling ref in case we copy items over it fItemsCopied = false;
entry_ref currentRef; // remember currently playling item in case we copy items over it
bool adjustCurrentRef = fPlaylist->GetRefAt(fPlaylist->CurrentRefIndex(), PlaylistItem* current = fPlaylist->ItemAt(fPlaylist->CurrentItemIndex());
&currentRef) == B_OK;
// remove refs from playlist // remove refs from playlist
int32 index = fToIndex; int32 index = fToIndex;
for (int32 i = 0; i < fCount; i++) { for (int32 i = 0; i < fCount; i++) {
fPlaylist->RemoveRef(index++, false); fPlaylist->RemoveItem(index++, false);
} }
// take care about currently played ref // take care about currently played item
if (adjustCurrentRef) if (current != NULL)
fPlaylist->SetCurrentRefIndex(fPlaylist->IndexOf(currentRef)); fPlaylist->SetCurrentItemIndex(fPlaylist->IndexOf(current));
return B_OK; return B_OK;
} }
@@ -1,28 +1,22 @@
/* /*
* Copyright 2007, Haiku. All rights reserved. * Copyright © 2007-2009 Stephan Aßmus <superstippi@gmx.de>.
* Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
*/ */
#ifndef COPY_PL_ITEMS_COMMAND_H #ifndef COPY_PL_ITEMS_COMMAND_H
#define COPY_PL_ITEMS_COMMAND_H #define COPY_PL_ITEMS_COMMAND_H
#include "Command.h" #include "PLItemsCommand.h"
class Playlist; class CopyPLItemsCommand : public PLItemsCommand {
struct entry_ref; public:
class CopyPLItemsCommand : public Command {
public:
CopyPLItemsCommand( CopyPLItemsCommand(
Playlist* playlist, Playlist* playlist,
const int32* indices, const int32* indices,
int32 count, int32 count,
int32 toIndex); int32 toIndex);
virtual ~CopyPLItemsCommand(); virtual ~CopyPLItemsCommand();
virtual status_t InitCheck(); virtual status_t InitCheck();
virtual status_t Perform(); virtual status_t Perform();
@@ -30,11 +24,12 @@ class CopyPLItemsCommand : public Command {
virtual void GetName(BString& name); virtual void GetName(BString& name);
private: private:
Playlist* fPlaylist; Playlist* fPlaylist;
entry_ref* fRefs; PlaylistItem** fItems;
int32 fToIndex; int32 fToIndex;
int32 fCount; int32 fCount;
bool fItemsCopied;
}; };
#endif // COPY_PL_ITEMS_COMMAND_H #endif // COPY_PL_ITEMS_COMMAND_H
@@ -1,152 +0,0 @@
/*
* Copyright 2009 Stephan Aßmus <superstippi@gmx.de>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#include "EntryRefPlaylistItem.h"
#include <new>
#include <MediaFile.h>
EntryRefPlaylistItem::EntryRefPlaylistItem(const entry_ref& ref)
:
fRef(ref)
{
}
EntryRefPlaylistItem::~EntryRefPlaylistItem()
{
}
status_t
EntryRefPlaylistItem::SetName(const BString& name)
{
BEntry entry(&fRef);
status_t ret = entry.Rename(name.String(), false);
if (ret != B_OK)
return ret;
entry.GetRef(&fRef);
_NotifyListeners();
return B_OK;
}
status_t
EntryRefPlaylistItem::GetName(BString& name) const
{
name = fRef.name;
return B_OK;
}
status_t
EntryRefPlaylistItem::SetTitle(const BString& title)
{
return B_NOT_SUPPORTED;
}
status_t
EntryRefPlaylistItem::GetTitle(BString& title) const
{
return B_NOT_SUPPORTED;
}
status_t
EntryRefPlaylistItem::SetAuthor(const BString& author)
{
return B_NOT_SUPPORTED;
}
status_t
EntryRefPlaylistItem::GetAuthor(BString& author) const
{
return B_NOT_SUPPORTED;
}
status_t
EntryRefPlaylistItem::SetAlbum(const BString& album)
{
return B_NOT_SUPPORTED;
}
status_t
EntryRefPlaylistItem::GetAlbum(BString& album) const
{
return B_NOT_SUPPORTED;
}
status_t
EntryRefPlaylistItem::SetTrackNumber(int32 trackNumber)
{
return B_NOT_SUPPORTED;
}
status_t
EntryRefPlaylistItem::GetTrackNumber(int32& trackNumber) const
{
return B_NOT_SUPPORTED;
}
status_t
EntryRefPlaylistItem::SetBitRate(int32 bitRate)
{
return B_NOT_SUPPORTED;
}
status_t
EntryRefPlaylistItem::GetBitRate(int32& bitRate) const
{
return B_NOT_SUPPORTED;
}
status_t
EntryRefPlaylistItem::GetDuration(bigtime_t& duration) const
{
return B_NOT_SUPPORTED;
}
// #pragma mark -
status_t
EntryRefPlaylistItem::MoveIntoTrash()
{
return B_NOT_SUPPORTED;
}
status_t
EntryRefPlaylistItem::RestoreFromTrash()
{
return B_NOT_SUPPORTED;
}
// #pragma mark -
BMediaFile*
EntryRefPlaylistItem::CreateMediaFile() const
{
return new (std::nothrow) BMediaFile(&fRef);
}
@@ -1,56 +0,0 @@
/*
* Copyright 2009 Stephan Aßmus <superstippi@gmx.de>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#ifndef ENTRY_REF_PLAYLIST_ITEM_H
#define ENTRY_REF_PLAYLIST_ITEM_H
#include "PlaylistItem.h"
#include <Entry.h>
class EntryRefPlaylistItem : public PlaylistItem {
public:
EntryRefPlaylistItem(const entry_ref& ref);
virtual ~EntryRefPlaylistItem();
// archiving
// virtual status_t Unarchive(const BMessage* archive);
// virtual status_t Archive(BMessage* into) const;
//
// virtual status_t Unflatten(BDataIO* stream);
// virtual status_t Flatten(BDataIO* stream) const;
// properties
virtual status_t SetName(const BString& name);
virtual status_t GetName(BString& name) const;
virtual status_t SetTitle(const BString& title);
virtual status_t GetTitle(BString& title) const;
virtual status_t SetAuthor(const BString& author);
virtual status_t GetAuthor(BString& author) const;
virtual status_t SetAlbum(const BString& album);
virtual status_t GetAlbum(BString& album) const;
virtual status_t SetTrackNumber(int32 trackNumber);
virtual status_t GetTrackNumber(int32& trackNumber) const;
virtual status_t SetBitRate(int32 bitRate);
virtual status_t GetBitRate(int32& bitRate) const;
virtual status_t GetDuration(bigtime_t& duration) const;
// methods
virtual status_t MoveIntoTrash();
virtual status_t RestoreFromTrash();
// playback
virtual BMediaFile* CreateMediaFile() const;
private:
entry_ref fRef;
};
#endif // ENTRY_REF_PLAYLIST_ITEM_H
@@ -0,0 +1,300 @@
/*
* Copyright © 2009 Stephan Aßmus <superstippi@gmx.de>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#include "FilePlaylistItem.h"
#include <stdio.h>
#include <new>
#include <Directory.h>
#include <File.h>
#include <FindDirectory.h>
#include <MediaFile.h>
#include <Path.h>
static const char* kPathKey = "path";
FilePlaylistItem::FilePlaylistItem(const entry_ref& ref)
:
fRef(ref),
fNameInTrash("")
{
}
FilePlaylistItem::FilePlaylistItem(const FilePlaylistItem& other)
:
fRef(other.fRef),
fNameInTrash(other.fNameInTrash)
{
}
FilePlaylistItem::FilePlaylistItem(const BMessage* archive)
:
fRef(),
fNameInTrash("")
{
const char* path;
if (archive != NULL && archive->FindString(kPathKey, &path) == B_OK) {
if (get_ref_for_path(path, &fRef) != B_OK)
fRef = entry_ref();
}
}
FilePlaylistItem::~FilePlaylistItem()
{
}
PlaylistItem*
FilePlaylistItem::Clone() const
{
return new (std::nothrow) FilePlaylistItem(*this);
}
BArchivable*
FilePlaylistItem::Instantiate(BMessage* archive)
{
if (validate_instantiation(archive, "FilePlaylistItem"))
return new (std::nothrow) FilePlaylistItem(archive);
return NULL;
}
// #pragma mark -
status_t
FilePlaylistItem::Archive(BMessage* into, bool deep) const
{
status_t ret = BArchivable::Archive(into, deep);
if (ret != B_OK)
return ret;
BPath path(&fRef);
ret = path.InitCheck();
if (ret == B_OK)
ret = into->AddString(kPathKey, path.Path());
return ret;
}
status_t
FilePlaylistItem::SetAttribute(const Attribute& attribute,
const BString& string)
{
return B_NOT_SUPPORTED;
}
status_t
FilePlaylistItem::GetAttribute(const Attribute& attribute,
BString& string) const
{
if (attribute == ATTR_STRING_NAME) {
string = fRef.name;
return B_OK;
}
return B_NOT_SUPPORTED;
}
status_t
FilePlaylistItem::SetAttribute(const Attribute& attribute,
const int32& value)
{
return B_NOT_SUPPORTED;
}
status_t
FilePlaylistItem::GetAttribute(const Attribute& attribute,
int32& value) const
{
return B_NOT_SUPPORTED;
}
status_t
FilePlaylistItem::SetAttribute(const Attribute& attribute,
const int64& value)
{
return B_NOT_SUPPORTED;
}
status_t
FilePlaylistItem::GetAttribute(const Attribute& attribute,
int64& value) const
{
return B_NOT_SUPPORTED;
}
// #pragma mark -
BString
FilePlaylistItem::LocationURI() const
{
BPath path(&fRef);
BString locationURI("file://");
locationURI << path.Path();
return locationURI;
}
status_t
FilePlaylistItem::GetIcon(BBitmap* bitmap, icon_size iconSize) const
{
BNode node(&fRef);
BNodeInfo info(&node);
return info.GetTrackerIcon(bitmap, iconSize);
}
status_t
FilePlaylistItem::MoveIntoTrash()
{
if (fNameInTrash.Length() != 0) {
// Already in the trash!
return B_ERROR;
}
char trashPath[B_PATH_NAME_LENGTH];
status_t err = find_directory(B_TRASH_DIRECTORY, fRef.device,
true /*create it*/, trashPath, B_PATH_NAME_LENGTH);
if (err != B_OK) {
fprintf(stderr, "failed to find Trash: %s\n", strerror(err));
return err;
}
BEntry entry(&fRef);
err = entry.InitCheck();
if (err != B_OK) {
fprintf(stderr, "failed to init BEntry for %s: %s\n",
fRef.name, strerror(err));
return err;
}
BDirectory trashDir(trashPath);
if (err != B_OK) {
fprintf(stderr, "failed to init BDirectory for %s: %s\n",
trashPath, strerror(err));
return err;
}
// Find a unique name for the entry in the trash
fNameInTrash = fRef.name;
int32 uniqueNameIndex = 1;
while (true) {
BEntry test(&trashDir, fNameInTrash.String());
if (!test.Exists())
break;
fNameInTrash = fRef.name;
fNameInTrash << ' ' << uniqueNameIndex;
uniqueNameIndex++;
}
// Remember the original path
BPath originalPath;
entry.GetPath(&originalPath);
// Finally, move the entry into the trash
err = entry.MoveTo(&trashDir, fNameInTrash.String());
if (err != B_OK) {
fprintf(stderr, "failed to move entry into trash %s: %s\n",
trashPath, strerror(err));
return err;
}
// Allow Tracker to restore this entry
BNode node(&entry);
BString originalPathString(originalPath.Path());
node.WriteAttrString("_trk/original_path", &originalPathString);
return err;
}
status_t
FilePlaylistItem::RestoreFromTrash()
{
if (fNameInTrash.Length() <= 0) {
// Not in the trash!
return B_ERROR;
}
char trashPath[B_PATH_NAME_LENGTH];
status_t err = find_directory(B_TRASH_DIRECTORY, fRef.device,
false /*create it*/, trashPath, B_PATH_NAME_LENGTH);
if (err != B_OK) {
fprintf(stderr, "failed to find Trash: %s\n", strerror(err));
return err;
}
// construct the entry to the file in the trash
// TODO: BEntry(const BDirectory* directory, const char* path) is broken!
// BEntry entry(trashPath, fNamesInTrash[i].String());
BPath path(trashPath, fNameInTrash.String());
BEntry entry(path.Path());
err = entry.InitCheck();
if (err != B_OK) {
fprintf(stderr, "failed to init BEntry for %s: %s\n",
fNameInTrash.String(), strerror(err));
return err;
}
//entry.GetPath(&path);
//printf("moving '%s'\n", path.Path());
// construct the folder of the original entry_ref
node_ref nodeRef;
nodeRef.device = fRef.device;
nodeRef.node = fRef.directory;
BDirectory originalDir(&nodeRef);
err = originalDir.InitCheck();
if (err != B_OK) {
fprintf(stderr, "failed to init original BDirectory for "
"%s: %s\n", fRef.name, strerror(err));
return err;
}
//path.SetTo(&originalDir, fItems[i].name);
//printf("as '%s'\n", path.Path());
// Reset the name here, the user may have already moved the entry
// out of the trash via Tracker for example.
fNameInTrash = "";
// Finally, move the entry back into the original folder
err = entry.MoveTo(&originalDir, fRef.name);
if (err != B_OK) {
fprintf(stderr, "failed to restore entry from trash "
"%s: %s\n", fRef.name, strerror(err));
return err;
}
// Remove the attribute that helps Tracker restore the entry.
BNode node(&entry);
node.RemoveAttr("_trk/original_path");
return err;
}
// #pragma mark -
BMediaFile*
FilePlaylistItem::CreateMediaFile() const
{
return new (std::nothrow) BMediaFile(&fRef);
}
@@ -0,0 +1,58 @@
/*
* Copyright © 2009 Stephan Aßmus <superstippi@gmx.de>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#ifndef FILE_PLAYLIST_ITEM_H
#define FILE_PLAYLIST_ITEM_H
#include "PlaylistItem.h"
#include <Entry.h>
class FilePlaylistItem : public PlaylistItem {
public:
FilePlaylistItem(const entry_ref& ref);
FilePlaylistItem(const FilePlaylistItem& item);
FilePlaylistItem(const BMessage* archive);
virtual ~FilePlaylistItem();
virtual PlaylistItem* Clone() const;
// archiving
static BArchivable* Instantiate(BMessage* archive);
virtual status_t Archive(BMessage* into,
bool deep = true) const;
// attributes
virtual status_t SetAttribute(const Attribute& attribute,
const BString& string);
virtual status_t GetAttribute(const Attribute& attribute,
BString& string) const;
virtual status_t SetAttribute(const Attribute& attribute,
const int32& value);
virtual status_t GetAttribute(const Attribute& attribute,
int32& value) const;
virtual status_t SetAttribute(const Attribute& attribute,
const int64& value);
virtual status_t GetAttribute(const Attribute& attribute,
int64& value) const;
// methods
virtual BString LocationURI() const;
virtual status_t GetIcon(BBitmap* bitmap,
icon_size iconSize) const;
virtual status_t MoveIntoTrash();
virtual status_t RestoreFromTrash();
// playback
virtual BMediaFile* CreateMediaFile() const;
private:
entry_ref fRef;
BString fNameInTrash;
};
#endif // FILE_PLAYLIST_ITEM_H
@@ -1,9 +1,6 @@
/* /*
* Copyright 2007, Haiku. All rights reserved. * Copyright 2007-2009 Stephan Aßmus <superstippi@gmx.de>.
* Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
*/ */
#include "ImportPLItemsCommand.h" #include "ImportPLItemsCommand.h"
@@ -15,6 +12,7 @@
#include <Autolock.h> #include <Autolock.h>
#include "Playlist.h" #include "Playlist.h"
#include "PlaylistItem.h"
using std::nothrow; using std::nothrow;
@@ -22,16 +20,20 @@ using std::nothrow;
ImportPLItemsCommand::ImportPLItemsCommand(Playlist* playlist, ImportPLItemsCommand::ImportPLItemsCommand(Playlist* playlist,
const BMessage* refsMessage, int32 toIndex) const BMessage* refsMessage, int32 toIndex)
: Command() :
, fPlaylist(playlist) PLItemsCommand(),
fPlaylist(playlist),
, fOldRefs(NULL) fOldItems(NULL),
, fOldCount(0) fOldCount(0),
, fNewRefs(NULL) fNewItems(NULL),
, fNewCount(0) fNewCount(0),
, fToIndex(toIndex) fToIndex(toIndex),
fPlaylingIndex(0),
fItemsAdded(false)
{ {
if (!fPlaylist) if (!fPlaylist)
return; return;
@@ -47,38 +49,40 @@ ImportPLItemsCommand::ImportPLItemsCommand(Playlist* playlist,
return; return;
} }
fNewRefs = new (nothrow) entry_ref[fNewCount]; fNewItems = new (nothrow) PlaylistItem*[fNewCount];
if (!fNewRefs) if (!fNewItems)
return; return;
memset(fNewItems, 0, fNewCount * sizeof(PlaylistItem*));
// init new entries // init new entries
for (int32 i = 0; i < fNewCount; i++) { for (int32 i = 0; i < fNewCount; i++) {
if (temp.GetRefAt(i, &fNewRefs[i]) < B_OK) { fNewItems[i] = temp.ItemAtFast(i)->Clone();
if (fNewItems[i] == NULL) {
// indicate bad object init // indicate bad object init
delete[] fNewRefs; _CleanUp(fNewItems, fNewCount, true);
fNewRefs = NULL;
return; return;
} }
} }
fPlaylingIndex = fPlaylist->CurrentItemIndex();
if (fToIndex < 0) { if (fToIndex < 0) {
fOldCount = fPlaylist->CountItems(); fOldCount = fPlaylist->CountItems();
if (fOldCount > 0) { if (fOldCount > 0) {
fOldRefs = new (nothrow) entry_ref[fOldCount]; fOldItems = new (nothrow) PlaylistItem*[fOldCount];
if (!fOldRefs) { if (!fOldItems) {
// indicate bad object init // indicate bad object init
delete[] fNewRefs; _CleanUp(fNewItems, fNewCount, true);
fNewRefs = NULL;
return;
} }
memset(fOldItems, 0, fOldCount * sizeof(PlaylistItem*));
} }
} }
for (int32 i = 0; i < fOldCount; i++) { for (int32 i = 0; i < fOldCount; i++) {
if (fPlaylist->GetRefAt(i, &fOldRefs[i]) < B_OK) { fOldItems[i] = fPlaylist->ItemAtFast(i)->Clone();
if (fOldItems[i] == NULL) {
// indicate bad object init // indicate bad object init
delete[] fNewRefs; _CleanUp(fNewItems, fNewCount, true);
fNewRefs = NULL;
return; return;
} }
} }
@@ -87,15 +91,15 @@ ImportPLItemsCommand::ImportPLItemsCommand(Playlist* playlist,
ImportPLItemsCommand::~ImportPLItemsCommand() ImportPLItemsCommand::~ImportPLItemsCommand()
{ {
delete[] fOldRefs; _CleanUp(fOldItems, fOldCount, fItemsAdded);
delete[] fNewRefs; _CleanUp(fNewItems, fNewCount, !fItemsAdded);
} }
status_t status_t
ImportPLItemsCommand::InitCheck() ImportPLItemsCommand::InitCheck()
{ {
if (!fPlaylist || !fNewRefs) if (!fPlaylist || !fNewItems)
return B_NO_INIT; return B_NO_INIT;
return B_OK; return B_OK;
} }
@@ -106,9 +110,11 @@ ImportPLItemsCommand::Perform()
{ {
BAutolock _(fPlaylist); BAutolock _(fPlaylist);
fItemsAdded = true;
int32 index = fToIndex; int32 index = fToIndex;
if (fToIndex < 0) { if (fToIndex < 0) {
fPlaylist->MakeEmpty(); fPlaylist->MakeEmpty(false);
index = 0; index = 0;
} }
@@ -116,13 +122,13 @@ ImportPLItemsCommand::Perform()
// add refs to playlist at the insertion index // add refs to playlist at the insertion index
for (int32 i = 0; i < fNewCount; i++) { for (int32 i = 0; i < fNewCount; i++) {
if (!fPlaylist->AddRef(fNewRefs[i], index++)) if (!fPlaylist->AddItem(fNewItems[i], index++))
return B_NO_MEMORY; return B_NO_MEMORY;
} }
if (startPlaying) { if (startPlaying) {
// open first file // open first file
fPlaylist->SetCurrentRefIndex(0); fPlaylist->SetCurrentItemIndex(0);
} }
return B_OK; return B_OK;
@@ -134,17 +140,22 @@ ImportPLItemsCommand::Undo()
{ {
BAutolock _(fPlaylist); BAutolock _(fPlaylist);
fItemsAdded = false;
if (fToIndex < 0) { if (fToIndex < 0) {
// remove new refs from playlist and restore old refs // remove new items from playlist and restore old refs
fPlaylist->MakeEmpty(); fPlaylist->MakeEmpty(false);
for (int32 i = 0; i < fOldCount; i++) { for (int32 i = 0; i < fOldCount; i++) {
if (!fPlaylist->AddRef(fOldRefs[i], i)) if (!fPlaylist->AddItem(fOldItems[i], i))
return B_NO_MEMORY; return B_NO_MEMORY;
} }
// Restore previously playing item
if (fPlaylingIndex >= 0)
fPlaylist->SetCurrentItemIndex(fPlaylingIndex);
} else { } else {
// remove refs from playlist // remove new items from playlist
for (int32 i = 0; i < fNewCount; i++) { for (int32 i = 0; i < fNewCount; i++) {
fPlaylist->RemoveRef(fToIndex); fPlaylist->RemoveItem(fToIndex);
} }
} }
@@ -160,3 +171,4 @@ ImportPLItemsCommand::GetName(BString& name)
else else
name << "Import Entry"; name << "Import Entry";
} }
@@ -1,28 +1,23 @@
/* /*
* Copyright 2007, Haiku. All rights reserved. * Copyright 2007-2009 Stephan Aßmus <superstippi@gmx.de>.
* Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
*/ */
#ifndef IMPORT_PL_ITEMS_COMMAND_H #ifndef IMPORT_PL_ITEMS_COMMAND_H
#define IMPORT_PL_ITEMS_COMMAND_H #define IMPORT_PL_ITEMS_COMMAND_H
#include "Command.h" #include "PLItemsCommand.h"
class BMessage; class BMessage;
class Playlist;
struct entry_ref;
class ImportPLItemsCommand : public Command { class ImportPLItemsCommand : public PLItemsCommand {
public: public:
ImportPLItemsCommand( ImportPLItemsCommand(
Playlist* playlist, Playlist* playlist,
const BMessage* refsMessage, const BMessage* refsMessage,
int32 toIndex); int32 toIndex);
virtual ~ImportPLItemsCommand(); virtual ~ImportPLItemsCommand();
virtual status_t InitCheck(); virtual status_t InitCheck();
virtual status_t Perform(); virtual status_t Perform();
@@ -30,13 +25,15 @@ class ImportPLItemsCommand : public Command {
virtual void GetName(BString& name); virtual void GetName(BString& name);
private: private:
Playlist* fPlaylist; Playlist* fPlaylist;
entry_ref* fOldRefs; PlaylistItem** fOldItems;
int32 fOldCount; int32 fOldCount;
entry_ref* fNewRefs; PlaylistItem** fNewItems;
int32 fNewCount; int32 fNewCount;
int32 fToIndex; int32 fToIndex;
int32 fPlaylingIndex;
bool fItemsAdded;
}; };
#endif // IMPORT_PL_ITEMS_COMMAND_H #endif // IMPORT_PL_ITEMS_COMMAND_H
@@ -1,9 +1,6 @@
/* /*
* Copyright 2007, Haiku. All rights reserved. * Copyright 2007-2009 Stephan Aßmus <superstippi@gmx.de>.
* Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
*/ */
#include "MovePLItemsCommand.h" #include "MovePLItemsCommand.h"
@@ -21,20 +18,22 @@ using std::nothrow;
MovePLItemsCommand::MovePLItemsCommand(Playlist* playlist, MovePLItemsCommand::MovePLItemsCommand(Playlist* playlist,
const int32* indices, int32 count, int32 toIndex) const int32* indices, int32 count, int32 toIndex)
: Command() :
, fPlaylist(playlist) PLItemsCommand(),
, fRefs(count > 0 ? new (nothrow) entry_ref[count] : NULL) fPlaylist(playlist),
, fIndices(count > 0 ? new (nothrow) int32[count] : NULL) fItems(count > 0 ? new (nothrow) PlaylistItem*[count] : NULL),
, fToIndex(toIndex) fIndices(count > 0 ? new (nothrow) int32[count] : NULL),
, fCount(count) fToIndex(toIndex),
fCount(count)
{ {
if (!indices || !fPlaylist || !fRefs || !fIndices) { if (!indices || !fPlaylist || !fItems || !fIndices) {
// indicate a bad object state // indicate a bad object state
delete[] fRefs; delete[] fItems;
fRefs = NULL; fItems = NULL;
return; return;
} }
memset(fItems, 0, sizeof(PlaylistItem*) * fCount);
memcpy(fIndices, indices, fCount * sizeof(int32)); memcpy(fIndices, indices, fCount * sizeof(int32));
// init original entry indices and // init original entry indices and
@@ -42,10 +41,11 @@ MovePLItemsCommand::MovePLItemsCommand(Playlist* playlist,
// are removed before that index // are removed before that index
int32 itemsBeforeIndex = 0; int32 itemsBeforeIndex = 0;
for (int32 i = 0; i < fCount; i++) { for (int32 i = 0; i < fCount; i++) {
if (fPlaylist->GetRefAt(fIndices[i], &fRefs[i]) < B_OK) { fItems[i] = fPlaylist->ItemAt(fIndices[i]);
if (fItems[i] == NULL) {
// indicate a bad object state // indicate a bad object state
delete[] fRefs; delete[] fItems;
fRefs = NULL; fItems = NULL;
return; return;
} }
if (fIndices[i] < fToIndex) if (fIndices[i] < fToIndex)
@@ -57,7 +57,7 @@ MovePLItemsCommand::MovePLItemsCommand(Playlist* playlist,
MovePLItemsCommand::~MovePLItemsCommand() MovePLItemsCommand::~MovePLItemsCommand()
{ {
delete[] fRefs; delete[] fItems;
delete[] fIndices; delete[] fIndices;
} }
@@ -65,7 +65,7 @@ MovePLItemsCommand::~MovePLItemsCommand()
status_t status_t
MovePLItemsCommand::InitCheck() MovePLItemsCommand::InitCheck()
{ {
if (!fRefs) if (!fItems)
return B_NO_INIT; return B_NO_INIT;
// analyse the move, don't return B_OK in case // analyse the move, don't return B_OK in case
@@ -106,21 +106,19 @@ MovePLItemsCommand::Perform()
status_t ret = B_OK; status_t ret = B_OK;
// remember currently playling ref in case we move it // remember currently playling item in case we move it
entry_ref currentRef; PlaylistItem* current = fPlaylist->ItemAt(fPlaylist->CurrentItemIndex());
bool adjustCurrentRef = fPlaylist->GetRefAt(fPlaylist->CurrentRefIndex(),
&currentRef) == B_OK;
// remove refs from playlist // remove refs from playlist
for (int32 i = 0; i < fCount; i++) { for (int32 i = 0; i < fCount; i++) {
// "- i" to account for the items already removed // "- i" to account for the items already removed
fPlaylist->RemoveRef(fIndices[i] - i, false); fPlaylist->RemoveItem(fIndices[i] - i, false);
} }
// add refs to playlist at the insertion index // add refs to playlist at the insertion index
int32 index = fToIndex; int32 index = fToIndex;
for (int32 i = 0; i < fCount; i++) { for (int32 i = 0; i < fCount; i++) {
if (!fPlaylist->AddRef(fRefs[i], index++)) { if (!fPlaylist->AddItem(fItems[i], index++)) {
ret = B_NO_MEMORY; ret = B_NO_MEMORY;
break; break;
} }
@@ -128,9 +126,9 @@ MovePLItemsCommand::Perform()
if (ret < B_OK) if (ret < B_OK)
return ret; return ret;
// take care about currently played ref // take care about currently played item
if (adjustCurrentRef) if (current != NULL)
fPlaylist->SetCurrentRefIndex(fPlaylist->IndexOf(currentRef)); fPlaylist->SetCurrentItemIndex(fPlaylist->IndexOf(current));
return B_OK; return B_OK;
} }
@@ -143,20 +141,18 @@ MovePLItemsCommand::Undo()
status_t ret = B_OK; status_t ret = B_OK;
// remember currently playling ref in case we move it // remember currently playling item in case we move it
entry_ref currentRef; PlaylistItem* current = fPlaylist->ItemAt(fPlaylist->CurrentItemIndex());
bool adjustCurrentRef = fPlaylist->GetRefAt(fPlaylist->CurrentRefIndex(),
&currentRef) == B_OK;
// remove refs from playlist // remove refs from playlist
int32 index = fToIndex; int32 index = fToIndex;
for (int32 i = 0; i < fCount; i++) { for (int32 i = 0; i < fCount; i++) {
fPlaylist->RemoveRef(index++, false); fPlaylist->RemoveItem(index++, false);
} }
// add ref to playlist at remembered indices // add ref to playlist at remembered indices
for (int32 i = 0; i < fCount; i++) { for (int32 i = 0; i < fCount; i++) {
if (!fPlaylist->AddRef(fRefs[i], fIndices[i])) { if (!fPlaylist->AddItem(fItems[i], fIndices[i])) {
ret = B_NO_MEMORY; ret = B_NO_MEMORY;
break; break;
} }
@@ -164,9 +160,9 @@ MovePLItemsCommand::Undo()
if (ret < B_OK) if (ret < B_OK)
return ret; return ret;
// take care about currently played ref // take care about currently played item
if (adjustCurrentRef) if (current != NULL)
fPlaylist->SetCurrentRefIndex(fPlaylist->IndexOf(currentRef)); fPlaylist->SetCurrentItemIndex(fPlaylist->IndexOf(current));
return B_OK; return B_OK;
} }
@@ -1,20 +1,14 @@
/* /*
* Copyright 2007, Haiku. All rights reserved. * Copyright 2007-2009 Stephan Aßmus <superstippi@gmx.de>.
* Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
*/ */
#ifndef MOVE_PL_ITEMS_COMMAND_H #ifndef MOVE_PL_ITEMS_COMMAND_H
#define MOVE_PL_ITEMS_COMMAND_H #define MOVE_PL_ITEMS_COMMAND_H
#include "Command.h" #include "PLItemsCommand.h"
class Playlist; class MovePLItemsCommand : public PLItemsCommand {
struct entry_ref;
class MovePLItemsCommand : public Command {
public: public:
MovePLItemsCommand( MovePLItemsCommand(
Playlist* playlist, Playlist* playlist,
@@ -22,7 +16,7 @@ class MovePLItemsCommand : public Command {
int32 count, int32 count,
int32 toIndex); int32 toIndex);
virtual ~MovePLItemsCommand(); virtual ~MovePLItemsCommand();
virtual status_t InitCheck(); virtual status_t InitCheck();
virtual status_t Perform(); virtual status_t Perform();
@@ -32,7 +26,7 @@ class MovePLItemsCommand : public Command {
private: private:
Playlist* fPlaylist; Playlist* fPlaylist;
entry_ref* fRefs; PlaylistItem** fItems;
int32* fIndices; int32* fIndices;
int32 fToIndex; int32 fToIndex;
int32 fCount; int32 fCount;
@@ -0,0 +1,41 @@
/*
* Copyright 2009 Stephan Aßmus <superstippi@gmx.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "PLItemsCommand.h"
#include <stdio.h>
#include "Playlist.h"
#include "PlaylistItem.h"
using std::nothrow;
PLItemsCommand::PLItemsCommand()
:
Command()
{
}
PLItemsCommand::~PLItemsCommand()
{
}
void
PLItemsCommand::_CleanUp(PlaylistItem**& items, int32 count, bool deleteItems)
{
if (items == NULL)
return;
if (deleteItems) {
for (int32 i = 0; i < count; i++)
items[i]->RemoveReference();
}
delete[] items;
items = NULL;
}
@@ -0,0 +1,24 @@
/*
* Copyright 2009 Stephan Aßmus <superstippi@gmx.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef PL_ITEMS_COMMAND_H
#define PL_ITEMS_COMMAND_H
#include "Command.h"
class Playlist;
class PlaylistItem;
class PLItemsCommand : public Command {
public:
PLItemsCommand();
virtual ~PLItemsCommand();
protected:
void _CleanUp(PlaylistItem**& items, int32 count,
bool deleteItems);
};
#endif // PL_ITEMS_COMMAND_H
+163 -125
View File
@@ -2,8 +2,8 @@
* Playlist.cpp - Media Player for the Haiku Operating System * Playlist.cpp - Media Player for the Haiku Operating System
* *
* Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de> * Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de>
* Copyright (C) 2007 Stephan Aßmus <superstippi@gmx.de> * Copyright (C) 2007-2009 Stephan Aßmus <superstippi@gmx.de> (MIT ok)
* Copyright (C) 2008-2009 Fredrik Modéen <[FirstName]@[LastName].se> (MIT ok) * Copyright (C) 2008-2009 Fredrik Modéen <[FirstName]@[LastName].se> (MIT ok)
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -19,21 +19,27 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* *
*/ */
#include "Playlist.h" #include "Playlist.h"
#include <debugger.h> #include <debugger.h>
#include <new> #include <new>
#include <stdio.h> #include <stdio.h>
#include <AppFileInfo.h>
#include <Application.h>
#include <Autolock.h> #include <Autolock.h>
#include <Directory.h> #include <Directory.h>
#include <Entry.h>
#include <File.h> #include <File.h>
#include <Message.h> #include <Message.h>
#include <Mime.h> #include <Mime.h>
#include <NodeInfo.h> #include <NodeInfo.h>
#include <Path.h> #include <Path.h>
#include <Roster.h>
#include <String.h> #include <String.h>
#include "FilePlaylistItem.h"
#include "FileReadWrite.h" #include "FileReadWrite.h"
using std::nothrow; using std::nothrow;
@@ -42,19 +48,54 @@ using std::nothrow;
Playlist::Listener::Listener() {} Playlist::Listener::Listener() {}
Playlist::Listener::~Listener() {} Playlist::Listener::~Listener() {}
void Playlist::Listener::RefAdded(const entry_ref& ref, int32 index) {} void Playlist::Listener::ItemAdded(PlaylistItem* item, int32 index) {}
void Playlist::Listener::RefRemoved(int32 index) {} void Playlist::Listener::ItemRemoved(int32 index) {}
void Playlist::Listener::RefsSorted() {} void Playlist::Listener::ItemsSorted() {}
void Playlist::Listener::CurrentRefChanged(int32 newIndex) {} void Playlist::Listener::CurrentItemChanged(int32 newIndex) {}
// #pragma mark -
static void
make_item_compare_string(const PlaylistItem* item, char* buffer,
size_t bufferSize)
{
// TODO: Maybe "location" would be useful here as well.
// snprintf(buffer, bufferSize, "%s - %s - %0*ld - %s",
// item->Author().String(),
// item->Album().String(),
// 3, item->TrackNumber(),
// item->Title().String());
snprintf(buffer, bufferSize, "%s", item->LocationURI().String());
}
static int
playlist_item_compare(const void* _item1, const void* _item2)
{
// compare complete path
const PlaylistItem* item1 = *(const PlaylistItem**)_item1;
const PlaylistItem* item2 = *(const PlaylistItem**)_item2;
static const size_t bufferSize = 1024;
char string1[bufferSize];
make_item_compare_string(item1, string1, bufferSize);
char string2[bufferSize];
make_item_compare_string(item2, string2, bufferSize);
return strcmp(string1, string2);
}
// #pragma mark - // #pragma mark -
Playlist::Playlist() Playlist::Playlist()
: BLocker("playlist lock") :
, fRefs() BLocker("playlist lock"),
, fCurrentIndex(-1) fItems(),
fCurrentIndex(-1)
{ {
} }
@@ -71,7 +112,7 @@ Playlist::~Playlist()
// #pragma mark - archiving // #pragma mark - archiving
static const char* kPathKey = "path"; static const char* kItemArchiveKey = "item";
status_t status_t
@@ -82,15 +123,21 @@ Playlist::Unarchive(const BMessage* archive)
MakeEmpty(); MakeEmpty();
BString path; BMessage itemArchive;
for (int32 i = 0; archive->FindString(kPathKey, i, &path) == B_OK; i++) { for (int32 i = 0;
BEntry entry(path.String(), false); archive->FindMessage(kItemArchiveKey, i, &itemArchive) == B_OK; i++) {
// don't follow links, we want to do that when opening files only
entry_ref ref; BArchivable* archivable = instantiate_object(&itemArchive);
if (entry.GetRef(&ref) != B_OK) PlaylistItem* item = dynamic_cast<PlaylistItem*>(archivable);
if (!item) {
delete archivable;
continue; continue;
if (!AddRef(ref)) }
if (!AddItem(item)) {
delete item;
return B_NO_MEMORY; return B_NO_MEMORY;
}
} }
return B_OK; return B_OK;
@@ -103,13 +150,14 @@ Playlist::Archive(BMessage* into) const
if (into == NULL) if (into == NULL)
return B_BAD_VALUE; return B_BAD_VALUE;
int32 count = fRefs.CountItems(); int32 count = CountItems();
for (int32 i = 0; i < count; i++) { for (int32 i = 0; i < count; i++) {
const entry_ref* ref = (entry_ref*)fRefs.ItemAtFast(i); const PlaylistItem* item = ItemAtFast(i);
BPath path(ref); BMessage itemArchive;
if (path.InitCheck() != B_OK) status_t ret = item->Archive(&itemArchive);
continue; if (ret != B_OK)
status_t ret = into->AddString(kPathKey, path.Path()); return ret;
ret = into->AddMessage(kItemArchiveKey, &itemArchive);
if (ret != B_OK) if (ret != B_OK)
return ret; return ret;
} }
@@ -145,7 +193,6 @@ Playlist::Unflatten(BDataIO* stream)
if (ret != B_OK) if (ret != B_OK)
return ret; return ret;
return Unarchive(&archive); return Unarchive(&archive);
} }
@@ -177,54 +224,51 @@ Playlist::Flatten(BDataIO* stream) const
void void
Playlist::MakeEmpty() Playlist::MakeEmpty(bool deleteItems)
{ {
int32 count = fRefs.CountItems(); int32 count = CountItems();
for (int32 i = count - 1; i >= 0; i--) { for (int32 i = count - 1; i >= 0; i--) {
entry_ref* ref = (entry_ref*)fRefs.RemoveItem(i); PlaylistItem* item = RemoveItem(i, false);
_NotifyRefRemoved(i); _NotifyItemRemoved(i);
delete ref; if (deleteItems)
item->RemoveReference();
} }
SetCurrentRefIndex(-1); SetCurrentItemIndex(-1);
} }
int32 int32
Playlist::CountItems() const Playlist::CountItems() const
{ {
return fRefs.CountItems(); return fItems.CountItems();
} }
void void
Playlist::Sort() Playlist::Sort()
{ {
fRefs.SortItems(playlist_cmp); fItems.SortItems(playlist_item_compare);
_NotifyRefsSorted(); _NotifyItemsSorted();
} }
bool bool
Playlist::AddRef(const entry_ref &ref) Playlist::AddItem(PlaylistItem* item)
{ {
return AddRef(ref, CountItems()); return AddItem(item, CountItems());
} }
bool bool
Playlist::AddRef(const entry_ref &ref, int32 index) Playlist::AddItem(PlaylistItem* item, int32 index)
{ {
entry_ref* copy = new (nothrow) entry_ref(ref); if (!fItems.AddItem(item, index))
if (!copy)
return false; return false;
if (!fRefs.AddItem(copy, index)) {
delete copy;
return false;
}
_NotifyRefAdded(ref, index);
if (index <= fCurrentIndex) if (index <= fCurrentIndex)
SetCurrentRefIndex(fCurrentIndex + 1); SetCurrentItemIndex(fCurrentIndex + 1);
_NotifyItemAdded(item, index);
return true; return true;
} }
@@ -244,85 +288,68 @@ Playlist::AdoptPlaylist(Playlist& other, int32 index)
return false; return false;
// NOTE: this is not intended to merge two "equal" playlists // NOTE: this is not intended to merge two "equal" playlists
// the given playlist is assumed to be a temporary "dummy" // the given playlist is assumed to be a temporary "dummy"
if (fRefs.AddList(&other.fRefs, index)) { if (fItems.AddList(&other.fItems, index)) {
// take care of the notifications // take care of the notifications
int32 count = other.fRefs.CountItems(); int32 count = other.CountItems();
for (int32 i = index; i < index + count; i++) { for (int32 i = index; i < index + count; i++) {
entry_ref* ref = (entry_ref*)fRefs.ItemAtFast(i); PlaylistItem* item = ItemAtFast(i);
_NotifyRefAdded(*ref, i); _NotifyItemAdded(item, i);
} }
if (index <= fCurrentIndex) if (index <= fCurrentIndex)
SetCurrentRefIndex(fCurrentIndex + count); SetCurrentItemIndex(fCurrentIndex + count);
// empty the other list, so that the entry_refs are now ours // empty the other list, so that the PlaylistItems are now ours
other.fRefs.MakeEmpty(); other.fItems.MakeEmpty();
return true; return true;
} }
return false; return false;
} }
entry_ref PlaylistItem*
Playlist::RemoveRef(int32 index, bool careAboutCurrentIndex) Playlist::RemoveItem(int32 index, bool careAboutCurrentIndex)
{ {
entry_ref _ref; PlaylistItem* item = (PlaylistItem*)fItems.RemoveItem(index);
entry_ref* ref = (entry_ref*)fRefs.RemoveItem(index); if (!item)
if (!ref) return NULL;
return _ref; _NotifyItemRemoved(index);
_NotifyRefRemoved(index);
_ref = *ref;
delete ref;
if (careAboutCurrentIndex) { if (careAboutCurrentIndex) {
if (index == fCurrentIndex) if (index == fCurrentIndex && index >= CountItems())
SetCurrentRefIndex(-1); SetCurrentItemIndex(CountItems() - 1);
else if (index < fCurrentIndex) else if (index < fCurrentIndex)
SetCurrentRefIndex(fCurrentIndex - 1); SetCurrentItemIndex(fCurrentIndex - 1);
} }
return _ref; return item;
} }
int32 int32
Playlist::IndexOf(const entry_ref& _ref) const Playlist::IndexOf(PlaylistItem* item) const
{ {
int32 count = CountItems(); return fItems.IndexOf(item);
for (int32 i = 0; i < count; i++) {
entry_ref* ref = (entry_ref*)fRefs.ItemAtFast(i);
if (*ref == _ref)
return i;
}
return -1;
} }
status_t PlaylistItem*
Playlist::GetRefAt(int32 index, entry_ref* _ref) const Playlist::ItemAt(int32 index) const
{ {
if (!_ref) return (PlaylistItem*)fItems.ItemAt(index);
return B_BAD_VALUE;
entry_ref* ref = (entry_ref*)fRefs.ItemAt(index);
if (!ref)
return B_BAD_INDEX;
*_ref = *ref;
return B_OK;
} }
//bool PlaylistItem*
//Playlist::HasRef(const entry_ref& ref) const Playlist::ItemAtFast(int32 index) const
//{ {
// return IndexOf(ref) >= 0; return (PlaylistItem*)fItems.ItemAtFast(index);
//} }
// #pragma mark - navigation // #pragma mark - navigation
bool bool
Playlist::SetCurrentRefIndex(int32 index) Playlist::SetCurrentItemIndex(int32 index)
{ {
bool result = true; bool result = true;
if (index >= CountItems() || index < 0) { if (index >= CountItems() || index < 0) {
@@ -334,13 +361,13 @@ Playlist::SetCurrentRefIndex(int32 index)
return result; return result;
fCurrentIndex = index; fCurrentIndex = index;
_NotifyCurrentRefChanged(fCurrentIndex); _NotifyCurrentItemChanged(fCurrentIndex);
return result; return result;
} }
int32 int32
Playlist::CurrentRefIndex() const Playlist::CurrentItemIndex() const
{ {
return fCurrentIndex; return fCurrentIndex;
} }
@@ -377,7 +404,7 @@ Playlist::RemoveListener(Listener* listener)
} }
// #pragma mark - // #pragma mark - support
void void
@@ -409,7 +436,7 @@ Playlist::AppendRefs(const BMessage* refsReceivedMessage, int32 appendIndex)
sortPlaylist = false; sortPlaylist = false;
} else { } else {
AppendToPlaylistRecursive(ref, &subPlaylist); AppendToPlaylistRecursive(ref, &subPlaylist);
// At least sort the this subsection of the playlist // At least sort this subsection of the playlist
// if the whole playlist is not sorted anymore. // if the whole playlist is not sorted anymore.
if (!sortPlaylist) if (!sortPlaylist)
subPlaylist.Sort(); subPlaylist.Sort();
@@ -426,7 +453,7 @@ Playlist::AppendRefs(const BMessage* refsReceivedMessage, int32 appendIndex)
if (startPlaying) { if (startPlaying) {
// open first file // open first file
SetCurrentRefIndex(0); SetCurrentItemIndex(0);
} }
} }
@@ -448,11 +475,11 @@ Playlist::AppendToPlaylistRecursive(const entry_ref& ref, Playlist* playlist)
while (dir.GetNextRef(&subRef) == B_OK) while (dir.GetNextRef(&subRef) == B_OK)
AppendToPlaylistRecursive(subRef, playlist); AppendToPlaylistRecursive(subRef, playlist);
} else if (entry.IsFile()) { } else if (entry.IsFile()) {
//printf("Is File\n");
BString mimeString = _MIMEString(&ref); BString mimeString = _MIMEString(&ref);
if (_IsMediaFile(mimeString)) { if (_IsMediaFile(mimeString)) {
//printf("Adding\n"); PlaylistItem* item = new (std::nothrow) FilePlaylistItem(ref);
playlist->AddRef(ref); if (item == NULL || !playlist->AddItem(item))
delete item;
} else } else
printf("MIME Type = %s\n", mimeString.String()); printf("MIME Type = %s\n", mimeString.String());
} }
@@ -483,7 +510,10 @@ Playlist::AppendPlaylistToPlaylist(const entry_ref& ref, Playlist* playlist)
printf("Line %s\n", path.Path()); printf("Line %s\n", path.Path());
if (path.Path() != NULL) { if (path.Path() != NULL) {
if ((err = get_ref_for_path(path.Path(), &refPath)) == B_OK) { if ((err = get_ref_for_path(path.Path(), &refPath)) == B_OK) {
playlist->AddRef(refPath); PlaylistItem* item
= new (std::nothrow) FilePlaylistItem(refPath);
if (item == NULL || !playlist->AddItem(item))
delete item;
} else } else
printf("Error - %s: [%lx]\n", strerror(err), (int32) err); printf("Error - %s: [%lx]\n", strerror(err), (int32) err);
} else } else
@@ -498,21 +528,7 @@ Playlist::AppendPlaylistToPlaylist(const entry_ref& ref, Playlist* playlist)
} }
// #pragma mark - // #pragma mark - private
int
Playlist::playlist_cmp(const void *p1, const void *p2)
{
// compare complete path
BEntry a(*(const entry_ref **)p1, false);
BEntry b(*(const entry_ref **)p2, false);
BPath aPath(&a);
BPath bPath(&b);
return strcmp(aPath.Path(), bPath.Path());
}
/*static*/ bool /*static*/ bool
@@ -524,10 +540,29 @@ Playlist::_IsMediaFile(const BString& mimeString)
if (fileType.GetSupertype(&superType) != B_OK) if (fileType.GetSupertype(&superType) != B_OK)
return false; return false;
// TODO: some media files have other super types, I think // try a shortcut first
// for example ASF has "application" super type... so it would if (superType == "audio" || superType == "video")
// need special handling return true;
return (superType == "audio" || superType == "video");
// Look through our supported types
app_info appInfo;
if (be_app->GetAppInfo(&appInfo) != B_OK)
return false;
BFile appFile(&appInfo.ref, B_READ_ONLY);
if (appFile.InitCheck() != B_OK)
return false;
BMessage types;
BAppFileInfo appFileInfo(&appFile);
if (appFileInfo.GetSupportedTypes(&types) != B_OK)
return false;
const char* type;
for (int32 i = 0; types.FindString("types", i, &type) == B_OK; i++) {
if (strcasecmp(mimeString.String(), type) == 0)
return true;
}
return false;
} }
@@ -570,50 +605,53 @@ Playlist::_MIMEString(const entry_ref* ref)
} }
// #pragma mark - notifications
void void
Playlist::_NotifyRefAdded(const entry_ref& ref, int32 index) const Playlist::_NotifyItemAdded(PlaylistItem* item, int32 index) const
{ {
BList listeners(fListeners); BList listeners(fListeners);
int32 count = listeners.CountItems(); int32 count = listeners.CountItems();
for (int32 i = 0; i < count; i++) { for (int32 i = 0; i < count; i++) {
Listener* listener = (Listener*)listeners.ItemAtFast(i); Listener* listener = (Listener*)listeners.ItemAtFast(i);
listener->RefAdded(ref, index); listener->ItemAdded(item, index);
} }
} }
void void
Playlist::_NotifyRefRemoved(int32 index) const Playlist::_NotifyItemRemoved(int32 index) const
{ {
BList listeners(fListeners); BList listeners(fListeners);
int32 count = listeners.CountItems(); int32 count = listeners.CountItems();
for (int32 i = 0; i < count; i++) { for (int32 i = 0; i < count; i++) {
Listener* listener = (Listener*)listeners.ItemAtFast(i); Listener* listener = (Listener*)listeners.ItemAtFast(i);
listener->RefRemoved(index); listener->ItemRemoved(index);
} }
} }
void void
Playlist::_NotifyRefsSorted() const Playlist::_NotifyItemsSorted() const
{ {
BList listeners(fListeners); BList listeners(fListeners);
int32 count = listeners.CountItems(); int32 count = listeners.CountItems();
for (int32 i = 0; i < count; i++) { for (int32 i = 0; i < count; i++) {
Listener* listener = (Listener*)listeners.ItemAtFast(i); Listener* listener = (Listener*)listeners.ItemAtFast(i);
listener->RefsSorted(); listener->ItemsSorted();
} }
} }
void void
Playlist::_NotifyCurrentRefChanged(int32 newIndex) const Playlist::_NotifyCurrentItemChanged(int32 newIndex) const
{ {
BList listeners(fListeners); BList listeners(fListeners);
int32 count = listeners.CountItems(); int32 count = listeners.CountItems();
for (int32 i = 0; i < count; i++) { for (int32 i = 0; i < count; i++) {
Listener* listener = (Listener*)listeners.ItemAtFast(i); Listener* listener = (Listener*)listeners.ItemAtFast(i);
listener->CurrentRefChanged(newIndex); listener->CurrentItemChanged(newIndex);
} }
} }
+24 -22
View File
@@ -2,8 +2,8 @@
* Playlist.h - Media Player for the Haiku Operating System * Playlist.h - Media Player for the Haiku Operating System
* *
* Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de> * Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de>
* Copyright (C) 2007 Stephan Aßmus <superstippi@gmx.de> * Copyright (C) 2007-2009 Stephan Aßmus <superstippi@gmx.de> (MIT ok)
* Copyright (C) 2008-2009 Fredrik Modéen <[FirstName]@[LastName].se> (MIT ok) * Copyright (C) 2008-2009 Fredrik Modéen <[FirstName]@[LastName].se> (MIT ok)
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -22,13 +22,15 @@
#ifndef __PLAYLIST_H #ifndef __PLAYLIST_H
#define __PLAYLIST_H #define __PLAYLIST_H
#include <Entry.h>
#include <List.h> #include <List.h>
#include <Locker.h> #include <Locker.h>
#include "PlaylistItem.h"
class BDataIO; class BDataIO;
class BMessage; class BMessage;
class BString; class BString;
struct entry_ref;
class Playlist : public BLocker { class Playlist : public BLocker {
@@ -38,12 +40,12 @@ public:
Listener(); Listener();
virtual ~Listener(); virtual ~Listener();
virtual void RefAdded(const entry_ref& ref, int32 index); virtual void ItemAdded(PlaylistItem* item, int32 index);
virtual void RefRemoved(int32 index); virtual void ItemRemoved(int32 index);
virtual void RefsSorted(); virtual void ItemsSorted();
virtual void CurrentRefChanged(int32 newIndex); virtual void CurrentItemChanged(int32 newIndex);
}; };
public: public:
@@ -58,26 +60,26 @@ public:
// list functionality // list functionality
void MakeEmpty(); void MakeEmpty(bool deleteItems = true);
int32 CountItems() const; int32 CountItems() const;
void Sort(); void Sort();
bool AddRef(const entry_ref& ref); bool AddItem(PlaylistItem* item);
bool AddRef(const entry_ref& ref, int32 index); bool AddItem(PlaylistItem* item, int32 index);
entry_ref RemoveRef(int32 index, PlaylistItem* RemoveItem(int32 index,
bool careAboutCurrentIndex = true); bool careAboutCurrentIndex = true);
bool AdoptPlaylist(Playlist& other); bool AdoptPlaylist(Playlist& other);
bool AdoptPlaylist(Playlist& other, int32 index); bool AdoptPlaylist(Playlist& other, int32 index);
int32 IndexOf(const entry_ref& ref) const; int32 IndexOf(PlaylistItem* item) const;
status_t GetRefAt(int32 index, entry_ref* ref) const; PlaylistItem* ItemAt(int32 index) const;
// bool HasRef(const entry_ref& ref) const; PlaylistItem* ItemAtFast(int32 index) const;
// navigating current ref // navigating current ref
bool SetCurrentRefIndex(int32 index); bool SetCurrentItemIndex(int32 index);
int32 CurrentRefIndex() const; int32 CurrentItemIndex() const;
void GetSkipInfo(bool* canSkipPrevious, void GetSkipInfo(bool* canSkipPrevious,
bool* canSkipNext) const; bool* canSkipNext) const;
@@ -95,20 +97,20 @@ public:
Playlist* playlist); Playlist* playlist);
private: private:
static int playlist_cmp(const void* p1, const void* p2);
static bool _IsMediaFile(const BString& mimeString); static bool _IsMediaFile(const BString& mimeString);
static bool _IsTextPlaylist(const BString& mimeString); static bool _IsTextPlaylist(const BString& mimeString);
static bool _IsBinaryPlaylist(const BString& mimeString); static bool _IsBinaryPlaylist(const BString& mimeString);
static bool _IsPlaylist(const BString& mimeString); static bool _IsPlaylist(const BString& mimeString);
static BString _MIMEString(const entry_ref* ref); static BString _MIMEString(const entry_ref* ref);
void _NotifyRefAdded(const entry_ref& ref,
void _NotifyItemAdded(PlaylistItem*,
int32 index) const; int32 index) const;
void _NotifyRefRemoved(int32 index) const; void _NotifyItemRemoved(int32 index) const;
void _NotifyRefsSorted() const; void _NotifyItemsSorted() const;
void _NotifyCurrentRefChanged(int32 newIndex) const; void _NotifyCurrentItemChanged(int32 newIndex) const;
private: private:
BList fRefs; BList fItems;
BList fListeners; BList fListeners;
int32 fCurrentIndex; int32 fCurrentIndex;
@@ -5,6 +5,8 @@
#include "PlaylistItem.h" #include "PlaylistItem.h"
#include <stdio.h>
PlaylistItem::Listener::Listener() PlaylistItem::Listener::Listener()
{ {
@@ -22,13 +24,97 @@ void PlaylistItem::Listener::ItemChanged(const PlaylistItem* item)
// #pragma mark - // #pragma mark -
//#define DEBUG_INSTANCE_COUNT
#ifdef DEBUG_INSTANCE_COUNT
static vint32 sInstanceCount = 0;
#endif
PlaylistItem::PlaylistItem() PlaylistItem::PlaylistItem()
{ {
#ifdef DEBUG_INSTANCE_COUNT
atomic_add(&sInstanceCount, 1);
printf("%p->PlaylistItem::PlaylistItem() (%ld)\n", this, sInstanceCount);
#endif
} }
PlaylistItem::~PlaylistItem() PlaylistItem::~PlaylistItem()
{ {
#ifdef DEBUG_INSTANCE_COUNT
atomic_add(&sInstanceCount, -1);
printf("%p->PlaylistItem::~PlaylistItem() (%ld)\n", this, sInstanceCount);
#endif
}
BString
PlaylistItem::Name() const
{
BString name;
if (GetAttribute(ATTR_STRING_NAME, name) != B_OK)
name = "<unnamed>";
return name;
}
BString
PlaylistItem::Author() const
{
BString author;
if (GetAttribute(ATTR_STRING_AUTHOR, author) != B_OK)
author = "<unknown>";
return author;
}
BString
PlaylistItem::Album() const
{
BString album;
if (GetAttribute(ATTR_STRING_ALBUM, album) != B_OK)
album = "<unknown>";
return album;
}
BString
PlaylistItem::Title() const
{
BString title;
if (GetAttribute(ATTR_STRING_TITLE, title) != B_OK)
title = "<untitled>";
return title;
}
int32
PlaylistItem::TrackNumber() const
{
int32 trackNumber;
if (GetAttribute(ATTR_INT32_TRACK, trackNumber) != B_OK)
trackNumber = 0;
return trackNumber;
}
int32
PlaylistItem::BitRate() const
{
int32 bitrate;
if (GetAttribute(ATTR_INT32_BIT_RATE, bitrate) != B_OK)
bitrate = 0;
return bitrate;
}
bigtime_t
PlaylistItem::Duration() const
{
bigtime_t duration;
if (GetAttribute(ATTR_INT64_DURATION, duration) != B_OK)
duration = 0;
return duration;
} }
+51 -20
View File
@@ -5,14 +5,18 @@
#ifndef PLAYLIST_ITEM_H #ifndef PLAYLIST_ITEM_H
#define PLAYLIST_ITEM_H #define PLAYLIST_ITEM_H
#include <Archivable.h>
#include <List.h> #include <List.h>
#include <NodeInfo.h>
#include <Referenceable.h>
#include <String.h> #include <String.h>
class BBitmap;
class BDataIO; class BDataIO;
class BMediaFile; class BMediaFile;
class BMessage; class BMessage;
class PlaylistItem { class PlaylistItem : public BArchivable, public Referenceable {
public: public:
class Listener { class Listener {
public: public:
@@ -26,35 +30,60 @@ public:
PlaylistItem(); PlaylistItem();
virtual ~PlaylistItem(); virtual ~PlaylistItem();
virtual PlaylistItem* Clone() const = 0;
// archiving // archiving
// virtual status_t Unarchive(const BMessage* archive) = 0; virtual status_t Archive(BMessage* into,
// virtual status_t Archive(BMessage* into) const = 0; bool deep = true) const = 0;
//
// virtual status_t Unflatten(BDataIO* stream) = 0;
// virtual status_t Flatten(BDataIO* stream) const = 0;
// properties // attributes
virtual status_t SetName(const BString& name) = 0; typedef enum {
virtual status_t GetName(BString& name) const = 0; ATTR_STRING_NAME = 'name',
ATTR_STRING_KEYWORDS = 'kwrd',
virtual status_t SetTitle(const BString& title) = 0; ATTR_STRING_AUTHOR = 'auth',
virtual status_t GetTitle(BString& title) const = 0; ATTR_STRING_ALBUM = 'albm',
ATTR_STRING_TITLE = 'titl',
virtual status_t SetAuthor(const BString& author) = 0; ATTR_INT32_TRACK = 'trck',
virtual status_t GetAuthor(BString& author) const = 0; ATTR_INT32_YEAR = 'year',
ATTR_INT32_RATING = 'rtng',
ATTR_INT32_BIT_RATE = 'btrt',
virtual status_t SetAlbum(const BString& album) = 0; ATTR_INT64_DURATION = 'drtn'
virtual status_t GetAlbum(BString& album) const = 0; } Attribute;
virtual status_t SetTrackNumber(int32 trackNumber) = 0; virtual status_t SetAttribute(const Attribute& attribute,
virtual status_t GetTrackNumber(int32& trackNumber) const = 0; const BString& string) = 0;
virtual status_t GetAttribute(const Attribute& attribute,
BString& string) const = 0;
virtual status_t SetBitRate(int32 bitRate) = 0; virtual status_t SetAttribute(const Attribute& attribute,
virtual status_t GetBitRate(int32& bitRate) const = 0; const int32& value) = 0;
virtual status_t GetAttribute(const Attribute& attribute,
int32& value) const = 0;
virtual status_t GetDuration(bigtime_t& duration) const = 0; virtual status_t SetAttribute(const Attribute& attribute,
const int64& value) = 0;
virtual status_t GetAttribute(const Attribute& attribute,
int64& value) const = 0;
// convenience access to attributes
BString Name() const;
BString Author() const;
BString Album() const;
BString Title() const;
int32 TrackNumber() const;
int32 BitRate() const;
bigtime_t Duration() const;
// methods // methods
virtual BString LocationURI() const = 0;
virtual status_t GetIcon(BBitmap* bitmap,
icon_size iconSize) const = 0;
virtual status_t MoveIntoTrash() = 0; virtual status_t MoveIntoTrash() = 0;
virtual status_t RestoreFromTrash() = 0; virtual status_t RestoreFromTrash() = 0;
@@ -72,4 +101,6 @@ private:
BList fListeners; BList fListeners;
}; };
typedef Reference<PlaylistItem> PlaylistItemRef;
#endif // PLAYLIST_ITEM_H #endif // PLAYLIST_ITEM_H
@@ -1,10 +1,8 @@
/* /*
* Copyright 2007-2009, Haiku. All rights reserved. * Copyright 2007-2009 Stephan Aßmus <superstippi@gmx.de>.
* Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
*/ */
#include "PlaylistListView.h" #include "PlaylistListView.h"
#include <new> #include <new>
@@ -29,6 +27,7 @@
#include "MovePLItemsCommand.h" #include "MovePLItemsCommand.h"
#include "PlaybackState.h" #include "PlaybackState.h"
#include "Playlist.h" #include "Playlist.h"
#include "PlaylistItem.h"
#include "PlaylistObserver.h" #include "PlaylistObserver.h"
#include "RandomizePLItemsCommand.h" #include "RandomizePLItemsCommand.h"
#include "RemovePLItemsCommand.h" #include "RemovePLItemsCommand.h"
@@ -56,32 +55,37 @@ text_offset(const font_height& fh)
} }
class PlaylistListView::Item : public SimpleItem { class PlaylistListView::Item : public SimpleItem,
public: public PlaylistItem::Listener {
Item(const entry_ref& ref); public:
virtual ~Item(); Item(PlaylistItem* item);
virtual ~Item();
void Draw(BView* owner, BRect frame, void Draw(BView* owner, BRect frame,
const font_height& fh, const font_height& fh,
bool tintedLine, uint32 mode, bool tintedLine, uint32 mode,
bool active, bool active,
uint32 playbackState); uint32 playbackState);
private: virtual void ItemChanged(const PlaylistItem* item);
entry_ref fRef;
private:
PlaylistItemRef fItem;
}; };
PlaylistListView::Item::Item(const entry_ref& ref) PlaylistListView::Item::Item(PlaylistItem* item)
: SimpleItem(ref.name), : SimpleItem(item->Name().String()),
fRef(ref) fItem(item)
{ {
fItem->AddListener(this);
} }
PlaylistListView::Item::~Item() PlaylistListView::Item::~Item()
{ {
fItem->RemoveListener(this);
} }
@@ -202,6 +206,13 @@ PlaylistListView::Item::Draw(BView* owner, BRect frame, const font_height& fh,
} }
void
PlaylistListView::Item::ItemChanged(const PlaylistItem* item)
{
// TODO: Invalidate
}
// #pragma mark - // #pragma mark -
@@ -234,6 +245,8 @@ PlaylistListView::PlaylistListView(BRect frame, Playlist* playlist,
PlaylistListView::~PlaylistListView() PlaylistListView::~PlaylistListView()
{ {
for (int32 i = CountItems() - 1; i >= 0; i--)
_RemoveItem(i);
fPlaylist->RemoveListener(fPlaylistObserver); fPlaylist->RemoveListener(fPlaylistObserver);
delete fPlaylistObserver; delete fPlaylistObserver;
fController->RemoveListener(fControllerObserver); fController->RemoveListener(fControllerObserver);
@@ -258,24 +271,27 @@ PlaylistListView::MessageReceived(BMessage* message)
// message->PrintToStream(); // message->PrintToStream();
switch (message->what) { switch (message->what) {
// PlaylistObserver messages // PlaylistObserver messages
case MSG_PLAYLIST_REF_ADDED: { case MSG_PLAYLIST_ITEM_ADDED:
entry_ref ref; {
PlaylistItem* item;
int32 index; int32 index;
if (message->FindRef("refs", &ref) == B_OK if (message->FindPointer("item", (void**)&item) == B_OK
&& message->FindInt32("index", &index) == B_OK) && message->FindInt32("index", &index) == B_OK)
_AddItem(ref, index); _AddItem(item, index);
break; break;
} }
case MSG_PLAYLIST_REF_REMOVED: { case MSG_PLAYLIST_ITEM_REMOVED:
{
int32 index; int32 index;
if (message->FindInt32("index", &index) == B_OK) if (message->FindInt32("index", &index) == B_OK)
_RemoveItem(index); _RemoveItem(index);
break; break;
} }
case MSG_PLAYLIST_REFS_SORTED: case MSG_PLAYLIST_ITEMS_SORTED:
_FullSync(); _FullSync();
break; break;
case MSG_PLAYLIST_CURRENT_REF_CHANGED: { case MSG_PLAYLIST_CURRENT_ITEM_CHANGED:
{
int32 index; int32 index;
if (message->FindInt32("index", &index) == B_OK) if (message->FindInt32("index", &index) == B_OK)
_SetCurrentPlaylistIndex(index); _SetCurrentPlaylistIndex(index);
@@ -283,7 +299,8 @@ PlaylistListView::MessageReceived(BMessage* message)
} }
// ControllerObserver messages // ControllerObserver messages
case MSG_CONTROLLER_PLAYBACK_STATE_CHANGED: { case MSG_CONTROLLER_PLAYBACK_STATE_CHANGED:
{
uint32 state; uint32 state;
if (message->FindInt32("state", (int32*)&state) == B_OK) if (message->FindInt32("state", (int32*)&state) == B_OK)
_SetPlaybackState(state); _SetPlaybackState(state);
@@ -330,7 +347,7 @@ PlaylistListView::MouseDown(BPoint where)
// only do something if user clicked the same item twice // only do something if user clicked the same item twice
if (fLastClickedItem == item) { if (fLastClickedItem == item) {
BAutolock _(fPlaylist); BAutolock _(fPlaylist);
fPlaylist->SetCurrentRefIndex(i); fPlaylist->SetCurrentItemIndex(i);
handled = true; handled = true;
} }
} else { } else {
@@ -486,16 +503,14 @@ PlaylistListView::_FullSync()
scrollBar->SetTarget((BView*)NULL); scrollBar->SetTarget((BView*)NULL);
} }
MakeEmpty(); for (int32 i = CountItems() - 1; i >= 0; i--)
_RemoveItem(i);
int32 count = fPlaylist->CountItems(); int32 count = fPlaylist->CountItems();
for (int32 i = 0; i < count; i++) { for (int32 i = 0; i < count; i++)
entry_ref ref; _AddItem(fPlaylist->ItemAt(i), i);
if (fPlaylist->GetRefAt(i, &ref) == B_OK)
_AddItem(ref, i);
}
_SetCurrentPlaylistIndex(fPlaylist->CurrentRefIndex()); _SetCurrentPlaylistIndex(fPlaylist->CurrentItemIndex());
_SetPlaybackState(fController->PlaybackState()); _SetPlaybackState(fController->PlaybackState());
// reattach scrollbar and sync it by calling FrameResized() // reattach scrollbar and sync it by calling FrameResized()
@@ -509,10 +524,13 @@ PlaylistListView::_FullSync()
void void
PlaylistListView::_AddItem(const entry_ref& ref, int32 index) PlaylistListView::_AddItem(PlaylistItem* _item, int32 index)
{ {
Item* item = new (nothrow) Item(ref); if (_item == NULL)
if (item) return;
Item* item = new (nothrow) Item(_item);
if (item != NULL)
AddItem(item, index); AddItem(item, index);
} }
@@ -14,6 +14,7 @@ class CommandStack;
class Controller; class Controller;
class ControllerObserver; class ControllerObserver;
class Playlist; class Playlist;
class PlaylistItem;
class PlaylistObserver; class PlaylistObserver;
class PlaylistListView : public SimpleListView { class PlaylistListView : public SimpleListView {
@@ -53,7 +54,7 @@ private:
class Item; class Item;
void _FullSync(); void _FullSync();
void _AddItem(const entry_ref& ref, int32 index); void _AddItem(PlaylistItem* item, int32 index);
void _RemoveItem(int32 index); void _RemoveItem(int32 index);
void _SetCurrentPlaylistIndex(int32 index); void _SetCurrentPlaylistIndex(int32 index);
@@ -1,9 +1,6 @@
/* /*
* Copyright 2007, Haiku. All rights reserved. * Copyright 2007-2009 Stephan Aßmus <superstippi@gmx.de>.
* Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
*/ */
#include "PlaylistObserver.h" #include "PlaylistObserver.h"
@@ -24,10 +21,10 @@ PlaylistObserver::~PlaylistObserver()
void void
PlaylistObserver::RefAdded(const entry_ref& ref, int32 index) PlaylistObserver::ItemAdded(PlaylistItem* item, int32 index)
{ {
BMessage message(MSG_PLAYLIST_REF_ADDED); BMessage message(MSG_PLAYLIST_ITEM_ADDED);
message.AddRef("refs", &ref); message.AddPointer("item", item);
message.AddInt32("index", index); message.AddInt32("index", index);
DeliverMessage(message); DeliverMessage(message);
@@ -35,9 +32,9 @@ PlaylistObserver::RefAdded(const entry_ref& ref, int32 index)
void void
PlaylistObserver::RefRemoved(int32 index) PlaylistObserver::ItemRemoved(int32 index)
{ {
BMessage message(MSG_PLAYLIST_REF_REMOVED); BMessage message(MSG_PLAYLIST_ITEM_REMOVED);
message.AddInt32("index", index); message.AddInt32("index", index);
DeliverMessage(message); DeliverMessage(message);
@@ -45,18 +42,18 @@ PlaylistObserver::RefRemoved(int32 index)
void void
PlaylistObserver::RefsSorted() PlaylistObserver::ItemsSorted()
{ {
BMessage message(MSG_PLAYLIST_REFS_SORTED); BMessage message(MSG_PLAYLIST_ITEMS_SORTED);
DeliverMessage(message); DeliverMessage(message);
} }
void void
PlaylistObserver::CurrentRefChanged(int32 newIndex) PlaylistObserver::CurrentItemChanged(int32 newIndex)
{ {
BMessage message(MSG_PLAYLIST_CURRENT_REF_CHANGED); BMessage message(MSG_PLAYLIST_CURRENT_ITEM_CHANGED);
message.AddInt32("index", newIndex); message.AddInt32("index", newIndex);
DeliverMessage(message); DeliverMessage(message);
@@ -1,9 +1,6 @@
/* /*
* Copyright 2007, Haiku. All rights reserved. * Copyright 2007-2009 Stephan Aßmus <superstippi@gmx.de>.
* Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
*/ */
#ifndef PLAYLIST_OBSERVER_H #ifndef PLAYLIST_OBSERVER_H
#define PLAYLIST_OBSERVER_H #define PLAYLIST_OBSERVER_H
@@ -12,24 +9,23 @@
#include "Playlist.h" #include "Playlist.h"
enum { enum {
MSG_PLAYLIST_REF_ADDED = 'plra', MSG_PLAYLIST_ITEM_ADDED = 'plia',
MSG_PLAYLIST_REF_REMOVED = 'plrr', MSG_PLAYLIST_ITEM_REMOVED = 'plir',
MSG_PLAYLIST_REFS_SORTED = 'plrs', MSG_PLAYLIST_ITEMS_SORTED = 'plis',
MSG_PLAYLIST_CURRENT_REF_CHANGED = 'plcc' MSG_PLAYLIST_CURRENT_ITEM_CHANGED = 'plcc'
}; };
class PlaylistObserver : public Playlist::Listener, class PlaylistObserver : public Playlist::Listener, public AbstractLOAdapter {
public AbstractLOAdapter { public:
public: PlaylistObserver(BHandler* target);
PlaylistObserver(BHandler* target); virtual ~PlaylistObserver();
virtual ~PlaylistObserver();
virtual void RefAdded(const entry_ref& ref, int32 index); virtual void ItemAdded(PlaylistItem* item, int32 index);
virtual void RefRemoved(int32 index); virtual void ItemRemoved(int32 index);
virtual void RefsSorted(); virtual void ItemsSorted();
virtual void CurrentRefChanged(int32 newIndex); virtual void CurrentItemChanged(int32 newIndex);
}; };
#endif // PLAYLIST_OBSERVER_H #endif // PLAYLIST_OBSERVER_H
@@ -1,6 +1,6 @@
/* /*
* Copyright © 2008 Stephan Aßmus. All rights reserved. * Copyright © 2008-2009 Stephan Aßmus <superstippi@gmx.de>
* Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
#include "RandomizePLItemsCommand.h" #include "RandomizePLItemsCommand.h"
@@ -19,31 +19,33 @@ using std::nothrow;
RandomizePLItemsCommand::RandomizePLItemsCommand(Playlist* playlist, RandomizePLItemsCommand::RandomizePLItemsCommand(Playlist* playlist,
const int32* indices, int32 count) const int32* indices, int32 count)
: Command() :
, fPlaylist(playlist) PLItemsCommand(),
, fRefs(count > 0 ? new (nothrow) entry_ref[count] : NULL) fPlaylist(playlist),
, fListIndices(count > 0 ? new (nothrow) int32[count] : NULL) fItems(count > 0 ? new (nothrow) PlaylistItem*[count] : NULL),
, fRandomInternalIndices(count > 0 ? new (nothrow) int32[count] : NULL) fListIndices(count > 0 ? new (nothrow) int32[count] : NULL),
, fCount(count) fRandomInternalIndices(count > 0 ? new (nothrow) int32[count] : NULL),
fCount(count)
{ {
if (!indices || !fPlaylist || !fRefs || !fListIndices if (!indices || !fPlaylist || !fItems || !fListIndices
|| !fRandomInternalIndices) { || !fRandomInternalIndices) {
// indicate a bad object state // indicate a bad object state
delete[] fRefs; delete[] fItems;
fRefs = NULL; fItems = NULL;
return; return;
} }
memcpy(fListIndices, indices, fCount * sizeof(int32)); memcpy(fListIndices, indices, fCount * sizeof(int32));
memset(fItems, 0, fCount * sizeof(PlaylistItem*));
// put the available indices into a "set" // put the available indices into a "set"
BList indexSet; BList indexSet;
for (int32 i = 0; i < fCount; i++) { for (int32 i = 0; i < fCount; i++) {
if (fPlaylist->GetRefAt(fListIndices[i], &fRefs[i]) < B_OK fItems[i] = fPlaylist->ItemAt(fListIndices[i]);
|| !indexSet.AddItem((void*)i)) { if (fItems[i] == NULL || !indexSet.AddItem((void*)i)) {
// indicate a bad object state // indicate a bad object state
delete[] fRefs; delete[] fItems;
fRefs = NULL; fItems = NULL;
return; return;
} }
} }
@@ -58,7 +60,7 @@ RandomizePLItemsCommand::RandomizePLItemsCommand(Playlist* playlist,
RandomizePLItemsCommand::~RandomizePLItemsCommand() RandomizePLItemsCommand::~RandomizePLItemsCommand()
{ {
delete[] fRefs; delete[] fItems;
delete[] fListIndices; delete[] fListIndices;
delete[] fRandomInternalIndices; delete[] fRandomInternalIndices;
} }
@@ -67,7 +69,7 @@ RandomizePLItemsCommand::~RandomizePLItemsCommand()
status_t status_t
RandomizePLItemsCommand::InitCheck() RandomizePLItemsCommand::InitCheck()
{ {
if (!fRefs) if (!fItems)
return B_NO_INIT; return B_NO_INIT;
return B_OK; return B_OK;
@@ -100,36 +102,34 @@ RandomizePLItemsCommand::_Sort(bool random)
{ {
BAutolock _(fPlaylist); BAutolock _(fPlaylist);
// remember currently playling ref in case we move it // remember currently playling item in case we move it
entry_ref currentRef; PlaylistItem* current = fPlaylist->ItemAt(fPlaylist->CurrentItemIndex());
bool adjustCurrentRef = fPlaylist->GetRefAt(fPlaylist->CurrentRefIndex(),
&currentRef) == B_OK;
// remove refs from playlist // remove refs from playlist
for (int32 i = 0; i < fCount; i++) { for (int32 i = 0; i < fCount; i++) {
// "- i" to account for the items already removed // "- i" to account for the items already removed
fPlaylist->RemoveRef(fListIndices[i] - i, false); fPlaylist->RemoveItem(fListIndices[i] - i, false);
} }
// add refs to playlist at the randomized indices // add refs to playlist at the randomized indices
if (random) { if (random) {
for (int32 i = 0; i < fCount; i++) { for (int32 i = 0; i < fCount; i++) {
if (!fPlaylist->AddRef(fRefs[fRandomInternalIndices[i]], if (!fPlaylist->AddItem(fItems[fRandomInternalIndices[i]],
fListIndices[i])) { fListIndices[i])) {
return B_NO_MEMORY; return B_NO_MEMORY;
} }
} }
} else { } else {
for (int32 i = 0; i < fCount; i++) { for (int32 i = 0; i < fCount; i++) {
if (!fPlaylist->AddRef(fRefs[i], fListIndices[i])) { if (!fPlaylist->AddItem(fItems[i], fListIndices[i])) {
return B_NO_MEMORY; return B_NO_MEMORY;
} }
} }
} }
// take care about currently played ref // take care about currently played item
if (adjustCurrentRef) if (current != NULL)
fPlaylist->SetCurrentRefIndex(fPlaylist->IndexOf(currentRef)); fPlaylist->SetCurrentItemIndex(fPlaylist->IndexOf(current));
return B_OK; return B_OK;
} }
@@ -1,24 +1,21 @@
/* /*
* Copyright © 2008 Stephan Aßmus. All rights reserved. * Copyright © 2008-2009 Stephan Aßmus <superstippi@gmx.de>
* Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
#ifndef RANDOMIZE_PL_ITEMS_COMMAND_H #ifndef RANDOMIZE_PL_ITEMS_COMMAND_H
#define RANDOMIZE_PL_ITEMS_COMMAND_H #define RANDOMIZE_PL_ITEMS_COMMAND_H
#include "Command.h" #include "PLItemsCommand.h"
class Playlist; class RandomizePLItemsCommand : public PLItemsCommand {
struct entry_ref; public:
class RandomizePLItemsCommand : public Command {
public:
RandomizePLItemsCommand( RandomizePLItemsCommand(
Playlist* playlist, Playlist* playlist,
const int32* indices, const int32* indices,
int32 count); int32 count);
virtual ~RandomizePLItemsCommand(); virtual ~RandomizePLItemsCommand();
virtual status_t InitCheck(); virtual status_t InitCheck();
virtual status_t Perform(); virtual status_t Perform();
@@ -26,11 +23,11 @@ class RandomizePLItemsCommand : public Command {
virtual void GetName(BString& name); virtual void GetName(BString& name);
private: private:
status_t _Sort(bool random); status_t _Sort(bool random);
Playlist* fPlaylist; Playlist* fPlaylist;
entry_ref* fRefs; PlaylistItem** fItems;
int32* fListIndices; int32* fListIndices;
int32* fRandomInternalIndices; int32* fRandomInternalIndices;
int32 fCount; int32 fCount;
@@ -1,9 +1,6 @@
/* /*
* Copyright 2007-2009, Haiku. All rights reserved. * Copyright © 2007-2009 Stephan Aßmus <superstippi@gmx.de>
* Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT license.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
*/ */
#include "RemovePLItemsCommand.h" #include "RemovePLItemsCommand.h"
@@ -13,10 +10,6 @@
#include <Alert.h> #include <Alert.h>
#include <Autolock.h> #include <Autolock.h>
#include <Directory.h>
#include <Entry.h>
#include <FindDirectory.h>
#include <Path.h>
#include "Playlist.h" #include "Playlist.h"
@@ -27,35 +20,31 @@ using std::nothrow;
RemovePLItemsCommand::RemovePLItemsCommand(Playlist* playlist, RemovePLItemsCommand::RemovePLItemsCommand(Playlist* playlist,
const int32* indices, int32 count, bool moveFilesToTrash) const int32* indices, int32 count, bool moveFilesToTrash)
: :
Command(), PLItemsCommand(),
fPlaylist(playlist), fPlaylist(playlist),
fRefs(count > 0 ? new (nothrow) entry_ref[count] : NULL), fItems(count > 0 ? new (nothrow) PlaylistItem*[count] : NULL),
fNamesInTrash(NULL),
fIndices(count > 0 ? new (nothrow) int32[count] : NULL), fIndices(count > 0 ? new (nothrow) int32[count] : NULL),
fCount(count), fCount(count),
fMoveFilesToTrash(moveFilesToTrash), fMoveFilesToTrash(moveFilesToTrash),
fMoveErrorShown(false) fMoveErrorShown(false),
fItemsRemoved(false)
{ {
if (!indices || !fPlaylist || !fRefs || !fIndices) { if (!indices || !fPlaylist || !fItems || !fIndices) {
// indicate a bad object state // indicate a bad object state
delete[] fRefs; delete[] fItems;
fRefs = NULL; fItems = NULL;
return; return;
} }
memcpy(fIndices, indices, fCount * sizeof(int32)); memcpy(fIndices, indices, fCount * sizeof(int32));
memset(fItems, 0, fCount * sizeof(PlaylistItem*));
if (fMoveFilesToTrash) {
fNamesInTrash = new (nothrow) BString[count];
if (fNamesInTrash == NULL)
return;
}
// init original entry indices // init original entry indices
for (int32 i = 0; i < fCount; i++) { for (int32 i = 0; i < fCount; i++) {
if (fPlaylist->GetRefAt(fIndices[i], &fRefs[i]) < B_OK) { fItems[i] = fPlaylist->ItemAt(fIndices[i]);
delete[] fRefs; if (fItems[i] == NULL) {
fRefs = NULL; delete[] fItems;
fItems = NULL;
return; return;
} }
} }
@@ -64,19 +53,16 @@ RemovePLItemsCommand::RemovePLItemsCommand(Playlist* playlist,
RemovePLItemsCommand::~RemovePLItemsCommand() RemovePLItemsCommand::~RemovePLItemsCommand()
{ {
delete[] fRefs; _CleanUp(fItems, fCount, fItemsRemoved);
delete[] fIndices; delete[] fIndices;
delete[] fNamesInTrash;
} }
status_t status_t
RemovePLItemsCommand::InitCheck() RemovePLItemsCommand::InitCheck()
{ {
if (!fPlaylist || !fRefs || !fIndices if (!fPlaylist || !fItems || !fIndices)
|| (fMoveFilesToTrash && !fNamesInTrash)) {
return B_NO_INIT; return B_NO_INIT;
}
return B_OK; return B_OK;
} }
@@ -86,65 +72,32 @@ RemovePLItemsCommand::Perform()
{ {
BAutolock _(fPlaylist); BAutolock _(fPlaylist);
fItemsRemoved = true;
int32 lastRemovedIndex = -1; int32 lastRemovedIndex = -1;
// remove refs from playlist // remove refs from playlist
for (int32 i = 0; i < fCount; i++) { for (int32 i = 0; i < fCount; i++) {
// "- i" to account for the items already removed // "- i" to account for the items already removed
lastRemovedIndex = fIndices[i] - i; lastRemovedIndex = fIndices[i] - i;
fPlaylist->RemoveRef(lastRemovedIndex); fPlaylist->RemoveItem(lastRemovedIndex);
} }
// in case we removed the currently playing file // in case we removed the currently playing file
if (fPlaylist->CurrentRefIndex() == -1) if (fPlaylist->CurrentItemIndex() == -1)
fPlaylist->SetCurrentRefIndex(lastRemovedIndex); fPlaylist->SetCurrentItemIndex(lastRemovedIndex);
if (fMoveFilesToTrash) { if (fMoveFilesToTrash) {
BString errorFiles; BString errorFiles;
status_t moveError = B_OK; status_t moveError = B_OK;
bool errorOnAllFiles = true; bool errorOnAllFiles = true;
char trashPath[B_PATH_NAME_LENGTH];
for (int32 i = 0; i < fCount; i++) { for (int32 i = 0; i < fCount; i++) {
status_t err = find_directory(B_TRASH_DIRECTORY, fRefs[i].device, status_t err = fItems[i]->MoveIntoTrash();
true /*create it*/, trashPath, B_PATH_NAME_LENGTH);
if (err != B_OK) {
fprintf(stderr, "failed to find Trash: %s\n", strerror(err));
continue;
}
BEntry entry(&fRefs[i]);
err = entry.InitCheck();
if (err != B_OK) {
fprintf(stderr, "failed to init BEntry for %s: %s\n",
fRefs[i].name, strerror(err));
continue;
}
BDirectory trashDir(trashPath);
if (err != B_OK) {
fprintf(stderr, "failed to init BDirectory for %s: %s\n",
trashPath, strerror(err));
continue;
}
// Find a unique name for the entry in the trash
fNamesInTrash[i] = fRefs[i].name;
int32 uniqueNameIndex = 1;
while (true) {
BEntry test(&trashDir, fNamesInTrash[i].String());
if (!test.Exists())
break;
fNamesInTrash[i] = fRefs[i].name;
fNamesInTrash[i] << ' ' << uniqueNameIndex;
uniqueNameIndex++;
}
// Finally, move the entry into the trash
err = entry.MoveTo(&trashDir, fNamesInTrash[i].String());
if (err != B_OK) { if (err != B_OK) {
moveError = err; moveError = err;
if (errorFiles.Length() > 0) if (errorFiles.Length() > 0)
errorFiles << ' '; errorFiles << ' ';
errorFiles << fRefs[i].name; errorFiles << fItems[i]->Name();
} else } else
errorOnAllFiles = false; errorOnAllFiles = false;
} }
@@ -173,61 +126,21 @@ RemovePLItemsCommand::Undo()
{ {
BAutolock _(fPlaylist); BAutolock _(fPlaylist);
status_t ret = B_OK; fItemsRemoved = false;
if (fMoveFilesToTrash) { if (fMoveFilesToTrash) {
char trashPath[B_PATH_NAME_LENGTH];
for (int32 i = 0; i < fCount; i++) { for (int32 i = 0; i < fCount; i++) {
status_t err = find_directory(B_TRASH_DIRECTORY, fRefs[i].device, fItems[i]->RestoreFromTrash();
false /*create it*/, trashPath, B_PATH_NAME_LENGTH);
if (err != B_OK) {
fprintf(stderr, "failed to find Trash: %s\n", strerror(err));
continue;
}
// construct the entry to the file in the trash
// TODO: BEntry(const BDirectory* directory, const char* path) is broken!
// BEntry entry(trashPath, fNamesInTrash[i].String());
BPath path(trashPath, fNamesInTrash[i].String());
BEntry entry(path.Path());
err = entry.InitCheck();
if (err != B_OK) {
fprintf(stderr, "failed to init BEntry for %s: %s\n",
fNamesInTrash[i].String(), strerror(err));
continue;
}
//entry.GetPath(&path);
//printf("moving '%s'\n", path.Path());
// construct the folder of the original entry_ref
node_ref nodeRef;
nodeRef.device = fRefs[i].device;
nodeRef.node = fRefs[i].directory;
BDirectory originalDir(&nodeRef);
if (err != B_OK) {
fprintf(stderr, "failed to init original BDirectory for "
"%s: %s\n", fRefs[i].name, strerror(err));
continue;
}
//path.SetTo(&originalDir, fRefs[i].name);
//printf("as '%s'\n", path.Path());
// Finally, move the entry back into the original folder
err = entry.MoveTo(&originalDir, fRefs[i].name);
if (err != B_OK)
ret = err;
} }
} }
// remember currently playling ref in case we move it // remember currently playling item in case we move it
entry_ref currentRef; PlaylistItem* current = fPlaylist->ItemAt(fPlaylist->CurrentItemIndex());
bool adjustCurrentRef = fPlaylist->GetRefAt(fPlaylist->CurrentRefIndex(),
&currentRef) == B_OK;
// add refs to playlist at remembered indices // add items to playlist at remembered indices
status_t ret = B_OK;
for (int32 i = 0; i < fCount; i++) { for (int32 i = 0; i < fCount; i++) {
if (!fPlaylist->AddRef(fRefs[i], fIndices[i])) { if (!fPlaylist->AddItem(fItems[i], fIndices[i])) {
ret = B_NO_MEMORY; ret = B_NO_MEMORY;
break; break;
} }
@@ -236,8 +149,8 @@ BEntry entry(path.Path());
return ret; return ret;
// take care about currently played ref // take care about currently played ref
if (adjustCurrentRef) if (current != NULL)
fPlaylist->SetCurrentRefIndex(fPlaylist->IndexOf(currentRef)); fPlaylist->SetCurrentItemIndex(fPlaylist->IndexOf(current));
return B_OK; return B_OK;
} }
@@ -1,21 +1,15 @@
/* /*
* Copyright 2007-2009, Haiku. All rights reserved. * Copyright © 2007-2009 Stephan Aßmus <superstippi@gmx.de>
* Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT license.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
*/ */
#ifndef REMOVE_PL_ITEMS_COMMAND_H #ifndef REMOVE_PL_ITEMS_COMMAND_H
#define REMOVE_PL_ITEMS_COMMAND_H #define REMOVE_PL_ITEMS_COMMAND_H
#include "Command.h" #include "PLItemsCommand.h"
struct entry_ref; class RemovePLItemsCommand : public PLItemsCommand {
class Playlist; public:
class RemovePLItemsCommand : public Command {
public:
RemovePLItemsCommand( RemovePLItemsCommand(
Playlist* playlist, Playlist* playlist,
const int32* indices, const int32* indices,
@@ -30,14 +24,14 @@ class RemovePLItemsCommand : public Command {
virtual void GetName(BString& name); virtual void GetName(BString& name);
private: private:
Playlist* fPlaylist; Playlist* fPlaylist;
entry_ref* fRefs; PlaylistItem** fItems;
BString* fNamesInTrash;
int32* fIndices; int32* fIndices;
int32 fCount; int32 fCount;
bool fMoveFilesToTrash; bool fMoveFilesToTrash;
bool fMoveErrorShown; bool fMoveErrorShown;
bool fItemsRemoved;
}; };
#endif // REMOVE_PL_ITEMS_COMMAND_H #endif // REMOVE_PL_ITEMS_COMMAND_H
@@ -17,7 +17,7 @@ using namespace std;
//#define TRACE_AUDIO_SUPPLIER //#define TRACE_AUDIO_SUPPLIER
#ifdef TRACE_AUDIO_SUPPLIER #ifdef TRACE_AUDIO_SUPPLIER
# define TRACE(x...) printf("MediaTrackAudioSupplier::"); printf(x) # define TRACE(x...) printf("MediaTrackAudioSupplier::" x)
#else #else
# define TRACE(x...) # define TRACE(x...)
#endif #endif
@@ -123,6 +123,8 @@ MediaTrackAudioSupplier::Read(void* buffer, int64 pos, int64 frames)
frames); frames);
TRACE(" this: %p, fOutOffset: %lld\n", this, fOutOffset); TRACE(" this: %p, fOutOffset: %lld\n", this, fOutOffset);
//printf("MediaTrackAudioSupplier::Read(%p, %lld, %lld)\n", buffer, pos, frames);
status_t error = InitCheck(); status_t error = InitCheck();
if (error != B_OK) { if (error != B_OK) {
TRACE("Read() done\n"); TRACE("Read() done\n");
@@ -141,6 +143,58 @@ MediaTrackAudioSupplier::Read(void* buffer, int64 pos, int64 frames)
TRACE(" after eliminating the frames after the track end: %p, %lld, %lld\n", TRACE(" after eliminating the frames after the track end: %p, %lld, %lld\n",
buffer, pos, frames); buffer, pos, frames);
#if 0
const media_format& format = Format();
int64 size = format.u.raw_audio.buffer_size;
uint32 bytesPerFrame = format.u.raw_audio.channel_count
* (format.u.raw_audio.format
& media_raw_audio_format::B_AUDIO_SIZE_MASK);
uint32 framesPerBuffer = size / bytesPerFrame;
if (fMediaTrack->CurrentFrame() != pos) {
printf(" needing to seek: %lld (%lld)\n", pos,
fMediaTrack->CurrentFrame());
int64 keyFrame = pos;
error = fMediaTrack->FindKeyFrameForFrame(&keyFrame,
B_MEDIA_SEEK_CLOSEST_BACKWARD);
if (error == B_OK) {
error = fMediaTrack->SeekToFrame(&keyFrame,
B_MEDIA_SEEK_CLOSEST_BACKWARD);
}
if (error != B_OK) {
printf(" error seeking to position: %lld (%lld)\n", pos,
fMediaTrack->CurrentFrame());
return error;
}
if (keyFrame < pos) {
printf(" need to skip %lld frames\n", pos - keyFrame);
uint8 dummyBuffer[size];
while (pos - keyFrame >= framesPerBuffer) {
printf(" skipped %lu frames (full buffer)\n", framesPerBuffer);
int64 sizeToRead = size;
fMediaTrack->ReadFrames(dummyBuffer, &sizeToRead);
keyFrame += framesPerBuffer;
}
int64 restSize = pos - keyFrame;
if (restSize > 0) {
printf(" skipped %lu frames (rest)\n", framesPerBuffer);
fMediaTrack->ReadFrames(dummyBuffer, &restSize);
}
}
}
while (frames > 0) {
printf(" reading %lu frames (full buffer)\n", framesPerBuffer);
int64 sizeToRead = min_c(size, frames * bytesPerFrame);
fMediaTrack->ReadFrames(buffer, &sizeToRead);
buffer = (uint8*)buffer + sizeToRead;
frames -= framesPerBuffer;
}
printf(" done\n\n");
#else
// read the cached frames // read the cached frames
bigtime_t time = system_time(); bigtime_t time = system_time();
if (frames > 0) if (frames > 0)
@@ -152,6 +206,7 @@ MediaTrackAudioSupplier::Read(void* buffer, int64 pos, int64 frames)
if (frames > 0) if (frames > 0)
_ReadUncachedFrames(buffer, pos, frames, time); _ReadUncachedFrames(buffer, pos, frames, time);
#endif
TRACE("Read() done\n"); TRACE("Read() done\n");
return B_OK; return B_OK;
@@ -203,6 +258,8 @@ MediaTrackAudioSupplier::_InitFromTrack()
TRACE("MediaTrackAudioSupplier: keyframes: %d, frame count: %lld\n", TRACE("MediaTrackAudioSupplier: keyframes: %d, frame count: %lld\n",
fHasKeyFrames, fCountFrames); fHasKeyFrames, fCountFrames);
printf("MediaTrackAudioSupplier: keyframes: %d, frame count: %lld\n",
fHasKeyFrames, fCountFrames);
} else } else
fMediaTrack = NULL; fMediaTrack = NULL;
} }
@@ -416,19 +473,6 @@ MediaTrackAudioSupplier::_ReadBuffer(Buffer* buffer, int64 position,
return error; return error;
} }
// _ReadCachedFrames
//
// Tries to read as much as possible data from the cache. The supplied
// buffer pointer as well as position and number of frames are adjusted
// accordingly. The used cache buffers are stamped with the current
// system time.
void
MediaTrackAudioSupplier::_ReadCachedFrames(void*& dest, int64& pos,
int64& frames)
{
_ReadCachedFrames(dest, pos, frames, system_time());
}
// _ReadCachedFrames // _ReadCachedFrames
// //
// Tries to read as much as possible data from the cache. The supplied // Tries to read as much as possible data from the cache. The supplied
@@ -454,8 +498,8 @@ MediaTrackAudioSupplier::_ReadCachedFrames(void*& dest, int64& pos,
pos += size; pos += size;
frames -= size; frames -= size;
dest = SkipFrames(dest, size); dest = SkipFrames(dest, size);
buffer->time_stamp = time;
} }
buffer->time_stamp = time;
} }
// Step backward through the list of cache buffers and try to read as // Step backward through the list of cache buffers and try to read as
// much data from the end as possible. // much data from the end as possible.
@@ -469,23 +513,11 @@ MediaTrackAudioSupplier::_ReadCachedFrames(void*& dest, int64& pos,
_CopyFrames(buffer->data, buffer->offset, dest, pos, _CopyFrames(buffer->data, buffer->offset, dest, pos,
pos + frames - size, size); pos + frames - size, size);
frames -= size; frames -= size;
buffer->time_stamp = time;
} }
} }
} }
// _ReadUncachedFrames
//
// Reads /frames/ frames from /position/ into /buffer/. The frames are not
// read from the cache, but read frames are cached, if possible.
// New cache buffers are stamped with the system time.
// If an error occurs, the untouched part of the buffer is set to 0.
status_t
MediaTrackAudioSupplier::_ReadUncachedFrames(void* buffer, int64 position,
int64 frames)
{
return _ReadUncachedFrames(buffer, position, frames, system_time());
}
// _ReadUncachedFrames // _ReadUncachedFrames
// //
// Reads /frames/ frames from /position/ into /buffer/. The frames are not // Reads /frames/ frames from /position/ into /buffer/. The frames are not
@@ -521,8 +553,10 @@ MediaTrackAudioSupplier::_ReadUncachedFrames(void* buffer, int64 position,
currentPos += cacheBuffer->size; currentPos += cacheBuffer->size;
} }
} }
#if 1
// Ensure that all frames up to the next key frame are cached. // Ensure that all frames up to the next key frame are cached.
// This avoids, that each read // This avoids, that each read reaches the BMediaTrack.
if (error == B_OK) { if (error == B_OK) {
int64 nextKeyFrame = currentPos; int64 nextKeyFrame = currentPos;
if (_FindKeyFrameForward(nextKeyFrame) == B_OK) { if (_FindKeyFrameForward(nextKeyFrame) == B_OK) {
@@ -540,6 +574,8 @@ MediaTrackAudioSupplier::_ReadUncachedFrames(void* buffer, int64 position,
} }
} }
} }
#endif
// on error fill up the buffer with silence // on error fill up the buffer with silence
if (error != B_OK && frames > 0) if (error != B_OK && frames > 0)
ReadSilence(buffer, frames); ReadSilence(buffer, frames);
@@ -551,17 +587,17 @@ status_t
MediaTrackAudioSupplier::_FindKeyFrameForward(int64& position) MediaTrackAudioSupplier::_FindKeyFrameForward(int64& position)
{ {
status_t error = B_OK; status_t error = B_OK;
// NOTE: the keyframe version confuses the Frauenhofer MP3 decoder, #ifdef __HAIKU__
// it works fine with the non-keyframe version, so let's hope this if (fHasKeyFrames) {
// is the case for all other keyframe based BeOS codecs... error = fMediaTrack->FindKeyFrameForFrame(
// if (fHasKeyFrames) { &position, B_MEDIA_SEEK_CLOSEST_FORWARD);
// error = fMediaTrack->FindKeyFrameForFrame( } else
// &position, B_MEDIA_SEEK_CLOSEST_FORWARD); #endif
// } else { {
int64 framesPerBuffer = _FramesPerBuffer(); int64 framesPerBuffer = _FramesPerBuffer();
position += framesPerBuffer - 1; position += framesPerBuffer - 1;
position = position % framesPerBuffer; position = position % framesPerBuffer;
// } }
return error; return error;
} }
@@ -578,6 +614,7 @@ MediaTrackAudioSupplier::_FindKeyFrameBackward(int64& position)
return error; return error;
} }
#if 0
// _SeekToKeyFrameForward // _SeekToKeyFrameForward
status_t status_t
MediaTrackAudioSupplier::_SeekToKeyFrameForward(int64& position) MediaTrackAudioSupplier::_SeekToKeyFrameForward(int64& position)
@@ -601,6 +638,7 @@ MediaTrackAudioSupplier::_SeekToKeyFrameForward(int64& position)
} }
return error; return error;
} }
#endif
// _SeekToKeyFrameBackward // _SeekToKeyFrameBackward
status_t status_t
@@ -614,16 +652,16 @@ MediaTrackAudioSupplier::_SeekToKeyFrameBackward(int64& position)
int64 oldPosition = position; int64 oldPosition = position;
error = fMediaTrack->FindKeyFrameForFrame(&position, error = fMediaTrack->FindKeyFrameForFrame(&position,
B_MEDIA_SEEK_CLOSEST_BACKWARD); B_MEDIA_SEEK_CLOSEST_BACKWARD);
if (error >= B_OK) if (error == B_OK)
error = fMediaTrack->SeekToFrame(&position, 0); error = fMediaTrack->SeekToFrame(&position, 0);
if (error < B_OK) { if (error != B_OK) {
position = fMediaTrack->CurrentFrame(); position = fMediaTrack->CurrentFrame();
if (fReportSeekError) { // if (fReportSeekError) {
printf(" seek to key frame backward: %lld -> %lld (%lld) " printf(" seek to key frame backward: %lld -> %lld (%lld) "
"- %s\n", oldPosition, position, "- %s\n", oldPosition, position,
fMediaTrack->CurrentFrame(), strerror(error)); fMediaTrack->CurrentFrame(), strerror(error));
fReportSeekError = false; fReportSeekError = false;
} // }
} else { } else {
fReportSeekError = true; fReportSeekError = true;
} }
@@ -62,21 +62,18 @@ class MediaTrackAudioSupplier : public AudioTrackSupplier {
status_t _ReadBuffer(Buffer* buffer, int64 position, status_t _ReadBuffer(Buffer* buffer, int64 position,
bigtime_t time); bigtime_t time);
void _ReadCachedFrames(void*& buffer,
int64& position, int64& frames);
void _ReadCachedFrames(void*& buffer, void _ReadCachedFrames(void*& buffer,
int64& position, int64& frames, int64& position, int64& frames,
bigtime_t time); bigtime_t time);
status_t _ReadUncachedFrames(void* buffer,
int64 position, int64 frames);
status_t _ReadUncachedFrames(void* buffer, status_t _ReadUncachedFrames(void* buffer,
int64 position, int64 frames, int64 position, int64 frames,
bigtime_t time); bigtime_t time);
status_t _FindKeyFrameForward(int64& position); status_t _FindKeyFrameForward(int64& position);
status_t _FindKeyFrameBackward(int64& position); status_t _FindKeyFrameBackward(int64& position);
status_t _SeekToKeyFrameForward(int64& position); // NOTE: unused
// status_t _SeekToKeyFrameForward(int64& position);
status_t _SeekToKeyFrameBackward(int64& position); status_t _SeekToKeyFrameBackward(int64& position);
private: private: