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