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 }