xref: /haiku/src/preferences/media/MediaWindow.cpp (revision 54391a5df206f617a4bf6e67fe5baf9c8b70a525)
1 /*
2  * Copyright 2003-2012, 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_TRANSLATION_CONTEXT
42 #define B_TRANSLATION_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 // #pragma mark -
152 
153 
154 MediaWindow::MediaWindow(BRect frame)
155 	:
156 	BWindow(frame, B_TRANSLATE_SYSTEM_NAME("Media"), B_TITLED_WINDOW,
157 		B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS),
158 	fCurrentNode(BMessenger(this)),
159 	fParamWeb(NULL),
160 	fAudioInputs(5, true),
161 	fAudioOutputs(5, true),
162 	fVideoInputs(5, true),
163 	fVideoOutputs(5, true),
164 	fAlert(NULL),
165 	fInitCheck(B_OK)
166 {
167 	_InitWindow();
168 }
169 
170 
171 MediaWindow::~MediaWindow()
172 {
173 	_EmptyNodeLists();
174 	_ClearParamView();
175 
176 	char buffer[512];
177 	BRect rect = Frame();
178 	PRINT_OBJECT(rect);
179 	snprintf(buffer, 512, "# MediaPrefs Settings\n rect = %i,%i,%i,%i\n",
180 		int(rect.left), int(rect.top), int(rect.right), int(rect.bottom));
181 
182 	BPath path;
183 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
184 		path.Append(SETTINGS_FILE);
185 		BFile file(path.Path(), B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
186 		if (file.InitCheck() == B_OK)
187 			file.Write(buffer, strlen(buffer));
188 	}
189 }
190 
191 
192 status_t
193 MediaWindow::InitCheck()
194 {
195 	return fInitCheck;
196 }
197 
198 
199 void
200 MediaWindow::SelectNode(const dormant_node_info* node)
201 {
202 	fCurrentNode.SetTo(node);
203 	_MakeParamView();
204 	fTitleView->SetLabel(node->name);
205 }
206 
207 
208 void
209 MediaWindow::SelectAudioSettings(const char* title)
210 {
211 	fContentLayout->SetVisibleItem(fContentLayout->IndexOfView(fAudioView));
212 	fTitleView->SetLabel(title);
213 }
214 
215 
216 void
217 MediaWindow::SelectVideoSettings(const char* title)
218 {
219 	fContentLayout->SetVisibleItem(fContentLayout->IndexOfView(fVideoView));
220 	fTitleView->SetLabel(title);
221 }
222 
223 
224 void
225 MediaWindow::SelectAudioMixer(const char* title)
226 {
227 	media_node mixerNode;
228 	BMediaRoster* roster = BMediaRoster::Roster();
229 	roster->GetAudioMixer(&mixerNode);
230 	fCurrentNode.SetTo(mixerNode);
231 	_MakeParamView();
232 	fTitleView->SetLabel(title);
233 }
234 
235 
236 void
237 MediaWindow::UpdateInputListItem(MediaListItem::media_type type,
238 	const dormant_node_info* node)
239 {
240 	NodeListItem compareTo(node, type);
241 	NodeListItemUpdater updater(&compareTo, &NodeListItem::SetDefaultInput);
242 	for (int32 i = 0; i < fListView->CountItems(); i++) {
243 		MediaListItem* item = static_cast<MediaListItem*>(fListView->ItemAt(i));
244 		item->Accept(updater);
245 	}
246 	fListView->Invalidate();
247 }
248 
249 
250 void
251 MediaWindow::UpdateOutputListItem(MediaListItem::media_type type,
252 	const dormant_node_info* node)
253 {
254 	NodeListItem compareTo(node, type);
255 	NodeListItemUpdater updater(&compareTo, &NodeListItem::SetDefaultOutput);
256 	for (int32 i = 0; i < fListView->CountItems(); i++) {
257 		MediaListItem* item = static_cast<MediaListItem*>(fListView->ItemAt(i));
258 		item->Accept(updater);
259 	}
260 	fListView->Invalidate();
261 }
262 
263 
264 bool
265 MediaWindow::QuitRequested()
266 {
267 	// stop watching the MediaRoster
268 	fCurrentNode.SetTo(NULL);
269 	be_app->PostMessage(B_QUIT_REQUESTED);
270 	return true;
271 }
272 
273 
274 void
275 MediaWindow::MessageReceived(BMessage* message)
276 {
277 	switch (message->what) {
278 		case ML_INIT_MEDIA:
279 			_InitMedia(false);
280 			break;
281 		case ML_RESTART_MEDIA_SERVER:
282 		{
283 			thread_id thread = spawn_thread(&MediaWindow::_RestartMediaServices,
284 				"restart_thread", B_NORMAL_PRIORITY, this);
285 			if (thread < 0)
286 				fprintf(stderr, "couldn't create restart thread\n");
287 			else
288 				resume_thread(thread);
289 			break;
290 		}
291 		case B_MEDIA_WEB_CHANGED:
292 		case ML_SELECTED_NODE:
293 		{
294 			PRINT_OBJECT(*message);
295 
296 			MediaListItem* item = static_cast<MediaListItem*>(
297 					fListView->ItemAt(fListView->CurrentSelection()));
298 			if (item == NULL)
299 				break;
300 
301 			fCurrentNode.SetTo(NULL);
302 			_ClearParamView();
303 			item->AlterWindow(this);
304 			break;
305 		}
306 		case B_SOME_APP_LAUNCHED:
307 		{
308 			PRINT_OBJECT(*message);
309 			if (fAlert == NULL)
310 				break;
311 
312 			BString mimeSig;
313 			if (message->FindString("be:signature", &mimeSig) == B_OK
314 				&& (mimeSig == "application/x-vnd.Be.addon-host"
315 					|| mimeSig == "application/x-vnd.Be.media-server")) {
316 				fAlert->Lock();
317 				fAlert->TextView()->SetText(
318 					B_TRANSLATE("Starting media server" B_UTF8_ELLIPSIS));
319 				fAlert->Unlock();
320 			}
321 			break;
322 		}
323 		case B_SOME_APP_QUIT:
324 		{
325 			PRINT_OBJECT(*message);
326 			BString mimeSig;
327 			if (message->FindString("be:signature", &mimeSig) == B_OK) {
328 				if (mimeSig == "application/x-vnd.Be.addon-host"
329 					|| mimeSig == "application/x-vnd.Be.media-server") {
330 					BMediaRoster* roster = BMediaRoster::CurrentRoster();
331 					if (roster != NULL && roster->Lock())
332 						roster->Quit();
333 				}
334 			}
335 			break;
336 		}
337 		default:
338 			BWindow::MessageReceived(message);
339 			break;
340 	}
341 }
342 
343 
344 // #pragma mark - private
345 
346 
347 void
348 MediaWindow::_InitWindow()
349 {
350 	fListView = new BListView("media_list_view");
351 	fListView->SetSelectionMessage(new BMessage(ML_SELECTED_NODE));
352 	fListView->SetExplicitMinSize(BSize(140, B_SIZE_UNSET));
353 
354 	// Add ScrollView to Media Menu for pretty border
355 	BScrollView* scrollView = new BScrollView("listscroller",
356 		fListView, 0, false, false, B_FANCY_BORDER);
357 
358 	// Create the Views
359 	fTitleView = new BSeparatorView(B_HORIZONTAL, B_FANCY_BORDER);
360 	fTitleView->SetLabel(B_TRANSLATE("Audio settings"));
361 	fTitleView->SetFont(be_bold_font);
362 
363 	fContentLayout = new BCardLayout();
364 	new BView("content view", 0, fContentLayout);
365 	fContentLayout->Owner()->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
366 
367 	fAudioView = new AudioSettingsView();
368 	fContentLayout->AddView(fAudioView);
369 
370 	fVideoView = new VideoSettingsView();
371 	fContentLayout->AddView(fVideoView);
372 
373 	// Layout all views
374 	BLayoutBuilder::Group<>(this, B_HORIZONTAL)
375 		.SetInsets(B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING,
376 			B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING)
377 		.Add(scrollView, 0.0f)
378 		.AddGroup(B_VERTICAL)
379 			.SetInsets(0, 0, 0, 0)
380 			.Add(fTitleView)
381 			.Add(fContentLayout);
382 
383 	// Start the window
384 	fInitCheck = _InitMedia(true);
385 	if (fInitCheck != B_OK)
386 		PostMessage(B_QUIT_REQUESTED);
387 	else if (IsHidden())
388 		Show();
389 }
390 
391 
392 status_t
393 MediaWindow::_InitMedia(bool first)
394 {
395 	status_t err = B_OK;
396 	BMediaRoster* roster = BMediaRoster::Roster(&err);
397 
398 	if (first && err != B_OK) {
399 		BAlert* alert = new BAlert("start_media_server",
400 			B_TRANSLATE("Could not connect to the media server.\n"
401 				"Would you like to start it ?"),
402 			B_TRANSLATE("Quit"),
403 			B_TRANSLATE("Start media server"), NULL,
404 			B_WIDTH_AS_USUAL, B_WARNING_ALERT);
405 		alert->SetShortcut(0, B_ESCAPE);
406 		if (alert->Go() == 0)
407 			return B_ERROR;
408 
409 		fAlert = new MediaAlert(BRect(0, 0, 300, 60), "restart_alert",
410 			B_TRANSLATE("Restarting media services\nStarting media server"
411 				B_UTF8_ELLIPSIS "\n"));
412 		fAlert->Show();
413 
414 		Show();
415 
416 		launch_media_server();
417 	}
418 
419 	Lock();
420 
421 	bool isVideoSelected = true;
422 	if (!first && fListView->ItemAt(0) != NULL
423 		&& fListView->ItemAt(0)->IsSelected())
424 		isVideoSelected = false;
425 
426 	if ((!first || (first && err) ) && fAlert) {
427 		BAutolock locker(fAlert);
428 		if (locker.IsLocked())
429 			fAlert->TextView()->SetText(
430 				B_TRANSLATE("Ready for use" B_UTF8_ELLIPSIS));
431 	}
432 
433 	while (fListView->CountItems() > 0)
434 		delete fListView->RemoveItem((int32)0);
435 	_EmptyNodeLists();
436 
437 	// Grab Media Info
438 	_FindNodes();
439 
440 	// Add video nodes first. They might have an additional audio
441 	// output or input, but still should be listed as video node.
442 	_AddNodeItems(fVideoOutputs, MediaListItem::VIDEO_TYPE);
443 	_AddNodeItems(fVideoInputs, MediaListItem::VIDEO_TYPE);
444 	_AddNodeItems(fAudioOutputs, MediaListItem::AUDIO_TYPE);
445 	_AddNodeItems(fAudioInputs, MediaListItem::AUDIO_TYPE);
446 
447 	fAudioView->AddOutputNodes(fAudioOutputs);
448 	fAudioView->AddInputNodes(fAudioInputs);
449 	fVideoView->AddOutputNodes(fVideoOutputs);
450 	fVideoView->AddInputNodes(fVideoInputs);
451 
452 	// build our list view
453 	DeviceListItem* audio = new DeviceListItem(B_TRANSLATE("Audio settings"),
454 		MediaListItem::AUDIO_TYPE);
455 	fListView->AddItem(audio);
456 
457 	MediaListItem* video = new DeviceListItem(B_TRANSLATE("Video settings"),
458 		MediaListItem::VIDEO_TYPE);
459 	fListView->AddItem(video);
460 
461 	MediaListItem* mixer = new AudioMixerListItem(B_TRANSLATE("Audio mixer"));
462 	fListView->AddItem(mixer);
463 
464 	fListView->SortItems(&MediaListItem::Compare);
465 	_UpdateListViewMinWidth();
466 
467 	// Set default nodes for our setting views
468 	media_node defaultNode;
469 	dormant_node_info nodeInfo;
470 	int32 outputID;
471 	BString outputName;
472 
473 	if (roster->GetAudioInput(&defaultNode) == B_OK) {
474 		roster->GetDormantNodeFor(defaultNode, &nodeInfo);
475 		fAudioView->SetDefaultInput(&nodeInfo);
476 			// this causes our listview to be updated as well
477 	}
478 
479 	if (roster->GetAudioOutput(&defaultNode, &outputID, &outputName) == B_OK) {
480 		roster->GetDormantNodeFor(defaultNode, &nodeInfo);
481 		fAudioView->SetDefaultOutput(&nodeInfo);
482 		fAudioView->SetDefaultChannel(outputID);
483 			// this causes our listview to be updated as well
484 	}
485 
486 	if (roster->GetVideoInput(&defaultNode) == B_OK) {
487 		roster->GetDormantNodeFor(defaultNode, &nodeInfo);
488 		fVideoView->SetDefaultInput(&nodeInfo);
489 			// this causes our listview to be updated as well
490 	}
491 
492 	if (roster->GetVideoOutput(&defaultNode) == B_OK) {
493 		roster->GetDormantNodeFor(defaultNode, &nodeInfo);
494 		fVideoView->SetDefaultOutput(&nodeInfo);
495 			// this causes our listview to be updated as well
496 	}
497 
498 	if (first)
499 		fListView->Select(fListView->IndexOf(mixer));
500 	else if (isVideoSelected)
501 		fListView->Select(fListView->IndexOf(video));
502 	else
503 		fListView->Select(fListView->IndexOf(audio));
504 
505 	if (fAlert != NULL) {
506 		snooze(800000);
507 		fAlert->PostMessage(B_QUIT_REQUESTED);
508 	}
509 	fAlert = NULL;
510 
511 	Unlock();
512 
513 	return B_OK;
514 }
515 
516 
517 void
518 MediaWindow::_FindNodes()
519 {
520 	_FindNodes(B_MEDIA_RAW_AUDIO, B_PHYSICAL_OUTPUT, fAudioOutputs);
521 	_FindNodes(B_MEDIA_RAW_AUDIO, B_PHYSICAL_INPUT, fAudioInputs);
522 	_FindNodes(B_MEDIA_ENCODED_AUDIO, B_PHYSICAL_OUTPUT, fAudioOutputs);
523 	_FindNodes(B_MEDIA_ENCODED_AUDIO, B_PHYSICAL_INPUT, fAudioInputs);
524 	_FindNodes(B_MEDIA_RAW_VIDEO, B_PHYSICAL_OUTPUT, fVideoOutputs);
525 	_FindNodes(B_MEDIA_RAW_VIDEO, B_PHYSICAL_INPUT, fVideoInputs);
526 	_FindNodes(B_MEDIA_ENCODED_VIDEO, B_PHYSICAL_OUTPUT, fVideoOutputs);
527 	_FindNodes(B_MEDIA_ENCODED_VIDEO, B_PHYSICAL_INPUT, fVideoInputs);
528 }
529 
530 
531 void
532 MediaWindow::_FindNodes(media_type type, uint64 kind, NodeList& into)
533 {
534 	dormant_node_info nodeInfo[64];
535 	int32 nodeInfoCount = 64;
536 
537 	media_format format;
538 	media_format* nodeInputFormat = NULL;
539 	media_format* nodeOutputFormat = NULL;
540 	format.type = type;
541 
542 	// output nodes must be BBufferConsumers => they have an input format
543 	// input nodes must be BBufferProducers => they have an output format
544 	if ((kind & B_PHYSICAL_OUTPUT) != 0)
545 		nodeInputFormat = &format;
546 	else if ((kind & B_PHYSICAL_INPUT) != 0)
547 		nodeOutputFormat = &format;
548 	else
549 		return;
550 
551 	BMediaRoster* roster = BMediaRoster::Roster();
552 
553 	if (roster->GetDormantNodes(nodeInfo, &nodeInfoCount, nodeInputFormat,
554 			nodeOutputFormat, NULL, kind) != B_OK) {
555 		// TODO: better error reporting!
556 		fprintf(stderr, "error\n");
557 		return;
558 	}
559 
560 	for (int32 i = 0; i < nodeInfoCount; i++) {
561 		PRINT(("node : %s, media_addon %i, flavor_id %i\n",
562 			nodeInfo[i].name, (int)nodeInfo[i].addon,
563 			(int)nodeInfo[i].flavor_id));
564 
565 		dormant_node_info* info = new dormant_node_info();
566 		strncpy(info->name, nodeInfo[i].name, B_MEDIA_NAME_LENGTH);
567 		info->flavor_id = nodeInfo[i].flavor_id;
568 		info->addon = nodeInfo[i].addon;
569 		into.AddItem(info);
570 	}
571 }
572 
573 
574 void
575 MediaWindow::_AddNodeItems(NodeList& list, MediaListItem::media_type type)
576 {
577 	int32 count = list.CountItems();
578 	for (int32 i = 0; i < count; i++) {
579 		dormant_node_info* info = list.ItemAt(i);
580 		if (_FindNodeListItem(info) == NULL)
581 			fListView->AddItem(new NodeListItem(info, type));
582 	}
583 }
584 
585 
586 void
587 MediaWindow::_EmptyNodeLists()
588 {
589 	fAudioOutputs.MakeEmpty();
590 	fAudioInputs.MakeEmpty();
591 	fVideoOutputs.MakeEmpty();
592 	fVideoInputs.MakeEmpty();
593 }
594 
595 
596 NodeListItem*
597 MediaWindow::_FindNodeListItem(dormant_node_info* info)
598 {
599 	NodeListItem audioItem(info, MediaListItem::AUDIO_TYPE);
600 	NodeListItem videoItem(info, MediaListItem::VIDEO_TYPE);
601 
602 	NodeListItem::Comparator audioComparator(&audioItem);
603 	NodeListItem::Comparator videoComparator(&videoItem);
604 
605 	for (int32 i = 0; i < fListView->CountItems(); i++) {
606 		MediaListItem* item = static_cast<MediaListItem*>(fListView->ItemAt(i));
607 		item->Accept(audioComparator);
608 		if (audioComparator.result == 0)
609 			return static_cast<NodeListItem*>(item);
610 
611 		item->Accept(videoComparator);
612 		if (videoComparator.result == 0)
613 			return static_cast<NodeListItem*>(item);
614 	}
615 	return NULL;
616 }
617 
618 
619 void
620 MediaWindow::_UpdateListViewMinWidth()
621 {
622 	float width = 0;
623 	for (int32 i = 0; i < fListView->CountItems(); i++) {
624 		BListItem* item = fListView->ItemAt(i);
625 		width = max_c(width, item->Width());
626 	}
627 	fListView->SetExplicitMinSize(BSize(width, B_SIZE_UNSET));
628 	fListView->InvalidateLayout();
629 }
630 
631 
632 status_t
633 MediaWindow::_RestartMediaServices(void* data)
634 {
635 	MediaWindow* window = (MediaWindow*)data;
636 	window->fAlert = new MediaAlert(BRect(0, 0, 300, 60),
637 		"restart_alert", B_TRANSLATE(
638 		"Restarting media services\nShutting down media server\n"));
639 
640 	window->fAlert->Show();
641 
642 	shutdown_media_server(B_INFINITE_TIMEOUT, MediaWindow::_UpdateProgress,
643 		window->fAlert);
644 
645 	{
646 		BAutolock locker(window->fAlert);
647 		if (locker.IsLocked())
648 			window->fAlert->TextView()->SetText(
649 				B_TRANSLATE("Starting media server" B_UTF8_ELLIPSIS));
650 	}
651 	launch_media_server();
652 
653 	return window->PostMessage(ML_INIT_MEDIA);
654 }
655 
656 
657 bool
658 MediaWindow::_UpdateProgress(int stage, const char* message, void* cookie)
659 {
660 	MediaAlert* alert = static_cast<MediaAlert*>(cookie);
661 	PRINT(("stage : %i\n", stage));
662 	const char* string = "Unknown stage";
663 	switch (stage) {
664 		case 10:
665 			string = B_TRANSLATE("Stopping media server" B_UTF8_ELLIPSIS);
666 			break;
667 		case 20:
668 			string = B_TRANSLATE("Telling media_addon_server to quit.");
669 			break;
670 		case 40:
671 			string = B_TRANSLATE("Waiting for media_server to quit.");
672 			break;
673 		case 70:
674 			string = B_TRANSLATE("Cleaning up.");
675 			break;
676 		case 100:
677 			string = B_TRANSLATE("Done shutting down.");
678 			break;
679 	}
680 
681 	BAutolock locker(alert);
682 	if (locker.IsLocked())
683 		alert->TextView()->SetText(string);
684 	return true;
685 }
686 
687 
688 void
689 MediaWindow::_ClearParamView()
690 {
691 	BLayoutItem* item = fContentLayout->VisibleItem();
692 	if (!item)
693 		return;
694 
695 	BView* view = item->View();
696 	if (view != fVideoView && view != fAudioView) {
697 		fContentLayout->RemoveItem(item);
698 		delete item;
699 		delete view;
700 		delete fParamWeb;
701 		fParamWeb = NULL;
702 	}
703 }
704 
705 
706 void
707 MediaWindow::_MakeParamView()
708 {
709 	if (!fCurrentNode.IsSet())
710 		return;
711 
712 	fParamWeb = NULL;
713 	BMediaRoster* roster = BMediaRoster::Roster();
714 	if (roster->GetParameterWebFor(fCurrentNode, &fParamWeb) == B_OK) {
715 		BRect hint(fContentLayout->Frame());
716 		BView* paramView = BMediaTheme::ViewFor(fParamWeb, &hint);
717 		if (paramView) {
718 			fContentLayout->AddView(paramView);
719 			fContentLayout->SetVisibleItem(fContentLayout->CountItems() - 1);
720 			return;
721 		}
722 	}
723 
724 	_MakeEmptyParamView();
725 }
726 
727 
728 void
729 MediaWindow::_MakeEmptyParamView()
730 {
731 	fParamWeb = NULL;
732 
733 	BStringView* stringView = new BStringView("noControls",
734 		B_TRANSLATE("This hardware has no controls."));
735 
736 	BSize unlimited(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED);
737 	stringView->SetExplicitMaxSize(unlimited);
738 
739 	BAlignment centered(B_ALIGN_HORIZONTAL_CENTER,
740 		B_ALIGN_VERTICAL_CENTER);
741 	stringView->SetExplicitAlignment(centered);
742 	stringView->SetAlignment(B_ALIGN_CENTER);
743 
744 	fContentLayout->AddView(stringView);
745 	fContentLayout->SetVisibleItem(fContentLayout->CountItems() - 1);
746 
747 	rgb_color panel = stringView->LowColor();
748 	stringView->SetHighColor(tint_color(panel,
749 		B_DISABLED_LABEL_TINT));
750 }
751 
752