source: trunk/eraser/Eraser.Manager/Task.cs @ 2543

Revision 2543, 10.0 KB checked in by lowjoel, 3 years ago (diff)

Tasks were not being cleared from the task list upon successful completion because they were reset to Manually executed tasks before returning to the Executor. This scheduling ability should be dealt with in the Executor and not the Task. Therefore, the Task Completion event will still have the schedule of the initial configuration, and not after the schedule has been reset to Manual. This allows context menu tasks which completed successfully to be cleared automatically.

Fixes bug in https://eraser.heidi.ie/forum/viewtopic.php?f=36&p=25922#p25922.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Rev URL
Line 
1/*
2 * $Id$
3 * Copyright 2008-2012 The Eraser Project
4 * Original Author: Joel Low <lowjoel@users.sourceforge.net>
5 * Modified By:
6 *
7 * This file is part of Eraser.
8 *
9 * Eraser is free software: you can redistribute it and/or modify it under the
10 * terms of the GNU General Public License as published by the Free Software
11 * Foundation, either version 3 of the License, or (at your option) any later
12 * version.
13 *
14 * Eraser is distributed in the hope that it will be useful, but WITHOUT ANY
15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17 *
18 * A copy of the GNU General Public License can be found at
19 * <http://www.gnu.org/licenses/>.
20 */
21
22using System;
23using System.Collections.Generic;
24using System.Text;
25using System.IO;
26using System.Runtime.Serialization;
27using System.Security.Permissions;
28using System.Threading;
29
30using Eraser.Util;
31using Eraser.Util.ExtensionMethods;
32using Eraser.Plugins;
33using Eraser.Plugins.ExtensionPoints;
34
35namespace Eraser.Manager
36{
37    /// <summary>
38    /// Deals with an erase task.
39    /// </summary>
40    [Serializable]
41    public class Task : ITask, ISerializable
42    {
43        #region Serialization code
44        protected Task(SerializationInfo info, StreamingContext context)
45        {
46            Name = (string)info.GetValue("Name", typeof(string));
47            Executor = context.Context as Executor;
48            Targets = (ErasureTargetCollection)info.GetValue("Targets", typeof(ErasureTargetCollection));
49            Targets.Owner = this;
50            Log = (List<LogSink>)info.GetValue("Log", typeof(List<LogSink>));
51            Canceled = false;
52
53            Schedule schedule = (Schedule)info.GetValue("Schedule", typeof(Schedule));
54            if (schedule.GetType() == Schedule.RunManually.GetType())
55                Schedule = Schedule.RunManually;
56            else if (schedule.GetType() == Schedule.RunNow.GetType())
57                Schedule = Schedule.RunNow;
58            else if (schedule.GetType() == Schedule.RunOnRestart.GetType())
59                Schedule = Schedule.RunOnRestart;
60            else if (schedule is RecurringSchedule)
61                Schedule = schedule;
62            else
63                throw new InvalidDataException(S._("An invalid type was found when loading " +
64                    "the task schedule"));
65        }
66
67        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
68        public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
69        {
70            info.AddValue("Name", Name);
71            info.AddValue("Schedule", Schedule);
72            info.AddValue("Targets", Targets);
73            info.AddValue("Log", Log);
74        }
75        #endregion
76
77        /// <summary>
78        /// Constructor.
79        /// </summary>
80        public Task()
81        {
82            Name = string.Empty;
83            Targets = new ErasureTargetCollection(this);
84            Schedule = Schedule.RunNow;
85            Canceled = false;
86            Log = new List<LogSink>();
87        }
88
89        /// <summary>
90        /// The Executor object which is managing this task.
91        /// </summary>
92        public Executor Executor
93        {
94            get
95            {
96                return executor;
97            }
98            internal set
99            {
100                if (executor != null && value != null)
101                    throw new InvalidOperationException("A task can only belong to one " +
102                        "executor at any one time");
103
104                executor = value;
105            }
106        }
107
108        /// <summary>
109        /// The name for this task. This is just an opaque value for the user to
110        /// recognize the task.
111        /// </summary>
112        public string Name { get; set; }
113
114        /// <summary>
115        /// The name of the task, used for display in UI elements.
116        /// </summary>
117        public override string ToString()
118        {
119            //Simple case, the task name was given by the user.
120            if (!string.IsNullOrEmpty(Name))
121                return Name;
122
123            string result = string.Empty;
124            if (Targets.Count == 0)
125                return result;
126            else if (Targets.Count < 5)
127            {
128                //Simpler case, small set of data.
129                foreach (IErasureTarget tgt in Targets)
130                    result += S._("{0}, ", tgt);
131
132                return result.Remove(result.Length - 2);
133            }
134            else
135            {
136                //Ok, we've quite a few entries, get the first, the mid and the end.
137                result = S._("{0}, ", Targets[0]);
138                result += S._("{0}, ", Targets[Targets.Count / 2]);
139                result += Targets[Targets.Count - 1];
140
141                return S._("{0} and {1} other targets", result, Targets.Count - 3);
142            }
143        }
144
145        /// <summary>
146        /// The set of data to erase when this task is executed.
147        /// </summary>
148        public ErasureTargetCollection Targets { get; private set; }
149
150        /// <summary>
151        /// <see cref="Targets"/>
152        /// </summary>
153        ICollection<IErasureTarget> ITask.Targets
154        {
155            get { return Targets; }
156        }
157
158        /// <summary>
159        /// The schedule for running the task.
160        /// </summary>
161        public Schedule Schedule
162        {
163            get
164            {
165                return schedule;
166            }
167            set
168            {
169                if (value.Owner != null)
170                    throw new ArgumentException("The schedule provided can only " +
171                        "belong to one task at a time");
172
173                if (schedule is RecurringSchedule)
174                    ((RecurringSchedule)schedule).Owner = null;
175                schedule = value;
176                if (schedule is RecurringSchedule)
177                    ((RecurringSchedule)schedule).Owner = this;
178                OnTaskEdited();
179            }
180        }
181
182        /// <summary>
183        /// The log entries which this task has accumulated.
184        /// </summary>
185        public List<LogSink> Log { get; private set; }
186
187        /// <summary>
188        /// The progress manager object which manages the progress of this task.
189        /// </summary>
190        public SteppedProgressManager Progress
191        {
192            get
193            {
194                if (!Executing)
195                    throw new InvalidOperationException("The progress of an erasure can only " +
196                        "be queried when the task is being executed.");
197
198                return progress;
199            }
200            private set
201            {
202                progress = value;
203            }
204        }
205
206        /// <summary>
207        /// Gets the status of the task - whether it is being executed.
208        /// </summary>
209        public bool Executing { get; private set; }
210
211        /// <summary>
212        /// Gets whether this task is currently queued to run. This is true only
213        /// if the queue it is in is an explicit request, i.e will run when the
214        /// executor is idle.
215        /// </summary>
216        public bool Queued
217        {
218            get
219            {
220                if (Executor == null)
221                    throw new InvalidOperationException();
222
223                return Executor.IsTaskQueued(this);
224            }
225        }
226
227        /// <summary>
228        /// Gets whether the task has been cancelled from execution.
229        /// </summary>
230        public bool Canceled
231        {
232            get;
233            private set;
234        }
235
236        /// <summary>
237        /// Cancels the task from running, or, if the task is queued for running,
238        /// removes the task from the queue.
239        /// </summary>
240        public void Cancel()
241        {
242            Executor.UnqueueTask(this);
243            Canceled = true;
244        }
245
246        /// <summary>
247        /// Executes the task in the context of the calling thread.
248        /// </summary>
249        public void Execute()
250        {
251            OnTaskStarted();
252            Executing = true;
253            Canceled = false;
254            Progress = new SteppedProgressManager();
255
256            try
257            {
258                //Run the task
259                foreach (IErasureTarget target in Targets)
260                    try
261                    {
262                        Progress.Steps.Add(new ErasureTargetProgressManagerStep(
263                            target, Targets.Count));
264                        target.Execute();
265                    }
266                    catch (FatalException)
267                    {
268                        throw;
269                    }
270                    catch (OperationCanceledException)
271                    {
272                        throw;
273                    }
274                    catch (SharingViolationException)
275                    {
276                    }
277            }
278            catch (FatalException e)
279            {
280                Logger.Log(e.Message, LogLevel.Fatal);
281            }
282            catch (OperationCanceledException e)
283            {
284                Logger.Log(e.Message, LogLevel.Fatal);
285            }
286            catch (SharingViolationException)
287            {
288            }
289            finally
290            {
291                //If the task is a recurring task, reschedule it since we are done.
292                if (Schedule is RecurringSchedule)
293                {
294                    ((RecurringSchedule)Schedule).Reschedule(DateTime.Now);
295                }
296
297                Progress = null;
298                Executing = false;
299                OnTaskFinished();
300            }
301        }
302
303        private Executor executor;
304        private Schedule schedule;
305        private SteppedProgressManager progress;
306
307        #region Events
308        /// <summary>
309        /// The task has been edited.
310        /// </summary>
311        public EventHandler TaskEdited { get; set; }
312
313        /// <summary>
314        /// The start of the execution of a task.
315        /// </summary>
316        public EventHandler TaskStarted { get; set; }
317
318        /// <summary>
319        /// The completion of the execution of a task.
320        /// </summary>
321        public EventHandler TaskFinished { get; set; }
322
323        /// <summary>
324        /// Broadcasts the task edited event.
325        /// </summary>
326        internal void OnTaskEdited()
327        {
328            if (TaskEdited != null)
329                TaskEdited(this, EventArgs.Empty);
330        }
331
332        /// <summary>
333        /// Broadcasts the task execution start event.
334        /// </summary>
335        private void OnTaskStarted()
336        {
337            if (TaskStarted != null)
338                TaskStarted(this, EventArgs.Empty);
339        }
340
341        /// <summary>
342        /// Broadcasts the task execution completion event.
343        /// </summary>
344        private void OnTaskFinished()
345        {
346            if (TaskFinished != null)
347                TaskFinished(this, EventArgs.Empty);
348        }
349        #endregion
350    }
351
352    /// <summary>
353    /// Returns the progress of an erasure target, since that comprises the
354    /// steps of the Task Progress.
355    /// </summary>
356    public class ErasureTargetProgressManagerStep : SteppedProgressManagerStepBase
357    {
358        /// <summary>
359        /// Constructor.
360        /// </summary>
361        /// <param name="target">The erasure target represented by this object.</param>
362        /// <param name="steps">The number of targets in the task.</param>
363        public ErasureTargetProgressManagerStep(IErasureTarget target, int targets)
364            : base(1.0f / targets)
365        {
366            Target = target;
367        }
368
369        public override ProgressManagerBase Progress
370        {
371            get
372            {
373                ProgressManagerBase targetProgress = Target.Progress;
374                if (targetProgress != null)
375                    TargetProgress = targetProgress;
376
377                return TargetProgress;
378            }
379            set
380            {
381                throw new InvalidOperationException();
382            }
383        }
384
385        /// <summary>
386        /// The erasure target represented by this step.
387        /// </summary>
388        public IErasureTarget Target
389        {
390            get;
391            private set;
392        }
393
394        /// <summary>
395        /// Caches a copy of the progress object for the Target. This is so that
396        /// for as long we our object is alive we can give valid information
397        /// (as required by the SteppedProgressManager class)
398        /// </summary>
399        private ProgressManagerBase TargetProgress;
400    }
401
402    /// <summary>
403    /// A base event class for all event arguments involving a task.
404    /// </summary>
405    public class TaskEventArgs : EventArgs
406    {
407        /// <summary>
408        /// Constructor.
409        /// </summary>
410        /// <param name="task">The task being referred to by this event.</param>
411        public TaskEventArgs(Task task)
412        {
413            Task = task;
414        }
415
416        /// <summary>
417        /// The executing task.
418        /// </summary>
419        public Task Task { get; private set; }
420    }
421}
Note: See TracBrowser for help on using the repository browser.