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