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