Mercurial > projects > dwt-addons
comparison dwtx/core/runtime/SubMonitor.d @ 3:6518c18a01f7
eclipse.core package without osgi dependencies
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Wed, 26 Mar 2008 00:57:19 +0100 |
parents | |
children | 46a6e0e6ccd4 |
comparison
equal
deleted
inserted
replaced
2:a012107a911c | 3:6518c18a01f7 |
---|---|
1 /******************************************************************************* | |
2 * Copyright (c) 2006, 2007 IBM Corporation and others. | |
3 * All rights reserved. This program and the accompanying materials | |
4 * are made available under the terms of the Eclipse Public License v1.0 | |
5 * which accompanies this distribution, and is available at | |
6 * http://www.eclipse.org/legal/epl-v10.html | |
7 * | |
8 * Contributors: | |
9 * Stefan Xenos - initial API and implementation | |
10 * Stefan Xenos - bug 174539 - add a 1-argument convert(...) method | |
11 * Stefan Xenos - bug 174040 - SubMonitor#convert doesn't always set task name | |
12 * Port to the D programming language: | |
13 * Frank Benoit <benoit@tionex.de> | |
14 *******************************************************************************/ | |
15 module dwtx.core.runtime.SubMonitor; | |
16 | |
17 import dwtx.core.runtime.IProgressMonitorWithBlocking; | |
18 import dwtx.core.runtime.IProgressMonitor; | |
19 import dwtx.core.runtime.IStatus; | |
20 import dwtx.core.runtime.NullProgressMonitor; | |
21 | |
22 import dwt.dwthelper.utils; | |
23 | |
24 /** | |
25 * <p>A progress monitor that uses a given amount of work ticks from a parent monitor. This is intended as a | |
26 * safer, easier-to-use alternative to SubProgressMonitor. The main benefits of SubMonitor over | |
27 * SubProgressMonitor are:</p> | |
28 * <ul> | |
29 * <li>It is not necessary to call beginTask() or done() on an instance of SubMonitor.</li> | |
30 * <li>SubMonitor has a simpler syntax for creating nested monitors.</li> | |
31 * <li>SubMonitor is more efficient for deep recursion chains.</li> | |
32 * <li>SubMonitor has a setWorkRemining method that allows the remaining space on the monitor to be | |
33 * redistributed without reporting any work.</li> | |
34 * <li>SubMonitor protects the caller from common progress reporting bugs in a called method. For example, | |
35 * if a called method fails to call done() on the given monitor or fails to consume all the ticks on | |
36 * the given monitor, the parent will correct the problem after the method returns.</li> | |
37 * </ul> | |
38 * <p></p> | |
39 * <p><b>USAGE:</b></p> | |
40 * | |
41 * <p>When implementing a method that accepts an IProgressMonitor:</p> | |
42 * <ul> | |
43 * <li>At the start of your method, use <code>SubMonitor.convert(...).</code> to convert the IProgressMonitor | |
44 * into a SubMonitor. </li> | |
45 * <li>Use <code>SubMonitor.newChild(...)</code> whenever you need to call another method that | |
46 * accepts an IProgressMonitor.</li> | |
47 * </ul> | |
48 * <p></p> | |
49 * <p><b>DEFAULT BEHAVIOR:</b></p> | |
50 * | |
51 * <p>When writing JavaDoc for a method that accepts an IProgressMonitor, you should assume the | |
52 * following default behavior unless the method's JavaDoc says otherwise:</p> | |
53 * <ul> | |
54 * <li>It WILL call beginTask on the IProgressMonitor.</li> | |
55 * <li>It WILL NOT accept a null argument.</li> | |
56 * <li>It WILL call done on the IProgressMonitor.</li> | |
57 * </ul> | |
58 * <p></p> | |
59 * <p><b>BEST PRACTISES:</b></p> | |
60 * | |
61 * <p>We recommend that newly-written methods follow the given contract:</p> | |
62 * <ul> | |
63 * <li>It WILL call beginTask on the IProgressMonitor.</li> | |
64 * <li>It WILL accept a null argument, indicating that no progress should be reported and the operation cannot be cancelled.</li> | |
65 * <li>It WILL NOT call done on the IProgressMonitor, leaving this responsibility up to the caller.</li> | |
66 * </ul> | |
67 * <p>If you wish to follow these conventions, you may copy and paste the following text into your method's JavaDoc:</p> | |
68 * | |
69 * <pre>@param monitor the progress monitor to use for reporting progress to the user. It is the caller's responsibility | |
70 * to call done() on the given monitor. Accepts <code>null</code>, indicating that no progress should be | |
71 * reported and that the operation cannot be cancelled.</pre> | |
72 * | |
73 * <p></p> | |
74 * <p><b>Example: Recommended usage</b></p> | |
75 * | |
76 * <p>This example demonstrates how the recommended usage of <code>SubMonitor</code> makes it unnecessary to call | |
77 * IProgressMonitor.done() in most situations.</p> | |
78 * | |
79 * <p>It is never necessary to call done() on a monitor obtained from <code>convert</code> or <code>progress.newChild()</code>. | |
80 * In this example, there is no guarantee that <code>monitor</code> is an instance of <code>SubMonitor</code>, making it | |
81 * necessary to call <code>monitor.done()</code>. The JavaDoc contract makes this the responsibility of the caller.</p> | |
82 * | |
83 * <pre> | |
84 * // param monitor the progress monitor to use for reporting progress to the user. It is the caller's responsibility | |
85 * // to call done() on the given monitor. Accepts <code>null</code>, indicating that no progress should be | |
86 * // reported and that the operation cannot be cancelled. | |
87 * // | |
88 * void doSomething(IProgressMonitor monitor) { | |
89 * // Convert the given monitor into a progress instance | |
90 * SubMonitor progress = SubMonitor.convert(monitor, 100); | |
91 * | |
92 * // Use 30% of the progress to do some work | |
93 * doSomeWork(progress.newChild(30)); | |
94 * | |
95 * // Advance the monitor by another 30% | |
96 * progress.worked(30); | |
97 * | |
98 * // Use the remaining 40% of the progress to do some more work | |
99 * doSomeWork(progress.newChild(40)); | |
100 * } | |
101 * </pre> | |
102 * | |
103 * | |
104 * <p></p> | |
105 * <p><b>Example: Default usage</b></p> | |
106 * | |
107 * <p>You will often need to implement a method that does not explicitly stipulate that calling done() is the responsibility | |
108 * of the caller. In this case, you should use the following pattern:</p> | |
109 * | |
110 * <pre> | |
111 * // param monitor the progress monitor to use for reporting progress to the user, or <code>null</code> indicating | |
112 * // that no progress should be reported and the operation cannot be cancelled. | |
113 * // | |
114 * void doSomething(IProgressMonitor monitor) { | |
115 * // Convert the given monitor into a progress instance | |
116 * SubMonitor progress = SubMonitor.convert(monitor, 100); | |
117 * try { | |
118 * // Use 30% of the progress to do some work | |
119 * doSomeWork(progress.newChild(30)); | |
120 * | |
121 * // Advance the monitor by another 30% | |
122 * progress.worked(30); | |
123 * | |
124 * // Use the remaining 40% of the progress to do some more work | |
125 * doSomeWork(progress.newChild(40)); | |
126 * | |
127 * } finally { | |
128 * if (monitor !is null) { | |
129 * monitor.done(); | |
130 * } | |
131 * } | |
132 * } | |
133 * </pre> | |
134 * | |
135 * <p></p> | |
136 * <p><b>Example: Branches</b></p> | |
137 * | |
138 * <p>This example demonstrates how to smoothly report progress in situations where some of the work is optional.</p> | |
139 * | |
140 * <pre> | |
141 * void doSomething(IProgressMonitor monitor) { | |
142 * SubMonitor progress = SubMonitor.convert(monitor, 100); | |
143 * | |
144 * if (condition) { | |
145 * // Use 50% of the progress to do some work | |
146 * doSomeWork(progress.newChild(50)); | |
147 * } | |
148 * | |
149 * // Don't report any work, but ensure that we have 50 ticks remaining on the progress monitor. | |
150 * // If we already consumed 50 ticks in the above branch, this is a no-op. Otherwise, the remaining | |
151 * // space in the monitor is redistributed into 50 ticks. | |
152 * | |
153 * progress.setWorkRemaining(50); | |
154 * | |
155 * // Use the remainder of the progress monitor to do the rest of the work | |
156 * doSomeWork(progress.newChild(50)); | |
157 * } | |
158 * </pre> | |
159 * | |
160 * <p>Please beware of the following anti-pattern:</p> | |
161 * | |
162 * <pre> | |
163 * if (condition) { | |
164 * // Use 50% of the progress to do some work | |
165 * doSomeWork(progress.newChild(50)); | |
166 * } else { | |
167 * // Bad: Causes the progress monitor to appear to start at 50%, wasting half of the | |
168 * // space in the monitor. | |
169 * progress.worked(50); | |
170 * } | |
171 * </pre> | |
172 * | |
173 * | |
174 * <p></p> | |
175 * <p><b>Example: Loops</b></p> | |
176 * | |
177 * <p>This example demonstrates how to report progress in a loop.</p> | |
178 * | |
179 * <pre> | |
180 * void doSomething(IProgressMonitor monitor, Collection someCollection) { | |
181 * SubMonitor progress = SubMonitor.convert(monitor, 100); | |
182 * | |
183 * // Create a new progress monitor that uses 70% of the total progress and will allocate one tick | |
184 * // for each element of the given collection. | |
185 * SubMonitor loopProgress = progress.newChild(70).setWorkRemaining(someCollection.size()); | |
186 * | |
187 * for (Iterator iter = someCollection.iterator(); iter.hasNext();) { | |
188 * Object next = iter.next(); | |
189 * | |
190 * doWorkOnElement(next, loopProgress.newChild(1)); | |
191 * } | |
192 * | |
193 * // Use the remaining 30% of the progress monitor to do some work outside the loop | |
194 * doSomeWork(progress.newChild(30)); | |
195 * } | |
196 * </pre> | |
197 * | |
198 * | |
199 * <p></p> | |
200 * <p><b>Example: Infinite progress</b></p> | |
201 * | |
202 * <p>This example demonstrates how to report logarithmic progress in situations where the number of ticks | |
203 * cannot be easily computed in advance.</p> | |
204 * | |
205 * <pre> | |
206 * void doSomething(IProgressMonitor monitor, LinkedListNode node) { | |
207 * SubMonitor progress = SubMonitor.convert(monitor, 100); | |
208 * | |
209 * while (node !is null) { | |
210 * // Regardless of the amount of progress reported so far, | |
211 * // use 5% of the space remaining in the monitor to process the next node. | |
212 * progress.setWorkRemaining(100); | |
213 * | |
214 * doWorkOnElement(node, progress.newChild(5)); | |
215 * | |
216 * node = node.next; | |
217 * } | |
218 * } | |
219 * </pre> | |
220 * | |
221 * <p> | |
222 * This class can be used without OSGi running. | |
223 * </p> | |
224 * | |
225 * @since dwtx.equinox.common 3.3 | |
226 */ | |
227 public final class SubMonitor : IProgressMonitorWithBlocking { | |
228 | |
229 /** | |
230 * Minimum number of ticks to allocate when calling beginTask on an unknown IProgressMonitor. | |
231 * Pick a number that is big enough such that, no matter where progress is being displayed, | |
232 * the user would be unlikely to notice if progress were to be reported with higher accuracy. | |
233 */ | |
234 private static final int MINIMUM_RESOLUTION = 1000; | |
235 | |
236 /** | |
237 * The RootInfo struct holds information about the root progress monitor. A SubMonitor and | |
238 * its active descendents share the same RootInfo struct. | |
239 */ | |
240 private static final class RootInfo { | |
241 private final IProgressMonitor root; | |
242 | |
243 /** | |
244 * Remembers the last task name. Prevents us from setting the same task name multiple | |
245 * times in a row. | |
246 */ | |
247 private String taskName = null; | |
248 | |
249 /** | |
250 * Remembers the last subtask name. Prevents the SubMonitor from setting the same | |
251 * subtask string more than once in a row. | |
252 */ | |
253 private String subTask_ = null; | |
254 | |
255 /** | |
256 * Creates a RootInfo struct that delegates to the given progress | |
257 * monitor. | |
258 * | |
259 * @param root progress monitor to delegate to | |
260 */ | |
261 public this(IProgressMonitor root) { | |
262 this.root = root; | |
263 } | |
264 | |
265 public bool isCanceled() { | |
266 return root.isCanceled(); | |
267 } | |
268 | |
269 public void setCanceled(bool value) { | |
270 root.setCanceled(value); | |
271 } | |
272 | |
273 public void setTaskName(String taskName) { | |
274 if (eq(taskName, this.taskName)) { | |
275 return; | |
276 } | |
277 this.taskName = taskName; | |
278 root.setTaskName(taskName); | |
279 } | |
280 | |
281 public void subTask(String name) { | |
282 if (eq(subTask_, name)) { | |
283 return; | |
284 } | |
285 | |
286 this.subTask_ = name; | |
287 root.subTask(name); | |
288 } | |
289 | |
290 public void worked(int i) { | |
291 root.worked(i); | |
292 } | |
293 | |
294 public void clearBlocked() { | |
295 if ( auto mon = cast(IProgressMonitorWithBlocking)root ) | |
296 mon.clearBlocked(); | |
297 } | |
298 | |
299 public void setBlocked(IStatus reason) { | |
300 if ( auto mon = cast(IProgressMonitorWithBlocking)root ) | |
301 mon.setBlocked(reason); | |
302 } | |
303 | |
304 } | |
305 | |
306 /** | |
307 * Total number of ticks that this progress monitor is permitted to consume | |
308 * from the root. | |
309 */ | |
310 private int totalParent; | |
311 | |
312 /** | |
313 * Number of ticks that this progress monitor has already reported in the root. | |
314 */ | |
315 private int usedForParent = 0; | |
316 | |
317 /** | |
318 * Number of ticks that have been consumed by this instance's children. | |
319 */ | |
320 private double usedForChildren = 0.0; | |
321 | |
322 /** | |
323 * Number of ticks allocated for this instance's children. This is the total number | |
324 * of ticks that may be passed into worked(int) or newChild(int). | |
325 */ | |
326 private int totalForChildren; | |
327 | |
328 /** | |
329 * Children created by newChild will be completed automatically the next time | |
330 * the parent progress monitor is touched. This points to the last incomplete child | |
331 * created with newChild. | |
332 */ | |
333 private IProgressMonitor lastSubMonitor = null; | |
334 | |
335 /** | |
336 * Used to communicate with the root of this progress monitor tree | |
337 */ | |
338 private const RootInfo root; | |
339 | |
340 /** | |
341 * A bitwise combination of the SUPPRESS_* flags. | |
342 */ | |
343 private const int flags; | |
344 | |
345 /** | |
346 * May be passed as a flag to newChild. Indicates that the calls | |
347 * to subTask on the child should be ignored. Without this flag, | |
348 * calling subTask on the child will result in a call to subTask | |
349 * on its parent. | |
350 */ | |
351 public static const int SUPPRESS_SUBTASK = 0x0001; | |
352 | |
353 /** | |
354 * May be passed as a flag to newChild. Indicates that strings | |
355 * passed into beginTask should be ignored. If this flag is | |
356 * specified, then the progress monitor instance will accept null | |
357 * as the first argument to beginTask. Without this flag, any | |
358 * string passed to beginTask will result in a call to | |
359 * setTaskName on the parent. | |
360 */ | |
361 public static const int SUPPRESS_BEGINTASK = 0x0002; | |
362 | |
363 /** | |
364 * May be passed as a flag to newChild. Indicates that strings | |
365 * passed into setTaskName should be ignored. If this string | |
366 * is omitted, then a call to setTaskName on the child will | |
367 * result in a call to setTaskName on the parent. | |
368 */ | |
369 public static const int SUPPRESS_SETTASKNAME = 0x0004; | |
370 | |
371 /** | |
372 * May be passed as a flag to newChild. Indicates that strings | |
373 * passed to setTaskName, subTask, and beginTask should all be ignored. | |
374 */ | |
375 public static const int SUPPRESS_ALL_LABELS = SUPPRESS_SETTASKNAME | SUPPRESS_BEGINTASK | SUPPRESS_SUBTASK; | |
376 | |
377 /** | |
378 * May be passed as a flag to newChild. Indicates that strings | |
379 * passed to setTaskName, subTask, and beginTask should all be propogated | |
380 * to the parent. | |
381 */ | |
382 public static const int SUPPRESS_NONE = 0; | |
383 | |
384 /** | |
385 * Creates a new SubMonitor that will report its progress via | |
386 * the given RootInfo. | |
387 * @param rootInfo the root of this progress monitor tree | |
388 * @param totalWork total work to perform on the given progress monitor | |
389 * @param availableToChildren number of ticks allocated for this instance's children | |
390 * @param flags a bitwise combination of the SUPPRESS_* constants | |
391 */ | |
392 private this(RootInfo rootInfo, int totalWork, int availableToChildren, int flags) { | |
393 root = rootInfo; | |
394 totalParent = (totalWork > 0) ? totalWork : 0; | |
395 this.totalForChildren = availableToChildren; | |
396 this.flags = flags; | |
397 } | |
398 | |
399 /** | |
400 * <p>Converts an unknown (possibly null) IProgressMonitor into a SubMonitor. It is | |
401 * not necessary to call done() on the result, but the caller is responsible for calling | |
402 * done() on the argument. Calls beginTask on the argument.</p> | |
403 * | |
404 * <p>This method should generally be called at the beginning of a method that accepts | |
405 * an IProgressMonitor in order to convert the IProgressMonitor into a SubMonitor.</p> | |
406 * | |
407 * @param monitor monitor to convert to a SubMonitor instance or null. Treats null | |
408 * as a new instance of <code>NullProgressMonitor</code>. | |
409 * @return a SubMonitor instance that adapts the argument | |
410 */ | |
411 public static SubMonitor convert(IProgressMonitor monitor) { | |
412 return convert(monitor, "", 0); //$NON-NLS-1$ | |
413 } | |
414 | |
415 /** | |
416 * <p>Converts an unknown (possibly null) IProgressMonitor into a SubMonitor allocated | |
417 * with the given number of ticks. It is not necessary to call done() on the result, | |
418 * but the caller is responsible for calling done() on the argument. Calls beginTask | |
419 * on the argument.</p> | |
420 * | |
421 * <p>This method should generally be called at the beginning of a method that accepts | |
422 * an IProgressMonitor in order to convert the IProgressMonitor into a SubMonitor.</p> | |
423 * | |
424 * @param monitor monitor to convert to a SubMonitor instance or null. Treats null | |
425 * as a new instance of <code>NullProgressMonitor</code>. | |
426 * @param work number of ticks that will be available in the resulting monitor | |
427 * @return a SubMonitor instance that adapts the argument | |
428 */ | |
429 public static SubMonitor convert(IProgressMonitor monitor, int work) { | |
430 return convert(monitor, "", work); //$NON-NLS-1$ | |
431 } | |
432 | |
433 /** | |
434 * <p>Converts an unknown (possibly null) IProgressMonitor into a SubMonitor allocated | |
435 * with the given number of ticks. It is not necessary to call done() on the result, | |
436 * but the caller is responsible for calling done() on the argument. Calls beginTask | |
437 * on the argument.</p> | |
438 * | |
439 * <p>This method should generally be called at the beginning of a method that accepts | |
440 * an IProgressMonitor in order to convert the IProgressMonitor into a SubMonitor.</p> | |
441 * | |
442 * @param monitor to convert into a SubMonitor instance or null. If given a null argument, | |
443 * the resulting SubMonitor will not report its progress anywhere. | |
444 * @param taskName user readable name to pass to monitor.beginTask. Never null. | |
445 * @param work initial number of ticks to allocate for children of the SubMonitor | |
446 * @return a new SubMonitor instance that is a child of the given monitor | |
447 */ | |
448 public static SubMonitor convert(IProgressMonitor monitor, String taskName, int work) { | |
449 if (monitor is null) | |
450 monitor = new NullProgressMonitor(); | |
451 | |
452 // Optimization: if the given monitor already a SubMonitor, no conversion is necessary | |
453 if ( cast(SubMonitor) monitor ) { | |
454 monitor.beginTask(taskName, work); | |
455 return cast(SubMonitor) monitor; | |
456 } | |
457 | |
458 monitor.beginTask(taskName, MINIMUM_RESOLUTION); | |
459 return new SubMonitor(new RootInfo(monitor), MINIMUM_RESOLUTION, work, SUPPRESS_NONE); | |
460 } | |
461 | |
462 /** | |
463 * <p>Sets the work remaining for this SubMonitor instance. This is the total number | |
464 * of ticks that may be reported by all subsequent calls to worked(int), newChild(int), etc. | |
465 * This may be called many times for the same SubMonitor instance. When this method | |
466 * is called, the remaining space on the progress monitor is redistributed into the given | |
467 * number of ticks.</p> | |
468 * | |
469 * <p>It doesn't matter how much progress has already been reported with this SubMonitor | |
470 * instance. If you call setWorkRemaining(100), you will be able to report 100 more ticks of | |
471 * work before the progress meter reaches 100%.</p> | |
472 * | |
473 * @param workRemaining total number of remaining ticks | |
474 * @return the receiver | |
475 */ | |
476 public SubMonitor setWorkRemaining(int workRemaining) { | |
477 // Ensure we don't try to allocate negative ticks | |
478 workRemaining = Math.max(0, workRemaining); | |
479 | |
480 // Ensure we don't cause division by zero | |
481 if (totalForChildren > 0 && totalParent > usedForParent) { | |
482 // Note: We want the following value to remain invariant after this method returns | |
483 double remainForParent = totalParent * (1.0 - (usedForChildren / totalForChildren)); | |
484 usedForChildren = (workRemaining * (1.0 - remainForParent / (totalParent - usedForParent))); | |
485 } else | |
486 usedForChildren = 0.0; | |
487 | |
488 totalParent = totalParent - usedForParent; | |
489 usedForParent = 0; | |
490 totalForChildren = workRemaining; | |
491 return this; | |
492 } | |
493 | |
494 /** | |
495 * Consumes the given number of child ticks, given as a double. Must only | |
496 * be called if the monitor is in floating-point mode. | |
497 * | |
498 * @param ticks the number of ticks to consume | |
499 * @return ticks the number of ticks to be consumed from parent | |
500 */ | |
501 private int consume(double ticks) { | |
502 if (totalParent is 0 || totalForChildren is 0) // this monitor has no available work to report | |
503 return 0; | |
504 | |
505 usedForChildren += ticks; | |
506 | |
507 if (usedForChildren > totalForChildren) | |
508 usedForChildren = totalForChildren; | |
509 else if (usedForChildren < 0.0) | |
510 usedForChildren = 0.0; | |
511 | |
512 int parentPosition = cast(int) (totalParent * usedForChildren / totalForChildren); | |
513 int delta = parentPosition - usedForParent; | |
514 | |
515 usedForParent = parentPosition; | |
516 return delta; | |
517 } | |
518 | |
519 /* (non-Javadoc) | |
520 * @see dwtx.core.runtime.IProgressMonitor#isCanceled() | |
521 */ | |
522 public bool isCanceled() { | |
523 return root.isCanceled(); | |
524 } | |
525 | |
526 /* (non-Javadoc) | |
527 * @see dwtx.core.runtime.IProgressMonitor#setTaskName(java.lang.String) | |
528 */ | |
529 public void setTaskName(String name) { | |
530 if ((flags & SUPPRESS_SETTASKNAME) is 0) | |
531 root.setTaskName(name); | |
532 } | |
533 | |
534 /** | |
535 * Starts a new main task. The string argument is ignored | |
536 * if and only if the SUPPRESS_BEGINTASK flag has been set on this SubMonitor | |
537 * instance. | |
538 * | |
539 * <p>This method is equivalent calling setWorkRemaining(...) on the reciever. Unless | |
540 * the SUPPRESS_BEGINTASK flag is set, this will also be equivalent to calling | |
541 * setTaskName(...) on the parent.</p> | |
542 * | |
543 * @param name new main task name | |
544 * @param totalWork number of ticks to allocate | |
545 * | |
546 * @see dwtx.core.runtime.IProgressMonitor#beginTask(java.lang.String, int) | |
547 */ | |
548 public void beginTask(String name, int totalWork) { | |
549 if ((flags & SUPPRESS_BEGINTASK) is 0 && name !is null) | |
550 root.setTaskName(name); | |
551 setWorkRemaining(totalWork); | |
552 } | |
553 | |
554 /* (non-Javadoc) | |
555 * @see dwtx.core.runtime.IProgressMonitor#done() | |
556 */ | |
557 public void done() { | |
558 cleanupActiveChild(); | |
559 int delta = totalParent - usedForParent; | |
560 if (delta > 0) | |
561 root.worked(delta); | |
562 | |
563 totalParent = 0; | |
564 usedForParent = 0; | |
565 totalForChildren = 0; | |
566 usedForChildren = 0.0; | |
567 } | |
568 | |
569 /* (non-Javadoc) | |
570 * @see dwtx.core.runtime.IProgressMonitor#internalWorked(double) | |
571 */ | |
572 public void internalWorked(double work) { | |
573 int delta = consume((work > 0.0) ? work : 0.0); | |
574 if (delta !is 0) | |
575 root.worked(delta); | |
576 } | |
577 | |
578 /* (non-Javadoc) | |
579 * @see dwtx.core.runtime.IProgressMonitor#subTask(java.lang.String) | |
580 */ | |
581 public void subTask(String name) { | |
582 if ((flags & SUPPRESS_SUBTASK) is 0) | |
583 root.subTask(name); | |
584 } | |
585 | |
586 /* (non-Javadoc) | |
587 * @see dwtx.core.runtime.IProgressMonitor#worked(int) | |
588 */ | |
589 public void worked(int work) { | |
590 internalWorked(work); | |
591 } | |
592 | |
593 /* (non-Javadoc) | |
594 * @see dwtx.core.runtime.IProgressMonitor#setCanceled(bool) | |
595 */ | |
596 public void setCanceled(bool b) { | |
597 root.setCanceled(b); | |
598 } | |
599 | |
600 /** | |
601 * <p>Creates a sub progress monitor that will consume the given number of ticks from the | |
602 * receiver. It is not necessary to call <code>beginTask</code> or <code>done</code> on the | |
603 * result. However, the resulting progress monitor will not report any work after the first | |
604 * call to done() or before ticks are allocated. Ticks may be allocated by calling beginTask | |
605 * or setWorkRemaining.</p> | |
606 * | |
607 * <p>Each SubMonitor only has one active child at a time. Each time newChild() is called, the | |
608 * result becomes the new active child and any unused progress from the previously-active child is | |
609 * consumed.</p> | |
610 * | |
611 * <p>This is property makes it unnecessary to call done() on a SubMonitor instance, since child | |
612 * monitors are automatically cleaned up the next time the parent is touched.</p> | |
613 * | |
614 * <code><pre> | |
615 * //////////////////////////////////////////////////////////////////////////// | |
616 * // Example 1: Typical usage of newChild | |
617 * void myMethod(IProgressMonitor parent) { | |
618 * SubMonitor progress = SubMonitor.convert(parent, 100); | |
619 * doSomething(progress.newChild(50)); | |
620 * doSomethingElse(progress.newChild(50)); | |
621 * } | |
622 * | |
623 * //////////////////////////////////////////////////////////////////////////// | |
624 * // Example 2: Demonstrates the function of active children. Creating children | |
625 * // is sufficient to smoothly report progress, even if worked(...) and done() | |
626 * // are never called. | |
627 * void myMethod(IProgressMonitor parent) { | |
628 * SubMonitor progress = SubMonitor.convert(parent, 100); | |
629 * | |
630 * for (int i = 0; i < 100; i++) { | |
631 * // Creating the next child monitor will clean up the previous one, | |
632 * // causing progress to be reported smoothly even if we don't do anything | |
633 * // with the monitors we create | |
634 * progress.newChild(1); | |
635 * } | |
636 * } | |
637 * | |
638 * //////////////////////////////////////////////////////////////////////////// | |
639 * // Example 3: Demonstrates a common anti-pattern | |
640 * void wrongMethod(IProgressMonitor parent) { | |
641 * SubMonitor progress = SubMonitor.convert(parent, 100); | |
642 * | |
643 * // WRONG WAY: Won't have the intended effect, as only one of these progress | |
644 * // monitors may be active at a time and the other will report no progress. | |
645 * callMethod(progress.newChild(50), computeValue(progress.newChild(50))); | |
646 * } | |
647 * | |
648 * void rightMethod(IProgressMonitor parent) { | |
649 * SubMonitor progress = SubMonitor.convert(parent, 100); | |
650 * | |
651 * // RIGHT WAY: Break up method calls so that only one SubMonitor is in use at a time. | |
652 * Object someValue = computeValue(progress.newChild(50)); | |
653 * callMethod(progress.newChild(50), someValue); | |
654 * } | |
655 * </pre></code> | |
656 * | |
657 * @param totalWork number of ticks to consume from the reciever | |
658 * @return new sub progress monitor that may be used in place of a new SubMonitor | |
659 */ | |
660 public SubMonitor newChild(int totalWork) { | |
661 return newChild(totalWork, SUPPRESS_BEGINTASK); | |
662 } | |
663 | |
664 /** | |
665 * <p>Creates a sub progress monitor that will consume the given number of ticks from the | |
666 * receiver. It is not necessary to call <code>beginTask</code> or <code>done</code> on the | |
667 * result. However, the resulting progress monitor will not report any work after the first | |
668 * call to done() or before ticks are allocated. Ticks may be allocated by calling beginTask | |
669 * or setWorkRemaining.</p> | |
670 * | |
671 * <p>Each SubMonitor only has one active child at a time. Each time newChild() is called, the | |
672 * result becomes the new active child and any unused progress from the previously-active child is | |
673 * consumed.</p> | |
674 * | |
675 * <p>This is property makes it unnecessary to call done() on a SubMonitor instance, since child | |
676 * monitors are automatically cleaned up the next time the parent is touched.</p> | |
677 * | |
678 * <code><pre> | |
679 * //////////////////////////////////////////////////////////////////////////// | |
680 * // Example 1: Typical usage of newChild | |
681 * void myMethod(IProgressMonitor parent) { | |
682 * SubMonitor progress = SubMonitor.convert(parent, 100); | |
683 * doSomething(progress.newChild(50)); | |
684 * doSomethingElse(progress.newChild(50)); | |
685 * } | |
686 * | |
687 * //////////////////////////////////////////////////////////////////////////// | |
688 * // Example 2: Demonstrates the function of active children. Creating children | |
689 * // is sufficient to smoothly report progress, even if worked(...) and done() | |
690 * // are never called. | |
691 * void myMethod(IProgressMonitor parent) { | |
692 * SubMonitor progress = SubMonitor.convert(parent, 100); | |
693 * | |
694 * for (int i = 0; i < 100; i++) { | |
695 * // Creating the next child monitor will clean up the previous one, | |
696 * // causing progress to be reported smoothly even if we don't do anything | |
697 * // with the monitors we create | |
698 * progress.newChild(1); | |
699 * } | |
700 * } | |
701 * | |
702 * //////////////////////////////////////////////////////////////////////////// | |
703 * // Example 3: Demonstrates a common anti-pattern | |
704 * void wrongMethod(IProgressMonitor parent) { | |
705 * SubMonitor progress = SubMonitor.convert(parent, 100); | |
706 * | |
707 * // WRONG WAY: Won't have the intended effect, as only one of these progress | |
708 * // monitors may be active at a time and the other will report no progress. | |
709 * callMethod(progress.newChild(50), computeValue(progress.newChild(50))); | |
710 * } | |
711 * | |
712 * void rightMethod(IProgressMonitor parent) { | |
713 * SubMonitor progress = SubMonitor.convert(parent, 100); | |
714 * | |
715 * // RIGHT WAY: Break up method calls so that only one SubMonitor is in use at a time. | |
716 * Object someValue = computeValue(progress.newChild(50)); | |
717 * callMethod(progress.newChild(50), someValue); | |
718 * } | |
719 * </pre></code> | |
720 * | |
721 * @param totalWork number of ticks to consume from the reciever | |
722 * @return new sub progress monitor that may be used in place of a new SubMonitor | |
723 */ | |
724 public SubMonitor newChild(int totalWork, int suppressFlags) { | |
725 double totalWorkDouble = (totalWork > 0) ? totalWork : 0.0; | |
726 totalWorkDouble = Math.min(totalWorkDouble, totalForChildren - usedForChildren); | |
727 cleanupActiveChild(); | |
728 | |
729 // Compute the flags for the child. We want the net effect to be as though the child is | |
730 // delegating to its parent, even though it is actually talking directly to the root. | |
731 // This means that we need to compute the flags such that - even if a label isn't | |
732 // suppressed by the child - if that same label would have been suppressed when the | |
733 // child delegated to its parent, the child must explicitly suppress the label. | |
734 int childFlags = SUPPRESS_NONE; | |
735 | |
736 if ((flags & SUPPRESS_SETTASKNAME) !is 0) { | |
737 // If the parent was ignoring labels passed to setTaskName, then the child will ignore | |
738 // labels passed to either beginTask or setTaskName - since both delegate to setTaskName | |
739 // on the parent | |
740 childFlags |= SUPPRESS_SETTASKNAME | SUPPRESS_BEGINTASK; | |
741 } | |
742 | |
743 if ((flags & SUPPRESS_SUBTASK) !is 0) { | |
744 // If the parent was suppressing labels passed to subTask, so will the child. | |
745 childFlags |= SUPPRESS_SUBTASK; | |
746 } | |
747 | |
748 // Note: the SUPPRESS_BEGINTASK flag does not affect the child since there | |
749 // is no method on the child that would delegate to beginTask on the parent. | |
750 childFlags |= suppressFlags; | |
751 | |
752 SubMonitor result = new SubMonitor(root, consume(totalWorkDouble), 0, childFlags); | |
753 lastSubMonitor = result; | |
754 return result; | |
755 } | |
756 | |
757 private void cleanupActiveChild() { | |
758 if (lastSubMonitor is null) | |
759 return; | |
760 | |
761 IProgressMonitor child = lastSubMonitor; | |
762 lastSubMonitor = null; | |
763 child.done(); | |
764 } | |
765 | |
766 /* (non-Javadoc) | |
767 * @see dwtx.core.runtime.IProgressMonitorWithBlocking#clearBlocked() | |
768 */ | |
769 public void clearBlocked() { | |
770 root.clearBlocked(); | |
771 } | |
772 | |
773 /* (non-Javadoc) | |
774 * @see dwtx.core.runtime.IProgressMonitorWithBlocking#setBlocked(dwtx.core.runtime.IStatus) | |
775 */ | |
776 public void setBlocked(IStatus reason) { | |
777 root.setBlocked(reason); | |
778 } | |
779 | |
780 protected static bool eq(String o1, String o2) { | |
781 if (o1.length is 0) | |
782 return (o2.length is 0); | |
783 if (o2.length is 0) | |
784 return false; | |
785 return o1.equals(o2); | |
786 } | |
787 } |