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