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