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