1 //
2 // Copyright (c) 2010-2018 Antmicro
3 // Copyright (c) 2011-2015 Realtime Embedded
4 //
5 // This file is licensed under the MIT License.
6 // Full license text is available in 'licenses/MIT.txt'.
7 //
8 using System;
9 using System.Collections.Generic;
10 using System.Threading;
11 using System.Linq;
12 
13 namespace Antmicro.Renode.Utilities
14 {
15     public class ProgressMonitor
16     {
Start(string description, bool cancelable = false, bool progressable = false)17         public MonitoredAction Start(string description, bool cancelable = false, bool progressable = false)
18         {
19             lock(locker)
20             {
21                 var threadId = Thread.CurrentThread.ManagedThreadId;
22                 if(!runningActions.ContainsKey(threadId))
23                 {
24                     runningActions.Add(threadId, new Stack<MonitoredAction>());
25                 }
26 
27                 var actions = runningActions[threadId];
28                 var action = new MonitoredAction(this, description, cancelable, progressable);
29                 actions.Push(action);
30 
31                 UpdateDialog();
32 
33                 return action;
34             }
35         }
36 
Stop()37         public void Stop()
38         {
39             lock(locker)
40             {
41                 while (runningActions.Count > 0)
42                 {
43                     var kvp = runningActions.First();
44                     while(kvp.Value.Count > 0)
45                     {
46                         var a = kvp.Value.Pop();
47                         a.Finish();
48                     }
49                 }
50             }
51         }
52 
UpdateDialog()53         private void UpdateDialog()
54         {
55             lock(locker)
56             {
57                 var h = Handler;
58                 var actionsToRemove = new List<int>();
59                 foreach(var action in runningActions)
60                 {
61                     MonitoredAction current = null;
62                     while(true)
63                     {
64                         current = action.Value.Count > 0 ? action.Value.Peek() : null;
65                         if(current != null && current.IsFinished)
66                         {
67                             action.Value.Pop();
68                             continue;
69                         }
70                         break;
71                     }
72 
73                     if(current == null)
74                     {
75                         actionsToRemove.Add(action.Key);
76                         if(h != null)
77                         {
78                             h.Finish(action.Key);
79                         }
80                         continue;
81                     }
82 
83                     if(h != null)
84                     {
85                         h.Update(action.Key, current.Description, current.Progress);
86                     }
87                 }
88 
89                 foreach(var actionToRemove in actionsToRemove)
90                 {
91                     runningActions.Remove(actionToRemove);
92                 }
93             }
94         }
95 
96         private Dictionary<int, Stack<MonitoredAction>> runningActions = new Dictionary<int, Stack<MonitoredAction>>();
97 
98         private object locker = new object();
99 
100         public IProgressMonitorHandler Handler { get; set; }
101 
102         public class MonitoredAction : IDisposable
103         {
MonitoredAction(ProgressMonitor monitor, string description, bool cancelable, bool progressable)104             public MonitoredAction(ProgressMonitor monitor, string description, bool cancelable, bool progressable)
105             {
106                 this.monitor = monitor;
107                 Description = description;
108                 IsCancelable = cancelable;
109 
110                 Progress = progressable ? (int?)0 : null;
111             }
112 
UpdateProgress(int progress, string description = null)113             public void UpdateProgress(int progress, string description = null)
114             {
115                 Progress = progress;
116                 if(description != null)
117                 {
118                     Description = description;
119                 }
120 
121                 if(progress == 100)
122                 {
123                     IsFinished = true;
124                 }
125 
126                 monitor.UpdateDialog();
127             }
128 
Finish()129             public void Finish()
130             {
131                 IsFinished = true;
132                 monitor.UpdateDialog();
133             }
134 
Dispose()135             public void Dispose()
136             {
137                 Finish();
138             }
139 
140             public bool IsCancelable { get; private set; }
141             public bool IsFinished { get; private set; }
142             public int? Progress { get; private set; }
143             public string Description { get; private set; }
144 
145             private ProgressMonitor monitor;
146         }
147     }
148 }
149 
150