Fix FreeBSD build.
[haiku.git] / src / preferences / sounds / HWindow.cpp
blob5b0fc2b57bf5c240a73a8197ec822b8ad766c6b6
1 /*
2 * Copyright 2003-2008, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Jérôme Duval
7 * Oliver Ruiz Dorantes
8 * Atsushi Takamatsu
9 */
12 #include "HWindow.h"
13 #include "HEventList.h"
15 #include <stdio.h>
17 #include <Alert.h>
18 #include <Application.h>
19 #include <Beep.h>
20 #include <Box.h>
21 #include <Button.h>
22 #include <Catalog.h>
23 #include <ControlLook.h>
24 #include <FindDirectory.h>
25 #include <fs_attr.h>
26 #include <LayoutBuilder.h>
27 #include <Locale.h>
28 #include <MediaFiles.h>
29 #include <MenuBar.h>
30 #include <MenuField.h>
31 #include <MenuItem.h>
32 #include <Node.h>
33 #include <NodeInfo.h>
34 #include <Path.h>
35 #include <Roster.h>
36 #include <ScrollView.h>
37 #include <StringView.h>
38 #include <Sound.h>
41 #undef B_TRANSLATION_CONTEXT
42 #define B_TRANSLATION_CONTEXT "HWindow"
44 static const char kSettingsFile[] = "Sounds_Settings";
47 HWindow::HWindow(BRect rect, const char* name)
49 BWindow(rect, name, B_TITLED_WINDOW, B_AUTO_UPDATE_SIZE_LIMITS),
50 fFilePanel(NULL),
51 fPlayer(NULL)
53 _InitGUI();
55 fFilePanel = new BFilePanel();
56 fFilePanel->SetTarget(this);
58 BPath path;
59 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
60 path.Append(kSettingsFile);
61 BFile file(path.Path(), B_READ_ONLY);
63 BMessage msg;
64 if (file.InitCheck() == B_OK && msg.Unflatten(&file) == B_OK
65 && msg.FindRect("frame", &fFrame) == B_OK) {
66 MoveTo(fFrame.LeftTop());
67 ResizeTo(fFrame.Width(), fFrame.Height());
71 MoveOnScreen();
75 HWindow::~HWindow()
77 delete fFilePanel;
78 delete fPlayer;
80 BPath path;
81 BMessage msg;
82 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
83 path.Append(kSettingsFile);
84 BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE);
86 if (file.InitCheck() == B_OK) {
87 msg.AddRect("frame", fFrame);
88 msg.Flatten(&file);
94 void
95 HWindow::DispatchMessage(BMessage* message, BHandler* handler)
97 if (message->what == B_PULSE)
98 _Pulse();
99 BWindow::DispatchMessage(message, handler);
103 void
104 HWindow::MessageReceived(BMessage* message)
106 switch (message->what) {
107 case M_OTHER_MESSAGE:
109 BMenuField* menufield
110 = dynamic_cast<BMenuField*>(FindView("filemenu"));
111 if (menufield == NULL)
112 return;
113 BMenu* menu = menufield->Menu();
115 HEventRow* row = (HEventRow*)fEventList->CurrentSelection();
116 if (row != NULL) {
117 BPath path(row->Path());
118 if (path.InitCheck() != B_OK) {
119 BMenuItem* item = menu->FindItem(B_TRANSLATE("<none>"));
120 if (item != NULL)
121 item->SetMarked(true);
122 } else {
123 BMenuItem* item = menu->FindItem(path.Leaf());
124 if (item != NULL)
125 item->SetMarked(true);
128 fFilePanel->Show();
129 break;
132 case B_SIMPLE_DATA:
133 case B_REFS_RECEIVED:
135 entry_ref ref;
136 HEventRow* row = (HEventRow*)fEventList->CurrentSelection();
137 if (message->FindRef("refs", &ref) == B_OK && row != NULL) {
138 BMenuField* menufield
139 = dynamic_cast<BMenuField*>(FindView("filemenu"));
140 if (menufield == NULL)
141 return;
142 BMenu* menu = menufield->Menu();
144 // check audio file
145 BNode node(&ref);
146 BNodeInfo ninfo(&node);
147 char type[B_MIME_TYPE_LENGTH + 1];
148 ninfo.GetType(type);
149 BMimeType mtype(type);
150 BMimeType superType;
151 mtype.GetSupertype(&superType);
152 if (superType.Type() == NULL
153 || strcmp(superType.Type(), "audio") != 0) {
154 beep();
155 BAlert* alert = new BAlert("",
156 B_TRANSLATE("This is not an audio file."),
157 B_TRANSLATE("OK"), NULL, NULL,
158 B_WIDTH_AS_USUAL, B_STOP_ALERT);
159 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
160 alert->Go();
161 break;
164 // add file item
165 BMessage* msg = new BMessage(M_ITEM_MESSAGE);
166 BPath path(&ref);
167 msg->AddRef("refs", &ref);
168 BMenuItem* menuitem = menu->FindItem(path.Leaf());
169 if (menuitem == NULL)
170 menu->AddItem(menuitem = new BMenuItem(path.Leaf(), msg), 0);
171 // refresh item
172 fEventList->SetPath(BPath(&ref).Path());
173 // check file menu
174 if (menuitem != NULL)
175 menuitem->SetMarked(true);
177 break;
180 case M_PLAY_MESSAGE:
182 HEventRow* row = (HEventRow*)fEventList->CurrentSelection();
183 if (row != NULL) {
184 const char* path = row->Path();
185 if (path != NULL) {
186 entry_ref ref;
187 ::get_ref_for_path(path, &ref);
188 delete fPlayer;
189 fPlayer = new BFileGameSound(&ref, false);
190 fPlayer->StartPlaying();
193 break;
196 case M_STOP_MESSAGE:
198 if (fPlayer == NULL)
199 break;
200 if (fPlayer->IsPlaying()) {
201 fPlayer->StopPlaying();
202 delete fPlayer;
203 fPlayer = NULL;
205 break;
208 case M_EVENT_CHANGED:
210 const char* path;
211 BMenuField* menufield
212 = dynamic_cast<BMenuField*>(FindView("filemenu"));
213 if (menufield == NULL)
214 return;
215 BMenu* menu = menufield->Menu();
217 if (message->FindString("path", &path) == B_OK) {
218 BPath path(path);
219 if (path.InitCheck() != B_OK) {
220 BMenuItem* item = menu->FindItem(B_TRANSLATE("<none>"));
221 if (item != NULL)
222 item->SetMarked(true);
223 } else {
224 BMenuItem* item = menu->FindItem(path.Leaf());
225 if (item != NULL)
226 item->SetMarked(true);
229 HEventRow* row = (HEventRow*)fEventList->CurrentSelection();
230 BButton* button = dynamic_cast<BButton*>(FindView("play"));
231 if (row != NULL) {
232 menufield->SetEnabled(true);
234 const char* path = row->Path();
235 if (path != NULL && strcmp(path, ""))
236 button->SetEnabled(true);
237 else
238 button->SetEnabled(false);
239 } else {
240 menufield->SetEnabled(false);
241 button->SetEnabled(false);
244 break;
247 case M_ITEM_MESSAGE:
249 entry_ref ref;
250 if (message->FindRef("refs", &ref) == B_OK) {
251 fEventList->SetPath(BPath(&ref).Path());
252 _UpdateZoomLimits();
254 break;
257 case M_NONE_MESSAGE:
259 fEventList->SetPath(NULL);
260 break;
263 default:
264 BWindow::MessageReceived(message);
269 bool
270 HWindow::QuitRequested()
272 fFrame = Frame();
274 fEventList->RemoveAll();
275 be_app->PostMessage(B_QUIT_REQUESTED);
276 return true;
280 void
281 HWindow::_InitGUI()
283 fEventList = new HEventList();
284 fEventList->SetType(BMediaFiles::B_SOUNDS);
285 fEventList->SetSelectionMode(B_SINGLE_SELECTION_LIST);
287 BMenu* menu = new BMenu("file");
288 menu->SetRadioMode(true);
289 menu->SetLabelFromMarked(true);
290 menu->AddSeparatorItem();
291 menu->AddItem(new BMenuItem(B_TRANSLATE("<none>"),
292 new BMessage(M_NONE_MESSAGE)));
293 menu->AddItem(new BMenuItem(B_TRANSLATE("Other" B_UTF8_ELLIPSIS),
294 new BMessage(M_OTHER_MESSAGE)));
296 BString label(B_TRANSLATE("Sound file:"));
297 BMenuField* menuField = new BMenuField("filemenu", label, menu);
298 menuField->SetDivider(menuField->StringWidth(label) + 10);
300 BSize buttonsSize(be_plain_font->Size() * 2.5, be_plain_font->Size() * 2.5);
302 BButton* stopbutton = new BButton("stop", "\xE2\x96\xA0",
303 new BMessage(M_STOP_MESSAGE));
304 stopbutton->SetEnabled(false);
305 stopbutton->SetExplicitSize(buttonsSize);
307 // We need at least one view to trigger B_PULSE_NEEDED events which we will
308 // intercept in DispatchMessage to trigger the buttons enabling or disabling.
309 stopbutton->SetFlags(stopbutton->Flags() | B_PULSE_NEEDED);
311 BButton* playbutton = new BButton("play", "\xE2\x96\xB6",
312 new BMessage(M_PLAY_MESSAGE));
313 playbutton->SetEnabled(false);
314 playbutton->SetExplicitSize(buttonsSize);
316 BLayoutBuilder::Group<>(this, B_VERTICAL)
317 .SetInsets(B_USE_WINDOW_SPACING)
318 .Add(fEventList)
319 .AddGroup(B_HORIZONTAL)
320 .Add(menuField)
321 .AddGroup(B_HORIZONTAL, 0)
322 .Add(playbutton)
323 .Add(stopbutton)
324 .End()
325 .End();
327 // setup file menu
328 _SetupMenuField();
329 BMenuItem* noneItem = menu->FindItem(B_TRANSLATE("<none>"));
330 if (noneItem != NULL)
331 noneItem->SetMarked(true);
333 _UpdateZoomLimits();
337 void
338 HWindow::_Pulse()
340 BButton* stop = dynamic_cast<BButton*>(FindView("stop"));
342 if (stop == NULL)
343 return;
345 if (fPlayer != NULL) {
346 if (fPlayer->IsPlaying())
347 stop->SetEnabled(true);
348 else
349 stop->SetEnabled(false);
350 } else
351 stop->SetEnabled(false);
355 void
356 HWindow::_SetupMenuField()
358 BMenuField* menufield = dynamic_cast<BMenuField*>(FindView("filemenu"));
359 if (menufield == NULL)
360 return;
361 BMenu* menu = menufield->Menu();
362 int32 count = fEventList->CountRows();
363 for (int32 i = 0; i < count; i++) {
364 HEventRow* row = (HEventRow*)fEventList->RowAt(i);
365 if (row == NULL)
366 continue;
368 BPath path(row->Path());
369 if (path.InitCheck() != B_OK)
370 continue;
371 if (menu->FindItem(path.Leaf()))
372 continue;
374 BMessage* msg = new BMessage(M_ITEM_MESSAGE);
375 entry_ref ref;
376 ::get_ref_for_path(path.Path(), &ref);
377 msg->AddRef("refs", &ref);
378 menu->AddItem(new BMenuItem(path.Leaf(), msg), 0);
381 directory_which whichDirectories[] = {
382 B_SYSTEM_SOUNDS_DIRECTORY,
383 B_SYSTEM_NONPACKAGED_SOUNDS_DIRECTORY,
384 B_USER_SOUNDS_DIRECTORY,
385 B_USER_NONPACKAGED_SOUNDS_DIRECTORY,
388 for (size_t i = 0;
389 i < sizeof(whichDirectories) / sizeof(whichDirectories[0]); i++) {
390 BPath path;
391 BDirectory dir;
392 BEntry entry;
393 BPath item_path;
395 status_t err = find_directory(whichDirectories[i], &path);
396 if (err == B_OK)
397 err = dir.SetTo(path.Path());
398 while (err == B_OK) {
399 err = dir.GetNextEntry(&entry, true);
400 if (entry.InitCheck() != B_NO_ERROR)
401 break;
403 entry.GetPath(&item_path);
405 if (menu->FindItem(item_path.Leaf()))
406 continue;
408 BMessage* msg = new BMessage(M_ITEM_MESSAGE);
409 entry_ref ref;
410 ::get_ref_for_path(item_path.Path(), &ref);
411 msg->AddRef("refs", &ref);
412 menu->AddItem(new BMenuItem(item_path.Leaf(), msg), 0);
418 void
419 HWindow::_UpdateZoomLimits()
421 const float kInset = be_control_look->DefaultItemSpacing();
423 BSize size = fEventList->PreferredSize();
424 SetZoomLimits(size.width + 2 * kInset + B_V_SCROLL_BAR_WIDTH,
425 size.height + 5 * kInset + 2 * B_H_SCROLL_BAR_HEIGHT
426 + 2 * be_plain_font->Size() * 2.5);