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