xref: /haiku/src/apps/mediaconverter/MediaConverterWindow.cpp (revision 1214ef1b2100f2b3299fc9d8d6142e46f70a4c3f)
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 }
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 	BEntry entry("/boot/beos/apps/MediaPlayer", true);
347 	char buffer[40];
348 	char buffer2[B_PATH_NAME_LENGTH];
349 	char *argv[3];
350 	argv[0] = "-pos";
351 	BMediaFile *inFile(NULL);
352 	int32 srcIndex = 0;
353 	BPath name;
354 	BEntry inentry;
355 	int32 value;
356    	BRect ButtonRect;
357 
358 	switch (msg->what) {
359 		#if B_BEOS_VERSION <= B_BEOS_VERSION_6
360 		case B_LANGUAGE_CHANGED:
361 			LanguageChanged();
362 			break;
363 		#endif
364 
365 		case INIT_FORMAT_MENUS:
366 			BuildFormatMenu();
367 			if (CountSourceFiles() == 0)
368 				SetEnabled(false, false);
369 			break;
370 
371 		case B_SIMPLE_DATA:
372 			if (msg->WasDropped())
373 			{
374 				DetachCurrentMessage();
375 				msg->what = B_REFS_RECEIVED;
376 				BMessenger(be_app).SendMessage(msg);
377 				delete msg;
378 			}
379 			break;
380 
381 		case FORMAT_SELECT_MESSAGE:
382 			BuildAudioVideoMenus();
383 			break;
384 		case AUDIO_CODEC_SELECT_MESSAGE:
385 			break;
386 		case VIDEO_CODEC_SELECT_MESSAGE:
387 			break;
388 
389 		case CONVERT_BUTTON_MESSAGE:
390 			if (!fConverting) {
391 				fConvertButton->SetLabel(CANCEL_LABEL);
392 				fConverting = true;
393 				SetStatusMessage(CONVERT_LABEL);
394 				SetEnabled(false, true);
395 				BMessenger(be_app).SendMessage(START_CONVERSION_MESSAGE);
396 			} else if (!fCancelling) {
397 				fCancelling = true;
398 				SetStatusMessage(CANCELLING_LABEL B_UTF8_ELLIPSIS);
399 				BMessenger(be_app).SendMessage(CANCEL_CONVERSION_MESSAGE);
400 			}
401 			break;
402 
403 		case CONVERSION_DONE_MESSAGE:
404 			SetStatusMessage(fCancelling ? CONV_CANCEL_LABEL : CONV_COMPLETE_LABEL);
405 			fConverting = false;
406 			fCancelling = false;
407 			{
408 				bool enable = CountSourceFiles() > 0;
409 				SetEnabled(enable, enable);
410 			}
411 			fConvertButton->SetLabel(CONVERT_LABEL);
412 
413 
414 			break;
415 
416 		case OUTPUT_FOLDER_MESSAGE:
417 		//	 Execute Save Panel
418 			if (!fSaveFilePanel) {
419 			    BButton *SelectThisDir;
420 
421 				fSaveFilePanel = new BFilePanel(B_OPEN_PANEL, NULL, NULL, B_DIRECTORY_NODE, true, new BMessage(FOLDER_SELECT_MESSAGE), NULL, false, true);
422 				fSaveFilePanel->SetButtonLabel(B_DEFAULT_BUTTON, SELECT_LABEL);
423 				fSaveFilePanel->Window()->SetTitle(SAVE_DIR_LABEL);
424 				fSaveFilePanel->SetTarget(this);
425 
426 				fSaveFilePanel->Window()->Lock();
427 				ButtonRect = fSaveFilePanel->Window()->ChildAt(0)->FindView("cancel button")->Frame();
428 				ButtonRect.right  = ButtonRect.left - 20;
429 				ButtonRect.left = ButtonRect.right - 130;
430 				SelectThisDir = new BButton(ButtonRect, NULL, SELECT_DIR_LABEL,
431 									 new BMessage(SELECT_THIS_DIR_MESSAGE), B_FOLLOW_BOTTOM | B_FOLLOW_RIGHT);
432 				SelectThisDir->SetTarget(this);
433 				fSaveFilePanel->Window()->ChildAt(0)->AddChild(SelectThisDir);
434 				fSaveFilePanel->Window()->Unlock();
435 
436 				BRefFilter *filter;
437 				filter = new DirectoryFilter;
438 				fSaveFilePanel->SetRefFilter(filter);
439 			}
440 			fSaveFilePanel->Show();
441 			break;
442 
443 		case FOLDER_SELECT_MESSAGE:
444 		//	 "SELECT" Button at Save Panel Pushed
445 			fSaveFilePanel->GetNextSelectedRef(&inRef);
446 			inentry.SetTo(&inRef, true);
447 			_SetOutputFolder(inentry);
448 			fOutputDirSpecified = true;
449 			break;
450 
451 		case SELECT_THIS_DIR_MESSAGE:
452 		//	 "THIS DIR" Button at Save Panel Pushed
453 			fSaveFilePanel->GetPanelDirectory(&inRef);
454 			fSaveFilePanel->Hide();
455 			inentry.SetTo(&inRef, true);
456 			_SetOutputFolder(inentry);
457 			fOutputDirSpecified = true;
458 			break;
459 
460 		case OPEN_FILE_MESSAGE:
461 		//	 Execute Open Panel
462 			if (!fOpenFilePanel) {
463 				fOpenFilePanel = new BFilePanel(B_OPEN_PANEL, NULL, NULL, B_FILE_NODE, true, NULL, NULL, false, true);
464 				fOpenFilePanel->SetTarget(this);
465 			}
466 			fOpenFilePanel->Show();
467 			break;
468 
469 		case B_REFS_RECEIVED:
470 		//	Media Files Seleced by Open Panel
471 			DetachCurrentMessage();
472 			msg->what = B_REFS_RECEIVED;
473 			BMessenger(be_app).SendMessage(msg);
474 			// fall through
475 
476 		case B_CANCEL:
477 			break;
478 
479 		case DISP_ABOUT_MESSAGE: {
480 			(new BAlert(ABOUT_TITLE_LABEL B_UTF8_ELLIPSIS,
481 					"MediaConverter\n"
482 					VERSION"\n"
483 					B_UTF8_COPYRIGHT" 1999, Be Incorporated.\n"
484 					B_UTF8_COPYRIGHT" 2000-2004 Jun Suzuki\n"
485 					B_UTF8_COPYRIGHT" 2007 Stephan Aßmus",
486 					OK_LABEL))->Go();
487 			break;
488 		}
489 
490 		case QUIT_MESSAGE:
491 			MediaConverterWindow::QuitRequested();
492 			break;
493 
494 		case PREVIEW_MESSAGE:
495 			entry.GetRef(&ref);
496 			string = "";
497 			string << fStartDurationTC->Text();
498 			string << "000";
499 
500 			strcpy(buffer,string.String());
501 			argv[1] = buffer;
502 			srcIndex = fListView->CurrentSelection();
503 			status = GetSourceFileAt(srcIndex, &inFile, &inRef);
504 			if (status == B_OK) {
505 				inentry.SetTo(&inRef);
506 				inentry.GetPath(&name);
507 
508 				strcpy(buffer, string.String());
509 
510 				strcpy(buffer2, name.Path());
511 				argv[2]= buffer2;
512 			}
513 
514 			status = be_roster->Launch(&ref, 3, argv);
515 
516 			if (status != B_OK) {
517 				string2 << LAUNCH_ERROR << strerror(status);
518 				(new BAlert("", string2.String(), OK_LABEL))->Go();
519 			}
520 			break;
521 
522 		case VIDEO_QUALITY_CHANGED_MESSAGE:
523 			msg->FindInt32("be:value",&value);
524 			sprintf(buffer, VIDEO_QUALITY_LABEL, (int8)value);
525 			fVideoQualitySlider->SetLabel(buffer);
526 			fVideoQuality = value;
527 			break;
528 
529 		case AUDIO_QUALITY_CHANGED_MESSAGE:
530 			msg->FindInt32("be:value",&value);
531 			sprintf(buffer, AUDIO_QUALITY_LABEL, (int8)value);
532 			fAudioQualitySlider->SetLabel(buffer);
533 			fAudioQuality = value;
534 			break;
535 
536 		default:
537 			BWindow::MessageReceived(msg);
538 	}
539 }
540 
541 
542 bool
543 MediaConverterWindow::QuitRequested()
544 {
545 	if (!fConverting) {
546 		BMessenger(be_app).SendMessage(B_QUIT_REQUESTED);
547 		return true;
548 	} else if (!fCancelling) {
549 		fCancelling = true;
550 		SetStatusMessage(CANCELLING_LABEL);
551 		BMessenger(be_app).SendMessage(CANCEL_CONVERSION_MESSAGE);
552 	}
553 	return false;
554 }
555 
556 
557 // #pragma mark -
558 
559 
560 void
561 MediaConverterWindow::LanguageChanged()
562 {
563 	_DestroyMenu();
564 	_CreateMenu();
565 	_UpdateLabels();
566 	BuildAudioVideoMenus();
567 	Lock();
568 	fInfoView->Invalidate();
569 	Unlock();
570 }
571 
572 
573 void
574 MediaConverterWindow::BuildAudioVideoMenus()
575 {
576 	BMenu *menu = fAudioMenu->Menu();
577 	BMenuItem *item;
578 	// clear out old audio codec menu items
579 	while ((item = menu->RemoveItem((int32)0)) != NULL) {
580 		delete item;
581 	}
582 
583 	bool separator = true;
584 
585 	// get selected file format
586 	FileFormatMenuItem *ffmi = (FileFormatMenuItem*)fFormatMenu->Menu()->FindMarked();
587 	media_file_format *mf_format = &(ffmi->fFileFormat);
588 
589 	media_format format, outfmt;
590 	memset(&format, 0, sizeof(format));
591 	media_codec_info codec_info;
592 	int32 cookie = 0;
593 	CodecMenuItem* cmi;
594 
595 	// add available audio encoders to menu
596 	format.type = B_MEDIA_RAW_AUDIO;
597 	format.u.raw_audio = media_raw_audio_format::wildcard;
598 	while (get_next_encoder(&cookie, mf_format, &format, &outfmt, &codec_info) == B_OK) {
599 		if (separator) {
600 			menu->AddItem(new BMenuItem("No Audio",
601 				new BMessage(AUDIO_CODEC_SELECT_MESSAGE)));
602 			menu->AddSeparatorItem();
603 			separator = false;
604 		}
605 
606 		cmi = new CodecMenuItem(&codec_info, AUDIO_CODEC_SELECT_MESSAGE);
607 		menu->AddItem(cmi);
608 		// reset media format struct
609 /*
610 		format.type = B_MEDIA_RAW_AUDIO;
611 		format.u.raw_audio = media_raw_audio_format::wildcard;
612 */
613 	}
614 
615 	// mark first audio encoder
616 	item = menu->ItemAt(0);
617 	if (item != NULL) {
618 		fAudioMenu->SetEnabled(fEnabled);
619 		fAudioQualitySlider->SetEnabled(fEnabled);
620 		item->SetMarked(true);
621 		((BInvoker *)item)->Invoke();
622 	} else {
623 		item = new BMenuItem(NONE_LABEL, NULL);
624 		menu->AddItem(item);
625 		item->SetMarked(true);
626 		fAudioMenu->SetEnabled(false);
627 		fAudioQualitySlider->SetEnabled(false);
628 	}
629 
630 	// clear out old video codec menu items
631 	menu = fVideoMenu->Menu();
632 	while ((item = menu->RemoveItem((int32)0)) != NULL) {
633 		delete item;
634 	}
635 
636 	separator = true;
637 
638 	// construct a generic video format.  Some of these parameters
639 	// seem silly, but are needed for R4.5.x, which is more picky
640 	// than subsequent BeOS releases will be.
641 	memset(&format, 0, sizeof(format));
642 	format.type = B_MEDIA_RAW_VIDEO;
643 	format.u.raw_video.last_active = (uint32)(240 - 1);
644 	format.u.raw_video.orientation = B_VIDEO_TOP_LEFT_RIGHT;
645 	format.u.raw_video.display.format = B_RGB32;
646 	format.u.raw_video.display.line_width = (int32)320;
647 	format.u.raw_video.display.line_count = (int32)240;
648 	format.u.raw_video.display.bytes_per_row = 4 * 320;
649 
650 	// add available video encoders to menu
651 	cookie = 0;
652 	while (get_next_encoder(&cookie, mf_format, &format, &outfmt, &codec_info) == B_OK) {
653 		if (separator) {
654 			menu->AddItem(new BMenuItem("No Video",
655 				new BMessage(VIDEO_CODEC_SELECT_MESSAGE)));
656 			menu->AddSeparatorItem();
657 			separator = false;
658 		}
659 
660 		cmi = new CodecMenuItem(&codec_info, VIDEO_CODEC_SELECT_MESSAGE);
661 		menu->AddItem(cmi);
662 	}
663 
664 	// mark first video encoder
665 	item = menu->ItemAt(0);
666 	if (item != NULL) {
667 		fVideoMenu->SetEnabled(fEnabled);
668 		fVideoQualitySlider->SetEnabled(fEnabled);
669 		item->SetMarked(true);
670 		((BInvoker *)item)->Invoke();
671 	} else {
672 		item = new BMenuItem(NONE_LABEL, NULL);
673 		menu->AddItem(item);
674 		item->SetMarked(true);
675 		fVideoMenu->SetEnabled(false);
676 		fVideoQualitySlider->SetEnabled(false);
677 	}
678 }
679 
680 void
681 MediaConverterWindow::GetSelectedFormatInfo(media_file_format** format,
682 	media_codec_info** audio, media_codec_info** video)
683 {
684 	*audio = NULL;
685 	*video = NULL;
686 	*format = NULL;
687 
688 	FileFormatMenuItem *formatItem =
689 		dynamic_cast<FileFormatMenuItem *>(fFormatMenu->Menu()->FindMarked());
690 	if (formatItem != NULL) {
691 		*format = &(formatItem->fFileFormat);
692 	}
693 
694 	*audio = *video = NULL;
695 	CodecMenuItem *codecItem =
696 		dynamic_cast<CodecMenuItem *>(fAudioMenu->Menu()->FindMarked());
697 	if (codecItem != NULL) {
698 		*audio =  &(codecItem->fCodecInfo);
699 	}
700 
701 	codecItem = dynamic_cast<CodecMenuItem *>(fVideoMenu->Menu()->FindMarked());
702 	if (codecItem != NULL) {
703 		*video =  &(codecItem->fCodecInfo);
704 	}
705 }
706 
707 
708 void
709 MediaConverterWindow::BuildFormatMenu()
710 {
711 	BMenu *menu = fFormatMenu->Menu();
712 	BMenuItem *item;
713 	// clear out old format menu items
714 	while ((item = menu->RemoveItem((int32)0)) != NULL) {
715 		delete item;
716 	}
717 
718 	// add menu items for each file format
719 	media_file_format mfi;
720 	int32 cookie = 0;
721 	FileFormatMenuItem *ff_item;
722 	while (get_next_file_format(&cookie, &mfi) == B_OK) {
723 		ff_item = new FileFormatMenuItem(&mfi);
724 		menu->AddItem(ff_item);
725 	}
726 
727 	// mark first item
728 	item = menu->ItemAt(0);
729 	if (item != NULL) {
730 		item->SetMarked(true);
731 		((BInvoker *)item)->Invoke();
732 	}
733 }
734 
735 void
736 MediaConverterWindow::SetFileMessage(const char *message)
737 {
738 	fStatusView->SetStatus(message);
739 }
740 
741 void
742 MediaConverterWindow::SetStatusMessage(const char *message)
743 {
744 	fStatusView2->SetStatus(message);
745 }
746 
747 
748 // #pragma mark -
749 
750 
751 void
752 MediaConverterWindow::AddSourceFile(BMediaFile* file, const entry_ref& ref)
753 {
754 	fListView->AddItem(file, ref);
755 
756 	if (!fOutputDirSpecified) {
757 		BEntry entry(&ref);
758 		entry.GetParent(&entry);
759 		_SetOutputFolder(entry);
760 	}
761 }
762 
763 
764 void
765 MediaConverterWindow::RemoveSourceFile(int32 index)
766 {
767 	delete fListView->RemoveItem(index);
768 	fStartDurationTC->SetText("0");
769 	fEndDurationTC->SetText("0");
770 }
771 
772 
773 int32
774 MediaConverterWindow::CountSourceFiles()
775 {
776 	return fListView->CountItems();
777 }
778 
779 
780 status_t
781 MediaConverterWindow::GetSourceFileAt(int32 index, BMediaFile** _file,
782 	entry_ref* ref)
783 {
784 	MediaFileListItem* item = dynamic_cast<MediaFileListItem*>(
785 		fListView->ItemAt(index));
786 	if (item != NULL) {
787 		*_file = item->fMediaFile;
788 		*ref = item->fRef;
789 		return B_OK;
790 	} else {
791 		return B_ERROR;
792 	}
793 }
794 
795 
796 void
797 MediaConverterWindow::SourceFileSelectionChanged()
798 {
799 	int32 selected = fListView->CurrentSelection();
800 	BMediaFile* file = NULL;
801 	entry_ref* _ref = NULL;
802 	entry_ref ref;
803 	bool enabled = false;
804 	if (GetSourceFileAt(selected, &file, &ref) == B_OK) {
805 		_ref = &ref;
806 		enabled = true;
807 	}
808 
809 	fPreviewButton->SetEnabled(enabled);
810 	fVideoQualitySlider->SetEnabled(enabled);
811 	fAudioQualitySlider->SetEnabled(enabled);
812 	fStartDurationTC->SetEnabled(enabled);
813 	fEndDurationTC->SetEnabled(enabled);
814 
815 	fInfoView->Update(file, _ref);
816 
817 	// HACK: get the fInfoView to update the duration "synchronously"
818 	UpdateIfNeeded();
819 
820 	// update duration text controls
821 	fStartDurationTC->SetText("0");
822 	BString duration;
823 	duration << fInfoView->Duration() / 1000;
824 	fEndDurationTC->SetText(duration.String());
825 }
826 
827 
828 // #pragma mark -
829 
830 
831 void
832 MediaConverterWindow::SetEnabled(bool enabled, bool convertEnabled)
833 {
834 	fConvertButton->SetEnabled(convertEnabled);
835 	if (enabled == fEnabled)
836 			return;
837 
838 	fFormatMenu->SetEnabled(enabled);
839 	fAudioMenu->SetEnabled(enabled);
840 	fVideoMenu->SetEnabled(enabled);
841 	fListView->SetEnabled(enabled);
842 	fStartDurationTC->SetEnabled(enabled);
843 	fEndDurationTC->SetEnabled(enabled);
844 
845 	fEnabled = enabled;
846 }
847 
848 
849 bool
850 MediaConverterWindow::IsEnabled()
851 {
852 	return fEnabled;
853 }
854 
855 
856 const char*
857 MediaConverterWindow::StartDuration() const
858 {
859 	return fStartDurationTC->Text();
860 }
861 
862 
863 const char*
864 MediaConverterWindow::EndDuration() const
865 {
866 	return fEndDurationTC->Text();
867 }
868 
869 
870 BDirectory
871 MediaConverterWindow::OutputDirectory() const
872 {
873 	return fOutputDir;
874 }
875 
876 
877 void
878 MediaConverterWindow::SetAudioQualityLabel(const char* label)
879 {
880 	fAudioQualitySlider->SetLabel(label);
881 }
882 
883 
884 void
885 MediaConverterWindow::SetVideoQualityLabel(const char* label)
886 {
887 	fVideoQualitySlider->SetLabel(label);
888 }
889 
890 
891 // #pragma mark -
892 
893 
894 void
895 MediaConverterWindow::_UpdateLabels()
896 {
897 	char buffer[255];
898 
899 	if (fBox1 != NULL)
900 		fBox1->SetLabel(SOURCE_BOX_LABEL);
901 	if (fBox2 != NULL)
902 		fBox2->SetLabel(INFO_BOX_LABEL);
903 	if (fBox3 != NULL)
904 		fBox3->SetLabel(OUTPUT_BOX_LABEL);
905 
906 	BRect r(Bounds());
907 	float w = 0;
908 
909 	if (fConvertButton != NULL) {
910 		fConvertButton->SetLabel(CONVERT_LABEL);
911 		fConvertButton->ResizeToPreferred();
912 		BRect buttonFrame(fConvertButton->Frame());
913 		w = buttonFrame.Width();
914 		buttonFrame.OffsetTo(r.right - w - 10, r.bottom - buttonFrame.Height() - 25);
915 		fConvertButton->MoveTo(buttonFrame.LeftTop());
916 	}
917 
918 	if (fPreviewButton != NULL) {
919 		fPreviewButton->SetLabel(PREVIEW_BUTTON_LABEL);
920 		fPreviewButton->ResizeToPreferred();
921 		BRect buttonFrame(fPreviewButton->Frame());
922 		w = buttonFrame.Width();
923 		buttonFrame.OffsetTo(r.right - w - buttonFrame.Width() - 40,
924 						 r.bottom - buttonFrame.Height() - 25);
925 		fPreviewButton->MoveTo(buttonFrame.LeftTop());
926 	}
927 
928 	if (fDestButton != NULL) {
929 		fDestButton->SetLabel(OUTPUT_FOLDER_LABEL);
930 		fDestButton->ResizeToPreferred();
931 	}
932 
933 	if (fOutputFolder != NULL) {
934 		BRect destrect;
935 		destrect = fDestButton->Frame();
936 		fOutputFolder->MoveTo(destrect.right + 10, destrect.top + 5);
937 		fOutputFolder->ResizeToPreferred();
938 	}
939 
940 	sprintf(buffer, VIDEO_QUALITY_LABEL, (int8)fVideoQuality);
941 	if (fVideoQualitySlider != NULL) {
942 		fVideoQualitySlider->SetLabel(buffer);
943 	    fVideoQualitySlider->SetLimitLabels(SLIDER_LOW_LABEL,
944 	    	SLIDER_HIGH_LABEL);
945 	}
946 
947 	sprintf(buffer, AUDIO_QUALITY_LABEL, (int8)fAudioQuality);
948 
949 	if (fAudioQualitySlider != NULL) {
950 		fAudioQualitySlider->SetLabel(buffer);
951 	    fAudioQualitySlider->SetLimitLabels(SLIDER_LOW_LABEL,
952 	    	SLIDER_HIGH_LABEL);
953 	}
954 
955 	float maxLabelLen = 0;
956 	if (fStartDurationTC != NULL) {
957 		fStartDurationTC->SetLabel(START_LABEL);
958 		maxLabelLen = fStartDurationTC->StringWidth(START_LABEL);
959 	}
960 	if (fEndDurationTC != NULL) {
961 		fEndDurationTC->SetLabel(END_LABEL);
962 		maxLabelLen = MAX(maxLabelLen, fEndDurationTC->StringWidth(END_LABEL));
963 	}
964 	if (fStartDurationTC != NULL)
965 		fStartDurationTC->SetDivider(maxLabelLen + 5);
966 	if (fEndDurationTC != NULL)
967 		fEndDurationTC->SetDivider(maxLabelLen + 5);
968 
969 	if (fFormatMenu != NULL) {
970 		fFormatMenu->SetLabel(FORMAT_LABEL);
971 		maxLabelLen = MAX(maxLabelLen, fFormatMenu->StringWidth(
972 			fFormatMenu->Label()));
973 	}
974 	if (fAudioMenu != NULL) {
975 		fAudioMenu->SetLabel(AUDIO_LABEL);
976 		maxLabelLen = MAX(maxLabelLen, fAudioMenu->StringWidth(
977 			fAudioMenu->Label()));
978 	}
979 	if (fVideoMenu != NULL) {
980 		fVideoMenu->SetLabel(VIDEO_LABEL);
981 		maxLabelLen = MAX(maxLabelLen, fVideoMenu->StringWidth(
982 			fVideoMenu->Label()));
983 	}
984 	maxLabelLen += 10;
985 
986 	if (fStartDurationTC != NULL)
987 		fStartDurationTC->SetDivider(maxLabelLen);
988 	if (fEndDurationTC != NULL)
989 		fEndDurationTC->SetDivider(maxLabelLen);
990 	if (fFormatMenu != NULL)
991 		fFormatMenu->SetDivider(maxLabelLen + 3);
992 	if (fAudioMenu != NULL)
993 		fAudioMenu->SetDivider(maxLabelLen + 3);
994 	if (fVideoMenu != NULL)
995 		fVideoMenu->SetDivider(maxLabelLen + 3);
996 
997 	SetFileMessage(DROP_MEDIA_FILE_LABEL);
998 }
999 
1000 
1001 void
1002 MediaConverterWindow::_DestroyMenu()
1003 {
1004 	BMenu* Menu;
1005 
1006 	while ((Menu = fMenuBar->SubmenuAt(0)) != NULL) {
1007 		fMenuBar->RemoveItem(Menu);
1008 		delete Menu;
1009 	}
1010 }
1011 
1012 
1013 void
1014 MediaConverterWindow::_CreateMenu()
1015 {
1016     BMenuItem* item;
1017     BMenu* menu;
1018 
1019     menu = new BMenu(FILE_MENU_LABEL);
1020 	item = new BMenuItem(OPEN_MENU_LABEL B_UTF8_ELLIPSIS,
1021 		new BMessage(OPEN_FILE_MESSAGE));
1022 	menu->AddItem(item);
1023 	menu->AddSeparatorItem();
1024 	item = new BMenuItem(ABOUT_MENU_LABEL B_UTF8_ELLIPSIS,
1025 		new BMessage(DISP_ABOUT_MESSAGE));
1026 	menu->AddItem(item);
1027 	menu->AddSeparatorItem();
1028 	item = new BMenuItem(QUIT_MENU_LABEL, new BMessage(QUIT_MESSAGE));
1029 	menu->AddItem(item);
1030 
1031     fMenuBar->AddItem(menu);
1032 }
1033 
1034 
1035 void
1036 MediaConverterWindow::_SetOutputFolder(BEntry entry)
1037 {
1038 	BPath path;
1039 	entry.GetPath(&path);
1040 	fOutputFolder->SetText(path.Path());
1041 	fOutputFolder->ResizeToPreferred();
1042 	fOutputDir.SetTo(path.Path());
1043 }
1044 
1045 
1046