| <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> |
| <html> |
| <head> |
| <title>Showing Modal Progress in Eclipse 3.0</title> |
| <link rel="stylesheet" href="http://dev.eclipse.org/default_style.css" type="text/css"> |
| </head> |
| <body text="#000000" bgcolor="#FFFFFF"> |
| |
| <h1>Showing Modal Progress in Eclipse 3.0</h1> |
| <font size="-1">Last modified: June 23, 2004</font> |
| <p> |
| A goal of the responsive UI plan item was to give the user the feeling of being in control |
| over things happening in the background. There is one scenario where |
| we need your help to achieve this goal. When a modal user operation is blocked by a |
| background job, we want to show the running jobs and provide the option to cancel some of |
| them. The existing JFace <tt>ProgressMonitorDialog</tt> can only provide limited support to |
| do so. All it can do is inform the user that the current operation needs to wait. |
| See the following screenshot: |
| <pre> |
| <img src="progress-images/progressdialog.gif"/> |
| </pre> |
| <p> |
| What we really want to show is the progress view with the option to cancel a job: |
| <pre> |
| <img src="progress-images/progressservice.gif"/> |
| </pre> |
| <p> |
| You can get this additional support by migrating from <tt>ProgressMonitorDialog</tt> to |
| the new <tt>org.eclipse.ui.progress.IProgressService</tt>. |
| <p> |
| Here is how you can migrate: |
| <ol> |
| <li> |
| <b>Existing code:</b> |
| <pre> |
| ProgressMonitorDialog progress = new ProgressMonitorDialog(shell); |
| progress.run(true, true, operation); |
| </pre> |
| <b>Replacement:</b> |
| <pre> |
| PlatformUI.getWorkbench().getProgressService().busyCursorWhile(operation); |
| </pre> |
| <tt>busyCursorWhile</tt> shows the busy cursor and after some delay it shows |
| an enhanced progress dialog as shown above. |
| <p> |
| </li> |
| <li> |
| <b>Existing code:</b> |
| <pre> |
| ProgressMonitorDialog progress = new ProgressMonitorDialog(shell); |
| progress.run(<b>false</b>, false, operation); |
| </pre> |
| In this case the first parameter, <tt>fork</tt>, in <tt>dialog.run()</tt> is <b><tt>false</tt></b>, |
| which means the operation isn't run in a separate thread but in the UI thread with |
| the consequence of preventing any UI refreshes. |
| <p> |
| <b>Replacement:</b><br><br> |
| The simplest replacement for non-forking progress is to call: |
| <pre> |
| PlatformUI.getWorkbench().getProgressService().run(false, false, operation); |
| </pre> |
| This will ensure that a progress dialog is shown, but the UI will still not be able |
| to refresh for the duration of the operation. A better replacement is to use: |
| <pre> |
| IProgressService service = PlatformUI.getWorkbench().getProgressService(); |
| service.runInUI(service, operation, schedulingRule); |
| </pre> |
| The <tt>runInUI</tt> method operates in two phases. First, it acquires the supplied |
| scheduling rule in the UI thread. If the scheduling rule is not available due to concurrent |
| modifications in another thread, it will block until the rule is available. During this time, |
| it will show a progress dialog and will continue to refresh the UI. Once the rule is |
| acquired, the operation will run in the UI thread, during which time the UI will not |
| refresh. This ensures that the UI remains responsive in situations where your operation |
| is blocked for unknown periods of time, while still allowing your operation to run |
| in the UI thread. |
| <p> |
| To use the <tt>runInUI</tt> API, you need to know what scheduling rule is appropriate |
| for your operation. In the case of operations that modify resources, the most defensive |
| scheduling rule to use is the workspace root: <tt>ResourcesPlugin.getWorkspace().getRoot()</tt>. |
| If possible use the <tt>IResourceRuleFactory</tt> to get a more fine grained scheduling rule. |
| You can read more about scheduling rules in the Platform Plugin Developer Guide, |
| under <b>Programmer's Guide > Runtime overview > Concurrency infrastructure</b>. |
| <p> |
| <b>Important:</b> whenever possible try to run your operations with <tt>fork==true</tt>. |
| When converting to <tt>IProgressService</tt> please check whether you can |
| convert from <tt>fork==false</tt> to <tt>fork==true</tt>. Using <tt>fork==false</tt> |
| simply because the operation needs to access some state from UI widgets is not an |
| excuse to not set <tt>fork==true</tt>. You should change your code so that you |
| can fetch the state from the widgets outside of the operation in the UI thread, or |
| gather all the necessary information from the UI before starting the operation. |
| </li> |
| <li> |
| An API method expects a runnable context, e.g.: |
| <pre> |
| createTypeDialog(Shell parent, IRunnableContext context, ...) |
| </pre> |
| <b>Existing code:</b> |
| <pre> |
| ProgressMonitorDialog progress= new ProgressMonitorDialog(shell); |
| createTypeDialog(shell, progress, ...); |
| </pre> |
| <b>Replacement:</b> |
| <pre> |
| createTypeDialog(shell, PlatformUI.getWorkbench().getProgressService()); |
| </pre> |
| <p> |
| In other words the <tt>IProgressService</tt> is an <tt>IRunnableContext</tt>. |
| </li> |
| </ol> |
| Note that <tt>IProgressService.busyCursorWhile</tt> also serves as a good replacement |
| for <tt>BusyIndicator.showWhile</tt>, and <tt>IStatusLineManager.getProgressMonitor()</tt>. |
| The progress service will progressively switch from a busy cursor to a progress dialog |
| if the operation exceeds a given duration, and will do a better job of reporting blockage |
| than any existing progress mechanism. This takes the guess-work out of deciding what |
| progress mechanism to use for potentially long running operations. |
| <p> |
| “The Eclipse 3.0 progress service, one-stop shopping for all your modal progress needs!” |
| <hr> |
| </p> |
| </body> |
| </html> |