Are you working with Progress Monitors, and wish you did not have too?
I recently got to investigate issues in p2 why the progress bar did not move while it was very clear that things where happening as subtasks changed the text. Looking into what was going on made me find a new Progress Monitor anti pattern.
The problem is how to handle a case where you need to do something like this:
Where a call to loadCandidate is potentially a long running task. The first loaded candidate means we are done.
Here is an implementation of the above example using the antipattern - i.e. "don't do this:
Well, what is wrong with this, you may ask… Well, the length of the progress bar will be divided into as many slots as there are candidates, and if the first candidate succeeds and uses its 1000 ticks, and the remaining candidates are never considered, we will end up reporting the 1000 ticks on a fraction of the overall progress bar. This means that for 10 candidates, you will see the progress-bar slowly go to about 10% of the overall length, to suddenly jump to 100%.
Here is the good pattern that makes use of the full progress bar:
Notice how “setWorkRemaining” is called each time in the loop. This reallocates the remaining ticks, but there is no need to compute how many that actually remains, the child allocation of 1000 ticks will always give the child 1000 ticks to report, even if there were not enough ticks left in the parent. All the scaling is performed by the SubMonitor, so you don’t have to worry about it.
Now, let’s say that the routine you are calling do need to perform a bit of work even if it does not need all of its ticks. Don’t worry, that will work too as long as it is a small portion of the allocation. If you risk consuming a larger part, you may be better off doing a true partitioning of the progress-bar as shown in the next section.
Good pattern - regular loop
Here is the good pattern for a regular loop where each iteration does consume ticks
Here I simply use SubMonitor’s newChild, this works without calling “done” because the next call to newChild (or “done” for that matter) will consume the ticks allocated for the child.
Rules of Thumb
- Use SubMonitor
- Always begin by converting the monitor you get to a SubMonitor
- Use newChild(n) to create a sub monitor to pass to methods that take an IProgressMonitor as argument.
- Never call “done” - but document that the caller must do so unless they used a SubMonitor