## Workbench concurrency support

We've seen that the JFace UI framework provides basic support for showing task progress in a dialog (see Long running operations for details). In Concurrency infrastructure, we reviewed the platform runtime support for concurrency and long running operations. Now we will look at how the platform UI enhances this infrastructure in the org.eclipse.ui.progress package. This package supplies the UI for showing job progress in the workbench and defines additional support for jobs that run in the UI thread.

Before we introduce the new APIs let's start by reviewing some concepts. We first have to distinguish between different kinds of background operations:

- User initiated. These jobs are set to be user jobs (Job#setUser). The workbench will automatically show user jobs in a modal progress dialog with a button to allow the user to run the operation in the background and continue working. A global preference is used to indicate if user jobs should always run in the background.

  Examples of user jobs include building, checking out a project, synchronizing with the repository, exporting a plug-in and searching.

- Automatically triggered. These operations have a meaning for users but were not initiated by the user. This is the default variety of job. These jobs are shown in the progress view and in the status line but the modal progress dialog won't show when they are run. Examples include autobuild and scheduled synchronization.

- System operations. Operations that are not triggered by the user and can be considered as an implementation detail. These jobs are created by setting the system flag (Job#setSystem). Examples of system jobs include jobs that lazily populate widgets or compute decorations and annotations for views.

Given an environment where several things may be happening at the same time the user needs:

- Indication when a long running operation has started.

  User jobs are shown to the user in a progress dialog giving immediate feedback, whereas automatically triggered jobs are shown in the status line and progress view. Also, jobs that affect a part should be scheduled or registered with the part so that the workbench can provide hints to the user that something is running that affects the part.

- Indication when an operation has ended.

  The user can easily know when user jobs ends because the progress dialog closes. But for non-user jobs there are a couple of feedback mechanisms available. If the job was scheduled or registered with a part then the parts progress hint will show when it is complete. If a job returns an error, an error indicator will appear in the bottom right of the status line showing a hint that an error has occured.

- Indication of interesting new results, or new information, without stealing focus with dialogs shown by a background operation.

  A user job can directly show the results to the user when the operation completes. For non-user jobs, it is recommended to not interrupt the user with a dialog. Instead, if the jobs results are shown in a view, the view can be opened when the job starts and the results shown in the view. This won't disrupt the users workflow. In addition, you can add properties to the job to indicate that it should be kept in the progress view and has an action that will show the results. A warning indication will appear in the bottom right corner of the status line when a job remains in the progress view and has results to show the user.

- A general feeling of being in control of what is running, with the ability to monitor and cancel background operations.

  User jobs provides the best control to the user since they are easily cancelled and provide strong indication of blocking or conccurent operations running via the Details tab of the progress dialog. Note that the enhanced progress dialog that provides the Details area is only shown when users call IProgressService#busyCursorWhile or IProgressService#runInUI. In addition, the progress view provides access to jobs that are running.

- All installed plug-ins must consistently show progress in the same way.

  The advantage of using the progress service API is that users get a consistent progress experience.

Next we will go into detail on how the new APIs can be used.

### Progress service

The workbench progress service (IProgressService) is the primary interface to the workbench progress support. It can be obtained from the workbench and then used to show progress for both background operations and operations that run in the UI thread. The main purpose of this class is to provide one-stop shopping for running operations, removing the need for plug-in developers to decide what mechanism should be used for showing progress in a given situation. Another advantage is that the progress dialog shown with these methods provides good support for indicating when an operation is blocked by another and gives the user control to resolve the conflict. Where possible, long running operations should be run using IProgressService#busyCursorWhile:

       IProgressService progressService = PlatformUI.getWorkbench().getProgressService();
       progressService.busyCursorWhile(new IRunnableWithProgress(){
          public void run(IProgressMonitor monitor) {
             //do non-UI work
          }
       });

This method will initially put up a busy cursor, and replace it with a progress dialog if the operation lasts longer than a specified time threshhold. The advantage of this method over using a progress dialog is that if the operation is short running the progress dialog won't be shown. If your operation must update the UI, you can always post an Display.asyncExec or Display.syncExec to run the code that modifies the UI. If an operation must be run in it's entirety in the UI thread, then you should call IProgressService#runInUI. Again, the advantage of this method is that it will display a progress dialog if the operation is blocked and give the user control.

       progressService.runInUI(
          PlatformUI.getWorkbench().getProgressService(),
          new IRunnableWithProgress() {
             public void run(IProgressMonitor monitor) {
                //do UI work
             }
          },
          Platform.getWorkspace().getRoot());

The third parameter can be null, or a scheduling rule for the operation. In this case we are specifying the workspace root which will essentially lock the workspace while this UI operation is run.
You can also register with the progress service an icon for a job familly so that the progress view can show the icon next to the running job. Here is an example of how the auto-build is associated with its icon:

       IProgressService service = PlatformUI.getWorkbench().getProgressService();
       ImageDescriptor newImage = IDEInternalWorkbenchImages.getImageDescriptor(
          IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC);
       service.registerIconForFamily(newImage, ResourcesPlugin.FAMILY_MANUAL_BUILD);
       service.registerIconForFamily(newImage, ResourcesPlugin.FAMILY_AUTO_BUILD);

### Showing that a part is busy

IWorkbenchSiteProgressService adds API for scheduling jobs that change the appearance of a workbench part while the job is running. If your plug-in is running background operations that affect the state of a part you can schedule the job via the part and the user will get feedback that the part is busy. Here is an example:

       IWorkbenchSiteProgressService siteService =
          (IWorkbenchSiteProgressService)view.getSite().getAdapter(IWorkbenchSiteProgressService.class);
       siteService.schedule(job, 0 /* now */, true /* use half-busy cursor in part */);

### Progress Properties for Jobs

There are a set of predefined properties defined in IProgressConstants that can be used to control how a job is shown in the progress view. These can be used to tell the progress view to keep (IProgressConstants#KEEP_PROPERTY) your job in the view after it has finished, or only keep one (IProgressConstants#KEEPONE_PROPERTY) job at a time in the view. You can also associate an action (IProgressConstants#ACTION_PROPERTY) with a job. When a job has an associated action, the progress view shows a hyperlink so that a user can run the action. You can also find out if a user job is currently being shown in a progress dialog (IProgressConstants#PROPERTY_IN_DIALOG). A hint is provided in the bottom right of the status line when an action is available. Here is an example that uses these properties:

       Job job = new Job("Do Work") {
          public IStatus run(IProgressMonitor monitor) {
             // do some work then only keep the finished job in the progress view if
             // not running in the progress dialog
             Boolean inDialog = (Boolean)getProperty(IProgressConstants.PROPERTY_IN_DIALOG);
             if(!inDialog.booleanValue())
                setProperty(IProgressConstants.KEEP_PROPERTY, Boolean.TRUE);
          }
       };
       job.setProperty(IProgressConstants.ICON_PROPERTY, Plugin.getImageDescriptor(WORK_IMAGE));
       IAction gotoAction = new Action("Results") {
          public void run() {
             // show the results
          }
       };
       job.setProperty(IProgressConstants.ACTION_PROPERTY, gotoAction);
       job.setUser(true);
       job.schedule();

### Workbench jobs

Where possible, long running operations should be performed outside of the UI thread. However, this cannot always be avoided when the operation's purpose is to update the UI. SWT threading issues explains how this can be done using the SWT Display. The workbench defines a special job, UIJob, whose run method runs inside an SWT `asyncExec`. Subclasses of UIJob should implement the method runInUIThread instead of the run method.

WorkbenchJob extends UIJob so that the job can only be scheduled or run when the workbench is running. As always, you should avoid excessive work in the UI thread because the UI will not refresh for the duration of the UI Job.