* roottypes.cs: Rename from tree.cs.
[mono.git] / mcs / class / System / System.ComponentModel / BackgroundWorker.cs
1 //
2 // BackgroundWorker.cs
3 //
4 // Authors:
5 //      Atsushi Enomoto <atsushi@ximian.com>
6 //
7 // Copyright (C) 2006 Novell, Inc.
8 //
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30 #if NET_2_0
31 using System.Collections.Generic;
32 using System.Threading;
33
34 namespace System.ComponentModel
35 {
36         public class BackgroundWorker : Component
37         {
38                 public BackgroundWorker ()
39                 {
40                 }
41
42                 AsyncOperation async;
43                 bool cancel_pending, report_progress = false, support_cancel = false;
44
45                 Dictionary<object,AsyncOperation> operations =
46                         new Dictionary<object,AsyncOperation> ();
47
48                 public event DoWorkEventHandler DoWork;
49                 public event ProgressChangedEventHandler ProgressChanged;
50                 public event RunWorkerCompletedEventHandler RunWorkerCompleted;
51
52                 [Browsable (false)]
53                 public bool CancellationPending {
54                         get { return cancel_pending; }
55                 }
56
57                 [Browsable (false)]
58                 public bool IsBusy {
59                         get { return async != null; }
60                 }
61
62                 [DefaultValue (false)]
63                 public bool WorkerReportsProgress {
64                         get { return report_progress; }
65                         set { report_progress = value; }
66                 }
67
68                 [DefaultValue (false)]
69                 public bool WorkerSupportsCancellation {
70                         get { return support_cancel; }
71                         set { support_cancel = value; }
72                 }
73
74                 [MonoTODO ("What should happen when IsBusy != true?")]
75                 public void CancelAsync ()
76                 {
77                         if (!support_cancel)
78                                 throw new InvalidOperationException ("This background worker does not support cancellation.");
79
80                         // FIXME: verify the expected behavior
81                         if (!IsBusy)
82                                 return;
83
84                         cancel_pending = true;
85
86                         async.PostOperationCompleted (delegate (object darg) {
87                                 OnRunWorkerCompleted (
88                                         new RunWorkerCompletedEventArgs (
89                                         null, null, true));
90                                 this.async = null;
91                                 cancel_pending = false;
92                                 },
93                                 null);
94                 }
95
96                 public void ReportProgress (int percentProgress)
97                 {
98                         ReportProgress (percentProgress, null);
99                 }
100
101                 [MonoTODO ("What should happen when IsBusy != true?")]
102                 public void ReportProgress (int percentProgress, object userState)
103                 {
104                         if (!WorkerReportsProgress)
105                                 throw new InvalidOperationException ("This background worker does not report progress.");
106
107                         // FIXME: verify the expected behavior
108                         if (!IsBusy)
109                                 return;
110
111                         async.Post (delegate (object o) {
112                                 ProgressChangedEventArgs e = o as ProgressChangedEventArgs;
113                                 OnProgressChanged (e);
114                                 },
115                                 new ProgressChangedEventArgs (percentProgress, userState));
116                 }
117
118                 public void RunWorkerAsync ()
119                 {
120                         RunWorkerAsync (null);
121                 }
122
123                 delegate void ProcessWorkerEventHandler (object argument, AsyncOperation async, SendOrPostCallback callback);
124
125                 void ProcessWorker (object argument, AsyncOperation async, SendOrPostCallback callback)
126                 {
127                         // do worker
128                         Exception error = null;
129                         DoWorkEventArgs e = new DoWorkEventArgs (argument);
130                         try {
131                                 OnDoWork (e);
132                         } catch (Exception ex) {
133                                 error = ex;
134                         }
135                         callback (new object [] {
136                                 new RunWorkerCompletedEventArgs (
137                                         e.Result, error, e.Cancel),
138                                 async});
139                 }
140
141                 void CompleteWorker (object state)
142                 {
143                         object [] args = (object []) state;
144                         RunWorkerCompletedEventArgs e =
145                                 args [0] as RunWorkerCompletedEventArgs;
146                         AsyncOperation async = args [1] as AsyncOperation;
147
148                         SendOrPostCallback callback = delegate (object darg) {
149                                 OnRunWorkerCompleted (darg as RunWorkerCompletedEventArgs);
150                         };
151
152                         async.PostOperationCompleted (callback, e);
153
154                         this.async = null;
155                 }
156
157                 public void RunWorkerAsync (object argument)
158                 {
159                         if (IsBusy)
160                                 throw new InvalidOperationException ("The background worker is busy.");
161
162                         async = AsyncOperationManager.CreateOperation (this);
163
164                         ProcessWorkerEventHandler handler =
165                                 new ProcessWorkerEventHandler (ProcessWorker);
166                         handler.BeginInvoke (argument, async, CompleteWorker, null, null);
167                 }
168
169                 protected virtual void OnDoWork (DoWorkEventArgs e)
170                 {
171                         if (DoWork != null)
172                                 DoWork (this, e);
173                 }
174
175                 protected virtual void OnProgressChanged (ProgressChangedEventArgs e)
176                 {
177                         if (ProgressChanged != null)
178                                 ProgressChanged (this, e);
179                 }
180
181                 protected virtual void OnRunWorkerCompleted (RunWorkerCompletedEventArgs e)
182                 {
183                         if (RunWorkerCompleted != null)
184                                 RunWorkerCompleted (this, e);
185                 }
186         }
187 }
188 #endif