* Copyright 2003-2008, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Jérôme Duval
* Oliver Ruiz Dorantes
* Atsushi Takamatsu
*/
#include "HWindow.h"
#include "HEventList.h"
#include <stdio.h>
#include <Alert.h>
#include <Application.h>
#include <Beep.h>
#include <Box.h>
#include <Button.h>
#include <Catalog.h>
#include <ControlLook.h>
#include <FindDirectory.h>
#include <LayoutBuilder.h>
#include <Locale.h>
#include <MediaFiles.h>
#include <MenuBar.h>
#include <MenuField.h>
#include <MenuItem.h>
#include <Node.h>
#include <NodeInfo.h>
#include <Path.h>
#include <PathFinder.h>
#include <Roster.h>
#include <ScrollView.h>
#include <Sound.h>
#include <StringView.h>
#include <fs_attr.h>
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "HWindow"
static const char kSettingsFile[] = "Sounds_Settings";
extern const char* kPlayLabel;
extern const char* kStopLabel;
HWindow::HWindow(BRect rect, const char* name)
:
BWindow(rect, name, B_TITLED_WINDOW, B_AUTO_UPDATE_SIZE_LIMITS),
fFilePanel(NULL),
fPlayButton(NULL),
fPlayer(NULL)
{
_InitGUI();
BPathFinder pathFinder;
BStringList paths;
pathFinder.FindPaths(B_FIND_PATH_SOUNDS_DIRECTORY, paths);
for (int i = 0; i < paths.CountStrings(); ++i) {
BEntry entry(paths.StringAt(i));
if (entry.Exists()) {
entry.GetRef(&fPathRef);
break;
}
}
BPath path;
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
path.Append(kSettingsFile);
BFile file(path.Path(), B_READ_ONLY);
BMessage msg;
if (file.InitCheck() == B_OK && msg.Unflatten(&file) == B_OK) {
if (msg.FindRect("frame", &fFrame) == B_OK) {
MoveTo(fFrame.LeftTop());
ResizeTo(fFrame.Width(), fFrame.Height());
}
entry_ref ref;
if (msg.FindRef("last_path", &ref) == B_OK) {
BNode node(&ref);
if (node.InitCheck() == B_OK && node.IsDirectory())
fPathRef = ref;
}
}
}
fFilePanel = new SoundFilePanel(this);
fFilePanel->SetTarget(this);
BEntry entry(&fPathRef);
if (entry.Exists())
fFilePanel->SetPanelDirectory(&fPathRef);
MoveOnScreen();
}
HWindow::~HWindow()
{
delete fFilePanel;
delete fPlayer;
BPath path;
BMessage msg;
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
path.Append(kSettingsFile);
BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE);
if (file.InitCheck() == B_OK) {
msg.AddRect("frame", fFrame);
msg.AddRef("last_path", &fPathRef);
msg.Flatten(&file);
}
}
}
void
HWindow::DispatchMessage(BMessage* message, BHandler* handler)
{
if (message->what == B_PULSE)
_Pulse();
BWindow::DispatchMessage(message, handler);
}
void
HWindow::MessageReceived(BMessage* message)
{
switch (message->what) {
case M_OTHER_MESSAGE:
{
BMenuField* menufield
= dynamic_cast<BMenuField*>(FindView("filemenu"));
if (menufield == NULL)
return;
BMenu* menu = menufield->Menu();
HEventRow* row = (HEventRow*)fEventList->CurrentSelection();
if (row != NULL) {
BPath path(row->Path());
if (path.InitCheck() != B_OK) {
BMenuItem* item = menu->FindItem(B_TRANSLATE("<none>"));
if (item != NULL)
item->SetMarked(true);
} else {
BMenuItem* item = menu->FindItem(path.Leaf());
if (item != NULL)
item->SetMarked(true);
}
}
fFilePanel->Show();
break;
}
case B_CANCEL:
{
fFilePanel->SetPanelDirectory(&fPathRef);
break;
}
case B_SIMPLE_DATA:
case B_REFS_RECEIVED:
{
entry_ref ref;
HEventRow* row = (HEventRow*)fEventList->CurrentSelection();
if (message->FindRef("refs", &ref) == B_OK && row != NULL) {
BMenuField* menufield
= dynamic_cast<BMenuField*>(FindView("filemenu"));
if (menufield == NULL)
return;
BMenu* menu = menufield->Menu();
BMessage* msg = new BMessage(M_ITEM_MESSAGE);
BPath path(&ref);
msg->AddRef("refs", &ref);
BMenuItem* menuitem = menu->FindItem(path.Leaf());
if (menuitem == NULL)
menu->AddItem(menuitem = new BMenuItem(path.Leaf(), msg), 0);
fEventList->SetPath(BPath(&ref).Path());
if (menuitem != NULL)
menuitem->SetMarked(true);
path.GetParent(&path);
get_ref_for_path(path.Path(), &fPathRef);
fFilePanel->SetPanelDirectory(&fPathRef);
fPlayButton->SetEnabled(true);
}
break;
}
case M_PLAY_MESSAGE:
{
HEventRow* row = (HEventRow*)fEventList->CurrentSelection();
if (row != NULL) {
const char* path = row->Path();
if (path != NULL) {
entry_ref ref;
::get_ref_for_path(path, &ref);
delete fPlayer;
fPlayer = new BFileGameSound(&ref, false);
fPlayer->StartPlaying();
}
}
break;
}
case M_STOP_MESSAGE:
{
if (fPlayer == NULL)
break;
if (fPlayer->IsPlaying()) {
fPlayer->StopPlaying();
delete fPlayer;
fPlayer = NULL;
}
break;
}
case M_EVENT_CHANGED:
{
BMenuField* menufield
= dynamic_cast<BMenuField*>(FindView("filemenu"));
if (menufield == NULL)
return;
menufield->SetEnabled(true);
const char* filePath;
if (message->FindString("path", &filePath) == B_OK) {
BMenu* menu = menufield->Menu();
BPath path(filePath);
if (path.InitCheck() != B_OK) {
BMenuItem* item = menu->FindItem(B_TRANSLATE("<none>"));
if (item != NULL)
item->SetMarked(true);
} else {
BMenuItem* item = menu->FindItem(path.Leaf());
if (item != NULL)
item->SetMarked(true);
}
HEventRow* row = (HEventRow*)fEventList->CurrentSelection();
if (row != NULL) {
menufield->SetEnabled(true);
const char* path = row->Path();
fPlayButton->SetEnabled(path != NULL && strcmp(path, "") != 0);
} else {
menufield->SetEnabled(false);
fPlayButton->SetEnabled(false);
}
}
break;
}
case M_ITEM_MESSAGE:
{
entry_ref ref;
if (message->FindRef("refs", &ref) == B_OK) {
fEventList->SetPath(BPath(&ref).Path());
_UpdateZoomLimits();
HEventRow* row = (HEventRow*)fEventList->CurrentSelection();
fPlayButton->SetEnabled(row != NULL && row->Path() != NULL);
}
break;
}
case M_NONE_MESSAGE:
{
fPlayButton->SetEnabled(false);
fEventList->SetPath(NULL);
break;
}
default:
BWindow::MessageReceived(message);
}
}
bool
HWindow::QuitRequested()
{
fFrame = Frame();
fEventList->RemoveAll();
be_app->PostMessage(B_QUIT_REQUESTED);
return true;
}
void
HWindow::_InitGUI()
{
fEventList = new HEventList();
fEventList->SetType(BMediaFiles::B_SOUNDS);
fEventList->SetSelectionMode(B_SINGLE_SELECTION_LIST);
BMenu* menu = new BMenu("file");
menu->SetRadioMode(true);
menu->SetLabelFromMarked(true);
menu->AddSeparatorItem();
menu->AddItem(new BMenuItem(B_TRANSLATE("<none>"),
new BMessage(M_NONE_MESSAGE)));
menu->AddItem(new BMenuItem(B_TRANSLATE("Other" B_UTF8_ELLIPSIS),
new BMessage(M_OTHER_MESSAGE)));
BString label(B_TRANSLATE("Sound file:"));
BMenuField* menuField = new BMenuField("filemenu", label, menu);
menuField->SetDivider(menuField->StringWidth(label) + 10);
BSize buttonsSize(be_plain_font->Size() * 2.5, be_plain_font->Size() * 2.5);
BButton* stopbutton = new BButton("stop", kStopLabel, new BMessage(M_STOP_MESSAGE));
stopbutton->SetEnabled(false);
stopbutton->SetExplicitSize(buttonsSize);
stopbutton->SetFlags(stopbutton->Flags() | B_PULSE_NEEDED);
fPlayButton = new BButton("play", kPlayLabel, new BMessage(M_PLAY_MESSAGE));
fPlayButton->SetEnabled(false);
fPlayButton->SetExplicitSize(buttonsSize);
BLayoutBuilder::Group<>(this, B_VERTICAL)
.SetInsets(B_USE_WINDOW_SPACING)
.Add(fEventList)
.AddGroup(B_HORIZONTAL)
.Add(menuField)
.AddGroup(B_HORIZONTAL, 0)
.Add(fPlayButton)
.Add(stopbutton)
.End()
.End();
_SetupMenuField();
BMenuItem* noneItem = menu->FindItem(B_TRANSLATE("<none>"));
if (noneItem != NULL)
noneItem->SetMarked(true);
menuField->SetEnabled(false);
_UpdateZoomLimits();
}
void
HWindow::_Pulse()
{
BButton* stop = dynamic_cast<BButton*>(FindView("stop"));
if (stop == NULL)
return;
if (fPlayer != NULL) {
if (fPlayer->IsPlaying())
stop->SetEnabled(true);
else
stop->SetEnabled(false);
} else
stop->SetEnabled(false);
}
void
HWindow::_SetupMenuField()
{
BMenuField* menufield = dynamic_cast<BMenuField*>(FindView("filemenu"));
if (menufield == NULL)
return;
BMenu* menu = menufield->Menu();
int32 count = fEventList->CountRows();
for (int32 i = 0; i < count; i++) {
HEventRow* row = (HEventRow*)fEventList->RowAt(i);
if (row == NULL)
continue;
BPath path(row->Path());
if (path.InitCheck() != B_OK)
continue;
if (menu->FindItem(path.Leaf()))
continue;
BMessage* msg = new BMessage(M_ITEM_MESSAGE);
entry_ref ref;
::get_ref_for_path(path.Path(), &ref);
msg->AddRef("refs", &ref);
menu->AddItem(new BMenuItem(path.Leaf(), msg), 0);
}
directory_which whichDirectories[] = {
B_SYSTEM_SOUNDS_DIRECTORY,
B_SYSTEM_NONPACKAGED_SOUNDS_DIRECTORY,
B_USER_SOUNDS_DIRECTORY,
B_USER_NONPACKAGED_SOUNDS_DIRECTORY,
};
for (size_t i = 0;
i < sizeof(whichDirectories) / sizeof(whichDirectories[0]); i++) {
BPath path;
BDirectory dir;
BEntry entry;
BPath item_path;
status_t err = find_directory(whichDirectories[i], &path);
if (err == B_OK)
err = dir.SetTo(path.Path());
while (err == B_OK) {
err = dir.GetNextEntry(&entry, true);
if (entry.InitCheck() != B_NO_ERROR)
break;
if (entry.IsDirectory())
continue;
entry.GetPath(&item_path);
if (menu->FindItem(item_path.Leaf()))
continue;
BMessage* msg = new BMessage(M_ITEM_MESSAGE);
entry_ref ref;
::get_ref_for_path(item_path.Path(), &ref);
msg->AddRef("refs", &ref);
menu->AddItem(new BMenuItem(item_path.Leaf(), msg), 0);
}
}
}
void
HWindow::_UpdateZoomLimits()
{
const float kInset = be_control_look->DefaultItemSpacing();
BSize size = fEventList->PreferredSize();
SetZoomLimits(size.width + 2 * kInset + B_V_SCROLL_BAR_WIDTH,
size.height + 5 * kInset + 2 * B_H_SCROLL_BAR_HEIGHT
+ 2 * be_plain_font->Size() * 2.5);
}