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