xref: /haiku/src/preferences/sounds/HWindow.cpp (revision 14e3d1b5768e7110b3d5c0855833267409b71dbb)
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->MoveTo(box->Bounds().right - button->Bounds().Width() - 15, 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
151 								,"play"
152 								,"Play"
153 								,new BMessage(M_PLAY_MESSAGE)
154 								,B_FOLLOW_RIGHT | B_FOLLOW_TOP);
155 	button->ResizeToPreferred();
156 	button->MoveTo(rect.left - button->Bounds().Width() - 15, rect.top);
157 	box->AddChild(button);
158 
159 	view->MoveTo(0, listView->Frame().bottom);
160 	ResizeTo(Bounds().Width(), listView->Frame().bottom + view->Bounds().Height());
161 	listView->SetResizingMode(B_FOLLOW_ALL);
162 	view->SetResizingMode(B_FOLLOW_LEFT_RIGHT | B_FOLLOW_BOTTOM);
163 
164 	// setup file menu
165 	SetupMenuField();
166 	menu->FindItem("<none>")->SetMarked(true);
167 }
168 
169 
170 /***********************************************************
171  * MessageReceived
172  ***********************************************************/
173 void
174 HWindow::MessageReceived(BMessage *message)
175 {
176 	switch(message->what) {
177 	case M_OTHER_MESSAGE:
178 		{
179 			BMenuField *menufield = cast_as(FindView("filemenu"),BMenuField);
180 			BMenu *menu = menufield->Menu();
181 
182 			int32 sel = fEventList->CurrentSelection();
183 			if(sel >= 0) {
184 				HEventItem *item = cast_as(fEventList->ItemAt(sel),HEventItem);
185 				BPath path(item->Path());
186 				if(path.InitCheck() != B_OK) {
187 					BMenuItem *item = menu->FindItem("<none>");
188 					if(item)
189 						item->SetMarked(true);
190 				} else{
191 					BMenuItem *item = menu->FindItem(path.Leaf());
192 					if(item)
193 						item->SetMarked(true);
194 				}
195 			}
196 			fFilePanel->Show();
197 			break;
198 		}
199 	case B_SIMPLE_DATA:
200 	case B_REFS_RECEIVED:
201 		{
202 			entry_ref ref;
203 			int32 sel = fEventList->CurrentSelection();
204 			if(message->FindRef("refs",&ref) == B_OK && sel >= 0) {
205 				BMenuField *menufield = cast_as(FindView("filemenu"),BMenuField);
206 				BMenu *menu = menufield->Menu();
207 				// check audio file
208 				BNode node(&ref);
209 				BNodeInfo ninfo(&node);
210 				char type[B_MIME_TYPE_LENGTH+1];
211 				ninfo.GetType(type);
212 				BMimeType mtype(type);
213 				BMimeType superType;
214 				mtype.GetSupertype(&superType);
215 				if(strcmp(superType.Type(),"audio") != 0) {
216 					beep();
217 					(new BAlert("","This is not a audio file.","OK",NULL,NULL,
218 							B_WIDTH_AS_USUAL,B_STOP_ALERT))->Go();
219 					break;
220 				}
221 				// add file item
222 				BMessage *msg = new BMessage(M_ITEM_MESSAGE);
223 				BPath path(&ref);
224 				msg->AddRef("refs",&ref);
225 				BMenuItem *menuitem = menu->FindItem(path.Leaf());
226 				if(!menuitem)
227 					menu->AddItem(menuitem = new BMenuItem(path.Leaf(),msg),0);
228 				// refresh item
229 				fEventList->SetPath(BPath(&ref).Path());
230 				// check file menu
231 				if(menuitem)
232 					menuitem->SetMarked(true);
233 			}
234 			break;
235 		}
236 	case M_PLAY_MESSAGE:
237 		{
238 			int32 sel = fEventList->CurrentSelection();
239 			if(sel >= 0)
240 			{
241 				HEventItem *item = cast_as(fEventList->ItemAt(sel),HEventItem);
242 				const char* path = item->Path();
243 				if(path)
244 				{
245 					entry_ref ref;
246 					::get_ref_for_path(path,&ref);
247 					delete fPlayer;
248 					fPlayer = new BFileGameSound(&ref,false);
249 					fPlayer->StartPlaying();
250 				}
251 			}
252 			break;
253 		}
254 	case M_STOP_MESSAGE:
255 		{
256 			if(!fPlayer)
257 				break;
258 			if(fPlayer->IsPlaying())
259 			{
260 				fPlayer->StopPlaying();
261 				delete fPlayer;
262 				fPlayer = NULL;
263 			}
264 			break;
265 		}
266 	case M_EVENT_CHANGED:
267 		{
268 			const char* path;
269 			BMenuField *menufield = cast_as(FindView("filemenu"),BMenuField);
270 			BMenu *menu = menufield->Menu();
271 
272 			if(message->FindString("path",&path) == B_OK) {
273 				BPath path(path);
274 				if(path.InitCheck() != B_OK) {
275 					BMenuItem *item = menu->FindItem("<none>");
276 					if(item)
277 						item->SetMarked(true);
278 				} else {
279 					BMenuItem *item = menu->FindItem(path.Leaf());
280 					if(item)
281 						item->SetMarked(true);
282 				}
283 			}
284 			break;
285 		}
286 	case M_ITEM_MESSAGE:
287 		{
288 			entry_ref ref;
289 			if(message->FindRef("refs",&ref) == B_OK) {
290 				fEventList->SetPath(BPath(&ref).Path());
291 			}
292 			break;
293 		}
294 	case M_NONE_MESSAGE:
295 		{
296 			fEventList->SetPath(NULL);
297 			break;
298 		}
299 	default:
300 		_inherited::MessageReceived(message);
301 	}
302 }
303 
304 /***********************************************************
305  * Init menu
306  ***********************************************************/
307 void
308 HWindow::SetupMenuField()
309 {
310 	BMenuField *menufield = cast_as(FindView("filemenu"),BMenuField);
311 	BMenu *menu = menufield->Menu();
312 	int32 count = fEventList->CountItems();
313 	for(int32 i = 0; i < count; i++) {
314 		HEventItem *item = cast_as(fEventList->ItemAt(i), HEventItem);
315 		if(!item)
316 			continue;
317 
318 		BPath path(item->Path());
319 		if(path.InitCheck() != B_OK)
320 			continue;
321 		if(menu->FindItem(path.Leaf()))
322 			continue;
323 
324 		BMessage *msg = new BMessage(M_ITEM_MESSAGE);
325 		entry_ref ref;
326 		::get_ref_for_path(path.Path(),&ref);
327 		msg->AddRef("refs",&ref);
328 		menu->AddItem(new BMenuItem(path.Leaf(),msg),0);
329 	}
330 
331 	BPath path("/boot/beos/etc/sounds");
332 	status_t err = B_OK;
333 	BDirectory dir( path.Path() );
334 	BEntry entry;
335 	BPath item_path;
336    	while( err == B_OK ){
337 		err = dir.GetNextEntry( (BEntry*)&entry, TRUE );
338 		if( entry.InitCheck() != B_NO_ERROR ){
339 			break;
340 		}
341 		entry.GetPath(&item_path);
342 
343 		if( menu->FindItem(item_path.Leaf()) )
344 			continue;
345 
346 		BMessage *msg = new BMessage(M_ITEM_MESSAGE);
347 		entry_ref ref;
348 		::get_ref_for_path(item_path.Path(),&ref);
349 		msg->AddRef("refs",&ref);
350 		menu->AddItem(new BMenuItem(item_path.Leaf(),msg),0);
351 	}
352 
353 	path.SetTo("/boot/home/config/sounds");
354 	dir.SetTo(path.Path());
355 	err = B_OK;
356 	while( err == B_OK ){
357 		err = dir.GetNextEntry( (BEntry*)&entry, TRUE );
358 		if( entry.InitCheck() != B_NO_ERROR ){
359 			break;
360 		}
361 		entry.GetPath(&item_path);
362 
363 		if( menu->FindItem(item_path.Leaf()) )
364 			continue;
365 
366 		BMessage *msg = new BMessage(M_ITEM_MESSAGE);
367 		entry_ref ref;
368 
369 		::get_ref_for_path(item_path.Path(),&ref);
370 		msg->AddRef("refs",&ref);
371 		menu->AddItem(new BMenuItem(item_path.Leaf(),msg),0);
372 	}
373 
374 	path.SetTo("/boot/home/media");
375 	dir.SetTo(path.Path());
376 	err = B_OK;
377 	while( err == B_OK ){
378 		err = dir.GetNextEntry( (BEntry*)&entry, TRUE );
379 		if( entry.InitCheck() != B_NO_ERROR ){
380 			break;
381 		}
382 		entry.GetPath(&item_path);
383 
384 		if( menu->FindItem(item_path.Leaf()) )
385 			continue;
386 
387 		BMessage *msg = new BMessage(M_ITEM_MESSAGE);
388 		entry_ref ref;
389 
390 		::get_ref_for_path(item_path.Path(),&ref);
391 		msg->AddRef("refs",&ref);
392 		menu->AddItem(new BMenuItem(item_path.Leaf(),msg),0);
393 	}
394 
395 }
396 
397 
398 /***********************************************************
399  * Pulse
400  ***********************************************************/
401 void
402 HWindow::Pulse()
403 {
404 	int32 sel = fEventList->CurrentSelection();
405 	BMenuField *menufield = cast_as(FindView("filemenu"),BMenuField);
406 	BButton *button = cast_as(FindView("play"),BButton);
407 	BButton *stop = cast_as(FindView("stop"),BButton);
408 
409 	if(!menufield)
410 		return;
411 	if(sel >=0) {
412 		menufield->SetEnabled(true);
413 		button->SetEnabled(true);
414 	} else {
415 		menufield->SetEnabled(false);
416 		button->SetEnabled(false);
417 	}
418 	if(fPlayer) {
419 		if(fPlayer->IsPlaying())
420 			stop->SetEnabled(true);
421 		else
422 			stop->SetEnabled(false);
423 	} else
424 		stop->SetEnabled(false);
425 }
426 
427 
428 /***********************************************************
429  * DispatchMessage
430  ***********************************************************/
431 void
432 HWindow::DispatchMessage(BMessage *message,BHandler *handler)
433 {
434 	if(message->what == B_PULSE)
435 		Pulse();
436 	BWindow::DispatchMessage(message,handler);
437 }
438 
439 /***********************************************************
440  * QuitRequested
441  ***********************************************************/
442 bool
443 HWindow::QuitRequested()
444 {
445 	fEventList->RemoveAll();
446 	be_app->PostMessage(B_QUIT_REQUESTED);
447 	return true;
448 }
449