// -------------------------------------------------------------------------------------------------------------------- // // This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. // // // HandBrakes Main Window // // -------------------------------------------------------------------------------------------------------------------- namespace HandBrakeWPF.ViewModels { using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Threading; using System.Windows; using System.Windows.Input; using Caliburn.Micro; using HandBrake.ApplicationServices.Interop; using HandBrakeWPF.Commands; using HandBrakeWPF.Commands.Menu; using HandBrakeWPF.EventArgs; using HandBrakeWPF.Factories; using HandBrakeWPF.Helpers; using HandBrakeWPF.Model; using HandBrakeWPF.Model.Audio; using HandBrakeWPF.Model.Subtitles; using HandBrakeWPF.Properties; using HandBrakeWPF.Services.Encode.EventArgs; using HandBrakeWPF.Services.Encode.Interfaces; using HandBrakeWPF.Services.Encode.Model; using HandBrakeWPF.Services.Encode.Model.Models; using HandBrakeWPF.Services.Interfaces; using HandBrakeWPF.Services.Presets.Interfaces; using HandBrakeWPF.Services.Presets.Model; using HandBrakeWPF.Services.Queue.Interfaces; using HandBrakeWPF.Services.Queue.Model; using HandBrakeWPF.Services.Scan.EventArgs; using HandBrakeWPF.Services.Scan.Interfaces; using HandBrakeWPF.Services.Scan.Model; using HandBrakeWPF.Startup; using HandBrakeWPF.Utilities; using HandBrakeWPF.ViewModels.Interfaces; using HandBrakeWPF.Views; using Ookii.Dialogs.Wpf; using Action = System.Action; using Application = System.Windows.Application; using DataFormats = System.Windows.DataFormats; using DragEventArgs = System.Windows.DragEventArgs; using Execute = Caliburn.Micro.Execute; using LogManager = HandBrakeWPF.Helpers.LogManager; using MessageBox = System.Windows.MessageBox; using OpenFileDialog = Microsoft.Win32.OpenFileDialog; using SaveFileDialog = Microsoft.Win32.SaveFileDialog; /// /// HandBrakes Main Window /// public class MainViewModel : ViewModelBase, IMainViewModel { #region Private Variables and Services private readonly IQueueProcessor queueProcessor; private readonly IPresetService presetService; private readonly IErrorService errorService; private readonly IUpdateService updateService; private readonly IWindowManager windowManager; private readonly IUserSettingService userSettingService; private readonly IScan scanService; private readonly IEncode encodeService; private readonly Win7 windowsSeven = new Win7(); private string windowName; private string sourceLabel; private OutputFormat selectedOutputFormat; private bool isMkv; private string statusLabel; private string programStatusLabel; private Source scannedSource; private Title selectedTitle; private string duration; private bool isEncoding; private bool showStatusWindow; private Preset selectedPreset; private EncodeTask queueEditTask; private int lastEncodePercentage; private bool isPresetPanelShowing; private bool showSourceSelection; private BindingList drives; private bool canPause; private bool showAlertWindow; private string alertWindowHeader; private string alertWindowText; private bool hasSource; #endregion /// /// Initializes a new instance of the class. /// The viewmodel for HandBrakes main window. /// /// /// The User Setting Service /// /// /// The scan Service. /// /// /// The encode Service. /// /// /// The preset Service. /// /// /// The Error Service /// /// /// The update Service. /// /// /// The when Done Service. /// *** Leave in Constructor. *** /// /// /// The window Manager. /// /// /// The picture Settings View Model. /// /// /// The video View Model. /// /// /// The filters View Model. /// /// /// The audio View Model. /// /// /// The subtitles View Model. /// /// /// The advanced View Model. /// /// /// The chapters View Model. /// /// /// The static Preview View Model. /// /// /// The queue View Model. /// /// /// The Meta Data View Model /// public MainViewModel(IUserSettingService userSettingService, IScan scanService, IEncode encodeService, IPresetService presetService, IErrorService errorService, IUpdateService updateService, IPrePostActionService whenDoneService, IWindowManager windowManager, IPictureSettingsViewModel pictureSettingsViewModel, IVideoViewModel videoViewModel, IFiltersViewModel filtersViewModel, IAudioViewModel audioViewModel, ISubtitlesViewModel subtitlesViewModel, IX264ViewModel advancedViewModel, IChaptersViewModel chaptersViewModel, IStaticPreviewViewModel staticPreviewViewModel, IQueueViewModel queueViewModel, IMetaDataViewModel metaDataViewModel) { this.scanService = scanService; this.encodeService = encodeService; this.presetService = presetService; this.errorService = errorService; this.updateService = updateService; this.windowManager = windowManager; this.QueueViewModel = queueViewModel; this.userSettingService = userSettingService; this.queueProcessor = IoC.Get(); this.PictureSettingsViewModel = pictureSettingsViewModel; this.VideoViewModel = videoViewModel; this.MetaDataViewModel = metaDataViewModel; this.FiltersViewModel = filtersViewModel; this.AudioViewModel = audioViewModel; this.SubtitleViewModel = subtitlesViewModel; this.ChaptersViewModel = chaptersViewModel; this.AdvancedViewModel = advancedViewModel; this.StaticPreviewViewModel = staticPreviewViewModel; // Setup Properties this.WindowTitle = Resources.HandBrake_Title; this.CurrentTask = new EncodeTask(); this.CurrentTask.PropertyChanged += this.CurrentTask_PropertyChanged; this.ScannedSource = new Source(); this.HasSource = false; // Setup Events this.scanService.ScanStarted += this.ScanStared; this.scanService.ScanCompleted += this.ScanCompleted; this.scanService.ScanStatusChanged += this.ScanStatusChanged; this.queueProcessor.JobProcessingStarted += this.QueueProcessorJobProcessingStarted; this.queueProcessor.QueueCompleted += this.QueueCompleted; this.queueProcessor.QueueChanged += this.QueueChanged; this.queueProcessor.EncodeService.EncodeStatusChanged += this.EncodeStatusChanged; this.userSettingService.SettingChanged += this.UserSettingServiceSettingChanged; this.Presets = this.presetService.Presets; this.Drives = new BindingList(); // Set Process Priority switch (this.userSettingService.GetUserSetting(UserSettingConstants.ProcessPriority)) { case "Realtime": Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.RealTime; break; case "High": Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High; break; case "Above Normal": Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.AboveNormal; break; case "Normal": Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.Normal; break; case "Low": Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.Idle; break; default: Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.BelowNormal; break; } // Setup Commands this.QueueCommand = new QueueCommands(this.QueueViewModel); LogManager.Init(); HandBrakeInstanceManager.Init(); } #region View Model Properties /// /// Gets or sets PictureSettingsViewModel. /// public IPictureSettingsViewModel PictureSettingsViewModel { get; set; } /// /// Gets or sets AudioViewModel. /// public IAudioViewModel AudioViewModel { get; set; } /// /// Gets or sets SubtitleViewModel. /// public ISubtitlesViewModel SubtitleViewModel { get; set; } /// /// Gets or sets ChaptersViewModel. /// public IChaptersViewModel ChaptersViewModel { get; set; } /// /// Gets or sets AdvancedViewModel. /// public IX264ViewModel AdvancedViewModel { get; set; } /// /// Gets or sets VideoViewModel. /// public IVideoViewModel VideoViewModel { get; set; } /// /// Gets or sets FiltersViewModel. /// public IFiltersViewModel FiltersViewModel { get; set; } /// /// Gets or sets the queue view model. /// public IQueueViewModel QueueViewModel { get; set; } /// /// Gets or sets the static preview view model. /// public IStaticPreviewViewModel StaticPreviewViewModel { get; set; } /// /// Gets or sets the The MetaData View Model /// public IMetaDataViewModel MetaDataViewModel { get; set; } #endregion #region Properties /// /// Gets or sets TestProperty. /// public string WindowTitle { get { return this.windowName; } set { if (!Equals(this.windowName, value)) { this.windowName = value; } } } /// /// Gets or sets the Program Status Toolbar Label /// This indicates the status of HandBrake /// public string ProgramStatusLabel { get { return string.IsNullOrEmpty(this.programStatusLabel) ? Resources.State_Ready : this.programStatusLabel; } set { if (!Equals(this.programStatusLabel, value)) { this.programStatusLabel = value; this.NotifyOfPropertyChange(() => this.ProgramStatusLabel); } } } /// /// Gets or sets the Program Status Toolbar Label /// This indicates the status of HandBrake /// public string StatusLabel { get { return string.IsNullOrEmpty(this.statusLabel) ? Resources.State_Ready : this.statusLabel; } set { if (!Equals(this.statusLabel, value)) { this.statusLabel = value; this.NotifyOfPropertyChange(() => this.StatusLabel); } } } /// /// Gets or sets Presets. /// public IEnumerable Presets { get; set; } /// /// Gets or sets SelectedPreset. /// public Preset SelectedPreset { get { return this.selectedPreset; } set { this.selectedPreset = value; if (this.SelectedPreset != null) { // Main Window Settings this.OptimizeMP4 = selectedPreset.Task.OptimizeMP4; this.IPod5GSupport = selectedPreset.Task.IPod5GSupport; this.SelectedOutputFormat = selectedPreset.Task.OutputFormat; // Tab Settings this.PictureSettingsViewModel.SetPreset(this.SelectedPreset, this.CurrentTask); this.VideoViewModel.SetPreset(this.SelectedPreset, this.CurrentTask); this.FiltersViewModel.SetPreset(this.SelectedPreset, this.CurrentTask); this.AudioViewModel.SetPreset(this.SelectedPreset, this.CurrentTask); this.SubtitleViewModel.SetPreset(this.SelectedPreset, this.CurrentTask); this.ChaptersViewModel.SetPreset(this.SelectedPreset, this.CurrentTask); this.AdvancedViewModel.SetPreset(this.SelectedPreset, this.CurrentTask); this.MetaDataViewModel.SetPreset(this.SelectedPreset, this.CurrentTask); // Do this again to force an update for m4v/mp4 selection this.SelectedOutputFormat = selectedPreset.Task.OutputFormat; } this.NotifyOfPropertyChange(() => this.SelectedPreset); } } /// /// Optimise MP4 Checkbox /// public bool OptimizeMP4 { get { return this.CurrentTask.OptimizeMP4; } set { if (value == this.CurrentTask.OptimizeMP4) { return; } this.CurrentTask.OptimizeMP4 = value; this.NotifyOfPropertyChange(() => this.OptimizeMP4); } } /// /// iPod 5G Status /// public bool IPod5GSupport { get { return this.CurrentTask.IPod5GSupport; } set { if (value == this.CurrentTask.IPod5GSupport) { return; } this.CurrentTask.IPod5GSupport = value; this.NotifyOfPropertyChange(() => this.IPod5GSupport); } } /// /// Gets or sets The Current Encode Task that the user is building /// public EncodeTask CurrentTask { get; set; } /// /// Gets or sets the Last Scanned Source /// This object contains information about the scanned source. /// public Source ScannedSource { get { return this.scannedSource; } set { this.scannedSource = value; this.NotifyOfPropertyChange(() => ScannedSource); } } /// /// Gets or sets the title specific scan. /// public int TitleSpecificScan { get; set; } /// /// Gets or sets a value indicating whether the encode serivce supports pausing. /// public bool CanPause { get { return this.canPause; } set { if (value.Equals(this.canPause)) { return; } this.canPause = value; this.NotifyOfPropertyChange(() => this.CanPause); } } /// /// Gets or sets the Source Label /// This indicates the status of scans. /// public string SourceLabel { get { return string.IsNullOrEmpty(this.sourceLabel) ? Resources.Main_SelectSource : this.sourceLabel; } set { if (!Equals(this.sourceLabel, value)) { this.sourceLabel = value; this.NotifyOfPropertyChange(() => SourceLabel); } } } /// /// Gets SourceName. /// public string SourceName { get { // Sanity Check if (ScannedSource == null || ScannedSource.ScanPath == null) { return string.Empty; } // The title that is selected has a source name. This means it's part of a batch scan. if (selectedTitle != null && !string.IsNullOrEmpty(selectedTitle.SourceName) && !selectedTitle.SourceName.EndsWith("\\")) { return Path.GetFileNameWithoutExtension(selectedTitle.SourceName); } // Check if we have a Folder, if so, check if it's a DVD / Bluray drive and get the label. if (ScannedSource.ScanPath.EndsWith("\\")) { foreach (DriveInformation item in DriveUtilities.GetDrives()) { if (item.RootDirectory.Contains(this.ScannedSource.ScanPath.Replace("\\\\", "\\"))) { return item.VolumeLabel; } } } if (Path.GetFileNameWithoutExtension(this.ScannedSource.ScanPath) != "VIDEO_TS") return Path.GetFileNameWithoutExtension(this.ScannedSource.ScanPath); return Path.GetFileNameWithoutExtension(Path.GetDirectoryName(this.ScannedSource.ScanPath)); } } /// /// Gets RangeMode. /// public IEnumerable RangeMode { get { return new List { PointToPointMode.Chapters, PointToPointMode.Seconds, PointToPointMode.Frames }; } } /// /// Gets a value indicating whether ShowTextEntryForPointToPointMode. /// public bool ShowTextEntryForPointToPointMode { get { return this.SelectedPointToPoint != PointToPointMode.Chapters; } } /// /// Gets StartEndRangeItems. /// public IEnumerable StartEndRangeItems { get { if (this.SelectedTitle == null) { return null; } return this.SelectedTitle.Chapters.Select(item => item.ChapterNumber).Select(dummy => dummy).ToList(); } } /// /// Gets Angles. /// public IEnumerable Angles { get { if (this.SelectedTitle == null) { return null; } List items = new List(); for (int i = 1; i <= this.selectedTitle.AngleCount; i++) { items.Add(i); } return items; } } /// /// Gets or sets Duration. /// public string Duration { get { return string.IsNullOrEmpty(duration) ? "--:--:--" : duration; } set { duration = value; this.NotifyOfPropertyChange(() => Duration); } } /// /// Gets or sets a value indicating whether IsEncoding. /// public bool IsEncoding { get { return this.isEncoding; } set { this.isEncoding = value; this.CanPause = value; this.NotifyOfPropertyChange(() => this.IsEncoding); } } /// /// Gets or sets a value indicating whether ShowStatusWindow. /// public bool ShowStatusWindow { get { return this.showStatusWindow; } set { this.showStatusWindow = value; this.NotifyOfPropertyChange(() => this.ShowStatusWindow); } } /// /// Gets or sets a value indicating whether IsMkv. /// public bool IsMkv { get { return this.isMkv; } set { this.isMkv = value; this.NotifyOfPropertyChange(() => this.IsMkv); } } /// /// Gets RangeMode. /// public IEnumerable OutputFormats { get { return new List { OutputFormat.Mp4, OutputFormat.Mkv }; } } /// /// Gets or sets Destination. /// public string Destination { get { return this.CurrentTask.Destination; } set { if (!Equals(this.CurrentTask.Destination, value)) { if (!string.IsNullOrEmpty(value)) { string ext = string.Empty; try { ext = Path.GetExtension(value); if (FileHelper.FilePathHasInvalidChars(value)) { this.errorService.ShowMessageBox(Resources.Main_InvalidDestination, Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error); return; } } catch (ArgumentException) { this.errorService.ShowMessageBox(Resources.Main_InvalidDestination, Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error); return; } this.CurrentTask.Destination = value; this.NotifyOfPropertyChange(() => this.Destination); switch (ext) { case ".mkv": this.SelectedOutputFormat = OutputFormat.Mkv; break; case ".mp4": this.SelectedOutputFormat = OutputFormat.Mp4; break; case ".m4v": this.SelectedOutputFormat = OutputFormat.Mp4; break; } } else { this.CurrentTask.Destination = string.Empty; this.NotifyOfPropertyChange(() => this.Destination); } } } } /// /// Gets or sets SelectedTitle. /// public Title SelectedTitle { get { return this.selectedTitle; } set { if (!Equals(this.selectedTitle, value)) { this.selectedTitle = value; if (this.selectedTitle == null) { return; } // Use the Path on the Title, or the Source Scan path if one doesn't exist. this.SourceLabel = this.SourceName; this.CurrentTask.Source = !string.IsNullOrEmpty(this.selectedTitle.SourceName) ? this.selectedTitle.SourceName : this.ScannedSource.ScanPath; this.CurrentTask.Title = value.TitleNumber; this.NotifyOfPropertyChange(() => this.StartEndRangeItems); this.NotifyOfPropertyChange(() => this.SelectedTitle); this.NotifyOfPropertyChange(() => this.Angles); // Default the Start and End Point dropdowns this.SelectedStartPoint = 1; this.SelectedEndPoint = this.selectedTitle.Chapters != null && this.selectedTitle.Chapters.Count != 0 ? this.selectedTitle.Chapters.Last().ChapterNumber : 1; this.SelectedPointToPoint = PointToPointMode.Chapters; this.SelectedAngle = 1; if (this.userSettingService.GetUserSetting(UserSettingConstants.AutoNaming)) { if (this.userSettingService.GetUserSetting(UserSettingConstants.AutoNameFormat) != null) { this.Destination = AutoNameHelper.AutoName(this.CurrentTask, this.SourceName, this.SelectedPreset); } } this.NotifyOfPropertyChange(() => this.CurrentTask); this.Duration = this.DurationCalculation(); // Setup the tab controls this.SetupTabs(); } } } /// /// Gets or sets SelectedAngle. /// public int SelectedAngle { get { return this.CurrentTask.StartPoint; } set { this.CurrentTask.Angle = value; this.NotifyOfPropertyChange(() => this.SelectedAngle); } } /// /// Gets or sets a value indicating whether is timespan range. /// public bool IsTimespanRange { get; set; } /// /// Gets or sets SelectedStartPoint. /// public int SelectedStartPoint { get { return this.CurrentTask.StartPoint; } set { this.CurrentTask.StartPoint = value; this.NotifyOfPropertyChange(() => this.SelectedStartPoint); this.Duration = this.DurationCalculation(); if (this.userSettingService.GetUserSetting(UserSettingConstants.AutoNaming) && this.ScannedSource.ScanPath != null) { if (this.SelectedPointToPoint == PointToPointMode.Chapters && this.userSettingService.GetUserSetting(UserSettingConstants.AutoNameFormat) != null && this.userSettingService.GetUserSetting(UserSettingConstants.AutoNameFormat).Contains(Constants.Chapters)) { this.Destination = AutoNameHelper.AutoName(this.CurrentTask, this.SourceName, this.SelectedPreset); } } if (this.SelectedStartPoint > this.SelectedEndPoint) { this.SelectedEndPoint = this.SelectedStartPoint; } } } /// /// Gets or sets SelectedEndPoint. /// public int SelectedEndPoint { get { return this.CurrentTask.EndPoint; } set { this.CurrentTask.EndPoint = value; this.NotifyOfPropertyChange(() => this.SelectedEndPoint); this.Duration = this.DurationCalculation(); if (this.SelectedPointToPoint == PointToPointMode.Chapters && this.userSettingService.GetUserSetting(UserSettingConstants.AutoNameFormat) != null && this.userSettingService.GetUserSetting(UserSettingConstants.AutoNameFormat).Contains(Constants.Chapters)) { this.Destination = AutoNameHelper.AutoName(this.CurrentTask, this.SourceName, this.SelectedPreset); } if (this.SelectedStartPoint > this.SelectedEndPoint && this.SelectedPointToPoint == PointToPointMode.Chapters) { this.SelectedStartPoint = this.SelectedEndPoint; } } } /// /// Gets or sets SelectedPointToPoint. /// public PointToPointMode SelectedPointToPoint { get { return this.CurrentTask.PointToPointMode; } set { this.CurrentTask.PointToPointMode = value; this.NotifyOfPropertyChange(() => SelectedPointToPoint); this.NotifyOfPropertyChange(() => ShowTextEntryForPointToPointMode); if (value == PointToPointMode.Chapters && this.SelectedTitle != null) { if (this.selectedTitle == null) { return; } this.SelectedStartPoint = 1; this.SelectedEndPoint = selectedTitle.Chapters != null && selectedTitle.Chapters.Count > 0 ? selectedTitle.Chapters.Last().ChapterNumber : 1; } else if (value == PointToPointMode.Seconds) { if (this.selectedTitle == null) { return; } this.SelectedStartPoint = 0; int timeInSeconds; if (int.TryParse(Math.Round(selectedTitle.Duration.TotalSeconds, 0).ToString(CultureInfo.InvariantCulture), out timeInSeconds)) { this.SelectedEndPoint = timeInSeconds; } this.IsTimespanRange = true; this.NotifyOfPropertyChange(() => this.IsTimespanRange); } else { if (this.selectedTitle == null) { return; } // Note this does not account for VFR. It's only a guesstimate. double estimatedTotalFrames = selectedTitle.Fps * selectedTitle.Duration.TotalSeconds; this.SelectedStartPoint = 0; int totalFrames; if (int.TryParse(Math.Round(estimatedTotalFrames, 0).ToString(CultureInfo.InvariantCulture), out totalFrames)) { this.SelectedEndPoint = totalFrames; } this.IsTimespanRange = false; this.NotifyOfPropertyChange(() => this.IsTimespanRange); } } } /// /// Gets or sets SelectedOutputFormat. /// public OutputFormat SelectedOutputFormat { get { return this.selectedOutputFormat; } set { if (!Equals(this.selectedOutputFormat, value)) { this.selectedOutputFormat = value; this.CurrentTask.OutputFormat = value; this.NotifyOfPropertyChange(() => SelectedOutputFormat); this.NotifyOfPropertyChange(() => this.CurrentTask.OutputFormat); this.NotifyOfPropertyChange(() => IsMkv); this.SetExtension(string.Format(".{0}", this.selectedOutputFormat.ToString().ToLower())); this.VideoViewModel.RefreshTask(); this.AudioViewModel.RefreshTask(); } } } /// /// Gets a value indicating whether show advanced tab. /// public bool ShowAdvancedTab { get { return this.userSettingService.GetUserSetting(UserSettingConstants.ShowAdvancedTab); } } /// /// Gets or sets a value indicating whether is preset panel showing. /// public bool IsPresetPanelShowing { get { return this.isPresetPanelShowing; } set { if (!Equals(this.isPresetPanelShowing, value)) { this.isPresetPanelShowing = value; this.NotifyOfPropertyChange(() => this.IsPresetPanelShowing); // Save the setting if it has changed. if (this.userSettingService.GetUserSetting(UserSettingConstants.ShowPresetPanel) != value) { this.userSettingService.SetUserSetting(UserSettingConstants.ShowPresetPanel, value); } } } } /// /// Gets or sets a value indicating progress percentage. /// public int ProgressPercentage { get; set; } /// /// Gets or sets a value indicating whether show source selection. /// public bool ShowSourceSelection { get { return this.showSourceSelection; } set { if (value.Equals(this.showSourceSelection)) { return; } this.showSourceSelection = value; this.NotifyOfPropertyChange(() => this.ShowSourceSelection); // Refresh the drives. if (this.showSourceSelection) { this.Drives.Clear(); foreach (SourceMenuItem menuItem in from item in DriveUtilities.GetDrives() let driveInformation = item select new SourceMenuItem { Text = string.Format("{0} ({1})", item.RootDirectory, item.VolumeLabel), Command = new SourceMenuCommand(() => this.ProcessDrive(driveInformation)), Tag = item, IsDrive = true }) { this.Drives.Add(menuItem); } this.TitleSpecificScan = 0; this.NotifyOfPropertyChange(() => this.TitleSpecificScan); } } } /// /// Gets or sets the drives. /// public BindingList Drives { get { return this.drives; } set { if (Equals(value, this.drives)) { return; } this.drives = value; this.NotifyOfPropertyChange(() => this.Drives); } } /// /// Gets the cancel action. /// public Action CancelAction { get { return this.CancelScan; } } /// /// Action for the status window. /// public Action OpenLogWindowAction { get { return this.OpenLogWindow; } } /// /// Gets or sets a value indicating whether show alert window. /// public bool ShowAlertWindow { get { return this.showAlertWindow; } set { if (value.Equals(this.showAlertWindow)) { return; } this.showAlertWindow = value; this.NotifyOfPropertyChange(() => this.ShowAlertWindow); } } /// /// Gets or sets a value indicating whether alert window header. /// public string AlertWindowHeader { get { return this.alertWindowHeader; } set { if (value == this.alertWindowHeader) { return; } this.alertWindowHeader = value; this.NotifyOfPropertyChange(() => this.AlertWindowHeader); } } /// /// Gets or sets a value indicating whether alert window text. /// public string AlertWindowText { get { return this.alertWindowText; } set { if (value == this.alertWindowText) { return; } this.alertWindowText = value; this.NotifyOfPropertyChange(() => this.AlertWindowText); } } /// /// Gets the alert window close. /// public Action AlertWindowClose { get { return this.CloseAlertWindow; } } /// /// Gets the add to queue label. /// public string QueueLabel { get { return string.Format(Resources.Main_QueueLabel, this.queueProcessor.Count > 0 ? string.Format(" ({0})", this.queueProcessor.Count) : string.Empty); } } /// /// Gets the start label. /// public string StartLabel { get { return this.queueProcessor.Count > 0 ? Resources.Main_StartQueue : Resources.Main_Start; } } /// /// Gets or sets a value indicating whether has source. /// public bool HasSource { get { return this.hasSource; } set { if (value.Equals(this.hasSource)) { return; } this.hasSource = value; this.NotifyOfPropertyChange(() => this.HasSource); } } /// /// Flag to indicate if the queue is showing on the main view. (I.e inline queue display) /// public bool IsQueueShowingInLine { get; set; } = false; #endregion #region Commands /// /// Gets or sets the queue command. /// public ICommand QueueCommand { get; set; } #endregion #region Load and Shutdown Handling /// /// Initialise this view model. /// public override void OnLoad() { // Perform an update check if required this.updateService.PerformStartupUpdateCheck(this.HandleUpdateCheckResults); // Show or Hide the Preset Panel. this.IsPresetPanelShowing = this.userSettingService.GetUserSetting(UserSettingConstants.ShowPresetPanel); // Setup the presets. this.presetService.Load(); this.NotifyOfPropertyChange(() => this.Presets); // Queue Recovery bool queueRecovered = QueueRecoveryHelper.RecoverQueue(this.queueProcessor, this.errorService, StartupOptions.AutoRestartQueue); // If the queue is not recovered, show the source selection window by default. if (!queueRecovered) { this.ShowSourceSelection = true; } else { this.HasSource = true; // Enable the GUI. Needed for in-line queue. } // If the user has enabled --auto-start-queue, start the queue. if (StartupOptions.AutoRestartQueue && !this.queueProcessor.IsProcessing && this.queueProcessor.Count > 0) { this.queueProcessor.Start(this.userSettingService.GetUserSetting(UserSettingConstants.ClearCompletedFromQueue)); } this.SelectedPreset = this.presetService.DefaultPreset; // Reset WhenDone if necessary. if (this.userSettingService.GetUserSetting(UserSettingConstants.ResetWhenDoneAction)) { this.WhenDone("Do nothing"); } // Log Cleaning if (userSettingService.GetUserSetting(UserSettingConstants.ClearOldLogs)) { Thread clearLog = new Thread(() => GeneralUtilities.ClearLogFiles(30)); clearLog.Start(); } } /// /// Shutdown this View /// public void Shutdown() { // Shutdown Service this.encodeService.Stop(); // Unsubscribe from Events. this.scanService.ScanStarted -= this.ScanStared; this.scanService.ScanCompleted -= this.ScanCompleted; this.scanService.ScanStatusChanged -= this.ScanStatusChanged; this.queueProcessor.QueueCompleted -= this.QueueCompleted; this.queueProcessor.QueueChanged -= this.QueueChanged; this.queueProcessor.JobProcessingStarted -= this.QueueProcessorJobProcessingStarted; this.queueProcessor.EncodeService.EncodeStatusChanged -= this.EncodeStatusChanged; this.userSettingService.SettingChanged -= this.UserSettingServiceSettingChanged; } #endregion #region Menu and Taskbar /// /// Open the About Window /// public void OpenAboutApplication() { OpenOptionsScreenCommand command = new OpenOptionsScreenCommand(); command.Execute(OptionsTab.About); } /// /// Open the Options Window /// public void OpenOptionsWindow() { IShellViewModel shellViewModel = IoC.Get(); shellViewModel.DisplayWindow(ShellWindow.OptionsWindow); } /// /// Open the Log Window /// public void OpenLogWindow() { Window window = Application.Current.Windows.Cast().FirstOrDefault(x => x.GetType() == typeof(LogView)); if (window != null) { window.Activate(); } else { ILogViewModel logvm = IoC.Get(); this.windowManager.ShowWindow(logvm); } } /// /// Open the Queue Window. /// public void OpenQueueWindow() { if (this.userSettingService.GetUserSetting(UserSettingConstants.ShowQueueInline)) { this.IsQueueShowingInLine = !this.IsQueueShowingInLine; if (this.IsQueueShowingInLine) { this.QueueViewModel.Activate(); } else { this.QueueViewModel.Deactivate(); } this.NotifyOfPropertyChange(() => this.IsQueueShowingInLine); } else { this.IsQueueShowingInLine = false; this.NotifyOfPropertyChange(() => this.IsQueueShowingInLine); Window window = Application.Current.Windows.Cast().FirstOrDefault(x => x.GetType() == typeof(QueueView)); if (window != null) { if (window.WindowState == WindowState.Minimized) { window.WindowState = WindowState.Normal; } window.Activate(); } else { this.windowManager.ShowWindow(IoC.Get()); } } } /// /// Open the Queue Window. /// public void OpenPreviewWindow() { if (!string.IsNullOrEmpty(this.CurrentTask.Source)) { this.StaticPreviewViewModel.IsOpen = true; this.StaticPreviewViewModel.UpdatePreviewFrame(this.CurrentTask, this.ScannedSource); this.windowManager.ShowWindow(this.StaticPreviewViewModel); } } /// /// Launch the Help pages. /// public void LaunchHelp() { try { Process.Start("https://handbrake.fr/docs"); } catch (Exception exc) { this.errorService.ShowError(Resources.Main_UnableToLoadHelpMessage, Resources.Main_UnableToLoadHelpSolution, exc); } } /// /// Check for Updates. /// public void CheckForUpdates() { OpenOptionsScreenCommand command = new OpenOptionsScreenCommand(); command.Execute(OptionsTab.Updates); } /// /// Add the current task to the queue. /// /// /// True if added, false if error. /// public bool AddToQueue() { if (this.ScannedSource == null || string.IsNullOrEmpty(this.ScannedSource.ScanPath) || this.ScannedSource.Titles.Count == 0) { this.errorService.ShowMessageBox(Resources.Main_ScanSource, Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error); return false; } if (string.IsNullOrEmpty(this.CurrentTask.Destination)) { this.errorService.ShowMessageBox(Resources.Main_SetDestination, Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error); return false; } if (!DirectoryUtilities.IsWritable(Path.GetDirectoryName(this.CurrentTask.Destination), true, this.errorService)) { this.errorService.ShowMessageBox(Resources.Main_NoPermissionsOrMissingDirectory, Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error); return false; } // Sanity check the filename if (!string.IsNullOrEmpty(this.Destination) && FileHelper.FilePathHasInvalidChars(this.Destination)) { this.errorService.ShowMessageBox(Resources.Main_InvalidDestination, Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error); this.NotifyOfPropertyChange(() => this.Destination); return false; } if (this.Destination == this.ScannedSource.ScanPath) { this.errorService.ShowMessageBox(Resources.Main_SourceDestinationMatchError, Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error); this.Destination = null; return false; } if (this.scannedSource != null && !string.IsNullOrEmpty(this.scannedSource.ScanPath) && this.Destination.ToLower() == this.scannedSource.ScanPath.ToLower()) { this.errorService.ShowMessageBox(Resources.Main_MatchingFileOverwriteWarning, Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error); return false; } QueueTask task = new QueueTask(new EncodeTask(this.CurrentTask), HBConfigurationFactory.Create(), this.ScannedSource.ScanPath); if (!this.queueProcessor.CheckForDestinationPathDuplicates(task.Task.Destination)) { this.queueProcessor.Add(task); } else { this.errorService.ShowMessageBox(Resources.Main_DuplicateDestinationOnQueue, Resources.Error, MessageBoxButton.OK, MessageBoxImage.Warning); return false; } if (!this.IsEncoding) { this.ProgramStatusLabel = string.Format(Resources.Main_XEncodesPending, this.queueProcessor.Count); } return true; } /// /// Add all Items to the queue /// public void AddAllToQueue() { if (this.ScannedSource == null || this.ScannedSource.Titles == null || this.ScannedSource.Titles.Count == 0) { this.errorService.ShowMessageBox(Resources.Main_ScanSource, Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error); return; } if (!AutoNameHelper.IsAutonamingEnabled()) { this.errorService.ShowMessageBox(Resources.Main_TurnOnAutoFileNaming, Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error); return; } if (this.CurrentTask != null && this.CurrentTask.SubtitleTracks != null && this.CurrentTask.SubtitleTracks.Count > 0) { if (this.SubtitleViewModel.SubtitleBehaviours == null || this.SubtitleViewModel.SubtitleBehaviours.SelectedBehaviour == SubtitleBehaviourModes.None) { System.Windows.MessageBoxResult result = this.errorService.ShowMessageBox( Resources.Main_AutoAdd_AudioAndSubWarning, Resources.Warning, MessageBoxButton.YesNo, MessageBoxImage.Warning); if (result == MessageBoxResult.No) { return; } } } foreach (Title title in this.ScannedSource.Titles) { this.SelectedTitle = title; this.AddToQueue(); } } /// /// The add selection to queue. /// public void AddSelectionToQueue() { if (this.ScannedSource == null || this.ScannedSource.Titles == null || this.ScannedSource.Titles.Count == 0) { this.errorService.ShowMessageBox(Resources.Main_ScanSource, Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error); return; } if (!AutoNameHelper.IsAutonamingEnabled()) { this.errorService.ShowMessageBox(Resources.Main_TurnOnAutoFileNaming, Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error); return; } Window window = Application.Current.Windows.Cast().FirstOrDefault(x => x.GetType() == typeof(QueueSelectionViewModel)); IQueueSelectionViewModel viewModel = IoC.Get(); viewModel.Setup(this.ScannedSource, this.SourceName, (tasks) => { foreach (SelectionTitle title in tasks) { this.SelectedTitle = title.Title; this.AddToQueue(); } }, this.selectedPreset); if (window != null) { window.Activate(); } else { this.windowManager.ShowWindow(viewModel); } } /// /// Folder Scan /// public void FolderScan() { VistaFolderBrowserDialog dialog = new VistaFolderBrowserDialog { Description = Resources.Main_PleaseSelectFolder, UseDescriptionForTitle = true }; bool? dialogResult = dialog.ShowDialog(); if (dialogResult.HasValue && dialogResult.Value) { this.StartScan(dialog.SelectedPath, this.TitleSpecificScan); } } /// /// File Scan /// public void FileScan() { OpenFileDialog dialog = new OpenFileDialog { Filter = "All files (*.*)|*.*" }; bool? dialogResult = dialog.ShowDialog(); if (dialogResult.HasValue && dialogResult.Value) { this.StartScan(dialog.FileName, this.TitleSpecificScan); } } /// /// Cancel a Scan /// public void CancelScan() { this.scanService.Cancel(); } /// /// Start an Encode /// public void StartEncode() { if (this.queueProcessor.IsProcessing) { this.IsEncoding = true; return; } // Check if we already have jobs, and if we do, just start the queue. if (this.queueProcessor.Count != 0 || this.encodeService.IsPasued) { if (this.encodeService.IsPasued) { this.IsEncoding = true; } this.queueProcessor.Start(this.userSettingService.GetUserSetting(UserSettingConstants.ClearCompletedFromQueue)); return; } // Otherwise, perform Santiy Checking then add to the queue and start if everything is ok. if (this.SelectedTitle == null) { this.errorService.ShowMessageBox(Resources.Main_ScanSource, Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error); return; } if (string.IsNullOrEmpty(this.Destination)) { this.errorService.ShowMessageBox(Resources.Main_ChooseDestination, Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error); return; } if (this.scannedSource != null && !string.IsNullOrEmpty(this.scannedSource.ScanPath) && this.Destination.ToLower() == this.scannedSource.ScanPath.ToLower()) { this.errorService.ShowMessageBox(Resources.Main_MatchingFileOverwriteWarning, Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error); return; } if (File.Exists(this.Destination)) { MessageBoxResult result = this.errorService.ShowMessageBox(Resources.Main_DestinationOverwrite, Resources.Question, MessageBoxButton.YesNo, MessageBoxImage.Question); if (result == MessageBoxResult.No) { return; } } // Create the Queue Task and Start Processing if (this.AddToQueue()) { this.IsEncoding = true; this.queueProcessor.Start(this.userSettingService.GetUserSetting(UserSettingConstants.ClearCompletedFromQueue)); } } /// /// Edit a Queue Task /// /// /// The task. /// public void EditQueueJob(EncodeTask task) { // Rescan the source to make sure it's still valid this.queueEditTask = task; this.scanService.Scan(task.Source, task.Title, QueueEditAction, HBConfigurationFactory.Create()); } /// /// Pause an Encode /// public void PauseEncode() { this.queueProcessor.Pause(); this.encodeService.Pause(); this.IsEncoding = false; } /// /// Stop an Encode. /// public void StopEncode() { this.queueProcessor.Pause(); this.encodeService.Stop(); } /// /// Shutdown the Application /// public void ExitApplication() { Application.Current.Shutdown(); } /// /// The select source window. /// public void SelectSourceWindow() { ShowSourceSelection = !ShowSourceSelection; } /// /// The close source selection. /// public void CloseSourceSelection() { this.ShowSourceSelection = false; } /// /// The close alert window. /// public void CloseAlertWindow() { this.ShowAlertWindow = false; this.AlertWindowText = string.Empty; this.AlertWindowHeader = string.Empty; } /// /// Pass on the "When Done" Action to the queue view model. /// /// action public void WhenDone(string action) { this.QueueViewModel?.WhenDone(action, true); } #endregion #region Main Window Public Methods /// /// Support dropping a file onto the main window to scan. /// /// /// The DragEventArgs. /// public void FilesDroppedOnWindow(DragEventArgs e) { if (e.Data.GetDataPresent(DataFormats.FileDrop)) { string[] fileNames = e.Data.GetData(DataFormats.FileDrop, true) as string[]; if (fileNames != null && fileNames.Any() && (File.Exists(fileNames[0]) || Directory.Exists(fileNames[0]))) { this.StartScan(fileNames[0], 0); } } e.Handled = true; } /// /// The Destination Path /// public void BrowseDestination() { SaveFileDialog saveFileDialog = new SaveFileDialog { Filter = "mp4|*.mp4;*.m4v|mkv|*.mkv", CheckPathExists = true, AddExtension = true, DefaultExt = ".mp4", OverwritePrompt = true, }; string extension = Path.GetExtension(this.CurrentTask.Destination); saveFileDialog.FilterIndex = !string.IsNullOrEmpty(this.CurrentTask.Destination) && !string.IsNullOrEmpty(extension) ? (extension == ".mp4" || extension == ".m4v" ? 1 : 2) : (this.CurrentTask.OutputFormat == OutputFormat.Mkv ? 2 : 0); if (this.CurrentTask != null && !string.IsNullOrEmpty(this.CurrentTask.Destination)) { if (Directory.Exists(Path.GetDirectoryName(this.CurrentTask.Destination))) { saveFileDialog.InitialDirectory = Path.GetDirectoryName(this.CurrentTask.Destination); } saveFileDialog.FileName = Path.GetFileName(this.CurrentTask.Destination); } bool? result = saveFileDialog.ShowDialog(); if (result.HasValue && result.Value) { if (saveFileDialog.FileName == this.ScannedSource.ScanPath) { this.errorService.ShowMessageBox(Resources.Main_SourceDestinationMatchError, Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error); this.Destination = null; return; } this.Destination = saveFileDialog.FileName; // Disk Space Check string drive = Path.GetPathRoot(this.Destination); if (drive != null && !drive.StartsWith(@"\\")) { DriveInfo c = new DriveInfo(drive); if (c.AvailableFreeSpace < this.userSettingService.GetUserSetting(UserSettingConstants.PauseOnLowDiskspaceLevel)) { this.errorService.ShowMessageBox( Resources.MainViewModel_LowDiskSpaceWarning, Resources.MainViewModel_LowDiskSpace, MessageBoxButton.OK, MessageBoxImage.Warning); } } // Set the Extension Dropdown. This will also set Mp4/m4v correctly. if (!string.IsNullOrEmpty(saveFileDialog.FileName)) { switch (Path.GetExtension(saveFileDialog.FileName)) { case ".mkv": this.SelectedOutputFormat = OutputFormat.Mkv; break; case ".mp4": case ".m4v": this.SelectedOutputFormat = OutputFormat.Mp4; break; } this.NotifyOfPropertyChange(() => this.CurrentTask); } } } /// /// The open destination directory. /// public void OpenDestinationDirectory() { if (!string.IsNullOrEmpty(this.Destination)) { try { string directory = Path.GetDirectoryName(this.Destination); if (!string.IsNullOrEmpty(directory) && Directory.Exists(directory)) { Process.Start(directory); } else { MessageBoxResult result = errorService.ShowMessageBox( string.Format(Resources.DirectoryUtils_CreateFolderMsg, directory), Resources.DirectoryUtils_CreateFolder, MessageBoxButton.YesNo, MessageBoxImage.Question); if (result == MessageBoxResult.Yes) { Directory.CreateDirectory(directory); Process.Start(directory); } } } catch (Exception exc) { this.errorService.ShowError(Resources.MainViewModel_UnableToLaunchDestDir, Resources.MainViewModel_UnableToLaunchDestDirSolution, exc); } } } /// /// Add a Preset /// public void PresetAdd() { IAddPresetViewModel presetViewModel = IoC.Get(); presetViewModel.Setup(this.CurrentTask, this.SelectedTitle, this.AudioViewModel.AudioBehaviours, this.SubtitleViewModel.SubtitleBehaviours); this.windowManager.ShowWindow(presetViewModel); } /// /// Update a selected preset. /// public void PresetUpdate() { if (this.SelectedPreset == null) { this.errorService.ShowMessageBox( Resources.Main_SelectPresetForUpdate, Resources.Main_NoPresetSelected, MessageBoxButton.OK, MessageBoxImage.Warning); return; } if (this.SelectedPreset.IsBuildIn) { this.errorService.ShowMessageBox( Resources.Main_NoUpdateOfBuiltInPresets, Resources.Main_NoPresetSelected, MessageBoxButton.OK, MessageBoxImage.Warning); return; } if (this.errorService.ShowMessageBox(Resources.Main_PresetUpdateConfrimation, Resources.AreYouSure, MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes) { this.SelectedPreset.Update(new EncodeTask(this.CurrentTask), new AudioBehaviours(this.AudioViewModel.AudioBehaviours), new SubtitleBehaviours(this.SubtitleViewModel.SubtitleBehaviours)); this.presetService.Update(this.SelectedPreset); this.errorService.ShowMessageBox( Resources.Main_PresetUpdated, Resources.Updated, MessageBoxButton.OK, MessageBoxImage.Information); } } /// /// Manage the current Preset /// public void PresetManage() { if (this.SelectedPreset == null) { this.errorService.ShowMessageBox( Resources.Main_SelectPresetForUpdate, Resources.Main_NoPresetSelected, MessageBoxButton.OK, MessageBoxImage.Warning); return; } if (this.SelectedPreset.IsBuildIn) { this.errorService.ShowMessageBox( Resources.Main_NoUpdateOfBuiltInPresets, Resources.Main_NoPresetSelected, MessageBoxButton.OK, MessageBoxImage.Warning); return; } IManagePresetViewModel presetViewModel = IoC.Get(); presetViewModel.Setup(this.SelectedPreset); this.windowManager.ShowDialog(presetViewModel); Preset preset = presetViewModel.Preset; this.SelectedPreset = preset; // Reselect the preset } /// /// Remove a Preset /// public void PresetRemove() { if (this.selectedPreset != null) { if (this.selectedPreset.IsDefault) { this.errorService.ShowMessageBox( Resources.MainViewModel_CanNotDeleteDefaultPreset, Resources.Warning, MessageBoxButton.OK, MessageBoxImage.Information); return; } MessageBoxResult result = this.errorService.ShowMessageBox( Resources.MainViewModel_PresetRemove_AreYouSure + this.selectedPreset.Name + " ?", Resources.Question, MessageBoxButton.YesNo, MessageBoxImage.Question); if (result == MessageBoxResult.No) { return; } this.presetService.Remove(this.selectedPreset); } else { MessageBox.Show(Resources.Main_SelectPreset, Resources.Warning, MessageBoxButton.OK, MessageBoxImage.Warning); } } /// /// Set a default preset /// public void PresetSetDefault() { if (this.selectedPreset != null) { this.presetService.SetDefault(this.selectedPreset); this.NotifyOfPropertyChange(() => this.Presets); MessageBox.Show(string.Format(Resources.Main_NewDefaultPreset, this.selectedPreset.Name), Resources.Main_Presets, MessageBoxButton.OK, MessageBoxImage.Information); } else { MessageBox.Show(Resources.Main_SelectPreset, Resources.Warning, MessageBoxButton.OK, MessageBoxImage.Warning); } } /// /// Import a Preset /// public void PresetImport() { OpenFileDialog dialog = new OpenFileDialog { Filter = "Preset Files|*.json;*.plist", CheckFileExists = true }; bool? dialogResult = dialog.ShowDialog(); if (dialogResult.HasValue && dialogResult.Value) { this.presetService.Import(dialog.FileName); this.NotifyOfPropertyChange(() => this.Presets); } } /// /// Export a Preset /// public void PresetExport() { SaveFileDialog savefiledialog = new SaveFileDialog { Filter = "json|*.json", CheckPathExists = true, AddExtension = true, DefaultExt = ".json", OverwritePrompt = true, FilterIndex = 0 }; if (this.selectedPreset != null) { savefiledialog.ShowDialog(); string filename = savefiledialog.FileName; if (!string.IsNullOrEmpty(filename)) { this.presetService.Export(savefiledialog.FileName, this.selectedPreset, HBConfigurationFactory.Create()); } } else { MessageBox.Show(Resources.Main_SelectPreset, Resources.Warning, MessageBoxButton.OK, MessageBoxImage.Warning); } } /// /// Reset built-in presets /// public void PresetReset() { this.presetService.UpdateBuiltInPresets(); this.NotifyOfPropertyChange(() => this.Presets); this.SelectedPreset = this.presetService.DefaultPreset; this.errorService.ShowMessageBox(Resources.Presets_ResetComplete, Resources.Presets_ResetHeader, MessageBoxButton.OK, MessageBoxImage.Information); } /// /// The preset select. /// /// /// The tag. /// public void PresetSelect(object tag) { Preset preset = tag as Preset; if (preset != null) { this.SelectedPreset = preset; } } /// /// Start a Scan /// /// /// The filename. /// /// /// The title. /// public void StartScan(string filename, int title) { if (!string.IsNullOrEmpty(filename)) { ShowSourceSelection = false; this.scanService.Scan(filename, title, null, HBConfigurationFactory.Create()); } } #endregion #region Private Methods /// /// Update all the UI Components to allow the user to edit their previous settings. /// /// /// The successful. /// /// /// The scanned Source. /// private void QueueEditAction(bool successful, Source scannedSource) { /* TODO Fix this. */ Execute.OnUIThread(() => { // Copy all the Scan data into the UI scannedSource.CopyTo(this.ScannedSource); this.NotifyOfPropertyChange(() => this.ScannedSource); this.NotifyOfPropertyChange(() => this.ScannedSource.Titles); // Select the Users Title this.SelectedTitle = this.ScannedSource.Titles.FirstOrDefault(); this.CurrentTask = new EncodeTask(queueEditTask); this.NotifyOfPropertyChange(() => this.CurrentTask); this.HasSource = true; // Update the Main Window this.NotifyOfPropertyChange(() => this.Destination); this.SelectedAngle = this.CurrentTask.Angle; int start = this.CurrentTask.StartPoint; int end = this.CurrentTask.EndPoint; this.SelectedPointToPoint = this.CurrentTask.PointToPointMode; // Force reset. this.SelectedStartPoint = start; this.SelectedEndPoint = end; this.NotifyOfPropertyChange(() => this.SelectedOutputFormat); this.NotifyOfPropertyChange(() => IsMkv); // Update the Tab Controls this.PictureSettingsViewModel.UpdateTask(this.CurrentTask); this.VideoViewModel.UpdateTask(this.CurrentTask); this.FiltersViewModel.UpdateTask(this.CurrentTask); this.AudioViewModel.UpdateTask(this.CurrentTask); this.SubtitleViewModel.UpdateTask(this.CurrentTask); this.ChaptersViewModel.UpdateTask(this.CurrentTask); this.AdvancedViewModel.UpdateTask(this.CurrentTask); this.MetaDataViewModel.UpdateTask(this.CurrentTask); // Cleanup this.ShowStatusWindow = false; this.SourceLabel = this.SourceName; this.StatusLabel = Resources.Main_ScanCompleted; }); } /// /// Make sure the correct file extension is set based on user preferences and setup the GUI for the file container selected. /// /// /// The new extension. /// private void SetExtension(string newExtension) { // Make sure the output extension is set correctly based on the users preferences and selection. if (newExtension == ".mp4" || newExtension == ".m4v") { switch (this.userSettingService.GetUserSetting(UserSettingConstants.UseM4v)) { case 0: // Auto newExtension = MP4Helper.RequiresM4v(this.CurrentTask) ? ".m4v" : ".mp4"; break; case 1: // MP4 newExtension = ".mp4"; break; case 2: // M4v newExtension = ".m4v"; break; } this.IsMkv = false; } // Now disable controls that are not required. The Following are for MP4 only! if (newExtension == ".mkv") { this.IsMkv = true; this.CurrentTask.OptimizeMP4 = false; this.CurrentTask.IPod5GSupport = false; this.NotifyOfPropertyChange(() => this.OptimizeMP4); this.NotifyOfPropertyChange(() => this.IPod5GSupport); } // Update The browse file extension display if (Path.HasExtension(newExtension)) { this.Destination = Path.ChangeExtension(this.Destination, newExtension); } // Update the UI Display this.NotifyOfPropertyChange(() => this.CurrentTask); } /// /// Setup the UI tabs. Passes in any relevant models for setup. /// private void SetupTabs() { // Setup the Tabs if (this.selectedTitle != null) { this.PictureSettingsViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.SelectedPreset, this.CurrentTask); this.VideoViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.SelectedPreset, this.CurrentTask); this.FiltersViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.SelectedPreset, this.CurrentTask); this.AudioViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.SelectedPreset, this.CurrentTask); this.SubtitleViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.SelectedPreset, this.CurrentTask); this.ChaptersViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.SelectedPreset, this.CurrentTask); this.AdvancedViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.SelectedPreset, this.CurrentTask); this.MetaDataViewModel.SetSource(this.ScannedSource, this.SelectedTitle, this.SelectedPreset, this.CurrentTask); } } /// /// Calculate the duration between the end and start point /// /// /// The duration calculation. /// private string DurationCalculation() { if (this.selectedTitle == null) { return "--:--:--"; } double startEndDuration = this.SelectedEndPoint - this.SelectedStartPoint; TimeSpan output; switch (this.SelectedPointToPoint) { case PointToPointMode.Chapters: output = this.SelectedTitle.CalculateDuration(this.SelectedStartPoint, this.SelectedEndPoint); return string.Format("{0:00}:{1:00}:{2:00}", output.Hours, output.Minutes, output.Seconds); case PointToPointMode.Seconds: output = TimeSpan.FromSeconds(startEndDuration); return string.Format("{0:00}:{1:00}:{2:00}", output.Hours, output.Minutes, output.Seconds); case PointToPointMode.Frames: startEndDuration = startEndDuration / selectedTitle.Fps; output = TimeSpan.FromSeconds(Math.Round(startEndDuration, 2)); return string.Format("{0:00}:{1:00}:{2:00}", output.Hours, output.Minutes, output.Seconds); } return "--:--:--"; } /// /// Handle Update Check Results /// /// /// The information. /// private void HandleUpdateCheckResults(UpdateCheckInformation information) { if (information.NewVersionAvailable) { this.ProgramStatusLabel = Resources.Main_NewUpdate; } } /// /// The open alert window. /// /// /// The header. /// /// /// The message. /// private void OpenAlertWindow(string header, string message) { this.ShowAlertWindow = true; this.AlertWindowHeader = header; this.AlertWindowText = message; } #endregion #region Event Handlers /// /// Handle the Scan Status Changed Event. /// /// /// The Sender /// /// /// The EventArgs /// private void ScanStatusChanged(object sender, ScanProgressEventArgs e) { this.SourceLabel = string.Format(Resources.Main_ScanningTitleXOfY, e.CurrentTitle, e.Titles, e.Percentage); this.StatusLabel = string.Format(Resources.Main_ScanningTitleXOfY, e.CurrentTitle, e.Titles, e.Percentage); } /// /// Handle the Scan Completed Event /// /// /// The Sender /// /// /// The EventArgs /// private void ScanCompleted(object sender, ScanCompletedEventArgs e) { if (e.ScannedSource != null) { e.ScannedSource.CopyTo(this.ScannedSource); } else { this.ScannedSource = null; } Execute.OnUIThread(() => { if (e.Successful) { this.NotifyOfPropertyChange(() => this.ScannedSource); this.NotifyOfPropertyChange(() => this.ScannedSource.Titles); this.HasSource = true; this.SelectedTitle = this.ScannedSource.Titles.FirstOrDefault(t => t.MainTitle) ?? this.ScannedSource.Titles.FirstOrDefault(); } else if (!e.Cancelled) { this.OpenAlertWindow(Resources.Main_ScanNoTitlesFound, Resources.Main_ScanNoTitlesFoundMessage); } this.ShowStatusWindow = false; if (e.Successful) { this.SourceLabel = this.SourceName; this.StatusLabel = Resources.Main_ScanCompleted; } else if (e.Cancelled) { this.SourceLabel = Resources.Main_ScanCancelled; this.StatusLabel = Resources.Main_ScanCancelled; } else { this.SourceLabel = Resources.Main_ScanFailled_CheckLog; this.StatusLabel = Resources.Main_ScanFailled_CheckLog; } }); } /// /// Handle the Scan Started Event /// /// /// The Sender /// /// /// The EventArgs /// private void ScanStared(object sender, EventArgs e) { Execute.OnUIThread( () => { this.StatusLabel = Resources.Main_ScanningPleaseWait; this.ShowStatusWindow = true; }); } /// /// The Encode Status has changed Handler /// /// /// The Sender /// /// /// The Encode Progress Event Args /// private void EncodeStatusChanged(object sender, EncodeProgressEventArgs e) { int percent; int.TryParse( Math.Round(e.PercentComplete).ToString(CultureInfo.InvariantCulture), out percent); Execute.OnUIThread( () => { if (this.queueProcessor.EncodeService.IsEncoding) { string jobsPending = string.Format(Resources.Main_JobsPending_addon, this.queueProcessor.Count); if (e.PassId == -1) { this.ProgramStatusLabel = string.Format(Resources.MainViewModel_EncodeStatusChanged_SubScan_StatusLabel, e.Task, e.TaskCount, e.PercentComplete, e.EstimatedTimeLeft, e.ElapsedTime, jobsPending); } else { this.ProgramStatusLabel = string.Format(Resources.MainViewModel_EncodeStatusChanged_StatusLabel, e.Task, e.TaskCount, e.PercentComplete, e.CurrentFrameRate, e.AverageFrameRate, e.EstimatedTimeLeft, e.ElapsedTime, jobsPending); } if (lastEncodePercentage != percent && this.windowsSeven.IsWindowsSeven) { this.windowsSeven.SetTaskBarProgress(percent); } lastEncodePercentage = percent; this.ProgressPercentage = percent; this.NotifyOfPropertyChange(() => ProgressPercentage); } else { this.ProgramStatusLabel = Resources.Main_QueueFinished; this.IsEncoding = false; if (this.windowsSeven.IsWindowsSeven) { this.windowsSeven.SetTaskBarProgressToNoProgress(); } } }); } /// /// Handle the Queue Starting Event /// /// /// The sender. /// /// /// The e. /// private void QueueProcessorJobProcessingStarted(object sender, QueueProgressEventArgs e) { Execute.OnUIThread( () => { this.ProgramStatusLabel = Resources.Main_PreparingToEncode; this.IsEncoding = true; }); } /// /// The Queue has completed handler /// /// /// The Sender /// /// /// The EventArgs /// private void QueueCompleted(object sender, EventArgs e) { this.IsEncoding = false; Execute.OnUIThread( () => { string errorDesc = string.Empty; if (this.queueProcessor.ErrorCount > 0) { errorDesc += string.Format(Resources.Main_QueueFinishedErrors, this.queueProcessor.ErrorCount); } this.ProgramStatusLabel = Resources.Main_QueueFinished + errorDesc; this.IsEncoding = false; if (this.windowsSeven.IsWindowsSeven) { this.windowsSeven.SetTaskBarProgressToNoProgress(); } }); } /// /// The queue changed. /// /// /// The sender. /// /// /// The EventArgs. /// private void QueueChanged(object sender, EventArgs e) { Execute.OnUIThread( () => { this.ProgramStatusLabel = string.Format(Resources.Main_XEncodesPending, this.queueProcessor.Count); this.NotifyOfPropertyChange(() => this.QueueLabel); this.NotifyOfPropertyChange(() => this.StartLabel); }); } /// /// The process drive. /// /// /// The item. /// public void ProcessDrive(object item) { if (item != null) { if (item.GetType() == typeof(DriveInformation)) { this.StartScan(((DriveInformation)item).RootDirectory, 0); } else if (item.GetType() == typeof(SourceMenuItem)) { DriveInformation driveInfo = ((SourceMenuItem)item).Tag as DriveInformation; if (driveInfo != null) { this.StartScan(driveInfo.RootDirectory, this.TitleSpecificScan); } this.ShowSourceSelection = false; } } } /// /// Allows the main window to respond to setting changes. /// /// /// The sender. /// /// /// The e. /// private void UserSettingServiceSettingChanged(object sender, SettingChangedEventArgs e) { switch (e.Key) { case UserSettingConstants.ShowAdvancedTab: this.NotifyOfPropertyChange(() => this.ShowAdvancedTab); break; case UserSettingConstants.WhenCompleteAction: this.QueueViewModel.WhenDone(this.userSettingService.GetUserSetting(UserSettingConstants.WhenCompleteAction), false); break; } } /// /// Handle the property changed event of the encode task. /// Allows the main window to respond to changes. /// /// /// The sender. /// /// /// The e. /// private void CurrentTask_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == UserSettingConstants.ShowAdvancedTab) { this.NotifyOfPropertyChange(() => this.ShowAdvancedTab); } } #endregion } }