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 - .../HandBrake.ApplicationServices.csproj | 8 - .../Services/Interfaces/IQueueProcessor.cs | 184 ------- .../Services/Interfaces/IServerService.cs | 96 ---- .../Services/QueueProcessor.cs | 602 -------------------- .../Services/ServerService.cs | 296 ---------- .../ServicesWindsorInstaller.cs | 37 -- .../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 +- 25 files changed, 941 insertions(+), 1363 deletions(-) delete mode 100644 win/CS/HandBrake.ApplicationServices/EventArgs/QueueCompletedEventArgs.cs delete mode 100644 win/CS/HandBrake.ApplicationServices/EventArgs/QueueProgressEventArgs.cs delete mode 100644 win/CS/HandBrake.ApplicationServices/EventArgs/SettingChangedEventArgs.cs delete mode 100644 win/CS/HandBrake.ApplicationServices/Services/Interfaces/IQueueProcessor.cs delete mode 100644 win/CS/HandBrake.ApplicationServices/Services/Interfaces/IServerService.cs delete mode 100644 win/CS/HandBrake.ApplicationServices/Services/QueueProcessor.cs delete mode 100644 win/CS/HandBrake.ApplicationServices/Services/ServerService.cs delete mode 100644 win/CS/HandBrake.ApplicationServices/ServicesWindsorInstaller.cs 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') diff --git a/win/CS/HandBrake.ApplicationServices/EventArgs/QueueCompletedEventArgs.cs b/win/CS/HandBrake.ApplicationServices/EventArgs/QueueCompletedEventArgs.cs deleted file mode 100644 index a98e784c3..000000000 --- a/win/CS/HandBrake.ApplicationServices/EventArgs/QueueCompletedEventArgs.cs +++ /dev/null @@ -1,38 +0,0 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// 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 HandBrake.ApplicationServices.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/HandBrake.ApplicationServices/EventArgs/QueueProgressEventArgs.cs b/win/CS/HandBrake.ApplicationServices/EventArgs/QueueProgressEventArgs.cs deleted file mode 100644 index 016b853fa..000000000 --- a/win/CS/HandBrake.ApplicationServices/EventArgs/QueueProgressEventArgs.cs +++ /dev/null @@ -1,37 +0,0 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// 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 HandBrake.ApplicationServices.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/HandBrake.ApplicationServices/EventArgs/SettingChangedEventArgs.cs b/win/CS/HandBrake.ApplicationServices/EventArgs/SettingChangedEventArgs.cs deleted file mode 100644 index 2687508b2..000000000 --- a/win/CS/HandBrake.ApplicationServices/EventArgs/SettingChangedEventArgs.cs +++ /dev/null @@ -1,27 +0,0 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// 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 HandBrake.ApplicationServices.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/HandBrake.ApplicationServices/HandBrake.ApplicationServices.csproj b/win/CS/HandBrake.ApplicationServices/HandBrake.ApplicationServices.csproj index 7b0c96fd8..bb00bc266 100644 --- a/win/CS/HandBrake.ApplicationServices/HandBrake.ApplicationServices.csproj +++ b/win/CS/HandBrake.ApplicationServices/HandBrake.ApplicationServices.csproj @@ -88,10 +88,7 @@ - - - @@ -216,10 +213,8 @@ - - @@ -249,14 +244,11 @@ True Resources.resx - - - diff --git a/win/CS/HandBrake.ApplicationServices/Services/Interfaces/IQueueProcessor.cs b/win/CS/HandBrake.ApplicationServices/Services/Interfaces/IQueueProcessor.cs deleted file mode 100644 index 4e5b51d93..000000000 --- a/win/CS/HandBrake.ApplicationServices/Services/Interfaces/IQueueProcessor.cs +++ /dev/null @@ -1,184 +0,0 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// 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 HandBrake.ApplicationServices.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/HandBrake.ApplicationServices/Services/Interfaces/IServerService.cs b/win/CS/HandBrake.ApplicationServices/Services/Interfaces/IServerService.cs deleted file mode 100644 index 367555418..000000000 --- a/win/CS/HandBrake.ApplicationServices/Services/Interfaces/IServerService.cs +++ /dev/null @@ -1,96 +0,0 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. -// -// -// Defines the IServerService type. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace HandBrake.ApplicationServices.Services.Interfaces -{ - using System.Runtime.Serialization; - using System.ServiceModel; - - using HandBrake.ApplicationServices.Model; - - /// - /// The HandBrakeService interface. - /// - [ServiceContract(CallbackContract = typeof(IHbServiceCallback), SessionMode = SessionMode.Required)] - public interface IServerService - { - /// - /// Gets the activity log. - /// - [DataMember] - string EncodeActivityLog { get; } - - /// - /// Gets a value indicating whether is encoding. - /// - bool IsEncoding - { - [OperationContract] - get; - } - - /// - /// Start the WCF Service - /// - /// - /// The port. - /// - void Start(string port); - - /// - /// Stop the WCF Service - /// - void Stop(); - - /// - /// Start and Encode - /// - /// - /// The job. - /// - [OperationContract] - void StartEncode(QueueTask job); - - /// - /// The process encode logs. - /// - /// - /// The destination. - /// - /// - /// The configuration. - /// - [OperationContract] - void ProcessEncodeLogs(string destination, HBConfiguration configuration); - - /// - /// Stop and Encode - /// - [OperationContract] - void StopEncode(); - - /// - /// Subscribe for callbacks from the called functions - /// - /// - /// The System.Boolean. - /// - [OperationContract] - bool Subscribe(); - - /// - /// Unsubscribe from callbacks. - /// - /// - /// The System.Boolean. - /// - [OperationContract] - bool Unsubscribe(); - } -} \ No newline at end of file diff --git a/win/CS/HandBrake.ApplicationServices/Services/QueueProcessor.cs b/win/CS/HandBrake.ApplicationServices/Services/QueueProcessor.cs deleted file mode 100644 index ba6a3a92e..000000000 --- a/win/CS/HandBrake.ApplicationServices/Services/QueueProcessor.cs +++ /dev/null @@ -1,602 +0,0 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// 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 HandBrake.ApplicationServices.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.EventArgs; - using HandBrake.ApplicationServices.Exceptions; - using HandBrake.ApplicationServices.Model; - using HandBrake.ApplicationServices.Services.Encode.EventArgs; - using HandBrake.ApplicationServices.Services.Encode.Interfaces; - using HandBrake.ApplicationServices.Services.Interfaces; - using HandBrake.ApplicationServices.Utilities; - - /// - /// 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"); - } - - 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 (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/HandBrake.ApplicationServices/Services/ServerService.cs b/win/CS/HandBrake.ApplicationServices/Services/ServerService.cs deleted file mode 100644 index d0f1b6a99..000000000 --- a/win/CS/HandBrake.ApplicationServices/Services/ServerService.cs +++ /dev/null @@ -1,296 +0,0 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. -// -// -// HandBrake WCF Service -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace HandBrake.ApplicationServices.Services -{ - using System; - using System.Collections.Generic; - using System.ServiceModel; - using System.Threading; - - using HandBrake.ApplicationServices.Model; - using HandBrake.ApplicationServices.Services.Encode; - using HandBrake.ApplicationServices.Services.Encode.EventArgs; - using HandBrake.ApplicationServices.Services.Encode.Interfaces; - using HandBrake.ApplicationServices.Services.Interfaces; - - /// - /// HandBrake WCF Service - /// - [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, IncludeExceptionDetailInFaults = true, ConcurrencyMode = ConcurrencyMode.Single)] - public class ServerService : IServerService - { - #region Constants and Fields - - /// - /// List of connected Clients. For now, this should only be one. - /// - private static readonly List Subscribers = new List(); - - /// - /// The encode service. - /// - private static IEncode encodeService; - - /// - /// The host. - /// - private static ServiceHost host; - - /// - /// The shutdown flag. - /// - private static ManualResetEvent shutdownFlag; - - #endregion - - #region Properties - - /// - /// Gets the activity log. - /// - public string EncodeActivityLog { get; private set; } - - /// - /// Gets a value indicating whether is encoding. - /// - public bool IsEncoding { get; private set; } - - /// - /// Gets the activity log. - /// - public string ScanActivityLog { get; private set; } - - #endregion - - #region Implemented Interfaces - - #region IServerService - - /// - /// The process encode logs. - /// - /// - /// The destination. - /// - /// - /// The configuration. - /// - public void ProcessEncodeLogs(string destination, HBConfiguration configuration) - { - encodeService.ProcessLogs(destination, configuration); - } - - /// - /// Start the service - /// - /// - /// The port. - /// - public void Start(string port) - { - using (host = new ServiceHost(typeof(ServerService), new Uri(string.Format("net.tcp://127.0.0.1:{0}", port)))) - { - // Setup a listener - host.AddServiceEndpoint(typeof(IServerService), new NetTcpBinding(), "IHbService"); - host.Open(); - Console.WriteLine("::: HandBrake Isolation Server - Debug Console:::"); - Console.WriteLine("Service Started. Waiting for Clients..."); - - // Setup the services we are going to use. - encodeService = new LibEncode(); - shutdownFlag = new ManualResetEvent(false); - shutdownFlag.WaitOne(); - } - } - - /// - /// Start and Encode - /// - /// - /// The job. - /// - public void StartEncode(QueueTask job) - { - Console.WriteLine("Starting Source Encode for: " + job.Task.Source); - encodeService.EncodeCompleted += this.EncodeServiceEncodeCompleted; - encodeService.EncodeStarted += this.encodeService_EncodeStarted; - encodeService.EncodeStatusChanged += this.encodeService_EncodeStatusChanged; - encodeService.Start(job); - } - - /// - /// Stop this service - /// - public void Stop() - { - if (host != null) - { - host.BeginClose(null, null); - // host.Abort(); - shutdownFlag.Set(); - } - } - - /// - /// Stop and Encode - /// - public void StopEncode() - { - encodeService.Stop(); - } - - /// - /// The subscribe. - /// - /// - /// The System.Boolean. - /// - public bool Subscribe() - { - try - { - // Get the hashCode of the connecting app and store it as a connection - var callback = OperationContext.Current.GetCallbackChannel(); - if (!Subscribers.Contains(callback)) - { - Console.WriteLine("Client Connected"); - Subscribers.Add(callback); - } - return true; - } - catch (Exception e) - { - Console.WriteLine(e.Message); - return false; - } - } - - /// - /// The unsubscribe. - /// - /// - /// The System.Boolean. - /// - public bool Unsubscribe() - { - try - { - var callback = OperationContext.Current.GetCallbackChannel(); - if (Subscribers.Contains(callback)) - { - Subscribers.Remove(callback); - if (Subscribers.Count == 0) - { - Console.WriteLine("Client Disconnected, Shutting down..."); - - // Shutdown the service. We no longer have any clients to serve. - // It is the responsibility of the UI to maintain a subscription while this service is in use. - this.Stop(); - } - } - return true; - } - catch - { - return false; - } - } - - #endregion - - #endregion - - #region Methods - - /// - /// The encode service_ encode completed. - /// - /// - /// The sender. - /// - /// - /// The e. - /// - private void EncodeServiceEncodeCompleted(object sender, EncodeCompletedEventArgs e) - { - encodeService.EncodeCompleted -= this.EncodeServiceEncodeCompleted; - encodeService.EncodeStarted -= this.encodeService_EncodeStarted; - encodeService.EncodeStatusChanged -= this.encodeService_EncodeStatusChanged; - - Subscribers.ForEach( - delegate(IHbServiceCallback callback) - { - if (((ICommunicationObject)callback).State == CommunicationState.Opened) - { - Console.WriteLine("Encode Completed Callback"); - callback.EncodeCompletedCallback(e); - } - else - { - Subscribers.Remove(callback); - } - }); - } - - /// - /// The encode service_ encode started. - /// - /// - /// The sender. - /// - /// - /// The e. - /// - private void encodeService_EncodeStarted(object sender, EventArgs e) - { - Subscribers.ForEach( - delegate(IHbServiceCallback callback) - { - if (((ICommunicationObject)callback).State == CommunicationState.Opened) - { - Console.WriteLine("Encode Started Callback"); - callback.EncodeStartedCallback(); - } - else - { - Subscribers.Remove(callback); - } - }); - } - - /// - /// The encode service_ encode status changed. - /// - /// - /// The sender. - /// - /// - /// The e. - /// - private void encodeService_EncodeStatusChanged(object sender, EncodeProgressEventArgs e) - { - Subscribers.ForEach( - delegate(IHbServiceCallback callback) - { - if (((ICommunicationObject)callback).State == CommunicationState.Opened) - { - Console.WriteLine("Encode Status Callback"); - callback.EncodeProgressCallback(e); - } - else - { - Subscribers.Remove(callback); - } - }); - } - - #endregion - } -} \ No newline at end of file diff --git a/win/CS/HandBrake.ApplicationServices/ServicesWindsorInstaller.cs b/win/CS/HandBrake.ApplicationServices/ServicesWindsorInstaller.cs deleted file mode 100644 index 72b32ef7f..000000000 --- a/win/CS/HandBrake.ApplicationServices/ServicesWindsorInstaller.cs +++ /dev/null @@ -1,37 +0,0 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. -// -// -// The Windsor Installer Interface Implementation -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace HandBrake.ApplicationServices -{ - using Castle.MicroKernel.Registration; - using Castle.MicroKernel.SubSystems.Configuration; - using Castle.Windsor; - - using HandBrake.ApplicationServices.Services; - using HandBrake.ApplicationServices.Services.Interfaces; - - /// - /// An Implimentation of IWindsorInstaller for this library. - /// - public class ServicesWindsorInstaller : IWindsorInstaller - { - #region Implementation of IWindsorInstaller - - /// - /// Performs the installation in the . - /// - /// The container.The configuration store. - public void Install(IWindsorContainer container, IConfigurationStore store) - { - container.Register(Component.For().ImplementedBy()); - } - - #endregion - } -} 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