From 29c62be71227ae33e382199f323890ae3bfffa69 Mon Sep 17 00:00:00 2001 From: sr55 Date: Sun, 1 Mar 2015 18:03:28 +0000 Subject: WinGui: Moving the Queue Code out to the UI level. The services library will be strictly a libhb warpper and service provider. git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@6959 b64f7644-9d1e-0410-96f1-a4d463321fa5 --- .../EventArgs/QueueCompletedEventArgs.cs | 38 ++ .../EventArgs/QueueProgressEventArgs.cs | 37 ++ .../EventArgs/SettingChangedEventArgs.cs | 27 + win/CS/HandBrakeWPF/HandBrakeWPF.csproj | 5 + win/CS/HandBrakeWPF/Helpers/QueueRecoveryHelper.cs | 2 + .../Services/Interfaces/IQueueProcessor.cs | 184 +++++++ .../Services/Interfaces/IUserSettingService.cs | 2 +- .../HandBrakeWPF/Services/NotificationService.cs | 2 + .../HandBrakeWPF/Services/PrePostActionService.cs | 20 +- win/CS/HandBrakeWPF/Services/QueueProcessor.cs | 604 +++++++++++++++++++++ win/CS/HandBrakeWPF/Services/UserSettingService.cs | 3 +- win/CS/HandBrakeWPF/Startup/CastleBootstrapper.cs | 5 +- win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs | 7 +- win/CS/HandBrakeWPF/ViewModels/QueueViewModel.cs | 39 +- win/CS/HandBrakeWPF/ViewModels/ShellViewModel.cs | 2 + win/CS/HandBrakeWPF/ViewModels/VideoViewModel.cs | 2 +- 16 files changed, 941 insertions(+), 38 deletions(-) create mode 100644 win/CS/HandBrakeWPF/EventArgs/QueueCompletedEventArgs.cs create mode 100644 win/CS/HandBrakeWPF/EventArgs/QueueProgressEventArgs.cs create mode 100644 win/CS/HandBrakeWPF/EventArgs/SettingChangedEventArgs.cs create mode 100644 win/CS/HandBrakeWPF/Services/Interfaces/IQueueProcessor.cs create mode 100644 win/CS/HandBrakeWPF/Services/QueueProcessor.cs (limited to 'win/CS/HandBrakeWPF') diff --git a/win/CS/HandBrakeWPF/EventArgs/QueueCompletedEventArgs.cs b/win/CS/HandBrakeWPF/EventArgs/QueueCompletedEventArgs.cs new file mode 100644 index 000000000..e7e1fc813 --- /dev/null +++ b/win/CS/HandBrakeWPF/EventArgs/QueueCompletedEventArgs.cs @@ -0,0 +1,38 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. +// +// +// Queue Completed Event Args +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace HandBrakeWPF.EventArgs +{ + using System; + using System.Runtime.Serialization; + + /// + /// Queue Completed Event Args + /// + [DataContract] + public class QueueCompletedEventArgs : EventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The was Manually Stopped. + /// + public QueueCompletedEventArgs(bool wasManuallyStopped) + { + this.WasManuallyStopped = wasManuallyStopped; + } + + /// + /// Gets a value indicating whether the queue WasManuallyStopped. + /// + [DataMember] + public bool WasManuallyStopped { get; private set; } + } +} diff --git a/win/CS/HandBrakeWPF/EventArgs/QueueProgressEventArgs.cs b/win/CS/HandBrakeWPF/EventArgs/QueueProgressEventArgs.cs new file mode 100644 index 000000000..3fa93fe7e --- /dev/null +++ b/win/CS/HandBrakeWPF/EventArgs/QueueProgressEventArgs.cs @@ -0,0 +1,37 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. +// +// +// Queue Progress Event Args +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace HandBrakeWPF.EventArgs +{ + using System; + + using HandBrake.ApplicationServices.Model; + + /// + /// Queue Progress Event Args + /// + public class QueueProgressEventArgs : EventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The new job. + /// + public QueueProgressEventArgs(QueueTask newJob) + { + this.NewJob = newJob; + } + + /// + /// Gets or sets the new job which is about to be processed. + /// + public QueueTask NewJob { get; set; } + } +} diff --git a/win/CS/HandBrakeWPF/EventArgs/SettingChangedEventArgs.cs b/win/CS/HandBrakeWPF/EventArgs/SettingChangedEventArgs.cs new file mode 100644 index 000000000..edd27b11c --- /dev/null +++ b/win/CS/HandBrakeWPF/EventArgs/SettingChangedEventArgs.cs @@ -0,0 +1,27 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. +// +// +// The setting changed event args. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace HandBrakeWPF.EventArgs +{ + /// + /// The setting changed event args. + /// + public class SettingChangedEventArgs + { + /// + /// Gets or sets the key. + /// + public string Key { get; set; } + + /// + /// Gets or sets the value. + /// + public object Value { get; set; } + } +} diff --git a/win/CS/HandBrakeWPF/HandBrakeWPF.csproj b/win/CS/HandBrakeWPF/HandBrakeWPF.csproj index a5bde0f97..e44fd25d7 100644 --- a/win/CS/HandBrakeWPF/HandBrakeWPF.csproj +++ b/win/CS/HandBrakeWPF/HandBrakeWPF.csproj @@ -140,12 +140,16 @@ + + + + @@ -155,6 +159,7 @@ + diff --git a/win/CS/HandBrakeWPF/Helpers/QueueRecoveryHelper.cs b/win/CS/HandBrakeWPF/Helpers/QueueRecoveryHelper.cs index 53ab407e2..ceb8943b8 100644 --- a/win/CS/HandBrakeWPF/Helpers/QueueRecoveryHelper.cs +++ b/win/CS/HandBrakeWPF/Helpers/QueueRecoveryHelper.cs @@ -24,6 +24,8 @@ namespace HandBrakeWPF.Helpers using HandBrakeWPF.Services.Interfaces; + using IQueueProcessor = HandBrakeWPF.Services.Interfaces.IQueueProcessor; + /// /// Queue Recovery Helper /// diff --git a/win/CS/HandBrakeWPF/Services/Interfaces/IQueueProcessor.cs b/win/CS/HandBrakeWPF/Services/Interfaces/IQueueProcessor.cs new file mode 100644 index 000000000..b04c825d9 --- /dev/null +++ b/win/CS/HandBrakeWPF/Services/Interfaces/IQueueProcessor.cs @@ -0,0 +1,184 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. +// +// +// The Queue Processor +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace HandBrakeWPF.Services.Interfaces +{ + using System; + using System.ComponentModel; + + using HandBrake.ApplicationServices.Model; + using HandBrake.ApplicationServices.Services.Encode.Interfaces; + + /// + /// The Queue Processor + /// + public interface IQueueProcessor + { + #region Events + + /// + /// Fires when the Queue has started + /// + event QueueProcessor.QueueProgressStatus JobProcessingStarted; + + /// + /// Fires when a job is Added, Removed or Re-Ordered. + /// Should be used for triggering an update of the Queue Window. + /// + event EventHandler QueueChanged; + + /// + /// Fires when the entire encode queue has completed. + /// + event QueueProcessor.QueueCompletedEventDelegate QueueCompleted; + + /// + /// Fires when a pause to the encode queue has been requested. + /// + event EventHandler QueuePaused; + + #endregion + + #region Properties + + /// + /// Gets the number of jobs in the queue + /// + int Count { get; } + + /// + /// Gets the IEncodeService instance. + /// + IEncode EncodeService { get; } + + /// + /// Gets a value indicating whether IsProcessing. + /// + bool IsProcessing { get; } + + /// + /// Gets or sets Last Processed Job. + /// This is set when the job is poped of the queue by GetNextJobForProcessing(); + /// + QueueTask LastProcessedJob { get; set; } + + /// + /// Gets The current queue. + /// + BindingList Queue { get; } + + #endregion + + #region Public Methods + + /// + /// Add a job to the Queue. + /// This method is Thread Safe. + /// + /// + /// The encode Job object. + /// + void Add(QueueTask job); + + /// + /// Backup any changes to the queue file + /// + /// + /// If this is not null or empty, this will be used instead of the standard backup location. + /// + void BackupQueue(string exportPath); + + /// + /// Checks the current queue for an existing instance of the specified destination. + /// + /// + /// The destination of the encode. + /// + /// + /// Whether or not the supplied destination is already in the queue. + /// + bool CheckForDestinationPathDuplicates(string destination); + + /// + /// Clear down all Queue Items + /// + void Clear(); + + /// + /// Clear down the Queue´s completed items + /// + void ClearCompleted(); + + /// + /// Get the first job on the queue for processing. + /// This also removes the job from the Queue and sets the LastProcessedJob + /// + /// + /// An encode Job object. + /// + QueueTask GetNextJobForProcessing(); + + /// + /// Moves an item down one position in the queue. + /// + /// + /// The zero-based location of the job in the queue. + /// + void MoveDown(int index); + + /// + /// Moves an item up one position in the queue. + /// + /// + /// The zero-based location of the job in the queue. + /// + void MoveUp(int index); + + /// + /// Requests a pause of the encode queue. + /// + void Pause(); + + /// + /// Remove a job from the Queue. + /// This method is Thread Safe + /// + /// + /// The job. + /// + void Remove(QueueTask job); + + /// + /// Reset a Queued Item from Error or Completed to Waiting + /// + /// + /// The job. + /// + void ResetJobStatusToWaiting(QueueTask job); + + /// + /// Restore a Queue from file or from the queue backup file. + /// + /// + /// The import path. String.Empty or null will result in the default file being loaded. + /// + void RestoreQueue(string importPath); + + /// + /// Starts encoding the first job in the queue and continues encoding until all jobs + /// have been encoded. + /// + /// + /// The clear Completed. + /// + void Start(bool clearCompleted); + + #endregion + } +} \ No newline at end of file diff --git a/win/CS/HandBrakeWPF/Services/Interfaces/IUserSettingService.cs b/win/CS/HandBrakeWPF/Services/Interfaces/IUserSettingService.cs index d2f433bc1..c8b34b7cd 100644 --- a/win/CS/HandBrakeWPF/Services/Interfaces/IUserSettingService.cs +++ b/win/CS/HandBrakeWPF/Services/Interfaces/IUserSettingService.cs @@ -9,7 +9,7 @@ namespace HandBrakeWPF.Services.Interfaces { - using HandBrake.ApplicationServices.EventArgs; + using SettingChangedEventArgs = HandBrakeWPF.EventArgs.SettingChangedEventArgs; /// /// The setting event handler. diff --git a/win/CS/HandBrakeWPF/Services/NotificationService.cs b/win/CS/HandBrakeWPF/Services/NotificationService.cs index 1a647a970..0f387fec3 100644 --- a/win/CS/HandBrakeWPF/Services/NotificationService.cs +++ b/win/CS/HandBrakeWPF/Services/NotificationService.cs @@ -15,6 +15,8 @@ namespace HandBrakeWPF.Services using HandBrakeWPF.Services.Interfaces; + using IQueueProcessor = HandBrakeWPF.Services.Interfaces.IQueueProcessor; + /// /// The Notification Service (Growl Connector) /// diff --git a/win/CS/HandBrakeWPF/Services/PrePostActionService.cs b/win/CS/HandBrakeWPF/Services/PrePostActionService.cs index c57935239..b8501b999 100644 --- a/win/CS/HandBrakeWPF/Services/PrePostActionService.cs +++ b/win/CS/HandBrakeWPF/Services/PrePostActionService.cs @@ -9,21 +9,19 @@ namespace HandBrakeWPF.Services { + using System; using System.Diagnostics; using System.Windows.Forms; using Caliburn.Micro; - using HandBrake.ApplicationServices.EventArgs; using HandBrake.ApplicationServices.Services.Encode.EventArgs; - using HandBrake.ApplicationServices.Services.Interfaces; using HandBrake.ApplicationServices.Utilities; + using HandBrakeWPF.EventArgs; using HandBrakeWPF.Services.Interfaces; using HandBrakeWPF.ViewModels.Interfaces; - using Application = System.Windows.Application; - /// /// The when done service. /// @@ -76,7 +74,7 @@ namespace HandBrakeWPF.Services /// /// The e. /// - private void EncodeService_EncodeStarted(object sender, System.EventArgs e) + private void EncodeService_EncodeStarted(object sender, EventArgs e) { if (this.userSettingService.GetUserSetting(UserSettingConstants.PreventSleep)) { @@ -134,7 +132,7 @@ namespace HandBrakeWPF.Services // Give the user the ability to cancel the shutdown. Default 60 second timer. ICountdownAlertViewModel titleSpecificView = IoC.Get(); - Caliburn.Micro.Execute.OnUIThread( + Execute.OnUIThread( () => { titleSpecificView.SetAction(this.userSettingService.GetUserSetting(UserSettingConstants.WhenCompleteAction)); @@ -153,16 +151,16 @@ namespace HandBrakeWPF.Services Win32.ExitWindowsEx(0, 0); break; case "Suspend": - System.Windows.Forms.Application.SetSuspendState(PowerState.Suspend, true, true); + Application.SetSuspendState(PowerState.Suspend, true, true); break; case "Hibernate": - System.Windows.Forms.Application.SetSuspendState(PowerState.Hibernate, true, true); + Application.SetSuspendState(PowerState.Hibernate, true, true); break; case "Lock System": Win32.LockWorkStation(); break; case "Quit HandBrake": - Execute.OnUIThread(() => Application.Current.Shutdown()); + Execute.OnUIThread(() => System.Windows.Application.Current.Shutdown()); break; } } @@ -180,8 +178,8 @@ namespace HandBrakeWPF.Services !string.IsNullOrEmpty(this.userSettingService.GetUserSetting(UserSettingConstants.SendFileTo))) { string args = string.Format( - "{0} \"{1}\"", - this.userSettingService.GetUserSetting(UserSettingConstants.SendFileToArgs), + "{0} \"{1}\"", + this.userSettingService.GetUserSetting(UserSettingConstants.SendFileToArgs), file); var vlc = new ProcessStartInfo( diff --git a/win/CS/HandBrakeWPF/Services/QueueProcessor.cs b/win/CS/HandBrakeWPF/Services/QueueProcessor.cs new file mode 100644 index 000000000..414113d2f --- /dev/null +++ b/win/CS/HandBrakeWPF/Services/QueueProcessor.cs @@ -0,0 +1,604 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. +// +// +// The HandBrake Queue +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace HandBrakeWPF.Services +{ + using System; + using System.Collections.Generic; + using System.ComponentModel; + using System.IO; + using System.Linq; + using System.Xml.Serialization; + + using Caliburn.Micro; + + using HandBrake.ApplicationServices.Exceptions; + using HandBrake.ApplicationServices.Model; + using HandBrake.ApplicationServices.Services.Encode.EventArgs; + using HandBrake.ApplicationServices.Services.Encode.Interfaces; + using HandBrake.ApplicationServices.Utilities; + + using IQueueProcessor = HandBrakeWPF.Services.Interfaces.IQueueProcessor; + using QueueCompletedEventArgs = HandBrakeWPF.EventArgs.QueueCompletedEventArgs; + using QueueProgressEventArgs = HandBrakeWPF.EventArgs.QueueProgressEventArgs; + + /// + /// The HandBrake Queue + /// + public class QueueProcessor : IQueueProcessor + { + #region Constants and Fields + + /// + /// A Lock object to maintain thread safety + /// + private static readonly object QueueLock = new object(); + + /// + /// The Queue of Job objects + /// + private readonly BindingList queue = new BindingList(); + + /// + /// HandBrakes Queue file with a place holder for an extra string. + /// + private readonly string queueFile; + + /// + /// The clear completed. + /// + private bool clearCompleted; + + #endregion + + #region Constructors and Destructors + + /// + /// Initializes a new instance of the class. + /// + /// + /// The encode Service. + /// + /// + /// Services are not setup + /// + public QueueProcessor(IEncode encodeService) + { + this.EncodeService = encodeService; + + // If this is the first instance, just use the main queue file, otherwise add the instance id to the filename. + this.queueFile = string.Format("hb_queue_recovery{0}.xml", GeneralUtilities.ProcessId); + } + + #endregion + + #region Delegates + + /// + /// Queue Progess Status + /// + /// + /// The sender. + /// + /// + /// The QueueProgressEventArgs. + /// + public delegate void QueueProgressStatus(object sender, QueueProgressEventArgs e); + + /// + /// The queue completed. + /// + /// + /// The sender. + /// + /// + /// The e. + /// + public delegate void QueueCompletedEventDelegate(object sender, QueueCompletedEventArgs e); + + #endregion + + #region Events + + /// + /// Fires when the Queue has started + /// + public event QueueProgressStatus JobProcessingStarted; + + /// + /// Fires when a job is Added, Removed or Re-Ordered. + /// Should be used for triggering an update of the Queue Window. + /// + public event EventHandler QueueChanged; + + /// + /// Fires when the entire encode queue has completed. + /// + public event QueueCompletedEventDelegate QueueCompleted; + + /// + /// Fires when a pause to the encode queue has been requested. + /// + public event EventHandler QueuePaused; + + #endregion + + #region Properties + + /// + /// Gets the number of jobs in the queue; + /// + public int Count + { + get + { + return this.queue.Count(item => item.Status == QueueItemStatus.Waiting); + } + } + + /// + /// Gets the IEncodeService instance. + /// + public IEncode EncodeService { get; private set; } + + /// + /// Gets a value indicating whether IsProcessing. + /// + public bool IsProcessing { get; private set; } + + /// + /// Gets or sets Last Processed Job. + /// This is set when the job is poped of the queue by GetNextJobForProcessing(); + /// + public QueueTask LastProcessedJob { get; set; } + + /// + /// Gets The current queue. + /// + public BindingList Queue + { + get + { + return this.queue; + } + } + + #endregion + + #region Public Methods + + /// + /// Add a job to the Queue. + /// This method is Thread Safe. + /// + /// + /// The encode Job object. + /// + public void Add(QueueTask job) + { + lock (QueueLock) + { + this.queue.Add(job); + this.InvokeQueueChanged(EventArgs.Empty); + } + } + + /// + /// Backup any changes to the queue file + /// + /// + /// If this is not null or empty, this will be used instead of the standard backup location. + /// + public void BackupQueue(string exportPath) + { + string appDataPath = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"HandBrake\"); + string tempPath = !string.IsNullOrEmpty(exportPath) + ? exportPath + : appDataPath + string.Format(this.queueFile, string.Empty); + + using (var strm = new FileStream(tempPath, FileMode.Create, FileAccess.Write)) + { + List tasks = this.queue.Where(item => item.Status != QueueItemStatus.Completed).ToList(); + var serializer = new XmlSerializer(typeof(List)); + serializer.Serialize(strm, tasks); + strm.Close(); + strm.Dispose(); + } + } + + /// + /// Checks the current queue for an existing instance of the specified destination. + /// + /// + /// The destination of the encode. + /// + /// + /// Whether or not the supplied destination is already in the queue. + /// + public bool CheckForDestinationPathDuplicates(string destination) + { + return this.queue.Any(job => job.Task != null && job.Status == QueueItemStatus.Waiting && job.Task.Destination != null && job.Task.Destination.Contains(destination.Replace("\\\\", "\\"))); + } + + /// + /// Clear down all Queue Items + /// + public void Clear() + { + List deleteList = this.queue.ToList(); + foreach (QueueTask item in deleteList) + { + this.queue.Remove(item); + } + this.InvokeQueueChanged(EventArgs.Empty); + } + + /// + /// Clear down the Queue´s completed items + /// + public void ClearCompleted() + { + Execute.OnUIThread( + () => + { + List deleteList = + this.queue.Where(task => task.Status == QueueItemStatus.Completed).ToList(); + foreach (QueueTask item in deleteList) + { + this.queue.Remove(item); + } + this.InvokeQueueChanged(EventArgs.Empty); + }); + } + + /// + /// Get the first job on the queue for processing. + /// This also removes the job from the Queue and sets the LastProcessedJob + /// + /// + /// An encode Job object. + /// + public QueueTask GetNextJobForProcessing() + { + if (this.queue.Count > 0) + { + QueueTask job = this.queue.FirstOrDefault(q => q.Status == QueueItemStatus.Waiting); + if (job != null) + { + job.Status = QueueItemStatus.InProgress; + this.LastProcessedJob = job; + this.InvokeQueueChanged(EventArgs.Empty); + } + + this.BackupQueue(string.Empty); + return job; + } + + this.BackupQueue(string.Empty); + return null; + } + + /// + /// Moves an item down one position in the queue. + /// + /// + /// The zero-based location of the job in the queue. + /// + public void MoveDown(int index) + { + if (index < this.queue.Count - 1) + { + QueueTask item = this.queue[index]; + + this.queue.RemoveAt(index); + this.queue.Insert((index + 1), item); + } + + this.InvokeQueueChanged(EventArgs.Empty); + } + + /// + /// Moves an item up one position in the queue. + /// + /// + /// The zero-based location of the job in the queue. + /// + public void MoveUp(int index) + { + if (index > 0) + { + QueueTask item = this.queue[index]; + + this.queue.RemoveAt(index); + this.queue.Insert((index - 1), item); + } + + this.InvokeQueueChanged(EventArgs.Empty); + } + + /// + /// Remove a job from the Queue. + /// This method is Thread Safe + /// + /// + /// The job. + /// + public void Remove(QueueTask job) + { + lock (QueueLock) + { + this.queue.Remove(job); + this.InvokeQueueChanged(EventArgs.Empty); + } + } + + /// + /// Reset a Queued Item from Error or Completed to Waiting + /// + /// + /// The job. + /// + public void ResetJobStatusToWaiting(QueueTask job) + { + if (job.Status != QueueItemStatus.Error && job.Status != QueueItemStatus.Completed) + { + throw new GeneralApplicationException( + "Job Error", "Unable to reset job status as it is not in an Error or Completed state", null); + } + + job.Status = QueueItemStatus.Waiting; + } + + /// + /// Restore a Queue from file or from the queue backup file. + /// + /// + /// The import path. String.Empty or null will result in the default file being loaded. + /// + public void RestoreQueue(string importPath) + { + string appDataPath = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"HandBrake\"); + string tempPath = !string.IsNullOrEmpty(importPath) + ? importPath + : (appDataPath + string.Format(this.queueFile, string.Empty)); + + if (File.Exists(tempPath)) + { + bool invokeUpdate = false; + using ( + var strm = new FileStream( + (!string.IsNullOrEmpty(importPath) ? importPath : tempPath), FileMode.Open, FileAccess.Read)) + { + if (strm.Length != 0) + { + var serializer = new XmlSerializer(typeof(List)); + + List list; + + try + { + list = serializer.Deserialize(strm) as List; + } + catch (Exception exc) + { + throw new GeneralApplicationException( + "Unable to restore queue file.", + "The file may be corrupted or from an older incompatible version of HandBrake", + exc); + } + + if (list != null) + { + foreach (QueueTask item in list) + { + if (item.Status != QueueItemStatus.Completed) + { + // Reset InProgress/Error to Waiting so it can be processed + if (item.Status == QueueItemStatus.InProgress) + { + item.Status = QueueItemStatus.Waiting; + } + + this.queue.Add(item); + } + } + } + + invokeUpdate = true; + } + } + + if (invokeUpdate) + { + this.InvokeQueueChanged(EventArgs.Empty); + } + } + } + + /// + /// Requests a pause of the encode queue. + /// + public void Pause() + { + this.InvokeQueuePaused(EventArgs.Empty); + this.IsProcessing = false; + } + + /// + /// Starts encoding the first job in the queue and continues encoding until all jobs + /// have been encoded. + /// + /// + /// The is Clear Completed. + /// + public void Start(bool isClearCompleted) + { + if (this.IsProcessing) + { + throw new Exception("Already Processing the Queue"); + } + + this.clearCompleted = isClearCompleted; + + this.EncodeService.EncodeCompleted -= this.EncodeServiceEncodeCompleted; + this.EncodeService.EncodeCompleted += this.EncodeServiceEncodeCompleted; + + if (this.EncodeService.CanPause && this.EncodeService.IsEncoding) + { + this.EncodeService.Resume(); + } + + if (!this.EncodeService.IsEncoding) + { + this.ProcessNextJob(); + } + + this.IsProcessing = true; + } + + #endregion + + #region Methods + + /// + /// After an encode is complete, move onto the next job. + /// + /// + /// The sender. + /// + /// + /// The EncodeCompletedEventArgs. + /// + private void EncodeServiceEncodeCompleted(object sender, EncodeCompletedEventArgs e) + { + this.LastProcessedJob.Status = QueueItemStatus.Completed; + + // Clear the completed item of the queue if the setting is set. + if (this.clearCompleted) + { + this.ClearCompleted(); + } + + if (!e.Successful) + { + this.LastProcessedJob.Status = QueueItemStatus.Error; + } + + // Move onto the next job. + if (this.IsProcessing) + { + this.ProcessNextJob(); + } + else + { + this.EncodeService.EncodeCompleted -= this.EncodeServiceEncodeCompleted; + this.OnQueueCompleted(new QueueCompletedEventArgs(true)); + this.BackupQueue(string.Empty); + } + } + + /// + /// Invoke the JobProcessingStarted event + /// + /// + /// The QueueProgressEventArgs. + /// + private void InvokeJobProcessingStarted(QueueProgressEventArgs e) + { + QueueProgressStatus handler = this.JobProcessingStarted; + if (handler != null) + { + handler(this, e); + } + } + + /// + /// Invoke the Queue Changed Event + /// + /// + /// The e. + /// + private void InvokeQueueChanged(EventArgs e) + { + try + { + this.BackupQueue(string.Empty); + } + catch (Exception) + { + // Do Nothing. + } + + EventHandler handler = this.QueueChanged; + if (handler != null) + { + handler(this, e); + } + } + + /// + /// Invoke the QueuePaused event + /// + /// + /// The EventArgs. + /// + private void InvokeQueuePaused(EventArgs e) + { + this.IsProcessing = false; + + EventHandler handler = this.QueuePaused; + if (handler != null) + { + handler(this, e); + } + } + + /// + /// The on queue completed. + /// + /// + /// The e. + /// + protected virtual void OnQueueCompleted(QueueCompletedEventArgs e) + { + QueueCompletedEventDelegate handler = this.QueueCompleted; + if (handler != null) + { + handler(this, e); + } + + this.IsProcessing = false; + } + + /// + /// Run through all the jobs on the queue. + /// + private void ProcessNextJob() + { + QueueTask job = this.GetNextJobForProcessing(); + if (job != null) + { + this.InvokeJobProcessingStarted(new QueueProgressEventArgs(job)); + this.EncodeService.Start(job); + } + else + { + // No more jobs to process, so unsubscribe the event + this.EncodeService.EncodeCompleted -= this.EncodeServiceEncodeCompleted; + + // Fire the event to tell connected services. + this.OnQueueCompleted(new QueueCompletedEventArgs(false)); + } + } + + #endregion + } +} \ No newline at end of file diff --git a/win/CS/HandBrakeWPF/Services/UserSettingService.cs b/win/CS/HandBrakeWPF/Services/UserSettingService.cs index 6b7d87f1b..6c5c6629b 100644 --- a/win/CS/HandBrakeWPF/Services/UserSettingService.cs +++ b/win/CS/HandBrakeWPF/Services/UserSettingService.cs @@ -16,11 +16,12 @@ namespace HandBrakeWPF.Services using System.Reflection; using System.Xml.Serialization; - using HandBrake.ApplicationServices.EventArgs; using HandBrake.ApplicationServices.Exceptions; using HandBrakeWPF.Services.Interfaces; + using SettingChangedEventArgs = HandBrakeWPF.EventArgs.SettingChangedEventArgs; + /// /// The User Setting Serivce /// diff --git a/win/CS/HandBrakeWPF/Startup/CastleBootstrapper.cs b/win/CS/HandBrakeWPF/Startup/CastleBootstrapper.cs index c8b327cd3..617413bc8 100644 --- a/win/CS/HandBrakeWPF/Startup/CastleBootstrapper.cs +++ b/win/CS/HandBrakeWPF/Startup/CastleBootstrapper.cs @@ -56,8 +56,8 @@ namespace HandBrakeWPF.Startup this.windsorContainer.Register(Component.For().ImplementedBy()); // Initialise the ApplicationServices IWindsorInstaller - this.windsorContainer.Register(Component.For().ImplementedBy()); - this.windsorContainer.Install(windsorContainer.ResolveAll()); + // this.windsorContainer.Register(Component.For().ImplementedBy()); + // this.windsorContainer.Install(windsorContainer.ResolveAll()); // Services this.windsorContainer.Register(Component.For().ImplementedBy().LifeStyle.Is(LifestyleType.Singleton)); @@ -67,6 +67,7 @@ namespace HandBrakeWPF.Startup this.windsorContainer.Register(Component.For().ImplementedBy().LifeStyle.Is(LifestyleType.Singleton)); this.windsorContainer.Register(Component.For().ImplementedBy()); this.windsorContainer.Register(Component.For().ImplementedBy()); + this.windsorContainer.Register(Component.For().ImplementedBy()); // Commands this.windsorContainer.Register(Component.For().ImplementedBy().LifeStyle.Is(LifestyleType.Singleton)); diff --git a/win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs b/win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs index f204b084d..08662882c 100644 --- a/win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs +++ b/win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs @@ -34,6 +34,7 @@ namespace HandBrakeWPF.ViewModels using HandBrake.ApplicationServices.Interop; using HandBrakeWPF.Commands; + using HandBrakeWPF.EventArgs; using HandBrakeWPF.Factories; using HandBrakeWPF.Helpers; using HandBrakeWPF.Model; @@ -52,6 +53,8 @@ namespace HandBrakeWPF.ViewModels using Ookii.Dialogs.Wpf; + using IQueueProcessor = HandBrakeWPF.Services.Interfaces.IQueueProcessor; + /// /// HandBrakes Main Window /// @@ -2104,7 +2107,7 @@ namespace HandBrakeWPF.ViewModels /// /// The e. /// - void QueueProcessorJobProcessingStarted(object sender, HandBrake.ApplicationServices.EventArgs.QueueProgressEventArgs e) + void QueueProcessorJobProcessingStarted(object sender, QueueProgressEventArgs e) { Execute.OnUIThread( () => @@ -2194,7 +2197,7 @@ namespace HandBrakeWPF.ViewModels /// /// The e. /// - private void UserSettingServiceSettingChanged(object sender, HandBrake.ApplicationServices.EventArgs.SettingChangedEventArgs e) + private void UserSettingServiceSettingChanged(object sender, SettingChangedEventArgs e) { if (e.Key == UserSettingConstants.ShowAdvancedTab) { diff --git a/win/CS/HandBrakeWPF/ViewModels/QueueViewModel.cs b/win/CS/HandBrakeWPF/ViewModels/QueueViewModel.cs index 7f5ba9b00..7191ad9b5 100644 --- a/win/CS/HandBrakeWPF/ViewModels/QueueViewModel.cs +++ b/win/CS/HandBrakeWPF/ViewModels/QueueViewModel.cs @@ -15,12 +15,11 @@ namespace HandBrakeWPF.ViewModels using Caliburn.Micro; - using HandBrake.ApplicationServices.EventArgs; using HandBrake.ApplicationServices.Model; using HandBrake.ApplicationServices.Services.Encode.EventArgs; using HandBrake.ApplicationServices.Services.Encode.Model; - using HandBrake.ApplicationServices.Services.Interfaces; + using HandBrakeWPF.EventArgs; using HandBrakeWPF.Properties; using HandBrakeWPF.Services.Interfaces; using HandBrakeWPF.ViewModels.Interfaces; @@ -245,7 +244,7 @@ namespace HandBrakeWPF.ViewModels 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", + 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); } @@ -261,9 +260,9 @@ namespace HandBrakeWPF.ViewModels { 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, + "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) @@ -317,9 +316,9 @@ namespace HandBrakeWPF.ViewModels { SaveFileDialog dialog = new SaveFileDialog { - Filter = "HandBrake Queue Files (*.hbq)|*.hbq", - OverwritePrompt = true, - DefaultExt = ".hbq", + Filter = "HandBrake Queue Files (*.hbq)|*.hbq", + OverwritePrompt = true, + DefaultExt = ".hbq", AddExtension = true }; if (dialog.ShowDialog() == true) @@ -349,9 +348,9 @@ namespace HandBrakeWPF.ViewModels 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, + "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) @@ -420,17 +419,17 @@ namespace HandBrakeWPF.ViewModels /// private void EncodeService_EncodeStatusChanged(object sender, EncodeProgressEventArgs e) { - Caliburn.Micro.Execute.OnUIThread(() => + 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, + "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); }); } diff --git a/win/CS/HandBrakeWPF/ViewModels/ShellViewModel.cs b/win/CS/HandBrakeWPF/ViewModels/ShellViewModel.cs index e297db422..6d4fcc84a 100644 --- a/win/CS/HandBrakeWPF/ViewModels/ShellViewModel.cs +++ b/win/CS/HandBrakeWPF/ViewModels/ShellViewModel.cs @@ -20,6 +20,8 @@ namespace HandBrakeWPF.ViewModels using HandBrakeWPF.Services.Interfaces; using HandBrakeWPF.ViewModels.Interfaces; + using IQueueProcessor = HandBrakeWPF.Services.Interfaces.IQueueProcessor; + /// /// The Shell View Model /// diff --git a/win/CS/HandBrakeWPF/ViewModels/VideoViewModel.cs b/win/CS/HandBrakeWPF/ViewModels/VideoViewModel.cs index a975a8bcd..5f1193cc7 100644 --- a/win/CS/HandBrakeWPF/ViewModels/VideoViewModel.cs +++ b/win/CS/HandBrakeWPF/ViewModels/VideoViewModel.cs @@ -17,7 +17,6 @@ namespace HandBrakeWPF.ViewModels using Caliburn.Micro; - using HandBrake.ApplicationServices.EventArgs; using HandBrake.ApplicationServices.Services.Encode.Model; using HandBrake.ApplicationServices.Services.Encode.Model.Models; using HandBrake.ApplicationServices.Services.Encode.Model.Models.Video; @@ -33,6 +32,7 @@ namespace HandBrakeWPF.ViewModels using HandBrakeWPF.ViewModels.Interfaces; using Clipboard = System.Windows.Clipboard; + using SettingChangedEventArgs = HandBrakeWPF.EventArgs.SettingChangedEventArgs; /// /// The Video View Model -- cgit v1.2.3