// Copyright 1999, Be Incorporated. All Rights Reserved. // Copyright 2000-2004, Jun Suzuki. All Rights Reserved. // Copyright 2007, 2010 Stephan Aßmus. All Rights Reserved. // Copyright 2010-2013, Haiku, Inc. All Rights Reserved. // This file may be used under the terms of the Be Sample Code License. #include "MediaConverterWindow.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "MediaFileInfoView.h" #include "MediaFileListView.h" #include "MessageConstants.h" #undef B_TRANSLATION_CONTEXT #define B_TRANSLATION_CONTEXT "MediaConverter" #define VERSION "1.3.0" static const unsigned int kMinSourceWidth = 12; static const unsigned int kQualitySliderWidth = 28; static const unsigned int kDurationWidth = 10; // #pragma mark - DirectoryFilter class DirectoryFilter : public BRefFilter { public: DirectoryFilter() {}; virtual bool Filter(const entry_ref* ref, BNode* node, struct stat_beos* st, const char* filetype) { return node->IsDirectory(); } }; // #pragma mark - FileFormatMenuItem class FileFormatMenuItem : public BMenuItem { public: FileFormatMenuItem(media_file_format* format); virtual ~FileFormatMenuItem(); media_file_format fFileFormat; }; FileFormatMenuItem::FileFormatMenuItem(media_file_format* format) : BMenuItem(format->pretty_name, new BMessage(FORMAT_SELECT_MESSAGE)) { memcpy(&fFileFormat, format, sizeof(fFileFormat)); } FileFormatMenuItem::~FileFormatMenuItem() { } // #pragma mark - CodecMenuItem class CodecMenuItem : public BMenuItem { public: CodecMenuItem(media_codec_info* ci, uint32 message_type); virtual ~CodecMenuItem(); media_codec_info fCodecInfo; }; CodecMenuItem::CodecMenuItem(media_codec_info* ci, uint32 message_type) : BMenuItem(ci->pretty_name, new BMessage(message_type)) { memcpy(&fCodecInfo, ci, sizeof(fCodecInfo)); } CodecMenuItem::~CodecMenuItem() { } // #pragma mark - OutputBox class OutputBox : public BBox { public: OutputBox(border_style border, BView* child); virtual void FrameResized(float width, float height) { MediaConverterWindow* window = dynamic_cast(Window()); if (window != NULL) window->TruncateOutputFolderPath(); BBox::FrameResized(width, height); } }; OutputBox::OutputBox(border_style border, BView* child) : BBox(border, child) { } // #pragma mark - MediaConverterWindow MediaConverterWindow::MediaConverterWindow(BRect frame) : BWindow(frame, B_TRANSLATE_SYSTEM_NAME("MediaConverter"), B_TITLED_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, B_NOT_ZOOMABLE | B_NOT_V_RESIZABLE | B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS), fVideoQuality(75), fAudioQuality(75), fSaveFilePanel(NULL), fOpenFilePanel(NULL), fOutputDirSpecified(false), fEnabled(true), fConverting(false), fCancelling(false) { BPath outputDir; if (find_directory(B_USER_DIRECTORY, &outputDir) != B_OK) outputDir.SetTo("/boot/home"); fOutputDir.SetTo(outputDir.Path()); fMenuBar = new BMenuBar("menubar"); _CreateMenu(); float padding = be_control_look->DefaultItemSpacing(); fListView = new MediaFileListView(); fListView->SetExplicitMinSize(BSize(padding * kMinSourceWidth, B_SIZE_UNSET)); BScrollView* scroller = new BScrollView(NULL, fListView, 0, false, true); // file list view box fSourcesBox = new BBox(B_FANCY_BORDER, scroller); fSourcesBox->SetLayout(new BGroupLayout(B_HORIZONTAL, 0)); // fSourcesBox's layout adjusted in _UpdateLabels // info box fInfoView = new MediaFileInfoView(); fInfoView->SetExplicitAlignment(BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_VERTICAL_UNSET)); fInfoBox = new BBox(B_FANCY_BORDER, fInfoView); // output menu fields fFormatMenu = new BMenuField(NULL, B_TRANSLATE("File format:"), new BPopUpMenu("")); fAudioMenu = new BMenuField(NULL, B_TRANSLATE("Audio encoding:"), new BPopUpMenu("")); fVideoMenu = new BMenuField(NULL, B_TRANSLATE("Video encoding:"), new BPopUpMenu("")); // output folder fDestButton = new BButton(B_TRANSLATE("Output folder"), new BMessage(OUTPUT_FOLDER_MESSAGE)); BAlignment labelAlignment(be_control_look->DefaultLabelAlignment()); fOutputFolder = new BStringView(NULL, outputDir.Path()); fOutputFolder->SetExplicitAlignment(labelAlignment); // start/end duration fStartDurationTC = new BTextControl(NULL, "0", NULL); BLayoutItem* startDuration = fStartDurationTC->CreateTextViewLayoutItem(); startDuration->SetExplicitSize(BSize(padding * kDurationWidth, B_SIZE_UNSET)); startDuration->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, B_ALIGN_VERTICAL_CENTER)); fEndDurationTC = new BTextControl(NULL, "0", NULL); BLayoutItem* endDuration = fEndDurationTC->CreateTextViewLayoutItem(); endDuration->SetExplicitSize(BSize(padding * kDurationWidth, B_SIZE_UNSET)); endDuration->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, B_ALIGN_VERTICAL_CENTER)); // video quality fVideoQualitySlider = new BSlider("VSlider", "" , new BMessage(VIDEO_QUALITY_CHANGED_MESSAGE), 1, 100, B_HORIZONTAL); fVideoQualitySlider->SetModificationMessage( new BMessage(VIDEO_QUALITY_CHANGED_MESSAGE)); fVideoQualitySlider->SetValue(fVideoQuality); fVideoQualitySlider->SetEnabled(false); fVideoQualitySlider->SetExplicitSize(BSize(padding * kQualitySliderWidth, B_SIZE_UNSET)); // audio quality fAudioQualitySlider = new BSlider("ASlider", "" , new BMessage(AUDIO_QUALITY_CHANGED_MESSAGE), 1, 100, B_HORIZONTAL); fAudioQualitySlider->SetModificationMessage( new BMessage(AUDIO_QUALITY_CHANGED_MESSAGE)); fAudioQualitySlider->SetValue(fAudioQuality); fAudioQualitySlider->SetEnabled(false); fAudioQualitySlider->SetExplicitSize(BSize(padding * kQualitySliderWidth, B_SIZE_UNSET)); // output format box BView* outputGrid = BLayoutBuilder::Grid<>() .Add(fFormatMenu->CreateLabelLayoutItem(), 0, 0) .Add(fFormatMenu->CreateMenuBarLayoutItem(), 1, 0) .Add(fAudioMenu->CreateLabelLayoutItem(), 0, 1) .Add(fAudioMenu->CreateMenuBarLayoutItem(), 1, 1) .Add(fVideoMenu->CreateLabelLayoutItem(), 0, 2) .Add(fVideoMenu->CreateMenuBarLayoutItem(), 1, 2) .Add(fDestButton, 0, 3) .Add(fOutputFolder, 1, 3) .Add(fStartDurationTC->CreateLabelLayoutItem(), 0, 4) .Add(startDuration, 1, 4) .Add(fEndDurationTC->CreateLabelLayoutItem(), 0, 5) .Add(endDuration, 1, 5) .Add(fVideoQualitySlider, 0, 6, 2, 1) .Add(fAudioQualitySlider, 0, 7, 2, 1) .View(); outputGrid->SetExplicitAlignment(BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT)); fOutputBox = new OutputBox(B_FANCY_BORDER, outputGrid); fOutputBox->SetLayout(new BGroupLayout(B_HORIZONTAL, 0)); // fOutputBox's layout adjusted in _UpdateLabels // buttons fPreviewButton = new BButton(B_TRANSLATE("Preview"), new BMessage(PREVIEW_MESSAGE)); fPreviewButton->SetEnabled(false); fConvertButton = new BButton(B_TRANSLATE("Convert"), new BMessage(CONVERT_BUTTON_MESSAGE)); // Status views fStatus = new BStringView(NULL, NULL); fStatus->SetExplicitAlignment(labelAlignment); fFileStatus = new BStringView(NULL, NULL); fFileStatus->SetExplicitAlignment(labelAlignment); SetStatusMessage(""); _UpdateLabels(); BLayoutBuilder::Group<>(this, B_VERTICAL, 0) .SetInsets(0, 0, 0, 0) .Add(fMenuBar) .AddSplit(B_HORIZONTAL, B_USE_DEFAULT_SPACING) .SetInsets(B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING, 0) .Add(fSourcesBox) .AddGroup(B_VERTICAL, B_USE_ITEM_SPACING) .Add(fInfoBox) .Add(fOutputBox) .End() .End() .AddGrid(B_USE_ITEM_SPACING) .SetInsets(B_USE_WINDOW_SPACING, B_USE_DEFAULT_SPACING, B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING) .Add(fStatus, 0, 0) .Add(fFileStatus, 0, 1) .Add(BSpaceLayoutItem::CreateGlue(), 1, 0) .Add(fPreviewButton, 2, 0) .Add(fConvertButton, 3, 0) .End(); } MediaConverterWindow::~MediaConverterWindow() { delete fSaveFilePanel; delete fOpenFilePanel; } // #pragma mark - void MediaConverterWindow::MessageReceived(BMessage* message) { entry_ref inRef; BEntry inEntry; BNumberFormat fNumberFormat; BString buffer; switch (message->what) { #if B_BEOS_VERSION <= B_BEOS_VERSION_6 case B_LANGUAGE_CHANGED: LanguageChanged(); break; #endif case INIT_FORMAT_MENUS: BuildFormatMenu(); if (CountSourceFiles() == 0) SetEnabled(false, false); break; case B_SIMPLE_DATA: if (message->WasDropped()) { DetachCurrentMessage(); message->what = B_REFS_RECEIVED; BMessenger(be_app).SendMessage(message); delete message; } break; case FORMAT_SELECT_MESSAGE: BuildAudioVideoMenus(); break; case AUDIO_CODEC_SELECT_MESSAGE: break; case VIDEO_CODEC_SELECT_MESSAGE: break; case CONVERT_BUTTON_MESSAGE: if (!fConverting) { fConvertButton->SetLabel(B_TRANSLATE("Cancel")); fConverting = true; SetStatusMessage(B_TRANSLATE("Convert")); SetEnabled(false, true); BMessenger(be_app).SendMessage(START_CONVERSION_MESSAGE); } else if (!fCancelling) { fCancelling = true; SetStatusMessage(B_TRANSLATE("Cancelling" B_UTF8_ELLIPSIS)); BMessenger(be_app).SendMessage(CANCEL_CONVERSION_MESSAGE); } break; case CONVERSION_DONE_MESSAGE: { SetStatusMessage(fCancelling ? B_TRANSLATE("Conversion cancelled") : B_TRANSLATE("Conversion completed")); fConverting = false; fCancelling = false; bool enable = CountSourceFiles() > 0; SetEnabled(enable, enable); fConvertButton->SetLabel(B_TRANSLATE("Convert")); break; } case OUTPUT_FOLDER_MESSAGE: // Execute Save Panel if (fSaveFilePanel == NULL) { BButton* selectThisDir; BMessage folderSelect(FOLDER_SELECT_MESSAGE); fSaveFilePanel = new BFilePanel(B_OPEN_PANEL, NULL, NULL, B_DIRECTORY_NODE, true, &folderSelect, NULL, false, true); fSaveFilePanel->SetButtonLabel(B_DEFAULT_BUTTON, B_TRANSLATE("Select")); fSaveFilePanel->SetTarget(this); fSaveFilePanel->Window()->Lock(); fSaveFilePanel->Window()->SetTitle( B_TRANSLATE("MediaConverter+:SaveDirectory")); BRect buttonRect = fSaveFilePanel->Window()->ChildAt(0)->FindView( "cancel button")->Frame(); buttonRect.right = buttonRect.left - 20; buttonRect.left = buttonRect.right - 130; selectThisDir = new BButton(buttonRect, NULL, B_TRANSLATE("Select this folder"), new BMessage(SELECT_THIS_DIR_MESSAGE), B_FOLLOW_BOTTOM | B_FOLLOW_RIGHT); selectThisDir->SetTarget(this); fSaveFilePanel->Window()->ChildAt(0)->AddChild(selectThisDir); fSaveFilePanel->Window()->Unlock(); fSaveFilePanel->SetRefFilter(new DirectoryFilter); } fSaveFilePanel->Show(); break; case FOLDER_SELECT_MESSAGE: // "SELECT" Button at Save Panel Pushed fSaveFilePanel->GetNextSelectedRef(&inRef); inEntry.SetTo(&inRef, true); _SetOutputFolder(inEntry); fOutputDirSpecified = true; fSaveFilePanel->Rewind(); break; case SELECT_THIS_DIR_MESSAGE: // "THIS DIR" Button at Save Panel Pushed fSaveFilePanel->GetPanelDirectory(&inRef); fSaveFilePanel->Hide(); inEntry.SetTo(&inRef, true); _SetOutputFolder(inEntry); fOutputDirSpecified = true; break; case OPEN_FILE_MESSAGE: // Execute Open Panel if (!fOpenFilePanel) { fOpenFilePanel = new BFilePanel(B_OPEN_PANEL, NULL, NULL, B_FILE_NODE, true, NULL, NULL, false, true); fOpenFilePanel->SetTarget(this); } fOpenFilePanel->Show(); break; case B_REFS_RECEIVED: // Media Files Seleced by Open Panel DetachCurrentMessage(); message->what = B_REFS_RECEIVED; BMessenger(be_app).SendMessage(message); // fall through case B_CANCEL: break; case QUIT_MESSAGE: MediaConverterWindow::QuitRequested(); break; case PREVIEW_MESSAGE: { // Build the command line to launch the preview application. // TODO: Launch the default app instead of hardcoded MediaPlayer! int32 srcIndex = fListView->CurrentSelection(); BMediaFile* inFile = NULL; status_t status = GetSourceFileAt(srcIndex, &inFile, &inRef); const char* argv[3]; BString startPosString; BPath path; if (status == B_OK) { argv[0] = "-pos"; // NOTE: -pos argument is currently not supported by Haiku // MediaPlayer. startPosString << fStartDurationTC->Text(); startPosString << "000"; argv[1] = startPosString.String(); status = inEntry.SetTo(&inRef); } if (status == B_OK) { status = inEntry.GetPath(&path); if (status == B_OK) argv[2] = path.Path(); } if (status == B_OK) { status = be_roster->Launch( "application/x-vnd.Haiku-MediaPlayer", 3, (char**)argv, NULL); } if (status != B_OK && status != B_ALREADY_RUNNING) { BString errorString(B_TRANSLATE("Error launching: %strError%")); errorString.ReplaceFirst("%strError%", strerror(status)); BAlert* alert = new BAlert(B_TRANSLATE("Error"), errorString.String(), B_TRANSLATE("OK")); alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); alert->Go(); } break; } case VIDEO_QUALITY_CHANGED_MESSAGE: { int32 value; BString data; message->FindInt32("be:value", &value); double percentValue = value / 100.0; if (fNumberFormat.FormatPercent(data, percentValue) != B_OK) data.SetToFormat("%d%%", (int8)value); buffer.SetToFormat(B_TRANSLATE("Video quality: %s"), data.String()); fVideoQualitySlider->SetLabel(buffer.String()); fVideoQuality = (int)percentValue; break; } case AUDIO_QUALITY_CHANGED_MESSAGE: { int32 value; BString data; message->FindInt32("be:value", &value); double percentValue = value / 100.0; if (fNumberFormat.FormatPercent(data, percentValue) != B_OK) data.SetToFormat("%d%%", (int8)value); buffer.SetToFormat(B_TRANSLATE("Audio quality: %s"), data.String()); fAudioQualitySlider->SetLabel(buffer.String()); fAudioQuality = (int)percentValue; break; } default: BWindow::MessageReceived(message); break; } } bool MediaConverterWindow::QuitRequested() { if (!fConverting) { BMessenger(be_app).SendMessage(B_QUIT_REQUESTED); return true; } else if (!fCancelling) { fCancelling = true; SetStatusMessage(B_TRANSLATE("Cancelling")); BMessenger(be_app).SendMessage(CANCEL_CONVERSION_MESSAGE); } return false; } // #pragma mark - void MediaConverterWindow::LanguageChanged() { _DestroyMenu(); _CreateMenu(); _UpdateLabels(); BuildAudioVideoMenus(); Lock(); fInfoView->Invalidate(); Unlock(); } void MediaConverterWindow::BuildAudioVideoMenus() { BMenu* menu = fAudioMenu->Menu(); BMenuItem* item; // clear out old audio codec menu items while ((item = menu->RemoveItem((int32)0)) != NULL) delete item; bool separator = true; // get selected file format FileFormatMenuItem* ffmi = (FileFormatMenuItem*)fFormatMenu->Menu()->FindMarked(); media_file_format* mf_format = &(ffmi->fFileFormat); media_format format, outfmt; format.Clear(); media_codec_info codec_info; int32 cookie = 0; CodecMenuItem* cmi; // add available audio encoders to menu format.type = B_MEDIA_RAW_AUDIO; format.u.raw_audio = media_raw_audio_format::wildcard; while (get_next_encoder(&cookie, mf_format, &format, &outfmt, &codec_info) == B_OK) { if (separator) { menu->AddItem(new BMenuItem( B_TRANSLATE_CONTEXT("No audio", "Audio codecs list"), new BMessage(AUDIO_CODEC_SELECT_MESSAGE))); menu->AddSeparatorItem(); separator = false; } cmi = new CodecMenuItem(&codec_info, AUDIO_CODEC_SELECT_MESSAGE); menu->AddItem(cmi); // reset media format struct /* format.type = B_MEDIA_RAW_AUDIO; format.u.raw_audio = media_raw_audio_format::wildcard; */ } // mark first audio encoder item = menu->ItemAt(0); if (item != NULL) { fAudioMenu->SetEnabled(fEnabled); fAudioQualitySlider->SetEnabled(fEnabled); item->SetMarked(true); ((BInvoker*)item)->Invoke(); } else { item = new BMenuItem( B_TRANSLATE_CONTEXT("None available", "Audio codecs"), NULL); menu->AddItem(item); item->SetMarked(true); fAudioMenu->SetEnabled(false); fAudioQualitySlider->SetEnabled(false); } // clear out old video codec menu items menu = fVideoMenu->Menu(); while ((item = menu->RemoveItem((int32)0)) != NULL) delete item; separator = true; // construct a generic video format. Some of these parameters // seem silly, but are needed for R4.5.x, which is more picky // than subsequent BeOS releases will be. format.Clear(); format.type = B_MEDIA_RAW_VIDEO; format.u.raw_video.last_active = (uint32)(240 - 1); format.u.raw_video.orientation = B_VIDEO_TOP_LEFT_RIGHT; format.u.raw_video.display.format = B_RGB32; format.u.raw_video.display.line_width = (int32)320; format.u.raw_video.display.line_count = (int32)240; format.u.raw_video.display.bytes_per_row = 4 * 320; // add available video encoders to menu cookie = 0; while (get_next_encoder(&cookie, mf_format, &format, &outfmt, &codec_info) == B_OK) { if (separator) { menu->AddItem(new BMenuItem( B_TRANSLATE_CONTEXT("No video", "Video codecs list"), new BMessage(VIDEO_CODEC_SELECT_MESSAGE))); menu->AddSeparatorItem(); separator = false; } cmi = new CodecMenuItem(&codec_info, VIDEO_CODEC_SELECT_MESSAGE); menu->AddItem(cmi); } // mark first video encoder item = menu->ItemAt(0); if (item != NULL) { fVideoMenu->SetEnabled(fEnabled); fVideoQualitySlider->SetEnabled(fEnabled); item->SetMarked(true); ((BInvoker*)item)->Invoke(); } else { item = new BMenuItem( B_TRANSLATE_CONTEXT("None available", "Video codecs"), NULL); menu->AddItem(item); item->SetMarked(true); fVideoMenu->SetEnabled(false); fVideoQualitySlider->SetEnabled(false); } } void MediaConverterWindow::GetSelectedFormatInfo(media_file_format** format, media_codec_info** audio, media_codec_info** video) { *audio = NULL; *video = NULL; *format = NULL; FileFormatMenuItem* formatItem = dynamic_cast(fFormatMenu->Menu()->FindMarked()); if (formatItem != NULL) *format = &(formatItem->fFileFormat); *audio = *video = NULL; CodecMenuItem* codecItem = dynamic_cast(fAudioMenu->Menu()->FindMarked()); if (codecItem != NULL) *audio = &(codecItem->fCodecInfo); codecItem = dynamic_cast(fVideoMenu->Menu()->FindMarked()); if (codecItem != NULL) *video = &(codecItem->fCodecInfo); } void MediaConverterWindow::BuildFormatMenu() { BMenu* menu = fFormatMenu->Menu(); BMenuItem* item; // clear out old format menu items while ((item = menu->RemoveItem((int32)0)) != NULL) delete item; // add menu items for each file format media_file_format mfi; int32 cookie = 0; FileFormatMenuItem* ff_item; while (get_next_file_format(&cookie, &mfi) == B_OK) { if ((mfi.capabilities & media_file_format::B_WRITABLE) == 0) continue; ff_item = new FileFormatMenuItem(&mfi); menu->AddItem(ff_item); } // mark first item item = menu->ItemAt(0); if (item != NULL) { item->SetMarked(true); ((BInvoker*)item)->Invoke(); } } void MediaConverterWindow::SetFileMessage(const char* message) { fFileStatus->SetText(message); } void MediaConverterWindow::SetStatusMessage(const char* message) { fStatus->SetText(message); } // #pragma mark - bool MediaConverterWindow::AddSourceFile(BMediaFile* file, const entry_ref& ref) { if (!fListView->AddMediaItem(file, ref)) return false; if (!fOutputDirSpecified) { BEntry entry(&ref); entry.GetParent(&entry); _SetOutputFolder(entry); } return true; } void MediaConverterWindow::RemoveSourceFile(int32 index) { delete fListView->RemoveItem(index); fStartDurationTC->SetText("0"); fEndDurationTC->SetText("0"); } int32 MediaConverterWindow::CountSourceFiles() { return fListView->CountItems(); } status_t MediaConverterWindow::GetSourceFileAt(int32 index, BMediaFile** _file, entry_ref* ref) { MediaFileListItem* item = dynamic_cast( fListView->ItemAt(index)); if (item != NULL) { *_file = item->fMediaFile; *ref = item->fRef; return B_OK; } else return B_ERROR; } void MediaConverterWindow::SourceFileSelectionChanged() { int32 selected = fListView->CurrentSelection(); BMediaFile* file = NULL; entry_ref ref; bool enabled = GetSourceFileAt(selected, &file, &ref) == B_OK; fPreviewButton->SetEnabled(enabled); fVideoQualitySlider->SetEnabled(enabled); fAudioQualitySlider->SetEnabled(enabled); fStartDurationTC->SetEnabled(enabled); fEndDurationTC->SetEnabled(enabled); BString duration; if (enabled) { fInfoView->Update(file, &ref); // HACK: get the fInfoView to update the duration "synchronously" UpdateIfNeeded(); duration << fInfoView->Duration() / 1000; } else duration = "0"; // update duration text controls fStartDurationTC->SetText("0"); fEndDurationTC->SetText(duration.String()); } // #pragma mark - void MediaConverterWindow::SetEnabled(bool enabled, bool convertEnabled) { fConvertButton->SetEnabled(convertEnabled); if (enabled == fEnabled) return; fFormatMenu->SetEnabled(enabled); fAudioMenu->SetEnabled(enabled); fVideoMenu->SetEnabled(enabled); fListView->SetEnabled(enabled); fStartDurationTC->SetEnabled(enabled); fEndDurationTC->SetEnabled(enabled); fEnabled = enabled; } bool MediaConverterWindow::IsEnabled() { return fEnabled; } const char* MediaConverterWindow::StartDuration() const { return fStartDurationTC->Text(); } const char* MediaConverterWindow::EndDuration() const { return fEndDurationTC->Text(); } BDirectory MediaConverterWindow::OutputDirectory() const { return fOutputDir; } void MediaConverterWindow::SetAudioQualityLabel(const char* label) { fAudioQualitySlider->SetLabel(label); } void MediaConverterWindow::SetVideoQualityLabel(const char* label) { fVideoQualitySlider->SetLabel(label); } void MediaConverterWindow::TruncateOutputFolderPath() { BEntry entry; fOutputDir.GetEntry(&entry); BPath path; entry.GetPath(&path); BString pathString(path.Path()); float maxWidth = fVideoMenu->MenuBar()->Frame().Width(); fOutputFolder->TruncateString(&pathString, B_TRUNCATE_MIDDLE, maxWidth); fOutputFolder->SetText(pathString.String()); if (fOutputFolder->StringWidth(path.Path()) > maxWidth) fOutputFolder->SetToolTip(path.Path()); else fOutputFolder->SetToolTip((const char*)NULL); } // #pragma mark - void MediaConverterWindow::_UpdateLabels() { BNumberFormat fNumberFormat; if (fSourcesBox != NULL) { fSourcesBox->SetLabel(B_TRANSLATE("Source files")); _UpdateBBoxLayoutInsets(fSourcesBox); } if (fInfoBox != NULL) fInfoBox->SetLabel(B_TRANSLATE("File details")); if (fOutputBox != NULL) { fOutputBox->SetLabel(B_TRANSLATE("Output format")); _UpdateBBoxLayoutInsets(fOutputBox); } if (fConvertButton != NULL) fConvertButton->SetLabel(B_TRANSLATE("Convert")); if (fPreviewButton != NULL) fPreviewButton->SetLabel(B_TRANSLATE("Preview")); if (fDestButton != NULL) fDestButton->SetLabel(B_TRANSLATE("Output folder")); if (fVideoQualitySlider != NULL) { BString buffer; BString data; double percentValue = fVideoQuality / 100.0; if (fNumberFormat.FormatPercent(data, percentValue) != B_OK) data.SetToFormat("%d%%", (int8)fVideoQuality); buffer.SetToFormat(B_TRANSLATE("Video quality: %s"), data.String()); fVideoQuality = (int)percentValue; fVideoQualitySlider->SetLabel(buffer.String()); fVideoQualitySlider->SetLimitLabels(B_TRANSLATE("Low"), B_TRANSLATE("High")); } if (fAudioQualitySlider != NULL) { BString buffer; BString data; double percentValue = fAudioQuality / 100.0; if (fNumberFormat.FormatPercent(data, percentValue) != B_OK) { data.SetToFormat("%d%%", (int8)fAudioQuality); } buffer.SetToFormat(B_TRANSLATE("Audio quality: %s"), data.String()); fAudioQuality = (int)percentValue; fAudioQualitySlider->SetLabel(buffer.String()); fAudioQualitySlider->SetLimitLabels(B_TRANSLATE("Low"), B_TRANSLATE("High")); } if (fStartDurationTC != NULL) fStartDurationTC->SetLabel(B_TRANSLATE("Start [ms]: ")); if (fEndDurationTC != NULL) fEndDurationTC->SetLabel(B_TRANSLATE("End   [ms]: ")); if (fFormatMenu != NULL) fFormatMenu->SetLabel(B_TRANSLATE("File format:")); if (fAudioMenu != NULL) fAudioMenu->SetLabel(B_TRANSLATE("Audio encoding:")); if (fVideoMenu != NULL) fVideoMenu->SetLabel(B_TRANSLATE("Video encoding:")); SetFileMessage(B_TRANSLATE("Drop media files onto this window")); } void MediaConverterWindow::_UpdateBBoxLayoutInsets(BBox* box) { BTwoDimensionalLayout* layout = dynamic_cast(box->GetLayout()); if (layout != NULL) { float padding = be_control_look->DefaultItemSpacing(); layout->SetInsets(padding, box->TopBorderOffset() + padding, padding, padding); } } void MediaConverterWindow::_DestroyMenu() { BMenu* menu; while ((menu = fMenuBar->SubmenuAt(0)) != NULL) { fMenuBar->RemoveItem(menu); delete menu; } } void MediaConverterWindow::_CreateMenu() { BMenu* menu; BMenuItem* item; menu = new BMenu(B_TRANSLATE_CONTEXT("File", "Menu")); item = new BMenuItem(B_TRANSLATE_CONTEXT("Open" B_UTF8_ELLIPSIS, "Menu"), new BMessage(OPEN_FILE_MESSAGE), 'O'); menu->AddItem(item); menu->AddSeparatorItem(); item = new BMenuItem(B_TRANSLATE_CONTEXT("Quit", "Menu"), new BMessage(QUIT_MESSAGE), 'Q'); menu->AddItem(item); fMenuBar->AddItem(menu); } void MediaConverterWindow::_SetOutputFolder(BEntry entry) { BPath path; entry.GetPath(&path); if (access(path.Path(), W_OK) != -1) { fOutputDir.SetTo(&entry); } else { BString errorString(B_TRANSLATE("Error writing to location: %strPath%." " Defaulting to location: /boot/home")); errorString.ReplaceFirst("%strPath%", path.Path()); BAlert* alert = new BAlert(B_TRANSLATE("Error"), errorString.String(), B_TRANSLATE("OK")); alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); alert->Go(); fOutputDir.SetTo("/boot/home"); } TruncateOutputFolderPath(); }