OSDN Git Service

5edbf39b05d753cbc6816eebc4b8e4eb77cab191
[handbrake-jp/handbrake-jp-git.git] / win / C# / HandBrake.ApplicationServices / Services / QueueManager.cs
1 namespace HandBrake.ApplicationServices.Services\r
2 {\r
3     using System;\r
4     using System.Collections.Generic;\r
5     using System.Collections.ObjectModel;\r
6     using System.IO;\r
7     using System.Linq;\r
8     using System.Windows.Forms;\r
9     using System.Xml.Serialization;\r
10 \r
11     using HandBrake.ApplicationServices.Model;\r
12     using HandBrake.ApplicationServices.Services.Interfaces;\r
13 \r
14     using EventArgs = System.EventArgs;\r
15 \r
16     /// <summary>\r
17     /// The Queue Manager.\r
18     /// Thread Safe.\r
19     /// </summary>\r
20     public class QueueManager : IQueueManager\r
21     {\r
22         /*\r
23          * TODO\r
24          * - Rewrite the batch script generator. \r
25          */\r
26 \r
27         #region Private Variables\r
28 \r
29         /// <summary>\r
30         /// A Lock object to maintain thread safety\r
31         /// </summary>\r
32         static readonly object QueueLock = new object();\r
33 \r
34         /// <summary>\r
35         /// The Queue of Job objects\r
36         /// </summary>\r
37         private readonly List<QueueTask> queue = new List<QueueTask>();\r
38 \r
39         /// <summary>\r
40         /// HandBrakes Queue file with a place holder for an extra string.\r
41         /// </summary>\r
42         private readonly string queueFile;\r
43 \r
44         /// <summary>\r
45         /// The ID of the job last added\r
46         /// </summary>\r
47         private int lastJobId;\r
48 \r
49         /// <summary>\r
50         /// The instance Id of this HandBrake instance.\r
51         /// </summary>\r
52         private int instanceId;\r
53 \r
54         #endregion\r
55 \r
56         /// <summary>\r
57         /// Initializes a new instance of the <see cref="QueueManager"/> class.\r
58         /// </summary>\r
59         /// <param name="instanceId">\r
60         /// The instance Id.\r
61         /// </param>\r
62         public QueueManager(int instanceId)\r
63         {\r
64             this.instanceId = instanceId;\r
65 \r
66             // If this is the first instance, just use the main queue file, otherwise add the instance id to the filename.\r
67             this.queueFile = instanceId == 0 ? "hb_queue_recovery.xml" : string.Format("hb_queue_recovery{0}.xml", instanceId);\r
68         }\r
69 \r
70         #region Events\r
71         /// <summary>\r
72         /// Fires when a job is Added, Removed or Re-Ordered.\r
73         /// Should be used for triggering an update of the Queue Window.\r
74         /// </summary>\r
75         public event EventHandler QueueChanged;\r
76 \r
77         /// <summary>\r
78         /// Invoke the Queue Changed Event\r
79         /// </summary>\r
80         /// <param name="e">\r
81         /// The e.\r
82         /// </param>\r
83         private void InvokeQueueChanged(EventArgs e)\r
84         {\r
85             try\r
86             {\r
87                 this.BackupQueue(string.Empty);\r
88             }\r
89             catch (Exception)\r
90             {\r
91                 // Do Nothing.\r
92             }\r
93 \r
94             EventHandler handler = this.QueueChanged;\r
95             if (handler != null)\r
96             {\r
97                 handler(this, e);\r
98             }\r
99         }\r
100 \r
101         #endregion\r
102 \r
103         #region Public Properties\r
104 \r
105         /// <summary>\r
106         /// Gets or sets Last Processed Job.\r
107         /// This is set when the job is poped of the queue by GetNextJobForProcessing();\r
108         /// </summary>\r
109         public QueueTask LastProcessedJob { get; set; }\r
110 \r
111         /// <summary>\r
112         /// Gets the number of jobs in the queue;\r
113         /// </summary>\r
114         public int Count\r
115         {\r
116             get\r
117             {\r
118                 return this.queue.Count;\r
119             }\r
120         }\r
121 \r
122         /// <summary>\r
123         /// Gets The current queue.\r
124         /// </summary>\r
125         public ReadOnlyCollection<QueueTask> Queue\r
126         {\r
127             get\r
128             {\r
129                 return this.queue.AsReadOnly();\r
130             }\r
131         }\r
132 \r
133         #endregion\r
134 \r
135         #region Public Methods\r
136 \r
137         /// <summary>\r
138         /// Add a job to the Queue. \r
139         /// This method is Thread Safe.\r
140         /// </summary>\r
141         /// <param name="job">\r
142         /// The encode Job object.\r
143         /// </param>\r
144         public void Add(QueueTask job)\r
145         {\r
146             lock (QueueLock)\r
147             {\r
148                 // Tag the job with an ID\r
149                 job.Id = lastJobId++;\r
150                 queue.Add(job);\r
151                 InvokeQueueChanged(EventArgs.Empty);\r
152             }\r
153         }\r
154 \r
155         /// <summary>\r
156         /// Remove a job from the Queue.\r
157         /// This method is Thread Safe\r
158         /// </summary>\r
159         /// <param name="job">\r
160         /// The job.\r
161         /// </param>\r
162         public void Remove(QueueTask job)\r
163         {\r
164             lock (QueueLock)\r
165             {\r
166                 // Tag the job with an ID\r
167                 job.Id = lastJobId++;\r
168                 queue.Add(job);\r
169                 InvokeQueueChanged(EventArgs.Empty);\r
170             }\r
171         }\r
172 \r
173         /// <summary>\r
174         /// Get the first job on the queue for processing.\r
175         /// This also removes the job from the Queue and sets the LastProcessedJob\r
176         /// </summary>\r
177         /// <returns>\r
178         /// An encode Job object.\r
179         /// </returns>\r
180         public QueueTask GetNextJobForProcessing()\r
181         {\r
182             if (this.queue.Count > 0)\r
183             {\r
184                 QueueTask job = this.queue[0];\r
185                 this.LastProcessedJob = job;\r
186                 this.Remove(job); // Remove the item which we are about to pass out.\r
187 \r
188                 return job;  \r
189             }\r
190 \r
191             return null;\r
192         }\r
193 \r
194         /// <summary>\r
195         /// Moves an item up one position in the queue.\r
196         /// </summary>\r
197         /// <param name="index">The zero-based location of the job in the queue.</param>\r
198         public void MoveUp(int index)\r
199         {\r
200             if (index > 0)\r
201             {\r
202                 QueueTask item = queue[index];\r
203 \r
204                 queue.RemoveAt(index);\r
205                 queue.Insert((index - 1), item);\r
206             }\r
207 \r
208             this.InvokeQueueChanged(EventArgs.Empty);\r
209         }\r
210 \r
211         /// <summary>\r
212         /// Moves an item down one position in the queue.\r
213         /// </summary>\r
214         /// <param name="index">The zero-based location of the job in the queue.</param>\r
215         public void MoveDown(int index)\r
216         {\r
217             if (index < this.queue.Count - 1)\r
218             {\r
219                 QueueTask item = this.queue[index];\r
220 \r
221                 this.queue.RemoveAt(index);\r
222                 this.queue.Insert((index + 1), item);\r
223             }\r
224 \r
225             this.InvokeQueueChanged(EventArgs.Empty);\r
226         }\r
227 \r
228         /// <summary>\r
229         /// Backup any changes to the queue file\r
230         /// </summary>\r
231         /// <param name="exportPath">\r
232         /// If this is not null or empty, this will be used instead of the standard backup location.\r
233         /// </param>\r
234         public void BackupQueue(string exportPath)\r
235         {\r
236             string appDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"HandBrake\");\r
237             string tempPath = !string.IsNullOrEmpty(exportPath) ? exportPath : appDataPath + string.Format(this.queueFile, string.Empty);\r
238 \r
239             if (File.Exists(tempPath))\r
240             {\r
241                 using (FileStream strm = new FileStream(tempPath, FileMode.Create, FileAccess.Write))\r
242                 {\r
243                     XmlSerializer serializer = new XmlSerializer(typeof(List<QueueTask>));\r
244                     serializer.Serialize(strm, queue);\r
245                     strm.Close();\r
246                     strm.Dispose();\r
247                 }\r
248             }\r
249         }\r
250 \r
251         /// <summary>\r
252         /// Restore a Queue from file or from the queue backup file.\r
253         /// </summary>\r
254         /// <param name="importPath">\r
255         /// The import path. String.Empty or null will result in the default file being loaded.\r
256         /// </param>\r
257         public void RestoreQueue(string importPath)\r
258         {\r
259             string appDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"HandBrake\");\r
260             string tempPath = !string.IsNullOrEmpty(importPath) ? importPath : (appDataPath + string.Format(this.queueFile, string.Empty));\r
261 \r
262             if (File.Exists(tempPath))\r
263             {\r
264                 using (FileStream strm = new FileStream((!string.IsNullOrEmpty(importPath) ? importPath : tempPath), FileMode.Open, FileAccess.Read))\r
265                 {\r
266                     if (strm.Length != 0)\r
267                     {\r
268                         XmlSerializer serializer = new XmlSerializer(typeof(List<QueueTask>));\r
269 \r
270                         List<QueueTask> list = serializer.Deserialize(strm) as List<QueueTask>;\r
271 \r
272                         if (list != null)\r
273                             foreach (QueueTask item in list)\r
274                                 this.queue.Add(item);\r
275 \r
276                         this.InvokeQueueChanged(EventArgs.Empty);\r
277                     }\r
278                 }\r
279             }\r
280         }\r
281 \r
282         /// <summary>\r
283         /// Checks the current queue for an existing instance of the specified destination.\r
284         /// </summary>\r
285         /// <param name="destination">The destination of the encode.</param>\r
286         /// <returns>Whether or not the supplied destination is already in the queue.</returns>\r
287         public bool CheckForDestinationPathDuplicates(string destination)\r
288         {\r
289             return this.queue.Any(checkItem => checkItem.Task.Destination.Contains(destination.Replace("\\\\", "\\")));\r
290         }\r
291 \r
292         /// <summary>\r
293         /// Writes the current state of the queue in the form of a batch (.bat) file.\r
294         /// </summary>\r
295         /// <param name="file">\r
296         /// The location of the file to write the batch file to.\r
297         /// </param>\r
298         /// <returns>\r
299         /// The write batch script to file.\r
300         /// </returns>\r
301         public bool WriteBatchScriptToFile(string file)\r
302         {\r
303             string queries = string.Empty;\r
304             foreach (QueueTask queueItem in this.queue)\r
305             {\r
306                 string qItem = queueItem.Query;\r
307                 string fullQuery = '"' + Application.StartupPath + "\\HandBrakeCLI.exe" + '"' + qItem;\r
308 \r
309                 if (queries == string.Empty)\r
310                     queries = queries + fullQuery;\r
311                 else\r
312                     queries = queries + " && " + fullQuery;\r
313             }\r
314             string strCmdLine = queries;\r
315 \r
316             if (file != string.Empty)\r
317             {\r
318                 try\r
319                 {\r
320                     // Create a StreamWriter and open the file, Write the batch file query to the file and \r
321                     // Close the stream\r
322                     using (StreamWriter line = new StreamWriter(file))\r
323                     {\r
324                         line.WriteLine(strCmdLine);\r
325                     }\r
326 \r
327                     return true;\r
328                 }\r
329                 catch (Exception exc)\r
330                 {\r
331                     throw new Exception("Unable to write to the file. Please make sure that the location has the correct permissions for file writing.", exc);\r
332                 }\r
333             }\r
334             return false;\r
335         }\r
336 \r
337         #endregion\r
338     }\r
339 }\r