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