xref: /haiku/src/preferences/sounds/HWindow.cpp (revision 99d027cd0238c1d86da86d7c3f4200509ccc61a6)
1 /*
2  * Copyright 2003-2008, Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Jérôme Duval
7  *		Oliver Ruiz Dorantes
8  *		Atsushi Takamatsu
9  */
10 
11 
12 #include "HWindow.h"
13 #include "HEventList.h"
14 
15 #include <stdio.h>
16 
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 <GroupLayoutBuilder.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>
39 
40 
41 #undef B_TRANSLATION_CONTEXT
42 #define B_TRANSLATION_CONTEXT "HWindow"
43 
44 static const char kSettingsFile[] = "Sounds_Settings";
45 
46 
47 HWindow::HWindow(BRect rect, const char* name)
48 	:
49 	BWindow(rect, name, B_TITLED_WINDOW, B_AUTO_UPDATE_SIZE_LIMITS),
50 	fFilePanel(NULL),
51 	fPlayer(NULL)
52 {
53 	InitGUI();
54 
55 	fFilePanel = new BFilePanel();
56 	fFilePanel->SetTarget(this);
57 
58 	BPath path;
59 	BMessage msg;
60 
61 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
62 		path.Append(kSettingsFile);
63 		BFile file(path.Path(), B_READ_ONLY);
64 
65 		if (file.InitCheck() == B_OK && msg.Unflatten(&file) == B_OK
66 			&& msg.FindRect("frame", &fFrame) == B_OK) {
67 			MoveTo(fFrame.LeftTop());
68 			ResizeTo(fFrame.Width(), fFrame.Height());
69 		}
70 	}
71 }
72 
73 
74 HWindow::~HWindow()
75 {
76 	delete fFilePanel;
77 	delete fPlayer;
78 
79 	BPath path;
80 	BMessage msg;
81 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
82 		path.Append(kSettingsFile);
83 		BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE);
84 
85 		if (file.InitCheck() == B_OK) {
86 			msg.AddRect("frame", fFrame);
87 			msg.Flatten(&file);
88 		}
89 	}
90 }
91 
92 
93 void
94 HWindow::InitGUI()
95 {
96 	fEventList = new HEventList();
97 	fEventList->SetType(BMediaFiles::B_SOUNDS);
98 	fEventList->SetSelectionMode(B_SINGLE_SELECTION_LIST);
99 
100 	BGroupView* view = new BGroupView();
101 	BBox* box = new BBox("", B_WILL_DRAW | B_FRAME_EVENTS
102 		| B_NAVIGABLE_JUMP | B_PULSE_NEEDED);
103 
104 	BMenu* menu = new BMenu("file");
105 	menu->SetRadioMode(true);
106 	menu->SetLabelFromMarked(true);
107 	menu->AddSeparatorItem();
108 	menu->AddItem(new BMenuItem(B_TRANSLATE("<none>"),
109 		new BMessage(M_NONE_MESSAGE)));
110 	menu->AddItem(new BMenuItem(B_TRANSLATE("Other" B_UTF8_ELLIPSIS),
111 		new BMessage(M_OTHER_MESSAGE)));
112 	BMenuField* menuField = new BMenuField("filemenu",
113 		B_TRANSLATE("Sound File:"), menu);
114 	menuField->SetDivider(menuField->StringWidth(B_TRANSLATE("Sound File:"))
115 		+ 10);
116 
117 	BButton* stopbutton = new BButton("stop", B_TRANSLATE("Stop"),
118 		new BMessage(M_STOP_MESSAGE));
119 	stopbutton->SetEnabled(false);
120 
121 	BButton* playbutton = new BButton("play", B_TRANSLATE("Play"),
122 		new BMessage(M_PLAY_MESSAGE));
123 	playbutton->SetEnabled(false);
124 
125 	const float kInset = be_control_look->DefaultItemSpacing();
126 	view->SetLayout(new BGroupLayout(B_HORIZONTAL));
127 	view->AddChild(BGroupLayoutBuilder(B_VERTICAL, kInset)
128 		.AddGroup(B_HORIZONTAL)
129 			.Add(menuField)
130 			.AddGlue()
131 		.End()
132 		.AddGroup(B_HORIZONTAL, kInset)
133 			.AddGlue()
134 			.Add(playbutton)
135 			.Add(stopbutton)
136 		.End()
137 		.SetInsets(kInset, kInset, kInset, kInset)
138 	);
139 
140 	box->AddChild(view);
141 
142 	SetLayout(new BGroupLayout(B_HORIZONTAL));
143 	AddChild(BGroupLayoutBuilder(B_VERTICAL)
144 		.AddGroup(B_VERTICAL, kInset)
145 			.Add(fEventList)
146 			.Add(box)
147 		.End()
148 		.SetInsets(kInset, kInset, kInset, kInset)
149 	);
150 
151 	// setup file menu
152 	SetupMenuField();
153 	BMenuItem* noneItem = menu->FindItem(B_TRANSLATE("<none>"));
154 	if (noneItem != NULL)
155 		noneItem->SetMarked(true);
156 }
157 
158 
159 void
160 HWindow::MessageReceived(BMessage* message)
161 {
162 	switch (message->what) {
163 		case M_OTHER_MESSAGE:
164 		{
165 			BMenuField* menufield
166 				= dynamic_cast<BMenuField*>(FindView("filemenu"));
167 			if (menufield == NULL)
168 				return;
169 			BMenu* menu = menufield->Menu();
170 
171 			HEventRow* row = (HEventRow*)fEventList->CurrentSelection();
172 			if (row != NULL) {
173 				BPath path(row->Path());
174 				if (path.InitCheck() != B_OK) {
175 					BMenuItem* item = menu->FindItem(B_TRANSLATE("<none>"));
176 					if (item != NULL)
177 						item->SetMarked(true);
178 				} else {
179 					BMenuItem* item = menu->FindItem(path.Leaf());
180 					if (item != NULL)
181 						item->SetMarked(true);
182 				}
183 			}
184 			fFilePanel->Show();
185 			break;
186 		}
187 
188 		case B_SIMPLE_DATA:
189 		case B_REFS_RECEIVED:
190 		{
191 			entry_ref ref;
192 			HEventRow* row = (HEventRow*)fEventList->CurrentSelection();
193 			if (message->FindRef("refs", &ref) == B_OK && row != NULL) {
194 				BMenuField* menufield
195 					= dynamic_cast<BMenuField*>(FindView("filemenu"));
196 				if (menufield == NULL)
197 					return;
198 				BMenu* menu = menufield->Menu();
199 
200 				// check audio file
201 				BNode node(&ref);
202 				BNodeInfo ninfo(&node);
203 				char type[B_MIME_TYPE_LENGTH + 1];
204 				ninfo.GetType(type);
205 				BMimeType mtype(type);
206 				BMimeType superType;
207 				mtype.GetSupertype(&superType);
208 				if (superType.Type() == NULL
209 					|| strcmp(superType.Type(), "audio") != 0) {
210 					beep();
211 					BAlert* alert = new BAlert("",
212 						B_TRANSLATE("This is not an audio file."),
213 						B_TRANSLATE("OK"), NULL, NULL,
214 						B_WIDTH_AS_USUAL, B_STOP_ALERT);
215 					alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
216 					alert->Go();
217 					break;
218 				}
219 
220 				// add file item
221 				BMessage* msg = new BMessage(M_ITEM_MESSAGE);
222 				BPath path(&ref);
223 				msg->AddRef("refs", &ref);
224 				BMenuItem* menuitem = menu->FindItem(path.Leaf());
225 				if (menuitem == NULL)
226 					menu->AddItem(menuitem = new BMenuItem(path.Leaf(), msg), 0);
227 				// refresh item
228 				fEventList->SetPath(BPath(&ref).Path());
229 				// check file menu
230 				if (menuitem != NULL)
231 					menuitem->SetMarked(true);
232 			}
233 			break;
234 		}
235 
236 		case M_PLAY_MESSAGE:
237 		{
238 			HEventRow* row = (HEventRow*)fEventList->CurrentSelection();
239 			if (row != NULL) {
240 				const char* path = row->Path();
241 				if (path != NULL) {
242 					entry_ref ref;
243 					::get_ref_for_path(path, &ref);
244 					delete fPlayer;
245 					fPlayer = new BFileGameSound(&ref, false);
246 					fPlayer->StartPlaying();
247 				}
248 			}
249 			break;
250 		}
251 
252 		case M_STOP_MESSAGE:
253 		{
254 			if (fPlayer == NULL)
255 				break;
256 			if (fPlayer->IsPlaying()) {
257 				fPlayer->StopPlaying();
258 				delete fPlayer;
259 				fPlayer = NULL;
260 			}
261 			break;
262 		}
263 
264 		case M_EVENT_CHANGED:
265 		{
266 			const char* path;
267 			BMenuField* menufield
268 				= dynamic_cast<BMenuField*>(FindView("filemenu"));
269 			if (menufield == NULL)
270 				return;
271 			BMenu* menu = menufield->Menu();
272 
273 			if (message->FindString("path", &path) == B_OK) {
274 				BPath path(path);
275 				if (path.InitCheck() != B_OK) {
276 					BMenuItem* item = menu->FindItem(B_TRANSLATE("<none>"));
277 					if (item != NULL)
278 						item->SetMarked(true);
279 				} else {
280 					BMenuItem* item = menu->FindItem(path.Leaf());
281 					if (item != NULL)
282 						item->SetMarked(true);
283 				}
284 			}
285 			break;
286 		}
287 
288 		case M_ITEM_MESSAGE:
289 		{
290 			entry_ref ref;
291 			if (message->FindRef("refs", &ref) == B_OK)
292 				fEventList->SetPath(BPath(&ref).Path());
293 			break;
294 		}
295 
296 		case M_NONE_MESSAGE:
297 		{
298 			fEventList->SetPath(NULL);
299 			break;
300 		}
301 
302 		default:
303 			BWindow::MessageReceived(message);
304 	}
305 }
306 
307 
308 void
309 HWindow::SetupMenuField()
310 {
311 	BMenuField* menufield = dynamic_cast<BMenuField*>(FindView("filemenu"));
312 	if (menufield == NULL)
313 		return;
314 	BMenu* menu = menufield->Menu();
315 	int32 count = fEventList->CountRows();
316 	for (int32 i = 0; i < count; i++) {
317 		HEventRow* row = (HEventRow*)fEventList->RowAt(i);
318 		if (row == NULL)
319 			continue;
320 
321 		BPath path(row->Path());
322 		if (path.InitCheck() != B_OK)
323 			continue;
324 		if (menu->FindItem(path.Leaf()))
325 			continue;
326 
327 		BMessage* msg = new BMessage(M_ITEM_MESSAGE);
328 		entry_ref ref;
329 		::get_ref_for_path(path.Path(), &ref);
330 		msg->AddRef("refs", &ref);
331 		menu->AddItem(new BMenuItem(path.Leaf(), msg), 0);
332 	}
333 
334 	BPath path;
335 	BDirectory dir;
336 	BEntry entry;
337 	BPath item_path;
338 
339 	status_t err = find_directory(B_BEOS_SOUNDS_DIRECTORY, &path);
340 	if (err == B_OK)
341 		err = dir.SetTo(path.Path());
342 	while (err == B_OK) {
343 		err = dir.GetNextEntry(&entry, true);
344 		if (entry.InitCheck() != B_NO_ERROR)
345 			break;
346 
347 		entry.GetPath(&item_path);
348 
349 		if (menu->FindItem(item_path.Leaf()))
350 			continue;
351 
352 		BMessage* msg = new BMessage(M_ITEM_MESSAGE);
353 		entry_ref ref;
354 		::get_ref_for_path(item_path.Path(), &ref);
355 		msg->AddRef("refs", &ref);
356 		menu->AddItem(new BMenuItem(item_path.Leaf(), msg), 0);
357 	}
358 
359 	err = find_directory(B_USER_SOUNDS_DIRECTORY, &path);
360 	if (err == B_OK)
361 		err = dir.SetTo(path.Path());
362 	while (err == B_OK) {
363 		err = dir.GetNextEntry(&entry, true);
364 		if (entry.InitCheck() != B_NO_ERROR)
365 			break;
366 
367 		entry.GetPath(&item_path);
368 
369 		if (menu->FindItem(item_path.Leaf()))
370 			continue;
371 
372 		BMessage* msg = new BMessage(M_ITEM_MESSAGE);
373 		entry_ref ref;
374 
375 		::get_ref_for_path(item_path.Path(), &ref);
376 		msg->AddRef("refs", &ref);
377 		menu->AddItem(new BMenuItem(item_path.Leaf(), msg), 0);
378 	}
379 
380 	err = find_directory(B_COMMON_SOUNDS_DIRECTORY, &path);
381 	if (err == B_OK)
382 		err = dir.SetTo(path.Path());
383 	while (err == B_OK) {
384 		err = dir.GetNextEntry(&entry, true);
385 		if (entry.InitCheck() != B_NO_ERROR)
386 			break;
387 
388 		entry.GetPath(&item_path);
389 
390 		if (menu->FindItem(item_path.Leaf()))
391 			continue;
392 
393 		BMessage* msg = new BMessage(M_ITEM_MESSAGE);
394 		entry_ref ref;
395 
396 		::get_ref_for_path(item_path.Path(), &ref);
397 		msg->AddRef("refs", &ref);
398 		menu->AddItem(new BMenuItem(item_path.Leaf(), msg), 0);
399 	}
400 
401 }
402 
403 
404 void
405 HWindow::Pulse()
406 {
407 	HEventRow* row = (HEventRow*)fEventList->CurrentSelection();
408 	BMenuField* menufield = dynamic_cast<BMenuField*>(FindView("filemenu"));
409 	BButton* button = dynamic_cast<BButton*>(FindView("play"));
410 	BButton* stop = dynamic_cast<BButton*>(FindView("stop"));
411 
412 	if (menufield == NULL || button == NULL || stop == NULL)
413 		return;
414 
415 	if (row != NULL) {
416 		menufield->SetEnabled(true);
417 
418 		const char* path = row->Path();
419 		if (path != NULL && strcmp(path, ""))
420 			button->SetEnabled(true);
421 		else
422 			button->SetEnabled(false);
423 	} else {
424 		menufield->SetEnabled(false);
425 		button->SetEnabled(false);
426 	}
427 
428 	if (fPlayer != NULL) {
429 		if (fPlayer->IsPlaying())
430 			stop->SetEnabled(true);
431 		else
432 			stop->SetEnabled(false);
433 	} else
434 		stop->SetEnabled(false);
435 }
436 
437 
438 void
439 HWindow::DispatchMessage(BMessage* message, BHandler* handler)
440 {
441 	if (message->what == B_PULSE)
442 		Pulse();
443 	BWindow::DispatchMessage(message, handler);
444 }
445 
446 
447 bool
448 HWindow::QuitRequested()
449 {
450 	fFrame = Frame();
451 
452 	fEventList->RemoveAll();
453 	be_app->PostMessage(B_QUIT_REQUESTED);
454 	return true;
455 }
456