* Refactor the "Remove and Put into Trash" backend a bit to allow giving it an

index and not work on the current selection only.
* Reenable the code in MainWin that implements the shortcuts to trigger this
  feature during playback. Now it uses the Undo/Redo stack and profits from
  existing polish.
* Add missing fPlaylist locking in MainWin at several places. Should not have
  caused any realworld problems, though.
* Add Undo/Redo shortcuts to MainWin and forward to Playlist window.
* Make sure the Playlist window opens on the same workspace as the player
  window. This could be seen when launching MediaPlayer on one workspace, later
  moving the window and then opening the Playlist window, it would open on
  the original workspace. The new behavior additionally pulls the playlist
  when it's already open and you invoke the "Playlist" menu item.
* Added the beginnings of a refactoring to make the Playlist and everything
  else use a PlaylistItem class, instead of entry_refs directly. This stuff is
  not yet used, though, just compiles.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30776 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus
2009-05-17 00:16:08 +00:00
parent e85f80eedf
commit dd09109647
11 changed files with 436 additions and 35 deletions
+2
View File
@@ -55,10 +55,12 @@ Application MediaPlayer :
# playlist
CopyPLItemsCommand.cpp
EntryRefPlaylistItem.cpp
ImportPLItemsCommand.cpp
ListViews.cpp
MovePLItemsCommand.cpp
Playlist.cpp
PlaylistItem.cpp
PlaylistListView.cpp
PlaylistObserver.cpp
PlaylistWindow.cpp
+37 -9
View File
@@ -194,6 +194,11 @@ MainWin::MainWin()
Settings::Default()->AddListener(&fGlobalSettingsListener);
_AdoptGlobalSettings();
AddShortcut('z', B_COMMAND_KEY, new BMessage(B_UNDO));
AddShortcut('y', B_COMMAND_KEY, new BMessage(B_UNDO));
AddShortcut('z', B_COMMAND_KEY | B_SHIFT_KEY, new BMessage(B_REDO));
AddShortcut('y', B_COMMAND_KEY | B_SHIFT_KEY, new BMessage(B_REDO));
Show();
}
@@ -358,6 +363,11 @@ MainWin::MessageReceived(BMessage *msg)
}
break;
case B_UNDO:
case B_REDO:
fPlaylistWindow->PostMessage(msg);
break;
case M_MEDIA_SERVER_STARTED:
printf("TODO: implement M_MEDIA_SERVER_STARTED\n");
// fController->...
@@ -404,6 +414,8 @@ MainWin::MessageReceived(BMessage *msg)
// ControllerObserver messages
case MSG_CONTROLLER_FILE_FINISHED:
{
BAutolock _(fPlaylist);
bool hadNext = fPlaylist->SetCurrentRefIndex(
fPlaylist->CurrentRefIndex() + 1);
if (!hadNext) {
@@ -653,6 +665,8 @@ MainWin::MessageReceived(BMessage *msg)
}
*/
case M_SET_PLAYLIST_POSITION: {
BAutolock _(fPlaylist);
int32 index;
if (msg->FindInt32("index", &index) == B_OK)
fPlaylist->SetCurrentRefIndex(index);
@@ -723,6 +737,7 @@ MainWin::OpenFile(const entry_ref &ref)
status_t err = fController->SetTo(ref);
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;
@@ -778,10 +793,17 @@ void
MainWin::ShowPlaylistWindow()
{
if (fPlaylistWindow->Lock()) {
// make sure the window shows on the same workspace as ourself
uint32 workspaces = Workspaces();
if (fPlaylistWindow->Workspaces() != workspaces)
fPlaylistWindow->SetWorkspaces(workspaces);
// show or activate
if (fPlaylistWindow->IsHidden())
fPlaylistWindow->Show();
else
fPlaylistWindow->Activate();
fPlaylistWindow->Unlock();
}
}
@@ -823,6 +845,7 @@ MainWin::_RefsReceived(BMessage* msg)
// the playlist ist replaced by dropped files
// or the dropped files are appended to the end
// of the existing playlist if <shift> is pressed
BAutolock _(fPlaylist);
int32 appendIndex = modifiers() & B_SHIFT_KEY ?
fPlaylist->CountItems() : -1;
msg->AddInt32("append_index", appendIndex);
@@ -1367,15 +1390,19 @@ MainWin::_KeyDown(BMessage *msg)
case 0x48: // numeric keypad left arrow
PostMessage(M_SKIP_PREV);
return B_OK;
// TODO: Reenable this and use Undo/Redo stack...
// case 0x34: //delete button
// case 0x3e: //d for delete
// case 0x2b: //t for Trash
// if (modifiers() & B_COMMAND_KEY) {
// PostMessage(M_FILE_DELETE);
// return B_OK;
// }
// break;
case 0x34: //delete button
case 0x3e: //d for delete
case 0x2b: //t for Trash
if (modifiers() & B_COMMAND_KEY) {
BAutolock _(fPlaylist);
BMessage removeMessage(M_PLAYLIST_REMOVE_AND_PUT_INTO_TRASH);
removeMessage.AddInt32("playlist index",
fPlaylist->CurrentRefIndex());
fPlaylistWindow->PostMessage(&removeMessage);
return B_OK;
}
break;
}
return B_ERROR;
@@ -1541,6 +1568,7 @@ MainWin::_UpdateControlsEnabledStatus()
if (fHasAudio)
enabledButtons |= VOLUME_ENABLED;
BAutolock _(fPlaylist);
bool canSkipPrevious, canSkipNext;
fPlaylist->GetSkipInfo(&canSkipPrevious, &canSkipNext);
if (canSkipPrevious)
@@ -0,0 +1,152 @@
/*
* 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);
}
@@ -0,0 +1,56 @@
/*
* 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
@@ -40,11 +40,6 @@ using std::nothrow;
// TODO: using BList for objects is bad, replace it with a template
// TODO: Remove this and use Tracker's Command.h once it is moved into the private headers
namespace BPrivate {
const uint32 kMoveToTrash = 'Ttrs';
}
Playlist::Listener::Listener() {}
Playlist::Listener::~Listener() {}
void Playlist::Listener::RefAdded(const entry_ref& ref, int32 index) {}
@@ -0,0 +1,63 @@
/*
* Copyright 2009 Stephan Aßmus <superstippi@gmx.de>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#include "PlaylistItem.h"
PlaylistItem::Listener::Listener()
{
}
PlaylistItem::Listener::~Listener()
{
}
void PlaylistItem::Listener::ItemChanged(const PlaylistItem* item)
{
}
// #pragma mark -
PlaylistItem::PlaylistItem()
{
}
PlaylistItem::~PlaylistItem()
{
}
//! You must hold the Playlist lock.
bool
PlaylistItem::AddListener(Listener* listener)
{
if (listener && !fListeners.HasItem(listener))
return fListeners.AddItem(listener);
return false;
}
//! You must hold the Playlist lock.
void
PlaylistItem::RemoveListener(Listener* listener)
{
fListeners.RemoveItem(listener);
}
void
PlaylistItem::_NotifyListeners() const
{
BList listeners(fListeners);
int32 count = listeners.CountItems();
for (int32 i = 0; i < count; i++) {
Listener* listener = (Listener*)listeners.ItemAtFast(i);
listener->ItemChanged(this);
}
}
@@ -0,0 +1,75 @@
/*
* Copyright 2009 Stephan Aßmus <superstippi@gmx.de>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#ifndef PLAYLIST_ITEM_H
#define PLAYLIST_ITEM_H
#include <List.h>
#include <String.h>
class BDataIO;
class BMediaFile;
class BMessage;
class PlaylistItem {
public:
class Listener {
public:
Listener();
virtual ~Listener();
virtual void ItemChanged(const PlaylistItem* item);
};
public:
PlaylistItem();
virtual ~PlaylistItem();
// 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;
// properties
virtual status_t SetName(const BString& name) = 0;
virtual status_t GetName(BString& name) const = 0;
virtual status_t SetTitle(const BString& title) = 0;
virtual status_t GetTitle(BString& title) const = 0;
virtual status_t SetAuthor(const BString& author) = 0;
virtual status_t GetAuthor(BString& author) const = 0;
virtual status_t SetAlbum(const BString& album) = 0;
virtual status_t GetAlbum(BString& album) const = 0;
virtual status_t SetTrackNumber(int32 trackNumber) = 0;
virtual status_t GetTrackNumber(int32& trackNumber) const = 0;
virtual status_t SetBitRate(int32 bitRate) = 0;
virtual status_t GetBitRate(int32& bitRate) const = 0;
virtual status_t GetDuration(bigtime_t& duration) const = 0;
// methods
virtual status_t MoveIntoTrash() = 0;
virtual status_t RestoreFromTrash() = 0;
// playback
virtual BMediaFile* CreateMediaFile() const = 0;
// listener support
bool AddListener(Listener* listener);
void RemoveListener(Listener* listener);
protected:
void _NotifyListeners() const;
private:
BList fListeners;
};
#endif // PLAYLIST_ITEM_H
@@ -1,5 +1,5 @@
/*
* Copyright 2007-2008, Haiku. All rights reserved.
* Copyright 2007-2009, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
@@ -56,10 +56,10 @@ text_offset(const font_height& fh)
}
class PlaylistItem : public SimpleItem {
class PlaylistListView::Item : public SimpleItem {
public:
PlaylistItem(const entry_ref& ref);
virtual ~PlaylistItem();
Item(const entry_ref& ref);
virtual ~Item();
void Draw(BView* owner, BRect frame,
const font_height& fh,
@@ -73,20 +73,20 @@ class PlaylistItem : public SimpleItem {
};
PlaylistItem::PlaylistItem(const entry_ref& ref)
PlaylistListView::Item::Item(const entry_ref& ref)
: SimpleItem(ref.name),
fRef(ref)
{
}
PlaylistItem::~PlaylistItem()
PlaylistListView::Item::~Item()
{
}
void
PlaylistItem::Draw(BView* owner, BRect frame, const font_height& fh,
PlaylistListView::Item::Draw(BView* owner, BRect frame, const font_height& fh,
bool tintedLine, uint32 mode, bool active, uint32 playbackState)
{
rgb_color color = (rgb_color){ 255, 255, 255, 255 };
@@ -323,7 +323,7 @@ PlaylistListView::MouseDown(BPoint where)
float textOffset = text_offset(fFontHeight);
for (int32 i = 0;
PlaylistItem* item = dynamic_cast<PlaylistItem*>(ItemAt(i)); i++) {
Item* item = dynamic_cast<Item*>(ItemAt(i)); i++) {
BRect r = ItemFrame(i);
if (r.Contains(where)) {
if (clicks == 2) {
@@ -385,15 +385,14 @@ PlaylistListView::CopyItems(const BList& indices, int32 toIndex)
void
PlaylistListView::RemoveItemList(const BList& indices)
{
fCommandStack->Perform(new (nothrow) RemovePLItemsCommand(fPlaylist,
(int32*)indices.Items(), indices.CountItems()));
RemoveItemList(indices, false);
}
void
PlaylistListView::DrawListItem(BView* owner, int32 index, BRect frame) const
{
if (PlaylistItem* item = dynamic_cast<PlaylistItem*>(ItemAt(index))) {
if (Item* item = dynamic_cast<Item*>(ItemAt(index))) {
item->Draw(owner, frame, fFontHeight, index % 2,
DISPLAY_NAME, index == fCurrentPlaylistIndex, fPlaybackState);
}
@@ -448,8 +447,24 @@ PlaylistListView::RemoveSelectionToTrash()
{
BList indices;
GetSelectedItems(indices);
RemoveItemList(indices, true);
}
void
PlaylistListView::RemoveToTrash(int32 index)
{
BList indices;
indices.AddItem((void*)index);
RemoveItemList(indices, true);
}
void
PlaylistListView::RemoveItemList(const BList& indices, bool intoTrash)
{
fCommandStack->Perform(new (nothrow) RemovePLItemsCommand(fPlaylist,
(int32*)indices.Items(), indices.CountItems(), true));
(int32*)indices.Items(), indices.CountItems(), intoTrash));
}
@@ -496,7 +511,7 @@ PlaylistListView::_FullSync()
void
PlaylistListView::_AddItem(const entry_ref& ref, int32 index)
{
PlaylistItem* item = new (nothrow) PlaylistItem(ref);
Item* item = new (nothrow) Item(ref);
if (item)
AddItem(item, index);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2007, Haiku. All rights reserved.
* Copyright 2007-2009, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
@@ -14,11 +14,10 @@ class CommandStack;
class Controller;
class ControllerObserver;
class Playlist;
class PlaylistItem;
class PlaylistObserver;
class PlaylistListView : public SimpleListView {
public:
public:
PlaylistListView(BRect frame,
Playlist* playlist,
Controller* controller,
@@ -46,8 +45,13 @@ class PlaylistListView : public SimpleListView {
void Randomize();
void RemoveSelectionToTrash();
void RemoveToTrash(int32 index);
void RemoveItemList(const BList& indices,
bool intoTrash);
private:
class Item;
private:
void _FullSync();
void _AddItem(const entry_ref& ref, int32 index);
void _RemoveItem(int32 index);
@@ -67,7 +71,7 @@ class PlaylistListView : public SimpleListView {
uint32 fPlaybackState;
font_height fFontHeight;
PlaylistItem* fLastClickedItem;
Item* fLastClickedItem;
};
#endif // PLAYLIST_LIST_VIEW_H
@@ -55,8 +55,7 @@ enum {
M_PLAYLIST_EMPTY = 'emty',
M_PLAYLIST_RANDOMIZE = 'rand',
M_PLAYLIST_REMOVE = 'rmov',
M_PLAYLIST_REMOVE_AND_PUT_INTO_TRASH = 'rmtr'
M_PLAYLIST_REMOVE = 'rmov'
};
#define SPACE 5
@@ -198,8 +197,16 @@ PlaylistWindow::MessageReceived(BMessage* message)
fListView->RemoveSelected();
break;
case M_PLAYLIST_REMOVE_AND_PUT_INTO_TRASH:
fListView->RemoveSelectionToTrash();
{
printf("M_PLAYLIST_REMOVE_AND_PUT_INTO_TRASH\n");
message->PrintToStream();
int32 index;
if (message->FindInt32("playlist index", &index) == B_OK)
fListView->RemoveToTrash(index);
else
fListView->RemoveSelectionToTrash();
break;
}
default:
BWindow::MessageReceived(message);
break;
@@ -27,6 +27,10 @@ class RWLocker;
class BButton;
class BFilePanel;
enum {
M_PLAYLIST_REMOVE_AND_PUT_INTO_TRASH = 'rmtr'
};
class PlaylistWindow : public BWindow {
public:
PlaylistWindow(BRect frame,