// --------------------------------------------------------------------------------------------------------------------
//
// 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.Interop.Interop;
using HandBrake.Interop.Utilities;
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.Options;
using HandBrakeWPF.Model.Subtitles;
using HandBrakeWPF.Properties;
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 Newtonsoft.Json;
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 OpenFileDialog = Microsoft.Win32.OpenFileDialog;
using SaveFileDialog = Microsoft.Win32.SaveFileDialog;
public class MainViewModel : ViewModelBase, IMainViewModel
{
private readonly IQueueService queueProcessor;
private readonly IPresetService presetService;
private readonly IErrorService errorService;
private readonly IUpdateService updateService;
private readonly IWindowManager windowManager;
private readonly INotifyIconService notifyIconService;
private readonly IUserSettingService userSettingService;
private readonly IScan scanService;
private readonly Win7 windowsSeven = new Win7();
private string windowName;
private string sourceLabel;
private string statusLabel;
private string programStatusLabel;
private Source scannedSource;
private Title selectedTitle;
private string duration;
private bool showStatusWindow;
private Preset selectedPreset;
private QueueTask queueEditTask;
private int lastEncodePercentage;
private bool showSourceSelection;
private BindingList drives;
private bool showAlertWindow;
private string alertWindowHeader;
private string alertWindowText;
private bool hasSource;
private bool isSettingPreset;
private bool isModifiedPreset;
private bool updateAvailable;
public MainViewModel(
IUserSettingService userSettingService,
IScan scanService,
IPresetService presetService,
IErrorService errorService,
IUpdateService updateService,
IPrePostActionService whenDoneService,
IWindowManager windowManager,
IPictureSettingsViewModel pictureSettingsViewModel,
IVideoViewModel videoViewModel,
ISummaryViewModel summaryViewModel,
IFiltersViewModel filtersViewModel,
IAudioViewModel audioViewModel,
ISubtitlesViewModel subtitlesViewModel,
IChaptersViewModel chaptersViewModel,
IStaticPreviewViewModel staticPreviewViewModel,
IQueueViewModel queueViewModel,
IMetaDataViewModel metaDataViewModel,
IPresetManagerViewModel presetManagerViewModel,
INotifyIconService notifyIconService,
ISystemService systemService)
: base(userSettingService)
{
this.scanService = scanService;
this.presetService = presetService;
this.errorService = errorService;
this.updateService = updateService;
this.windowManager = windowManager;
this.notifyIconService = notifyIconService;
this.QueueViewModel = queueViewModel;
this.userSettingService = userSettingService;
this.queueProcessor = IoC.Get();
this.SummaryViewModel = summaryViewModel;
this.PictureSettingsViewModel = pictureSettingsViewModel;
this.VideoViewModel = videoViewModel;
this.MetaDataViewModel = metaDataViewModel;
this.FiltersViewModel = filtersViewModel;
this.AudioViewModel = audioViewModel;
this.SubtitleViewModel = subtitlesViewModel;
this.ChaptersViewModel = chaptersViewModel;
this.StaticPreviewViewModel = staticPreviewViewModel;
this.PresetManagerViewModel = presetManagerViewModel;
// Setup Properties
this.WindowTitle = Resources.HandBrake_Title;
this.CurrentTask = new EncodeTask();
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.QueuePaused += this.QueueProcessor_QueuePaused;
this.queueProcessor.QueueJobStatusChanged += this.QueueProcessor_QueueJobStatusChanged;
this.userSettingService.SettingChanged += this.UserSettingServiceSettingChanged;
this.PresetsCategories = new BindingList();
this.Drives = new BindingList();
// Set Process Priority
switch ((ProcessPriority)this.userSettingService.GetUserSetting(UserSettingConstants.ProcessPriorityInt))
{
case ProcessPriority.High:
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
break;
case ProcessPriority.AboveNormal:
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.AboveNormal;
break;
case ProcessPriority.Normal:
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.Normal;
break;
case ProcessPriority.Low:
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.Idle;
break;
default:
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.BelowNormal;
break;
}
// Setup Commands
this.QueueCommand = new QueueCommands(this.QueueViewModel);
// Monitor the system.
systemService.Start();
}
/* View Model Properties */
public IPictureSettingsViewModel PictureSettingsViewModel { get; set; }
public IAudioViewModel AudioViewModel { get; set; }
public ISubtitlesViewModel SubtitleViewModel { get; set; }
public IChaptersViewModel ChaptersViewModel { get; set; }
public IVideoViewModel VideoViewModel { get; set; }
public IFiltersViewModel FiltersViewModel { get; set; }
public IQueueViewModel QueueViewModel { get; set; }
public IStaticPreviewViewModel StaticPreviewViewModel { get; set; }
public IMetaDataViewModel MetaDataViewModel { get; set; }
public ISummaryViewModel SummaryViewModel { get; set; }
public IPresetManagerViewModel PresetManagerViewModel { get; set; }
public int SelectedTab { get; set; }
/* Properties */
public string WindowTitle
{
get => this.windowName;
set
{
if (!Equals(this.windowName, value))
{
this.windowName = value;
this.NotifyOfPropertyChange(() => this.WindowTitle);
}
}
}
public string ProgramStatusLabel
{
get => string.IsNullOrEmpty(this.programStatusLabel) ? Resources.State_Ready : this.programStatusLabel;
set
{
if (!Equals(this.programStatusLabel, value))
{
this.programStatusLabel = value;
this.NotifyOfPropertyChange(() => this.ProgramStatusLabel);
}
}
}
public string StatusLabel
{
get => string.IsNullOrEmpty(this.statusLabel) ? Resources.State_Ready : this.statusLabel;
set
{
if (!Equals(this.statusLabel, value))
{
this.statusLabel = value;
this.NotifyOfPropertyChange(() => this.StatusLabel);
}
}
}
public bool QueueRecoveryArchivesExist { get; set; }
public IEnumerable PresetsCategories { get; set; }
public Preset SelectedPreset
{
get => this.selectedPreset;
set
{
if (!object.Equals(this.selectedPreset, value))
{
if (value == null)
{
this.errorService.ShowError("Null Preset", null, Environment.StackTrace.ToString());
}
if (value != null)
{
this.PresetSelect(value);
}
this.selectedPreset = value;
this.NotifyOfPropertyChange(() => this.SelectedPreset);
}
}
}
public bool IsModifiedPreset
{
get => this.isModifiedPreset;
set
{
if (value == this.isModifiedPreset)
{
return;
}
this.isModifiedPreset = value;
this.NotifyOfPropertyChange();
}
}
public EncodeTask CurrentTask { get; set; }
public Source ScannedSource
{
get => this.scannedSource;
set
{
this.scannedSource = value;
this.NotifyOfPropertyChange(() => ScannedSource);
}
}
public int TitleSpecificScan { get; set; }
public string SourceLabel
{
get => string.IsNullOrEmpty(this.sourceLabel) ? Resources.Main_SelectSource : this.sourceLabel;
set
{
if (!Equals(this.sourceLabel, value))
{
this.sourceLabel = value;
this.NotifyOfPropertyChange(() => SourceLabel);
}
}
}
public BindingList RangeMode { get; } = new BindingList { PointToPointMode.Chapters, PointToPointMode.Seconds, PointToPointMode.Frames };
public bool ShowTextEntryForPointToPointMode => this.SelectedPointToPoint != PointToPointMode.Chapters;
public IEnumerable StartEndRangeItems
{
get => this.SelectedTitle?.Chapters.Select(item => item.ChapterNumber).Select(dummy => dummy).ToList();
}
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;
}
}
public string Duration
{
get => string.IsNullOrEmpty(duration) ? "--:--:--" : duration;
set
{
duration = value;
this.NotifyOfPropertyChange(() => Duration);
}
}
public bool IsEncoding => this.queueProcessor.IsEncoding;
public bool ShowStatusWindow
{
get => this.showStatusWindow;
set
{
this.showStatusWindow = value;
this.NotifyOfPropertyChange(() => this.ShowStatusWindow);
}
}
public IEnumerable OutputFormats => new List { OutputFormat.Mp4, OutputFormat.Mkv, OutputFormat.WebM };
public string Destination
{
get => this.CurrentTask.Destination;
set
{
if (!Equals(this.CurrentTask.Destination, value))
{
if (!string.IsNullOrEmpty(value))
{
string ext = string.Empty;
try
{
if (FileHelper.FilePathHasInvalidChars(value))
{
this.errorService.ShowMessageBox(Resources.Main_InvalidDestination, Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
if (value == this.ScannedSource.ScanPath)
{
this.errorService.ShowMessageBox(Resources.Main_MatchingFileOverwriteWarning, Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
ext = Path.GetExtension(value);
}
catch (Exception exc)
{
this.errorService.ShowError(Resources.Main_InvalidDestination, string.Empty, value + Environment.NewLine + exc);
return;
}
this.CurrentTask.Destination = value;
this.NotifyOfPropertyChange(() => this.Destination);
switch (ext)
{
case ".mkv":
this.SummaryViewModel.SetContainer(OutputFormat.Mkv);
break;
case ".mp4":
case ".m4v":
this.SummaryViewModel.SetContainer(OutputFormat.Mp4);
break;
case ".webm":
this.SummaryViewModel.SetContainer(OutputFormat.WebM);
break;
}
}
else
{
this.CurrentTask.Destination = string.Empty;
this.NotifyOfPropertyChange(() => this.Destination);
}
}
}
}
public Title SelectedTitle
{
get => 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.ScannedSource?.SourceName ?? this.SelectedTitle?.DisplaySourceName;
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);
this.NotifyOfPropertyChange(() => this.SourceInfo);
// 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.ScannedSource?.SourceName ?? this.SelectedTitle?.DisplaySourceName, this.selectedPreset);
}
}
this.NotifyOfPropertyChange(() => this.CurrentTask);
this.Duration = this.DurationCalculation();
// Setup the tab controls
this.SetupTabs();
}
}
}
public int SelectedAngle
{
get => this.CurrentTask.Angle;
set
{
this.CurrentTask.Angle = value;
this.NotifyOfPropertyChange(() => this.SelectedAngle);
}
}
public bool IsTimespanRange { get; set; }
public long SelectedStartPoint
{
get => 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.ScannedSource?.SourceName ?? this.SelectedTitle?.DisplaySourceName, this.selectedPreset);
}
}
if (this.SelectedStartPoint > this.SelectedEndPoint)
{
this.SelectedEndPoint = this.SelectedStartPoint;
}
}
}
public long SelectedEndPoint
{
get => 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.ScannedSource?.SourceName ?? this.SelectedTitle?.DisplaySourceName, this.selectedPreset);
}
if (this.SelectedStartPoint > this.SelectedEndPoint && this.SelectedPointToPoint == PointToPointMode.Chapters)
{
this.SelectedStartPoint = this.SelectedEndPoint;
}
}
}
public PointToPointMode SelectedPointToPoint
{
get => 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);
}
}
}
public int ProgressPercentage { get; set; }
public bool ShowSourceSelection
{
get => 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);
}
}
}
public BindingList Drives
{
get => this.drives;
set
{
if (Equals(value, this.drives))
{
return;
}
this.drives = value;
this.NotifyOfPropertyChange(() => this.Drives);
}
}
public Action CancelAction => this.CancelScan;
public Action OpenLogWindowAction => this.OpenLogWindow;
public bool ShowAlertWindow
{
get => this.showAlertWindow;
set
{
if (value.Equals(this.showAlertWindow))
{
return;
}
this.showAlertWindow = value;
this.NotifyOfPropertyChange(() => this.ShowAlertWindow);
}
}
public string AlertWindowHeader
{
get => this.alertWindowHeader;
set
{
if (value == this.alertWindowHeader)
{
return;
}
this.alertWindowHeader = value;
this.NotifyOfPropertyChange(() => this.AlertWindowHeader);
}
}
public string AlertWindowText
{
get => this.alertWindowText;
set
{
if (value == this.alertWindowText)
{
return;
}
this.alertWindowText = value;
this.NotifyOfPropertyChange(() => this.AlertWindowText);
}
}
public Action AlertWindowClose => this.CloseAlertWindow;
public string QueueLabel => string.Format(Resources.Main_QueueLabel, this.queueProcessor.Count > 0 ? string.Format(" ({0})", this.queueProcessor.Count) : string.Empty);
public string StartLabel
{
get
{
if (this.queueProcessor.IsPaused)
{
return Resources.Main_ResumeEncode;
}
return this.queueProcessor.Count > 0 ? Resources.Main_StartQueue : Resources.Main_Start;
}
}
public bool HasSource
{
get => this.hasSource;
set
{
if (value.Equals(this.hasSource))
{
return;
}
this.hasSource = value;
this.NotifyOfPropertyChange(() => this.HasSource);
}
}
public string SourceInfo
{
get
{
if (this.SelectedTitle != null)
{
int parW = this.SelectedTitle.ParVal.Width;
int parH = this.SelectedTitle.ParVal.Height;
int displayW = this.SelectedTitle.Resolution.Width * parW / parH;
return string.Format("{0}x{1} ({2}x{3}), {4} FPS, {5} {6}, {7} {8}",
this.SelectedTitle.Resolution.Width,
this.SelectedTitle.Resolution.Height,
displayW,
this.SelectedTitle.Resolution.Height,
Math.Round(this.SelectedTitle.Fps, 2),
this.SelectedTitle.AudioTracks.Count,
Resources.MainView_AudioTrackCount,
this.SelectedTitle.Subtitles.Count,
Resources.MainView_SubtitleTracksCount);
}
return string.Empty;
}
}
public bool ShowAddAllToQueue => this.userSettingService.GetUserSetting(UserSettingConstants.ShowAddAllToQueue);
public bool ShowAddSelectionToQueue => this.userSettingService.GetUserSetting(UserSettingConstants.ShowAddSelectionToQueue);
public string ShowAddAllMenuName =>
string.Format("{0} {1}", (!this.ShowAddAllToQueue ? Resources.MainView_Show : Resources.MainView_Hide), Resources.MainView_ShowAddAllToQueue);
public string ShowAddSelectionMenuName =>
string.Format("{0} {1}", (!this.ShowAddSelectionToQueue ? Resources.MainView_Show : Resources.MainView_Hide), Resources.MainView_ShowAddSelectionToQueue);
public bool UpdateAvailable
{
get => this.updateAvailable;
set
{
if (value == this.updateAvailable)
{
return;
}
this.updateAvailable = value;
this.NotifyOfPropertyChange(() => this.UpdateAvailable);
}
}
public bool IsMultiProcess { get; set; }
public bool IsNightly => HandBrakeVersionHelper.IsNightly();
/* Commands */
public ICommand QueueCommand { get; set; }
/* Load and Shutdown Handling */
public override void OnLoad()
{
// Perform an update check if required
this.updateService.PerformStartupUpdateCheck(this.HandleUpdateCheckResults);
// Setup the presets.
this.presetService.Load();
this.PresetsCategories = this.presetService.Presets;
this.NotifyOfPropertyChange(() => this.PresetsCategories);
this.presetService.LoadCategoryStates();
this.SummaryViewModel.OutputFormatChanged += this.SummaryViewModel_OutputFormatChanged;
// Queue Recovery
bool queueRecovered = QueueRecoveryHelper.RecoverQueue(this.queueProcessor, this.errorService, StartupOptions.AutoRestartQueue, StartupOptions.QueueRecoveryIds);
this.QueueRecoveryArchivesExist = QueueRecoveryHelper.ArchivesExist();
this.NotifyOfPropertyChange(() => this.QueueRecoveryArchivesExist);
// 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();
}
// Preset Selection
this.SetDefaultPreset();
// Reset WhenDone if necessary.
if (this.userSettingService.GetUserSetting(UserSettingConstants.ResetWhenDoneAction))
{
this.WhenDone(0);
}
// Log Cleaning
if (this.userSettingService.GetUserSetting(UserSettingConstants.ClearOldLogs))
{
Thread clearLog = new Thread(() => GeneralUtilities.ClearLogFiles(7));
clearLog.Start();
}
this.PictureSettingsViewModel.TabStatusChanged += this.TabStatusChanged;
this.VideoViewModel.TabStatusChanged += this.TabStatusChanged;
this.FiltersViewModel.TabStatusChanged += this.TabStatusChanged;
this.AudioViewModel.TabStatusChanged += this.TabStatusChanged;
this.SubtitleViewModel.TabStatusChanged += this.TabStatusChanged;
this.ChaptersViewModel.TabStatusChanged += this.TabStatusChanged;
this.MetaDataViewModel.TabStatusChanged += this.TabStatusChanged;
this.SummaryViewModel.TabStatusChanged += this.TabStatusChanged;
}
public void Shutdown()
{
// Shutdown Service
this.queueProcessor.Stop(true);
this.presetService.SaveCategoryStates();
// Unsubscribe from Events.
this.scanService.ScanStarted -= this.ScanStared;
this.scanService.ScanCompleted -= this.ScanCompleted;
this.scanService.ScanStatusChanged -= this.ScanStatusChanged;
this.queueProcessor.QueuePaused -= this.QueueProcessor_QueuePaused;
this.queueProcessor.QueueCompleted -= this.QueueCompleted;
this.queueProcessor.QueueChanged -= this.QueueChanged;
this.queueProcessor.JobProcessingStarted -= this.QueueProcessorJobProcessingStarted;
this.userSettingService.SettingChanged -= this.UserSettingServiceSettingChanged;
this.SummaryViewModel.OutputFormatChanged -= this.SummaryViewModel_OutputFormatChanged;
// Tab status events
this.PictureSettingsViewModel.TabStatusChanged -= this.TabStatusChanged;
this.VideoViewModel.TabStatusChanged -= this.TabStatusChanged;
this.FiltersViewModel.TabStatusChanged -= this.TabStatusChanged;
this.AudioViewModel.TabStatusChanged -= this.TabStatusChanged;
this.SubtitleViewModel.TabStatusChanged -= this.TabStatusChanged;
this.ChaptersViewModel.TabStatusChanged -= this.TabStatusChanged;
this.MetaDataViewModel.TabStatusChanged -= this.TabStatusChanged;
this.SummaryViewModel.TabStatusChanged -= this.TabStatusChanged;
}
/* Menu and Toolbar */
public void OpenAboutApplication()
{
OpenOptionsScreenCommand command = new OpenOptionsScreenCommand();
command.Execute(OptionsTab.About);
}
public void OpenOptionsWindow()
{
OpenOptionsScreenCommand command = new OpenOptionsScreenCommand();
command.Execute(null);
}
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);
}
}
public void OpenQueueWindow()
{
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());
}
}
public void OpenPreviewWindow()
{
if (!string.IsNullOrEmpty(this.CurrentTask.Source) && !this.StaticPreviewViewModel.IsOpen)
{
this.StaticPreviewViewModel.IsOpen = true;
this.StaticPreviewViewModel.UpdatePreviewFrame(this.CurrentTask, this.ScannedSource);
this.windowManager.ShowWindow(this.StaticPreviewViewModel);
}
else if (this.StaticPreviewViewModel.IsOpen)
{
Window window = Application.Current.Windows.Cast().FirstOrDefault(x => x.GetType() == typeof(StaticPreviewView));
window?.Focus();
}
}
public void OpenPresetWindow()
{
if (!this.PresetManagerViewModel.IsOpen)
{
this.PresetManagerViewModel.IsOpen = true;
this.PresetManagerViewModel.SetupWindow(() => this.NotifyOfPropertyChange(() => this.PresetsCategories));
this.windowManager.ShowWindow(this.PresetManagerViewModel);
}
else if (this.PresetManagerViewModel.IsOpen)
{
Window window = Application.Current.Windows.Cast().FirstOrDefault(x => x.GetType() == typeof(PresetManagerView));
window?.Focus();
}
}
public void LaunchHelp()
{
try
{
Process.Start("explorer.exe", "https://handbrake.fr/docs");
}
catch (Exception exc)
{
this.errorService.ShowError(Resources.Main_UnableToLoadHelpMessage, Resources.Main_UnableToLoadHelpSolution, exc);
}
}
public void CheckForUpdates()
{
OpenOptionsScreenCommand command = new OpenOptionsScreenCommand();
command.Execute(OptionsTab.Updates);
}
public AddQueueError AddToQueue(bool batch)
{
if (this.ScannedSource == null || string.IsNullOrEmpty(this.ScannedSource.ScanPath) || this.ScannedSource.Titles.Count == 0)
{
return new AddQueueError(Resources.Main_ScanSource, Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error);
}
if (string.IsNullOrEmpty(this.CurrentTask.Destination))
{
return new AddQueueError(Resources.Main_SetDestination, Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error);
}
if (this.Destination.ToLower() == this.ScannedSource.ScanPath.ToLower())
{
return new AddQueueError(Resources.Main_MatchingFileOverwriteWarning, Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error);
}
if (File.Exists(this.CurrentTask.Destination))
{
FileOverwriteBehaviour behaviour = (FileOverwriteBehaviour)this.userSettingService.GetUserSetting(UserSettingConstants.FileOverwriteBehaviour);
if (behaviour == FileOverwriteBehaviour.Ask)
{
MessageBoxResult result = this.errorService.ShowMessageBox(string.Format(Resources.Main_QueueOverwritePrompt, Path.GetFileName(this.CurrentTask.Destination)), Resources.Question, MessageBoxButton.YesNo, MessageBoxImage.Warning);
if (result == MessageBoxResult.No)
{
return null; // Handled by the above action.
}
}
}
if (!DirectoryUtilities.IsWritable(Path.GetDirectoryName(this.CurrentTask.Destination), false, this.errorService))
{
return new AddQueueError(Resources.Main_NoPermissionsOrMissingDirectory, Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error);
}
if (!batch && !DriveUtilities.HasMinimumDiskSpace(
this.Destination,
this.userSettingService.GetUserSetting(UserSettingConstants.PauseQueueOnLowDiskspaceLevel)))
{
MessageBoxResult result = this.errorService.ShowMessageBox(Resources.Main_LowDiskspace, Resources.Warning, MessageBoxButton.YesNo, MessageBoxImage.Question);
if (result == MessageBoxResult.No)
{
return null; // Handled by the above action.
}
}
// Sanity check the filename
if (FileHelper.FilePathHasInvalidChars(this.Destination))
{
this.NotifyOfPropertyChange(() => this.Destination);
return new AddQueueError(Resources.Main_InvalidDestination, Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error);
}
// defer to subtitle's validation messages
if (!this.SubtitleViewModel.ValidateSubtitles())
{
return new AddQueueError(Resources.Subtitles_WebmSubtitleIncompatibilityHeader, Resources.Main_PleaseFixSubtitleSettings, MessageBoxButton.OK, MessageBoxImage.Error);
}
QueueTask task = new QueueTask(new EncodeTask(this.CurrentTask), HBConfigurationFactory.Create(), this.ScannedSource.ScanPath, this.SelectedPreset, this.IsModifiedPreset);
if (!this.queueProcessor.CheckForDestinationPathDuplicates(task.Task.Destination))
{
this.queueProcessor.Add(task);
}
else
{
return new AddQueueError(Resources.Main_DuplicateDestinationOnQueue, Resources.Error, MessageBoxButton.OK, MessageBoxImage.Warning);
}
if (!this.IsEncoding)
{
this.ProgramStatusLabel = string.Format(Resources.Main_XEncodesPending, this.queueProcessor.Count);
}
return null;
}
public void AddToQueueWithErrorHandling()
{
var addError = this.AddToQueue(false);
if (addError != null)
{
this.errorService.ShowMessageBox(addError.Message, addError.Header, addError.Buttons, addError.ErrorType);
}
}
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 (!DriveUtilities.HasMinimumDiskSpace(this.Destination, this.userSettingService.GetUserSetting(UserSettingConstants.PauseQueueOnLowDiskspaceLevel)))
{
MessageBoxResult result = this.errorService.ShowMessageBox(Resources.Main_LowDiskspace, Resources.Warning, MessageBoxButton.YesNo, MessageBoxImage.Question);
if (result == MessageBoxResult.No)
{
return; // Handled by the above action.
}
}
foreach (Title title in this.ScannedSource.Titles)
{
this.SelectedTitle = title;
var addError = this.AddToQueue(true);
if (addError != null)
{
MessageBoxResult result = this.errorService.ShowMessageBox(addError.Message + Environment.NewLine + Environment.NewLine + Resources.Main_ContinueAddingToQueue, addError.Header, MessageBoxButton.YesNo, addError.ErrorType);
if (result == MessageBoxResult.No)
{
break;
}
}
}
}
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;
}
if (!DriveUtilities.HasMinimumDiskSpace(this.Destination, this.userSettingService.GetUserSetting(UserSettingConstants.PauseQueueOnLowDiskspaceLevel)))
{
MessageBoxResult result = this.errorService.ShowMessageBox(Resources.Main_LowDiskspace, Resources.Warning, MessageBoxButton.YesNo, MessageBoxImage.Question);
if (result == MessageBoxResult.No)
{
return; // Handled by the above action.
}
}
// Always use the current settings when adding to the queue as best as possible.
Preset temporaryPreset = this.selectedPreset;
if (this.IsModifiedPreset)
{
temporaryPreset = new Preset(this.SelectedPreset);
temporaryPreset.Name = string.Format(
"{0} {1}",
temporaryPreset.Name,
Resources.MainView_ModifiedPreset);
temporaryPreset.Task = new EncodeTask(this.CurrentTask);
temporaryPreset.AudioTrackBehaviours = this.AudioViewModel.AudioBehaviours.Clone();
temporaryPreset.SubtitleTrackBehaviours = this.SubtitleViewModel.SubtitleBehaviours.Clone();
}
Window window = Application.Current.Windows.Cast().FirstOrDefault(x => x.GetType() == typeof(QueueSelectionViewModel));
IQueueSelectionViewModel viewModel = IoC.Get();
viewModel.Setup(
this.ScannedSource,
(tasks) =>
{
foreach (SelectionTitle title in tasks)
{
this.SelectedTitle = title.Title;
var addError = this.AddToQueue(true);
if (addError != null)
{
MessageBoxResult result = this.errorService.ShowMessageBox(addError.Message + Environment.NewLine + Environment.NewLine + Resources.Main_ContinueAddingToQueue, addError.Header, MessageBoxButton.YesNo, addError.ErrorType);
if (result == MessageBoxResult.No)
{
break;
}
}
}
},
temporaryPreset);
if (window != null)
{
window.Activate();
}
else
{
this.windowManager.ShowWindow(viewModel);
}
}
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);
}
}
public void FileScan()
{
OpenFileDialog dialog = new OpenFileDialog { Filter = "All files (*.*)|*.*" };
string mruDir = this.GetMru(Constants.FileScanMru);
if (!string.IsNullOrEmpty(mruDir) && Directory.Exists(mruDir))
{
dialog.InitialDirectory = mruDir;
}
bool? dialogResult = dialog.ShowDialog();
if (dialogResult.HasValue && dialogResult.Value)
{
this.SetMru(Constants.FileScanMru, Path.GetDirectoryName(dialog.FileName));
this.StartScan(dialog.FileName, this.TitleSpecificScan);
}
}
public void CancelScan()
{
this.ShowStatusWindow = false;
this.scanService.Cancel();
}
public void StartEncode()
{
if (this.queueProcessor.IsProcessing)
{
this.NotifyOfPropertyChange(() => this.IsEncoding);
return;
}
// Check if we already have jobs, and if we do, just start the queue.
if (this.queueProcessor.Count != 0 || this.queueProcessor.IsPaused)
{
this.NotifyOfPropertyChange(() => this.IsEncoding);
this.queueProcessor.Start();
return;
}
// Otherwise, perform Sanity 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;
}
// Create the Queue Task and Start Processing
var addError = this.AddToQueue(false);
if (addError == null)
{
this.NotifyOfPropertyChange(() => this.IsEncoding);
this.queueProcessor.Start();
}
else
{
this.errorService.ShowMessageBox(
addError.Message,
addError.Header,
addError.Buttons,
addError.ErrorType);
}
}
public void EditQueueJob(QueueTask queueTask)
{
// Rescan the source to make sure it's still valid
EncodeTask task = queueTask.Task;
this.queueEditTask = queueTask;
this.scanService.Scan(task.Source, task.Title, QueueEditAction);
}
public void PauseEncode()
{
this.queueProcessor.Pause(true);
this.NotifyOfPropertyChange(() => this.IsEncoding);
}
public void StopEncode()
{
MessageBoxResult result = this.errorService.ShowMessageBox(
Resources.MainView_StopEncodeConfirm,
Resources.MainView_StopEncode,
MessageBoxButton.YesNo,
MessageBoxImage.Question);
if (result == MessageBoxResult.Yes)
{
this.queueProcessor.Stop(true);
}
}
public void ExitApplication()
{
Application.Current.Shutdown();
}
public void SelectSourceWindow()
{
ShowSourceSelection = !ShowSourceSelection;
}
public void CloseSourceSelection()
{
this.ShowSourceSelection = false;
}
public void CloseAlertWindow()
{
this.ShowAlertWindow = false;
this.AlertWindowText = string.Empty;
this.AlertWindowHeader = string.Empty;
}
public void WhenDone(int action)
{
this.QueueViewModel?.WhenDone(action, true);
}
public void ExportSourceData()
{
if (this.ScannedSource == null)
{
return;
}
string json = JsonConvert.SerializeObject(this.ScannedSource, Formatting.Indented);
SaveFileDialog savefiledialog = new SaveFileDialog
{
Filter = "json|*.json",
CheckPathExists = true,
AddExtension = true,
DefaultExt = ".json",
OverwritePrompt = true,
FilterIndex = 0,
FileName = "debug.scan_output.json"
};
savefiledialog.ShowDialog();
if (!string.IsNullOrEmpty(savefiledialog.FileName))
{
using (StreamWriter writer = new StreamWriter(savefiledialog.FileName))
{
writer.Write(json);
}
}
}
public void ImportSourceData()
{
OpenFileDialog dialog = new OpenFileDialog { Filter = "Debug Files|*.json", CheckFileExists = true };
bool? dialogResult = dialog.ShowDialog();
if (dialogResult.HasValue && dialogResult.Value)
{
using (StreamReader reader = new StreamReader(dialog.FileName))
{
string json = reader.ReadToEnd();
if (!string.IsNullOrEmpty(json))
{
Source source = JsonConvert.DeserializeObject