xref: /haiku/src/preferences/sounds/HWindow.cpp (revision 746cac055adc6ac3308c7bc2d29040fb95689cc9)
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 #include "HEventItem.h"
15 
16 #include <stdio.h>
17 
18 #include <Alert.h>
19 #include <Application.h>
20 #include <Beep.h>
21 #include <Box.h>
22 #include <Button.h>
23 #include <ClassInfo.h>
24 #include <FindDirectory.h>
25 #include <fs_attr.h>
26 #include <MediaFiles.h>
27 #include <MenuBar.h>
28 #include <MenuField.h>
29 #include <MenuItem.h>
30 #include <Node.h>
31 #include <NodeInfo.h>
32 #include <Path.h>
33 #include <Roster.h>
34 #include <ScrollView.h>
35 #include <StringView.h>
36 #include <Sound.h>
37 
38 
39 HWindow::HWindow(BRect rect, const char *name)
40 	: _inherited(rect, name, B_TITLED_WINDOW, 0),
41 	fFilePanel(NULL),
42 	fPlayer(NULL)
43 {
44 	InitGUI();
45 	float min_width, min_height, max_width, max_height;
46 	GetSizeLimits(&min_width, &max_width, &min_height, &max_height);
47 	min_width = 300;
48 	min_height = 200;
49 	SetSizeLimits(min_width, max_width, min_height, max_height);
50 
51 	fFilePanel = new BFilePanel();
52 	fFilePanel->SetTarget(this);
53 
54 	fEventList->Select(0);
55 }
56 
57 
58 HWindow::~HWindow()
59 {
60 	delete fFilePanel;
61 	delete fPlayer;
62 }
63 
64 
65 void
66 HWindow::InitGUI()
67 {
68 	BRect rect = Bounds();
69 	rect.bottom -= 106;
70 	BView *listView = new BView(rect, "", B_FOLLOW_NONE, B_WILL_DRAW | B_PULSE_NEEDED);
71 	listView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
72 	AddChild(listView);
73 
74 	BRect stringRect(16, 5, 60, 22);
75 	BStringView *stringView = new BStringView(stringRect, "event", "Event");
76 	stringView->SetFont(be_bold_font);
77 	stringView->ResizeToPreferred();
78 	listView->AddChild(stringView);
79 
80 	stringRect.OffsetBy(120, 0);
81 	stringView = new BStringView(stringRect, "sound", "Sound");
82 	stringView->SetFont(be_bold_font);
83 	stringView->ResizeToPreferred();
84 	listView->AddChild(stringView);
85 
86 	rect.left += 13;
87 	rect.right -= B_V_SCROLL_BAR_WIDTH + 13;
88 	rect.top += 28;
89 	rect.bottom -= 7;
90 	fEventList = new HEventList(rect);
91 	fEventList->SetType(BMediaFiles::B_SOUNDS);
92 
93 	BScrollView *scrollView = new BScrollView("", fEventList, B_FOLLOW_ALL, 0,
94 		false, true);
95 	listView->AddChild(scrollView);
96 
97 	rect = Bounds();
98 	rect.top = rect.bottom - 105;
99 	BView *view = new BView(rect, "", B_FOLLOW_NONE, B_WILL_DRAW | B_PULSE_NEEDED);
100 	view->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
101 	AddChild(view);
102 	rect = view->Bounds().InsetBySelf(12, 12);
103 	BBox *box = new BBox(rect, "", B_FOLLOW_ALL);
104 	view->AddChild(box);
105 	rect = box->Bounds();
106 	rect.top += 10;
107 	rect.left += 15;
108 	rect.right -= 10;
109 	rect.bottom = rect.top + 20;
110 	BMenu *menu = new BMenu("file");
111 	menu->SetRadioMode(true);
112 	menu->SetLabelFromMarked(true);
113 	menu->AddSeparatorItem();
114 
115 	menu->AddItem(new BMenuItem("<none>", new BMessage(M_NONE_MESSAGE)));
116 	menu->AddItem(new BMenuItem("Other" B_UTF8_ELLIPSIS, new BMessage(M_OTHER_MESSAGE)));
117 	BMenuField *menuField = new BMenuField(rect, "filemenu", "Sound File:", menu,
118 		B_FOLLOW_TOP | B_FOLLOW_LEFT);
119 	menuField->SetDivider(menuField->StringWidth("Sound File:") + 10);
120 	box->AddChild(menuField);
121 	rect.OffsetBy(-2, menuField->Bounds().Height() + 15);
122 	BButton *button = new BButton(rect, "stop", "Stop", new BMessage(M_STOP_MESSAGE),
123 		B_FOLLOW_RIGHT | B_FOLLOW_TOP);
124 	button->ResizeToPreferred();
125 	button->SetEnabled(false);
126 	button->MoveTo(box->Bounds().right - button->Bounds().Width() - 15, rect.top);
127 	box->AddChild(button);
128 
129 	rect = button->Frame();
130 	view->ResizeTo(view->Bounds().Width(), 24 + rect.bottom + 12);
131 	box->ResizeTo(box->Bounds().Width(), rect.bottom + 12);
132 
133 	button->SetResizingMode(B_FOLLOW_RIGHT | B_FOLLOW_TOP);
134 	button = new BButton(rect, "play", "Play", new BMessage(M_PLAY_MESSAGE),
135 		B_FOLLOW_RIGHT | B_FOLLOW_TOP);
136 	button->ResizeToPreferred();
137 	button->SetEnabled(false);
138 	button->MoveTo(rect.left - button->Bounds().Width() - 15, rect.top);
139 	box->AddChild(button);
140 
141 	view->MoveTo(0, listView->Frame().bottom);
142 	ResizeTo(Bounds().Width(), listView->Frame().bottom + view->Bounds().Height());
143 	listView->SetResizingMode(B_FOLLOW_ALL);
144 	view->SetResizingMode(B_FOLLOW_LEFT_RIGHT | B_FOLLOW_BOTTOM);
145 
146 	// setup file menu
147 	SetupMenuField();
148 	menu->FindItem("<none>")->SetMarked(true);
149 }
150 
151 
152 void
153 HWindow::MessageReceived(BMessage *message)
154 {
155 	switch (message->what) {
156 		case M_OTHER_MESSAGE:
157 		{
158 			BMenuField *menufield = cast_as(FindView("filemenu"), BMenuField);
159 			BMenu *menu = menufield->Menu();
160 
161 			int32 sel = fEventList->CurrentSelection();
162 			if (sel >= 0) {
163 				HEventItem *item = cast_as(fEventList->ItemAt(sel), HEventItem);
164 				BPath path(item->Path());
165 				if (path.InitCheck() != B_OK) {
166 					BMenuItem *item = menu->FindItem("<none>");
167 					if (item)
168 						item->SetMarked(true);
169 				} else {
170 					BMenuItem *item = menu->FindItem(path.Leaf());
171 					if (item)
172 						item->SetMarked(true);
173 				}
174 			}
175 			fFilePanel->Show();
176 			break;
177 		}
178 
179 		case B_SIMPLE_DATA:
180 		case B_REFS_RECEIVED:
181 		{
182 			entry_ref ref;
183 			int32 sel = fEventList->CurrentSelection();
184 			if (message->FindRef("refs", &ref) == B_OK && sel >= 0) {
185 				BMenuField *menufield = cast_as(FindView("filemenu"), BMenuField);
186 				BMenu *menu = menufield->Menu();
187 
188 				// check audio file
189 				BNode node(&ref);
190 				BNodeInfo ninfo(&node);
191 				char type[B_MIME_TYPE_LENGTH + 1];
192 				ninfo.GetType(type);
193 				BMimeType mtype(type);
194 				BMimeType superType;
195 				mtype.GetSupertype(&superType);
196 				if (superType.Type() == NULL || strcmp(superType.Type(), "audio") != 0) {
197 					beep();
198 					(new BAlert("", "This is not a audio file.", "OK", NULL, NULL,
199 						B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go();
200 					break;
201 				}
202 
203 				// add file item
204 				BMessage *msg = new BMessage(M_ITEM_MESSAGE);
205 				BPath path(&ref);
206 				msg->AddRef("refs", &ref);
207 				BMenuItem *menuitem = menu->FindItem(path.Leaf());
208 				if (!menuitem)
209 					menu->AddItem(menuitem = new BMenuItem(path.Leaf(), msg), 0);
210 				// refresh item
211 				fEventList->SetPath(BPath(&ref).Path());
212 				// check file menu
213 				if (menuitem)
214 					menuitem->SetMarked(true);
215 			}
216 			break;
217 		}
218 
219 		case M_PLAY_MESSAGE:
220 		{
221 			int32 sel = fEventList->CurrentSelection();
222 			if (sel >= 0) {
223 				HEventItem *item = cast_as(fEventList->ItemAt(sel), HEventItem);
224 				const char *path = item->Path();
225 				if (path) {
226 					entry_ref ref;
227 					::get_ref_for_path(path, &ref);
228 					delete fPlayer;
229 					fPlayer = new BFileGameSound(&ref, false);
230 					fPlayer->StartPlaying();
231 				}
232 			}
233 			break;
234 		}
235 
236 		case M_STOP_MESSAGE:
237 		{
238 			if (!fPlayer)
239 				break;
240 			if (fPlayer->IsPlaying()) {
241 				fPlayer->StopPlaying();
242 				delete fPlayer;
243 				fPlayer = NULL;
244 			}
245 			break;
246 		}
247 
248 		case M_EVENT_CHANGED:
249 		{
250 			const char *path;
251 			BMenuField *menufield = cast_as(FindView("filemenu"), BMenuField);
252 			BMenu *menu = menufield->Menu();
253 
254 			if (message->FindString("path", &path) == B_OK) {
255 				BPath path(path);
256 				if (path.InitCheck() != B_OK) {
257 					BMenuItem *item = menu->FindItem("<none>");
258 					if (item)
259 						item->SetMarked(true);
260 				} else {
261 					BMenuItem *item = menu->FindItem(path.Leaf());
262 					if (item)
263 						item->SetMarked(true);
264 				}
265 			}
266 			break;
267 		}
268 
269 		case M_ITEM_MESSAGE:
270 		{
271 			entry_ref ref;
272 			if (message->FindRef("refs", &ref) == B_OK)
273 				fEventList->SetPath(BPath(&ref).Path());
274 			break;
275 		}
276 
277 		case M_NONE_MESSAGE:
278 		{
279 			fEventList->SetPath(NULL);
280 			break;
281 		}
282 
283 		default:
284 			_inherited::MessageReceived(message);
285 	}
286 }
287 
288 
289 void
290 HWindow::SetupMenuField()
291 {
292 	BMenuField *menufield = cast_as(FindView("filemenu"), BMenuField);
293 	BMenu *menu = menufield->Menu();
294 	int32 count = fEventList->CountItems();
295 	for (int32 i = 0; i < count; i++) {
296 		HEventItem *item = cast_as(fEventList->ItemAt(i), HEventItem);
297 		if (!item)
298 			continue;
299 
300 		BPath path(item->Path());
301 		if (path.InitCheck() != B_OK)
302 			continue;
303 		if (menu->FindItem(path.Leaf()))
304 			continue;
305 
306 		BMessage *msg = new BMessage(M_ITEM_MESSAGE);
307 		entry_ref ref;
308 		::get_ref_for_path(path.Path(), &ref);
309 		msg->AddRef("refs", &ref);
310 		menu->AddItem(new BMenuItem(path.Leaf(), msg), 0);
311 	}
312 
313 	BPath path;
314 	BDirectory dir;
315 	BEntry entry;
316 	BPath item_path;
317 
318 	status_t err = find_directory(B_BEOS_SOUNDS_DIRECTORY, &path);
319 	if (err == B_OK)
320 		err = dir.SetTo(path.Path());
321 	while (err == B_OK) {
322 		err = dir.GetNextEntry((BEntry*)&entry, true);
323 		if (entry.InitCheck() != B_NO_ERROR)
324 			break;
325 
326 		entry.GetPath(&item_path);
327 
328 		if (menu->FindItem(item_path.Leaf()))
329 			continue;
330 
331 		BMessage *msg = new BMessage(M_ITEM_MESSAGE);
332 		entry_ref ref;
333 		::get_ref_for_path(item_path.Path(), &ref);
334 		msg->AddRef("refs", &ref);
335 		menu->AddItem(new BMenuItem(item_path.Leaf(), msg), 0);
336 	}
337 
338 	err = find_directory(B_USER_SOUNDS_DIRECTORY, &path);
339 	if (err == B_OK)
340 		err = dir.SetTo(path.Path());
341 	while (err == B_OK) {
342 		err = dir.GetNextEntry((BEntry*)&entry, true);
343 		if (entry.InitCheck() != B_NO_ERROR)
344 			break;
345 
346 		entry.GetPath(&item_path);
347 
348 		if (menu->FindItem(item_path.Leaf()))
349 			continue;
350 
351 		BMessage *msg = new BMessage(M_ITEM_MESSAGE);
352 		entry_ref ref;
353 
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_COMMON_SOUNDS_DIRECTORY, &path);
360 	if (err == B_OK)
361 		err = dir.SetTo(path.Path());
362 	while (err == B_OK) {
363 		err = dir.GetNextEntry((BEntry*)&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 }
381 
382 
383 void
384 HWindow::Pulse()
385 {
386 	int32 sel = fEventList->CurrentSelection();
387 	BMenuField *menufield = cast_as(FindView("filemenu"), BMenuField);
388 	BButton *button = cast_as(FindView("play"), BButton);
389 	BButton *stop = cast_as(FindView("stop"), BButton);
390 
391 	if (!menufield)
392 		return;
393 
394 	if (sel >= 0) {
395 		menufield->SetEnabled(true);
396 
397 		HEventItem *item = cast_as(fEventList->ItemAt(sel), HEventItem);
398 		const char *path = item->Path();
399 		if (path && strcmp(path, ""))
400 			button->SetEnabled(true);
401 		else
402 			button->SetEnabled(false);
403 	} else {
404 		menufield->SetEnabled(false);
405 		button->SetEnabled(false);
406 	}
407 
408 	if (fPlayer) {
409 		if (fPlayer->IsPlaying())
410 			stop->SetEnabled(true);
411 		else
412 			stop->SetEnabled(false);
413 	} else
414 		stop->SetEnabled(false);
415 }
416 
417 
418 void
419 HWindow::DispatchMessage(BMessage *message, BHandler *handler)
420 {
421 	if (message->what == B_PULSE)
422 		Pulse();
423 	BWindow::DispatchMessage(message, handler);
424 }
425 
426 
427 bool
428 HWindow::QuitRequested()
429 {
430 	fEventList->RemoveAll();
431 	be_app->PostMessage(B_QUIT_REQUESTED);
432 	return true;
433 }
434