// -------------------------------------------------------------------------------------------------------------------- // // This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. // // // The Preview View Model // // -------------------------------------------------------------------------------------------------------------------- namespace HandBrakeWPF.ViewModels { using System; using System.ComponentModel; using System.Windows; using Caliburn.Micro; using HandBrake.ApplicationServices.Model; using HandBrake.ApplicationServices.Services.Encode.EventArgs; using HandBrake.ApplicationServices.Services.Encode.Model; using HandBrakeWPF.EventArgs; using HandBrakeWPF.Properties; using HandBrakeWPF.Services.Interfaces; using HandBrakeWPF.ViewModels.Interfaces; using Microsoft.Win32; /// /// The Preview View Model /// public class QueueViewModel : ViewModelBase, IQueueViewModel { #region Constants and Fields /// /// The Error Service Backing field /// private readonly IErrorService errorService; /// /// The User Setting Service Backing Field. /// private readonly IUserSettingService userSettingService; /// /// Queue Processor Backing field /// private readonly IQueueProcessor queueProcessor; /// /// IsEncoding Backing field /// private bool isEncoding; /// /// Job Status Backing field. /// private string jobStatus; /// /// Jobs pending backing field /// private string jobsPending; /// /// Backing field for the when done action description /// private string whenDoneAction; #endregion #region Constructors and Destructors /// /// Initializes a new instance of the class. /// /// /// The user Setting Service. /// /// /// The Queue Processor Service /// /// /// The Error Service /// public QueueViewModel(IUserSettingService userSettingService, IQueueProcessor queueProcessor, IErrorService errorService) { this.userSettingService = userSettingService; this.queueProcessor = queueProcessor; this.errorService = errorService; this.Title = "Queue"; this.JobsPending = "No encodes pending"; this.JobStatus = "There are no jobs currently encoding"; } #endregion #region Properties /// /// Gets or sets a value indicating whether IsEncoding. /// public bool IsEncoding { get { return this.isEncoding; } set { this.isEncoding = value; this.NotifyOfPropertyChange(() => IsEncoding); } } /// /// Gets or sets JobStatus. /// public string JobStatus { get { return this.jobStatus; } set { this.jobStatus = value; this.NotifyOfPropertyChange(() => this.JobStatus); } } /// /// Gets or sets JobsPending. /// public string JobsPending { get { return this.jobsPending; } set { this.jobsPending = value; this.NotifyOfPropertyChange(() => this.JobsPending); } } /// /// Gets or sets WhenDoneAction. /// public string WhenDoneAction { get { return this.whenDoneAction; } set { this.whenDoneAction = value; this.NotifyOfPropertyChange(() => this.WhenDoneAction); } } /// /// Gets the queue tasks. /// public BindingList QueueTasks { get { return this.queueProcessor.Queue; } } #endregion #region Public Methods /// /// Update the When Done Setting /// /// /// The action. /// public void WhenDone(string action) { this.WhenDoneAction = action; this.userSettingService.SetUserSetting(UserSettingConstants.WhenCompleteAction, action); } /// /// Clear the Queue /// public void Clear() { MessageBoxResult result = this.errorService.ShowMessageBox( "Are you sure you wish to clear the queue?", "Confirm", MessageBoxButton.YesNo, MessageBoxImage.Warning); if (result == MessageBoxResult.Yes) { this.queueProcessor.Clear(); } } /// /// Clear Completed Items /// public void ClearCompleted() { this.queueProcessor.ClearCompleted(); } /// /// Close this window. /// public void Close() { this.TryClose(); } /// /// Handle the On Window Load /// public override void OnLoad() { // Setup the window to the correct state. this.IsEncoding = this.queueProcessor.EncodeService.IsEncoding; this.JobsPending = string.Format("{0} jobs pending", this.queueProcessor.Count); base.OnLoad(); } /// /// Pause Encode /// public void PauseEncode() { this.queueProcessor.Pause(); this.JobStatus = "Queue Paused"; this.JobsPending = string.Format("{0} jobs pending", this.queueProcessor.Count); this.IsEncoding = false; MessageBox.Show("The Queue has been paused. The currently running job will run to completion and no further jobs will start.", "Queue", MessageBoxButton.OK, MessageBoxImage.Information); } /// /// Remove a Job from the queue /// /// /// The Job to remove from the queue /// public void RemoveJob(QueueTask task) { if (task.Status == QueueItemStatus.InProgress) { MessageBoxResult result = this.errorService.ShowMessageBox( "This encode is currently in progress. If you delete it, the encode will be stopped. Are you sure you wish to proceed?", Resources.Warning, MessageBoxButton.YesNo, MessageBoxImage.Question); if (result == MessageBoxResult.Yes) { this.queueProcessor.EncodeService.Stop(); this.queueProcessor.Remove(task); } } else { this.queueProcessor.Remove(task); } } /// /// Reset the job state to waiting. /// /// /// The task. /// public void RetryJob(QueueTask task) { task.Status = QueueItemStatus.Waiting; this.queueProcessor.BackupQueue(null); this.JobsPending = string.Format("{0} jobs pending", this.queueProcessor.Count); } /// /// Start Encode /// public void StartEncode() { if (this.queueProcessor.Count == 0) { this.errorService.ShowMessageBox( "There are no pending jobs.", Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error); return; } this.JobStatus = "Queue Started"; this.JobsPending = string.Format("{0} jobs pending", this.queueProcessor.Count); this.IsEncoding = true; this.queueProcessor.Start(UserSettingService.GetUserSetting(UserSettingConstants.ClearCompletedFromQueue)); } /// /// Export the Queue to a file. /// public void Export() { SaveFileDialog dialog = new SaveFileDialog { Filter = "HandBrake Queue Files (*.hbq)|*.hbq", OverwritePrompt = true, DefaultExt = ".hbq", AddExtension = true }; if (dialog.ShowDialog() == true) { this.queueProcessor.BackupQueue(dialog.FileName); } } /// /// Import a saved queue /// public void Import() { OpenFileDialog dialog = new OpenFileDialog { Filter = "HandBrake Queue Files (*.hbq)|*.hbq", CheckFileExists = true }; if (dialog.ShowDialog() == true) { this.queueProcessor.RestoreQueue(dialog.FileName); } } /// /// Edit this Job /// /// /// The task. /// public void EditJob(QueueTask task) { MessageBoxResult result = this.errorService.ShowMessageBox( "Are you sure you wish to edit this job? It will be removed from the queue and sent to the main window.", "Modify Job?", MessageBoxButton.YesNo, MessageBoxImage.Question); if (result != MessageBoxResult.Yes) { return; } // Remove the job if it is not already encoding. Let the user decide if they want to cancel or not. this.RemoveJob(task); // Pass a copy of the job back to the Main Screen IMainViewModel mvm = IoC.Get(); mvm.EditQueueJob(new EncodeTask(task.Task)); } #endregion #region Methods /// /// Override the OnActive to run the Screen Loading code in the view model base. /// protected override void OnActivate() { this.Load(); this.WhenDoneAction = this.userSettingService.GetUserSetting(UserSettingConstants.WhenCompleteAction); this.queueProcessor.QueueCompleted += this.queueProcessor_QueueCompleted; this.queueProcessor.QueueChanged += this.QueueManager_QueueChanged; this.queueProcessor.EncodeService.EncodeStatusChanged += this.EncodeService_EncodeStatusChanged; this.queueProcessor.EncodeService.EncodeCompleted += EncodeService_EncodeCompleted; this.queueProcessor.JobProcessingStarted += this.QueueProcessorJobProcessingStarted; this.JobsPending = string.Format("{0} jobs pending", this.queueProcessor.Count); this.JobStatus = "Queue Ready"; base.OnActivate(); } /// /// Override the Deactivate /// /// /// The close. /// protected override void OnDeactivate(bool close) { this.queueProcessor.QueueCompleted -= this.queueProcessor_QueueCompleted; this.queueProcessor.QueueChanged -= this.QueueManager_QueueChanged; this.queueProcessor.EncodeService.EncodeStatusChanged -= this.EncodeService_EncodeStatusChanged; this.queueProcessor.EncodeService.EncodeCompleted -= EncodeService_EncodeCompleted; this.queueProcessor.JobProcessingStarted -= this.QueueProcessorJobProcessingStarted; base.OnDeactivate(close); } /// /// Handle the Encode Status Changed Event. /// /// /// The sender. /// /// /// The EncodeProgressEventArgs. /// private void EncodeService_EncodeStatusChanged(object sender, EncodeProgressEventArgs e) { Execute.OnUIThread(() => { this.JobStatus = string.Format( "Encoding: Pass {0} of {1}, {2:00.00}%, FPS: {3:000.0}, Avg FPS: {4:000.0}, Time Remaining: {5}, Elapsed: {6:hh\\:mm\\:ss}", e.Task, e.TaskCount, e.PercentComplete, e.CurrentFrameRate, e.AverageFrameRate, e.EstimatedTimeLeft, e.ElapsedTime); }); } /// /// Handle the Queue Changed Event. /// /// /// The sender. /// /// /// The e. /// private void QueueManager_QueueChanged(object sender, EventArgs e) { this.JobsPending = string.Format("{0} jobs pending", this.queueProcessor.Count); if (!queueProcessor.IsProcessing) { this.JobStatus = "Queue Not Running"; } } /// /// Handle the Queue Completed Event /// /// /// The sender. /// /// /// The EventArgs. /// private void queueProcessor_QueueCompleted(object sender, EventArgs e) { this.JobStatus = "Queue Completed"; this.JobsPending = string.Format("{0} jobs pending", this.queueProcessor.Count); this.IsEncoding = false; } /// /// The encode service_ encode completed. /// /// /// The sender. /// /// /// The e. /// private void EncodeService_EncodeCompleted(object sender, EncodeCompletedEventArgs e) { if (!this.queueProcessor.IsProcessing) { this.JobStatus = "Last Queued Job Finished"; } } /// /// The queue processor job processing started. /// /// /// The sender. /// /// /// The QueueProgressEventArgs. /// private void QueueProcessorJobProcessingStarted(object sender, QueueProgressEventArgs e) { this.JobStatus = "Queue Started"; this.JobsPending = string.Format("{0} jobs pending", this.queueProcessor.Count); this.IsEncoding = true; } #endregion } }