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