source: branches/eraser6/SpeedMeter/Eraser.Manager/ProgressManager.cs @ 1503

Revision 1503, 13.1 KB checked in by lowjoel, 5 years ago (diff)

Current revision finally compiles.
-Instead of having a separate class for stepped progress handlers, it occurred to me that when nesting we may not be nesting a SteppedProgressManagerStep? (e,g, the Task is a SteppedProgressManager? but the steps are not: they are SteppedProgressManagers? in their own right) so instead hold the step information in an external structure (SteppedProgressManager?.Step)
-Fixed the foreach loops in the ParallelProgressManager?.
-I wanted to get rid of the TaskProgressEventArgs? class, but looks like it can't be removed since certain things (like pass index and current file name) cannot be conveyed in the ProgressManager? classes.
-The OnProgressChanged? event for the Task object will have the currently running erasure target as the sender instead of the task
-The old abstract Progress field in the ErasureTarget? has been replaced with a simple variable (for now, just for convenience)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
3 * Copyright 2008-2009 The Eraser Project
4 * Original Author: Joel Low <lowjoel@users.sourceforge.net>
5 * Modified By: Kasra Nassiri <cjax@users.sourceforge.net> @17/10/2008
6 * Modified By:
7 *
8 * This file is part of Eraser.
9 *
10 * Eraser is free software: you can redistribute it and/or modify it under the
11 * terms of the GNU General Public License as published by the Free Software
12 * Foundation, either version 3 of the License, or (at your option) any later
13 * version.
14 *
15 * Eraser is distributed in the hope that it will be useful, but WITHOUT ANY
16 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
17 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 *
19 * A copy of the GNU General Public License can be found at
20 * <http://www.gnu.org/licenses/>.
21 */
22
23using System;
24using System.Collections.Generic;
25using System.Linq;
26using System.Text;
27
28namespace Eraser.Manager
29{
30    /// <summary>
31    /// Manages the progress for any operation.
32    /// </summary>
33    public abstract class ProgressManagerBase
34    {
35        /// <summary>
36        /// Records the starting time of the task. This allows the computation of
37        /// the estimated end time by extrapolating collected data based on the
38        /// amount of time already elapsed.
39        /// </summary>
40        public abstract void Start();
41
42        /// <summary>
43        /// Gets the percentage of the operation completed.
44        /// </summary>
45        public abstract float Progress
46        {
47            get;
48        }
49
50        /// <summary>
51        /// Computes the speed of the erase, in units of completion per second,
52        /// based on the information collected in the previous 15 seconds.
53        /// </summary>
54        public abstract int Speed
55        {
56            get;
57        }
58
59        /// <summary>
60        /// Calculates the estimated amount of time left based on the total
61        /// amount of information to erase and the current speed of the erase
62        /// </summary>
63        public abstract TimeSpan TimeLeft
64        {
65            get;
66        }
67    }
68
69    /// <summary>
70    /// Manages progress based only on one input, set through the Completed and Total
71    /// properties.
72    /// </summary>
73    public class ProgressManager : ProgressManagerBase
74    {
75        public override void Start()
76        {
77            startTime = DateTime.Now;
78        }
79
80        /// <summary>
81        /// Gets or sets the number of work units already completed.
82        /// </summary>
83        public long Completed
84        {
85            get;
86            set;
87        }
88
89        /// <summary>
90        /// Gets or sets the total number of work units that this task has.
91        /// </summary>
92        public long Total
93        {
94            get;
95            set;
96        }
97
98        public override float Progress
99        {
100            get
101            {
102                return (float)((double)Completed / Total);
103            }
104        }
105
106        public override int Speed
107        {
108            get
109            {
110                if (DateTime.Now == startTime)
111                    return 0;
112
113                if ((DateTime.Now - lastSpeedCalc).Seconds < 5 && lastSpeed != 0)
114                    return lastSpeed;
115
116                //Calculate how much time has passed
117                double timeElapsed = (DateTime.Now - lastSpeedCalc).TotalSeconds;
118                if (timeElapsed == 0.0)
119                    return 0;
120
121                //Then compute the speed of the calculation
122                lastSpeed = (int)((Completed - lastCompleted) / timeElapsed);
123                lastSpeedCalc = DateTime.Now;
124                lastCompleted = Completed;
125                return lastSpeed;
126            }
127        }
128
129        public override TimeSpan TimeLeft
130        {
131            get
132            {
133                if (Speed == 0)
134                    return TimeSpan.Zero;
135                return new TimeSpan(0, 0, (int)((Total - Completed) / Speed));
136            }
137        }
138
139        /// <summary>
140        /// The starting time of the operation, used to determine average speed.
141        /// </summary>
142        private DateTime startTime;
143
144        /// <summary>
145        /// The last time a speed calculation was computed so that speed is not
146        /// computed too often.
147        /// </summary>
148        private DateTime lastSpeedCalc;
149
150        /// <summary>
151        /// The amount of the operation completed at the last speed computation.
152        /// </summary>
153        private long lastCompleted;
154
155        /// <summary>
156        /// The last calculated speed of the operation.
157        /// </summary>
158        private int lastSpeed;
159    }
160
161    /// <summary>
162    /// Manages progress based on sub-tasks.
163    /// </summary>
164    public abstract class ChainedProgressManager : ProgressManagerBase
165    {
166        public override void Start()
167        {
168            StartTime = DateTime.Now;
169        }
170
171        /// <summary>
172        /// The time the process was started.
173        /// </summary>
174        protected DateTime StartTime
175        {
176            get;
177            private set;
178        }
179    }
180
181    /// <summary>
182    /// Manages progress based on sub-tasks, taking each sub-task to be a step
183    /// in which the next step will not be executed until the current step is
184    /// complete. Each step is also assign weights so that certain steps which
185    /// take more time are given a larger amount of progress-bar space for finer
186    /// grained progress reporting.
187    /// </summary>
188    public class SteppedProgressManager : ChainedProgressManager
189    {
190        /// <summary>
191        /// Represents one step in the list of steps to complete.
192        /// </summary>
193        public class Step
194        {
195            /// <summary>
196            /// Constructor.
197            /// </summary>
198            /// <param name="progress">The <see cref="ProgressManagerBase"/> instance
199            /// which measures the progress of this step.</param>
200            /// <param name="weight">The weight of this step. The weight is a decimal
201            /// number in the range [0.0, 1.0] which represents the percentage of the
202            /// entire process this particular step is.</param>
203            public Step(ProgressManagerBase progress, float weight)
204                : this(progress, weight, null)
205            {
206            }
207
208            /// <summary>
209            /// Constructor.
210            /// </summary>
211            /// <param name="progress">The <see cref="ProgressManagerBase"/> instance
212            /// which measures the progress of this step.</param>
213            /// <param name="weight">The weight of this step. The weight is a decimal
214            /// number in the range [0.0, 1.0] which represents the percentage of the
215            /// entire process this particular step is.</param>
216            /// <param name="name">A user-specified value of the name of this step.
217            /// This value is not used by the class at all.</param>
218            public Step(ProgressManagerBase progress, float weight, string name)
219            {
220                Progress = progress;
221                Weight = weight;
222                Name = name;
223            }
224
225            /// <summary>
226            /// The <see cref="ProgressManagerBase"/> instance which measures the
227            /// progress of the step.
228            /// </summary>
229            public ProgressManagerBase Progress
230            {
231                get;
232                set;
233            }
234
235            /// <summary>
236            /// The weight associated with this step.
237            /// </summary>
238            public float Weight
239            {
240                get;
241                private set;
242            }
243
244            /// <summary>
245            /// The name of this step.
246            /// </summary>
247            public string Name
248            {
249                get;
250                set;
251            }
252        }
253
254        /// <summary>
255        /// The class which manages the steps which comprise the overall progress.
256        /// </summary>
257        public class StepsList : IList<Step>
258        {
259            public StepsList(SteppedProgressManager manager)
260            {
261                List = new List<Step>();
262                Manager = manager;
263            }
264
265            #region IList<Step> Members
266
267            public int IndexOf(Step item)
268            {
269                return List.IndexOf(item);
270            }
271
272            public void Insert(int index, Step item)
273            {
274                List.Insert(index, item);
275                TotalWeights += item.Weight;
276            }
277
278            public void RemoveAt(int index)
279            {
280                TotalWeights -= List[index].Weight;
281                List.RemoveAt(index);
282            }
283
284            public Step this[int index]
285            {
286                get
287                {
288                    return List[index];
289                }
290                set
291                {
292                    TotalWeights -= List[index].Weight;
293                    List[index] = value;
294                    TotalWeights += value.Weight;
295                }
296            }
297
298            #endregion
299
300            #region ICollection<Step> Members
301
302            public void Add(Step item)
303            {
304                List.Add(item);
305                TotalWeights += item.Weight;
306            }
307
308            public void Clear()
309            {
310                List.Clear();
311                TotalWeights = 0;
312            }
313
314            public bool Contains(Step item)
315            {
316                return List.Contains(item);
317            }
318
319            public void CopyTo(Step[] array, int arrayIndex)
320            {
321                List.CopyTo(array, arrayIndex);
322            }
323
324            public int Count
325            {
326                get { return List.Count; }
327            }
328
329            public bool IsReadOnly
330            {
331                get { return false; }
332            }
333
334            public bool Remove(Step item)
335            {
336                int index = List.IndexOf(item);
337                if (index != -1)
338                    TotalWeights -= List[index].Weight;
339
340                return List.Remove(item);
341            }
342
343            #endregion
344
345            #region IEnumerable<Step> Members
346
347            public IEnumerator<Step> GetEnumerator()
348            {
349                return List.GetEnumerator();
350            }
351
352            #endregion
353
354            #region IEnumerable Members
355
356            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
357            {
358                return List.GetEnumerator();
359            }
360
361            #endregion
362
363            /// <summary>
364            /// The total weights of all the steps.
365            /// </summary>
366            public float TotalWeights
367            {
368                get
369                {
370                    return totalWeights;
371                }
372                private set
373                {
374                    if (value > 1.0f || value < 0.0f)
375                        throw new ArgumentOutOfRangeException("The total weights of all steps in " +
376                            "the task must be within the range [0.0, 1.0]");
377
378                    totalWeights = value;
379                }
380            }
381
382            /// <summary>
383            /// The list storing the steps for this instance.
384            /// </summary>
385            private List<Step> List;
386
387            /// <summary>
388            /// The <see cref="SteppedProgressManager"/> instance which owns this list.
389            /// </summary>
390            private SteppedProgressManager Manager;
391
392            /// <summary>
393            /// The backing variable for the total weights of all the steps.
394            /// </summary>
395            private float totalWeights;
396        }
397
398        /// <summary>
399        /// Constructor.
400        /// </summary>
401        public SteppedProgressManager()
402        {
403            Steps = new StepsList(this);
404        }
405
406        public override float Progress
407        {
408            get
409            {
410                float totalWeight = (float)Steps.TotalWeights;
411                float result = 0.0f;
412
413                foreach (Step step in Steps)
414                    result += step.Progress.Progress * step.Weight;
415
416                return result;
417            }
418        }
419
420        public override int Speed
421        {
422            get
423            {
424                return CurrentStep.Progress.Speed;
425            }
426        }
427
428        public override TimeSpan TimeLeft
429        {
430            get
431            {
432                long ticksElapsed = (DateTime.Now - StartTime).Ticks;
433                float progressRemaining = 1.0f - Progress;
434                return new TimeSpan((long)
435                    (progressRemaining * (ticksElapsed / (double)Progress)));
436            }
437        }
438
439        /// <summary>
440        /// The list of steps involved in completion of the task.
441        /// </summary>
442        public StepsList Steps
443        {
444            get;
445            private set;
446        }
447
448        /// <summary>
449        /// Gets the current step which is executing. This property is null if
450        /// no steps are executing (also when the task is complete)
451        /// </summary>
452        public Step CurrentStep
453        {
454            get
455            {
456                if (StartTime == DateTime.MinValue)
457                    return null;
458
459                foreach (Step step in Steps)
460                    if (step.Progress.Progress < 1.0f)
461                        return step;
462
463                return null;
464            }
465        }
466    }
467
468    /// <summary>
469    /// Manages progress based on sub-tasks, assuming each sub-task to be independent
470    /// of the rest.
471    /// </summary>
472    public class ParallelProgressManager : ChainedProgressManager
473    {
474        /// <summary>
475        /// The class which manages the progress of each dependent task.
476        /// </summary>
477        public class SubTasksList : IList<ProgressManagerBase>
478        {
479            public SubTasksList()
480            {
481                List = new List<ProgressManagerBase>();
482            }
483
484            #region IList<SubTasksList> Members
485
486            public int IndexOf(ProgressManagerBase item)
487            {
488                return List.IndexOf(item);
489            }
490
491            public void Insert(int index, ProgressManagerBase item)
492            {
493                List.Insert(index, item);
494            }
495
496            public void RemoveAt(int index)
497            {
498                List.RemoveAt(index);
499            }
500
501            public ProgressManagerBase this[int index]
502            {
503                get
504                {
505                    return List[index];
506                }
507                set
508                {
509                    List[index] = value;
510                }
511            }
512
513            #endregion
514
515            #region ICollection<SteppedProgressManagerStep> Members
516
517            public void Add(ProgressManagerBase item)
518            {
519                List.Add(item);
520            }
521
522            public void Clear()
523            {
524                List.Clear();
525            }
526
527            public bool Contains(ProgressManagerBase item)
528            {
529                return List.Contains(item);
530            }
531
532            public void CopyTo(ProgressManagerBase[] array, int arrayIndex)
533            {
534                List.CopyTo(array, arrayIndex);
535            }
536
537            public int Count
538            {
539                get { return List.Count; }
540            }
541
542            public bool IsReadOnly
543            {
544                get { return false; }
545            }
546
547            public bool Remove(ProgressManagerBase item)
548            {
549                return List.Remove(item);
550            }
551
552            #endregion
553
554            #region IEnumerable<ProgressManagerBase> Members
555
556            public IEnumerator<ProgressManagerBase> GetEnumerator()
557            {
558                return List.GetEnumerator();
559            }
560
561            #endregion
562
563            #region IEnumerable Members
564
565            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
566            {
567                return List.GetEnumerator();
568            }
569
570            #endregion
571
572            /// <summary>
573            /// The list storing the steps for this instance.
574            /// </summary>
575            private List<ProgressManagerBase> List;
576
577            /// <summary>
578            /// The total weights of all the steps.
579            /// </summary>
580            public int TotalWeights
581            {
582                get;
583                private set;
584            }
585        }
586
587        /// <summary>
588        /// Constructor.
589        /// </summary>
590        public ParallelProgressManager()
591        {
592            Tasks = new SubTasksList();
593        }
594
595        public override float Progress
596        {
597            get
598            {
599                float result = 0.0f;
600                foreach (ProgressManagerBase subTask in Tasks)
601                    result += subTask.Progress * (1.0f / Tasks.Count);
602
603                return result;
604            }
605        }
606
607        public override int Speed
608        {
609            get
610            {
611                int maxSpeed = 0;
612                foreach (ProgressManagerBase subTask in Tasks)
613                    maxSpeed = Math.Max(subTask.Speed, maxSpeed);
614
615                return maxSpeed;
616            }
617        }
618
619        public override TimeSpan TimeLeft
620        {
621            get
622            {
623                TimeSpan maxTime = TimeSpan.MinValue;
624                foreach (ProgressManagerBase subTask in Tasks)
625                    if (maxTime < subTask.TimeLeft)
626                        maxTime = subTask.TimeLeft;
627
628                return maxTime;
629            }
630        }
631
632        /// <summary>
633        /// Gets the list of tasks which must complete execution before the task
634        /// is completed.
635        /// </summary>
636        public SubTasksList Tasks
637        {
638            get;
639            private set;
640        }
641    }
642}
Note: See TracBrowser for help on using the repository browser.