From 69d24d74273fde9bb4c790755c95575b4e6c3c0c Mon Sep 17 00:00:00 2001 From: sr55 Date: Sun, 7 Aug 2011 21:31:14 +0000 Subject: WinGui: Change the Queue to work in the same way as the Mac/Lin Queue. Retain Completed jobs and mark them as such. - Added option to clear completed jobs. - Added option to re-encode a completed/errored job. - In-progress/Waiting jobs get saved into queue recovery. git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@4161 b64f7644-9d1e-0410-96f1-a4d463321fa5 --- win/CS/Functions/Main.cs | 2 +- .../HandBrake.ApplicationServices.csproj | 1 + .../Model/QueueItemStatus.cs | 30 ++++++++++ .../Model/QueueTask.cs | 17 ++++++ .../Services/Encode.cs | 19 +++++-- .../Services/Interfaces/IQueueManager.cs | 13 +++++ .../Services/QueueManager.cs | 60 ++++++++++++++++++-- .../Services/QueueProcessor.cs | 16 +++++- win/CS/frmQueue.Designer.cs | 42 +++++++++++--- win/CS/frmQueue.cs | 66 +++++++++++++++++++++- 10 files changed, 243 insertions(+), 23 deletions(-) create mode 100644 win/CS/HandBrake.ApplicationServices/Model/QueueItemStatus.cs diff --git a/win/CS/Functions/Main.cs b/win/CS/Functions/Main.cs index 2775b8064..9aa5afdc4 100644 --- a/win/CS/Functions/Main.cs +++ b/win/CS/Functions/Main.cs @@ -412,7 +412,7 @@ namespace Handbrake.Functions return queueFiles; } - catch (Exception) + catch (Exception exc) { return new List(); // Keep quiet about the error. } diff --git a/win/CS/HandBrake.ApplicationServices/HandBrake.ApplicationServices.csproj b/win/CS/HandBrake.ApplicationServices/HandBrake.ApplicationServices.csproj index 55fa4a380..52906af73 100644 --- a/win/CS/HandBrake.ApplicationServices/HandBrake.ApplicationServices.csproj +++ b/win/CS/HandBrake.ApplicationServices/HandBrake.ApplicationServices.csproj @@ -107,6 +107,7 @@ + diff --git a/win/CS/HandBrake.ApplicationServices/Model/QueueItemStatus.cs b/win/CS/HandBrake.ApplicationServices/Model/QueueItemStatus.cs new file mode 100644 index 000000000..774d0a788 --- /dev/null +++ b/win/CS/HandBrake.ApplicationServices/Model/QueueItemStatus.cs @@ -0,0 +1,30 @@ +/* QueueItemStatus.cs $ + This file is part of the HandBrake source code. + Homepage: . + It may be used under the terms of the GNU General Public License. */ + +namespace HandBrake.ApplicationServices.Model +{ + using System.ComponentModel; + + using HandBrake.ApplicationServices.Converters; + + /// + /// Queue Item Status + /// + [TypeConverter(typeof(EnumToDescConveter))] + public enum QueueItemStatus + { + [Description("Waiting")] + Waiting = 0, + + [Description("In Progress")] + InProgress, + + [Description("Completed")] + Completed, + + [Description("Error")] + Error, + } +} diff --git a/win/CS/HandBrake.ApplicationServices/Model/QueueTask.cs b/win/CS/HandBrake.ApplicationServices/Model/QueueTask.cs index 83948a1f3..aa71a2819 100644 --- a/win/CS/HandBrake.ApplicationServices/Model/QueueTask.cs +++ b/win/CS/HandBrake.ApplicationServices/Model/QueueTask.cs @@ -5,6 +5,8 @@ namespace HandBrake.ApplicationServices.Model { + using System; + /// /// The QueueTask. /// @@ -64,6 +66,21 @@ namespace HandBrake.ApplicationServices.Model /// public bool CustomQuery { get; set; } + /// + /// Gets or sets Status. + /// + public QueueItemStatus Status { get; set; } + + /// + /// Gets or sets StartTime. + /// + public DateTime StartTime { get; set; } + + /// + /// Gets or sets ElaspedEncodeTime. + /// + public TimeSpan ElaspedEncodeTime { get; set; } + /// /// Gets or sets the Encode Task. /// diff --git a/win/CS/HandBrake.ApplicationServices/Services/Encode.cs b/win/CS/HandBrake.ApplicationServices/Services/Encode.cs index 26708434f..953831732 100644 --- a/win/CS/HandBrake.ApplicationServices/Services/Encode.cs +++ b/win/CS/HandBrake.ApplicationServices/Services/Encode.cs @@ -40,6 +40,11 @@ namespace HandBrake.ApplicationServices.Services /// private DateTime startTime; + /// + /// The Current Task + /// + private QueueTask currentTask; + #endregion /// @@ -75,7 +80,7 @@ namespace HandBrake.ApplicationServices.Services { try { - QueueTask queueTask = encodeQueueTask; + this.currentTask = encodeQueueTask; if (this.IsEncoding) { @@ -88,7 +93,7 @@ namespace HandBrake.ApplicationServices.Services { try { - this.SetupLogging(queueTask); + this.SetupLogging(currentTask); } catch (Exception) { @@ -103,10 +108,10 @@ namespace HandBrake.ApplicationServices.Services } // Make sure the path exists, attempt to create it if it doesn't - this.VerifyEncodeDestinationPath(queueTask); + this.VerifyEncodeDestinationPath(currentTask); string handbrakeCLIPath = Path.Combine(Application.StartupPath, "HandBrakeCLI.exe"); - ProcessStartInfo cliStart = new ProcessStartInfo(handbrakeCLIPath, queueTask.Query) + ProcessStartInfo cliStart = new ProcessStartInfo(handbrakeCLIPath, currentTask.Query) { RedirectStandardOutput = true, RedirectStandardError = enableLogging ? true : false, @@ -164,7 +169,10 @@ namespace HandBrake.ApplicationServices.Services } catch (Exception exc) { - this.Invoke_encodeCompleted(new EncodeCompletedEventArgs(false, exc, "An Error occured when trying to encode this source. ")); + TimeSpan time = DateTime.Now.Subtract(this.currentTask.StartTime); + this.Invoke_encodeCompleted( + new EncodeCompletedEventArgs( + false, exc, "An Error occured when trying to encode this source. ")); } } @@ -266,6 +274,7 @@ namespace HandBrake.ApplicationServices.Services // This exception doesn't warrent user interaction, but it should be logged (TODO) } + this.currentTask.Status = QueueItemStatus.Completed; this.Invoke_encodeCompleted(new EncodeCompletedEventArgs(true, null, string.Empty)); } diff --git a/win/CS/HandBrake.ApplicationServices/Services/Interfaces/IQueueManager.cs b/win/CS/HandBrake.ApplicationServices/Services/Interfaces/IQueueManager.cs index 2c9005cfb..be87b3705 100644 --- a/win/CS/HandBrake.ApplicationServices/Services/Interfaces/IQueueManager.cs +++ b/win/CS/HandBrake.ApplicationServices/Services/Interfaces/IQueueManager.cs @@ -55,6 +55,19 @@ namespace HandBrake.ApplicationServices.Services.Interfaces /// void Remove(QueueTask job); + /// + /// Reset a Queued Item from Error or Completed to Waiting + /// + /// + /// The job. + /// + void ResetJobStatusToWaiting(QueueTask job); + + /// + /// 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 diff --git a/win/CS/HandBrake.ApplicationServices/Services/QueueManager.cs b/win/CS/HandBrake.ApplicationServices/Services/QueueManager.cs index ad56043ac..d8ebbf31e 100644 --- a/win/CS/HandBrake.ApplicationServices/Services/QueueManager.cs +++ b/win/CS/HandBrake.ApplicationServices/Services/QueueManager.cs @@ -13,6 +13,7 @@ namespace HandBrake.ApplicationServices.Services using System.Windows.Forms; using System.Xml.Serialization; + using HandBrake.ApplicationServices.Exceptions; using HandBrake.ApplicationServices.Model; using HandBrake.ApplicationServices.Services.Interfaces; @@ -114,7 +115,7 @@ namespace HandBrake.ApplicationServices.Services { get { - return this.queue.Count; + return this.queue.Where(item => item.Status == QueueItemStatus.Waiting).Count(); } } @@ -167,6 +168,35 @@ namespace HandBrake.ApplicationServices.Services } } + /// + /// 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; + } + + /// + /// Clear down the Queue´s completed items + /// + public void ClearCompleted() + { + 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 @@ -178,9 +208,14 @@ namespace HandBrake.ApplicationServices.Services { if (this.queue.Count > 0) { - QueueTask job = this.queue[0]; - this.LastProcessedJob = job; - this.Remove(job); // Remove the item which we are about to pass out. + QueueTask job = this.queue.FirstOrDefault(q => q.Status == QueueItemStatus.Waiting); + if (job != null) + { + job.Status = QueueItemStatus.InProgress; + job.StartTime = DateTime.Now; + this.LastProcessedJob = job; + InvokeQueueChanged(EventArgs.Empty); + } return job; } @@ -233,10 +268,12 @@ namespace HandBrake.ApplicationServices.Services string appDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"HandBrake\"); string tempPath = !string.IsNullOrEmpty(exportPath) ? exportPath : appDataPath + string.Format(this.queueFile, string.Empty); + using (FileStream strm = new FileStream(tempPath, FileMode.Create, FileAccess.Write)) { + List tasks = queue.Where(item => item.Status != QueueItemStatus.Completed).ToList(); XmlSerializer serializer = new XmlSerializer(typeof(List)); - serializer.Serialize(strm, queue); + serializer.Serialize(strm, tasks); strm.Close(); strm.Dispose(); } @@ -265,7 +302,18 @@ namespace HandBrake.ApplicationServices.Services if (list != null) foreach (QueueTask item in list) - this.queue.Add(item); + { + 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); + } + } this.InvokeQueueChanged(EventArgs.Empty); } diff --git a/win/CS/HandBrake.ApplicationServices/Services/QueueProcessor.cs b/win/CS/HandBrake.ApplicationServices/Services/QueueProcessor.cs index fe3eb8549..be9c46359 100644 --- a/win/CS/HandBrake.ApplicationServices/Services/QueueProcessor.cs +++ b/win/CS/HandBrake.ApplicationServices/Services/QueueProcessor.cs @@ -30,6 +30,7 @@ namespace HandBrake.ApplicationServices.Services /// The encode Service. /// /// + /// Services are not setup /// public QueueProcessor(IQueueManager queueManager, IEncode encodeService) { @@ -177,7 +178,6 @@ namespace HandBrake.ApplicationServices.Services /// public void Pause() { - this.EncodeService.EncodeCompleted -= this.EncodeServiceEncodeCompleted; this.InvokeQueuePaused(EventArgs.Empty); this.IsProcessing = false; } @@ -193,6 +193,8 @@ namespace HandBrake.ApplicationServices.Services /// private void EncodeServiceEncodeCompleted(object sender, EncodeCompletedEventArgs e) { + this.QueueManager.LastProcessedJob.Status = QueueItemStatus.Completed; + // Growl if (Properties.Settings.Default.GrowlEncode) GrowlCommunicator.Notify("Encode Completed", @@ -200,6 +202,7 @@ namespace HandBrake.ApplicationServices.Services if (!e.Successful) { + this.QueueManager.LastProcessedJob.Status = QueueItemStatus.Error; this.Pause(); throw new GeneralApplicationException(e.ErrorInformation, e.Exception.Message, e.Exception); } @@ -214,7 +217,16 @@ namespace HandBrake.ApplicationServices.Services } // Move onto the next job. - this.ProcessNextJob(); + if (this.IsProcessing) + { + this.ProcessNextJob(); + } + else + { + this.EncodeService.EncodeCompleted -= this.EncodeServiceEncodeCompleted; + this.InvokeQueueCompleted(EventArgs.Empty); + this.QueueManager.BackupQueue(string.Empty); + } } /// diff --git a/win/CS/frmQueue.Designer.cs b/win/CS/frmQueue.Designer.cs index 5a4924325..9beaf0a5e 100644 --- a/win/CS/frmQueue.Designer.cs +++ b/win/CS/frmQueue.Designer.cs @@ -54,6 +54,7 @@ namespace Handbrake this.toolStripButton1 = new System.Windows.Forms.ToolStripButton(); this.SaveFile = new System.Windows.Forms.SaveFileDialog(); this.list_queue = new System.Windows.Forms.ListView(); + this.Status = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.Title = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.Chapters = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.Source = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); @@ -67,6 +68,7 @@ namespace Handbrake this.mnu_edit = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator4 = new System.Windows.Forms.ToolStripSeparator(); this.mnu_delete = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuClearCompleted = new System.Windows.Forms.ToolStripMenuItem(); this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.lbl_encodesPending = new System.Windows.Forms.ToolStripStatusLabel(); this.OpenFile = new System.Windows.Forms.OpenFileDialog(); @@ -76,6 +78,7 @@ namespace Handbrake this.panel3 = new System.Windows.Forms.Panel(); this.panel2 = new System.Windows.Forms.Panel(); this.panel1 = new System.Windows.Forms.Panel(); + this.mnu_Retry = new System.Windows.Forms.ToolStripMenuItem(); this.toolStrip1.SuspendLayout(); this.mnu_queue.SuspendLayout(); this.statusStrip1.SuspendLayout(); @@ -257,6 +260,7 @@ namespace Handbrake // list_queue // this.list_queue.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.Status, this.Title, this.Chapters, this.Source, @@ -277,6 +281,11 @@ namespace Handbrake this.list_queue.View = System.Windows.Forms.View.Details; this.list_queue.KeyUp += new System.Windows.Forms.KeyEventHandler(this.ListQueueDeleteKey); // + // Status + // + this.Status.Text = "Job Status"; + this.Status.Width = 80; + // // Title // this.Title.Text = "Title"; @@ -314,49 +323,58 @@ namespace Handbrake this.mnu_Down, this.toolStripSeparator3, this.mnu_edit, + this.mnu_Retry, this.toolStripSeparator4, + this.mnuClearCompleted, this.mnu_delete}); this.mnu_queue.Name = "mnu_queue"; - this.mnu_queue.Size = new System.Drawing.Size(139, 104); + this.mnu_queue.Size = new System.Drawing.Size(164, 148); // // mnu_up // this.mnu_up.Name = "mnu_up"; - this.mnu_up.Size = new System.Drawing.Size(138, 22); + this.mnu_up.Size = new System.Drawing.Size(163, 22); this.mnu_up.Text = "Move Up"; this.mnu_up.Click += new System.EventHandler(this.MnuUpClick); // // mnu_Down // this.mnu_Down.Name = "mnu_Down"; - this.mnu_Down.Size = new System.Drawing.Size(138, 22); + this.mnu_Down.Size = new System.Drawing.Size(163, 22); this.mnu_Down.Text = "Move Down"; this.mnu_Down.Click += new System.EventHandler(this.MnuDownClick); // // toolStripSeparator3 // this.toolStripSeparator3.Name = "toolStripSeparator3"; - this.toolStripSeparator3.Size = new System.Drawing.Size(135, 6); + this.toolStripSeparator3.Size = new System.Drawing.Size(160, 6); // // mnu_edit // this.mnu_edit.Name = "mnu_edit"; - this.mnu_edit.Size = new System.Drawing.Size(138, 22); + this.mnu_edit.Size = new System.Drawing.Size(163, 22); this.mnu_edit.Text = "Edit"; this.mnu_edit.Click += new System.EventHandler(this.MnuEditClick); // // toolStripSeparator4 // this.toolStripSeparator4.Name = "toolStripSeparator4"; - this.toolStripSeparator4.Size = new System.Drawing.Size(135, 6); + this.toolStripSeparator4.Size = new System.Drawing.Size(160, 6); // // mnu_delete // this.mnu_delete.Name = "mnu_delete"; - this.mnu_delete.Size = new System.Drawing.Size(138, 22); + this.mnu_delete.Size = new System.Drawing.Size(163, 22); this.mnu_delete.Text = "Delete"; this.mnu_delete.Click += new System.EventHandler(this.MnuDeleteClick); // + // mnuClearCompleted + // + this.mnuClearCompleted.Name = "mnuClearCompleted"; + this.mnuClearCompleted.Size = new System.Drawing.Size(163, 22); + this.mnuClearCompleted.Text = "Clear Completed"; + this.mnuClearCompleted.Click += new System.EventHandler(this.mnuClearCompleted_Click); + // // statusStrip1 // this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -459,6 +477,13 @@ namespace Handbrake this.panel1.Size = new System.Drawing.Size(15, 214); this.panel1.TabIndex = 0; // + // mnu_Retry + // + this.mnu_Retry.Name = "mnu_Retry"; + this.mnu_Retry.Size = new System.Drawing.Size(163, 22); + this.mnu_Retry.Text = "Retry Encode"; + this.mnu_Retry.Click += new System.EventHandler(this.mnu_Retry_Click); + // // frmQueue // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -531,5 +556,8 @@ namespace Handbrake private System.Windows.Forms.ToolStripComboBox drp_completeOption; private System.Windows.Forms.ToolStripButton toolStripButton1; private System.Windows.Forms.Panel panel3; + private System.Windows.Forms.ColumnHeader Status; + private System.Windows.Forms.ToolStripMenuItem mnuClearCompleted; + private System.Windows.Forms.ToolStripMenuItem mnu_Retry; } } diff --git a/win/CS/frmQueue.cs b/win/CS/frmQueue.cs index 6bc7081f5..94c7cebd0 100644 --- a/win/CS/frmQueue.cs +++ b/win/CS/frmQueue.cs @@ -47,6 +47,9 @@ namespace Handbrake /// private readonly frmMain mainWindow; + /// + /// The User setting service + /// private readonly IUserSettingService userSettingService = new UserSettingService(); /// @@ -137,6 +140,8 @@ namespace Handbrake return; } + this.queue.QueueManager.LastProcessedJob.ElaspedEncodeTime = e.ElapsedTime; + lbl_encodeStatus.Text = 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}", @@ -299,6 +304,7 @@ namespace Handbrake btn_pause.Visible = false; btn_encode.Enabled = true; + this.RedrawQueue(); ResetEncodeText(); } @@ -353,7 +359,9 @@ namespace Handbrake chapters = chapters + " - " + parsed.EndPoint; } - ListViewItem item = new ListViewItem { Tag = queueItem, Text = title }; + ListViewItem item = new ListViewItem + { Tag = queueItem, Text = EnumHelper.GetDescription(queueItem.Status) }; + item.SubItems.Add(title); item.SubItems.Add(chapters); // Chapters item.SubItems.Add(queueItem.Source); // Source item.SubItems.Add(queueItem.Destination); // Destination @@ -389,6 +397,9 @@ namespace Handbrake UpdateStatusLabel(); } + /// + /// Update the Display + /// private void UpdateStatusLabel() { if (InvokeRequired) @@ -397,7 +408,7 @@ namespace Handbrake return; } - lbl_encodesPending.Text = string.Format("{0} encodes(s) pending", list_queue.Items.Count); + lbl_encodesPending.Text = string.Format("{0} encodes(s) pending", this.queue.QueueManager.Count); } /// @@ -718,5 +729,56 @@ namespace Handbrake { userSettingService.SetUserSetting(UserSettingConstants.WhenCompleteAction, drp_completeOption.Text); } + + /// + /// Clear all completed items + /// + /// + /// The sender. + /// + /// + /// The e. + /// + private void mnuClearCompleted_Click(object sender, EventArgs e) + { + this.queue.QueueManager.ClearCompleted(); + } + + /// + /// Retry Job Menu Item + /// + /// + /// The sender. + /// + /// + /// The e. + /// + private void mnu_Retry_Click(object sender, EventArgs e) + { + if (list_queue.SelectedIndices.Count != 0) + { + lock (queue) + { + lock (list_queue) + { + QueueTask index = list_queue.SelectedItems[0].Tag as QueueTask; + + try + { + queue.QueueManager.ResetJobStatusToWaiting(index); + } + catch (Exception) + { + MessageBox.Show( + "Can only retry a job if it is in an Error or Completed state.", + "Notice", + MessageBoxButtons.OK, + MessageBoxIcon.Information); + } + RedrawQueue(); + } + } + } + } } } \ No newline at end of file -- cgit v1.2.3