xref: /haiku/src/preferences/media/MediaWindow.cpp (revision 922e7ba1f3228e6f28db69b0ded8f86eb32dea17)
1 /*
2  * Copyright (c) 2003-2010, Haiku, Inc.
3  * Distributed under the terms of the MIT license.
4  *
5  * Authors:
6  *		Sikosis, Jérôme Duval
7  *		yourpalal, Alex Wilson
8  */
9 
10 
11 #include "MediaWindow.h"
12 
13 #include <stdio.h>
14 
15 #include <Alert.h>
16 #include <Application.h>
17 #include <Autolock.h>
18 #include <Bitmap.h>
19 #include <Button.h>
20 #include <CardLayout.h>
21 #include <Catalog.h>
22 #include <Debug.h>
23 #include <Deskbar.h>
24 #include <LayoutBuilder.h>
25 #include <Locale.h>
26 #include <MediaRoster.h>
27 #include <MediaTheme.h>
28 #include <Resources.h>
29 #include <Roster.h>
30 #include <Screen.h>
31 #include <ScrollView.h>
32 #include <SeparatorView.h>
33 #include <SpaceLayoutItem.h>
34 #include <StorageKit.h>
35 #include <String.h>
36 #include <TextView.h>
37 
38 #include "MediaIcons.h"
39 
40 
41 #undef B_TRANSLATE_CONTEXT
42 #define B_TRANSLATE_CONTEXT "Media Window"
43 
44 
45 const uint32 ML_SELECTED_NODE = 'MlSN';
46 const uint32 ML_INIT_MEDIA = 'MlIM';
47 
48 
49 class NodeListItemUpdater : public MediaListItem::Visitor {
50 public:
51 	typedef void (NodeListItem::*UpdateMethod)(bool);
52 
53 	NodeListItemUpdater(NodeListItem* target, UpdateMethod action)
54 		:
55 		fComparator(target),
56 		fAction(action)
57 	{
58 	}
59 
60 
61 	virtual	void	Visit(AudioMixerListItem*){}
62 	virtual	void	Visit(DeviceListItem*){}
63 
64 	virtual void	Visit(NodeListItem* item)
65 	{
66 		item->Accept(fComparator);
67 		(item->*(fAction))(fComparator.result == 0);
68 	}
69 
70 private:
71 
72 			NodeListItem::Comparator		fComparator;
73 			UpdateMethod					fAction;
74 };
75 
76 
77 MediaWindow::SmartNode::SmartNode(const BMessenger& notifyHandler)
78 	:
79 	fNode(NULL),
80 	fMessenger(notifyHandler)
81 {
82 }
83 
84 
85 MediaWindow::SmartNode::~SmartNode()
86 {
87 	_FreeNode();
88 }
89 
90 
91 void
92 MediaWindow::SmartNode::SetTo(const dormant_node_info* info)
93 {
94 	_FreeNode();
95 	if (!info)
96 		return;
97 
98 	fNode = new media_node();
99 	BMediaRoster* roster = BMediaRoster::Roster();
100 
101 	// TODO: error codes
102 	media_node_id node_id;
103 	if (roster->GetInstancesFor(info->addon, info->flavor_id, &node_id) == B_OK)
104 		roster->GetNodeFor(node_id, fNode);
105 	else
106 		roster->InstantiateDormantNode(*info, fNode, B_FLAVOR_IS_GLOBAL);
107 	roster->StartWatching(fMessenger, *fNode, B_MEDIA_WILDCARD);
108 }
109 
110 
111 void
112 MediaWindow::SmartNode::SetTo(const media_node& node)
113 {
114 	_FreeNode();
115 	fNode = new media_node(node);
116 	BMediaRoster* roster = BMediaRoster::Roster();
117 	roster->StartWatching(fMessenger, *fNode, B_MEDIA_WILDCARD);
118 }
119 
120 
121 bool
122 MediaWindow::SmartNode::IsSet()
123 {
124 	return fNode != NULL;
125 }
126 
127 
128 MediaWindow::SmartNode::operator media_node()
129 {
130 	if (fNode)
131 		return *fNode;
132 	media_node node;
133 	return node;
134 }
135 
136 
137 void
138 MediaWindow::SmartNode::_FreeNode()
139 {
140 	if (!IsSet())
141 		return;
142 	// TODO: check error codes
143 	BMediaRoster* roster = BMediaRoster::Roster();
144 	roster->StopWatching(fMessenger, *fNode, B_MEDIA_WILDCARD);
145 	roster->ReleaseNode(*fNode);
146 	delete fNode;
147 	fNode = NULL;
148 }
149 
150 
151 // MediaWindow - Constructor
152 MediaWindow::MediaWindow(BRect frame)
153 	:
154 	BWindow(frame, B_TRANSLATE_SYSTEM_NAME("Media"), B_TITLED_WINDOW,
155 		B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS),
156 	fCurrentNode(BMessenger(this)),
157 	fParamWeb(NULL),
158 	fAudioInputs(5, true),
159 	fAudioOutputs(5, true),
160 	fVideoInputs(5, true),
161 	fVideoOutputs(5, true),
162 	fAlert(NULL),
163 	fInitCheck(B_OK)
164 {
165 	InitWindow();
166 }
167 
168 
169 status_t
170 MediaWindow::InitCheck()
171 {
172 	return fInitCheck;
173 }
174 
175 
176 MediaWindow::~MediaWindow()
177 {
178 	_EmptyNodeLists();
179 	_ClearParamView();
180 
181 	char buffer[512];
182 	BRect rect = Frame();
183 	PRINT_OBJECT(rect);
184 	snprintf(buffer, 512, "# MediaPrefs Settings\n rect = %i,%i,%i,%i\n",
185 		int(rect.left), int(rect.top), int(rect.right), int(rect.bottom));
186 
187 	BPath path;
188 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
189 		path.Append(SETTINGS_FILE);
190 		BFile file(path.Path(), B_READ_WRITE|B_CREATE_FILE|B_ERASE_FILE);
191 		if (file.InitCheck()==B_OK) {
192 			file.Write(buffer, strlen(buffer));
193 		}
194 	}
195 }
196 
197 
198 void
199 MediaWindow::SelectNode(const dormant_node_info* node)
200 {
201 	fCurrentNode.SetTo(node);
202 	_MakeParamView();
203 	fTitleView->SetLabel(node->name);
204 }
205 
206 
207 void
208 MediaWindow::SelectAudioSettings(const char* title)
209 {
210 	fContentLayout->SetVisibleItem(fContentLayout->IndexOfView(fAudioView));
211 	fTitleView->SetLabel(title);
212 }
213 
214 
215 void
216 MediaWindow::SelectVideoSettings(const char* title)
217 {
218 	fContentLayout->SetVisibleItem(fContentLayout->IndexOfView(fVideoView));
219 	fTitleView->SetLabel(title);
220 }
221 
222 
223 void
224 MediaWindow::SelectAudioMixer(const char* title)
225 {
226 	media_node mixerNode;
227 	BMediaRoster* roster = BMediaRoster::Roster();
228 	roster->GetAudioMixer(&mixerNode);
229 	fCurrentNode.SetTo(mixerNode);
230 	_MakeParamView();
231 	fTitleView->SetLabel(title);
232 }
233 
234 
235 void
236 MediaWindow::UpdateInputListItem(MediaListItem::media_type type,
237 	const dormant_node_info* node)
238 {
239 	NodeListItem compareTo(node, type);
240 	NodeListItemUpdater updater(&compareTo, &NodeListItem::SetDefaultInput);
241 	for (int32 i = 0; i < fListView->CountItems(); i++) {
242 		MediaListItem* item = static_cast<MediaListItem*>(fListView->ItemAt(i));
243 		item->Accept(updater);
244 	}
245 	fListView->Invalidate();
246 }
247 
248 
249 void
250 MediaWindow::UpdateOutputListItem(MediaListItem::media_type type,
251 	const dormant_node_info* node)
252 {
253 	NodeListItem compareTo(node, type);
254 	NodeListItemUpdater updater(&compareTo, &NodeListItem::SetDefaultOutput);
255 	for (int32 i = 0; i < fListView->CountItems(); i++) {
256 		MediaListItem* item = static_cast<MediaListItem*>(fListView->ItemAt(i));
257 		item->Accept(updater);
258 	}
259 	fListView->Invalidate();
260 }
261 
262 
263 void
264 MediaWindow::_FindNodes()
265 {
266 	_FindNodes(B_MEDIA_RAW_AUDIO, B_PHYSICAL_OUTPUT, fAudioOutputs);
267 	_FindNodes(B_MEDIA_RAW_AUDIO, B_PHYSICAL_INPUT, fAudioInputs);
268 	_FindNodes(B_MEDIA_ENCODED_AUDIO, B_PHYSICAL_OUTPUT, fAudioOutputs);
269 	_FindNodes(B_MEDIA_ENCODED_AUDIO, B_PHYSICAL_INPUT, fAudioInputs);
270 	_FindNodes(B_MEDIA_RAW_VIDEO, B_PHYSICAL_OUTPUT, fVideoOutputs);
271 	_FindNodes(B_MEDIA_RAW_VIDEO, B_PHYSICAL_INPUT, fVideoInputs);
272 	_FindNodes(B_MEDIA_ENCODED_VIDEO, B_PHYSICAL_OUTPUT, fVideoOutputs);
273 	_FindNodes(B_MEDIA_ENCODED_VIDEO, B_PHYSICAL_INPUT, fVideoInputs);
274 }
275 
276 
277 void
278 MediaWindow::_FindNodes(media_type type, uint64 kind, NodeList& into)
279 {
280 	dormant_node_info node_info[64];
281 	int32 node_info_count = 64;
282 
283 	media_format format;
284 	media_format* nodeInputFormat = NULL, *nodeOutputFormat = NULL;
285 	format.type = type;
286 
287 	// output nodes must be BBufferConsumers => they have an input format
288 	// input nodes must be BBufferProducers => they have an output format
289 	if (kind & B_PHYSICAL_OUTPUT)
290 		nodeInputFormat = &format;
291 	else if (kind & B_PHYSICAL_INPUT)
292 		nodeOutputFormat = &format;
293 	else
294 		return;
295 
296 	BMediaRoster* roster = BMediaRoster::Roster();
297 
298 	if (roster->GetDormantNodes(node_info, &node_info_count, nodeInputFormat,
299 		nodeOutputFormat, NULL, kind) != B_OK) {
300 		// TODO: better error reporting!
301 		fprintf(stderr, "error\n");
302 		return;
303 	}
304 
305 	for (int32 i = 0; i < node_info_count; i++) {
306 		PRINT(("node : %s, media_addon %i, flavor_id %i\n",
307 			node_info[i].name, (int)node_info[i].addon,
308 			(int)node_info[i].flavor_id));
309 
310 		dormant_node_info* info = new dormant_node_info();
311 		strncpy(info->name, node_info[i].name, B_MEDIA_NAME_LENGTH);
312 		info->flavor_id = node_info[i].flavor_id;
313 		info->addon = node_info[i].addon;
314 		into.AddItem(info);
315 	}
316 }
317 
318 
319 NodeListItem*
320 MediaWindow::_FindNodeListItem(dormant_node_info* info)
321 {
322 	NodeListItem audioItem(info, MediaListItem::AUDIO_TYPE);
323 	NodeListItem videoItem(info, MediaListItem::VIDEO_TYPE);
324 
325 	NodeListItem::Comparator audioComparator(&audioItem);
326 	NodeListItem::Comparator videoComparator(&videoItem);
327 
328 	for (int32 i = 0; i < fListView->CountItems(); i++) {
329 		MediaListItem* item
330 			= static_cast<MediaListItem*>(fListView->ItemAt(i));
331 		item->Accept(audioComparator);
332 		if (audioComparator.result == 0)
333 			return static_cast<NodeListItem*>(item);
334 
335 		item->Accept(videoComparator);
336 		if (videoComparator.result == 0)
337 			return static_cast<NodeListItem*>(item);
338 	}
339 	return NULL;
340 }
341 
342 
343 void
344 MediaWindow::_UpdateListViewMinWidth()
345 {
346 	float width = 0;
347 	for (int32 i = 0; i < fListView->CountItems(); i++) {
348 		BListItem* item = fListView->ItemAt(i);
349 		width = max_c(width, item->Width());
350 	}
351 	fListView->SetExplicitMinSize(BSize(width, B_SIZE_UNSET));
352 	fListView->InvalidateLayout();
353 }
354 
355 
356 void
357 MediaWindow::_AddNodeItems(NodeList &list, MediaListItem::media_type type)
358 {
359 	int32 count = list.CountItems();
360 	for (int32 i = 0; i < count; i++) {
361 		dormant_node_info* info = list.ItemAt(i);
362 		if (!_FindNodeListItem(info))
363 			fListView->AddItem(new NodeListItem(info, type));
364 	}
365 }
366 
367 
368 void
369 MediaWindow::_EmptyNodeLists()
370 {
371 	fAudioOutputs.MakeEmpty();
372 	fAudioInputs.MakeEmpty();
373 	fVideoOutputs.MakeEmpty();
374 	fVideoInputs.MakeEmpty();
375 }
376 
377 
378 void
379 MediaWindow::InitWindow()
380 {
381 	fListView = new BListView("media_list_view");
382 	fListView->SetSelectionMessage(new BMessage(ML_SELECTED_NODE));
383 
384 	// Add ScrollView to Media Menu for pretty border
385 	BScrollView* scrollView = new BScrollView("listscroller",
386 		fListView, 0, false, false, B_FANCY_BORDER);
387 
388 	// Create the Views
389 	fTitleView = new BSeparatorView(B_HORIZONTAL, B_FANCY_BORDER);
390 	fTitleView->SetLabel(B_TRANSLATE("Audio settings"));
391 	fTitleView->SetFont(be_bold_font);
392 
393 	fContentLayout = new BCardLayout();
394 	new BView("content view", 0, fContentLayout);
395 	fContentLayout->Owner()->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
396 
397 	fAudioView = new AudioSettingsView();
398 	fContentLayout->AddView(fAudioView);
399 
400 	fVideoView = new VideoSettingsView();
401 	fContentLayout->AddView(fVideoView);
402 
403 
404 	// Layout all views
405 	BLayoutBuilder::Group<>(this, B_HORIZONTAL)
406 		.SetInsets(B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING,
407 			B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING)
408 		.Add(scrollView)
409 		.AddGroup(B_VERTICAL)
410 			.SetInsets(0, 0, 0, 0)
411 			.Add(fTitleView)
412 			.Add(fContentLayout);
413 
414 	// Start the window
415 	fInitCheck = InitMedia(true);
416 	if (fInitCheck != B_OK) {
417 		PostMessage(B_QUIT_REQUESTED);
418 	} else 	if (IsHidden()) {
419 			Show();
420 	}
421 }
422 
423 
424 // #pragma mark -
425 
426 
427 status_t
428 MediaWindow::InitMedia(bool first)
429 {
430 	status_t err = B_OK;
431 	BMediaRoster* roster = BMediaRoster::Roster(&err);
432 
433 	if (first && err != B_OK) {
434 		BAlert* alert = new BAlert("start_media_server",
435 			B_TRANSLATE("Could not connect to the media server.\n"
436 			"Would you like to start it ?"),
437 			B_TRANSLATE("Quit"),
438 			B_TRANSLATE("Start media server"), NULL,
439 			B_WIDTH_AS_USUAL, B_WARNING_ALERT);
440 		if (alert->Go()==0)
441 			return B_ERROR;
442 
443 		fAlert = new MediaAlert(BRect(0, 0, 300, 60),
444 			"restart_alert", B_TRANSLATE(
445 				"Restarting media services\nStarting media server"
446 				B_UTF8_ELLIPSIS "\n"));
447 		fAlert->Show();
448 
449 		Show();
450 
451 		launch_media_server();
452 	}
453 
454 	Lock();
455 
456 	bool isVideoSelected = true;
457 	if (!first && fListView->ItemAt(0) && fListView->ItemAt(0)->IsSelected())
458 		isVideoSelected = false;
459 
460 	if ((!first || (first && err) ) && fAlert) {
461 		BAutolock locker(fAlert);
462 		if (locker.IsLocked())
463 			fAlert->TextView()->SetText(
464 				B_TRANSLATE("Ready for use" B_UTF8_ELLIPSIS));
465 	}
466 
467 	while (fListView->CountItems() > 0)
468 		delete fListView->RemoveItem((int32)0);
469 	_EmptyNodeLists();
470 
471 	// Grab Media Info
472 	_FindNodes();
473 
474 	// Add video nodes first. They might have an additional audio
475 	// output or input, but still should be listed as video node.
476 	_AddNodeItems(fVideoOutputs, MediaListItem::VIDEO_TYPE);
477 	_AddNodeItems(fVideoInputs, MediaListItem::VIDEO_TYPE);
478 	_AddNodeItems(fAudioOutputs, MediaListItem::AUDIO_TYPE);
479 	_AddNodeItems(fAudioInputs, MediaListItem::AUDIO_TYPE);
480 
481 	fAudioView->AddOutputNodes(fAudioOutputs);
482 	fAudioView->AddInputNodes(fAudioInputs);
483 	fVideoView->AddOutputNodes(fVideoOutputs);
484 	fVideoView->AddInputNodes(fVideoInputs);
485 
486 	// build our list view
487 	DeviceListItem* audio = new DeviceListItem(B_TRANSLATE("Audio settings"),
488 		MediaListItem::AUDIO_TYPE);
489 	fListView->AddItem(audio);
490 
491 	MediaListItem* video = new DeviceListItem(B_TRANSLATE("Video settings"),
492 		MediaListItem::VIDEO_TYPE);
493 	fListView->AddItem(video);
494 
495 	MediaListItem* mixer = new AudioMixerListItem(B_TRANSLATE("Audio mixer"));
496 	fListView->AddItem(mixer);
497 
498 	fListView->SortItems(&MediaListItem::Compare);
499 	_UpdateListViewMinWidth();
500 
501 	// Set default nodes for our setting views
502 	media_node default_node;
503 	dormant_node_info node_info;
504 	int32 outputID;
505 	BString outputName;
506 
507 	if (roster->GetAudioInput(&default_node) == B_OK) {
508 		roster->GetDormantNodeFor(default_node, &node_info);
509 		fAudioView->SetDefaultInput(&node_info);
510 			// this causes our listview to be updated as well
511 	}
512 
513 	if (roster->GetAudioOutput(&default_node, &outputID, &outputName)==B_OK) {
514 		roster->GetDormantNodeFor(default_node, &node_info);
515 		fAudioView->SetDefaultOutput(&node_info);
516 		fAudioView->SetDefaultChannel(outputID);
517 			// this causes our listview to be updated as well
518 	}
519 
520 	if (roster->GetVideoInput(&default_node)==B_OK) {
521 		roster->GetDormantNodeFor(default_node, &node_info);
522 		fVideoView->SetDefaultInput(&node_info);
523 			// this causes our listview to be updated as well
524 	}
525 
526 	if (roster->GetVideoOutput(&default_node)==B_OK) {
527 		roster->GetDormantNodeFor(default_node, &node_info);
528 		fVideoView->SetDefaultOutput(&node_info);
529 			// this causes our listview to be updated as well
530 	}
531 
532 	if (first) {
533 		fListView->Select(fListView->IndexOf(mixer));
534 	} else {
535 		if (isVideoSelected)
536 			fListView->Select(fListView->IndexOf(video));
537 		else
538 			fListView->Select(fListView->IndexOf(audio));
539 	}
540 
541 	if (fAlert) {
542 		snooze(800000);
543 		fAlert->PostMessage(B_QUIT_REQUESTED);
544 	}
545 	fAlert = NULL;
546 
547 	Unlock();
548 
549 	return B_OK;
550 }
551 
552 
553 bool
554 MediaWindow::QuitRequested()
555 {
556 	// stop watching the MediaRoster
557 	fCurrentNode.SetTo(NULL);
558 	be_app->PostMessage(B_QUIT_REQUESTED);
559 	return true;
560 }
561 
562 
563 // ErrorAlert -- Displays a BAlert Box with a Custom Error or Debug Message
564 void
565 ErrorAlert(char* errorMessage) {
566 	printf("%s\n", errorMessage);
567 	BAlert* alert = new BAlert("BAlert", errorMessage, B_TRANSLATE("OK"),
568 		NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
569 	alert->Go();
570 	exit(1);
571 }
572 
573 
574 void
575 MediaWindow::MessageReceived(BMessage* message)
576 {
577 	switch(message->what)
578 	{
579 		case ML_INIT_MEDIA:
580 			InitMedia(false);
581 			break;
582 		case ML_RESTART_MEDIA_SERVER:
583 		{
584 			thread_id thread = spawn_thread(&MediaWindow::RestartMediaServices,
585 				"restart_thread", B_NORMAL_PRIORITY, this);
586 			if (thread < B_OK)
587 				fprintf(stderr, "couldn't create restart thread\n");
588 			else
589 				resume_thread(thread);
590 			break;
591 		}
592 		case B_MEDIA_WEB_CHANGED:
593 		case ML_SELECTED_NODE:
594 		{
595 			PRINT_OBJECT(*message);
596 
597 			MediaListItem* item = static_cast<MediaListItem*>(
598 					fListView->ItemAt(fListView->CurrentSelection()));
599 			if (!item)
600 				break;
601 
602 			fCurrentNode.SetTo(NULL);
603 			_ClearParamView();
604 			item->AlterWindow(this);
605 			break;
606 		}
607 		case B_SOME_APP_LAUNCHED:
608 			{
609 				PRINT_OBJECT(*message);
610 				if (!fAlert)
611 					break;
612 
613 				BString mimeSig;
614 				if (message->FindString("be:signature", &mimeSig) == B_OK
615 					&& (mimeSig == "application/x-vnd.Be.addon-host"
616 						|| mimeSig == "application/x-vnd.Be.media-server")) {
617 					fAlert->Lock();
618 					fAlert->TextView()->SetText(
619 						B_TRANSLATE("Starting media server" B_UTF8_ELLIPSIS));
620 					fAlert->Unlock();
621 				}
622 			}
623 			break;
624 		case B_SOME_APP_QUIT:
625 			{
626 				PRINT_OBJECT(*message);
627 				BString mimeSig;
628 				if (message->FindString("be:signature", &mimeSig) == B_OK) {
629 					if (mimeSig == "application/x-vnd.Be.addon-host"
630 						|| mimeSig == "application/x-vnd.Be.media-server") {
631 						BMediaRoster* roster = BMediaRoster::CurrentRoster();
632 						if (roster && roster->Lock())
633 							roster->Quit();
634 					}
635 				}
636 
637 			}
638 			break;
639 		default:
640 			BWindow::MessageReceived(message);
641 			break;
642 	}
643 }
644 
645 status_t
646 MediaWindow::RestartMediaServices(void* data)
647 {
648 	MediaWindow* window = (MediaWindow*)data;
649 	window->fAlert = new MediaAlert(BRect(0, 0, 300, 60),
650 		"restart_alert", B_TRANSLATE(
651 		"Restarting media services\nShutting down media server\n"));
652 
653 	window->fAlert->Show();
654 
655 	shutdown_media_server(B_INFINITE_TIMEOUT, MediaWindow::UpdateProgress,
656 		window->fAlert);
657 
658 	{
659 		BAutolock locker(window->fAlert);
660 		if (locker.IsLocked())
661 			window->fAlert->TextView()->SetText(
662 				B_TRANSLATE("Starting media server" B_UTF8_ELLIPSIS));
663 	}
664 	launch_media_server();
665 
666 	return window->PostMessage(ML_INIT_MEDIA);
667 }
668 
669 
670 bool
671 MediaWindow::UpdateProgress(int stage, const char * message, void * cookie)
672 {
673 	MediaAlert* alert = static_cast<MediaAlert*>(cookie);
674 	PRINT(("stage : %i\n", stage));
675 	const char* string = "Unknown stage";
676 	switch (stage) {
677 		case 10:
678 			string = B_TRANSLATE("Stopping media server" B_UTF8_ELLIPSIS);
679 			break;
680 		case 20:
681 			string = B_TRANSLATE("Telling media_addon_server to quit.");
682 			break;
683 		case 40:
684 			string = B_TRANSLATE("Waiting for media_server to quit.");
685 			break;
686 		case 70:
687 			string = B_TRANSLATE("Cleaning up.");
688 			break;
689 		case 100:
690 			string = B_TRANSLATE("Done shutting down.");
691 			break;
692 	}
693 
694 	BAutolock locker(alert);
695 	if (locker.IsLocked())
696 		alert->TextView()->SetText(string);
697 	return true;
698 }
699 
700 
701 void
702 MediaWindow::_ClearParamView()
703 {
704 	BLayoutItem* item = fContentLayout->VisibleItem();
705 	if (!item)
706 		return;
707 
708 	BView* view = item->View();
709 	if (view != fVideoView && view != fAudioView) {
710 		fContentLayout->RemoveItem(item);
711 		delete item;
712 		delete view;
713 		delete fParamWeb;
714 		fParamWeb = NULL;
715 	}
716 }
717 
718 
719 void
720 MediaWindow::_MakeParamView()
721 {
722 	if (!fCurrentNode.IsSet())
723 		return;
724 
725 	fParamWeb = NULL;
726 	BMediaRoster* roster = BMediaRoster::Roster();
727 	if (roster->GetParameterWebFor(fCurrentNode, &fParamWeb) == B_OK) {
728 		BRect hint(fContentLayout->Frame());
729 		BView* paramView = BMediaTheme::ViewFor(fParamWeb, &hint);
730 		if (paramView) {
731 			fContentLayout->AddView(paramView);
732 			fContentLayout->SetVisibleItem(fContentLayout->CountItems() - 1);
733 			return;
734 		}
735 	}
736 
737 	_MakeEmptyParamView();
738 }
739 
740 
741 void
742 MediaWindow::_MakeEmptyParamView()
743 {
744 	fParamWeb = NULL;
745 
746 	BStringView* stringView = new BStringView("noControls",
747 		B_TRANSLATE("This hardware has no controls."));
748 
749 	BSize unlimited(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED);
750 	stringView->SetExplicitMaxSize(unlimited);
751 
752 	BAlignment centered(B_ALIGN_HORIZONTAL_CENTER,
753 		B_ALIGN_VERTICAL_CENTER);
754 	stringView->SetExplicitAlignment(centered);
755 	stringView->SetAlignment(B_ALIGN_CENTER);
756 
757 	fContentLayout->AddView(stringView);
758 	fContentLayout->SetVisibleItem(fContentLayout->CountItems() - 1);
759 
760 	rgb_color panel = stringView->LowColor();
761 	stringView->SetHighColor(tint_color(panel,
762 		B_DISABLED_LABEL_TINT));
763 }
764 
765