* 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

View File

@ -51,10 +51,10 @@
using std::nothrow;
void
void
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));
fflush(NULL);
exit(1);
@ -91,7 +91,7 @@ Controller::Controller()
// but use only if there are multiple players running at all!
fMuted(false),
fRef(),
fItem(NULL),
fMediaFile(NULL),
fVideoSupplier(new ProxyVideoSupplier()),
@ -185,11 +185,11 @@ Controller::CreateAudioSupplier()
status_t
Controller::SetTo(const entry_ref &ref)
Controller::SetTo(const PlaylistItemRef& item)
{
BAutolock _(this);
if (fRef == ref) {
if (fItem == item) {
if (InitCheck() == B_OK) {
if (fAutoplay) {
SetPosition(0.0);
@ -199,14 +199,14 @@ Controller::SetTo(const entry_ref &ref)
return B_OK;
}
fRef = ref;
fItem = item;
fAudioSupplier->SetSupplier(NULL, fVideoFrameRate);
fVideoSupplier->SetSupplier(NULL);
fAudioTrackList.MakeEmpty();
fVideoTrackList.MakeEmpty();
ObjectDeleter<BMediaFile> oldMediaFileDeleter(fMediaFile);
// BMediaFile destructor will call ReleaseAllTracks()
fMediaFile = NULL;
@ -224,25 +224,26 @@ Controller::SetTo(const entry_ref &ref)
fDuration = 0;
fVideoFrameRate = 25.0;
status_t err;
BMediaFile* mf = new BMediaFile(&ref);
if (fItem.Get() == NULL)
return B_BAD_VALUE;
BMediaFile* mf = fItem->CreateMediaFile();
ObjectDeleter<BMediaFile> mediaFileDeleter(mf);
err = mf->InitCheck();
status_t err = mf->InitCheck();
if (err != B_OK) {
printf("Controller::SetTo: initcheck failed\n");
_NotifyFileChanged();
return err;
}
int trackcount = mf->CountTracks();
if (trackcount <= 0) {
printf("Controller::SetTo: trackcount %d\n", trackcount);
_NotifyFileChanged();
return B_MEDIA_NO_HANDLER;
}
for (int i = 0; i < trackcount; i++) {
BMediaTrack* t = mf->TrackAt(i);
media_format f;
@ -253,13 +254,13 @@ Controller::SetTo(const entry_ref &ref)
mf->ReleaseTrack(t);
continue;
}
if (t->Duration() <= 0) {
printf("Controller::SetTo: track index %d has no duration\n",i);
mf->ReleaseTrack(t);
continue;
}
if (f.IsAudio()) {
if (!fAudioTrackList.AddItem(t))
return B_NO_MEMORY;
@ -395,7 +396,7 @@ Controller::VideoTrackCount()
status_t
Controller::SelectAudioTrack(int n)
{
{
BAutolock _(this);
BMediaTrack* track = (BMediaTrack *)fAudioTrackList.ItemAt(n);
@ -503,7 +504,7 @@ Controller::Play()
//printf("Controller::Play\n");
BAutolock _(this);
StartPlaying();
fAutoplay = true;
}
@ -602,7 +603,7 @@ Controller::VolumeDown()
void
Controller::ToggleMute()
{
{
if (!Lock())
return;
@ -624,7 +625,7 @@ Controller::Volume()
{
BAutolock _(this);
return fVolume;
return fVolume;
}
@ -679,14 +680,9 @@ status_t
Controller::GetLocation(BString* location)
{
// you need to hold the data lock
if (!fMediaFile)
if (fItem.Get() == NULL)
return B_NO_INIT;
BPath path(&fRef);
status_t ret = path.InitCheck();
if (ret < B_OK)
return ret;
*location = "";
*location << "file://" << path.Path();
*location = fItem->LocationURI();
return B_OK;
}
@ -695,9 +691,9 @@ status_t
Controller::GetName(BString* name)
{
// you need to hold the data lock
if (!fMediaFile)
if (fItem.Get() == NULL)
return B_NO_INIT;
*name = fRef.name;
*name = fItem->Name();
return B_OK;
}

View File

@ -31,11 +31,13 @@
#include "ListenerAdapter.h"
#include "NodeManager.h"
#include "PlaylistItem.h"
class AudioTrackSupplier;
class BBitmap;
class BMediaFile;
class BMediaTrack;
class PlaylistItem;
class ProxyAudioSupplier;
class ProxyVideoSupplier;
class SoundOutput;
@ -78,16 +80,16 @@ public:
virtual AudioSupplier* CreateAudioSupplier();
// Controller
status_t SetTo(const entry_ref &ref);
entry_ref Ref() const
{ return fRef; }
status_t SetTo(const PlaylistItemRef& item);
const PlaylistItem* Item() const
{ return fItem.Get(); }
void PlayerActivated(bool active);
void GetSize(int *width, int *height);
int AudioTrackCount();
int VideoTrackCount();
status_t SelectAudioTrack(int n);
int CurrentAudioTrack();
status_t SelectVideoTrack(int n);
@ -123,7 +125,7 @@ public:
// video view
void SetVideoView(VideoView *view);
bool IsOverlayActive();
// notification support
@ -148,7 +150,7 @@ private:
void _NotifyVolumeChanged(float volume) const;
void _NotifyMutedChanged(bool muted) const;
// overridden from PlaybackManager so that we
// overridden from PlaybackManager so that we
// can use our own Listener mechanism
virtual void NotifyPlayModeChanged(int32 mode) const;
virtual void NotifyLoopModeChanged(int32 mode) const;
@ -167,7 +169,7 @@ private:
float fActiveVolume;
bool fMuted;
entry_ref fRef;
PlaylistItemRef fItem;
BMediaFile* fMediaFile;
ProxyVideoSupplier* fVideoSupplier;
@ -194,7 +196,7 @@ private:
bool fLoopMovies;
bool fLoopSounds;
uint32 fBackgroundMovieVolumeMode;
BList fListeners;
};

View File

@ -63,18 +63,18 @@ ControllerView::Draw(BRect updateRect)
void
ControllerView::MessageReceived(BMessage *msg)
ControllerView::MessageReceived(BMessage* message)
{
switch (msg->what) {
case MSG_PLAYLIST_REF_ADDED:
case MSG_PLAYLIST_REF_REMOVED:
case MSG_PLAYLIST_REFS_SORTED:
case MSG_PLAYLIST_CURRENT_REF_CHANGED:
switch (message->what) {
case MSG_PLAYLIST_ITEM_ADDED:
case MSG_PLAYLIST_ITEM_REMOVED:
case MSG_PLAYLIST_ITEMS_SORTED:
case MSG_PLAYLIST_CURRENT_ITEM_CHANGED:
_CheckSkippable();
break;
default:
TransportControlGroup::MessageReceived(msg);
TransportControlGroup::MessageReceived(message);
}
}
@ -123,7 +123,7 @@ void
ControllerView::SkipBackward()
{
BAutolock _(fPlaylist);
fPlaylist->SetCurrentRefIndex(fPlaylist->CurrentRefIndex() - 1);
fPlaylist->SetCurrentItemIndex(fPlaylist->CurrentItemIndex() - 1);
}
@ -131,7 +131,7 @@ void
ControllerView::SkipForward()
{
BAutolock _(fPlaylist);
fPlaylist->SetCurrentRefIndex(fPlaylist->CurrentRefIndex() + 1);
fPlaylist->SetCurrentItemIndex(fPlaylist->CurrentItemIndex() + 1);
}

View File

@ -34,6 +34,7 @@
#include "Controller.h"
#include "ControllerObserver.h"
#include "PlaylistItem.h"
#define NAME "File Info"
@ -55,7 +56,7 @@ public:
virtual ~InfoView();
virtual void Draw(BRect updateRect);
status_t SetIcon(const entry_ref& ref);
status_t SetIcon(const PlaylistItem* item);
status_t SetIcon(const char* mimeType);
void SetGenericIcon();
@ -71,7 +72,7 @@ InfoView::InfoView(BRect frame, const char *name, float divider)
fIconBitmap(NULL)
{
BRect rect(0, 0, B_LARGE_ICON - 1, B_LARGE_ICON - 1);
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
fIconBitmap = new BBitmap(rect, B_RGBA32);
#else
@ -106,11 +107,9 @@ InfoView::Draw(BRect updateRect)
status_t
InfoView::SetIcon(const entry_ref& ref)
InfoView::SetIcon(const PlaylistItem* item)
{
BNode node(&ref);
BNodeInfo info(&node);
return info.GetTrackerIcon(fIconBitmap, B_LARGE_ICON);
return item->GetIcon(fIconBitmap, B_LARGE_ICON);
}
@ -180,14 +179,14 @@ InfoWin::InfoWin(BPoint leftTop, Controller* controller)
rect.right - 10,
20 + fh.ascent + 5),
"filename", "");
AddChild(fFilenameView);
AddChild(fFilenameView);
fFilenameView->SetFont(&bigFont);
fFilenameView->SetViewColor(fInfoView->ViewColor());
fFilenameView->SetLowColor(fInfoView->ViewColor());
#ifdef B_BEOS_VERSION_DANO /* maybe we should support that as well ? */
fFilenameView->SetTruncation(B_TRUNCATE_END);
#endif
rect.top = BASE_HEIGHT;
BRect lr(rect);
@ -403,9 +402,9 @@ printf("InfoWin::Update(0x%08lx)\n", which);
bigtime_t v;
//s << d << "µs; ";
d /= 1000;
v = d / (3600 * 1000);
d = d % (3600 * 1000);
bool hours = v > 0;
@ -423,13 +422,13 @@ printf("InfoWin::Update(0x%08lx)\n", which);
s << "\n";
fContentsView->Insert(s.String());
// TODO: demux/video/audio/... perfs (Kb/s)
fLabelsView->Insert("Display Mode\n");
if (fController->IsOverlayActive())
fContentsView->Insert("Overlay\n");
else
fContentsView->Insert("DrawBitmap\n");
fLabelsView->Insert("\n");
fContentsView->Insert("\n");
}
@ -441,8 +440,8 @@ printf("InfoWin::Update(0x%08lx)\n", which);
if (which & INFO_FILE) {
bool iconSet = false;
if (fController->HasFile()) {
entry_ref ref = fController->Ref();
iconSet = fInfoView->SetIcon(ref) == B_OK;
const PlaylistItem* item = fController->Item();
iconSet = fInfoView->SetIcon(item) == B_OK;
media_file_format fileFormat;
BString s;
if (fController->GetFileFormatInfo(&fileFormat) == B_OK) {
@ -470,7 +469,7 @@ printf("InfoWin::Update(0x%08lx)\n", which);
}
if ((which & INFO_COPYRIGHT) && fController->HasFile()) {
BString s;
if (fController->GetCopyright(&s) == B_OK && s.Length() > 0) {
fLabelsView->Insert("Copyright\n\n");
@ -480,6 +479,6 @@ printf("InfoWin::Update(0x%08lx)\n", which);
}
fController->Unlock();
ResizeToPreferred();
}

View File

@ -55,7 +55,7 @@ Application MediaPlayer :
# playlist
CopyPLItemsCommand.cpp
EntryRefPlaylistItem.cpp
FilePlaylistItem.cpp
ImportPLItemsCommand.cpp
ListViews.cpp
MovePLItemsCommand.cpp
@ -64,6 +64,7 @@ Application MediaPlayer :
PlaylistListView.cpp
PlaylistObserver.cpp
PlaylistWindow.cpp
PLItemsCommand.cpp
RandomizePLItemsCommand.cpp
RemovePLItemsCommand.cpp

View File

@ -2,7 +2,7 @@
* MainWin.cpp - Media Player for the Haiku Operating System
*
* 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)
*
* This program is free software; you can redistribute it and/or
@ -20,6 +20,7 @@
* USA.
*
*/
#include "MainWin.h"
#include <math.h>
@ -45,6 +46,7 @@
#include "ControllerObserver.h"
#include "MainApp.h"
#include "PeakView.h"
#include "PlaylistItem.h"
#include "PlaylistObserver.h"
#include "PlaylistWindow.h"
#include "Settings.h"
@ -379,33 +381,35 @@ MainWin::MessageReceived(BMessage *msg)
break;
// PlaylistObserver messages
case MSG_PLAYLIST_REF_ADDED: {
entry_ref ref;
case MSG_PLAYLIST_ITEM_ADDED:
{
PlaylistItem* item;
int32 index;
if (msg->FindRef("refs", &ref) == B_OK
if (msg->FindPointer("item", (void**)&item) == B_OK
&& msg->FindInt32("index", &index) == B_OK) {
_AddPlaylistItem(ref, index);
_AddPlaylistItem(item, index);
}
break;
}
case MSG_PLAYLIST_REF_REMOVED: {
case MSG_PLAYLIST_ITEM_REMOVED:
{
int32 index;
if (msg->FindInt32("index", &index) == B_OK) {
if (msg->FindInt32("index", &index) == B_OK)
_RemovePlaylistItem(index);
}
break;
}
case MSG_PLAYLIST_CURRENT_REF_CHANGED: {
case MSG_PLAYLIST_CURRENT_ITEM_CHANGED:
{
BAutolock _(fPlaylist);
int32 index;
if (msg->FindInt32("index", &index) < B_OK
|| index != fPlaylist->CurrentRefIndex())
|| index != fPlaylist->CurrentItemIndex())
break;
entry_ref ref;
if (fPlaylist->GetRefAt(index, &ref) == B_OK) {
printf("open ref: %s\n", ref.name);
OpenFile(ref);
PlaylistItemRef item(fPlaylist->ItemAt(index));
if (item.Get() != NULL) {
printf("open playlist item: %s\n", item->Name().String());
OpenPlaylistItem(item);
_MarkPlaylistItem(index);
}
break;
@ -416,8 +420,8 @@ MainWin::MessageReceived(BMessage *msg)
{
BAutolock _(fPlaylist);
bool hadNext = fPlaylist->SetCurrentRefIndex(
fPlaylist->CurrentRefIndex() + 1);
bool hadNext = fPlaylist->SetCurrentItemIndex(
fPlaylist->CurrentItemIndex() + 1);
if (!hadNext) {
if (fHasVideo) {
if (fCloseWhenDonePlayingMovie)
@ -434,7 +438,8 @@ MainWin::MessageReceived(BMessage *msg)
// notification
// _UpdatePlaylistMenu();
break;
case MSG_CONTROLLER_VIDEO_TRACK_CHANGED: {
case MSG_CONTROLLER_VIDEO_TRACK_CHANGED:
{
int32 index;
if (msg->FindInt32("index", &index) == B_OK) {
BMenuItem* item = fVideoTrackMenu->ItemAt(index);
@ -443,7 +448,8 @@ MainWin::MessageReceived(BMessage *msg)
}
break;
}
case MSG_CONTROLLER_AUDIO_TRACK_CHANGED: {
case MSG_CONTROLLER_AUDIO_TRACK_CHANGED:
{
int32 index;
if (msg->FindInt32("index", &index) == B_OK) {
BMenuItem* item = fAudioTrackMenu->ItemAt(index);
@ -452,25 +458,29 @@ MainWin::MessageReceived(BMessage *msg)
}
break;
}
case MSG_CONTROLLER_PLAYBACK_STATE_CHANGED: {
case MSG_CONTROLLER_PLAYBACK_STATE_CHANGED:
{
uint32 state;
if (msg->FindInt32("state", (int32*)&state) == B_OK)
fControls->SetPlaybackState(state);
break;
}
case MSG_CONTROLLER_POSITION_CHANGED: {
case MSG_CONTROLLER_POSITION_CHANGED:
{
float position;
if (msg->FindFloat("position", &position) == B_OK)
fControls->SetPosition(position);
break;
}
case MSG_CONTROLLER_VOLUME_CHANGED: {
case MSG_CONTROLLER_VOLUME_CHANGED:
{
float volume;
if (msg->FindFloat("volume", &volume) == B_OK)
fControls->SetVolume(volume);
break;
}
case MSG_CONTROLLER_MUTED_CHANGED: {
case MSG_CONTROLLER_MUTED_CHANGED:
{
bool muted;
if (msg->FindBool("muted", &muted) == B_OK)
fControls->SetMuted(muted);
@ -481,7 +491,8 @@ MainWin::MessageReceived(BMessage *msg)
case M_FILE_NEWPLAYER:
gMainApp->NewWindow();
break;
case M_FILE_OPEN: {
case M_FILE_OPEN:
{
BMessenger target(this);
BMessage result(B_REFS_RECEIVED);
BMessage appMessage(M_SHOW_OPEN_PANEL);
@ -499,6 +510,7 @@ MainWin::MessageReceived(BMessage *msg)
ShowPlaylistWindow();
break;
case B_ABOUT_REQUESTED:
{
BAlert *alert;
alert = new BAlert("about", NAME"\n\n Written by Marcus Overhagen "
", Stephan Aßmus and Frederik Modéen", "Thanks");
@ -510,6 +522,7 @@ MainWin::MessageReceived(BMessage *msg)
alert->Go(NULL); // Asynchronous mode
}
break;
}
case M_FILE_CLOSE:
PostMessage(B_QUIT_REQUESTED);
break;
@ -664,12 +677,13 @@ MainWin::MessageReceived(BMessage *msg)
break;
}
*/
case M_SET_PLAYLIST_POSITION: {
case M_SET_PLAYLIST_POSITION:
{
BAutolock _(fPlaylist);
int32 index;
if (msg->FindInt32("index", &index) == B_OK)
fPlaylist->SetCurrentRefIndex(index);
fPlaylist->SetCurrentItemIndex(index);
break;
}
@ -731,18 +745,18 @@ MainWin::QuitRequested()
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) {
BAutolock _(fPlaylist);
if (fPlaylist->CountItems() == 1) {
// display error if this is the only file we're supposed to play
BString message;
message << "The file '";
message << ref.name;
message << item->Name();
message << "' could not be opened.\n\n";
if (err == B_MEDIA_NO_HANDLER) {
@ -757,7 +771,7 @@ MainWin::OpenFile(const entry_ref &ref)
(new BAlert("error", message.String(), "OK"))->Go();
} else {
// just go to the next file and don't bother user
fPlaylist->SetCurrentRefIndex(fPlaylist->CurrentRefIndex() + 1);
fPlaylist->SetCurrentItemIndex(fPlaylist->CurrentItemIndex() + 1);
}
fHasFile = false;
fHasVideo = false;
@ -767,7 +781,7 @@ MainWin::OpenFile(const entry_ref &ref)
fHasFile = true;
fHasVideo = fController->VideoTrackCount() != 0;
fHasAudio = fController->AudioTrackCount() != 0;
SetTitle(ref.name);
SetTitle(item->Name().String());
}
_SetupWindow();
}
@ -1398,7 +1412,7 @@ MainWin::_KeyDown(BMessage *msg)
BAutolock _(fPlaylist);
BMessage removeMessage(M_PLAYLIST_REMOVE_AND_PUT_INTO_TRASH);
removeMessage.AddInt32("playlist index",
fPlaylist->CurrentRefIndex());
fPlaylist->CurrentItemIndex());
fPlaylistWindow->PostMessage(&removeMessage);
return B_OK;
}
@ -1592,26 +1606,24 @@ MainWin::_UpdatePlaylistMenu()
int32 count = fPlaylist->CountItems();
for (int32 i = 0; i < count; i++) {
entry_ref ref;
if (fPlaylist->GetRefAt(i, &ref) < B_OK)
continue;
_AddPlaylistItem(ref, i);
PlaylistItem* item = fPlaylist->ItemAtFast(i);
_AddPlaylistItem(item, i);
}
fPlaylistMenu->SetTargetForItems(this);
_MarkPlaylistItem(fPlaylist->CurrentRefIndex());
_MarkPlaylistItem(fPlaylist->CurrentItemIndex());
fPlaylist->Unlock();
}
void
MainWin::_AddPlaylistItem(const entry_ref& ref, int32 index)
MainWin::_AddPlaylistItem(PlaylistItem* item, int32 index)
{
BMessage* message = new BMessage(M_SET_PLAYLIST_POSITION);
message->AddInt32("index", index);
BMenuItem* item = new BMenuItem(ref.name, message);
fPlaylistMenu->AddItem(item, index);
BMenuItem* menuItem = new BMenuItem(item->Name().String(), message);
fPlaylistMenu->AddItem(menuItem, index);
}

View File

@ -2,7 +2,7 @@
* MainWin.h - Media Player for the Haiku Operating System
*
* 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
* modify it under the terms of the GNU General Public License
@ -31,6 +31,7 @@
#include "InfoWin.h"
#include "ListenerAdapter.h"
#include "Playlist.h"
#include "PlaylistItem.h"
#include "VideoView.h"
class ControllerObserver;
@ -51,18 +52,18 @@ public:
virtual void WindowActivated(bool active);
virtual bool QuitRequested();
void OpenFile(const entry_ref& ref);
void OpenPlaylistItem(const PlaylistItemRef& item);
void ShowFileInfo();
void ShowPlaylistWindow();
void ShowSettingsWindow();
void VideoFormatChange(int width, int height,
float widthScale, float heightScale);
private:
void _RefsReceived(BMessage *message);
void _RefsReceived(BMessage* message);
void _SetupWindow();
void _CreateMenu();
void _SetupTrackMenus();
@ -70,7 +71,7 @@ private:
void _ResizeWindow(int percent);
void _ResizeVideoView(int x, int y, int width,
int height);
void _MouseDown(BMessage* message,
BView* originalHandler);
void _MouseMoved(BMessage* message,
@ -78,7 +79,7 @@ private:
void _MouseUp(BMessage* message);
void _ShowContextMenu(const BPoint& screenPoint);
status_t _KeyDown(BMessage* message);
void _ToggleFullscreen();
void _ToggleKeepAspectRatio();
void _ToggleAlwaysOnTop();
@ -86,10 +87,10 @@ private:
void _ToggleNoMenu();
void _ToggleNoControls();
void _ToggleNoBorderNoMenu();
void _UpdateControlsEnabledStatus();
void _UpdatePlaylistMenu();
void _AddPlaylistItem(const entry_ref& ref,
void _AddPlaylistItem(PlaylistItem* item,
int32 index);
void _RemovePlaylistItem(int32 index);
void _MarkPlaylistItem(int32 index);
@ -103,7 +104,7 @@ private:
ControllerView* fControls;
InfoWin* fInfoWin;
PlaylistWindow* fPlaylistWindow;
BMenu* fFileMenu;
BMenu* fAudioMenu;
BMenu* fVideoMenu;
@ -112,11 +113,11 @@ private:
BMenu* fSettingsMenu;
BMenu* fPlaylistMenu;
BMenu* fDebugMenu;
bool fHasFile;
bool fHasVideo;
bool fHasAudio;
Playlist* fPlaylist;
PlaylistObserver* fPlaylistObserver;
Controller* fController;

View File

@ -1,11 +1,7 @@
/*
* Copyright 2007, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
* Copyright © 2007-2009 Stephan Aßmus <superstippi@gmx.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "CopyPLItemsCommand.h"
#include <new>
@ -21,24 +17,31 @@ using std::nothrow;
CopyPLItemsCommand::CopyPLItemsCommand(Playlist* playlist,
const int32* indices, int32 count, int32 toIndex)
: Command()
, fPlaylist(playlist)
, fRefs(count > 0 ? new (nothrow) entry_ref[count] : NULL)
, fToIndex(toIndex)
, fCount(count)
:
PLItemsCommand(),
fPlaylist(playlist),
fItems(count > 0 ? new (nothrow) PlaylistItem*[count] : NULL),
fToIndex(toIndex),
fCount(count),
fItemsCopied(false)
{
if (!indices || !fPlaylist || !fRefs) {
if (!indices || !fPlaylist || !fItems) {
// indicate a bad object state
delete[] fRefs;
fRefs = NULL;
delete[] fItems;
fItems = NULL;
return;
}
memcpy(fItems, 0, sizeof(PlaylistItem*) * fCount);
// init original entries and
for (int32 i = 0; i < fCount; i++) {
if (fPlaylist->GetRefAt(indices[i], &fRefs[i]) < B_OK) {
delete[] fRefs;
fRefs = NULL;
PlaylistItem* item = fPlaylist->ItemAt(indices[i]);
if (item != NULL)
fItems[i] = item->Clone();
if (fItems[i] == NULL) {
// indicate a bad object state
_CleanUp(fItems, fCount, true);
return;
}
}
@ -47,14 +50,14 @@ CopyPLItemsCommand::CopyPLItemsCommand(Playlist* playlist,
CopyPLItemsCommand::~CopyPLItemsCommand()
{
delete[] fRefs;
_CleanUp(fItems, fCount, !fItemsCopied);
}
status_t
CopyPLItemsCommand::InitCheck()
{
if (!fPlaylist || !fRefs)
if (!fPlaylist || !fItems)
return B_NO_INIT;
return B_OK;
}
@ -67,18 +70,17 @@ CopyPLItemsCommand::Perform()
status_t ret = B_OK;
fItemsCopied = true;
// add refs to playlist at the insertion index
int32 index = fToIndex;
for (int32 i = 0; i < fCount; i++) {
if (!fPlaylist->AddRef(fRefs[i], index++)) {
if (!fPlaylist->AddItem(fItems[i], index++)) {
ret = B_NO_MEMORY;
break;
}
}
if (ret < B_OK)
return ret;
return B_OK;
return ret;
}
@ -87,20 +89,19 @@ CopyPLItemsCommand::Undo()
{
BAutolock _(fPlaylist);
// remember currently playling ref in case we copy items over it
entry_ref currentRef;
bool adjustCurrentRef = fPlaylist->GetRefAt(fPlaylist->CurrentRefIndex(),
&currentRef) == B_OK;
fItemsCopied = false;
// remember currently playling item in case we copy items over it
PlaylistItem* current = fPlaylist->ItemAt(fPlaylist->CurrentItemIndex());
// remove refs from playlist
int32 index = fToIndex;
for (int32 i = 0; i < fCount; i++) {
fPlaylist->RemoveRef(index++, false);
fPlaylist->RemoveItem(index++, false);
}
// take care about currently played ref
if (adjustCurrentRef)
fPlaylist->SetCurrentRefIndex(fPlaylist->IndexOf(currentRef));
// take care about currently played item
if (current != NULL)
fPlaylist->SetCurrentItemIndex(fPlaylist->IndexOf(current));
return B_OK;
}

View File

@ -1,28 +1,22 @@
/*
* Copyright 2007, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
* Copyright © 2007-2009 Stephan Aßmus <superstippi@gmx.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef COPY_PL_ITEMS_COMMAND_H
#define COPY_PL_ITEMS_COMMAND_H
#include "Command.h"
#include "PLItemsCommand.h"
class Playlist;
struct entry_ref;
class CopyPLItemsCommand : public Command {
public:
class CopyPLItemsCommand : public PLItemsCommand {
public:
CopyPLItemsCommand(
Playlist* playlist,
const int32* indices,
int32 count,
int32 toIndex);
virtual ~CopyPLItemsCommand();
virtual status_t InitCheck();
virtual status_t Perform();
@ -30,11 +24,12 @@ class CopyPLItemsCommand : public Command {
virtual void GetName(BString& name);
private:
private:
Playlist* fPlaylist;
entry_ref* fRefs;
PlaylistItem** fItems;
int32 fToIndex;
int32 fCount;
bool fItemsCopied;
};
#endif // COPY_PL_ITEMS_COMMAND_H

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -1,9 +1,6 @@
/*
* Copyright 2007, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
* Copyright 2007-2009 Stephan Aßmus <superstippi@gmx.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "ImportPLItemsCommand.h"
@ -15,6 +12,7 @@
#include <Autolock.h>
#include "Playlist.h"
#include "PlaylistItem.h"
using std::nothrow;
@ -22,16 +20,20 @@ using std::nothrow;
ImportPLItemsCommand::ImportPLItemsCommand(Playlist* playlist,
const BMessage* refsMessage, int32 toIndex)
: Command()
, fPlaylist(playlist)
:
PLItemsCommand(),
fPlaylist(playlist),
, fOldRefs(NULL)
, fOldCount(0)
fOldItems(NULL),
fOldCount(0),
, fNewRefs(NULL)
, fNewCount(0)
fNewItems(NULL),
fNewCount(0),
, fToIndex(toIndex)
fToIndex(toIndex),
fPlaylingIndex(0),
fItemsAdded(false)
{
if (!fPlaylist)
return;
@ -47,38 +49,40 @@ ImportPLItemsCommand::ImportPLItemsCommand(Playlist* playlist,
return;
}
fNewRefs = new (nothrow) entry_ref[fNewCount];
if (!fNewRefs)
fNewItems = new (nothrow) PlaylistItem*[fNewCount];
if (!fNewItems)
return;
memset(fNewItems, 0, fNewCount * sizeof(PlaylistItem*));
// init new entries
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
delete[] fNewRefs;
fNewRefs = NULL;
_CleanUp(fNewItems, fNewCount, true);
return;
}
}
fPlaylingIndex = fPlaylist->CurrentItemIndex();
if (fToIndex < 0) {
fOldCount = fPlaylist->CountItems();
if (fOldCount > 0) {
fOldRefs = new (nothrow) entry_ref[fOldCount];
if (!fOldRefs) {
fOldItems = new (nothrow) PlaylistItem*[fOldCount];
if (!fOldItems) {
// indicate bad object init
delete[] fNewRefs;
fNewRefs = NULL;
return;
_CleanUp(fNewItems, fNewCount, true);
}
memset(fOldItems, 0, fOldCount * sizeof(PlaylistItem*));
}
}
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
delete[] fNewRefs;
fNewRefs = NULL;
_CleanUp(fNewItems, fNewCount, true);
return;
}
}
@ -87,15 +91,15 @@ ImportPLItemsCommand::ImportPLItemsCommand(Playlist* playlist,
ImportPLItemsCommand::~ImportPLItemsCommand()
{
delete[] fOldRefs;
delete[] fNewRefs;
_CleanUp(fOldItems, fOldCount, fItemsAdded);
_CleanUp(fNewItems, fNewCount, !fItemsAdded);
}
status_t
ImportPLItemsCommand::InitCheck()
{
if (!fPlaylist || !fNewRefs)
if (!fPlaylist || !fNewItems)
return B_NO_INIT;
return B_OK;
}
@ -106,9 +110,11 @@ ImportPLItemsCommand::Perform()
{
BAutolock _(fPlaylist);
fItemsAdded = true;
int32 index = fToIndex;
if (fToIndex < 0) {
fPlaylist->MakeEmpty();
fPlaylist->MakeEmpty(false);
index = 0;
}
@ -116,13 +122,13 @@ ImportPLItemsCommand::Perform()
// add refs to playlist at the insertion index
for (int32 i = 0; i < fNewCount; i++) {
if (!fPlaylist->AddRef(fNewRefs[i], index++))
if (!fPlaylist->AddItem(fNewItems[i], index++))
return B_NO_MEMORY;
}
if (startPlaying) {
// open first file
fPlaylist->SetCurrentRefIndex(0);
fPlaylist->SetCurrentItemIndex(0);
}
return B_OK;
@ -134,17 +140,22 @@ ImportPLItemsCommand::Undo()
{
BAutolock _(fPlaylist);
fItemsAdded = false;
if (fToIndex < 0) {
// remove new refs from playlist and restore old refs
fPlaylist->MakeEmpty();
// remove new items from playlist and restore old refs
fPlaylist->MakeEmpty(false);
for (int32 i = 0; i < fOldCount; i++) {
if (!fPlaylist->AddRef(fOldRefs[i], i))
if (!fPlaylist->AddItem(fOldItems[i], i))
return B_NO_MEMORY;
}
// Restore previously playing item
if (fPlaylingIndex >= 0)
fPlaylist->SetCurrentItemIndex(fPlaylingIndex);
} else {
// remove refs from playlist
// remove new items from playlist
for (int32 i = 0; i < fNewCount; i++) {
fPlaylist->RemoveRef(fToIndex);
fPlaylist->RemoveItem(fToIndex);
}
}
@ -160,3 +171,4 @@ ImportPLItemsCommand::GetName(BString& name)
else
name << "Import Entry";
}

View File

@ -1,28 +1,23 @@
/*
* Copyright 2007, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
* Copyright 2007-2009 Stephan Aßmus <superstippi@gmx.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef IMPORT_PL_ITEMS_COMMAND_H
#define IMPORT_PL_ITEMS_COMMAND_H
#include "Command.h"
#include "PLItemsCommand.h"
class BMessage;
class Playlist;
struct entry_ref;
class ImportPLItemsCommand : public Command {
public:
class ImportPLItemsCommand : public PLItemsCommand {
public:
ImportPLItemsCommand(
Playlist* playlist,
const BMessage* refsMessage,
int32 toIndex);
virtual ~ImportPLItemsCommand();
virtual status_t InitCheck();
virtual status_t Perform();
@ -30,13 +25,15 @@ class ImportPLItemsCommand : public Command {
virtual void GetName(BString& name);
private:
private:
Playlist* fPlaylist;
entry_ref* fOldRefs;
PlaylistItem** fOldItems;
int32 fOldCount;
entry_ref* fNewRefs;
PlaylistItem** fNewItems;
int32 fNewCount;
int32 fToIndex;
int32 fPlaylingIndex;
bool fItemsAdded;
};
#endif // IMPORT_PL_ITEMS_COMMAND_H

View File

@ -1,9 +1,6 @@
/*
* Copyright 2007, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
* Copyright 2007-2009 Stephan Aßmus <superstippi@gmx.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "MovePLItemsCommand.h"
@ -21,20 +18,22 @@ using std::nothrow;
MovePLItemsCommand::MovePLItemsCommand(Playlist* playlist,
const int32* indices, int32 count, int32 toIndex)
: Command()
, fPlaylist(playlist)
, fRefs(count > 0 ? new (nothrow) entry_ref[count] : NULL)
, fIndices(count > 0 ? new (nothrow) int32[count] : NULL)
, fToIndex(toIndex)
, fCount(count)
:
PLItemsCommand(),
fPlaylist(playlist),
fItems(count > 0 ? new (nothrow) PlaylistItem*[count] : NULL),
fIndices(count > 0 ? new (nothrow) int32[count] : NULL),
fToIndex(toIndex),
fCount(count)
{
if (!indices || !fPlaylist || !fRefs || !fIndices) {
if (!indices || !fPlaylist || !fItems || !fIndices) {
// indicate a bad object state
delete[] fRefs;
fRefs = NULL;
delete[] fItems;
fItems = NULL;
return;
}
memset(fItems, 0, sizeof(PlaylistItem*) * fCount);
memcpy(fIndices, indices, fCount * sizeof(int32));
// init original entry indices and
@ -42,10 +41,11 @@ MovePLItemsCommand::MovePLItemsCommand(Playlist* playlist,
// are removed before that index
int32 itemsBeforeIndex = 0;
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
delete[] fRefs;
fRefs = NULL;
delete[] fItems;
fItems = NULL;
return;
}
if (fIndices[i] < fToIndex)
@ -57,7 +57,7 @@ MovePLItemsCommand::MovePLItemsCommand(Playlist* playlist,
MovePLItemsCommand::~MovePLItemsCommand()
{
delete[] fRefs;
delete[] fItems;
delete[] fIndices;
}
@ -65,7 +65,7 @@ MovePLItemsCommand::~MovePLItemsCommand()
status_t
MovePLItemsCommand::InitCheck()
{
if (!fRefs)
if (!fItems)
return B_NO_INIT;
// analyse the move, don't return B_OK in case
@ -106,21 +106,19 @@ MovePLItemsCommand::Perform()
status_t ret = B_OK;
// remember currently playling ref in case we move it
entry_ref currentRef;
bool adjustCurrentRef = fPlaylist->GetRefAt(fPlaylist->CurrentRefIndex(),
&currentRef) == B_OK;
// remember currently playling item in case we move it
PlaylistItem* current = fPlaylist->ItemAt(fPlaylist->CurrentItemIndex());
// remove refs from playlist
for (int32 i = 0; i < fCount; i++) {
// "- 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
int32 index = fToIndex;
for (int32 i = 0; i < fCount; i++) {
if (!fPlaylist->AddRef(fRefs[i], index++)) {
if (!fPlaylist->AddItem(fItems[i], index++)) {
ret = B_NO_MEMORY;
break;
}
@ -128,9 +126,9 @@ MovePLItemsCommand::Perform()
if (ret < B_OK)
return ret;
// take care about currently played ref
if (adjustCurrentRef)
fPlaylist->SetCurrentRefIndex(fPlaylist->IndexOf(currentRef));
// take care about currently played item
if (current != NULL)
fPlaylist->SetCurrentItemIndex(fPlaylist->IndexOf(current));
return B_OK;
}
@ -143,20 +141,18 @@ MovePLItemsCommand::Undo()
status_t ret = B_OK;
// remember currently playling ref in case we move it
entry_ref currentRef;
bool adjustCurrentRef = fPlaylist->GetRefAt(fPlaylist->CurrentRefIndex(),
&currentRef) == B_OK;
// remember currently playling item in case we move it
PlaylistItem* current = fPlaylist->ItemAt(fPlaylist->CurrentItemIndex());
// remove refs from playlist
int32 index = fToIndex;
for (int32 i = 0; i < fCount; i++) {
fPlaylist->RemoveRef(index++, false);
fPlaylist->RemoveItem(index++, false);
}
// add ref to playlist at remembered indices
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;
break;
}
@ -164,9 +160,9 @@ MovePLItemsCommand::Undo()
if (ret < B_OK)
return ret;
// take care about currently played ref
if (adjustCurrentRef)
fPlaylist->SetCurrentRefIndex(fPlaylist->IndexOf(currentRef));
// take care about currently played item
if (current != NULL)
fPlaylist->SetCurrentItemIndex(fPlaylist->IndexOf(current));
return B_OK;
}

View File

@ -1,20 +1,14 @@
/*
* Copyright 2007, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
* Copyright 2007-2009 Stephan Aßmus <superstippi@gmx.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef MOVE_PL_ITEMS_COMMAND_H
#define MOVE_PL_ITEMS_COMMAND_H
#include "Command.h"
#include "PLItemsCommand.h"
class Playlist;
struct entry_ref;
class MovePLItemsCommand : public Command {
class MovePLItemsCommand : public PLItemsCommand {
public:
MovePLItemsCommand(
Playlist* playlist,
@ -22,7 +16,7 @@ class MovePLItemsCommand : public Command {
int32 count,
int32 toIndex);
virtual ~MovePLItemsCommand();
virtual status_t InitCheck();
virtual status_t Perform();
@ -32,7 +26,7 @@ class MovePLItemsCommand : public Command {
private:
Playlist* fPlaylist;
entry_ref* fRefs;
PlaylistItem** fItems;
int32* fIndices;
int32 fToIndex;
int32 fCount;

View File

@ -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;
}

View File

@ -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

View File

@ -2,8 +2,8 @@
* Playlist.cpp - Media Player for the Haiku Operating System
*
* Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de>
* Copyright (C) 2007 Stephan Aßmus <superstippi@gmx.de>
* Copyright (C) 2008-2009 Fredrik Modéen <[FirstName]@[LastName].se> (MIT ok)
* Copyright (C) 2007-2009 Stephan Aßmus <superstippi@gmx.de> (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
* 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.
*
*/
#include "Playlist.h"
#include <debugger.h>
#include <new>
#include <stdio.h>
#include <AppFileInfo.h>
#include <Application.h>
#include <Autolock.h>
#include <Directory.h>
#include <Entry.h>
#include <File.h>
#include <Message.h>
#include <Mime.h>
#include <NodeInfo.h>
#include <Path.h>
#include <Roster.h>
#include <String.h>
#include "FilePlaylistItem.h"
#include "FileReadWrite.h"
using std::nothrow;
@ -42,19 +48,54 @@ using std::nothrow;
Playlist::Listener::Listener() {}
Playlist::Listener::~Listener() {}
void Playlist::Listener::RefAdded(const entry_ref& ref, int32 index) {}
void Playlist::Listener::RefRemoved(int32 index) {}
void Playlist::Listener::RefsSorted() {}
void Playlist::Listener::CurrentRefChanged(int32 newIndex) {}
void Playlist::Listener::ItemAdded(PlaylistItem* item, int32 index) {}
void Playlist::Listener::ItemRemoved(int32 index) {}
void Playlist::Listener::ItemsSorted() {}
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 -
Playlist::Playlist()
: BLocker("playlist lock")
, fRefs()
, fCurrentIndex(-1)
:
BLocker("playlist lock"),
fItems(),
fCurrentIndex(-1)
{
}
@ -71,7 +112,7 @@ Playlist::~Playlist()
// #pragma mark - archiving
static const char* kPathKey = "path";
static const char* kItemArchiveKey = "item";
status_t
@ -82,15 +123,21 @@ Playlist::Unarchive(const BMessage* archive)
MakeEmpty();
BString path;
for (int32 i = 0; archive->FindString(kPathKey, i, &path) == B_OK; i++) {
BEntry entry(path.String(), false);
// don't follow links, we want to do that when opening files only
entry_ref ref;
if (entry.GetRef(&ref) != B_OK)
BMessage itemArchive;
for (int32 i = 0;
archive->FindMessage(kItemArchiveKey, i, &itemArchive) == B_OK; i++) {
BArchivable* archivable = instantiate_object(&itemArchive);
PlaylistItem* item = dynamic_cast<PlaylistItem*>(archivable);
if (!item) {
delete archivable;
continue;
if (!AddRef(ref))
}
if (!AddItem(item)) {
delete item;
return B_NO_MEMORY;
}
}
return B_OK;
@ -103,13 +150,14 @@ Playlist::Archive(BMessage* into) const
if (into == NULL)
return B_BAD_VALUE;
int32 count = fRefs.CountItems();
int32 count = CountItems();
for (int32 i = 0; i < count; i++) {
const entry_ref* ref = (entry_ref*)fRefs.ItemAtFast(i);
BPath path(ref);
if (path.InitCheck() != B_OK)
continue;
status_t ret = into->AddString(kPathKey, path.Path());
const PlaylistItem* item = ItemAtFast(i);
BMessage itemArchive;
status_t ret = item->Archive(&itemArchive);
if (ret != B_OK)
return ret;
ret = into->AddMessage(kItemArchiveKey, &itemArchive);
if (ret != B_OK)
return ret;
}
@ -145,7 +193,6 @@ Playlist::Unflatten(BDataIO* stream)
if (ret != B_OK)
return ret;
return Unarchive(&archive);
}
@ -177,54 +224,51 @@ Playlist::Flatten(BDataIO* stream) const
void
Playlist::MakeEmpty()
Playlist::MakeEmpty(bool deleteItems)
{
int32 count = fRefs.CountItems();
int32 count = CountItems();
for (int32 i = count - 1; i >= 0; i--) {
entry_ref* ref = (entry_ref*)fRefs.RemoveItem(i);
_NotifyRefRemoved(i);
delete ref;
PlaylistItem* item = RemoveItem(i, false);
_NotifyItemRemoved(i);
if (deleteItems)
item->RemoveReference();
}
SetCurrentRefIndex(-1);
SetCurrentItemIndex(-1);
}
int32
Playlist::CountItems() const
{
return fRefs.CountItems();
return fItems.CountItems();
}
void
Playlist::Sort()
{
fRefs.SortItems(playlist_cmp);
_NotifyRefsSorted();
fItems.SortItems(playlist_item_compare);
_NotifyItemsSorted();
}
bool
Playlist::AddRef(const entry_ref &ref)
Playlist::AddItem(PlaylistItem* item)
{
return AddRef(ref, CountItems());
return AddItem(item, CountItems());
}
bool
Playlist::AddRef(const entry_ref &ref, int32 index)
Playlist::AddItem(PlaylistItem* item, int32 index)
{
entry_ref* copy = new (nothrow) entry_ref(ref);
if (!copy)
if (!fItems.AddItem(item, index))
return false;
if (!fRefs.AddItem(copy, index)) {
delete copy;
return false;
}
_NotifyRefAdded(ref, index);
if (index <= fCurrentIndex)
SetCurrentRefIndex(fCurrentIndex + 1);
SetCurrentItemIndex(fCurrentIndex + 1);
_NotifyItemAdded(item, index);
return true;
}
@ -244,85 +288,68 @@ Playlist::AdoptPlaylist(Playlist& other, int32 index)
return false;
// NOTE: this is not intended to merge two "equal" playlists
// 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
int32 count = other.fRefs.CountItems();
int32 count = other.CountItems();
for (int32 i = index; i < index + count; i++) {
entry_ref* ref = (entry_ref*)fRefs.ItemAtFast(i);
_NotifyRefAdded(*ref, i);
PlaylistItem* item = ItemAtFast(i);
_NotifyItemAdded(item, i);
}
if (index <= fCurrentIndex)
SetCurrentRefIndex(fCurrentIndex + count);
// empty the other list, so that the entry_refs are now ours
other.fRefs.MakeEmpty();
SetCurrentItemIndex(fCurrentIndex + count);
// empty the other list, so that the PlaylistItems are now ours
other.fItems.MakeEmpty();
return true;
}
return false;
}
entry_ref
Playlist::RemoveRef(int32 index, bool careAboutCurrentIndex)
PlaylistItem*
Playlist::RemoveItem(int32 index, bool careAboutCurrentIndex)
{
entry_ref _ref;
entry_ref* ref = (entry_ref*)fRefs.RemoveItem(index);
if (!ref)
return _ref;
_NotifyRefRemoved(index);
_ref = *ref;
delete ref;
PlaylistItem* item = (PlaylistItem*)fItems.RemoveItem(index);
if (!item)
return NULL;
_NotifyItemRemoved(index);
if (careAboutCurrentIndex) {
if (index == fCurrentIndex)
SetCurrentRefIndex(-1);
if (index == fCurrentIndex && index >= CountItems())
SetCurrentItemIndex(CountItems() - 1);
else if (index < fCurrentIndex)
SetCurrentRefIndex(fCurrentIndex - 1);
SetCurrentItemIndex(fCurrentIndex - 1);
}
return _ref;
return item;
}
int32
Playlist::IndexOf(const entry_ref& _ref) const
Playlist::IndexOf(PlaylistItem* item) const
{
int32 count = CountItems();
for (int32 i = 0; i < count; i++) {
entry_ref* ref = (entry_ref*)fRefs.ItemAtFast(i);
if (*ref == _ref)
return i;
}
return -1;
return fItems.IndexOf(item);
}
status_t
Playlist::GetRefAt(int32 index, entry_ref* _ref) const
PlaylistItem*
Playlist::ItemAt(int32 index) const
{
if (!_ref)
return B_BAD_VALUE;
entry_ref* ref = (entry_ref*)fRefs.ItemAt(index);
if (!ref)
return B_BAD_INDEX;
*_ref = *ref;
return B_OK;
return (PlaylistItem*)fItems.ItemAt(index);
}
//bool
//Playlist::HasRef(const entry_ref& ref) const
//{
// return IndexOf(ref) >= 0;
//}
PlaylistItem*
Playlist::ItemAtFast(int32 index) const
{
return (PlaylistItem*)fItems.ItemAtFast(index);
}
// #pragma mark - navigation
bool
Playlist::SetCurrentRefIndex(int32 index)
Playlist::SetCurrentItemIndex(int32 index)
{
bool result = true;
if (index >= CountItems() || index < 0) {
@ -334,13 +361,13 @@ Playlist::SetCurrentRefIndex(int32 index)
return result;
fCurrentIndex = index;
_NotifyCurrentRefChanged(fCurrentIndex);
_NotifyCurrentItemChanged(fCurrentIndex);
return result;
}
int32
Playlist::CurrentRefIndex() const
Playlist::CurrentItemIndex() const
{
return fCurrentIndex;
}
@ -377,7 +404,7 @@ Playlist::RemoveListener(Listener* listener)
}
// #pragma mark -
// #pragma mark - support
void
@ -409,7 +436,7 @@ Playlist::AppendRefs(const BMessage* refsReceivedMessage, int32 appendIndex)
sortPlaylist = false;
} else {
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 (!sortPlaylist)
subPlaylist.Sort();
@ -426,7 +453,7 @@ Playlist::AppendRefs(const BMessage* refsReceivedMessage, int32 appendIndex)
if (startPlaying) {
// 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)
AppendToPlaylistRecursive(subRef, playlist);
} else if (entry.IsFile()) {
//printf("Is File\n");
BString mimeString = _MIMEString(&ref);
if (_IsMediaFile(mimeString)) {
//printf("Adding\n");
playlist->AddRef(ref);
PlaylistItem* item = new (std::nothrow) FilePlaylistItem(ref);
if (item == NULL || !playlist->AddItem(item))
delete item;
} else
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());
if (path.Path() != NULL) {
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
printf("Error - %s: [%lx]\n", strerror(err), (int32) err);
} else
@ -498,21 +528,7 @@ Playlist::AppendPlaylistToPlaylist(const entry_ref& ref, Playlist* playlist)
}
// #pragma mark -
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());
}
// #pragma mark - private
/*static*/ bool
@ -524,10 +540,29 @@ Playlist::_IsMediaFile(const BString& mimeString)
if (fileType.GetSupertype(&superType) != B_OK)
return false;
// TODO: some media files have other super types, I think
// for example ASF has "application" super type... so it would
// need special handling
return (superType == "audio" || superType == "video");
// try a shortcut first
if (superType == "audio" || superType == "video")
return true;
// 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
Playlist::_NotifyRefAdded(const entry_ref& ref, int32 index) const
Playlist::_NotifyItemAdded(PlaylistItem* item, int32 index) const
{
BList listeners(fListeners);
int32 count = listeners.CountItems();
for (int32 i = 0; i < count; i++) {
Listener* listener = (Listener*)listeners.ItemAtFast(i);
listener->RefAdded(ref, index);
listener->ItemAdded(item, index);
}
}
void
Playlist::_NotifyRefRemoved(int32 index) const
Playlist::_NotifyItemRemoved(int32 index) const
{
BList listeners(fListeners);
int32 count = listeners.CountItems();
for (int32 i = 0; i < count; i++) {
Listener* listener = (Listener*)listeners.ItemAtFast(i);
listener->RefRemoved(index);
listener->ItemRemoved(index);
}
}
void
Playlist::_NotifyRefsSorted() const
Playlist::_NotifyItemsSorted() const
{
BList listeners(fListeners);
int32 count = listeners.CountItems();
for (int32 i = 0; i < count; i++) {
Listener* listener = (Listener*)listeners.ItemAtFast(i);
listener->RefsSorted();
listener->ItemsSorted();
}
}
void
Playlist::_NotifyCurrentRefChanged(int32 newIndex) const
Playlist::_NotifyCurrentItemChanged(int32 newIndex) const
{
BList listeners(fListeners);
int32 count = listeners.CountItems();
for (int32 i = 0; i < count; i++) {
Listener* listener = (Listener*)listeners.ItemAtFast(i);
listener->CurrentRefChanged(newIndex);
listener->CurrentItemChanged(newIndex);
}
}

View File

@ -2,8 +2,8 @@
* Playlist.h - Media Player for the Haiku Operating System
*
* Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de>
* Copyright (C) 2007 Stephan Aßmus <superstippi@gmx.de>
* Copyright (C) 2008-2009 Fredrik Modéen <[FirstName]@[LastName].se> (MIT ok)
* Copyright (C) 2007-2009 Stephan Aßmus <superstippi@gmx.de> (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
* modify it under the terms of the GNU General Public License
@ -22,13 +22,15 @@
#ifndef __PLAYLIST_H
#define __PLAYLIST_H
#include <Entry.h>
#include <List.h>
#include <Locker.h>
#include "PlaylistItem.h"
class BDataIO;
class BMessage;
class BString;
struct entry_ref;
class Playlist : public BLocker {
@ -38,12 +40,12 @@ public:
Listener();
virtual ~Listener();
virtual void RefAdded(const entry_ref& ref, int32 index);
virtual void RefRemoved(int32 index);
virtual void ItemAdded(PlaylistItem* item, int32 index);
virtual void ItemRemoved(int32 index);
virtual void RefsSorted();
virtual void ItemsSorted();
virtual void CurrentRefChanged(int32 newIndex);
virtual void CurrentItemChanged(int32 newIndex);
};
public:
@ -58,26 +60,26 @@ public:
// list functionality
void MakeEmpty();
void MakeEmpty(bool deleteItems = true);
int32 CountItems() const;
void Sort();
bool AddRef(const entry_ref& ref);
bool AddRef(const entry_ref& ref, int32 index);
entry_ref RemoveRef(int32 index,
bool AddItem(PlaylistItem* item);
bool AddItem(PlaylistItem* item, int32 index);
PlaylistItem* RemoveItem(int32 index,
bool careAboutCurrentIndex = true);
bool AdoptPlaylist(Playlist& other);
bool AdoptPlaylist(Playlist& other, int32 index);
int32 IndexOf(const entry_ref& ref) const;
status_t GetRefAt(int32 index, entry_ref* ref) const;
// bool HasRef(const entry_ref& ref) const;
int32 IndexOf(PlaylistItem* item) const;
PlaylistItem* ItemAt(int32 index) const;
PlaylistItem* ItemAtFast(int32 index) const;
// navigating current ref
bool SetCurrentRefIndex(int32 index);
int32 CurrentRefIndex() const;
bool SetCurrentItemIndex(int32 index);
int32 CurrentItemIndex() const;
void GetSkipInfo(bool* canSkipPrevious,
bool* canSkipNext) const;
@ -95,20 +97,20 @@ public:
Playlist* playlist);
private:
static int playlist_cmp(const void* p1, const void* p2);
static bool _IsMediaFile(const BString& mimeString);
static bool _IsTextPlaylist(const BString& mimeString);
static bool _IsBinaryPlaylist(const BString& mimeString);
static bool _IsPlaylist(const BString& mimeString);
static BString _MIMEString(const entry_ref* ref);
void _NotifyRefAdded(const entry_ref& ref,
void _NotifyItemAdded(PlaylistItem*,
int32 index) const;
void _NotifyRefRemoved(int32 index) const;
void _NotifyRefsSorted() const;
void _NotifyCurrentRefChanged(int32 newIndex) const;
void _NotifyItemRemoved(int32 index) const;
void _NotifyItemsSorted() const;
void _NotifyCurrentItemChanged(int32 newIndex) const;
private:
BList fRefs;
BList fItems;
BList fListeners;
int32 fCurrentIndex;

View File

@ -5,6 +5,8 @@
#include "PlaylistItem.h"
#include <stdio.h>
PlaylistItem::Listener::Listener()
{
@ -22,13 +24,97 @@ void PlaylistItem::Listener::ItemChanged(const PlaylistItem* item)
// #pragma mark -
//#define DEBUG_INSTANCE_COUNT
#ifdef DEBUG_INSTANCE_COUNT
static vint32 sInstanceCount = 0;
#endif
PlaylistItem::PlaylistItem()
{
#ifdef DEBUG_INSTANCE_COUNT
atomic_add(&sInstanceCount, 1);
printf("%p->PlaylistItem::PlaylistItem() (%ld)\n", this, sInstanceCount);
#endif
}
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;
}

View File

@ -5,14 +5,18 @@
#ifndef PLAYLIST_ITEM_H
#define PLAYLIST_ITEM_H
#include <Archivable.h>
#include <List.h>
#include <NodeInfo.h>
#include <Referenceable.h>
#include <String.h>
class BBitmap;
class BDataIO;
class BMediaFile;
class BMessage;
class PlaylistItem {
class PlaylistItem : public BArchivable, public Referenceable {
public:
class Listener {
public:
@ -26,35 +30,60 @@ public:
PlaylistItem();
virtual ~PlaylistItem();
virtual PlaylistItem* Clone() const = 0;
// archiving
// virtual status_t Unarchive(const BMessage* archive) = 0;
// virtual status_t Archive(BMessage* into) const = 0;
//
// virtual status_t Unflatten(BDataIO* stream) = 0;
// virtual status_t Flatten(BDataIO* stream) const = 0;
virtual status_t Archive(BMessage* into,
bool deep = true) const = 0;
// properties
virtual status_t SetName(const BString& name) = 0;
virtual status_t GetName(BString& name) const = 0;
// attributes
typedef enum {
ATTR_STRING_NAME = 'name',
ATTR_STRING_KEYWORDS = 'kwrd',
virtual status_t SetTitle(const BString& title) = 0;
virtual status_t GetTitle(BString& title) const = 0;
ATTR_STRING_AUTHOR = 'auth',
ATTR_STRING_ALBUM = 'albm',
ATTR_STRING_TITLE = 'titl',
virtual status_t SetAuthor(const BString& author) = 0;
virtual status_t GetAuthor(BString& author) const = 0;
ATTR_INT32_TRACK = 'trck',
ATTR_INT32_YEAR = 'year',
ATTR_INT32_RATING = 'rtng',
ATTR_INT32_BIT_RATE = 'btrt',
virtual status_t SetAlbum(const BString& album) = 0;
virtual status_t GetAlbum(BString& album) const = 0;
ATTR_INT64_DURATION = 'drtn'
} Attribute;
virtual status_t SetTrackNumber(int32 trackNumber) = 0;
virtual status_t GetTrackNumber(int32& trackNumber) const = 0;
virtual status_t SetAttribute(const Attribute& attribute,
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 GetBitRate(int32& bitRate) const = 0;
virtual status_t SetAttribute(const Attribute& attribute,
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
virtual BString LocationURI() const = 0;
virtual status_t GetIcon(BBitmap* bitmap,
icon_size iconSize) const = 0;
virtual status_t MoveIntoTrash() = 0;
virtual status_t RestoreFromTrash() = 0;
@ -72,4 +101,6 @@ private:
BList fListeners;
};
typedef Reference<PlaylistItem> PlaylistItemRef;
#endif // PLAYLIST_ITEM_H

View File

@ -1,10 +1,8 @@
/*
* Copyright 2007-2009, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
* Copyright 2007-2009 Stephan Aßmus <superstippi@gmx.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "PlaylistListView.h"
#include <new>
@ -29,6 +27,7 @@
#include "MovePLItemsCommand.h"
#include "PlaybackState.h"
#include "Playlist.h"
#include "PlaylistItem.h"
#include "PlaylistObserver.h"
#include "RandomizePLItemsCommand.h"
#include "RemovePLItemsCommand.h"
@ -56,32 +55,37 @@ text_offset(const font_height& fh)
}
class PlaylistListView::Item : public SimpleItem {
public:
Item(const entry_ref& ref);
virtual ~Item();
class PlaylistListView::Item : public SimpleItem,
public PlaylistItem::Listener {
public:
Item(PlaylistItem* item);
virtual ~Item();
void Draw(BView* owner, BRect frame,
void Draw(BView* owner, BRect frame,
const font_height& fh,
bool tintedLine, uint32 mode,
bool active,
uint32 playbackState);
private:
entry_ref fRef;
virtual void ItemChanged(const PlaylistItem* item);
private:
PlaylistItemRef fItem;
};
PlaylistListView::Item::Item(const entry_ref& ref)
: SimpleItem(ref.name),
fRef(ref)
PlaylistListView::Item::Item(PlaylistItem* item)
: SimpleItem(item->Name().String()),
fItem(item)
{
fItem->AddListener(this);
}
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 -
@ -234,6 +245,8 @@ PlaylistListView::PlaylistListView(BRect frame, Playlist* playlist,
PlaylistListView::~PlaylistListView()
{
for (int32 i = CountItems() - 1; i >= 0; i--)
_RemoveItem(i);
fPlaylist->RemoveListener(fPlaylistObserver);
delete fPlaylistObserver;
fController->RemoveListener(fControllerObserver);
@ -258,24 +271,27 @@ PlaylistListView::MessageReceived(BMessage* message)
// message->PrintToStream();
switch (message->what) {
// PlaylistObserver messages
case MSG_PLAYLIST_REF_ADDED: {
entry_ref ref;
case MSG_PLAYLIST_ITEM_ADDED:
{
PlaylistItem* item;
int32 index;
if (message->FindRef("refs", &ref) == B_OK
if (message->FindPointer("item", (void**)&item) == B_OK
&& message->FindInt32("index", &index) == B_OK)
_AddItem(ref, index);
_AddItem(item, index);
break;
}
case MSG_PLAYLIST_REF_REMOVED: {
case MSG_PLAYLIST_ITEM_REMOVED:
{
int32 index;
if (message->FindInt32("index", &index) == B_OK)
_RemoveItem(index);
break;
}
case MSG_PLAYLIST_REFS_SORTED:
case MSG_PLAYLIST_ITEMS_SORTED:
_FullSync();
break;
case MSG_PLAYLIST_CURRENT_REF_CHANGED: {
case MSG_PLAYLIST_CURRENT_ITEM_CHANGED:
{
int32 index;
if (message->FindInt32("index", &index) == B_OK)
_SetCurrentPlaylistIndex(index);
@ -283,7 +299,8 @@ PlaylistListView::MessageReceived(BMessage* message)
}
// ControllerObserver messages
case MSG_CONTROLLER_PLAYBACK_STATE_CHANGED: {
case MSG_CONTROLLER_PLAYBACK_STATE_CHANGED:
{
uint32 state;
if (message->FindInt32("state", (int32*)&state) == B_OK)
_SetPlaybackState(state);
@ -330,7 +347,7 @@ PlaylistListView::MouseDown(BPoint where)
// only do something if user clicked the same item twice
if (fLastClickedItem == item) {
BAutolock _(fPlaylist);
fPlaylist->SetCurrentRefIndex(i);
fPlaylist->SetCurrentItemIndex(i);
handled = true;
}
} else {
@ -486,16 +503,14 @@ PlaylistListView::_FullSync()
scrollBar->SetTarget((BView*)NULL);
}
MakeEmpty();
for (int32 i = CountItems() - 1; i >= 0; i--)
_RemoveItem(i);
int32 count = fPlaylist->CountItems();
for (int32 i = 0; i < count; i++) {
entry_ref ref;
if (fPlaylist->GetRefAt(i, &ref) == B_OK)
_AddItem(ref, i);
}
for (int32 i = 0; i < count; i++)
_AddItem(fPlaylist->ItemAt(i), i);
_SetCurrentPlaylistIndex(fPlaylist->CurrentRefIndex());
_SetCurrentPlaylistIndex(fPlaylist->CurrentItemIndex());
_SetPlaybackState(fController->PlaybackState());
// reattach scrollbar and sync it by calling FrameResized()
@ -509,10 +524,13 @@ PlaylistListView::_FullSync()
void
PlaylistListView::_AddItem(const entry_ref& ref, int32 index)
PlaylistListView::_AddItem(PlaylistItem* _item, int32 index)
{
Item* item = new (nothrow) Item(ref);
if (item)
if (_item == NULL)
return;
Item* item = new (nothrow) Item(_item);
if (item != NULL)
AddItem(item, index);
}

View File

@ -14,6 +14,7 @@ class CommandStack;
class Controller;
class ControllerObserver;
class Playlist;
class PlaylistItem;
class PlaylistObserver;
class PlaylistListView : public SimpleListView {
@ -53,7 +54,7 @@ private:
class Item;
void _FullSync();
void _AddItem(const entry_ref& ref, int32 index);
void _AddItem(PlaylistItem* item, int32 index);
void _RemoveItem(int32 index);
void _SetCurrentPlaylistIndex(int32 index);

View File

@ -1,9 +1,6 @@
/*
* Copyright 2007, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
* Copyright 2007-2009 Stephan Aßmus <superstippi@gmx.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "PlaylistObserver.h"
@ -24,10 +21,10 @@ PlaylistObserver::~PlaylistObserver()
void
PlaylistObserver::RefAdded(const entry_ref& ref, int32 index)
PlaylistObserver::ItemAdded(PlaylistItem* item, int32 index)
{
BMessage message(MSG_PLAYLIST_REF_ADDED);
message.AddRef("refs", &ref);
BMessage message(MSG_PLAYLIST_ITEM_ADDED);
message.AddPointer("item", item);
message.AddInt32("index", index);
DeliverMessage(message);
@ -35,9 +32,9 @@ PlaylistObserver::RefAdded(const entry_ref& ref, int32 index)
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);
DeliverMessage(message);
@ -45,18 +42,18 @@ PlaylistObserver::RefRemoved(int32 index)
void
PlaylistObserver::RefsSorted()
PlaylistObserver::ItemsSorted()
{
BMessage message(MSG_PLAYLIST_REFS_SORTED);
BMessage message(MSG_PLAYLIST_ITEMS_SORTED);
DeliverMessage(message);
}
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);
DeliverMessage(message);

View File

@ -1,9 +1,6 @@
/*
* Copyright 2007, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
* Copyright 2007-2009 Stephan Aßmus <superstippi@gmx.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef PLAYLIST_OBSERVER_H
#define PLAYLIST_OBSERVER_H
@ -12,24 +9,23 @@
#include "Playlist.h"
enum {
MSG_PLAYLIST_REF_ADDED = 'plra',
MSG_PLAYLIST_REF_REMOVED = 'plrr',
MSG_PLAYLIST_REFS_SORTED = 'plrs',
MSG_PLAYLIST_CURRENT_REF_CHANGED = 'plcc'
MSG_PLAYLIST_ITEM_ADDED = 'plia',
MSG_PLAYLIST_ITEM_REMOVED = 'plir',
MSG_PLAYLIST_ITEMS_SORTED = 'plis',
MSG_PLAYLIST_CURRENT_ITEM_CHANGED = 'plcc'
};
class PlaylistObserver : public Playlist::Listener,
public AbstractLOAdapter {
public:
PlaylistObserver(BHandler* target);
virtual ~PlaylistObserver();
class PlaylistObserver : public Playlist::Listener, public AbstractLOAdapter {
public:
PlaylistObserver(BHandler* target);
virtual ~PlaylistObserver();
virtual void RefAdded(const entry_ref& ref, int32 index);
virtual void RefRemoved(int32 index);
virtual void ItemAdded(PlaylistItem* item, 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

View File

@ -1,6 +1,6 @@
/*
* Copyright © 2008 Stephan Aßmus. All rights reserved.
* Distributed under the terms of the MIT License.
* Copyright © 2008-2009 Stephan Aßmus <superstippi@gmx.de>
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "RandomizePLItemsCommand.h"
@ -19,31 +19,33 @@ using std::nothrow;
RandomizePLItemsCommand::RandomizePLItemsCommand(Playlist* playlist,
const int32* indices, int32 count)
: Command()
, fPlaylist(playlist)
, fRefs(count > 0 ? new (nothrow) entry_ref[count] : NULL)
, fListIndices(count > 0 ? new (nothrow) int32[count] : NULL)
, fRandomInternalIndices(count > 0 ? new (nothrow) int32[count] : NULL)
, fCount(count)
:
PLItemsCommand(),
fPlaylist(playlist),
fItems(count > 0 ? new (nothrow) PlaylistItem*[count] : NULL),
fListIndices(count > 0 ? new (nothrow) int32[count] : NULL),
fRandomInternalIndices(count > 0 ? new (nothrow) int32[count] : NULL),
fCount(count)
{
if (!indices || !fPlaylist || !fRefs || !fListIndices
if (!indices || !fPlaylist || !fItems || !fListIndices
|| !fRandomInternalIndices) {
// indicate a bad object state
delete[] fRefs;
fRefs = NULL;
delete[] fItems;
fItems = NULL;
return;
}
memcpy(fListIndices, indices, fCount * sizeof(int32));
memset(fItems, 0, fCount * sizeof(PlaylistItem*));
// put the available indices into a "set"
BList indexSet;
for (int32 i = 0; i < fCount; i++) {
if (fPlaylist->GetRefAt(fListIndices[i], &fRefs[i]) < B_OK
|| !indexSet.AddItem((void*)i)) {
fItems[i] = fPlaylist->ItemAt(fListIndices[i]);
if (fItems[i] == NULL || !indexSet.AddItem((void*)i)) {
// indicate a bad object state
delete[] fRefs;
fRefs = NULL;
delete[] fItems;
fItems = NULL;
return;
}
}
@ -58,7 +60,7 @@ RandomizePLItemsCommand::RandomizePLItemsCommand(Playlist* playlist,
RandomizePLItemsCommand::~RandomizePLItemsCommand()
{
delete[] fRefs;
delete[] fItems;
delete[] fListIndices;
delete[] fRandomInternalIndices;
}
@ -67,7 +69,7 @@ RandomizePLItemsCommand::~RandomizePLItemsCommand()
status_t
RandomizePLItemsCommand::InitCheck()
{
if (!fRefs)
if (!fItems)
return B_NO_INIT;
return B_OK;
@ -100,36 +102,34 @@ RandomizePLItemsCommand::_Sort(bool random)
{
BAutolock _(fPlaylist);
// remember currently playling ref in case we move it
entry_ref currentRef;
bool adjustCurrentRef = fPlaylist->GetRefAt(fPlaylist->CurrentRefIndex(),
&currentRef) == B_OK;
// remember currently playling item in case we move it
PlaylistItem* current = fPlaylist->ItemAt(fPlaylist->CurrentItemIndex());
// remove refs from playlist
for (int32 i = 0; i < fCount; i++) {
// "- i" to account for the items already removed
fPlaylist->RemoveRef(fListIndices[i] - i, false);
fPlaylist->RemoveItem(fListIndices[i] - i, false);
}
// add refs to playlist at the randomized indices
if (random) {
for (int32 i = 0; i < fCount; i++) {
if (!fPlaylist->AddRef(fRefs[fRandomInternalIndices[i]],
if (!fPlaylist->AddItem(fItems[fRandomInternalIndices[i]],
fListIndices[i])) {
return B_NO_MEMORY;
}
}
} else {
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;
}
}
}
// take care about currently played ref
if (adjustCurrentRef)
fPlaylist->SetCurrentRefIndex(fPlaylist->IndexOf(currentRef));
// take care about currently played item
if (current != NULL)
fPlaylist->SetCurrentItemIndex(fPlaylist->IndexOf(current));
return B_OK;
}

View File

@ -1,24 +1,21 @@
/*
* Copyright © 2008 Stephan Aßmus. All rights reserved.
* Distributed under the terms of the MIT License.
* Copyright © 2008-2009 Stephan Aßmus <superstippi@gmx.de>
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef RANDOMIZE_PL_ITEMS_COMMAND_H
#define RANDOMIZE_PL_ITEMS_COMMAND_H
#include "Command.h"
#include "PLItemsCommand.h"
class Playlist;
struct entry_ref;
class RandomizePLItemsCommand : public Command {
public:
class RandomizePLItemsCommand : public PLItemsCommand {
public:
RandomizePLItemsCommand(
Playlist* playlist,
const int32* indices,
int32 count);
virtual ~RandomizePLItemsCommand();
virtual status_t InitCheck();
virtual status_t Perform();
@ -26,11 +23,11 @@ class RandomizePLItemsCommand : public Command {
virtual void GetName(BString& name);
private:
private:
status_t _Sort(bool random);
Playlist* fPlaylist;
entry_ref* fRefs;
PlaylistItem** fItems;
int32* fListIndices;
int32* fRandomInternalIndices;
int32 fCount;

View File

@ -1,9 +1,6 @@
/*
* Copyright 2007-2009, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
* Copyright © 2007-2009 Stephan Aßmus <superstippi@gmx.de>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#include "RemovePLItemsCommand.h"
@ -13,10 +10,6 @@
#include <Alert.h>
#include <Autolock.h>
#include <Directory.h>
#include <Entry.h>
#include <FindDirectory.h>
#include <Path.h>
#include "Playlist.h"
@ -27,35 +20,31 @@ using std::nothrow;
RemovePLItemsCommand::RemovePLItemsCommand(Playlist* playlist,
const int32* indices, int32 count, bool moveFilesToTrash)
:
Command(),
PLItemsCommand(),
fPlaylist(playlist),
fRefs(count > 0 ? new (nothrow) entry_ref[count] : NULL),
fNamesInTrash(NULL),
fItems(count > 0 ? new (nothrow) PlaylistItem*[count] : NULL),
fIndices(count > 0 ? new (nothrow) int32[count] : NULL),
fCount(count),
fMoveFilesToTrash(moveFilesToTrash),
fMoveErrorShown(false)
fMoveErrorShown(false),
fItemsRemoved(false)
{
if (!indices || !fPlaylist || !fRefs || !fIndices) {
if (!indices || !fPlaylist || !fItems || !fIndices) {
// indicate a bad object state
delete[] fRefs;
fRefs = NULL;
delete[] fItems;
fItems = NULL;
return;
}
memcpy(fIndices, indices, fCount * sizeof(int32));
if (fMoveFilesToTrash) {
fNamesInTrash = new (nothrow) BString[count];
if (fNamesInTrash == NULL)
return;
}
memset(fItems, 0, fCount * sizeof(PlaylistItem*));
// init original entry indices
for (int32 i = 0; i < fCount; i++) {
if (fPlaylist->GetRefAt(fIndices[i], &fRefs[i]) < B_OK) {
delete[] fRefs;
fRefs = NULL;
fItems[i] = fPlaylist->ItemAt(fIndices[i]);
if (fItems[i] == NULL) {
delete[] fItems;
fItems = NULL;
return;
}
}
@ -64,19 +53,16 @@ RemovePLItemsCommand::RemovePLItemsCommand(Playlist* playlist,
RemovePLItemsCommand::~RemovePLItemsCommand()
{
delete[] fRefs;
_CleanUp(fItems, fCount, fItemsRemoved);
delete[] fIndices;
delete[] fNamesInTrash;
}
status_t
RemovePLItemsCommand::InitCheck()
{
if (!fPlaylist || !fRefs || !fIndices
|| (fMoveFilesToTrash && !fNamesInTrash)) {
if (!fPlaylist || !fItems || !fIndices)
return B_NO_INIT;
}
return B_OK;
}
@ -86,65 +72,32 @@ RemovePLItemsCommand::Perform()
{
BAutolock _(fPlaylist);
fItemsRemoved = true;
int32 lastRemovedIndex = -1;
// remove refs from playlist
for (int32 i = 0; i < fCount; i++) {
// "- i" to account for the items already removed
lastRemovedIndex = fIndices[i] - i;
fPlaylist->RemoveRef(lastRemovedIndex);
fPlaylist->RemoveItem(lastRemovedIndex);
}
// in case we removed the currently playing file
if (fPlaylist->CurrentRefIndex() == -1)
fPlaylist->SetCurrentRefIndex(lastRemovedIndex);
if (fPlaylist->CurrentItemIndex() == -1)
fPlaylist->SetCurrentItemIndex(lastRemovedIndex);
if (fMoveFilesToTrash) {
BString errorFiles;
status_t moveError = B_OK;
bool errorOnAllFiles = true;
char trashPath[B_PATH_NAME_LENGTH];
for (int32 i = 0; i < fCount; i++) {
status_t err = find_directory(B_TRASH_DIRECTORY, fRefs[i].device,
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());
status_t err = fItems[i]->MoveIntoTrash();
if (err != B_OK) {
moveError = err;
if (errorFiles.Length() > 0)
errorFiles << ' ';
errorFiles << fRefs[i].name;
errorFiles << fItems[i]->Name();
} else
errorOnAllFiles = false;
}
@ -173,61 +126,21 @@ RemovePLItemsCommand::Undo()
{
BAutolock _(fPlaylist);
status_t ret = B_OK;
fItemsRemoved = false;
if (fMoveFilesToTrash) {
char trashPath[B_PATH_NAME_LENGTH];
for (int32 i = 0; i < fCount; i++) {
status_t err = find_directory(B_TRASH_DIRECTORY, fRefs[i].device,
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;
fItems[i]->RestoreFromTrash();
}
}
// remember currently playling ref in case we move it
entry_ref currentRef;
bool adjustCurrentRef = fPlaylist->GetRefAt(fPlaylist->CurrentRefIndex(),
&currentRef) == B_OK;
// remember currently playling item in case we move it
PlaylistItem* current = fPlaylist->ItemAt(fPlaylist->CurrentItemIndex());
// 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++) {
if (!fPlaylist->AddRef(fRefs[i], fIndices[i])) {
if (!fPlaylist->AddItem(fItems[i], fIndices[i])) {
ret = B_NO_MEMORY;
break;
}
@ -236,8 +149,8 @@ BEntry entry(path.Path());
return ret;
// take care about currently played ref
if (adjustCurrentRef)
fPlaylist->SetCurrentRefIndex(fPlaylist->IndexOf(currentRef));
if (current != NULL)
fPlaylist->SetCurrentItemIndex(fPlaylist->IndexOf(current));
return B_OK;
}

View File

@ -1,21 +1,15 @@
/*
* Copyright 2007-2009, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
* Copyright © 2007-2009 Stephan Aßmus <superstippi@gmx.de>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#ifndef REMOVE_PL_ITEMS_COMMAND_H
#define REMOVE_PL_ITEMS_COMMAND_H
#include "Command.h"
#include "PLItemsCommand.h"
struct entry_ref;
class Playlist;
class RemovePLItemsCommand : public Command {
public:
class RemovePLItemsCommand : public PLItemsCommand {
public:
RemovePLItemsCommand(
Playlist* playlist,
const int32* indices,
@ -30,14 +24,14 @@ class RemovePLItemsCommand : public Command {
virtual void GetName(BString& name);
private:
private:
Playlist* fPlaylist;
entry_ref* fRefs;
BString* fNamesInTrash;
PlaylistItem** fItems;
int32* fIndices;
int32 fCount;
bool fMoveFilesToTrash;
bool fMoveErrorShown;
bool fItemsRemoved;
};
#endif // REMOVE_PL_ITEMS_COMMAND_H

View File

@ -17,7 +17,7 @@ using namespace std;
//#define TRACE_AUDIO_SUPPLIER
#ifdef TRACE_AUDIO_SUPPLIER
# define TRACE(x...) printf("MediaTrackAudioSupplier::"); printf(x)
# define TRACE(x...) printf("MediaTrackAudioSupplier::" x)
#else
# define TRACE(x...)
#endif
@ -123,6 +123,8 @@ MediaTrackAudioSupplier::Read(void* buffer, int64 pos, int64 frames)
frames);
TRACE(" this: %p, fOutOffset: %lld\n", this, fOutOffset);
//printf("MediaTrackAudioSupplier::Read(%p, %lld, %lld)\n", buffer, pos, frames);
status_t error = InitCheck();
if (error != B_OK) {
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",
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
bigtime_t time = system_time();
if (frames > 0)
@ -152,6 +206,7 @@ MediaTrackAudioSupplier::Read(void* buffer, int64 pos, int64 frames)
if (frames > 0)
_ReadUncachedFrames(buffer, pos, frames, time);
#endif
TRACE("Read() done\n");
return B_OK;
@ -203,6 +258,8 @@ MediaTrackAudioSupplier::_InitFromTrack()
TRACE("MediaTrackAudioSupplier: keyframes: %d, frame count: %lld\n",
fHasKeyFrames, fCountFrames);
printf("MediaTrackAudioSupplier: keyframes: %d, frame count: %lld\n",
fHasKeyFrames, fCountFrames);
} else
fMediaTrack = NULL;
}
@ -416,19 +473,6 @@ MediaTrackAudioSupplier::_ReadBuffer(Buffer* buffer, int64 position,
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
//
// 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;
frames -= 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
// much data from the end as possible.
@ -469,23 +513,11 @@ MediaTrackAudioSupplier::_ReadCachedFrames(void*& dest, int64& pos,
_CopyFrames(buffer->data, buffer->offset, dest, pos,
pos + frames - size, 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
//
// Reads /frames/ frames from /position/ into /buffer/. The frames are not
@ -521,8 +553,10 @@ MediaTrackAudioSupplier::_ReadUncachedFrames(void* buffer, int64 position,
currentPos += cacheBuffer->size;
}
}
#if 1
// 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) {
int64 nextKeyFrame = currentPos;
if (_FindKeyFrameForward(nextKeyFrame) == B_OK) {
@ -540,6 +574,8 @@ MediaTrackAudioSupplier::_ReadUncachedFrames(void* buffer, int64 position,
}
}
}
#endif
// on error fill up the buffer with silence
if (error != B_OK && frames > 0)
ReadSilence(buffer, frames);
@ -551,17 +587,17 @@ status_t
MediaTrackAudioSupplier::_FindKeyFrameForward(int64& position)
{
status_t error = B_OK;
// NOTE: the keyframe version confuses the Frauenhofer MP3 decoder,
// it works fine with the non-keyframe version, so let's hope this
// is the case for all other keyframe based BeOS codecs...
// if (fHasKeyFrames) {
// error = fMediaTrack->FindKeyFrameForFrame(
// &position, B_MEDIA_SEEK_CLOSEST_FORWARD);
// } else {
#ifdef __HAIKU__
if (fHasKeyFrames) {
error = fMediaTrack->FindKeyFrameForFrame(
&position, B_MEDIA_SEEK_CLOSEST_FORWARD);
} else
#endif
{
int64 framesPerBuffer = _FramesPerBuffer();
position += framesPerBuffer - 1;
position = position % framesPerBuffer;
// }
}
return error;
}
@ -578,6 +614,7 @@ MediaTrackAudioSupplier::_FindKeyFrameBackward(int64& position)
return error;
}
#if 0
// _SeekToKeyFrameForward
status_t
MediaTrackAudioSupplier::_SeekToKeyFrameForward(int64& position)
@ -601,6 +638,7 @@ MediaTrackAudioSupplier::_SeekToKeyFrameForward(int64& position)
}
return error;
}
#endif
// _SeekToKeyFrameBackward
status_t
@ -614,16 +652,16 @@ MediaTrackAudioSupplier::_SeekToKeyFrameBackward(int64& position)
int64 oldPosition = position;
error = fMediaTrack->FindKeyFrameForFrame(&position,
B_MEDIA_SEEK_CLOSEST_BACKWARD);
if (error >= B_OK)
if (error == B_OK)
error = fMediaTrack->SeekToFrame(&position, 0);
if (error < B_OK) {
if (error != B_OK) {
position = fMediaTrack->CurrentFrame();
if (fReportSeekError) {
// if (fReportSeekError) {
printf(" seek to key frame backward: %lld -> %lld (%lld) "
"- %s\n", oldPosition, position,
fMediaTrack->CurrentFrame(), strerror(error));
fReportSeekError = false;
}
// }
} else {
fReportSeekError = true;
}

View File

@ -62,21 +62,18 @@ class MediaTrackAudioSupplier : public AudioTrackSupplier {
status_t _ReadBuffer(Buffer* buffer, int64 position,
bigtime_t time);
void _ReadCachedFrames(void*& buffer,
int64& position, int64& frames);
void _ReadCachedFrames(void*& buffer,
int64& position, int64& frames,
bigtime_t time);
status_t _ReadUncachedFrames(void* buffer,
int64 position, int64 frames);
status_t _ReadUncachedFrames(void* buffer,
int64 position, int64 frames,
bigtime_t time);
status_t _FindKeyFrameForward(int64& position);
status_t _FindKeyFrameBackward(int64& position);
status_t _SeekToKeyFrameForward(int64& position);
// NOTE: unused
// status_t _SeekToKeyFrameForward(int64& position);
status_t _SeekToKeyFrameBackward(int64& position);
private: