ワークベンチ並行性のサポート

JFace UI フレームワークでは、ダイアログでのタスク進行状況の表示が基本的にサポートされることを確認しました (詳しくは、『長期に渡る運用』を参照)。 『並行性インフラストラクチャー』では、並行性と長時間に渡る操作に対するプラットフォーム・ランタイム・サポートについて検討しました。 ここでは、org.eclipse.ui.progress パッケージにおいて、このインフラストラクチャーがプラットフォーム UI によりどのように拡張されるのかを説明をします。 このパッケージには、ワークベンチでのジョブの進行状況を表示するための UI が提供され、UI スレッドで実行されるジョブの追加サポートが定義されています。

最初に、実行される可能性のある各種バックグラウンド操作と、これらの操作がワークベンチ UI に表示される方法を見てみましょう。


複数の事項が同時に発生する環境で、ユーザーは以下を行う必要があります。

進行状況サービス

ワークベンチの進行状況サービス (IProgressService) は、ワークベンチでの進行状況サポートのための 1 次インターフェースです。 これは、ワークベンチから取得して、バックグラウンド操作および UI スレッドで実行される操作の進行状況を表示するために使用できます。 このクラスの主な目的は、実行中の操作にワンストップ・ショッピングを提供し、 特定の状況の進行状況を示すために使用するメカニズムを、プラグイン開発者が決定しなくてもよいようにすることです。 また、これらのメソッドで表示される進行状況ダイアログにより、ある操作が他の操作によりブロックされている状況を示し、 ユーザーに競合を解決するための制御を与えられるようサポートできることも利点となります。 可能であれば、長時間に渡る操作では、IProgressService#busyCursorWhile を使用して実行してください。

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

このメソッドは、最初にビジー・カーソルを表示し、指定された時間しきい値を超えて操作が続く場合は、これを進行状況ダイアログに置き換えます。 進行状況ダイアログに対するこのメソッドの利点としては、操作が短時間の場合、進行状況ダイアログを表示せずに済む点を挙げることができます。操作で UI を更新する必要がある場合は、常に Display.asyncExec または Display.syncExec を使用して、UI を変更するコードを実行することができます。

操作全体を UI スレッドで実行しなければならない場合は、IProgressService#runInUI を使用する必要があります。このメソッドはまた、操作がブロックされた場合に進行状況ダイアログを表示して、ユーザーが制御できるようにします。

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

3 番目のパラメーターはヌルとするか、操作のスケジューリング規則とすることができます。 この例では、この UI 操作の実行中は基本的にワークスペースをロックするワークスペース・ルートを指定しています。

進行状況サービスには、ジョブ・ファミリーのアイコンを登録して、進行状況ビューで実行中のジョブの横にアイコンを表示することができます。以下に、自動ビルド・ジョブ・ファミリーとそのアイコンの関連付けの例を示します。

   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);

パーツがビジーであることを示す

IWorkbenchSiteProgressService は、ジョブの実行中にワークベンチ・パーツの外観を変更するスケジューリング・ジョブの API を組み込みます。プラグインが、パーツの状態に影響するバックグラウンド操作を実行している場合、パーツを介してジョブをスケジュールすることにより、パーツがビジーであることをユーザーにフィードバックできます。以下に例を示します。

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

ジョブの進行状況プロパティー

ワークベンチは、ジョブの進行状況に関連したプロパティーを IProgressConstants に定義します。これらを使用して、進行状況ビューでのジョブの表示方法を制御できます。これを使用することにより、進行状況ビューでジョブの終了後にジョブを保持したり (IProgressConstants#KEEP_PROPERTY)、 ビュー内で一度に 1 つのジョブのみを保持したりすることができます (IProgressConstants#KEEPONE_PROPERTY)。 アクション (IProgressConstants#ACTION_PROPERTY) をジョブに関連付けることもできます。 ジョブにアクションが関連付けられている場合、進行状況ビューには、ユーザーがアクションを実行できるようにハイパーリンクが表示されます。 ユーザー・ジョブが進行状況ダイアログに表示されているかを検出することもできます (IProgressConstants#PROPERTY_IN_DIALOG)。 アクションが使用可能な場合は、状況表示行の右下にヒントが表示されます。 以下の例では、これらのプロパティーが使用されています。

   Job job = new Job("Do Work") {
      public IStatus run(IProgressMonitor monitor) {
         // do some work.  
         // Keep the finished job in the progress view only if it is 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();

ワークベンチ・ジョブ

可能であれば、時間のかかる操作は、UI スレッドの外部で実行してください。 ただし、操作の目的が UI の更新である場合、常に UI スレッド外で実行できるとは限りません。 『SWT スレッド化の問題』では、SWT 表示を使用してこれを行う方法について説明しています。 ワークベンチは、SWT asyncExec 内部で実行される実行メソッドを持つ特殊ジョブ UIJob を定義しています。 UIJob のサブクラスは、run メソッドでなく、runInUIThread メソッドを実装する必要があります。

WorkbenchJobUIJob を拡張し、ワークベンチの実行中にのみジョブをスケジュールまたは実行できるようにします。 UI ジョブが行われている間には UI の更新が行われないため、UI スレッドでの過剰な処理は避ける必要があります。