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 <storage/FindDirectory.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_ASYNCHRONOUS_CONTROLS | 117 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 fListView = new MediaFileListView(); 136 fListView->SetExplicitMinSize(BSize(100, B_SIZE_UNSET)); 137 BScrollView* scroller = new BScrollView(NULL, fListView, 0, false, true); 138 139 // file list view box 140 fSourcesBox = new BBox(B_FANCY_BORDER, scroller); 141 fSourcesBox->SetLayout(new BGroupLayout(B_HORIZONTAL, 0)); 142 // We give fSourcesBox a layout to provide insets for the sources list 143 // said insets are adjusted in _UpdateLabels 144 145 fInfoView = new MediaFileInfoView(); 146 fInfoBox = new BBox(B_FANCY_BORDER, fInfoView); 147 fInfoBox->SetExplicitAlignment(BAlignment(B_ALIGN_USE_FULL_WIDTH, 148 B_ALIGN_USE_FULL_HEIGHT)); 149 150 float padding = be_control_look->DefaultItemSpacing(); 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 (new BAlert(B_TRANSLATE("Error"), errorString.String(), 433 B_TRANSLATE("OK")))->Go(); 434 } 435 break; 436 } 437 438 case VIDEO_QUALITY_CHANGED_MESSAGE: 439 { 440 int32 value; 441 msg->FindInt32("be:value", &value); 442 snprintf(buffer, sizeof(buffer), 443 B_TRANSLATE("Video quality: %3d%%"), (int8)value); 444 fVideoQualitySlider->SetLabel(buffer); 445 fVideoQuality = value; 446 break; 447 } 448 449 case AUDIO_QUALITY_CHANGED_MESSAGE: 450 { 451 int32 value; 452 msg->FindInt32("be:value", &value); 453 snprintf(buffer, sizeof(buffer), 454 B_TRANSLATE("Audio quality: %3d%%"), (int8)value); 455 fAudioQualitySlider->SetLabel(buffer); 456 fAudioQuality = value; 457 break; 458 } 459 460 default: 461 BWindow::MessageReceived(msg); 462 } 463 } 464 465 466 bool 467 MediaConverterWindow::QuitRequested() 468 { 469 if (!fConverting) { 470 BMessenger(be_app).SendMessage(B_QUIT_REQUESTED); 471 return true; 472 } else if (!fCancelling) { 473 fCancelling = true; 474 SetStatusMessage(B_TRANSLATE("Cancelling")); 475 BMessenger(be_app).SendMessage(CANCEL_CONVERSION_MESSAGE); 476 } 477 return false; 478 } 479 480 481 // #pragma mark - 482 483 484 void 485 MediaConverterWindow::LanguageChanged() 486 { 487 _DestroyMenu(); 488 _CreateMenu(); 489 _UpdateLabels(); 490 BuildAudioVideoMenus(); 491 Lock(); 492 fInfoView->Invalidate(); 493 Unlock(); 494 } 495 496 497 void 498 MediaConverterWindow::BuildAudioVideoMenus() 499 { 500 BMenu* menu = fAudioMenu->Menu(); 501 BMenuItem* item; 502 // clear out old audio codec menu items 503 while ((item = menu->RemoveItem(0L)) != NULL) 504 delete item; 505 506 bool separator = true; 507 508 // get selected file format 509 FileFormatMenuItem* ffmi 510 = (FileFormatMenuItem*)fFormatMenu->Menu()->FindMarked(); 511 media_file_format* mf_format = &(ffmi->fFileFormat); 512 513 media_format format, outfmt; 514 memset(&format, 0, sizeof(format)); 515 media_codec_info codec_info; 516 int32 cookie = 0; 517 CodecMenuItem* cmi; 518 519 // add available audio encoders to menu 520 format.type = B_MEDIA_RAW_AUDIO; 521 format.u.raw_audio = media_raw_audio_format::wildcard; 522 while (get_next_encoder(&cookie, mf_format, &format, &outfmt, &codec_info) 523 == B_OK) { 524 if (separator) { 525 menu->AddItem(new BMenuItem( 526 B_TRANSLATE_CONTEXT("No audio", "Audio codecs list"), 527 new BMessage(AUDIO_CODEC_SELECT_MESSAGE))); 528 menu->AddSeparatorItem(); 529 separator = false; 530 } 531 532 cmi = new CodecMenuItem(&codec_info, AUDIO_CODEC_SELECT_MESSAGE); 533 menu->AddItem(cmi); 534 // reset media format struct 535 /* 536 format.type = B_MEDIA_RAW_AUDIO; 537 format.u.raw_audio = media_raw_audio_format::wildcard; 538 */ 539 } 540 541 // mark first audio encoder 542 item = menu->ItemAt(0); 543 if (item != NULL) { 544 fAudioMenu->SetEnabled(fEnabled); 545 fAudioQualitySlider->SetEnabled(fEnabled); 546 item->SetMarked(true); 547 ((BInvoker *)item)->Invoke(); 548 } else { 549 item = new BMenuItem( 550 B_TRANSLATE_CONTEXT("None available", "Audio codecs"), 551 NULL); 552 menu->AddItem(item); 553 item->SetMarked(true); 554 fAudioMenu->SetEnabled(false); 555 fAudioQualitySlider->SetEnabled(false); 556 } 557 558 // clear out old video codec menu items 559 menu = fVideoMenu->Menu(); 560 while ((item = menu->RemoveItem(0L)) != NULL) 561 delete item; 562 563 separator = true; 564 565 // construct a generic video format. Some of these parameters 566 // seem silly, but are needed for R4.5.x, which is more picky 567 // than subsequent BeOS releases will be. 568 memset(&format, 0, sizeof(format)); 569 format.type = B_MEDIA_RAW_VIDEO; 570 format.u.raw_video.last_active = (uint32)(240 - 1); 571 format.u.raw_video.orientation = B_VIDEO_TOP_LEFT_RIGHT; 572 format.u.raw_video.display.format = B_RGB32; 573 format.u.raw_video.display.line_width = (int32)320; 574 format.u.raw_video.display.line_count = (int32)240; 575 format.u.raw_video.display.bytes_per_row = 4 * 320; 576 577 // add available video encoders to menu 578 cookie = 0; 579 while (get_next_encoder(&cookie, mf_format, &format, &outfmt, &codec_info) == B_OK) { 580 if (separator) { 581 menu->AddItem(new BMenuItem( 582 B_TRANSLATE_CONTEXT("No video", "Video codecs list"), 583 new BMessage(VIDEO_CODEC_SELECT_MESSAGE))); 584 menu->AddSeparatorItem(); 585 separator = false; 586 } 587 588 cmi = new CodecMenuItem(&codec_info, VIDEO_CODEC_SELECT_MESSAGE); 589 menu->AddItem(cmi); 590 } 591 592 // mark first video encoder 593 item = menu->ItemAt(0); 594 if (item != NULL) { 595 fVideoMenu->SetEnabled(fEnabled); 596 fVideoQualitySlider->SetEnabled(fEnabled); 597 item->SetMarked(true); 598 ((BInvoker *)item)->Invoke(); 599 } else { 600 item = new BMenuItem( 601 B_TRANSLATE_CONTEXT("None available", "Video codecs"), 602 NULL); 603 menu->AddItem(item); 604 item->SetMarked(true); 605 fVideoMenu->SetEnabled(false); 606 fVideoQualitySlider->SetEnabled(false); 607 } 608 } 609 610 void 611 MediaConverterWindow::GetSelectedFormatInfo(media_file_format** format, 612 media_codec_info** audio, media_codec_info** video) 613 { 614 *audio = NULL; 615 *video = NULL; 616 *format = NULL; 617 618 FileFormatMenuItem *formatItem = 619 dynamic_cast<FileFormatMenuItem *>(fFormatMenu->Menu()->FindMarked()); 620 if (formatItem != NULL) { 621 *format = &(formatItem->fFileFormat); 622 } 623 624 *audio = *video = NULL; 625 CodecMenuItem *codecItem = 626 dynamic_cast<CodecMenuItem *>(fAudioMenu->Menu()->FindMarked()); 627 if (codecItem != NULL) { 628 *audio = &(codecItem->fCodecInfo); 629 } 630 631 codecItem = dynamic_cast<CodecMenuItem *>(fVideoMenu->Menu()->FindMarked()); 632 if (codecItem != NULL) { 633 *video = &(codecItem->fCodecInfo); 634 } 635 } 636 637 638 void 639 MediaConverterWindow::BuildFormatMenu() 640 { 641 BMenu *menu = fFormatMenu->Menu(); 642 BMenuItem *item; 643 // clear out old format menu items 644 while ((item = menu->RemoveItem((int32)0)) != NULL) { 645 delete item; 646 } 647 648 // add menu items for each file format 649 media_file_format mfi; 650 int32 cookie = 0; 651 FileFormatMenuItem *ff_item; 652 while (get_next_file_format(&cookie, &mfi) == B_OK) { 653 ff_item = new FileFormatMenuItem(&mfi); 654 menu->AddItem(ff_item); 655 } 656 657 // mark first item 658 item = menu->ItemAt(0); 659 if (item != NULL) { 660 item->SetMarked(true); 661 ((BInvoker *)item)->Invoke(); 662 } 663 } 664 665 666 void 667 MediaConverterWindow::SetFileMessage(const char *message) 668 { 669 fFileStatus->SetText(message); 670 } 671 672 673 void 674 MediaConverterWindow::SetStatusMessage(const char *message) 675 { 676 fStatus->SetText(message); 677 } 678 679 680 // #pragma mark - 681 682 683 bool 684 MediaConverterWindow::AddSourceFile(BMediaFile* file, const entry_ref& ref) 685 { 686 if (!fListView->AddMediaItem(file, ref)) 687 return false; 688 689 if (!fOutputDirSpecified) { 690 BEntry entry(&ref); 691 entry.GetParent(&entry); 692 _SetOutputFolder(entry); 693 } 694 695 return true; 696 } 697 698 699 void 700 MediaConverterWindow::RemoveSourceFile(int32 index) 701 { 702 delete fListView->RemoveItem(index); 703 fStartDurationTC->SetText("0"); 704 fEndDurationTC->SetText("0"); 705 } 706 707 708 int32 709 MediaConverterWindow::CountSourceFiles() 710 { 711 return fListView->CountItems(); 712 } 713 714 715 status_t 716 MediaConverterWindow::GetSourceFileAt(int32 index, BMediaFile** _file, 717 entry_ref* ref) 718 { 719 MediaFileListItem* item = dynamic_cast<MediaFileListItem*>( 720 fListView->ItemAt(index)); 721 if (item != NULL) { 722 *_file = item->fMediaFile; 723 *ref = item->fRef; 724 return B_OK; 725 } else { 726 return B_ERROR; 727 } 728 } 729 730 731 void 732 MediaConverterWindow::SourceFileSelectionChanged() 733 { 734 int32 selected = fListView->CurrentSelection(); 735 BMediaFile* file = NULL; 736 entry_ref ref; 737 bool enabled = GetSourceFileAt(selected, &file, &ref) == B_OK; 738 739 fPreviewButton->SetEnabled(enabled); 740 fVideoQualitySlider->SetEnabled(enabled); 741 fAudioQualitySlider->SetEnabled(enabled); 742 fStartDurationTC->SetEnabled(enabled); 743 fEndDurationTC->SetEnabled(enabled); 744 745 BString duration; 746 if (enabled) { 747 fInfoView->Update(file, &ref); 748 // HACK: get the fInfoView to update the duration "synchronously" 749 UpdateIfNeeded(); 750 duration << fInfoView->Duration() / 1000; 751 } else 752 duration = "0"; 753 754 // update duration text controls 755 fStartDurationTC->SetText("0"); 756 fEndDurationTC->SetText(duration.String()); 757 } 758 759 760 // #pragma mark - 761 762 763 void 764 MediaConverterWindow::SetEnabled(bool enabled, bool convertEnabled) 765 { 766 fConvertButton->SetEnabled(convertEnabled); 767 if (enabled == fEnabled) 768 return; 769 770 fFormatMenu->SetEnabled(enabled); 771 fAudioMenu->SetEnabled(enabled); 772 fVideoMenu->SetEnabled(enabled); 773 fListView->SetEnabled(enabled); 774 fStartDurationTC->SetEnabled(enabled); 775 fEndDurationTC->SetEnabled(enabled); 776 777 fEnabled = enabled; 778 } 779 780 781 bool 782 MediaConverterWindow::IsEnabled() 783 { 784 return fEnabled; 785 } 786 787 788 const char* 789 MediaConverterWindow::StartDuration() const 790 { 791 return fStartDurationTC->Text(); 792 } 793 794 795 const char* 796 MediaConverterWindow::EndDuration() const 797 { 798 return fEndDurationTC->Text(); 799 } 800 801 802 BDirectory 803 MediaConverterWindow::OutputDirectory() const 804 { 805 return fOutputDir; 806 } 807 808 809 void 810 MediaConverterWindow::SetAudioQualityLabel(const char* label) 811 { 812 fAudioQualitySlider->SetLabel(label); 813 } 814 815 816 void 817 MediaConverterWindow::SetVideoQualityLabel(const char* label) 818 { 819 fVideoQualitySlider->SetLabel(label); 820 } 821 822 823 // #pragma mark - 824 825 826 void 827 MediaConverterWindow::_UpdateLabels() 828 { 829 if (fSourcesBox != NULL) { 830 fSourcesBox->SetLabel(B_TRANSLATE("Source files")); 831 _UpdateBBoxLayoutInsets(fSourcesBox); 832 } 833 834 if (fInfoBox != NULL) 835 fInfoBox->SetLabel(B_TRANSLATE("File details")); 836 837 if (fOutputBox != NULL) { 838 fOutputBox->SetLabel(B_TRANSLATE("Output format")); 839 _UpdateBBoxLayoutInsets(fOutputBox); 840 } 841 842 if (fConvertButton != NULL) 843 fConvertButton->SetLabel(B_TRANSLATE("Convert")); 844 845 if (fPreviewButton != NULL) 846 fPreviewButton->SetLabel(B_TRANSLATE("Preview")); 847 848 if (fDestButton != NULL) 849 fDestButton->SetLabel(B_TRANSLATE("Output folder")); 850 851 if (fVideoQualitySlider != NULL) { 852 char buffer[40]; 853 snprintf(buffer, sizeof(buffer), B_TRANSLATE("Video quality: %3d%%"), 854 (int8)fVideoQuality); 855 fVideoQualitySlider->SetLabel(buffer); 856 fVideoQualitySlider->SetLimitLabels(B_TRANSLATE("Low"), 857 B_TRANSLATE("High")); 858 } 859 860 if (fAudioQualitySlider != NULL) { 861 char buffer[40]; 862 snprintf(buffer, sizeof(buffer), B_TRANSLATE("Audio quality: %3d%%"), 863 (int8)fAudioQuality); 864 fAudioQualitySlider->SetLabel(buffer); 865 fAudioQualitySlider->SetLimitLabels(B_TRANSLATE("Low"), 866 B_TRANSLATE("High")); 867 } 868 869 if (fStartDurationTC != NULL) 870 fStartDurationTC->SetLabel(B_TRANSLATE("Start [ms]: ")); 871 872 if (fEndDurationTC != NULL) 873 fEndDurationTC->SetLabel(B_TRANSLATE("End [ms]: ")); 874 875 if (fFormatMenu != NULL) 876 fFormatMenu->SetLabel(B_TRANSLATE("File format:")); 877 878 if (fAudioMenu != NULL) 879 fAudioMenu->SetLabel(B_TRANSLATE("Audio encoding:")); 880 881 if (fVideoMenu != NULL) 882 fVideoMenu->SetLabel(B_TRANSLATE("Video encoding:")); 883 884 SetFileMessage(B_TRANSLATE("Drop media files onto this window")); 885 } 886 887 888 void 889 MediaConverterWindow::_UpdateBBoxLayoutInsets(BBox* box) 890 { 891 BTwoDimensionalLayout* layout 892 = dynamic_cast<BTwoDimensionalLayout*>(box->GetLayout()); 893 if (layout != NULL) { 894 float padding = be_control_look->DefaultItemSpacing(); 895 layout->SetInsets(padding, box->TopBorderOffset() + padding, padding, 896 padding); 897 } 898 } 899 900 901 void 902 MediaConverterWindow::_DestroyMenu() 903 { 904 BMenu* Menu; 905 906 while ((Menu = fMenuBar->SubmenuAt(0)) != NULL) { 907 fMenuBar->RemoveItem(Menu); 908 delete Menu; 909 } 910 } 911 912 913 void 914 MediaConverterWindow::_CreateMenu() 915 { 916 BMenuItem* item; 917 BMenu* menu; 918 919 menu = new BMenu(B_TRANSLATE_CONTEXT("File", "Menu")); 920 item = new BMenuItem(B_TRANSLATE_CONTEXT( 921 "Open" B_UTF8_ELLIPSIS, "Menu"), 922 new BMessage(OPEN_FILE_MESSAGE), 'O'); 923 menu->AddItem(item); 924 menu->AddSeparatorItem(); 925 item = new BMenuItem(B_TRANSLATE_CONTEXT("Quit", "Menu"), 926 new BMessage(QUIT_MESSAGE), 'Q'); 927 menu->AddItem(item); 928 929 fMenuBar->AddItem(menu); 930 } 931 932 933 void 934 MediaConverterWindow::_SetOutputFolder(BEntry entry) 935 { 936 BPath path; 937 entry.GetPath(&path); 938 fOutputFolder->SetText(path.Path()); 939 fOutputFolder->ResizeToPreferred(); 940 fOutputDir.SetTo(path.Path()); 941 } 942 943 944