xref: /haiku/src/apps/mediaconverter/MediaConverterWindow.cpp (revision 560ff4478d5c85455ea3e5ed5e392ef93132d545)
1 // Copyright 1999, Be Incorporated. All Rights Reserved.
2 // Copyright 2000-2004, Jun Suzuki. All Rights Reserved.
3 // Copyright 2007, 2010 Stephan Aßmus. All Rights Reserved.
4 // Copyright 2010, Haiku, Inc. All Rights Reserved.
5 // This file may be used under the terms of the Be Sample Code License.
6 
7 #include "MediaConverterWindow.h"
8 
9 #include <stdio.h>
10 #include <string.h>
11 
12 #include <AboutMenuItem.h>
13 #include <Alert.h>
14 #include <Application.h>
15 #include <Box.h>
16 #include <Button.h>
17 #include <Catalog.h>
18 #include <ControlLook.h>
19 #include <FilePanel.h>
20 #include <LayoutBuilder.h>
21 #include <Locale.h>
22 #include <Menu.h>
23 #include <MenuBar.h>
24 #include <MenuField.h>
25 #include <MenuItem.h>
26 #include <Path.h>
27 #include <PopUpMenu.h>
28 #include <Roster.h>
29 #include <ScrollBar.h>
30 #include <ScrollView.h>
31 #include <Slider.h>
32 #include <StringView.h>
33 #include <TextControl.h>
34 
35 #include "MediaFileInfoView.h"
36 #include "MediaFileListView.h"
37 #include "MessageConstants.h"
38 
39 
40 #undef B_TRANSLATE_CONTEXT
41 #define B_TRANSLATE_CONTEXT "MediaConverter"
42 #define VERSION "1.3.0"
43 
44 
45 // #pragma mark - DirectoryFilter
46 
47 
48 class DirectoryFilter : public BRefFilter {
49 public:
50 	DirectoryFilter() {};
51 	virtual bool Filter(const entry_ref* ref,
52 		BNode* node, struct stat_beos* st, const char* filetype)
53 	{
54 		return node->IsDirectory();
55 	}
56 };
57 
58 
59 // #pragma mark - FileFormatMenuItem
60 
61 
62 class FileFormatMenuItem : public BMenuItem {
63 public:
64 	FileFormatMenuItem(media_file_format* format);
65 	virtual ~FileFormatMenuItem();
66 
67 	media_file_format fFileFormat;
68 };
69 
70 
71 FileFormatMenuItem::FileFormatMenuItem(media_file_format *format)
72 	:
73 	BMenuItem(format->pretty_name, new BMessage(FORMAT_SELECT_MESSAGE))
74 {
75 	memcpy(&fFileFormat, format, sizeof(fFileFormat));
76 }
77 
78 
79 FileFormatMenuItem::~FileFormatMenuItem()
80 {
81 }
82 
83 
84 // #pragma mark - CodecMenuItem
85 
86 
87 class CodecMenuItem : public BMenuItem {
88 	public:
89 				CodecMenuItem(media_codec_info *ci, uint32 msg_type);
90 	virtual		~CodecMenuItem();
91 
92 	media_codec_info fCodecInfo;
93 };
94 
95 
96 CodecMenuItem::CodecMenuItem(media_codec_info *ci, uint32 msg_type)
97 	:
98 	BMenuItem(ci->pretty_name, new BMessage(msg_type))
99 {
100 	memcpy(&fCodecInfo, ci, sizeof(fCodecInfo));
101 }
102 
103 
104 CodecMenuItem::~CodecMenuItem()
105 {
106 }
107 
108 
109 // #pragma mark - MediaConverterWindow
110 
111 
112 MediaConverterWindow::MediaConverterWindow(BRect frame)
113 	:
114 	BWindow(frame, B_TRANSLATE_SYSTEM_NAME("MediaConverter"), B_TITLED_WINDOW_LOOK,
115 		B_NORMAL_WINDOW_FEEL, B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS |
116 		B_AUTO_UPDATE_SIZE_LIMITS),
117 	fVideoQuality(75),
118 	fAudioQuality(75),
119 	fSaveFilePanel(NULL),
120 	fOpenFilePanel(NULL),
121 	fOutputDirSpecified(false),
122 	fEnabled(true),
123 	fConverting(false),
124 	fCancelling(false)
125 {
126 	const char* defaultDirectory = "/boot/home";
127 	fOutputDir.SetTo(defaultDirectory);
128 
129 	fMenuBar = new BMenuBar("menubar");
130 	_CreateMenu();
131 
132 	fListView = new MediaFileListView();
133 	fListView->SetExplicitMinSize(BSize(100, B_SIZE_UNSET));
134 	BScrollView* scroller = new BScrollView(NULL, fListView, 0, false, true);
135 
136 	// file list view box
137 	fSourcesBox = new BBox(B_FANCY_BORDER, scroller);
138 	fSourcesBox->SetLayout(new BGroupLayout(B_HORIZONTAL, 0));
139 	// We give fSourcesBox a layout to provide insets for the sources list
140 	// said insets are adjusted in _UpdateLabels
141 
142 	fInfoView = new MediaFileInfoView();
143 	fInfoBox = new BBox(B_FANCY_BORDER, fInfoView);
144 	fInfoBox->SetExplicitAlignment(BAlignment(B_ALIGN_USE_FULL_WIDTH,
145 			B_ALIGN_USE_FULL_HEIGHT));
146 	fInfoBox->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
147 
148 	float padding = be_control_look->DefaultItemSpacing();
149 
150 	// Output format box
151 	fOutputBox = new BBox(B_FANCY_BORDER, NULL);
152 	BGridLayout* outputGrid = new BGridLayout(padding, padding);
153 	fOutputBox->SetLayout(outputGrid);
154 		// fOutputBox's layout is also adjusted in _UpdateLabels
155 	outputGrid->SetExplicitAlignment(BAlignment(B_ALIGN_USE_FULL_WIDTH,
156 			B_ALIGN_USE_FULL_HEIGHT));
157 	fOutputBox->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED));
158 
159 	fFormatMenu = new BMenuField(NULL, B_TRANSLATE("File format:"),
160 		new BPopUpMenu(""));
161 	fAudioMenu = new BMenuField(NULL, B_TRANSLATE("Audio encoding:"),
162 		new BPopUpMenu(""));
163 	fVideoMenu = new BMenuField(NULL, B_TRANSLATE("Video encoding:"),
164 		new BPopUpMenu(""));
165 
166 	// output folder
167 	fDestButton = new BButton(B_TRANSLATE("Output folder"),
168 		new BMessage(OUTPUT_FOLDER_MESSAGE));
169 	BAlignment labelAlignment(be_control_look->DefaultLabelAlignment());
170 	fOutputFolder = new BStringView(NULL, defaultDirectory);
171 	fOutputFolder->SetExplicitAlignment(labelAlignment);
172 
173 	// start/end duration
174 	fStartDurationTC = new BTextControl(NULL, NULL, NULL);
175 	fStartDurationTC->SetText("0");
176 
177 	fEndDurationTC = new BTextControl(NULL, NULL, NULL);
178 	fEndDurationTC->SetText("0");
179 
180 	// Video Quality
181 	fVideoQualitySlider = new BSlider("VSlider", "" ,
182 		new BMessage(VIDEO_QUALITY_CHANGED_MESSAGE), 1, 100, B_HORIZONTAL);
183 	fVideoQualitySlider->SetValue(fVideoQuality);
184 	fVideoQualitySlider->SetEnabled(false);
185 
186 	// Audio Quality
187 	fAudioQualitySlider = new BSlider("ASlider", "" ,
188 		new BMessage(AUDIO_QUALITY_CHANGED_MESSAGE), 1, 100, B_HORIZONTAL);
189 	fAudioQualitySlider->SetValue(fAudioQuality);
190 	fAudioQualitySlider->SetEnabled(false);
191 
192 	BLayoutBuilder::Grid<>(outputGrid)
193 		.SetInsets(padding, padding, padding, padding)
194 		.AddMenuField(fFormatMenu, 0, 0)
195 		.AddMenuField(fAudioMenu, 0, 1)
196 		.AddMenuField(fVideoMenu, 0, 2)
197 		.Add(fDestButton, 0, 3)
198 		.Add(fOutputFolder, 1, 3)
199 		.AddTextControl(fStartDurationTC, 0, 4)
200 		.AddTextControl(fEndDurationTC, 0, 5)
201 		.Add(fVideoQualitySlider, 0, 6, 2, 1)
202 		.Add(fAudioQualitySlider, 0, 7, 2, 1);
203 
204 	// buttons
205 	fPreviewButton = new BButton(B_TRANSLATE("Preview"),
206 		new BMessage(PREVIEW_MESSAGE));
207 	fPreviewButton->SetEnabled(false);
208 
209 	fConvertButton = new BButton(B_TRANSLATE("Convert"),
210 		new BMessage(CONVERT_BUTTON_MESSAGE));
211 
212 	// Status views
213 	fStatus = new BStringView(NULL, NULL);
214 	fStatus->SetExplicitAlignment(labelAlignment);
215 	fFileStatus = new BStringView(NULL, NULL);
216 	fFileStatus->SetExplicitAlignment(labelAlignment);
217 
218 	SetStatusMessage("");
219 	_UpdateLabels();
220 
221 	BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
222 		.SetInsets(0, 0, 0, 0)
223 		.Add(fMenuBar)
224 		.AddSplit(B_HORIZONTAL, padding / 2)
225 			.SetInsets(padding, padding, padding, padding)
226 			.Add(fSourcesBox, 0.4)
227 			.AddGroup(B_VERTICAL, padding, 0.6)
228 				.Add(fInfoBox)
229 				.Add(fOutputBox)
230 			.End()
231 		.End()
232 		.AddGrid(padding, padding)
233 			.SetInsets(padding, 0, padding, padding)
234 			.Add(fStatus, 0, 0)
235 			.Add(fFileStatus, 0, 1)
236 			.Add(fPreviewButton, 2, 0)
237 			.Add(fConvertButton, 3, 0)
238 		.End()
239 	;
240 }
241 
242 
243 MediaConverterWindow::~MediaConverterWindow()
244 {
245 	delete fSaveFilePanel;
246 	delete fOpenFilePanel;
247 }
248 
249 
250 // #pragma mark -
251 
252 
253 void
254 MediaConverterWindow::MessageReceived(BMessage* msg)
255 {
256 	entry_ref inRef;
257 
258 	char buffer[40];
259 	BEntry inEntry;
260 
261 	switch (msg->what) {
262 		#if B_BEOS_VERSION <= B_BEOS_VERSION_6
263 		case B_LANGUAGE_CHANGED:
264 			LanguageChanged();
265 			break;
266 		#endif
267 
268 		case INIT_FORMAT_MENUS:
269 			BuildFormatMenu();
270 			if (CountSourceFiles() == 0)
271 				SetEnabled(false, false);
272 			break;
273 
274 		case B_SIMPLE_DATA:
275 			if (msg->WasDropped()) {
276 				DetachCurrentMessage();
277 				msg->what = B_REFS_RECEIVED;
278 				BMessenger(be_app).SendMessage(msg);
279 				delete msg;
280 			}
281 			break;
282 
283 		case FORMAT_SELECT_MESSAGE:
284 			BuildAudioVideoMenus();
285 			break;
286 		case AUDIO_CODEC_SELECT_MESSAGE:
287 			break;
288 		case VIDEO_CODEC_SELECT_MESSAGE:
289 			break;
290 
291 		case CONVERT_BUTTON_MESSAGE:
292 			if (!fConverting) {
293 				fConvertButton->SetLabel(B_TRANSLATE("Cancel"));
294 				fConverting = true;
295 				SetStatusMessage(B_TRANSLATE("Convert"));
296 				SetEnabled(false, true);
297 				BMessenger(be_app).SendMessage(START_CONVERSION_MESSAGE);
298 			} else if (!fCancelling) {
299 				fCancelling = true;
300 				SetStatusMessage(B_TRANSLATE("Cancelling" B_UTF8_ELLIPSIS));
301 				BMessenger(be_app).SendMessage(CANCEL_CONVERSION_MESSAGE);
302 			}
303 			break;
304 
305 		case CONVERSION_DONE_MESSAGE:
306 		{
307 			SetStatusMessage(fCancelling ? B_TRANSLATE("Conversion cancelled")
308 				: B_TRANSLATE("Conversion completed"));
309 			fConverting = false;
310 			fCancelling = false;
311 			bool enable = CountSourceFiles() > 0;
312 			SetEnabled(enable, enable);
313 			fConvertButton->SetLabel(B_TRANSLATE("Convert"));
314 			break;
315 		}
316 
317 		case OUTPUT_FOLDER_MESSAGE:
318 			// Execute Save Panel
319 			if (fSaveFilePanel == NULL) {
320 				BButton* selectThisDir;
321 
322 				BMessage message(FOLDER_SELECT_MESSAGE);
323 				fSaveFilePanel = new BFilePanel(B_OPEN_PANEL, NULL, NULL,
324 					B_DIRECTORY_NODE, true, &message, NULL, false, true);
325 				fSaveFilePanel->SetButtonLabel(B_DEFAULT_BUTTON,
326 					B_TRANSLATE("Select"));
327 				fSaveFilePanel->SetTarget(this);
328 
329 				fSaveFilePanel->Window()->Lock();
330 				fSaveFilePanel->Window()->SetTitle(
331 					B_TRANSLATE("MediaConverter+:SaveDirectory"));
332 				BRect buttonRect
333 					= fSaveFilePanel->Window()->ChildAt(0)->FindView(
334 						"cancel button")->Frame();
335 				buttonRect.right  = buttonRect.left - 20;
336 				buttonRect.left = buttonRect.right - 130;
337 				selectThisDir = new BButton(buttonRect, NULL,
338 					B_TRANSLATE("Select this folder"),
339 					new BMessage(SELECT_THIS_DIR_MESSAGE),
340 					B_FOLLOW_BOTTOM | B_FOLLOW_RIGHT);
341 				selectThisDir->SetTarget(this);
342 				fSaveFilePanel->Window()->ChildAt(0)->AddChild(selectThisDir);
343 				fSaveFilePanel->Window()->Unlock();
344 
345 				fSaveFilePanel->SetRefFilter(new DirectoryFilter);
346 			}
347 			fSaveFilePanel->Show();
348 			break;
349 
350 		case FOLDER_SELECT_MESSAGE:
351 			// "SELECT" Button at Save Panel Pushed
352 			fSaveFilePanel->GetNextSelectedRef(&inRef);
353 			inEntry.SetTo(&inRef, true);
354 			_SetOutputFolder(inEntry);
355 			fOutputDirSpecified = true;
356 			break;
357 
358 		case SELECT_THIS_DIR_MESSAGE:
359 			// "THIS DIR" Button at Save Panel Pushed
360 			fSaveFilePanel->GetPanelDirectory(&inRef);
361 			fSaveFilePanel->Hide();
362 			inEntry.SetTo(&inRef, true);
363 			_SetOutputFolder(inEntry);
364 			fOutputDirSpecified = true;
365 			break;
366 
367 		case OPEN_FILE_MESSAGE:
368 			// Execute Open Panel
369 			if (!fOpenFilePanel) {
370 				fOpenFilePanel = new BFilePanel(B_OPEN_PANEL, NULL, NULL,
371 					B_FILE_NODE, true, NULL, NULL, false, true);
372 				fOpenFilePanel->SetTarget(this);
373 			}
374 			fOpenFilePanel->Show();
375 			break;
376 
377 		case B_REFS_RECEIVED:
378 			// Media Files Seleced by Open Panel
379 			DetachCurrentMessage();
380 			msg->what = B_REFS_RECEIVED;
381 			BMessenger(be_app).SendMessage(msg);
382 			// fall through
383 
384 		case B_CANCEL:
385 			break;
386 
387 		case B_ABOUT_REQUESTED:
388 		{
389 			BString title(B_TRANSLATE("About" B_UTF8_ELLIPSIS));
390 			(new BAlert(title,
391 					B_TRANSLATE("MediaConverter\n"
392 					VERSION"\n"
393 					B_UTF8_COPYRIGHT" 1999, Be Incorporated.\n"
394 					B_UTF8_COPYRIGHT" 2000-2004 Jun Suzuki\n"
395 					B_UTF8_COPYRIGHT" 2007 Stephan Aßmus\n"
396 					B_UTF8_COPYRIGHT" 2010 Haiku, Inc."),
397  					B_TRANSLATE("OK")))->Go();
398 			break;
399 		}
400 
401 		case QUIT_MESSAGE:
402 			MediaConverterWindow::QuitRequested();
403 			break;
404 
405 		case PREVIEW_MESSAGE:
406 		{
407 			// Build the command line to launch the preview application.
408 			// TODO: Launch the default app instead of hardcoded MediaPlayer!
409 			int32 srcIndex = fListView->CurrentSelection();
410 			BMediaFile* inFile = NULL;
411 			status_t status = GetSourceFileAt(srcIndex, &inFile, &inRef);
412 
413 			const char* argv[3];
414 			BString startPosString;
415 			BPath path;
416 
417 			if (status == B_OK) {
418 				argv[0] = "-pos";
419 					// NOTE: -pos argument is currently not supported by Haiku
420 					// MediaPlayer.
421 				startPosString << fStartDurationTC->Text();
422 				startPosString << "000";
423 				argv[1] = startPosString.String();
424 
425 				status = inEntry.SetTo(&inRef);
426 			}
427 
428 			if (status == B_OK) {
429 				status = inEntry.GetPath(&path);
430 				if (status == B_OK)
431 					argv[2] = path.Path();
432 			}
433 
434 			if (status == B_OK) {
435 				status = be_roster->Launch(
436 					"application/x-vnd.Haiku-MediaPlayer",
437 					3, (char**)argv, NULL);
438 			}
439 
440 			if (status != B_OK && status != B_ALREADY_RUNNING) {
441 				BString errorString(B_TRANSLATE("Error launching: %strError%"));
442 				errorString.ReplaceFirst("%strError%", strerror(status));
443 				(new BAlert(B_TRANSLATE("Error"), errorString.String(),
444 					B_TRANSLATE("OK")))->Go();
445 			}
446 			break;
447 		}
448 
449 		case VIDEO_QUALITY_CHANGED_MESSAGE:
450 		{
451 			int32 value;
452 			msg->FindInt32("be:value", &value);
453 			snprintf(buffer, sizeof(buffer),
454 				B_TRANSLATE("Video quality: %3d%%"), (int8)value);
455 			fVideoQualitySlider->SetLabel(buffer);
456 			fVideoQuality = value;
457 			break;
458 		}
459 
460 		case AUDIO_QUALITY_CHANGED_MESSAGE:
461 		{
462 			int32 value;
463 			msg->FindInt32("be:value", &value);
464 			snprintf(buffer, sizeof(buffer),
465 				B_TRANSLATE("Audio quality: %3d%%"), (int8)value);
466 			fAudioQualitySlider->SetLabel(buffer);
467 			fAudioQuality = value;
468 			break;
469 		}
470 
471 		default:
472 			BWindow::MessageReceived(msg);
473 	}
474 }
475 
476 
477 bool
478 MediaConverterWindow::QuitRequested()
479 {
480 	if (!fConverting) {
481 		BMessenger(be_app).SendMessage(B_QUIT_REQUESTED);
482 		return true;
483 	} else if (!fCancelling) {
484 		fCancelling = true;
485 		SetStatusMessage(B_TRANSLATE("Cancelling"));
486 		BMessenger(be_app).SendMessage(CANCEL_CONVERSION_MESSAGE);
487 	}
488 	return false;
489 }
490 
491 
492 // #pragma mark -
493 
494 
495 void
496 MediaConverterWindow::LanguageChanged()
497 {
498 	_DestroyMenu();
499 	_CreateMenu();
500 	_UpdateLabels();
501 	BuildAudioVideoMenus();
502 	Lock();
503 	fInfoView->Invalidate();
504 	Unlock();
505 }
506 
507 
508 void
509 MediaConverterWindow::BuildAudioVideoMenus()
510 {
511 	BMenu* menu = fAudioMenu->Menu();
512 	BMenuItem* item;
513 	// clear out old audio codec menu items
514 	while ((item = menu->RemoveItem(0L)) != NULL)
515 		delete item;
516 
517 	bool separator = true;
518 
519 	// get selected file format
520 	FileFormatMenuItem* ffmi
521 		= (FileFormatMenuItem*)fFormatMenu->Menu()->FindMarked();
522 	media_file_format* mf_format = &(ffmi->fFileFormat);
523 
524 	media_format format, outfmt;
525 	memset(&format, 0, sizeof(format));
526 	media_codec_info codec_info;
527 	int32 cookie = 0;
528 	CodecMenuItem* cmi;
529 
530 	// add available audio encoders to menu
531 	format.type = B_MEDIA_RAW_AUDIO;
532 	format.u.raw_audio = media_raw_audio_format::wildcard;
533 	while (get_next_encoder(&cookie, mf_format, &format, &outfmt, &codec_info)
534 		== B_OK) {
535 		if (separator) {
536 			menu->AddItem(new BMenuItem(
537 				B_TRANSLATE_WITH_CONTEXT("No audio", "Audio codecs list"),
538 				new BMessage(AUDIO_CODEC_SELECT_MESSAGE)));
539 			menu->AddSeparatorItem();
540 			separator = false;
541 		}
542 
543 		cmi = new CodecMenuItem(&codec_info, AUDIO_CODEC_SELECT_MESSAGE);
544 		menu->AddItem(cmi);
545 		// reset media format struct
546 /*
547 		format.type = B_MEDIA_RAW_AUDIO;
548 		format.u.raw_audio = media_raw_audio_format::wildcard;
549 */
550 	}
551 
552 	// mark first audio encoder
553 	item = menu->ItemAt(0);
554 	if (item != NULL) {
555 		fAudioMenu->SetEnabled(fEnabled);
556 		fAudioQualitySlider->SetEnabled(fEnabled);
557 		item->SetMarked(true);
558 		((BInvoker *)item)->Invoke();
559 	} else {
560 		item = new BMenuItem(
561 			B_TRANSLATE_WITH_CONTEXT("None available", "Audio codecs"),
562 			NULL);
563 		menu->AddItem(item);
564 		item->SetMarked(true);
565 		fAudioMenu->SetEnabled(false);
566 		fAudioQualitySlider->SetEnabled(false);
567 	}
568 
569 	// clear out old video codec menu items
570 	menu = fVideoMenu->Menu();
571 	while ((item = menu->RemoveItem(0L)) != NULL)
572 		delete item;
573 
574 	separator = true;
575 
576 	// construct a generic video format.  Some of these parameters
577 	// seem silly, but are needed for R4.5.x, which is more picky
578 	// than subsequent BeOS releases will be.
579 	memset(&format, 0, sizeof(format));
580 	format.type = B_MEDIA_RAW_VIDEO;
581 	format.u.raw_video.last_active = (uint32)(240 - 1);
582 	format.u.raw_video.orientation = B_VIDEO_TOP_LEFT_RIGHT;
583 	format.u.raw_video.display.format = B_RGB32;
584 	format.u.raw_video.display.line_width = (int32)320;
585 	format.u.raw_video.display.line_count = (int32)240;
586 	format.u.raw_video.display.bytes_per_row = 4 * 320;
587 
588 	// add available video encoders to menu
589 	cookie = 0;
590 	while (get_next_encoder(&cookie, mf_format, &format, &outfmt, &codec_info) == B_OK) {
591 		if (separator) {
592 			menu->AddItem(new BMenuItem(
593 				B_TRANSLATE_WITH_CONTEXT("No video", "Video codecs list"),
594 				new BMessage(VIDEO_CODEC_SELECT_MESSAGE)));
595 			menu->AddSeparatorItem();
596 			separator = false;
597 		}
598 
599 		cmi = new CodecMenuItem(&codec_info, VIDEO_CODEC_SELECT_MESSAGE);
600 		menu->AddItem(cmi);
601 	}
602 
603 	// mark first video encoder
604 	item = menu->ItemAt(0);
605 	if (item != NULL) {
606 		fVideoMenu->SetEnabled(fEnabled);
607 		fVideoQualitySlider->SetEnabled(fEnabled);
608 		item->SetMarked(true);
609 		((BInvoker *)item)->Invoke();
610 	} else {
611 		item = new BMenuItem(
612 			B_TRANSLATE_WITH_CONTEXT("None available", "Video codecs"),
613 			NULL);
614 		menu->AddItem(item);
615 		item->SetMarked(true);
616 		fVideoMenu->SetEnabled(false);
617 		fVideoQualitySlider->SetEnabled(false);
618 	}
619 }
620 
621 void
622 MediaConverterWindow::GetSelectedFormatInfo(media_file_format** format,
623 	media_codec_info** audio, media_codec_info** video)
624 {
625 	*audio = NULL;
626 	*video = NULL;
627 	*format = NULL;
628 
629 	FileFormatMenuItem *formatItem =
630 		dynamic_cast<FileFormatMenuItem *>(fFormatMenu->Menu()->FindMarked());
631 	if (formatItem != NULL) {
632 		*format = &(formatItem->fFileFormat);
633 	}
634 
635 	*audio = *video = NULL;
636 	CodecMenuItem *codecItem =
637 		dynamic_cast<CodecMenuItem *>(fAudioMenu->Menu()->FindMarked());
638 	if (codecItem != NULL) {
639 		*audio =  &(codecItem->fCodecInfo);
640 	}
641 
642 	codecItem = dynamic_cast<CodecMenuItem *>(fVideoMenu->Menu()->FindMarked());
643 	if (codecItem != NULL) {
644 		*video =  &(codecItem->fCodecInfo);
645 	}
646 }
647 
648 
649 void
650 MediaConverterWindow::BuildFormatMenu()
651 {
652 	BMenu *menu = fFormatMenu->Menu();
653 	BMenuItem *item;
654 	// clear out old format menu items
655 	while ((item = menu->RemoveItem((int32)0)) != NULL) {
656 		delete item;
657 	}
658 
659 	// add menu items for each file format
660 	media_file_format mfi;
661 	int32 cookie = 0;
662 	FileFormatMenuItem *ff_item;
663 	while (get_next_file_format(&cookie, &mfi) == B_OK) {
664 		ff_item = new FileFormatMenuItem(&mfi);
665 		menu->AddItem(ff_item);
666 	}
667 
668 	// mark first item
669 	item = menu->ItemAt(0);
670 	if (item != NULL) {
671 		item->SetMarked(true);
672 		((BInvoker *)item)->Invoke();
673 	}
674 }
675 
676 
677 void
678 MediaConverterWindow::SetFileMessage(const char *message)
679 {
680 	fFileStatus->SetText(message);
681 }
682 
683 
684 void
685 MediaConverterWindow::SetStatusMessage(const char *message)
686 {
687 	fStatus->SetText(message);
688 }
689 
690 
691 // #pragma mark -
692 
693 
694 bool
695 MediaConverterWindow::AddSourceFile(BMediaFile* file, const entry_ref& ref)
696 {
697 	if (!fListView->AddMediaItem(file, ref))
698 		return false;
699 
700 	if (!fOutputDirSpecified) {
701 		BEntry entry(&ref);
702 		entry.GetParent(&entry);
703 		_SetOutputFolder(entry);
704 	}
705 
706 	return true;
707 }
708 
709 
710 void
711 MediaConverterWindow::RemoveSourceFile(int32 index)
712 {
713 	delete fListView->RemoveItem(index);
714 	fStartDurationTC->SetText("0");
715 	fEndDurationTC->SetText("0");
716 }
717 
718 
719 int32
720 MediaConverterWindow::CountSourceFiles()
721 {
722 	return fListView->CountItems();
723 }
724 
725 
726 status_t
727 MediaConverterWindow::GetSourceFileAt(int32 index, BMediaFile** _file,
728 	entry_ref* ref)
729 {
730 	MediaFileListItem* item = dynamic_cast<MediaFileListItem*>(
731 		fListView->ItemAt(index));
732 	if (item != NULL) {
733 		*_file = item->fMediaFile;
734 		*ref = item->fRef;
735 		return B_OK;
736 	} else {
737 		return B_ERROR;
738 	}
739 }
740 
741 
742 void
743 MediaConverterWindow::SourceFileSelectionChanged()
744 {
745 	int32 selected = fListView->CurrentSelection();
746 	BMediaFile* file = NULL;
747 	entry_ref ref;
748 	bool enabled = GetSourceFileAt(selected, &file, &ref) == B_OK;
749 
750 	fPreviewButton->SetEnabled(enabled);
751 	fVideoQualitySlider->SetEnabled(enabled);
752 	fAudioQualitySlider->SetEnabled(enabled);
753 	fStartDurationTC->SetEnabled(enabled);
754 	fEndDurationTC->SetEnabled(enabled);
755 
756 	BString duration;
757 	if (enabled) {
758 		fInfoView->Update(file, &ref);
759 		// HACK: get the fInfoView to update the duration "synchronously"
760 		UpdateIfNeeded();
761 		duration << fInfoView->Duration() / 1000;
762 	} else
763 		duration = "0";
764 
765 	// update duration text controls
766 	fStartDurationTC->SetText("0");
767 	fEndDurationTC->SetText(duration.String());
768 }
769 
770 
771 // #pragma mark -
772 
773 
774 void
775 MediaConverterWindow::SetEnabled(bool enabled, bool convertEnabled)
776 {
777 	fConvertButton->SetEnabled(convertEnabled);
778 	if (enabled == fEnabled)
779 			return;
780 
781 	fFormatMenu->SetEnabled(enabled);
782 	fAudioMenu->SetEnabled(enabled);
783 	fVideoMenu->SetEnabled(enabled);
784 	fListView->SetEnabled(enabled);
785 	fStartDurationTC->SetEnabled(enabled);
786 	fEndDurationTC->SetEnabled(enabled);
787 
788 	fEnabled = enabled;
789 }
790 
791 
792 bool
793 MediaConverterWindow::IsEnabled()
794 {
795 	return fEnabled;
796 }
797 
798 
799 const char*
800 MediaConverterWindow::StartDuration() const
801 {
802 	return fStartDurationTC->Text();
803 }
804 
805 
806 const char*
807 MediaConverterWindow::EndDuration() const
808 {
809 	return fEndDurationTC->Text();
810 }
811 
812 
813 BDirectory
814 MediaConverterWindow::OutputDirectory() const
815 {
816 	return fOutputDir;
817 }
818 
819 
820 void
821 MediaConverterWindow::SetAudioQualityLabel(const char* label)
822 {
823 	fAudioQualitySlider->SetLabel(label);
824 }
825 
826 
827 void
828 MediaConverterWindow::SetVideoQualityLabel(const char* label)
829 {
830 	fVideoQualitySlider->SetLabel(label);
831 }
832 
833 
834 // #pragma mark -
835 
836 
837 void
838 MediaConverterWindow::_UpdateLabels()
839 {
840 	if (fSourcesBox != NULL) {
841 		fSourcesBox->SetLabel(B_TRANSLATE("Source files"));
842 		_UpdateBBoxLayoutInsets(fSourcesBox);
843 	}
844 
845 	if (fInfoBox != NULL)
846 		fInfoBox->SetLabel(B_TRANSLATE("File details"));
847 
848 	if (fOutputBox != NULL) {
849 		fOutputBox->SetLabel(B_TRANSLATE("Output format"));
850 		_UpdateBBoxLayoutInsets(fOutputBox);
851 	}
852 
853 	if (fConvertButton != NULL)
854 		fConvertButton->SetLabel(B_TRANSLATE("Convert"));
855 
856 	if (fPreviewButton != NULL)
857 		fPreviewButton->SetLabel(B_TRANSLATE("Preview"));
858 
859 	if (fDestButton != NULL)
860 		fDestButton->SetLabel(B_TRANSLATE("Output folder"));
861 
862 	if (fVideoQualitySlider != NULL) {
863 		char buffer[40];
864 		snprintf(buffer, sizeof(buffer), B_TRANSLATE("Video quality: %3d%%"),
865 			(int8)fVideoQuality);
866 		fVideoQualitySlider->SetLabel(buffer);
867 		fVideoQualitySlider->SetLimitLabels(B_TRANSLATE("Low"),
868 			B_TRANSLATE("High"));
869 	}
870 
871 	if (fAudioQualitySlider != NULL) {
872 		char buffer[40];
873 		snprintf(buffer, sizeof(buffer), B_TRANSLATE("Audio quality: %3d%%"),
874 			(int8)fAudioQuality);
875 		fAudioQualitySlider->SetLabel(buffer);
876 		fAudioQualitySlider->SetLimitLabels(B_TRANSLATE("Low"),
877 			B_TRANSLATE("High"));
878 	}
879 
880 	if (fStartDurationTC != NULL)
881 		fStartDurationTC->SetLabel(B_TRANSLATE("Start [ms]: "));
882 
883 	if (fEndDurationTC != NULL)
884 		fEndDurationTC->SetLabel(B_TRANSLATE("End   [ms]: "));
885 
886 	if (fFormatMenu != NULL)
887 		fFormatMenu->SetLabel(B_TRANSLATE("File format:"));
888 
889 	if (fAudioMenu != NULL)
890 		fAudioMenu->SetLabel(B_TRANSLATE("Audio encoding:"));
891 
892 	if (fVideoMenu != NULL)
893 		fVideoMenu->SetLabel(B_TRANSLATE("Video encoding:"));
894 
895 	SetFileMessage(B_TRANSLATE("Drop media files onto this window"));
896 }
897 
898 
899 void
900 MediaConverterWindow::_UpdateBBoxLayoutInsets(BBox* box)
901 {
902 	BTwoDimensionalLayout* layout
903 		= dynamic_cast<BTwoDimensionalLayout*>(box->GetLayout());
904 	if (layout != NULL) {
905 		float padding = be_control_look->DefaultItemSpacing();
906 		layout->SetInsets(padding, box->TopBorderOffset() + padding, padding,
907 			padding);
908 	}
909 }
910 
911 
912 void
913 MediaConverterWindow::_DestroyMenu()
914 {
915 	BMenu* Menu;
916 
917 	while ((Menu = fMenuBar->SubmenuAt(0)) != NULL) {
918 		fMenuBar->RemoveItem(Menu);
919 		delete Menu;
920 	}
921 }
922 
923 
924 void
925 MediaConverterWindow::_CreateMenu()
926 {
927 	BMenuItem* item;
928 	BMenu* menu;
929 
930 	menu = new BMenu(B_TRANSLATE_WITH_CONTEXT("File", "Menu"));
931 	item = new BMenuItem(B_TRANSLATE_WITH_CONTEXT(
932 		"Open" B_UTF8_ELLIPSIS, "Menu"),
933 		new BMessage(OPEN_FILE_MESSAGE), 'O');
934 	menu->AddItem(item);
935 	menu->AddSeparatorItem();
936 	item = new BAboutMenuItem(),
937 	menu->AddItem(item);
938 	menu->AddSeparatorItem();
939 	item = new BMenuItem(B_TRANSLATE_WITH_CONTEXT("Quit", "Menu"),
940 		new BMessage(QUIT_MESSAGE), 'Q');
941 	menu->AddItem(item);
942 
943 	fMenuBar->AddItem(menu);
944 }
945 
946 
947 void
948 MediaConverterWindow::_SetOutputFolder(BEntry entry)
949 {
950 	BPath path;
951 	entry.GetPath(&path);
952 	fOutputFolder->SetText(path.Path());
953 	fOutputFolder->ResizeToPreferred();
954 	fOutputDir.SetTo(path.Path());
955 }
956 
957 
958