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

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

新規 API を紹介する前に、いくつかの概念について確認します。 最初に、各種のバックグラウンド操作の違いを確認します。


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

次に、新しい API の使用方法について説明します。

進行状況サービス

ワークベンチの進行状況サービス (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 half-busy cursor in 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 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();

ワークベンチ・ジョブ

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

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

特記事項