* Cleanup with regards to file panel usage. There are two global file panels
now maintained by the application. (So that the last used folder is more consistently remembered.) * Added a message protocol for using the file panels from other loopers. * Implemented playlist saving and loading for the binary (BMessage-based) format. There were some beginnings for supporting a m3u-like text-based format as well. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27955 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
* MainApp.cpp - Media Player for the Haiku Operating System
|
||||
*
|
||||
* Copyright (C) 2006 Marcus Overhagen <[email protected]>
|
||||
* Copyright (C) 2008 Stephan Aßmus <[email protected]>
|
||||
* Copyright (C) 2008 Stephan Aßmus <[email protected]> (MIT Ok)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <Alert.h>
|
||||
#include <Autolock.h>
|
||||
#include <Entry.h>
|
||||
#include <FilePanel.h>
|
||||
#include <MediaRoster.h>
|
||||
#include <Path.h>
|
||||
#include <Roster.h>
|
||||
@@ -35,7 +36,7 @@
|
||||
#include "SettingsWindow.h"
|
||||
|
||||
|
||||
MainApp *gMainApp;
|
||||
MainApp* gMainApp;
|
||||
const char* kAppSig = "application/x-vnd.Haiku-MediaPlayer";
|
||||
|
||||
static const char* kMediaServerSig = "application/x-vnd.Be.media-server";
|
||||
@@ -45,9 +46,13 @@ static const char* kMediaServerAddOnSig = "application/x-vnd.Be.addon-host";
|
||||
MainApp::MainApp()
|
||||
: BApplication(kAppSig),
|
||||
fPlayerCount(0),
|
||||
//fFirstWindow(NewWindow()),
|
||||
fFirstWindow(NULL),
|
||||
fSettingsWindow(NULL),
|
||||
|
||||
fOpenFilePanel(NULL),
|
||||
fSaveFilePanel(NULL),
|
||||
fLastFilePanelFolder(),
|
||||
|
||||
fMediaServerRunning(false),
|
||||
fMediaAddOnServerRunning(false)
|
||||
{
|
||||
@@ -56,6 +61,8 @@ MainApp::MainApp()
|
||||
|
||||
MainApp::~MainApp()
|
||||
{
|
||||
delete fOpenFilePanel;
|
||||
delete fSaveFilePanel;
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +70,8 @@ bool
|
||||
MainApp::QuitRequested()
|
||||
{
|
||||
// Note: This needs to be done here, SettingsWindow::QuitRequested()
|
||||
// returns "false" always.
|
||||
// returns "false" always. (Standard BApplication quit procedure will
|
||||
// hang otherwise.)
|
||||
if (fSettingsWindow && fSettingsWindow->Lock())
|
||||
fSettingsWindow->Quit();
|
||||
fSettingsWindow = NULL;
|
||||
@@ -76,7 +84,7 @@ BWindow*
|
||||
MainApp::FirstWindow()
|
||||
{
|
||||
BAutolock _(this);
|
||||
if (fFirstWindow)
|
||||
if (fFirstWindow != NULL)
|
||||
return fFirstWindow;
|
||||
return NewWindow();
|
||||
}
|
||||
@@ -85,13 +93,12 @@ MainApp::FirstWindow()
|
||||
BWindow*
|
||||
MainApp::NewWindow()
|
||||
{
|
||||
BWindow* win;
|
||||
BAutolock _(this);
|
||||
fPlayerCount++;
|
||||
win = new MainWin();
|
||||
if (!fFirstWindow)
|
||||
fFirstWindow = win;
|
||||
return win;
|
||||
BWindow* window = new MainWin();
|
||||
if (fFirstWindow == NULL)
|
||||
fFirstWindow = window;
|
||||
return window;
|
||||
}
|
||||
|
||||
|
||||
@@ -130,7 +137,7 @@ MainApp::ReadyToRun()
|
||||
|
||||
|
||||
void
|
||||
MainApp::RefsReceived(BMessage *msg)
|
||||
MainApp::RefsReceived(BMessage* message)
|
||||
{
|
||||
// The user dropped a file (or files) on this app's icon,
|
||||
// or double clicked a file that's handled by this app.
|
||||
@@ -142,14 +149,9 @@ MainApp::RefsReceived(BMessage *msg)
|
||||
// window.
|
||||
printf("MainApp::RefsReceived\n");
|
||||
|
||||
entry_ref ref;
|
||||
for (int i = 0; B_OK == msg->FindRef("refs", i, &ref); i++) {
|
||||
BWindow *win;
|
||||
win = NewWindow();
|
||||
BMessage m(B_REFS_RECEIVED);
|
||||
m.AddRef("refs", &ref);
|
||||
win->PostMessage(&m);
|
||||
}
|
||||
BWindow* window = NewWindow();
|
||||
if (window)
|
||||
window->PostMessage(message);
|
||||
}
|
||||
|
||||
|
||||
@@ -245,6 +247,20 @@ MainApp::MessageReceived(BMessage* message)
|
||||
_ShowSettingsWindow();
|
||||
break;
|
||||
|
||||
case M_SHOW_OPEN_PANEL:
|
||||
_ShowOpenFilePanel(message);
|
||||
break;
|
||||
case M_SHOW_SAVE_PANEL:
|
||||
_ShowSaveFilePanel(message);
|
||||
break;
|
||||
|
||||
case M_OPEN_PANEL_RESULT:
|
||||
_HandleOpenPanelResult(message);
|
||||
break;
|
||||
case M_SAVE_PANEL_RESULT:
|
||||
_HandleSavePanelResult(message);
|
||||
break;
|
||||
|
||||
default:
|
||||
BApplication::MessageReceived(message);
|
||||
break;
|
||||
@@ -259,6 +275,9 @@ MainApp::AboutRequested()
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
void
|
||||
MainApp::_BroadcastMessage(const BMessage& _message)
|
||||
{
|
||||
@@ -272,17 +291,155 @@ MainApp::_BroadcastMessage(const BMessage& _message)
|
||||
void
|
||||
MainApp::_ShowSettingsWindow()
|
||||
{
|
||||
if (fSettingsWindow->Lock()) {
|
||||
if (fSettingsWindow->IsHidden())
|
||||
fSettingsWindow->Show();
|
||||
else
|
||||
fSettingsWindow->Activate();
|
||||
fSettingsWindow->Unlock();
|
||||
BAutolock lock(fSettingsWindow);
|
||||
if (!lock.IsLocked())
|
||||
return;
|
||||
|
||||
// If the window is already showing, don't jerk the workspaces around,
|
||||
// just pull it to the current one.
|
||||
uint32 workspace = 1UL << (uint32)current_workspace();
|
||||
uint32 windowWorkspaces = fSettingsWindow->Workspaces();
|
||||
if ((windowWorkspaces & workspace) == 0) {
|
||||
// window in a different workspace, reopen in current
|
||||
fSettingsWindow->SetWorkspaces(workspace);
|
||||
}
|
||||
|
||||
if (fSettingsWindow->IsHidden())
|
||||
fSettingsWindow->Show();
|
||||
else
|
||||
fSettingsWindow->Activate();
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark - file panels
|
||||
|
||||
|
||||
void
|
||||
MainApp::_ShowOpenFilePanel(const BMessage* message)
|
||||
{
|
||||
if (fOpenFilePanel == NULL) {
|
||||
BMessenger target(this);
|
||||
fOpenFilePanel = new BFilePanel(B_OPEN_PANEL, &target);
|
||||
}
|
||||
|
||||
_ShowFilePanel(fOpenFilePanel, M_OPEN_PANEL_RESULT, message,
|
||||
"Open", "Open");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MainApp::_ShowSaveFilePanel(const BMessage* message)
|
||||
{
|
||||
if (fSaveFilePanel == NULL) {
|
||||
BMessenger target(this);
|
||||
fSaveFilePanel = new BFilePanel(B_SAVE_PANEL, &target);
|
||||
}
|
||||
|
||||
_ShowFilePanel(fSaveFilePanel, M_SAVE_PANEL_RESULT, message,
|
||||
"Save", "Save");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MainApp::_ShowFilePanel(BFilePanel* panel, uint32 command,
|
||||
const BMessage* message, const char* defaultTitle,
|
||||
const char* defaultLabel)
|
||||
{
|
||||
// printf("_ShowFilePanel()\n");
|
||||
// message->PrintToStream();
|
||||
|
||||
BMessage panelMessage(command);
|
||||
|
||||
if (message != NULL) {
|
||||
BMessage targetMessage;
|
||||
if (message->FindMessage("message", &targetMessage) == B_OK)
|
||||
panelMessage.AddMessage("message", &targetMessage);
|
||||
|
||||
BMessenger target;
|
||||
if (message->FindMessenger("target", &target) == B_OK)
|
||||
panelMessage.AddMessenger("target", target);
|
||||
|
||||
const char* panelTitle;
|
||||
if (message->FindString("title", &panelTitle) != B_OK)
|
||||
panelTitle = defaultTitle;
|
||||
{
|
||||
BString finalPanelTitle = "MediaPlayer: ";
|
||||
finalPanelTitle << panelTitle;
|
||||
BAutolock lock(panel->Window());
|
||||
panel->Window()->SetTitle(finalPanelTitle.String());
|
||||
}
|
||||
const char* buttonLabel;
|
||||
if (message->FindString("label", &buttonLabel) != B_OK)
|
||||
buttonLabel = defaultLabel;
|
||||
panel->SetButtonLabel(B_DEFAULT_BUTTON, buttonLabel);
|
||||
}
|
||||
|
||||
// panelMessage.PrintToStream();
|
||||
panel->SetMessage(&panelMessage);
|
||||
|
||||
if (fLastFilePanelFolder != entry_ref()) {
|
||||
panel->SetPanelDirectory(&fLastFilePanelFolder);
|
||||
}
|
||||
|
||||
panel->Show();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MainApp::_HandleOpenPanelResult(const BMessage* message)
|
||||
{
|
||||
_HandleFilePanelResult(fOpenFilePanel, message);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MainApp::_HandleSavePanelResult(const BMessage* message)
|
||||
{
|
||||
_HandleFilePanelResult(fSaveFilePanel, message);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MainApp::_HandleFilePanelResult(BFilePanel* panel, const BMessage* message)
|
||||
{
|
||||
// printf("_HandleFilePanelResult()\n");
|
||||
// message->PrintToStream();
|
||||
|
||||
panel->GetPanelDirectory(&fLastFilePanelFolder);
|
||||
|
||||
BMessage targetMessage;
|
||||
if (message->FindMessage("message", &targetMessage) != B_OK)
|
||||
targetMessage.what = message->what;
|
||||
|
||||
BMessenger target;
|
||||
if (message->FindMessenger("target", &target) != B_OK) {
|
||||
if (targetMessage.what == M_OPEN_PANEL_RESULT
|
||||
|| targetMessage.what == M_SAVE_PANEL_RESULT) {
|
||||
// prevent endless message cycle
|
||||
return;
|
||||
}
|
||||
// send result message to ourselves
|
||||
target = BMessenger(this);
|
||||
}
|
||||
|
||||
// copy the important contents of the message
|
||||
// save panel
|
||||
entry_ref directory;
|
||||
if (message->FindRef("directory", &directory) == B_OK)
|
||||
targetMessage.AddRef("directory", &directory);
|
||||
const char* name;
|
||||
if (message->FindString("name", &name) == B_OK)
|
||||
targetMessage.AddString("name", name);
|
||||
// open panel
|
||||
entry_ref ref;
|
||||
for (int32 i = 0; message->FindRef("refs", i, &ref) == B_OK; i++)
|
||||
targetMessage.AddRef("refs", &ref);
|
||||
|
||||
target.SendMessage(&targetMessage);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - main
|
||||
|
||||
|
||||
int
|
||||
|
||||
@@ -22,18 +22,36 @@
|
||||
#define __MAIN_APP_H
|
||||
|
||||
#include <Application.h>
|
||||
#include <Entry.h>
|
||||
|
||||
#include "MainWin.h"
|
||||
|
||||
|
||||
enum {
|
||||
M_PLAYER_QUIT = 'plqt',
|
||||
M_SETTINGS = 'stng',
|
||||
|
||||
M_SHOW_OPEN_PANEL = 'swop',
|
||||
M_SHOW_SAVE_PANEL = 'swsp',
|
||||
// "target" - This BMessenger will be sent the result message.
|
||||
// "message" - This message will be sent back to the target, with
|
||||
// the additional fields that a BFilePanel provides.
|
||||
// If no result message is specified, the constants below
|
||||
// will be used.
|
||||
// "title" - String that will be used to name the panel window.
|
||||
// "label" - String that will be used to name the Default button.
|
||||
|
||||
M_OPEN_PANEL_RESULT = 'oprs',
|
||||
M_SAVE_PANEL_RESULT = 'sprs',
|
||||
|
||||
M_MEDIA_SERVER_STARTED = 'msst',
|
||||
M_MEDIA_SERVER_QUIT = 'msqt'
|
||||
};
|
||||
|
||||
class BFilePanel;
|
||||
class SettingsWindow;
|
||||
|
||||
|
||||
class MainApp : public BApplication {
|
||||
public:
|
||||
MainApp();
|
||||
@@ -55,10 +73,26 @@ private:
|
||||
void _ShowSettingsWindow();
|
||||
void _BroadcastMessage(const BMessage& message);
|
||||
|
||||
void _ShowOpenFilePanel(const BMessage* message);
|
||||
void _ShowSaveFilePanel(const BMessage* message);
|
||||
void _ShowFilePanel(BFilePanel* panel,
|
||||
uint32 command, const BMessage* message,
|
||||
const char* defaultTitle,
|
||||
const char* defaultLabel);
|
||||
|
||||
void _HandleOpenPanelResult(const BMessage* message);
|
||||
void _HandleSavePanelResult(const BMessage* message);
|
||||
void _HandleFilePanelResult(BFilePanel* panel,
|
||||
const BMessage* message);
|
||||
|
||||
int32 fPlayerCount;
|
||||
BWindow* fFirstWindow;
|
||||
SettingsWindow* fSettingsWindow;
|
||||
|
||||
BFilePanel* fOpenFilePanel;
|
||||
BFilePanel* fSaveFilePanel;
|
||||
entry_ref fLastFilePanelFolder;
|
||||
|
||||
bool fMediaServerRunning;
|
||||
bool fMediaAddOnServerRunning;
|
||||
};
|
||||
|
||||
@@ -101,7 +101,6 @@ enum {
|
||||
MainWin::MainWin()
|
||||
: BWindow(BRect(100,100,400,300), NAME, B_TITLED_WINDOW,
|
||||
B_ASYNCHRONOUS_CONTROLS /* | B_WILL_ACCEPT_FIRST_CLICK */),
|
||||
fFilePanel(NULL),
|
||||
fInfoWin(NULL),
|
||||
fPlaylistWindow(NULL),
|
||||
fHasFile(false),
|
||||
@@ -218,7 +217,6 @@ MainWin::~MainWin()
|
||||
fPlaylistWindow->Quit();
|
||||
|
||||
delete fPlaylist;
|
||||
delete fFilePanel;
|
||||
|
||||
// quit the Controller looper thread
|
||||
thread_id controllerThread = fController->Thread();
|
||||
@@ -469,14 +467,17 @@ MainWin::MessageReceived(BMessage *msg)
|
||||
case M_FILE_NEWPLAYER:
|
||||
gMainApp->NewWindow();
|
||||
break;
|
||||
case M_FILE_OPEN:
|
||||
if (!fFilePanel) {
|
||||
fFilePanel = new BFilePanel();
|
||||
fFilePanel->SetTarget(BMessenger(0, this));
|
||||
fFilePanel->SetPanelDirectory("/boot/home/");
|
||||
}
|
||||
fFilePanel->Show();
|
||||
case M_FILE_OPEN: {
|
||||
BMessenger target(this);
|
||||
BMessage result(B_REFS_RECEIVED);
|
||||
BMessage appMessage(M_SHOW_OPEN_PANEL);
|
||||
appMessage.AddMessenger("target", target);
|
||||
appMessage.AddMessage("message", &result);
|
||||
appMessage.AddString("title", "Open Clips");
|
||||
appMessage.AddString("label", "Open");
|
||||
be_app->PostMessage(&appMessage);
|
||||
break;
|
||||
}
|
||||
case M_FILE_INFO:
|
||||
ShowFileInfo();
|
||||
break;
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include <Menu.h>
|
||||
#include <Button.h>
|
||||
#include <Slider.h>
|
||||
#include <FilePanel.h>
|
||||
|
||||
#include "Controller.h"
|
||||
#include "ControllerView.h"
|
||||
@@ -101,7 +100,6 @@ private:
|
||||
BMenuBar* fMenuBar;
|
||||
BView* fBackground;
|
||||
VideoView* fVideoView;
|
||||
BFilePanel* fFilePanel;
|
||||
ControllerView* fControls;
|
||||
InfoWin* fInfoWin;
|
||||
PlaylistWindow* fPlaylistWindow;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <new>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <Alert.h>
|
||||
#include <Autolock.h>
|
||||
|
||||
#include "Playlist.h"
|
||||
@@ -39,8 +40,12 @@ ImportPLItemsCommand::ImportPLItemsCommand(Playlist* playlist,
|
||||
temp.AppendRefs(refsMessage);
|
||||
|
||||
fNewCount = temp.CountItems();
|
||||
if (fNewCount <= 0)
|
||||
if (fNewCount <= 0) {
|
||||
BAlert* alert = new BAlert("Nothing to Play", "None of the files "
|
||||
"you wanted to play appear to be media files.", "Ok");
|
||||
alert->Go(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
fNewRefs = new (nothrow) entry_ref[fNewCount];
|
||||
if (!fNewRefs)
|
||||
|
||||
@@ -75,7 +75,7 @@ static const char* kPathKey = "path";
|
||||
|
||||
|
||||
status_t
|
||||
Playlist::UnArchive(const BMessage* archive)
|
||||
Playlist::Unarchive(const BMessage* archive)
|
||||
{
|
||||
if (archive == NULL)
|
||||
return B_BAD_VALUE;
|
||||
@@ -118,6 +118,61 @@ Playlist::Archive(BMessage* into) const
|
||||
}
|
||||
|
||||
|
||||
static const uint32 kPlaylistMagicBytes = 'MPPL';
|
||||
static const char* kTextPlaylistMimeString = "text/x-playlist";
|
||||
static const char* kBinaryPlaylistMimeString
|
||||
= "application/x-vnd.haiku-playlist";
|
||||
|
||||
status_t
|
||||
Playlist::Unflatten(BDataIO* stream)
|
||||
{
|
||||
if (stream == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
uint32 magicBytes;
|
||||
ssize_t read = stream->Read(&magicBytes, 4);
|
||||
if (read != 4) {
|
||||
if (read < 0)
|
||||
return (status_t)read;
|
||||
return B_IO_ERROR;
|
||||
}
|
||||
|
||||
if (B_LENDIAN_TO_HOST_INT32(magicBytes) != kPlaylistMagicBytes)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
BMessage archive;
|
||||
status_t ret = archive.Unflatten(stream);
|
||||
if (ret != B_OK)
|
||||
return ret;
|
||||
|
||||
|
||||
return Unarchive(&archive);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Playlist::Flatten(BDataIO* stream) const
|
||||
{
|
||||
if (stream == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
BMessage archive;
|
||||
status_t ret = Archive(&archive);
|
||||
if (ret != B_OK)
|
||||
return ret;
|
||||
|
||||
uint32 magicBytes = B_HOST_TO_LENDIAN_INT32(kPlaylistMagicBytes);
|
||||
ssize_t written = stream->Write(&magicBytes, 4);
|
||||
if (written != 4) {
|
||||
if (written < 0)
|
||||
return (status_t)written;
|
||||
return B_IO_ERROR;
|
||||
}
|
||||
|
||||
return archive.Flatten(stream);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - list access
|
||||
|
||||
|
||||
@@ -386,7 +441,7 @@ Playlist::AppendToPlaylistRecursive(const entry_ref& ref, Playlist* playlist)
|
||||
if (_IsMediaFile(mimeString)) {
|
||||
//printf("Adding\n");
|
||||
playlist->AddRef(ref);
|
||||
} else if (_IsPlaylist(mimeString)) {
|
||||
} else if (_IsTextPlaylist(mimeString)) {
|
||||
//printf("RunPlaylist thing\n");
|
||||
BFile file(&ref, B_READ_ONLY);
|
||||
FileReadWrite lineReader(&file);
|
||||
@@ -408,6 +463,11 @@ Playlist::AppendToPlaylistRecursive(const entry_ref& ref, Playlist* playlist)
|
||||
} else
|
||||
printf("Error - No File Found in playlist\n");
|
||||
}
|
||||
} else if (_IsBinaryPlaylist(mimeString)) {
|
||||
BFile file(&ref, B_READ_ONLY);
|
||||
Playlist temp;
|
||||
if (temp.Unflatten(&file) == B_OK)
|
||||
playlist->AdoptPlaylist(temp, playlist->CountItems());
|
||||
} else
|
||||
printf("MIME Type = %s\n", mimeString.String());
|
||||
}
|
||||
@@ -431,30 +491,6 @@ Playlist::playlist_cmp(const void *p1, const void *p2)
|
||||
}
|
||||
|
||||
|
||||
/*static*/ void
|
||||
Playlist::_AddPlayListFileToPlayList(const entry_ref& ref, Playlist* playlist)
|
||||
{
|
||||
|
||||
BFile file(&ref, B_READ_ONLY);
|
||||
FileReadWrite lineReader(&file);
|
||||
|
||||
BString str;
|
||||
while (lineReader.Next(str)) {
|
||||
BPath path = BPath(str.String());
|
||||
entry_ref refPath;
|
||||
status_t err;
|
||||
if ((err = get_ref_for_path(path.Path(), &refPath)) == B_OK) {
|
||||
AppendToPlaylistRecursive(refPath, playlist);
|
||||
} else
|
||||
printf("Error - %s: [%lx]\n", strerror(err), (int32) err);
|
||||
}
|
||||
/*
|
||||
Read line for x to the end of file (while?)
|
||||
make a enty_ref and call AppendToPlaylistRecursive(with new entry, playlist)
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
/*static*/ bool
|
||||
Playlist::_IsMediaFile(const BString& mimeString)
|
||||
{
|
||||
@@ -472,9 +508,16 @@ Playlist::_IsMediaFile(const BString& mimeString)
|
||||
|
||||
|
||||
/*static*/ bool
|
||||
Playlist::_IsPlaylist(const BString& mimeString)
|
||||
Playlist::_IsTextPlaylist(const BString& mimeString)
|
||||
{
|
||||
return mimeString.Compare("text/x-playlist") == 0;
|
||||
return mimeString.Compare(kTextPlaylistMimeString) == 0;
|
||||
}
|
||||
|
||||
|
||||
/*static*/ bool
|
||||
Playlist::_IsBinaryPlaylist(const BString& mimeString)
|
||||
{
|
||||
return mimeString.Compare(kBinaryPlaylistMimeString) == 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <List.h>
|
||||
#include <Locker.h>
|
||||
|
||||
class BDataIO;
|
||||
class BMessage;
|
||||
class BString;
|
||||
|
||||
@@ -49,9 +50,12 @@ public:
|
||||
Playlist();
|
||||
~Playlist();
|
||||
// archiving
|
||||
status_t UnArchive(const BMessage* archive);
|
||||
status_t Unarchive(const BMessage* archive);
|
||||
status_t Archive(BMessage* into) const;
|
||||
|
||||
status_t Unflatten(BDataIO* stream);
|
||||
status_t Flatten(BDataIO* stream) const;
|
||||
|
||||
|
||||
// list functionality
|
||||
void MakeEmpty();
|
||||
@@ -91,10 +95,9 @@ public:
|
||||
private:
|
||||
static int playlist_cmp(const void* p1, const void* p2);
|
||||
static bool _IsMediaFile(const BString& mimeString);
|
||||
static bool _IsPlaylist(const BString& mimeString);
|
||||
static bool _IsTextPlaylist(const BString& mimeString);
|
||||
static bool _IsBinaryPlaylist(const BString& mimeString);
|
||||
static BString _MIMEString(const entry_ref* entry);
|
||||
static void _AddPlayListFileToPlayList(const entry_ref& ref,
|
||||
Playlist* playlist);
|
||||
void _NotifyRefAdded(const entry_ref& ref,
|
||||
int32 index) const;
|
||||
void _NotifyRefRemoved(int32 index) const;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2007, Haiku. All rights reserved.
|
||||
* Copyright 2007-2008, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
@@ -11,12 +11,17 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <Alert.h>
|
||||
#include <Application.h>
|
||||
#include <Autolock.h>
|
||||
#include <Entry.h>
|
||||
#include <File.h>
|
||||
#include <Roster.h>
|
||||
#include <Path.h>
|
||||
#include <Menu.h>
|
||||
#include <MenuBar.h>
|
||||
#include <MenuItem.h>
|
||||
#include <NodeInfo.h>
|
||||
#include <ScrollBar.h>
|
||||
#include <ScrollView.h>
|
||||
#include <String.h>
|
||||
@@ -25,6 +30,7 @@
|
||||
#include <FilePanel.h>
|
||||
|
||||
#include "CommandStack.h"
|
||||
#include "MainApp.h"
|
||||
#include "PlaylistListView.h"
|
||||
#include "RWLocker.h"
|
||||
|
||||
@@ -34,6 +40,7 @@ enum {
|
||||
// file
|
||||
M_PLAYLIST_OPEN = 'open',
|
||||
M_PLAYLIST_SAVE = 'save',
|
||||
M_PLAYLIST_SAVE_RESULT = 'psrs',
|
||||
|
||||
// edit
|
||||
M_PLAYLIST_EMPTY = 'emty',
|
||||
@@ -45,12 +52,11 @@ enum {
|
||||
PlaylistWindow::PlaylistWindow(BRect frame, Playlist* playlist,
|
||||
Controller* controller)
|
||||
: BWindow(frame, "Playlist", B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
|
||||
B_ASYNCHRONOUS_CONTROLS)
|
||||
, fOpenPanel(NULL)
|
||||
, fSavePanel(NULL)
|
||||
, fLocker(new RWLocker("command stack lock"))
|
||||
, fCommandStack(new CommandStack(fLocker))
|
||||
, fCommandStackListener(this)
|
||||
B_ASYNCHRONOUS_CONTROLS),
|
||||
fPlaylist(playlist),
|
||||
fLocker(new RWLocker("command stack lock")),
|
||||
fCommandStack(new CommandStack(fLocker)),
|
||||
fCommandStackListener(this)
|
||||
{
|
||||
frame = Bounds();
|
||||
|
||||
@@ -89,9 +95,6 @@ PlaylistWindow::~PlaylistWindow()
|
||||
fCommandStack->RemoveListener(&fCommandStackListener);
|
||||
delete fCommandStack;
|
||||
delete fLocker;
|
||||
|
||||
delete fOpenPanel;
|
||||
delete fSavePanel;
|
||||
}
|
||||
|
||||
|
||||
@@ -138,20 +141,32 @@ PlaylistWindow::MessageReceived(BMessage* message)
|
||||
break;
|
||||
}
|
||||
|
||||
case M_PLAYLIST_SAVE:
|
||||
if (!fSavePanel)
|
||||
fSavePanel = new BFilePanel(B_SAVE_PANEL);
|
||||
fSavePanel->Show();
|
||||
case M_PLAYLIST_OPEN: {
|
||||
BMessenger target(this);
|
||||
BMessage result(B_REFS_RECEIVED);
|
||||
BMessage appMessage(M_SHOW_OPEN_PANEL);
|
||||
appMessage.AddMessenger("target", target);
|
||||
appMessage.AddMessage("message", &result);
|
||||
appMessage.AddString("title", "Open Playlist");
|
||||
appMessage.AddString("label", "Open");
|
||||
be_app->PostMessage(&appMessage);
|
||||
break;
|
||||
case B_SAVE_REQUESTED:
|
||||
printf("We are saving\n");
|
||||
//Use fListView and have a SaveToFile?
|
||||
}
|
||||
case M_PLAYLIST_SAVE: {
|
||||
BMessenger target(this);
|
||||
BMessage result(M_PLAYLIST_SAVE_RESULT);
|
||||
BMessage appMessage(M_SHOW_SAVE_PANEL);
|
||||
appMessage.AddMessenger("target", target);
|
||||
appMessage.AddMessage("message", &result);
|
||||
appMessage.AddString("title", "Save Playlist");
|
||||
appMessage.AddString("label", "Save");
|
||||
be_app->PostMessage(&appMessage);
|
||||
break;
|
||||
case M_PLAYLIST_OPEN:
|
||||
if (!fOpenPanel)
|
||||
fOpenPanel = new BFilePanel(B_OPEN_PANEL);
|
||||
fOpenPanel->Show();
|
||||
}
|
||||
case M_PLAYLIST_SAVE_RESULT: {
|
||||
_SavePlaylist(message);
|
||||
break;
|
||||
}
|
||||
|
||||
case M_PLAYLIST_EMPTY:
|
||||
fListView->RemoveAll();
|
||||
@@ -177,11 +192,11 @@ PlaylistWindow::_CreateMenu(BRect& frame)
|
||||
BMenuBar* menuBar = new BMenuBar(frame, "main menu");
|
||||
BMenu* fileMenu = new BMenu("Playlist");
|
||||
menuBar->AddItem(fileMenu);
|
||||
// fileMenu->AddItem(new BMenuItem("Open"B_UTF8_ELLIPSIS,
|
||||
// new BMessage(M_PLAYLIST_OPEN), 'O'));
|
||||
// fileMenu->AddItem(new BMenuItem("Save"B_UTF8_ELLIPSIS,
|
||||
// new BMessage(M_PLAYLIST_SAVE), 'S'));
|
||||
// fileMenu->AddSeparatorItem();
|
||||
fileMenu->AddItem(new BMenuItem("Open"B_UTF8_ELLIPSIS,
|
||||
new BMessage(M_PLAYLIST_OPEN), 'O'));
|
||||
fileMenu->AddItem(new BMenuItem("Save"B_UTF8_ELLIPSIS,
|
||||
new BMessage(M_PLAYLIST_SAVE), 'S'));
|
||||
fileMenu->AddSeparatorItem();
|
||||
fileMenu->AddItem(new BMenuItem("Close",
|
||||
new BMessage(B_QUIT_REQUESTED), 'W'));
|
||||
|
||||
@@ -207,7 +222,6 @@ PlaylistWindow::_CreateMenu(BRect& frame)
|
||||
}
|
||||
|
||||
|
||||
// _ObjectChanged
|
||||
void
|
||||
PlaylistWindow::_ObjectChanged(const Notifier* object)
|
||||
{
|
||||
@@ -230,3 +244,108 @@ PlaylistWindow::_ObjectChanged(const Notifier* object)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
display_save_alert(const char* message)
|
||||
{
|
||||
BAlert* alert = new BAlert("Save Error", message, "Ok", NULL, NULL,
|
||||
B_WIDTH_AS_USUAL, B_STOP_ALERT);
|
||||
alert->Go(NULL);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
display_save_alert(status_t error)
|
||||
{
|
||||
BString errorMessage("Saving the playlist failed.\n\nError: ");
|
||||
errorMessage << strerror(error);
|
||||
display_save_alert(errorMessage.String());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistWindow::_SavePlaylist(const BMessage* message)
|
||||
{
|
||||
entry_ref ref;
|
||||
const char* name;
|
||||
if (message->FindRef("directory", &ref) != B_OK
|
||||
|| message->FindString("name", &name) != B_OK) {
|
||||
display_save_alert("Internal error (malformed message). "
|
||||
"Saving the Playlist failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
BString tempName(name);
|
||||
tempName << system_time();
|
||||
|
||||
BPath origPath(&ref);
|
||||
BPath tempPath(&ref);
|
||||
if (origPath.InitCheck() != B_OK || tempPath.InitCheck() != B_OK
|
||||
|| origPath.Append(name) != B_OK
|
||||
|| tempPath.Append(tempName.String()) != B_OK) {
|
||||
display_save_alert("Internal error (out of memory). "
|
||||
"Saving the Playlist failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
BEntry origEntry(origPath.Path());
|
||||
BEntry tempEntry(tempPath.Path());
|
||||
if (origEntry.InitCheck() != B_OK || tempEntry.InitCheck() != B_OK) {
|
||||
display_save_alert("Internal error (out of memory). "
|
||||
"Saving the Playlist failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
class TempEntryRemover {
|
||||
public:
|
||||
TempEntryRemover(BEntry* entry)
|
||||
: fEntry(entry)
|
||||
{
|
||||
}
|
||||
~TempEntryRemover()
|
||||
{
|
||||
if (fEntry)
|
||||
fEntry->Remove();
|
||||
}
|
||||
void Detach()
|
||||
{
|
||||
fEntry = NULL;
|
||||
}
|
||||
private:
|
||||
BEntry* fEntry;
|
||||
} remover(&tempEntry);
|
||||
|
||||
BFile file(&tempEntry, B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY);
|
||||
if (file.InitCheck() != B_OK) {
|
||||
BString errorMessage("Saving the playlist failed:\n\nError: ");
|
||||
errorMessage << strerror(file.InitCheck());
|
||||
display_save_alert(errorMessage.String());
|
||||
return;
|
||||
}
|
||||
|
||||
AutoLocker<Playlist> lock(fPlaylist);
|
||||
if (!lock.IsLocked()) {
|
||||
display_save_alert("Internal error (locking failed). "
|
||||
"Saving the Playlist failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
status_t ret = fPlaylist->Flatten(&file);
|
||||
if (ret != B_OK) {
|
||||
display_save_alert(ret);
|
||||
return;
|
||||
}
|
||||
lock.Unlock();
|
||||
|
||||
if (origEntry.Exists()) {
|
||||
// TODO: copy attributes
|
||||
}
|
||||
|
||||
// clobber original entry, if it exists
|
||||
tempEntry.Rename(name, true);
|
||||
remover.Detach();
|
||||
|
||||
BNodeInfo info(&file);
|
||||
info.SetType("application/x-vnd.haiku-playlist");
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ class PlaylistWindow : public BWindow {
|
||||
private:
|
||||
void _CreateMenu(BRect& frame);
|
||||
void _ObjectChanged(const Notifier* object);
|
||||
void _SavePlaylist(const BMessage* message);
|
||||
|
||||
Playlist* fPlaylist;
|
||||
PlaylistListView* fListView;
|
||||
@@ -47,9 +48,6 @@ class PlaylistWindow : public BWindow {
|
||||
BMenuItem* fUndoMI;
|
||||
BMenuItem* fRedoMI;
|
||||
|
||||
BFilePanel* fOpenPanel;
|
||||
BFilePanel* fSavePanel;
|
||||
|
||||
RWLocker* fLocker;
|
||||
CommandStack* fCommandStack;
|
||||
ListenerAdapter fCommandStackListener;
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
|
||||
#ifdef __HAIKU__
|
||||
# include <GridLayoutBuilder.h>
|
||||
# include <GroupLayout.h>
|
||||
# include <GroupLayoutBuilder.h>
|
||||
# include <SpaceLayoutItem.h>
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user