| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> |
| <html> |
| <head> |
| <meta http-equiv="Content-Type" content="text/html; charset=windows-1252"> |
| <title>Using Progress Monitors</title> |
| <link rel="stylesheet" href="../default_style.css"> |
| </head> |
| |
| <body link="#0000ff" vlink="#800080"> |
| <div align="right"> <font face="Times New Roman, Times, serif" size="2">Copyright |
| © 2016 Stefan Xenos and others</font> |
| |
| <table border="0" cellpadding="2" cellspacing="0" width="100%"> |
| <tbody> |
| <tr> |
| <td colspan="2" align="left" bgcolor="#0080c0" valign="top"><b><font face="Arial,Helvetica"><font color="#ffffff"> Eclipse |
| Corner Article</font></font></b></td> |
| </tr> |
| </tbody> |
| </table> |
| </div> |
| <div align="left"> |
| <h1><img src="images/Idea.jpg" align="middle" height="86" width="120"></h1> |
| </div> |
| <p> </p> |
| <h1 align="center">Using Progress Monitors</h1> |
| <blockquote> |
| <b>Summary</b> |
| |
| <br> |
| |
| In this article I'll explain how to report progress in Eclipse. I'll |
| discuss the contract on IProgressMonitor, demonstrate some common patterns |
| using SubMonitor, and explain how to migrate legacy code to take advantage |
| of the API introduced in Eclipse 4.6. |
| |
| <br> |
| |
| <p><b> By Stefan Xenos, Google</b> <br> |
| October 19, 2016<font size="-1"></font> </p> |
| |
| </blockquote> |
| |
| <hr width="100%"> |
| |
| <h2>1.0 Introduction</h2> |
| |
| So you're writing a long-running method. It takes an IProgressMonitor as a parameter. You want it to |
| report smooth progress, be cancellable from the UI thread and accomplish this with minimal boilerplate. |
| Unfortunately, most of the examples you've seen either omit progress reporting entirely or contain |
| more boilerplate than code. |
| <p> |
| Is it possible to get the smooth progress reporting without all that boilerplate? If so, what are the |
| responsibilities of your method and what are the responsibilities of its caller? This article should help. |
| |
| <h2>2.0 Using SubMonitor</h2> |
| |
| Use SubMonitor. If you remember nothing else from this article, remember that. |
| <p> |
| SubMonitor is an implementation of IProgressMonitor that simplifies everything related to progress |
| reporting. Whenever you write a method that accepts an IProgressMonitor, the first thing you should |
| do is convert it to a SubMonitor using <code>SubMonitor.convert(...)</code>. |
| |
| <h3>2.1 Allocating Ticks</h3> |
| <p> |
| There are several overloads for <code>convert</code> and most of them accept a number of ticks as an |
| argument. These are said to "allocate ticks". A tick is a unit of work to be performed. Allocating |
| ticks distributes those ticks across the remaining space of the progress monitor but doesn't |
| actually report any progress. It basically sets the denominator that will be used for subsequent |
| progress reporting. |
| <p> |
| How many ticks do you need? Take a look at all the slow things your method does and assign them |
| a number of ticks based on how long you think they will take. Any method you call that takes a |
| progress monitor should be considered a "slow thing". If you think one thing will take longer |
| than another, give it more ticks. If you think it will take twice as long, give it twice as many. |
| When you're done, add up all the ticks. That's how many you should allocate. Ticks only have |
| meaning relative to other ticks on the same monitor instance: their absolute value doesn't |
| mean anything. |
| <p> |
| There are several methods which allocate ticks. Normally you'll allocate them at construction-time |
| using <code>SubMonitor.convert(...)</code> but this only works if you're creating a new |
| SubMonitor instance. |
| <p> |
| Sometimes you'll want to allocate (or reallocate) the ticks on an existing |
| monitor in which case you'll want <code>SubMonitor.setWorkRemaining</code>. You can |
| call this as often as you like on a SubMonitor instance. When you do, any remaining unconsumed |
| space on the monitor is divided into the given number of ticks and any previously-allocated |
| ticks are forgotten. |
| <p> |
| The last method that allocates ticks is called <code>beginTask</code>. It's used as part of the |
| progress reporting framework and you rarely need to call it directly. You'll see this used |
| a lot in older code and we'll get more into it later. For now, it's best to avoid it in new |
| code unless you're implementing your own IProgressMonitor. |
| |
| <h3>2.2 Consuming Ticks</h3> |
| |
| Once you've allocated the ticks you can consume them. Consuming ticks is what reports progress. |
| Let's say you allocate 50 ticks and then consume 3 of them. That means your progress bar will |
| be 3/50 of the way across, or 6%. Note that you must allocate ticks before you can consume them |
| on any given progress monitor instance. Attempting to consume ticks without allocating them is an error. |
| <p> |
| There are several methods on SubMonitor which consume ticks. Namely, <code>split(...)</code>, |
| <code>newChild(...)</code>, and <code>worked(...)</code>. Practically speaking the only one you |
| need is <code>split(...)</code>. |
| <p> |
| I'll be using <code>split(...)</code> for most of the code examples in this article, but it is new |
| in Eclipse 4.6. If your code is meant to work on earlier versions of Eclipse you should use |
| <code>newChild(...)</code> instead of <code>split(...)</code>. The two do pretty much the same |
| thing except that <code>split(...)</code> also performs cancellation checks. |
| <p> |
| |
| <h3>2.3 Split</h3> |
| |
| <code>split(...)</code> doesn't immediately consume the ticks. It uses the ticks to create a new |
| child monitor but first it fully consumes any leftover ticks in any previous children |
| of the same parent. |
| <p> |
| I'll demonstrate with an example: |
| <pre> |
| void myMethod(IProgressMonitor monitor) { |
| // No ticks have been allocated yet, so we can't consume them. |
| SubMonitor subMonitor = SubMonitor.convert(monitor, 100); |
| |
| // monitor is now being managed by subMonitor. We shouldn't use it directly again. |
| // subMonitor has 100 ticks allocated for it and we can start consuming them. |
| |
| SubMonitor child1 = subMonitor.split(10); |
| |
| // subMonitor now has 90 ticks allocated. 10 of the original 100 were used to build child1. |
| // child1 has no ticks allocated for it yet so we can't consume ticks from it yet. |
| |
| child1.setWorkRemaining(100); |
| |
| // child1 now has 100 ticks allocated for it. Consuming 1 tick from child1 now would |
| // advance the root monitor by 0.1%. |
| |
| SubMonitor grandchild1 = child1.split(50); |
| |
| // child1 now has 50 ticks allocated. |
| |
| SubMonitor grandchild2 = child1.split(50); |
| |
| // Allocating a new grandchild from child1 has caused grandchild1 to be consumed. |
| // Our root progress monitor now shows 5% progress. |
| |
| SubMonitor child2 = subMonitor.split(40); |
| |
| // Allocating a new child from subMonitor has caused child1 and grandchild2 to be |
| // consumed. Our root progress monitor now shows 10% progress. |
| |
| SubMonitor child3 = subMonitor.split(10); |
| |
| // Child2 was consumed. The root progress monitor now shows 50% progress. |
| |
| SubMonitor child4 = subMonitor.split(40); |
| |
| // Child3 was consumed. The root progress monitor now shows 60% progress. |
| } |
| </pre> |
| |
| <h3>2.4 Cancellation</h3> |
| |
| Long-running methods should check the value of <code>IProgressMonitor.isCanceled()</code> |
| periodically. If it returns true, they should terminate cleanly and throw |
| <code>OperationCanceledException</code>. In Eclipse 4.5 and earlier, this was done with |
| explicit cancellation checks like this: |
| |
| <pre> |
| if (monitor.isCanceled()) { |
| throw new OperationCanceledException(); |
| } |
| </pre> |
| |
| Unfortunately, these sorts of cancellation checks are cumbersome and can become a |
| performance bottleneck if performed too frequently. |
| <p> |
| In Eclipse 4.6 and on, cancellation checks are be performed implicitly by |
| <code>SubMonitor.split(...)</code>. Code should be migrated to use <code>split</code> |
| wherever possible and explicit cancellation checks should be deleted. |
| <p> |
| So how does <code>split</code> work and how does it replace explicit cancellation checks? |
| It's basically just a helper that does the same thing as <code>newChild</code> but |
| additionally includes a cancellation check. Internally, split does something like this |
| (pseudocode): |
| |
| <pre> |
| SubMonitor split(int ticks) { |
| if (checking_cancelation_now_wouldnt_cause_a_performance_problem()) { |
| if (isCanceled()) { |
| throw new OperationCanceledException(); |
| } |
| } |
| return newChild(ticks); |
| } |
| </pre> |
| |
| <p> |
| In some rare cases, you really need to perform an explicit cancellation check |
| at a specific time and can't rely on the sparse cancellation checks done |
| by <code>split</code>. In such cases, you can use the <code>SubMonitor.checkCanceled</code> |
| utility introduced in Eclipse 4.7. |
| <p> |
| For example, this code converts an IProgressMonitor to a SubMonitor while performing |
| a guaranteed cancellation check: |
| <pre> |
| SubMonitor subMonitor = SubMonitor.convert(monitor).checkCanceled(); |
| </pre> |
| |
| <h3>2.5 Testing and Debugging</h3> |
| |
| Whenever you add or change progress monitoring in a method, you should test it by |
| enabling the progress monitor self-tests while you run your code. To do this, add |
| the following tracing options to an Eclipse .options file: |
| <p> |
| <pre> |
| org.eclipse.equinox.common/debug=true |
| org.eclipse.equinox.common/progress_monitors=true |
| </pre> |
| <p> |
| Once enabled, you will see a warning written to the log whenever your code violates |
| the API contracts on a SubMonitor. The tracing options can also be enabled in the |
| <i>tracing</i> tab of any launch configuration. If you maintain any code that reports |
| progress, it's generally a good idea to leave these options enabled at all times. |
| <p> |
| If you see nothing, it either means that your code is working perfectly or that the |
| diagnostic tool isn't running. You can confirm that the diagnostic tool is running by |
| using your debugger to confirm that the following variable is true: |
| |
| <pre> |
| org.eclipse.core.internal.runtime.TracingOptions.debugProgressMonitors |
| </pre> |
| <p> |
| More information about enabling Eclipse tracing options can be found |
| <a href="https://wiki.eclipse.org/FAQ_How_do_I_use_the_platform_debug_tracing_facility">here</a>. |
| |
| <h2>3.0 Examples</h2> |
| |
| Lets look at some examples of common progress reporting patterns. |
| |
| <h3>3.1 Calling child methods</h3> |
| |
| Most long-running operation will need to call out to other long-running operations. |
| |
| <pre> |
| void doSomething(IProgressMonitor monitor) { |
| // Convert the given monitor into a SubMonitor instance. We shouldn't use the original |
| // monitor object again since subMonitor will consume the entire monitor. |
| SubMonitor subMonitor = SubMonitor.convert(monitor, 100); |
| |
| // Use 30% of the progress to do some work |
| someChildTask(subMonitor.split(30)); |
| |
| // Use the remaining 70% of the progress to do some more work |
| someChildTask(subMonitor.split(70)); |
| } |
| </pre> |
| |
| <h3>3.2 Branches</h3> |
| |
| Sometimes some long-running piece of code is optional. If the optional piece is skipped, you still want the |
| total work to add up to 100%, but you also don't want to waste a portion of the progress monitor just to |
| make the ticks line up. One approach is to do the optional part first and then use setWorkRemaining to |
| redistribute the remaining ticks. |
| |
| <pre> |
| void doSomething(IProgressMonitor monitor) { |
| SubMonitor subMonitor = SubMonitor.convert(monitor, 100); |
| |
| if (condition1) { |
| doSomeWork(subMonitor.split(20)); |
| } |
| |
| // Don't report any work, but ensure that we have 80 ticks remaining on the progress monitor. |
| // If we already consumed ticks in the above branch, this is a no-op. Otherwise, the remaining |
| // space in the monitor is redistributed. |
| subMonitor.setWorkRemaining(80); |
| |
| if (condition2) { |
| doMoreWork(subMonitor.split(40)); |
| } |
| |
| subMonitor.setWorkRemaining(40) |
| |
| doSomeMoreWork(subMonitor.split(40)); |
| } |
| </pre> |
| |
| This approach works well enough in most cases and requires minimal boilerplate but the progress it reports |
| can sometimes be uneven if the method ends with a bunch of conditionals that are often skipped. Another |
| approach is to count the number of ticks in advance: |
| |
| <pre> |
| void doSomething(IProgressMonitor monitor) { |
| int totalTicks = 0; |
| if (condition1) { |
| totalTicks += OPERATION_ONE_TICKS; |
| } |
| if (condition2) { |
| totalTicks += OPERATION_TWO_TICKS; |
| } |
| if (condition3) { |
| totalTicks += OPERATION_THREE_TICKS; |
| } |
| // Allocate a different number of ticks based on which branches we expect to execute. |
| SubMonitor subMonitor = SubMonitor.convert(monitor, totalTicks); |
| |
| if (condition1) { |
| doSomeWork(subMonitor.split(OPERATION_ONE_TICKS)); |
| } |
| if (condition2) { |
| doSomeWork(subMonitor.split(OPERATION_TWO_TICKS)); |
| } |
| if (condition3) { |
| doSomeWork(subMonitor.split(OPERATION_THREE_TICKS)); |
| } |
| } |
| </pre> |
| |
| This will usually report smoother progress, but due to the extra complexity it's usually best to only |
| use this pattern if otherwise jerkiness of reported progress would be annoying to the user. |
| |
| <h3>3.3 Loops</h3> |
| |
| This example demonstrates how to report progress in a loop where every iteration takes roughly |
| the same amount of time.</p> |
| |
| <pre> |
| void doSomething(IProgressMonitor monitor, Collection someCollection) { |
| SubMonitor subMonitor = SubMonitor.convert(monitor, 100); |
| |
| // Create a new progress monitor for the loop. |
| SubMonitor loopMonitor = subMonitor.split(70).setWorkRemaining(someCollection.size()); |
| |
| for (Object next: someCollection) { |
| // Create a progress monitor for each loop iteration. |
| SubMonitor iterationMonitor = loopMonitor.split(1); |
| |
| doWorkOnElement(next, iterationMonitor); |
| } |
| |
| // The original progress monitor can be used for further work after the loop terminates. |
| doSomeWork(subMonitor.split(30)); |
| } |
| </pre> |
| |
| <h3>3.4 Skipping elements in a loop</h3> |
| |
| Sometimes some elements from a loop will be skipped. In that case, it's better to use the space |
| in the progress monitor to report the work done for the long-running elements rather than the |
| fast elements. |
| |
| <pre> |
| void doSomething(IProgressMonitor monitor, Collection someCollection) { |
| SubMonitor loopMonitor = SubMonitor.convert(monitor, someCollection.size()); |
| |
| int remaining = someCollection.size(); |
| for (Object next : someCollection) { |
| loopMonitor.setWorkRemaining(remaining--); |
| |
| if (shouldSkip(next)) { |
| continue; |
| } |
| |
| // Create a progress monitor for each loop iteration. |
| SubMonitor iterationMonitor = loopMonitor.split(1); |
| doWorkOnElement(next, iterationMonitor); |
| } |
| } |
| </pre> |
| |
| This works well enough if skipped elements are rare but if most of the elements are skipped, this pattern |
| will tend to make poor use of the end of the monitor. If many elements might be skipped, it's better to |
| pre-filter the list like this: |
| |
| <pre> |
| void doSomething(IProgressMonitor monitor, Collection someCollection) { |
| List filteredElements = someCollection |
| .stream() |
| .filter(next -> !shouldSkip(next)) |
| .collect(Collectors.toList()); |
| |
| SubMonitor loopMonitor = SubMonitor.convert(monitor, filteredElements.size()); |
| for (Object next : filteredElements) { |
| doWorkOnElement(next, loopMonitor.split(1)); |
| } |
| } |
| </pre> |
| |
| <h3>3.5 Queues</h3> |
| |
| What if you're performing a depth-first search or some other algorithm where more work is |
| continually discovered as you proceed? Try putting the work-discovered-so-far in a queue |
| and using the size of the queue to allocate ticks on your monitor. When using this pattern, |
| always make sure you never allocate less than some minimum number of ticks or you'll consume |
| the entire progress monitor on the first few iterations of your algorithm. |
| |
| <pre> |
| void depthFirstSearch(IProgressMonitor monitor, Object root) { |
| SubMonitor subMonitor = SubMonitor.convert(monitor); |
| ArrayList queue = new ArrayList(); |
| queue.add(root); |
| |
| while (!queue.isEmpty()) { |
| // Allocate a number of ticks equal to the size of the queue or some constant, |
| // whatever is larger. This constant prevents the entire monitor from being consumed |
| // at the start when the queue is very small. |
| subMonitor.setWorkRemaining(Math.max(queue.size(), 20)); |
| Object next = queue.remove(queue.size() - 1); |
| processElement(next, subMonitor.split(1)); |
| queue.addAll(getChildrenFor(next)); |
| } |
| } |
| </pre> |
| |
| <h3>3.6 Unknown progress</h3> |
| |
| What about those situations where you really have no idea how much work to report or how |
| long it will take? Try allocating a small percentage of the remaining space on each iteration. |
| |
| <pre> |
| void unknownProgress(IProgressMonitor monitor) { |
| SubMonitor subMonitor = SubMonitor.convert(monitor); |
| while (hasMore()) { |
| // Use 1% of the remaining space for each iteration |
| processNext(subMonitor.setWorkRemaining(100).split(1)); |
| } |
| } |
| </pre> |
| |
| Notice the idiom <code>setWorkRemaining(denominator).split(numerator)</code>. This can be used |
| at any point to consume numerator/denominator of the remaining space in a monitor. |
| |
| <h3>3.7 Try / catch / finally blocks</h3> |
| |
| What if you need to do something in a catch or finally block that reports progress? |
| This is tricky since catch and finally blocks should almost never perform cancellation checks. |
| Otherwise, they're likely to throw an <code>OperationCanceledException</code> while running the very |
| code that reacts to <code>OperationCanceledException</code>. For this reason, you should use the |
| <code>SUPPRESS_ISCANCELED</code> flag whenever creating a child monitor within a catch or finally |
| block. |
| |
| <pre> |
| void tryFinallyBlockExample(IProgressMonitor monitor) { |
| SubMonitor subMonitor = SubMonitor.convert(monitor, 2); |
| try { |
| doOperation(subMonitor.split(1)); |
| } catch (SomeException e) { |
| handleException(subMonitor.setWorkRemaining(2) |
| .split(1, SubMonitor.SUPPRESS_ISCANCELED | SubMonitor.SUPPRESS_BEGINTASK)); |
| } finally { |
| doFinallyBlock(subMonitor |
| .split(1, SubMonitor.SUPPRESS_ISCANCELED | SubMonitor.SUPPRESS_BEGINTASK)); |
| } |
| } |
| </pre> |
| |
| Notice that this example also uses the <code>SUPPRESS_BEGINTASK</code> flag. When passing flags to |
| <code>split</code> or <code>newChild</code>, you should always include the |
| <code>SUPPRESS_BEGINTASK</code> flag unless you have a specific reason not to. |
| |
| <h3>3.8 Naming conventions</h3> |
| |
| In these examples we've used the same naming convention that has been used within |
| the Eclipse platform. You may wish to use the same convention to help convey the purpose of your |
| progress monitors: |
| |
| <ul> |
| <li><b>subMonitor</b> - a SubMonitor that tracks the entire progress of the method.</li> |
| <li><b>loopMonitor</b> - a SubMonitor that tracks the progress of a single loop. If a method contains |
| multiple loops, this is used as a suffix.</li> |
| <li><b>iterationMonitor</b> - a SubMonitor that tracks the progress of a single iteration of a loop. |
| If there are multiple nested loops, this may be used as a suffix.</li> |
| <li><b>monitor</b> - an IProgressMonitor that is passed as a method argument.</li> |
| </ul> |
| |
| </ul> |
| |
| <h2>4.0 Responsibilities of callers and callees</h2> |
| |
| Imagine you need to invoke another method that accepts an IProgressMonitor. |
| What are the responsibilities of the caller and what are the responsibilities |
| of the callee? |
| <p> |
| The caller: |
| <ul> |
| <li><b>Will</b> pass an IProgressMonitor instance which has not had <code>beginTask</code> invoked on it yet |
| (or an implementation such as SubMonitor which permits beginTask to be invoked multiple times).</li> |
| <li><b>Will not</b> expect that the callee invokes <code>done()</code> on the monitor. The |
| caller must either use an SubMonitor (or a similar implementation which does not require <code>done()</code> |
| to be invoked), or it must take responsibility for calling <code>done()</code> on the monitor after the |
| callee has finished.</li> |
| <li><b>Will not</b> pass in a null monitor unless the JavaDoc for the callee says that it accepts null.</li> |
| <li><b>Will</b> pass in a monitor which ignores the String argument to <code>beginTask</code> unless the JavaDoc |
| for the callee says that it requires otherwise.</li> |
| </ul> |
| The callee: |
| <ul> |
| <li><b>Will</b> call <code>beginTask</code> 0 or 1 times on the monitor, at its option.</li> |
| <li><b>Will not</b> promise to call <code>done()</code> on the monitor, although it is allowed to do so.</li> |
| <li><b>Will not</b> call <code>setCanceled</code> on the monitor.</li> |
| <li><b>Will not</b> accept a null monitor unless its JavaDoc says otherwise.</li> |
| <li><b>Will not</b> expect the caller to do anything with the string passed to <code>beginTask</code> unless |
| its JavaDoc says otherwise.</li> |
| </ul> |
| |
| In practice, callers will be using SubMonitor wherever possible and method |
| implementations will not be calling <code>done()</code>. This means that the only |
| calls to <code>done()</code> will occur in root-level methods (methods which obtain |
| their own IProgressMonitor via some mechanism other than having it passed it as a method parameter). |
| |
| <h2>5.0 Different versions of Eclipse</h2> |
| |
| In Eclipse 4.5 (Mars) and earlier, it was standard practice for method implementations |
| to invoke <code>done()</code> on any monitor passed in as an argument and for the caller |
| to rely upon this fact. |
| <p> |
| In Eclipse 4.6 (Neon), method implementations should still invoke <code>done()</code> if |
| they did so previously. Callers are also required to either invoke <code>done()</code> |
| or select a monitor implementation like SubMonitor which doesn't require the use of |
| <code>done()</code>. |
| <p> |
| In Eclipse 4.7 (Oxygen) and higher, method implementations are not required to invoke |
| <code>done()</code>. Callers must either invoke <code>done()</code> or select a monitor |
| implementation like SubMonitor which doesn't require the use of <code>done()</code>. |
| |
| |
| <h3>5.1 Changes in Eclipse 4.6</h3> |
| |
| The following changes were made in Eclipse 4.6: |
| |
| <ul> |
| <li>SubMonitor now has a static <code>done(IProgressMonitor)</code> method that can be used to |
| call <code>done()</code> on a possibly-null IProgressMonitor instance.</li> |
| <li>The recommended policy for checking cancellation has changed. Rather than |
| using explicit cancellation checks, clients should rely on the implicit |
| cancellation checks done by SubMonitor.split.</li> |
| <li>SubProgressMonitor is now deprecated.</li> |
| </ul> |
| |
| As of Eclipse 4.6 (Neon), any client code that obtains a root monitor (any monitor |
| that isn't passed in as a method argument) is responsible for invoking <code>done()</code> |
| on that monitor. It must not rely on the methods it calls to invoke |
| <code>done()</code>. Please see the |
| <a href="https://www.eclipse.org/eclipse/development/porting/eclipse_4_6_porting_guide.html">Migration guide</a> |
| for more information on how to locate such code. |
| <p> |
| Method implementations that previously invoked <code>done()</code> should |
| continue to do so, since the root monitors need to be updated first. |
| |
| <h3>5.2 Migrating from SubProgressMonitor to SubMonitor</h3> |
| |
| Eclipse 3.2 and earlier used SubProgressMonitor for nesting progress monitors. This class is |
| deprecated as of Eclipse 4.6 (Neon). It has been replaced by SubMonitor. |
| <p> |
| The process for converting code which used SubProgressMonitor into SubMonitor is: |
| <ul> |
| <li>Calls to <code>IProgressMonitor.beginTask</code> on the root monitor should be replaced by a call |
| to <code>SubMonitor.convert</code>. Keep the returned SubMonitor around as a local variable and refer |
| to it instead of the root monitor for the remainder of the method.</li> |
| <li>All calls to <code>new SubProgressMonitor(IProgressMonitor, int)</code> should be replaced by calls to |
| <code>SubMonitor.split(int)</code>.</li> |
| <li>If a SubProgressMonitor is constructed using the SUPPRESS_SUBTASK_LABEL flag, replace it with the |
| two-argument version of <code>SubMonitor.split(int, int)</code> using <code>SubMonitor.SUPPRESS_SUBTASK</code> |
| as the second argument.</li> |
| <li>It is not necessary to call done on an instance of <code>SubMonitor</code>.</li> |
| <li>There is no drop-in replacement for PREPEND_MAIN_LABEL_TO_SUBTASK. PREPEND_MAIN_LABEL_TO_SUBTASK |
| made use of string arithmetic that didn't handle translation well. Clients that were using this |
| previously should switch to using fully-formatted task labels instead. |
| </ul> |
| |
| Note that <code>SubMonitor.convert(monitor, ticks)</code> is <b>not</b> a direct replacement for |
| <code>new SubProgressMonitor(monitor, ticks)</code>. The former fully consumes a |
| monitor which hasn't had ticks allocated on it yet and creates a new monitor with the given |
| number of ticks allocated. The latter consumes only the given number of ticks from an input |
| monitor which has already had ticks allocated and produces a monitor with no ticks allocated. |
| If you attempt to do a search-and-replace of one to the other, your progress reporting won't work. |
| |
| <h3>5.3 Changes in Eclipse 4.7</h3> |
| |
| In Eclipse 4.7 (Oxygen) and higher, method implementations that receive a progress monitor are |
| not required to invoke <code>done()</code> on it. Such calls may be removed if they were present |
| in earlier versions. |
| <p> |
| Methods in plugins that are also intended for use with earlier Eclipse versions should continue calling |
| <code>done()</code> as long as those earlier Eclipse versions are still being supported by the plugin. |
| <p> |
| Eclipse 4.7 also introduced the <code>SubMonitor.checkCanceled</code> utility for convenient |
| explicit cancellation checks. |
| |
| <h2>6.0 The protocol of <i>IProgressMonitor</i></h2> |
| |
| This section is for those of you doing something advanced. What if you want to implement your own |
| IProgressMonitor or can't use the SubMonitor helper class? In that case you'll need |
| to work with the IProgressMonitor contracts directly. |
| <p> |
| An IProgressMonitor instance can be in one of three states. Any given |
| implementation may or may not track state changes and may or may |
| not do anything about them. |
| <p> |
| |
| <b>UNALLOCATED</b> |
| <p> |
| This is the initial state of a newly created <code>IProgressMonitor</code> instance, |
| before <code>beginTask()</code> has been called to allocate ticks. Attempting to |
| call <code>worked()</code> or otherwise consume ticks from a monitor in this state is an error. |
| From here the monitor can enter the ALLOCATED state as a result of a <code>beginTask()</code> |
| call or the FINISHED <code>done()</code> state as a result of a call to <code>done()</code>. |
| <p> |
| <b>ALLOCATED</b> |
| <p> |
| The monitor enters this state after the first and only call to <code>beginTask()</code> |
| has allocated ticks for the monitor. Attempting to call <code>beginTask()</code> in this |
| state is an error. From here the monitor can enter the FINISHED state as a result of a |
| <code>done()</code> call. |
| <p> |
| <b>FINISHED</b> |
| <p> |
| The monitor enters this state after the first call to <code>done()</code>. |
| Unlike <code>beginTask()</code>, <code>done()</code> may be called any number of times. |
| However, only the first call to <code>done()</code> has any effect. |
| Reporting work or calling <code>beginTask()</code> on a FINISHED monitor is a programming |
| error and will have no effect. Unless the implementation says otherwise, <code>done()</code> must always |
| be called on a monitor once <code>beginTask()</code> has been called. |
| It is not necessary to call <code>done()</code> on a monitor in the UNALLOCATED |
| state. |
| </ul> |
| |
| <h3>6.1 Cancellation</h3> |
| |
| A monitor can become cancelled at any time due to activity on another thread. |
| The monitor indicates that it has been cancelled by returning |
| true from <code>isCanceled()</code>. When a long-running operation detects that |
| it has been cancelled, it should abort its operation cleanly. |
| <p> |
| It is technically possible to cancel a monitor by invoking |
| <code>setCanceled()</code> but you should |
| never do this. A long-running method that wishes to cancel itself it should |
| throw OperationCanceledException rather than invoking any particular method |
| on its monitor. |
| |
| <h3>6.2 Threading</h3> |
| |
| All implementations of IProgressMonitor are single-threaded by default. Unless the |
| JavaDoc for the specific monitor implementation says otherwise, all methods |
| must be invoked on the same thread that instantiated the monitor. If the concrete |
| type of the IProgressMonitor is unknown, it must be assumed to be single-threaded. |
| |
| <h3>6.3 Allocating ticks</h3> |
| |
| When using <code>beginTask</code> to allocate ticks on an IProgressMonitor, the caller should |
| always allocate at least 1000 ticks. Many root monitors use this value to set |
| the resolution for all subsequent progress reporting, even if the ticks are |
| later subdivided using a SubMonitor. |
| <p> |
| SubMonitor users don't need to worry about this since <code>SubMonitor.convert</code> |
| does this internally when converting an unknown monitor. |
| <p> |
| |
| <h3>6.4 Passing strings to beginTask</h3> |
| |
| At the lowest level, any method that needs to allocate ticks ends up calling |
| <code>beginTask</code>. Usually this is done indirectly by a call to |
| <code>SubMonitor.convert(...)</code>. Unfortunately, <code>beginTask</code> |
| also takes a string argument which root monitors use to set the task name. |
| <p> |
| Every long-running operation needs to allocate ticks but most don't want to |
| modify the task name. For this reason, most callers of <code>beginTask</code> |
| call it with the empty string or a temporary string that isn't intended |
| to be seen by the end user. Similarly, most implementations of |
| <code>beginTask</code> are expected to ignore the string argument. |
| <p> |
| The exception is root monitors. Many root monitors display the string argument |
| somewhere. For this reason, any code that obtains a root monitor is expected |
| to convert it to a form that will filter out the string argument |
| before passing it to another method. |
| <p> |
| The default expectation is that progress monitors passed as parameters will |
| do this filtering. Any method that receives a progress monitor and does not |
| want the <code>beginTask(...)</code> argument filtered must say so clearly in |
| its JavaDoc. |
| |
| <h3>6.5 IProgressMonitor.UNKNOWN</h3> |
| |
| IProgressMonitor.UNKNOWN is only supported by root monitors and should never |
| be used by method implementations which receive a progress monitor as a parameter. |
| |
| <h3>6.6 Task names and performance concerns</h3> |
| |
| As of the time of this writing (Eclipse 4.6), several of the root monitors |
| in Eclipse have expensive implementations of <code>setTaskName(...)</code> |
| and <code>subTask(...)</code>. Plugin authors are advised not to call |
| these methods more than 3 times per second. Doing so may introduce |
| performance problems. See |
| <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=445802">Eclipse bug 445802</a> |
| for more information. |
| <p> |
| </body> |
| </html> |