KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > runtime > SubMonitor


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  *******************************************************************************/

13 package org.eclipse.core.runtime;
14
15 /**
16  * <p>A progress monitor that uses a given amount of work ticks from a parent monitor. This is intended as a
17  * safer, easier-to-use alternative to SubProgressMonitor. The main benefits of SubMonitor over
18  * SubProgressMonitor are:</p>
19  * <ul>
20  * <li>It is not necessary to call beginTask() or done() on an instance of SubMonitor.</li>
21  * <li>SubMonitor has a simpler syntax for creating nested monitors.</li>
22  * <li>SubMonitor is more efficient for deep recursion chains.</li>
23  * <li>SubMonitor has a setWorkRemining method that allows the remaining space on the monitor to be
24  * redistributed without reporting any work.</li>
25  * <li>SubMonitor protects the caller from common progress reporting bugs in a called method. For example,
26  * if a called method fails to call done() on the given monitor or fails to consume all the ticks on
27  * the given monitor, the parent will correct the problem after the method returns.</li>
28  * </ul>
29  * <p></p>
30  * <p><b>USAGE:</b></p>
31  *
32  * <p>When implementing a method that accepts an IProgressMonitor:</p>
33  * <ul>
34  * <li>At the start of your method, use <code>SubMonitor.convert(...).</code> to convert the IProgressMonitor
35  * into a SubMonitor. </li>
36  * <li>Use <code>SubMonitor.newChild(...)</code> whenever you need to call another method that
37  * accepts an IProgressMonitor.</li>
38  * </ul>
39  * <p></p>
40  * <p><b>DEFAULT BEHAVIOR:</b></p>
41  *
42  * <p>When writing JavaDoc for a method that accepts an IProgressMonitor, you should assume the
43  * following default behavior unless the method's JavaDoc says otherwise:</p>
44  * <ul>
45  * <li>It WILL call beginTask on the IProgressMonitor.</li>
46  * <li>It WILL NOT accept a null argument.</li>
47  * <li>It WILL call done on the IProgressMonitor.</li>
48  * </ul>
49  * <p></p>
50  * <p><b>BEST PRACTISES:</b></p>
51  *
52  * <p>We recommend that newly-written methods follow the given contract:</p>
53  * <ul>
54  * <li>It WILL call beginTask on the IProgressMonitor.</li>
55  * <li>It WILL accept a null argument, indicating that no progress should be reported and the operation cannot be cancelled.</li>
56  * <li>It WILL NOT call done on the IProgressMonitor, leaving this responsibility up to the caller.</li>
57  * </ul>
58  * <p>If you wish to follow these conventions, you may copy and paste the following text into your method's JavaDoc:</p>
59  *
60  * <pre>@param monitor the progress monitor to use for reporting progress to the user. It is the caller's responsibility
61  * to call done() on the given monitor. Accepts <code>null</code>, indicating that no progress should be
62  * reported and that the operation cannot be cancelled.</pre>
63  *
64  * <p></p>
65  * <p><b>Example: Recommended usage</b></p>
66  *
67  * <p>This example demonstrates how the recommended usage of <code>SubMonitor</code> makes it unnecessary to call
68  * IProgressMonitor.done() in most situations.</p>
69  *
70  * <p>It is never necessary to call done() on a monitor obtained from <code>convert</code> or <code>progress.newChild()</code>.
71  * In this example, there is no guarantee that <code>monitor</code> is an instance of <code>SubMonitor</code>, making it
72  * necessary to call <code>monitor.done()</code>. The JavaDoc contract makes this the responsibility of the caller.</p>
73  *
74  * <pre>
75  * // param monitor the progress monitor to use for reporting progress to the user. It is the caller's responsibility
76  * // to call done() on the given monitor. Accepts <code>null</code>, indicating that no progress should be
77  * // reported and that the operation cannot be cancelled.
78  * //
79  * void doSomething(IProgressMonitor monitor) {
80  * // Convert the given monitor into a progress instance
81  * SubMonitor progress = SubMonitor.convert(monitor, 100);
82  *
83  * // Use 30% of the progress to do some work
84  * doSomeWork(progress.newChild(30));
85  *
86  * // Advance the monitor by another 30%
87  * progress.worked(30);
88  *
89  * // Use the remaining 40% of the progress to do some more work
90  * doSomeWork(progress.newChild(40));
91  * }
92  * </pre>
93  *
94  *
95  * <p></p>
96  * <p><b>Example: Default usage</b></p>
97  *
98  * <p>You will often need to implement a method that does not explicitly stipulate that calling done() is the responsibility
99  * of the caller. In this case, you should use the following pattern:</p>
100  *
101  * <pre>
102  * // param monitor the progress monitor to use for reporting progress to the user, or <code>null</code> indicating
103  * // that no progress should be reported and the operation cannot be cancelled.
104  * //
105  * void doSomething(IProgressMonitor monitor) {
106  * // Convert the given monitor into a progress instance
107  * SubMonitor progress = SubMonitor.convert(monitor, 100);
108  * try {
109  * // Use 30% of the progress to do some work
110  * doSomeWork(progress.newChild(30));
111  *
112  * // Advance the monitor by another 30%
113  * progress.worked(30);
114  *
115  * // Use the remaining 40% of the progress to do some more work
116  * doSomeWork(progress.newChild(40));
117  *
118  * } finally {
119  * if (monitor != null) {
120  * monitor.done();
121  * }
122  * }
123  * }
124  * </pre>
125  *
126  * <p></p>
127  * <p><b>Example: Branches</b></p>
128  *
129  * <p>This example demonstrates how to smoothly report progress in situations where some of the work is optional.</p>
130  *
131  * <pre>
132  * void doSomething(IProgressMonitor monitor) {
133  * SubMonitor progress = SubMonitor.convert(monitor, 100);
134  *
135  * if (condition) {
136  * // Use 50% of the progress to do some work
137  * doSomeWork(progress.newChild(50));
138  * }
139  *
140  * // Don't report any work, but ensure that we have 50 ticks remaining on the progress monitor.
141  * // If we already consumed 50 ticks in the above branch, this is a no-op. Otherwise, the remaining
142  * // space in the monitor is redistributed into 50 ticks.
143  *
144  * progress.setWorkRemaining(50);
145  *
146  * // Use the remainder of the progress monitor to do the rest of the work
147  * doSomeWork(progress.newChild(50));
148  * }
149  * </pre>
150  *
151  * <p>Please beware of the following anti-pattern:</p>
152  *
153  * <pre>
154  * if (condition) {
155  * // Use 50% of the progress to do some work
156  * doSomeWork(progress.newChild(50));
157  * } else {
158  * // Bad: Causes the progress monitor to appear to start at 50%, wasting half of the
159  * // space in the monitor.
160  * progress.worked(50);
161  * }
162  * </pre>
163  *
164  *
165  * <p></p>
166  * <p><b>Example: Loops</b></p>
167  *
168  * <p>This example demonstrates how to report progress in a loop.</p>
169  *
170  * <pre>
171  * void doSomething(IProgressMonitor monitor, Collection someCollection) {
172  * SubMonitor progress = SubMonitor.convert(monitor, 100);
173  *
174  * // Create a new progress monitor that uses 70% of the total progress and will allocate one tick
175  * // for each element of the given collection.
176  * SubMonitor loopProgress = progress.newChild(70).setWorkRemaining(someCollection.size());
177  *
178  * for (Iterator iter = someCollection.iterator(); iter.hasNext();) {
179  * Object next = iter.next();
180  *
181  * doWorkOnElement(next, loopProgress.newChild(1));
182  * }
183  *
184  * // Use the remaining 30% of the progress monitor to do some work outside the loop
185  * doSomeWork(progress.newChild(30));
186  * }
187  * </pre>
188  *
189  *
190  * <p></p>
191  * <p><b>Example: Infinite progress</b></p>
192  *
193  * <p>This example demonstrates how to report logarithmic progress in situations where the number of ticks
194  * cannot be easily computed in advance.</p>
195  *
196  * <pre>
197  * void doSomething(IProgressMonitor monitor, LinkedListNode node) {
198  * SubMonitor progress = SubMonitor.convert(monitor, 100);
199  *
200  * while (node != null) {
201  * // Regardless of the amount of progress reported so far,
202  * // use 5% of the space remaining in the monitor to process the next node.
203  * progress.setWorkRemaining(100);
204  *
205  * doWorkOnElement(node, progress.newChild(5));
206  *
207  * node = node.next;
208  * }
209  * }
210  * </pre>
211  *
212  * <p>
213  * This class can be used without OSGi running.
214  * </p>
215  *
216  * @since org.eclipse.equinox.common 3.3
217  */

218 public final class SubMonitor implements IProgressMonitorWithBlocking {
219
220     /**
221      * Minimum number of ticks to allocate when calling beginTask on an unknown IProgressMonitor.
222      * Pick a number that is big enough such that, no matter where progress is being displayed,
223      * the user would be unlikely to notice if progress were to be reported with higher accuracy.
224      */

225     private static final int MINIMUM_RESOLUTION = 1000;
226
227     /**
228      * The RootInfo struct holds information about the root progress monitor. A SubMonitor and
229      * its active descendents share the same RootInfo struct.
230      */

231     private static final class RootInfo {
232         private final IProgressMonitor root;
233
234         /**
235          * Remembers the last task name. Prevents us from setting the same task name multiple
236          * times in a row.
237          */

238         private String JavaDoc taskName = null;
239
240         /**
241          * Remembers the last subtask name. Prevents the SubMonitor from setting the same
242          * subtask string more than once in a row.
243          */

244         private String JavaDoc subTask = null;
245
246         /**
247          * Creates a RootInfo struct that delegates to the given progress
248          * monitor.
249          *
250          * @param root progress monitor to delegate to
251          */

252         public RootInfo(IProgressMonitor root) {
253             this.root = root;
254         }
255
256         public boolean isCanceled() {
257             return root.isCanceled();
258         }
259
260         public void setCanceled(boolean value) {
261             root.setCanceled(value);
262         }
263
264         public void setTaskName(String JavaDoc taskName) {
265             if (eq(taskName, this.taskName)) {
266                 return;
267             }
268             this.taskName = taskName;
269             root.setTaskName(taskName);
270         }
271
272         public void subTask(String JavaDoc name) {
273             if (eq(subTask, name)) {
274                 return;
275             }
276
277             this.subTask = name;
278             root.subTask(name);
279         }
280
281         public void worked(int i) {
282             root.worked(i);
283         }
284
285         public void clearBlocked() {
286             if (root instanceof IProgressMonitorWithBlocking)
287                 ((IProgressMonitorWithBlocking) root).clearBlocked();
288         }
289
290         public void setBlocked(IStatus reason) {
291             if (root instanceof IProgressMonitorWithBlocking)
292                 ((IProgressMonitorWithBlocking) root).setBlocked(reason);
293         }
294
295     }
296
297     /**
298      * Total number of ticks that this progress monitor is permitted to consume
299      * from the root.
300      */

301     private int totalParent;
302
303     /**
304      * Number of ticks that this progress monitor has already reported in the root.
305      */

306     private int usedForParent = 0;
307
308     /**
309      * Number of ticks that have been consumed by this instance's children.
310      */

311     private double usedForChildren = 0.0;
312
313     /**
314      * Number of ticks allocated for this instance's children. This is the total number
315      * of ticks that may be passed into worked(int) or newChild(int).
316      */

317     private int totalForChildren;
318
319     /**
320      * Children created by newChild will be completed automatically the next time
321      * the parent progress monitor is touched. This points to the last incomplete child
322      * created with newChild.
323      */

324     private IProgressMonitor lastSubMonitor = null;
325
326     /**
327      * Used to communicate with the root of this progress monitor tree
328      */

329     private final RootInfo root;
330
331     /**
332      * A bitwise combination of the SUPPRESS_* flags.
333      */

334     private final int flags;
335
336     /**
337      * May be passed as a flag to newChild. Indicates that the calls
338      * to subTask on the child should be ignored. Without this flag,
339      * calling subTask on the child will result in a call to subTask
340      * on its parent.
341      */

342     public static final int SUPPRESS_SUBTASK = 0x0001;
343
344     /**
345      * May be passed as a flag to newChild. Indicates that strings
346      * passed into beginTask should be ignored. If this flag is
347      * specified, then the progress monitor instance will accept null
348      * as the first argument to beginTask. Without this flag, any
349      * string passed to beginTask will result in a call to
350      * setTaskName on the parent.
351      */

352     public static final int SUPPRESS_BEGINTASK = 0x0002;
353
354     /**
355      * May be passed as a flag to newChild. Indicates that strings
356      * passed into setTaskName should be ignored. If this string
357      * is omitted, then a call to setTaskName on the child will
358      * result in a call to setTaskName on the parent.
359      */

360     public static final int SUPPRESS_SETTASKNAME = 0x0004;
361
362     /**
363      * May be passed as a flag to newChild. Indicates that strings
364      * passed to setTaskName, subTask, and beginTask should all be ignored.
365      */

366     public static final int SUPPRESS_ALL_LABELS = SUPPRESS_SETTASKNAME | SUPPRESS_BEGINTASK | SUPPRESS_SUBTASK;
367
368     /**
369      * May be passed as a flag to newChild. Indicates that strings
370      * passed to setTaskName, subTask, and beginTask should all be propogated
371      * to the parent.
372      */

373     public static final int SUPPRESS_NONE = 0;
374
375     /**
376      * Creates a new SubMonitor that will report its progress via
377      * the given RootInfo.
378      * @param rootInfo the root of this progress monitor tree
379      * @param totalWork total work to perform on the given progress monitor
380      * @param availableToChildren number of ticks allocated for this instance's children
381      * @param flags a bitwise combination of the SUPPRESS_* constants
382      */

383     private SubMonitor(RootInfo rootInfo, int totalWork, int availableToChildren, int flags) {
384         root = rootInfo;
385         totalParent = (totalWork > 0) ? totalWork : 0;
386         this.totalForChildren = availableToChildren;
387         this.flags = flags;
388     }
389
390     /**
391      * <p>Converts an unknown (possibly null) IProgressMonitor into a SubMonitor. It is
392      * not necessary to call done() on the result, but the caller is responsible for calling
393      * done() on the argument. Calls beginTask on the argument.</p>
394      *
395      * <p>This method should generally be called at the beginning of a method that accepts
396      * an IProgressMonitor in order to convert the IProgressMonitor into a SubMonitor.</p>
397      *
398      * @param monitor monitor to convert to a SubMonitor instance or null. Treats null
399      * as a new instance of <code>NullProgressMonitor</code>.
400      * @return a SubMonitor instance that adapts the argument
401      */

402     public static SubMonitor convert(IProgressMonitor monitor) {
403         return convert(monitor, "", 0); //$NON-NLS-1$
404
}
405
406     /**
407      * <p>Converts an unknown (possibly null) IProgressMonitor into a SubMonitor allocated
408      * with the given number of ticks. It is not necessary to call done() on the result,
409      * but the caller is responsible for calling done() on the argument. Calls beginTask
410      * on the argument.</p>
411      *
412      * <p>This method should generally be called at the beginning of a method that accepts
413      * an IProgressMonitor in order to convert the IProgressMonitor into a SubMonitor.</p>
414      *
415      * @param monitor monitor to convert to a SubMonitor instance or null. Treats null
416      * as a new instance of <code>NullProgressMonitor</code>.
417      * @param work number of ticks that will be available in the resulting monitor
418      * @return a SubMonitor instance that adapts the argument
419      */

420     public static SubMonitor convert(IProgressMonitor monitor, int work) {
421         return convert(monitor, "", work); //$NON-NLS-1$
422
}
423
424     /**
425      * <p>Converts an unknown (possibly null) IProgressMonitor into a SubMonitor allocated
426      * with the given number of ticks. It is not necessary to call done() on the result,
427      * but the caller is responsible for calling done() on the argument. Calls beginTask
428      * on the argument.</p>
429      *
430      * <p>This method should generally be called at the beginning of a method that accepts
431      * an IProgressMonitor in order to convert the IProgressMonitor into a SubMonitor.</p>
432      *
433      * @param monitor to convert into a SubMonitor instance or null. If given a null argument,
434      * the resulting SubMonitor will not report its progress anywhere.
435      * @param taskName user readable name to pass to monitor.beginTask. Never null.
436      * @param work initial number of ticks to allocate for children of the SubMonitor
437      * @return a new SubMonitor instance that is a child of the given monitor
438      */

439     public static SubMonitor convert(IProgressMonitor monitor, String JavaDoc taskName, int work) {
440         if (monitor == null)
441             monitor = new NullProgressMonitor();
442
443         // Optimization: if the given monitor already a SubMonitor, no conversion is necessary
444
if (monitor instanceof SubMonitor) {
445             monitor.beginTask(taskName, work);
446             return (SubMonitor) monitor;
447         }
448
449         monitor.beginTask(taskName, MINIMUM_RESOLUTION);
450         return new SubMonitor(new RootInfo(monitor), MINIMUM_RESOLUTION, work, SUPPRESS_NONE);
451     }
452
453     /**
454      * <p>Sets the work remaining for this SubMonitor instance. This is the total number
455      * of ticks that may be reported by all subsequent calls to worked(int), newChild(int), etc.
456      * This may be called many times for the same SubMonitor instance. When this method
457      * is called, the remaining space on the progress monitor is redistributed into the given
458      * number of ticks.</p>
459      *
460      * <p>It doesn't matter how much progress has already been reported with this SubMonitor
461      * instance. If you call setWorkRemaining(100), you will be able to report 100 more ticks of
462      * work before the progress meter reaches 100%.</p>
463      *
464      * @param workRemaining total number of remaining ticks
465      * @return the receiver
466      */

467     public SubMonitor setWorkRemaining(int workRemaining) {
468         // Ensure we don't try to allocate negative ticks
469
workRemaining = Math.max(0, workRemaining);
470
471         // Ensure we don't cause division by zero
472
if (totalForChildren > 0 && totalParent > usedForParent) {
473             // Note: We want the following value to remain invariant after this method returns
474
double remainForParent = totalParent * (1.0d - (usedForChildren / totalForChildren));
475             usedForChildren = (workRemaining * (1.0d - remainForParent / (totalParent - usedForParent)));
476         } else
477             usedForChildren = 0.0d;
478
479         totalParent = totalParent - usedForParent;
480         usedForParent = 0;
481         totalForChildren = workRemaining;
482         return this;
483     }
484
485     /**
486      * Consumes the given number of child ticks, given as a double. Must only
487      * be called if the monitor is in floating-point mode.
488      *
489      * @param ticks the number of ticks to consume
490      * @return ticks the number of ticks to be consumed from parent
491      */

492     private int consume(double ticks) {
493         if (totalParent == 0 || totalForChildren == 0) // this monitor has no available work to report
494
return 0;
495
496         usedForChildren += ticks;
497
498         if (usedForChildren > totalForChildren)
499             usedForChildren = totalForChildren;
500         else if (usedForChildren < 0.0)
501             usedForChildren = 0.0;
502
503         int parentPosition = (int) (totalParent * usedForChildren / totalForChildren);
504         int delta = parentPosition - usedForParent;
505
506         usedForParent = parentPosition;
507         return delta;
508     }
509
510     /* (non-Javadoc)
511      * @see org.eclipse.core.runtime.IProgressMonitor#isCanceled()
512      */

513     public boolean isCanceled() {
514         return root.isCanceled();
515     }
516
517     /* (non-Javadoc)
518      * @see org.eclipse.core.runtime.IProgressMonitor#setTaskName(java.lang.String)
519      */

520     public void setTaskName(String JavaDoc name) {
521         if ((flags & SUPPRESS_SETTASKNAME) == 0)
522             root.setTaskName(name);
523     }
524
525     /**
526      * Starts a new main task. The string argument is ignored
527      * if and only if the SUPPRESS_BEGINTASK flag has been set on this SubMonitor
528      * instance.
529      *
530      * <p>This method is equivalent calling setWorkRemaining(...) on the reciever. Unless
531      * the SUPPRESS_BEGINTASK flag is set, this will also be equivalent to calling
532      * setTaskName(...) on the parent.</p>
533      *
534      * @param name new main task name
535      * @param totalWork number of ticks to allocate
536      *
537      * @see org.eclipse.core.runtime.IProgressMonitor#beginTask(java.lang.String, int)
538      */

539     public void beginTask(String JavaDoc name, int totalWork) {
540         if ((flags & SUPPRESS_BEGINTASK) == 0 && name != null)
541             root.setTaskName(name);
542         setWorkRemaining(totalWork);
543     }
544
545     /* (non-Javadoc)
546      * @see org.eclipse.core.runtime.IProgressMonitor#done()
547      */

548     public void done() {
549         cleanupActiveChild();
550         int delta = totalParent - usedForParent;
551         if (delta > 0)
552             root.worked(delta);
553
554         totalParent = 0;
555         usedForParent = 0;
556         totalForChildren = 0;
557         usedForChildren = 0.0d;
558     }
559
560     /* (non-Javadoc)
561      * @see org.eclipse.core.runtime.IProgressMonitor#internalWorked(double)
562      */

563     public void internalWorked(double work) {
564         int delta = consume((work > 0.0d) ? work : 0.0d);
565         if (delta != 0)
566             root.worked(delta);
567     }
568
569     /* (non-Javadoc)
570      * @see org.eclipse.core.runtime.IProgressMonitor#subTask(java.lang.String)
571      */

572     public void subTask(String JavaDoc name) {
573         if ((flags & SUPPRESS_SUBTASK) == 0)
574             root.subTask(name);
575     }
576
577     /* (non-Javadoc)
578      * @see org.eclipse.core.runtime.IProgressMonitor#worked(int)
579      */

580     public void worked(int work) {
581         internalWorked(work);
582     }
583
584     /* (non-Javadoc)
585      * @see org.eclipse.core.runtime.IProgressMonitor#setCanceled(boolean)
586      */

587     public void setCanceled(boolean b) {
588         root.setCanceled(b);
589     }
590
591     /**
592      * <p>Creates a sub progress monitor that will consume the given number of ticks from the
593      * receiver. It is not necessary to call <code>beginTask</code> or <code>done</code> on the
594      * result. However, the resulting progress monitor will not report any work after the first
595      * call to done() or before ticks are allocated. Ticks may be allocated by calling beginTask
596      * or setWorkRemaining.</p>
597      *
598      * <p>Each SubMonitor only has one active child at a time. Each time newChild() is called, the
599      * result becomes the new active child and any unused progress from the previously-active child is
600      * consumed.</p>
601      *
602      * <p>This is property makes it unnecessary to call done() on a SubMonitor instance, since child
603      * monitors are automatically cleaned up the next time the parent is touched.</p>
604      *
605      * <code><pre>
606      * ////////////////////////////////////////////////////////////////////////////
607      * // Example 1: Typical usage of newChild
608      * void myMethod(IProgressMonitor parent) {
609      * SubMonitor progress = SubMonitor.convert(parent, 100);
610      * doSomething(progress.newChild(50));
611      * doSomethingElse(progress.newChild(50));
612      * }
613      *
614      * ////////////////////////////////////////////////////////////////////////////
615      * // Example 2: Demonstrates the function of active children. Creating children
616      * // is sufficient to smoothly report progress, even if worked(...) and done()
617      * // are never called.
618      * void myMethod(IProgressMonitor parent) {
619      * SubMonitor progress = SubMonitor.convert(parent, 100);
620      *
621      * for (int i = 0; i < 100; i++) {
622      * // Creating the next child monitor will clean up the previous one,
623      * // causing progress to be reported smoothly even if we don't do anything
624      * // with the monitors we create
625      * progress.newChild(1);
626      * }
627      * }
628      *
629      * ////////////////////////////////////////////////////////////////////////////
630      * // Example 3: Demonstrates a common anti-pattern
631      * void wrongMethod(IProgressMonitor parent) {
632      * SubMonitor progress = SubMonitor.convert(parent, 100);
633      *
634      * // WRONG WAY: Won't have the intended effect, as only one of these progress
635      * // monitors may be active at a time and the other will report no progress.
636      * callMethod(progress.newChild(50), computeValue(progress.newChild(50)));
637      * }
638      *
639      * void rightMethod(IProgressMonitor parent) {
640      * SubMonitor progress = SubMonitor.convert(parent, 100);
641      *
642      * // RIGHT WAY: Break up method calls so that only one SubMonitor is in use at a time.
643      * Object someValue = computeValue(progress.newChild(50));
644      * callMethod(progress.newChild(50), someValue);
645      * }
646      * </pre></code>
647      *
648      * @param totalWork number of ticks to consume from the reciever
649      * @return new sub progress monitor that may be used in place of a new SubMonitor
650      */

651     public SubMonitor newChild(int totalWork) {
652         return newChild(totalWork, SUPPRESS_BEGINTASK);
653     }
654
655     /**
656      * <p>Creates a sub progress monitor that will consume the given number of ticks from the
657      * receiver. It is not necessary to call <code>beginTask</code> or <code>done</code> on the
658      * result. However, the resulting progress monitor will not report any work after the first
659      * call to done() or before ticks are allocated. Ticks may be allocated by calling beginTask
660      * or setWorkRemaining.</p>
661      *
662      * <p>Each SubMonitor only has one active child at a time. Each time newChild() is called, the
663      * result becomes the new active child and any unused progress from the previously-active child is
664      * consumed.</p>
665      *
666      * <p>This is property makes it unnecessary to call done() on a SubMonitor instance, since child
667      * monitors are automatically cleaned up the next time the parent is touched.</p>
668      *
669      * <code><pre>
670      * ////////////////////////////////////////////////////////////////////////////
671      * // Example 1: Typical usage of newChild
672      * void myMethod(IProgressMonitor parent) {
673      * SubMonitor progress = SubMonitor.convert(parent, 100);
674      * doSomething(progress.newChild(50));
675      * doSomethingElse(progress.newChild(50));
676      * }
677      *
678      * ////////////////////////////////////////////////////////////////////////////
679      * // Example 2: Demonstrates the function of active children. Creating children
680      * // is sufficient to smoothly report progress, even if worked(...) and done()
681      * // are never called.
682      * void myMethod(IProgressMonitor parent) {
683      * SubMonitor progress = SubMonitor.convert(parent, 100);
684      *
685      * for (int i = 0; i < 100; i++) {
686      * // Creating the next child monitor will clean up the previous one,
687      * // causing progress to be reported smoothly even if we don't do anything
688      * // with the monitors we create
689      * progress.newChild(1);
690      * }
691      * }
692      *
693      * ////////////////////////////////////////////////////////////////////////////
694      * // Example 3: Demonstrates a common anti-pattern
695      * void wrongMethod(IProgressMonitor parent) {
696      * SubMonitor progress = SubMonitor.convert(parent, 100);
697      *
698      * // WRONG WAY: Won't have the intended effect, as only one of these progress
699      * // monitors may be active at a time and the other will report no progress.
700      * callMethod(progress.newChild(50), computeValue(progress.newChild(50)));
701      * }
702      *
703      * void rightMethod(IProgressMonitor parent) {
704      * SubMonitor progress = SubMonitor.convert(parent, 100);
705      *
706      * // RIGHT WAY: Break up method calls so that only one SubMonitor is in use at a time.
707      * Object someValue = computeValue(progress.newChild(50));
708      * callMethod(progress.newChild(50), someValue);
709      * }
710      * </pre></code>
711      *
712      * @param totalWork number of ticks to consume from the reciever
713      * @return new sub progress monitor that may be used in place of a new SubMonitor
714      */

715     public SubMonitor newChild(int totalWork, int suppressFlags) {
716         double totalWorkDouble = (totalWork > 0) ? totalWork : 0.0d;
717         totalWorkDouble = Math.min(totalWorkDouble, totalForChildren - usedForChildren);
718         cleanupActiveChild();
719
720         // Compute the flags for the child. We want the net effect to be as though the child is
721
// delegating to its parent, even though it is actually talking directly to the root.
722
// This means that we need to compute the flags such that - even if a label isn't
723
// suppressed by the child - if that same label would have been suppressed when the
724
// child delegated to its parent, the child must explicitly suppress the label.
725
int childFlags = SUPPRESS_NONE;
726
727         if ((flags & SUPPRESS_SETTASKNAME) != 0) {
728             // If the parent was ignoring labels passed to setTaskName, then the child will ignore
729
// labels passed to either beginTask or setTaskName - since both delegate to setTaskName
730
// on the parent
731
childFlags |= SUPPRESS_SETTASKNAME | SUPPRESS_BEGINTASK;
732         }
733
734         if ((flags & SUPPRESS_SUBTASK) != 0) {
735             // If the parent was suppressing labels passed to subTask, so will the child.
736
childFlags |= SUPPRESS_SUBTASK;
737         }
738
739         // Note: the SUPPRESS_BEGINTASK flag does not affect the child since there
740
// is no method on the child that would delegate to beginTask on the parent.
741
childFlags |= suppressFlags;
742
743         SubMonitor result = new SubMonitor(root, consume(totalWorkDouble), 0, childFlags);
744         lastSubMonitor = result;
745         return result;
746     }
747
748     private void cleanupActiveChild() {
749         if (lastSubMonitor == null)
750             return;
751
752         IProgressMonitor child = lastSubMonitor;
753         lastSubMonitor = null;
754         child.done();
755     }
756
757     /* (non-Javadoc)
758      * @see org.eclipse.core.runtime.IProgressMonitorWithBlocking#clearBlocked()
759      */

760     public void clearBlocked() {
761         root.clearBlocked();
762     }
763
764     /* (non-Javadoc)
765      * @see org.eclipse.core.runtime.IProgressMonitorWithBlocking#setBlocked(org.eclipse.core.runtime.IStatus)
766      */

767     public void setBlocked(IStatus reason) {
768         root.setBlocked(reason);
769     }
770
771     protected static boolean eq(Object JavaDoc o1, Object JavaDoc o2) {
772         if (o1 == null)
773             return (o2 == null);
774         if (o2 == null)
775             return false;
776         return o1.equals(o2);
777     }
778 }
779
Popular Tags