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

Revision 1504, 13.3 KB checked in by lowjoel, 5 years ago (diff)

Fixed a few behaviours in the ProgressManager? classes:
-for ProgressManager?, if the Total field is zero, always return 0 for progress (prevents division by zero)
-for SteppedProgressManager?, the Speed property is dependent on the CurrentStep? property; if that is null, the speed should be zero.
-for SteppedProgressManager?, the TimeLeft? property is dependent on the StartTime? of the task, if it is invalid, the TimeLeft? property will now return TimeSpan?.MinValue?
-for SteppedProgressManager?, the CurrentStep? property will return the last completed step if all the steps have been completed

  • 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                if (Total == 0)
103                    return 0.0f;
104
105                return (float)((double)Completed / Total);
106            }
107        }
108
109        public override int Speed
110        {
111            get
112            {
113                if (DateTime.Now == startTime)
114                    return 0;
115
116                if ((DateTime.Now - lastSpeedCalc).Seconds < 5 && lastSpeed != 0)
117                    return lastSpeed;
118
119                //Calculate how much time has passed
120                double timeElapsed = (DateTime.Now - lastSpeedCalc).TotalSeconds;
121                if (timeElapsed == 0.0)
122                    return 0;
123
124                //Then compute the speed of the calculation
125                lastSpeed = (int)((Completed - lastCompleted) / timeElapsed);
126                lastSpeedCalc = DateTime.Now;
127                lastCompleted = Completed;
128                return lastSpeed;
129            }
130        }
131
132        public override TimeSpan TimeLeft
133        {
134            get
135            {
136                if (Speed == 0)
137                    return TimeSpan.Zero;
138                return new TimeSpan(0, 0, (int)((Total - Completed) / Speed));
139            }
140        }
141
142        /// <summary>
143        /// The starting time of the operation, used to determine average speed.
144        /// </summary>
145        private DateTime startTime;
146
147        /// <summary>
148        /// The last time a speed calculation was computed so that speed is not
149        /// computed too often.
150        /// </summary>
151        private DateTime lastSpeedCalc;
152
153        /// <summary>
154        /// The amount of the operation completed at the last speed computation.
155        /// </summary>
156        private long lastCompleted;
157
158        /// <summary>
159        /// The last calculated speed of the operation.
160        /// </summary>
161        private int lastSpeed;
162    }
163
164    /// <summary>
165    /// Manages progress based on sub-tasks.
166    /// </summary>
167    public abstract class ChainedProgressManager : ProgressManagerBase
168    {
169        public override void Start()
170        {
171            StartTime = DateTime.Now;
172        }
173
174        /// <summary>
175        /// The time the process was started.
176        /// </summary>
177        protected DateTime StartTime
178        {
179            get;
180            private set;
181        }
182    }
183
184    /// <summary>
185    /// Manages progress based on sub-tasks, taking each sub-task to be a step
186    /// in which the next step will not be executed until the current step is
187    /// complete. Each step is also assign weights so that certain steps which
188    /// take more time are given a larger amount of progress-bar space for finer
189    /// grained progress reporting.
190    /// </summary>
191    public class SteppedProgressManager : ChainedProgressManager
192    {
193        /// <summary>
194        /// Represents one step in the list of steps to complete.
195        /// </summary>
196        public class Step
197        {
198            /// <summary>
199            /// Constructor.
200            /// </summary>
201            /// <param name="progress">The <see cref="ProgressManagerBase"/> instance
202            /// which measures the progress of this step.</param>
203            /// <param name="weight">The weight of this step. The weight is a decimal
204            /// number in the range [0.0, 1.0] which represents the percentage of the
205            /// entire process this particular step is.</param>
206            public Step(ProgressManagerBase progress, float weight)
207                : this(progress, weight, null)
208            {
209            }
210
211            /// <summary>
212            /// Constructor.
213            /// </summary>
214            /// <param name="progress">The <see cref="ProgressManagerBase"/> instance
215            /// which measures the progress of this step.</param>
216            /// <param name="weight">The weight of this step. The weight is a decimal
217            /// number in the range [0.0, 1.0] which represents the percentage of the
218            /// entire process this particular step is.</param>
219            /// <param name="name">A user-specified value of the name of this step.
220            /// This value is not used by the class at all.</param>
221            public Step(ProgressManagerBase progress, float weight, string name)
222            {
223                Progress = progress;
224                Weight = weight;
225                Name = name;
226            }
227
228            /// <summary>
229            /// The <see cref="ProgressManagerBase"/> instance which measures the
230            /// progress of the step.
231            /// </summary>
232            public ProgressManagerBase Progress
233            {
234                get;
235                set;
236            }
237
238            /// <summary>
239            /// The weight associated with this step.
240            /// </summary>
241            public float Weight
242            {
243                get;
244                private set;
245            }
246
247            /// <summary>
248            /// The name of this step.
249            /// </summary>
250            public string Name
251            {
252                get;
253                set;
254            }
255        }
256
257        /// <summary>
258        /// The class which manages the steps which comprise the overall progress.
259        /// </summary>
260        public class StepsList : IList<Step>
261        {
262            public StepsList(SteppedProgressManager manager)
263            {
264                List = new List<Step>();
265                Manager = manager;
266            }
267
268            #region IList<Step> Members
269
270            public int IndexOf(Step item)
271            {
272                return List.IndexOf(item);
273            }
274
275            public void Insert(int index, Step item)
276            {
277                List.Insert(index, item);
278                TotalWeights += item.Weight;
279            }
280
281            public void RemoveAt(int index)
282            {
283                TotalWeights -= List[index].Weight;
284                List.RemoveAt(index);
285            }
286
287            public Step this[int index]
288            {
289                get
290                {
291                    return List[index];
292                }
293                set
294                {
295                    TotalWeights -= List[index].Weight;
296                    List[index] = value;
297                    TotalWeights += value.Weight;
298                }
299            }
300
301            #endregion
302
303            #region ICollection<Step> Members
304
305            public void Add(Step item)
306            {
307                List.Add(item);
308                TotalWeights += item.Weight;
309            }
310
311            public void Clear()
312            {
313                List.Clear();
314                TotalWeights = 0;
315            }
316
317            public bool Contains(Step item)
318            {
319                return List.Contains(item);
320            }
321
322            public void CopyTo(Step[] array, int arrayIndex)
323            {
324                List.CopyTo(array, arrayIndex);
325            }
326
327            public int Count
328            {
329                get { return List.Count; }
330            }
331
332            public bool IsReadOnly
333            {
334                get { return false; }
335            }
336
337            public bool Remove(Step item)
338            {
339                int index = List.IndexOf(item);
340                if (index != -1)
341                    TotalWeights -= List[index].Weight;
342
343                return List.Remove(item);
344            }
345
346            #endregion
347
348            #region IEnumerable<Step> Members
349
350            public IEnumerator<Step> GetEnumerator()
351            {
352                return List.GetEnumerator();
353            }
354
355            #endregion
356
357            #region IEnumerable Members
358
359            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
360            {
361                return List.GetEnumerator();
362            }
363
364            #endregion
365
366            /// <summary>
367            /// The total weights of all the steps.
368            /// </summary>
369            public float TotalWeights
370            {
371                get
372                {
373                    return totalWeights;
374                }
375                private set
376                {
377                    if (value > 1.0f || value < 0.0f)
378                        throw new ArgumentOutOfRangeException("The total weights of all steps in " +
379                            "the task must be within the range [0.0, 1.0]");
380
381                    totalWeights = value;
382                }
383            }
384
385            /// <summary>
386            /// The list storing the steps for this instance.
387            /// </summary>
388            private List<Step> List;
389
390            /// <summary>
391            /// The <see cref="SteppedProgressManager"/> instance which owns this list.
392            /// </summary>
393            private SteppedProgressManager Manager;
394
395            /// <summary>
396            /// The backing variable for the total weights of all the steps.
397            /// </summary>
398            private float totalWeights;
399        }
400
401        /// <summary>
402        /// Constructor.
403        /// </summary>
404        public SteppedProgressManager()
405        {
406            Steps = new StepsList(this);
407        }
408
409        public override float Progress
410        {
411            get
412            {
413                float result = 0.0f;
414                foreach (Step step in Steps)
415                    result += step.Progress.Progress * step.Weight;
416
417                return result;
418            }
419        }
420
421        public override int Speed
422        {
423            get
424            {
425                if (CurrentStep == null)
426                    return 0;
427
428                return CurrentStep.Progress.Speed;
429            }
430        }
431
432        public override TimeSpan TimeLeft
433        {
434            get
435            {
436                if (StartTime == DateTime.MinValue)
437                    return TimeSpan.MinValue;
438
439                long ticksElapsed = (DateTime.Now - StartTime).Ticks;
440                float progressRemaining = 1.0f - Progress;
441                return new TimeSpan((long)
442                    (progressRemaining * (ticksElapsed / (double)Progress)));
443            }
444        }
445
446        /// <summary>
447        /// The list of steps involved in completion of the task.
448        /// </summary>
449        public StepsList Steps
450        {
451            get;
452            private set;
453        }
454
455        /// <summary>
456        /// Gets the current step which is executing. This property is null if
457        /// no steps are executing (also when the task is complete)
458        /// </summary>
459        public Step CurrentStep
460        {
461            get
462            {
463                if (StartTime == DateTime.MinValue)
464                    return null;
465
466                if (Steps.Count == 0)
467                    return null;
468
469                foreach (Step step in Steps)
470                    if (step.Progress.Progress < 1.0f)
471                        return step;
472
473                //Return the last step since we don't have any
474                return Steps[Steps.Count - 1];
475            }
476        }
477    }
478
479    /// <summary>
480    /// Manages progress based on sub-tasks, assuming each sub-task to be independent
481    /// of the rest.
482    /// </summary>
483    public class ParallelProgressManager : ChainedProgressManager
484    {
485        /// <summary>
486        /// The class which manages the progress of each dependent task.
487        /// </summary>
488        public class SubTasksList : IList<ProgressManagerBase>
489        {
490            public SubTasksList()
491            {
492                List = new List<ProgressManagerBase>();
493            }
494
495            #region IList<SubTasksList> Members
496
497            public int IndexOf(ProgressManagerBase item)
498            {
499                return List.IndexOf(item);
500            }
501
502            public void Insert(int index, ProgressManagerBase item)
503            {
504                List.Insert(index, item);
505            }
506
507            public void RemoveAt(int index)
508            {
509                List.RemoveAt(index);
510            }
511
512            public ProgressManagerBase this[int index]
513            {
514                get
515                {
516                    return List[index];
517                }
518                set
519                {
520                    List[index] = value;
521                }
522            }
523
524            #endregion
525
526            #region ICollection<SteppedProgressManagerStep> Members
527
528            public void Add(ProgressManagerBase item)
529            {
530                List.Add(item);
531            }
532
533            public void Clear()
534            {
535                List.Clear();
536            }
537
538            public bool Contains(ProgressManagerBase item)
539            {
540                return List.Contains(item);
541            }
542
543            public void CopyTo(ProgressManagerBase[] array, int arrayIndex)
544            {
545                List.CopyTo(array, arrayIndex);
546            }
547
548            public int Count
549            {
550                get { return List.Count; }
551            }
552
553            public bool IsReadOnly
554            {
555                get { return false; }
556            }
557
558            public bool Remove(ProgressManagerBase item)
559            {
560                return List.Remove(item);
561            }
562
563            #endregion
564
565            #region IEnumerable<ProgressManagerBase> Members
566
567            public IEnumerator<ProgressManagerBase> GetEnumerator()
568            {
569                return List.GetEnumerator();
570            }
571
572            #endregion
573
574            #region IEnumerable Members
575
576            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
577            {
578                return List.GetEnumerator();
579            }
580
581            #endregion
582
583            /// <summary>
584            /// The list storing the steps for this instance.
585            /// </summary>
586            private List<ProgressManagerBase> List;
587
588            /// <summary>
589            /// The total weights of all the steps.
590            /// </summary>
591            public int TotalWeights
592            {
593                get;
594                private set;
595            }
596        }
597
598        /// <summary>
599        /// Constructor.
600        /// </summary>
601        public ParallelProgressManager()
602        {
603            Tasks = new SubTasksList();
604        }
605
606        public override float Progress
607        {
608            get
609            {
610                float result = 0.0f;
611                foreach (ProgressManagerBase subTask in Tasks)
612                    result += subTask.Progress * (1.0f / Tasks.Count);
613
614                return result;
615            }
616        }
617
618        public override int Speed
619        {
620            get
621            {
622                int maxSpeed = 0;
623                foreach (ProgressManagerBase subTask in Tasks)
624                    maxSpeed = Math.Max(subTask.Speed, maxSpeed);
625
626                return maxSpeed;
627            }
628        }
629
630        public override TimeSpan TimeLeft
631        {
632            get
633            {
634                TimeSpan maxTime = TimeSpan.MinValue;
635                foreach (ProgressManagerBase subTask in Tasks)
636                    if (maxTime < subTask.TimeLeft)
637                        maxTime = subTask.TimeLeft;
638
639                return maxTime;
640            }
641        }
642
643        /// <summary>
644        /// Gets the list of tasks which must complete execution before the task
645        /// is completed.
646        /// </summary>
647        public SubTasksList Tasks
648        {
649            get;
650            private set;
651        }
652    }
653}
Note: See TracBrowser for help on using the repository browser.