xref: /haiku/src/preferences/sounds/HWindow.cpp (revision 1d9d47fc72028bb71b5f232a877231e59cfe2438)
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 *view = new BView(rect,"",B_FOLLOW_ALL, B_WILL_DRAW|B_PULSE_NEEDED);
78 	view->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
79 	AddChild(view);
80 
81 	BRect stringRect(16, 5, 60, 22);
82 	BStringView *stringView = new BStringView(stringRect, "event", "Event");
83 	stringView->SetFont(be_bold_font);
84 	view->AddChild(stringView);
85 
86 	stringRect.OffsetBy(100, 0);
87 	stringView = new BStringView(stringRect, "sound", "Sound");
88 	stringView->SetFont(be_bold_font);
89 	view->AddChild(stringView);
90 
91 	rect.left += 13;
92 	rect.right -= B_V_SCROLL_BAR_WIDTH + 13;
93 	rect.top += 28;
94 	rect.bottom -= 7;
95 	fEventList = new HEventList(rect);
96 	fEventList->SetType(BMediaFiles::B_SOUNDS);
97 
98 	BScrollView *scrollView = new BScrollView(""
99 									,fEventList
100 									,B_FOLLOW_ALL
101 									,0
102 									,false
103 									,true);
104 	view->AddChild(scrollView);
105 
106 	rect = Bounds();
107 	rect.top = rect.bottom - 105;
108 	view = new BView(rect,"",B_FOLLOW_LEFT_RIGHT|B_FOLLOW_BOTTOM,B_WILL_DRAW|B_PULSE_NEEDED);
109 	view->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
110 	AddChild(view);
111 	rect = view->Bounds().InsetBySelf(12, 12);
112 	BBox *box = new BBox(rect,"",B_FOLLOW_ALL);
113 	view->AddChild(box);
114 	rect = box->Bounds();
115 	rect.top += 10;
116 	rect.left += 15;
117 	rect.right -= 10;
118 	rect.bottom = rect.top + 20;
119 	BMenu *menu = new BMenu("file");
120 	menu->SetRadioMode(true);
121 	menu->SetLabelFromMarked(true);
122 	menu->AddSeparatorItem();
123 
124 	menu->AddItem(new BMenuItem("<none>",new BMessage(M_NONE_MESSAGE)));
125 	menu->AddItem(new BMenuItem("Other…",new BMessage(M_OTHER_MESSAGE)));
126 	BMenuField *menuField = new BMenuField(rect
127 										,"filemenu"
128 										,"Sound File:"
129 										,menu
130 										,B_FOLLOW_TOP|B_FOLLOW_LEFT);
131 	menuField->SetDivider(menuField->StringWidth("Sound File:")+10);
132 	box->AddChild(menuField);
133 	rect.OffsetBy(-2,38);
134 	rect.left = rect.right - 80;
135 	BButton *button = new BButton(rect
136 						,"stop"
137 						,"Stop"
138 						,new BMessage(M_STOP_MESSAGE)
139 						,B_FOLLOW_RIGHT|B_FOLLOW_TOP);
140 	box->AddChild(button);
141 
142 	rect.OffsetBy(-90,0);
143 	button = new BButton(rect
144 								,"play"
145 								,"Play"
146 								,new BMessage(M_PLAY_MESSAGE)
147 								,B_FOLLOW_RIGHT|B_FOLLOW_TOP);
148 	box->AddChild(button);
149 
150 	// setup file menu
151 	SetupMenuField();
152 	menu->FindItem("<none>")->SetMarked(true);
153 }
154 
155 
156 /***********************************************************
157  * MessageReceived
158  ***********************************************************/
159 void
160 HWindow::MessageReceived(BMessage *message)
161 {
162 	switch(message->what) {
163 	case M_OTHER_MESSAGE:
164 		{
165 			BMenuField *menufield = cast_as(FindView("filemenu"),BMenuField);
166 			BMenu *menu = menufield->Menu();
167 
168 			int32 sel = fEventList->CurrentSelection();
169 			if(sel >= 0) {
170 				HEventItem *item = cast_as(fEventList->ItemAt(sel),HEventItem);
171 				BPath path(item->Path());
172 				if(path.InitCheck() != B_OK) {
173 					BMenuItem *item = menu->FindItem("<none>");
174 					if(item)
175 						item->SetMarked(true);
176 				} else{
177 					BMenuItem *item = menu->FindItem(path.Leaf());
178 					if(item)
179 						item->SetMarked(true);
180 				}
181 			}
182 			fFilePanel->Show();
183 			break;
184 		}
185 	case B_SIMPLE_DATA:
186 	case B_REFS_RECEIVED:
187 		{
188 			entry_ref ref;
189 			int32 sel = fEventList->CurrentSelection();
190 			if(message->FindRef("refs",&ref) == B_OK && sel >= 0) {
191 				BMenuField *menufield = cast_as(FindView("filemenu"),BMenuField);
192 				BMenu *menu = menufield->Menu();
193 				// check audio file
194 				BNode node(&ref);
195 				BNodeInfo ninfo(&node);
196 				char type[B_MIME_TYPE_LENGTH+1];
197 				ninfo.GetType(type);
198 				BMimeType mtype(type);
199 				BMimeType superType;
200 				mtype.GetSupertype(&superType);
201 				if(strcmp(superType.Type(),"audio") != 0) {
202 					beep();
203 					(new BAlert("","This is not a audio file.","OK",NULL,NULL,
204 							B_WIDTH_AS_USUAL,B_STOP_ALERT))->Go();
205 					break;
206 				}
207 				// add file item
208 				BMessage *msg = new BMessage(M_ITEM_MESSAGE);
209 				BPath path(&ref);
210 				msg->AddRef("refs",&ref);
211 				BMenuItem *menuitem = menu->FindItem(path.Leaf());
212 				if(!menuitem)
213 					menu->AddItem(menuitem = new BMenuItem(path.Leaf(),msg),0);
214 				// refresh item
215 				fEventList->SetPath(BPath(&ref).Path());
216 				// check file menu
217 				if(menuitem)
218 					menuitem->SetMarked(true);
219 			}
220 			break;
221 		}
222 	case M_PLAY_MESSAGE:
223 		{
224 			int32 sel = fEventList->CurrentSelection();
225 			if(sel >= 0)
226 			{
227 				HEventItem *item = cast_as(fEventList->ItemAt(sel),HEventItem);
228 				const char* path = item->Path();
229 				if(path)
230 				{
231 					entry_ref ref;
232 					::get_ref_for_path(path,&ref);
233 					delete fPlayer;
234 					fPlayer = new BFileGameSound(&ref,false);
235 					fPlayer->StartPlaying();
236 				}
237 			}
238 			break;
239 		}
240 	case M_STOP_MESSAGE:
241 		{
242 			if(!fPlayer)
243 				break;
244 			if(fPlayer->IsPlaying())
245 			{
246 				fPlayer->StopPlaying();
247 				delete fPlayer;
248 				fPlayer = NULL;
249 			}
250 			break;
251 		}
252 	case M_EVENT_CHANGED:
253 		{
254 			const char* path;
255 			BMenuField *menufield = cast_as(FindView("filemenu"),BMenuField);
256 			BMenu *menu = menufield->Menu();
257 
258 			if(message->FindString("path",&path) == B_OK) {
259 				BPath path(path);
260 				if(path.InitCheck() != B_OK) {
261 					BMenuItem *item = menu->FindItem("<none>");
262 					if(item)
263 						item->SetMarked(true);
264 				} else {
265 					BMenuItem *item = menu->FindItem(path.Leaf());
266 					if(item)
267 						item->SetMarked(true);
268 				}
269 			}
270 			break;
271 		}
272 	case M_ITEM_MESSAGE:
273 		{
274 			entry_ref ref;
275 			if(message->FindRef("refs",&ref) == B_OK) {
276 				fEventList->SetPath(BPath(&ref).Path());
277 			}
278 			break;
279 		}
280 	case M_NONE_MESSAGE:
281 		{
282 			fEventList->SetPath(NULL);
283 			break;
284 		}
285 	default:
286 		_inherited::MessageReceived(message);
287 	}
288 }
289 
290 /***********************************************************
291  * Init menu
292  ***********************************************************/
293 void
294 HWindow::SetupMenuField()
295 {
296 	BMenuField *menufield = cast_as(FindView("filemenu"),BMenuField);
297 	BMenu *menu = menufield->Menu();
298 	int32 count = fEventList->CountItems();
299 	for(int32 i = 0; i < count; i++) {
300 		HEventItem *item = cast_as(fEventList->ItemAt(i), HEventItem);
301 		if(!item)
302 			continue;
303 
304 		BPath path(item->Path());
305 		if(path.InitCheck() != B_OK)
306 			continue;
307 		if(menu->FindItem(path.Leaf()))
308 			continue;
309 
310 		BMessage *msg = new BMessage(M_ITEM_MESSAGE);
311 		entry_ref ref;
312 		::get_ref_for_path(path.Path(),&ref);
313 		msg->AddRef("refs",&ref);
314 		menu->AddItem(new BMenuItem(path.Leaf(),msg),0);
315 	}
316 
317 	BPath path("/boot/beos/etc/sounds");
318 	status_t err = B_OK;
319 	BDirectory dir( path.Path() );
320 	BEntry entry;
321 	BPath item_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 		::get_ref_for_path(item_path.Path(),&ref);
335 		msg->AddRef("refs",&ref);
336 		menu->AddItem(new BMenuItem(item_path.Leaf(),msg),0);
337 	}
338 
339 	path.SetTo("/boot/home/config/sounds");
340 	dir.SetTo(path.Path());
341 	err = B_OK;
342 	while( err == B_OK ){
343 		err = dir.GetNextEntry( (BEntry*)&entry, TRUE );
344 		if( entry.InitCheck() != B_NO_ERROR ){
345 			break;
346 		}
347 		entry.GetPath(&item_path);
348 
349 		if( menu->FindItem(item_path.Leaf()) )
350 			continue;
351 
352 		BMessage *msg = new BMessage(M_ITEM_MESSAGE);
353 		entry_ref ref;
354 
355 		::get_ref_for_path(item_path.Path(),&ref);
356 		msg->AddRef("refs",&ref);
357 		menu->AddItem(new BMenuItem(item_path.Leaf(),msg),0);
358 	}
359 
360 	path.SetTo("/boot/home/media");
361 	dir.SetTo(path.Path());
362 	err = B_OK;
363 	while( err == B_OK ){
364 		err = dir.GetNextEntry( (BEntry*)&entry, TRUE );
365 		if( entry.InitCheck() != B_NO_ERROR ){
366 			break;
367 		}
368 		entry.GetPath(&item_path);
369 
370 		if( menu->FindItem(item_path.Leaf()) )
371 			continue;
372 
373 		BMessage *msg = new BMessage(M_ITEM_MESSAGE);
374 		entry_ref ref;
375 
376 		::get_ref_for_path(item_path.Path(),&ref);
377 		msg->AddRef("refs",&ref);
378 		menu->AddItem(new BMenuItem(item_path.Leaf(),msg),0);
379 	}
380 
381 }
382 
383 
384 /***********************************************************
385  * Pulse
386  ***********************************************************/
387 void
388 HWindow::Pulse()
389 {
390 	int32 sel = fEventList->CurrentSelection();
391 	BMenuField *menufield = cast_as(FindView("filemenu"),BMenuField);
392 	BButton *button = cast_as(FindView("play"),BButton);
393 	BButton *stop = cast_as(FindView("stop"),BButton);
394 
395 	if(!menufield)
396 		return;
397 	if(sel >=0) {
398 		menufield->SetEnabled(true);
399 		button->SetEnabled(true);
400 	} else {
401 		menufield->SetEnabled(false);
402 		button->SetEnabled(false);
403 	}
404 	if(fPlayer) {
405 		if(fPlayer->IsPlaying())
406 			stop->SetEnabled(true);
407 		else
408 			stop->SetEnabled(false);
409 	} else
410 		stop->SetEnabled(false);
411 }
412 
413 
414 /***********************************************************
415  * DispatchMessage
416  ***********************************************************/
417 void
418 HWindow::DispatchMessage(BMessage *message,BHandler *handler)
419 {
420 	if(message->what == B_PULSE)
421 		Pulse();
422 	BWindow::DispatchMessage(message,handler);
423 }
424 
425 /***********************************************************
426  * QuitRequested
427  ***********************************************************/
428 bool
429 HWindow::QuitRequested()
430 {
431 	fEventList->RemoveAll();
432 	be_app->PostMessage(B_QUIT_REQUESTED);
433 	return true;
434 }
435