* 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
|
* MainApp.cpp - Media Player for the Haiku Operating System
|
||||||
*
|
*
|
||||||
* Copyright (C) 2006 Marcus Overhagen <[email protected]>
|
* 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
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
#include <Alert.h>
|
#include <Alert.h>
|
||||||
#include <Autolock.h>
|
#include <Autolock.h>
|
||||||
#include <Entry.h>
|
#include <Entry.h>
|
||||||
|
#include <FilePanel.h>
|
||||||
#include <MediaRoster.h>
|
#include <MediaRoster.h>
|
||||||
#include <Path.h>
|
#include <Path.h>
|
||||||
#include <Roster.h>
|
#include <Roster.h>
|
||||||
@@ -35,7 +36,7 @@
|
|||||||
#include "SettingsWindow.h"
|
#include "SettingsWindow.h"
|
||||||
|
|
||||||
|
|
||||||
MainApp *gMainApp;
|
MainApp* gMainApp;
|
||||||
const char* kAppSig = "application/x-vnd.Haiku-MediaPlayer";
|
const char* kAppSig = "application/x-vnd.Haiku-MediaPlayer";
|
||||||
|
|
||||||
static const char* kMediaServerSig = "application/x-vnd.Be.media-server";
|
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()
|
MainApp::MainApp()
|
||||||
: BApplication(kAppSig),
|
: BApplication(kAppSig),
|
||||||
fPlayerCount(0),
|
fPlayerCount(0),
|
||||||
//fFirstWindow(NewWindow()),
|
fFirstWindow(NULL),
|
||||||
fSettingsWindow(NULL),
|
fSettingsWindow(NULL),
|
||||||
|
|
||||||
|
fOpenFilePanel(NULL),
|
||||||
|
fSaveFilePanel(NULL),
|
||||||
|
fLastFilePanelFolder(),
|
||||||
|
|
||||||
fMediaServerRunning(false),
|
fMediaServerRunning(false),
|
||||||
fMediaAddOnServerRunning(false)
|
fMediaAddOnServerRunning(false)
|
||||||
{
|
{
|
||||||
@@ -56,6 +61,8 @@ MainApp::MainApp()
|
|||||||
|
|
||||||
MainApp::~MainApp()
|
MainApp::~MainApp()
|
||||||
{
|
{
|
||||||
|
delete fOpenFilePanel;
|
||||||
|
delete fSaveFilePanel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -63,7 +70,8 @@ bool
|
|||||||
MainApp::QuitRequested()
|
MainApp::QuitRequested()
|
||||||
{
|
{
|
||||||
// Note: This needs to be done here, SettingsWindow::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())
|
if (fSettingsWindow && fSettingsWindow->Lock())
|
||||||
fSettingsWindow->Quit();
|
fSettingsWindow->Quit();
|
||||||
fSettingsWindow = NULL;
|
fSettingsWindow = NULL;
|
||||||
@@ -76,7 +84,7 @@ BWindow*
|
|||||||
MainApp::FirstWindow()
|
MainApp::FirstWindow()
|
||||||
{
|
{
|
||||||
BAutolock _(this);
|
BAutolock _(this);
|
||||||
if (fFirstWindow)
|
if (fFirstWindow != NULL)
|
||||||
return fFirstWindow;
|
return fFirstWindow;
|
||||||
return NewWindow();
|
return NewWindow();
|
||||||
}
|
}
|
||||||
@@ -85,13 +93,12 @@ MainApp::FirstWindow()
|
|||||||
BWindow*
|
BWindow*
|
||||||
MainApp::NewWindow()
|
MainApp::NewWindow()
|
||||||
{
|
{
|
||||||
BWindow* win;
|
|
||||||
BAutolock _(this);
|
BAutolock _(this);
|
||||||
fPlayerCount++;
|
fPlayerCount++;
|
||||||
win = new MainWin();
|
BWindow* window = new MainWin();
|
||||||
if (!fFirstWindow)
|
if (fFirstWindow == NULL)
|
||||||
fFirstWindow = win;
|
fFirstWindow = window;
|
||||||
return win;
|
return window;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -130,7 +137,7 @@ MainApp::ReadyToRun()
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
MainApp::RefsReceived(BMessage *msg)
|
MainApp::RefsReceived(BMessage* message)
|
||||||
{
|
{
|
||||||
// The user dropped a file (or files) on this app's icon,
|
// The user dropped a file (or files) on this app's icon,
|
||||||
// or double clicked a file that's handled by this app.
|
// or double clicked a file that's handled by this app.
|
||||||
@@ -142,14 +149,9 @@ MainApp::RefsReceived(BMessage *msg)
|
|||||||
// window.
|
// window.
|
||||||
printf("MainApp::RefsReceived\n");
|
printf("MainApp::RefsReceived\n");
|
||||||
|
|
||||||
entry_ref ref;
|
BWindow* window = NewWindow();
|
||||||
for (int i = 0; B_OK == msg->FindRef("refs", i, &ref); i++) {
|
if (window)
|
||||||
BWindow *win;
|
window->PostMessage(message);
|
||||||
win = NewWindow();
|
|
||||||
BMessage m(B_REFS_RECEIVED);
|
|
||||||
m.AddRef("refs", &ref);
|
|
||||||
win->PostMessage(&m);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -245,6 +247,20 @@ MainApp::MessageReceived(BMessage* message)
|
|||||||
_ShowSettingsWindow();
|
_ShowSettingsWindow();
|
||||||
break;
|
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:
|
default:
|
||||||
BApplication::MessageReceived(message);
|
BApplication::MessageReceived(message);
|
||||||
break;
|
break;
|
||||||
@@ -259,6 +275,9 @@ MainApp::AboutRequested()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
MainApp::_BroadcastMessage(const BMessage& _message)
|
MainApp::_BroadcastMessage(const BMessage& _message)
|
||||||
{
|
{
|
||||||
@@ -272,17 +291,155 @@ MainApp::_BroadcastMessage(const BMessage& _message)
|
|||||||
void
|
void
|
||||||
MainApp::_ShowSettingsWindow()
|
MainApp::_ShowSettingsWindow()
|
||||||
{
|
{
|
||||||
if (fSettingsWindow->Lock()) {
|
BAutolock lock(fSettingsWindow);
|
||||||
if (fSettingsWindow->IsHidden())
|
if (!lock.IsLocked())
|
||||||
fSettingsWindow->Show();
|
return;
|
||||||
else
|
|
||||||
fSettingsWindow->Activate();
|
// If the window is already showing, don't jerk the workspaces around,
|
||||||
fSettingsWindow->Unlock();
|
// 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
|
int
|
||||||
|
|||||||
@@ -22,18 +22,36 @@
|
|||||||
#define __MAIN_APP_H
|
#define __MAIN_APP_H
|
||||||
|
|
||||||
#include <Application.h>
|
#include <Application.h>
|
||||||
|
#include <Entry.h>
|
||||||
|
|
||||||
#include "MainWin.h"
|
#include "MainWin.h"
|
||||||
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
M_PLAYER_QUIT = 'plqt',
|
M_PLAYER_QUIT = 'plqt',
|
||||||
M_SETTINGS = 'stng',
|
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_STARTED = 'msst',
|
||||||
M_MEDIA_SERVER_QUIT = 'msqt'
|
M_MEDIA_SERVER_QUIT = 'msqt'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class BFilePanel;
|
||||||
class SettingsWindow;
|
class SettingsWindow;
|
||||||
|
|
||||||
|
|
||||||
class MainApp : public BApplication {
|
class MainApp : public BApplication {
|
||||||
public:
|
public:
|
||||||
MainApp();
|
MainApp();
|
||||||
@@ -55,10 +73,26 @@ private:
|
|||||||
void _ShowSettingsWindow();
|
void _ShowSettingsWindow();
|
||||||
void _BroadcastMessage(const BMessage& message);
|
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;
|
int32 fPlayerCount;
|
||||||
BWindow* fFirstWindow;
|
BWindow* fFirstWindow;
|
||||||
SettingsWindow* fSettingsWindow;
|
SettingsWindow* fSettingsWindow;
|
||||||
|
|
||||||
|
BFilePanel* fOpenFilePanel;
|
||||||
|
BFilePanel* fSaveFilePanel;
|
||||||
|
entry_ref fLastFilePanelFolder;
|
||||||
|
|
||||||
bool fMediaServerRunning;
|
bool fMediaServerRunning;
|
||||||
bool fMediaAddOnServerRunning;
|
bool fMediaAddOnServerRunning;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -101,7 +101,6 @@ enum {
|
|||||||
MainWin::MainWin()
|
MainWin::MainWin()
|
||||||
: BWindow(BRect(100,100,400,300), NAME, B_TITLED_WINDOW,
|
: BWindow(BRect(100,100,400,300), NAME, B_TITLED_WINDOW,
|
||||||
B_ASYNCHRONOUS_CONTROLS /* | B_WILL_ACCEPT_FIRST_CLICK */),
|
B_ASYNCHRONOUS_CONTROLS /* | B_WILL_ACCEPT_FIRST_CLICK */),
|
||||||
fFilePanel(NULL),
|
|
||||||
fInfoWin(NULL),
|
fInfoWin(NULL),
|
||||||
fPlaylistWindow(NULL),
|
fPlaylistWindow(NULL),
|
||||||
fHasFile(false),
|
fHasFile(false),
|
||||||
@@ -218,7 +217,6 @@ MainWin::~MainWin()
|
|||||||
fPlaylistWindow->Quit();
|
fPlaylistWindow->Quit();
|
||||||
|
|
||||||
delete fPlaylist;
|
delete fPlaylist;
|
||||||
delete fFilePanel;
|
|
||||||
|
|
||||||
// quit the Controller looper thread
|
// quit the Controller looper thread
|
||||||
thread_id controllerThread = fController->Thread();
|
thread_id controllerThread = fController->Thread();
|
||||||
@@ -469,14 +467,17 @@ MainWin::MessageReceived(BMessage *msg)
|
|||||||
case M_FILE_NEWPLAYER:
|
case M_FILE_NEWPLAYER:
|
||||||
gMainApp->NewWindow();
|
gMainApp->NewWindow();
|
||||||
break;
|
break;
|
||||||
case M_FILE_OPEN:
|
case M_FILE_OPEN: {
|
||||||
if (!fFilePanel) {
|
BMessenger target(this);
|
||||||
fFilePanel = new BFilePanel();
|
BMessage result(B_REFS_RECEIVED);
|
||||||
fFilePanel->SetTarget(BMessenger(0, this));
|
BMessage appMessage(M_SHOW_OPEN_PANEL);
|
||||||
fFilePanel->SetPanelDirectory("/boot/home/");
|
appMessage.AddMessenger("target", target);
|
||||||
}
|
appMessage.AddMessage("message", &result);
|
||||||
fFilePanel->Show();
|
appMessage.AddString("title", "Open Clips");
|
||||||
|
appMessage.AddString("label", "Open");
|
||||||
|
be_app->PostMessage(&appMessage);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case M_FILE_INFO:
|
case M_FILE_INFO:
|
||||||
ShowFileInfo();
|
ShowFileInfo();
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
#include <Menu.h>
|
#include <Menu.h>
|
||||||
#include <Button.h>
|
#include <Button.h>
|
||||||
#include <Slider.h>
|
#include <Slider.h>
|
||||||
#include <FilePanel.h>
|
|
||||||
|
|
||||||
#include "Controller.h"
|
#include "Controller.h"
|
||||||
#include "ControllerView.h"
|
#include "ControllerView.h"
|
||||||
@@ -101,7 +100,6 @@ private:
|
|||||||
BMenuBar* fMenuBar;
|
BMenuBar* fMenuBar;
|
||||||
BView* fBackground;
|
BView* fBackground;
|
||||||
VideoView* fVideoView;
|
VideoView* fVideoView;
|
||||||
BFilePanel* fFilePanel;
|
|
||||||
ControllerView* fControls;
|
ControllerView* fControls;
|
||||||
InfoWin* fInfoWin;
|
InfoWin* fInfoWin;
|
||||||
PlaylistWindow* fPlaylistWindow;
|
PlaylistWindow* fPlaylistWindow;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <new>
|
#include <new>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <Alert.h>
|
||||||
#include <Autolock.h>
|
#include <Autolock.h>
|
||||||
|
|
||||||
#include "Playlist.h"
|
#include "Playlist.h"
|
||||||
@@ -39,8 +40,12 @@ ImportPLItemsCommand::ImportPLItemsCommand(Playlist* playlist,
|
|||||||
temp.AppendRefs(refsMessage);
|
temp.AppendRefs(refsMessage);
|
||||||
|
|
||||||
fNewCount = temp.CountItems();
|
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;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
fNewRefs = new (nothrow) entry_ref[fNewCount];
|
fNewRefs = new (nothrow) entry_ref[fNewCount];
|
||||||
if (!fNewRefs)
|
if (!fNewRefs)
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ static const char* kPathKey = "path";
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Playlist::UnArchive(const BMessage* archive)
|
Playlist::Unarchive(const BMessage* archive)
|
||||||
{
|
{
|
||||||
if (archive == NULL)
|
if (archive == NULL)
|
||||||
return B_BAD_VALUE;
|
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
|
// #pragma mark - list access
|
||||||
|
|
||||||
|
|
||||||
@@ -386,7 +441,7 @@ Playlist::AppendToPlaylistRecursive(const entry_ref& ref, Playlist* playlist)
|
|||||||
if (_IsMediaFile(mimeString)) {
|
if (_IsMediaFile(mimeString)) {
|
||||||
//printf("Adding\n");
|
//printf("Adding\n");
|
||||||
playlist->AddRef(ref);
|
playlist->AddRef(ref);
|
||||||
} else if (_IsPlaylist(mimeString)) {
|
} else if (_IsTextPlaylist(mimeString)) {
|
||||||
//printf("RunPlaylist thing\n");
|
//printf("RunPlaylist thing\n");
|
||||||
BFile file(&ref, B_READ_ONLY);
|
BFile file(&ref, B_READ_ONLY);
|
||||||
FileReadWrite lineReader(&file);
|
FileReadWrite lineReader(&file);
|
||||||
@@ -408,6 +463,11 @@ Playlist::AppendToPlaylistRecursive(const entry_ref& ref, Playlist* playlist)
|
|||||||
} else
|
} else
|
||||||
printf("Error - No File Found in playlist\n");
|
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
|
} else
|
||||||
printf("MIME Type = %s\n", mimeString.String());
|
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
|
/*static*/ bool
|
||||||
Playlist::_IsMediaFile(const BString& mimeString)
|
Playlist::_IsMediaFile(const BString& mimeString)
|
||||||
{
|
{
|
||||||
@@ -472,9 +508,16 @@ Playlist::_IsMediaFile(const BString& mimeString)
|
|||||||
|
|
||||||
|
|
||||||
/*static*/ bool
|
/*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 <List.h>
|
||||||
#include <Locker.h>
|
#include <Locker.h>
|
||||||
|
|
||||||
|
class BDataIO;
|
||||||
class BMessage;
|
class BMessage;
|
||||||
class BString;
|
class BString;
|
||||||
|
|
||||||
@@ -49,9 +50,12 @@ public:
|
|||||||
Playlist();
|
Playlist();
|
||||||
~Playlist();
|
~Playlist();
|
||||||
// archiving
|
// archiving
|
||||||
status_t UnArchive(const BMessage* archive);
|
status_t Unarchive(const BMessage* archive);
|
||||||
status_t Archive(BMessage* into) const;
|
status_t Archive(BMessage* into) const;
|
||||||
|
|
||||||
|
status_t Unflatten(BDataIO* stream);
|
||||||
|
status_t Flatten(BDataIO* stream) const;
|
||||||
|
|
||||||
|
|
||||||
// list functionality
|
// list functionality
|
||||||
void MakeEmpty();
|
void MakeEmpty();
|
||||||
@@ -91,10 +95,9 @@ public:
|
|||||||
private:
|
private:
|
||||||
static int playlist_cmp(const void* p1, const void* p2);
|
static int playlist_cmp(const void* p1, const void* p2);
|
||||||
static bool _IsMediaFile(const BString& mimeString);
|
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 BString _MIMEString(const entry_ref* entry);
|
||||||
static void _AddPlayListFileToPlayList(const entry_ref& ref,
|
|
||||||
Playlist* playlist);
|
|
||||||
void _NotifyRefAdded(const entry_ref& ref,
|
void _NotifyRefAdded(const entry_ref& ref,
|
||||||
int32 index) const;
|
int32 index) const;
|
||||||
void _NotifyRefRemoved(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.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
@@ -11,12 +11,17 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <Alert.h>
|
||||||
#include <Application.h>
|
#include <Application.h>
|
||||||
|
#include <Autolock.h>
|
||||||
|
#include <Entry.h>
|
||||||
|
#include <File.h>
|
||||||
#include <Roster.h>
|
#include <Roster.h>
|
||||||
#include <Path.h>
|
#include <Path.h>
|
||||||
#include <Menu.h>
|
#include <Menu.h>
|
||||||
#include <MenuBar.h>
|
#include <MenuBar.h>
|
||||||
#include <MenuItem.h>
|
#include <MenuItem.h>
|
||||||
|
#include <NodeInfo.h>
|
||||||
#include <ScrollBar.h>
|
#include <ScrollBar.h>
|
||||||
#include <ScrollView.h>
|
#include <ScrollView.h>
|
||||||
#include <String.h>
|
#include <String.h>
|
||||||
@@ -25,6 +30,7 @@
|
|||||||
#include <FilePanel.h>
|
#include <FilePanel.h>
|
||||||
|
|
||||||
#include "CommandStack.h"
|
#include "CommandStack.h"
|
||||||
|
#include "MainApp.h"
|
||||||
#include "PlaylistListView.h"
|
#include "PlaylistListView.h"
|
||||||
#include "RWLocker.h"
|
#include "RWLocker.h"
|
||||||
|
|
||||||
@@ -34,6 +40,7 @@ enum {
|
|||||||
// file
|
// file
|
||||||
M_PLAYLIST_OPEN = 'open',
|
M_PLAYLIST_OPEN = 'open',
|
||||||
M_PLAYLIST_SAVE = 'save',
|
M_PLAYLIST_SAVE = 'save',
|
||||||
|
M_PLAYLIST_SAVE_RESULT = 'psrs',
|
||||||
|
|
||||||
// edit
|
// edit
|
||||||
M_PLAYLIST_EMPTY = 'emty',
|
M_PLAYLIST_EMPTY = 'emty',
|
||||||
@@ -45,12 +52,11 @@ enum {
|
|||||||
PlaylistWindow::PlaylistWindow(BRect frame, Playlist* playlist,
|
PlaylistWindow::PlaylistWindow(BRect frame, Playlist* playlist,
|
||||||
Controller* controller)
|
Controller* controller)
|
||||||
: BWindow(frame, "Playlist", B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
|
: BWindow(frame, "Playlist", B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
|
||||||
B_ASYNCHRONOUS_CONTROLS)
|
B_ASYNCHRONOUS_CONTROLS),
|
||||||
, fOpenPanel(NULL)
|
fPlaylist(playlist),
|
||||||
, fSavePanel(NULL)
|
fLocker(new RWLocker("command stack lock")),
|
||||||
, fLocker(new RWLocker("command stack lock"))
|
fCommandStack(new CommandStack(fLocker)),
|
||||||
, fCommandStack(new CommandStack(fLocker))
|
fCommandStackListener(this)
|
||||||
, fCommandStackListener(this)
|
|
||||||
{
|
{
|
||||||
frame = Bounds();
|
frame = Bounds();
|
||||||
|
|
||||||
@@ -89,9 +95,6 @@ PlaylistWindow::~PlaylistWindow()
|
|||||||
fCommandStack->RemoveListener(&fCommandStackListener);
|
fCommandStack->RemoveListener(&fCommandStackListener);
|
||||||
delete fCommandStack;
|
delete fCommandStack;
|
||||||
delete fLocker;
|
delete fLocker;
|
||||||
|
|
||||||
delete fOpenPanel;
|
|
||||||
delete fSavePanel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -138,20 +141,32 @@ PlaylistWindow::MessageReceived(BMessage* message)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case M_PLAYLIST_SAVE:
|
case M_PLAYLIST_OPEN: {
|
||||||
if (!fSavePanel)
|
BMessenger target(this);
|
||||||
fSavePanel = new BFilePanel(B_SAVE_PANEL);
|
BMessage result(B_REFS_RECEIVED);
|
||||||
fSavePanel->Show();
|
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;
|
break;
|
||||||
case B_SAVE_REQUESTED:
|
}
|
||||||
printf("We are saving\n");
|
case M_PLAYLIST_SAVE: {
|
||||||
//Use fListView and have a SaveToFile?
|
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;
|
break;
|
||||||
case M_PLAYLIST_OPEN:
|
}
|
||||||
if (!fOpenPanel)
|
case M_PLAYLIST_SAVE_RESULT: {
|
||||||
fOpenPanel = new BFilePanel(B_OPEN_PANEL);
|
_SavePlaylist(message);
|
||||||
fOpenPanel->Show();
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case M_PLAYLIST_EMPTY:
|
case M_PLAYLIST_EMPTY:
|
||||||
fListView->RemoveAll();
|
fListView->RemoveAll();
|
||||||
@@ -177,11 +192,11 @@ PlaylistWindow::_CreateMenu(BRect& frame)
|
|||||||
BMenuBar* menuBar = new BMenuBar(frame, "main menu");
|
BMenuBar* menuBar = new BMenuBar(frame, "main menu");
|
||||||
BMenu* fileMenu = new BMenu("Playlist");
|
BMenu* fileMenu = new BMenu("Playlist");
|
||||||
menuBar->AddItem(fileMenu);
|
menuBar->AddItem(fileMenu);
|
||||||
// fileMenu->AddItem(new BMenuItem("Open"B_UTF8_ELLIPSIS,
|
fileMenu->AddItem(new BMenuItem("Open"B_UTF8_ELLIPSIS,
|
||||||
// new BMessage(M_PLAYLIST_OPEN), 'O'));
|
new BMessage(M_PLAYLIST_OPEN), 'O'));
|
||||||
// fileMenu->AddItem(new BMenuItem("Save"B_UTF8_ELLIPSIS,
|
fileMenu->AddItem(new BMenuItem("Save"B_UTF8_ELLIPSIS,
|
||||||
// new BMessage(M_PLAYLIST_SAVE), 'S'));
|
new BMessage(M_PLAYLIST_SAVE), 'S'));
|
||||||
// fileMenu->AddSeparatorItem();
|
fileMenu->AddSeparatorItem();
|
||||||
fileMenu->AddItem(new BMenuItem("Close",
|
fileMenu->AddItem(new BMenuItem("Close",
|
||||||
new BMessage(B_QUIT_REQUESTED), 'W'));
|
new BMessage(B_QUIT_REQUESTED), 'W'));
|
||||||
|
|
||||||
@@ -207,7 +222,6 @@ PlaylistWindow::_CreateMenu(BRect& frame)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// _ObjectChanged
|
|
||||||
void
|
void
|
||||||
PlaylistWindow::_ObjectChanged(const Notifier* object)
|
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:
|
private:
|
||||||
void _CreateMenu(BRect& frame);
|
void _CreateMenu(BRect& frame);
|
||||||
void _ObjectChanged(const Notifier* object);
|
void _ObjectChanged(const Notifier* object);
|
||||||
|
void _SavePlaylist(const BMessage* message);
|
||||||
|
|
||||||
Playlist* fPlaylist;
|
Playlist* fPlaylist;
|
||||||
PlaylistListView* fListView;
|
PlaylistListView* fListView;
|
||||||
@@ -47,9 +48,6 @@ class PlaylistWindow : public BWindow {
|
|||||||
BMenuItem* fUndoMI;
|
BMenuItem* fUndoMI;
|
||||||
BMenuItem* fRedoMI;
|
BMenuItem* fRedoMI;
|
||||||
|
|
||||||
BFilePanel* fOpenPanel;
|
|
||||||
BFilePanel* fSavePanel;
|
|
||||||
|
|
||||||
RWLocker* fLocker;
|
RWLocker* fLocker;
|
||||||
CommandStack* fCommandStack;
|
CommandStack* fCommandStack;
|
||||||
ListenerAdapter fCommandStackListener;
|
ListenerAdapter fCommandStackListener;
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
|
|
||||||
#ifdef __HAIKU__
|
#ifdef __HAIKU__
|
||||||
# include <GridLayoutBuilder.h>
|
# include <GridLayoutBuilder.h>
|
||||||
# include <GroupLayout.h>
|
|
||||||
# include <GroupLayoutBuilder.h>
|
# include <GroupLayoutBuilder.h>
|
||||||
# include <SpaceLayoutItem.h>
|
# include <SpaceLayoutItem.h>
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user