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