// --------------------------------------------------------------------------------------------------------------------
//
// 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.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Windows;
using Caliburn.Micro;
using HandBrakeWPF.EventArgs;
using HandBrakeWPF.Properties;
using HandBrakeWPF.Services.Interfaces;
using HandBrakeWPF.Services.Queue.Interfaces;
using HandBrakeWPF.Services.Queue.Model;
using HandBrakeWPF.ViewModels.Interfaces;
using Microsoft.Win32;
using EncodeCompletedEventArgs = HandBrakeWPF.Services.Encode.EventArgs.EncodeCompletedEventArgs;
using EncodeProgressEventArgs = HandBrakeWPF.Services.Encode.EventArgs.EncodeProgressEventArgs;
using EncodeTask = HandBrakeWPF.Services.Encode.Model.EncodeTask;
///
/// The Preview View Model
///
public class QueueViewModel : ViewModelBase, IQueueViewModel
{
#region Constants and Fields
private readonly IErrorService errorService;
private readonly IUserSettingService userSettingService;
private readonly IQueueProcessor queueProcessor;
private bool isEncoding;
private string jobStatus;
private string jobsPending;
private string whenDoneAction;
private bool isQueueRunning;
#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 = Resources.QueueViewModel_Queue;
this.JobsPending = Resources.QueueViewModel_NoEncodesPending;
this.JobStatus = Resources.QueueViewModel_NoJobsPending;
this.SelectedItems = new BindingList();
this.DisplayName = "Queue";
this.IsQueueRunning = false;
this.WhenDoneAction = this.userSettingService.GetUserSetting(UserSettingConstants.WhenCompleteAction);
}
#endregion
#region Properties
///
/// Gets or sets a value indicating whether the Queue is paused or not..
///
public bool IsQueueRunning
{
get
{
return this.isQueueRunning;
}
set
{
if (value == this.isQueueRunning) return;
this.isQueueRunning = value;
this.NotifyOfPropertyChange(() => this.IsQueueRunning);
}
}
///
/// 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;
}
}
///
/// Gets or sets the selected items.
///
public BindingList SelectedItems { get; set; }
#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(
Resources.QueueViewModel_ClearQueueConfrimation, Resources.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.IsQueueRunning = this.queueProcessor.EncodeService.IsEncoding;
this.JobsPending = string.Format(Resources.QueueViewModel_JobsPending, this.queueProcessor.Count);
base.OnLoad();
}
///
/// Can Pause the Queue.
/// Used by Caliburn Micro to enable/disable the context menu item.
///
///
/// True when we can pause the queue.
///
public bool CanPauseQueue()
{
return this.IsQueueRunning;
}
///
/// Pause the Queue
///
public void PauseQueue()
{
this.queueProcessor.Pause();
this.JobStatus = Resources.QueueViewModel_QueuePending;
this.JobsPending = string.Format(Resources.QueueViewModel_JobsPending, this.queueProcessor.Count);
this.IsQueueRunning = false;
MessageBox.Show(Resources.QueueViewModel_QueuePauseNotice, Resources.QueueViewModel_Queue,
MessageBoxButton.OK, MessageBoxImage.Information);
}
///
/// Pause the Queue
///
///
/// Prevents evaluation of CanPauseQueue
///
public void PauseQueueToolbar()
{
this.PauseQueue();
}
///
/// The remove selected jobs.
///
public void RemoveSelectedJobs()
{
MessageBoxResult result =
this.errorService.ShowMessageBox(
Resources.QueueViewModel_DelSelectedJobConfirmation,
Resources.Question,
MessageBoxButton.YesNo,
MessageBoxImage.Question);
if (result == MessageBoxResult.No)
{
return;
}
List tasksToRemove = this.SelectedItems.ToList();
foreach (QueueTask job in tasksToRemove)
{
this.RemoveJob(job);
}
}
///
/// Remove a Job from the queue
///
///
/// The Job to remove from the queue
///
public void RemoveJob(object queueTask)
{
QueueTask task = queueTask as QueueTask;
if (task == null)
{
return;
}
if (task.Status == QueueItemStatus.InProgress)
{
MessageBoxResult result =
this.errorService.ShowMessageBox(
Resources.QueueViewModel_JobCurrentlyRunningWarning,
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(Resources.QueueViewModel_JobsPending, this.queueProcessor.Count);
}
///
/// Can Start Encoding.
/// Used by Caliburn Micro to enable/disable the context menu item.
///
///
/// True when we can start encoding.
///
public bool CanStartQueue()
{
return !this.IsQueueRunning;
}
///
/// Start Encode
///
public void StartQueue()
{
if (this.queueProcessor.Count == 0)
{
this.errorService.ShowMessageBox(
Resources.QueueViewModel_NoPendingJobs, Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
this.JobStatus = Resources.QueueViewModel_QueueStarted;
this.JobsPending = string.Format(Resources.QueueViewModel_JobsPending, this.queueProcessor.Count);
this.IsQueueRunning = true;
this.queueProcessor.Start(userSettingService.GetUserSetting(UserSettingConstants.ClearCompletedFromQueue));
}
///
/// Export the Queue to a file.
///
public void Export()
{
SaveFileDialog dialog = new SaveFileDialog
{
Filter = "Legacy Queue Files (*.hbq)|*.hbq|Json for CLI (*.json)|*.json",
OverwritePrompt = true,
DefaultExt = ".hbq",
AddExtension = true
};
if (dialog.ShowDialog() == true)
{
if (Path.GetExtension(dialog.FileName).ToLower().Trim() == ".json")
{
this.queueProcessor.ExportJson(dialog.FileName);
}
else
{
this.queueProcessor.BackupQueue(dialog.FileName);
}
}
}
///
/// Import a saved queue
///
public void Import()
{
OpenFileDialog dialog = new OpenFileDialog { Filter = "Legacy 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(
Resources.QueueViewModel_EditConfrimation,
"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
public void Activate()
{
this.queueProcessor.QueueCompleted += this.queueProcessor_QueueCompleted;
this.queueProcessor.QueueChanged += this.QueueManager_QueueChanged;
this.queueProcessor.JobProcessingStarted += this.QueueProcessorJobProcessingStarted;
}
public void Deactivate()
{
this.queueProcessor.QueueCompleted -= this.queueProcessor_QueueCompleted;
this.queueProcessor.QueueChanged -= this.QueueManager_QueueChanged;
this.queueProcessor.JobProcessingStarted -= this.QueueProcessorJobProcessingStarted;
}
///
/// Override the OnActive to run the Screen Loading code in the view model base.
///
protected override void OnActivate()
{
this.Load();
this.queueProcessor.QueueCompleted += this.queueProcessor_QueueCompleted;
this.queueProcessor.QueueChanged += this.QueueManager_QueueChanged;
this.queueProcessor.EncodeService.EncodeStatusChanged += this.EncodeService_EncodeStatusChanged;
this.queueProcessor.EncodeService.EncodeCompleted += this.EncodeService_EncodeCompleted;
this.queueProcessor.JobProcessingStarted += this.QueueProcessorJobProcessingStarted;
this.queueProcessor.LowDiskspaceDetected += this.QueueProcessor_LowDiskspaceDetected;
this.JobsPending = string.Format(Resources.QueueViewModel_JobsPending, this.queueProcessor.Count);
this.JobStatus = Resources.QueueViewModel_QueueReady;
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 -= this.EncodeService_EncodeCompleted;
this.queueProcessor.JobProcessingStarted -= this.QueueProcessorJobProcessingStarted;
this.queueProcessor.LowDiskspaceDetected -= this.QueueProcessor_LowDiskspaceDetected;
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(
Resources.QueueViewModel_QueueStatusDisplay,
e.Task,
e.TaskCount,
e.PercentComplete,
e.CurrentFrameRate,
e.AverageFrameRate,
e.EstimatedTimeLeft,
e.ElapsedTime);
});
}
///
/// Detect Low Disk Space before starting new queue tasks.
///
/// Event invoker.
/// Event Args.
private void QueueProcessor_LowDiskspaceDetected(object sender, EventArgs e)
{
Execute.OnUIThreadAsync(
() =>
{
this.queueProcessor.Pause();
this.JobStatus = Resources.QueueViewModel_QueuePending;
this.JobsPending = string.Format(Resources.QueueViewModel_JobsPending, this.queueProcessor.Count);
this.IsQueueRunning = false;
this.errorService.ShowMessageBox(
Resources.MainViewModel_LowDiskSpaceWarning,
Resources.MainViewModel_LowDiskSpace,
MessageBoxButton.OK,
MessageBoxImage.Warning);
});
}
///
/// Handle the Queue Changed Event.
///
///
/// The sender.
///
///
/// The e.
///
private void QueueManager_QueueChanged(object sender, EventArgs e)
{
this.JobsPending = string.Format(Resources.QueueViewModel_JobsPending, this.queueProcessor.Count);
if (!queueProcessor.IsProcessing)
{
this.JobStatus = Resources.QueueViewModel_QueueNotRunning;
this.IsQueueRunning = false;
}
}
///
/// Handle the Queue Completed Event
///
///
/// The sender.
///
///
/// The EventArgs.
///
private void queueProcessor_QueueCompleted(object sender, EventArgs e)
{
this.JobStatus = Resources.QueueViewModel_QueueCompleted;
this.JobsPending = string.Format(Resources.QueueViewModel_JobsPending, this.queueProcessor.Count);
this.IsQueueRunning = false;
}
///
/// The encode service_ encode completed.
///
///
/// The sender.
///
///
/// The e.
///
private void EncodeService_EncodeCompleted(object sender, EncodeCompletedEventArgs e)
{
if (!this.queueProcessor.IsProcessing)
{
this.JobStatus = Resources.QueueViewModel_LastJobFinished;
}
}
///
/// The queue processor job processing started.
///
///
/// The sender.
///
///
/// The QueueProgressEventArgs.
///
private void QueueProcessorJobProcessingStarted(object sender, QueueProgressEventArgs e)
{
this.JobStatus = Resources.QueueViewModel_QueueStarted;
this.JobsPending = string.Format(Resources.QueueViewModel_JobsPending, this.queueProcessor.Count);
this.IsQueueRunning = true;
}
#endregion
}
}