JFace UI フレームワークでは、ダイアログでのタスク進行状況の表示が基本的にサポートされることを確認しました
(詳しくは、『長期に渡る運用』を参照)。
『並行性インフラストラクチャー』では、並行性と長時間に渡る操作に対するプラットフォーム・ランタイム・サポートについて検討しました。
ここでは、org.eclipse.ui.progress
パッケージにおいて、このインフラストラクチャーがプラットフォーム UI によりどのように拡張されるのかを説明をします。
このパッケージには、ワークベンチでのジョブの進行状況を表示するための UI が提供され、UI スレッドで実行されるジョブの追加サポートが定義されています。
最初に、実行される可能性のある各種バックグラウンド操作と、これらの操作がワークベンチ UI に表示される方法を見てみましょう。
ユーザー開始 ジョブは、ユーザーがトリガーしたジョブです。 ワークベンチでは、ボタンの付いたモーダル進行状況ダイアログにユーザー・ジョブが自動的に表示され、 ユーザーは、バックグラウンドで操作を行い作業を続けることができます。 ユーザー・ジョブを常にバックグラウンドで実行するかどうかを指示するため、グローバル設定が使用されます。ユーザー・ジョブは、ジョブ API 内で (Job#setUser) を使用して区別されます。 ユーザー・ジョブの例として、ビルド、プロジェクトのチェックアウト、リポジトリーとの同期化、プラグインのエクスポート、および検索があります。
自動トリガー・ジョブは、ユーザーにとって意味を持ちますが、ユーザーにより開始されるジョブではありません。これらのジョブは、進行状況ビューと状況表示行に表示されますが、実行時にモーダル進行状況ダイアログは表示されません。 例として、自動ビルドやスケジュール同期があります。
システム操作 は、ユーザーによりトリガーされることはなく、プラットフォーム実装の詳細と見なすことができます。これらのジョブは、システム・フラグ (Job#setSystem) を設定することにより作成されます。 システム・ジョブの例に、おおまかなウィジェットの配置や、ビューの装飾や注釈の計算があります。
複数の事項が同時に発生する環境で、ユーザーは以下を行う必要があります。
長時間にわたる操作が開始したことを示す。
ユーザー・ジョブは進行状況ダイアログでユーザーに示され、即時にフィードバックされるのに対し、
自動トリガーされたジョブは、状況表示行および進行状況ビューに表示されます。
パーツに影響するジョブは、スケジュールまたはパーツに登録して、
パーツに影響するエレメントが実行されていることをワークベンチからユーザーに示す必要があります。
操作が終了したことを示す。
進行状況ダイアログが閉じるため、ユーザーは、ジョブが終了したことを容易に知ることができます。非ユーザー・ジョブの場合には、いくつかのフィードバック・メカニズムを使用できます。ジョブがスケジュールまたはパーツに登録されている場合は、パーツの進行状況を示すヒントにより、これがいつ完了するかが分かります。ジョブがエラーを戻す場合、状況表示行の右下にエラー標識が表示され、エラーが発生したことを示します。
ダイアログを使用してフォーカスを移動することなく、関心を引く新しい結果や新しい情報を示す。
ユーザー・ジョブは、操作が終了すると、ユーザーに結果を直接に表示することができます。
非ユーザー・ジョブの場合は、ユーザーに割り込まないようにするために、ダイアログ以外のものを使用して結果を表示することが推奨されます。例えば、ジョブの開始時にビューを開いて、ユーザーのワークフローを妨害することなく、このビューに結果を表示することができます。また、ジョブにジョブ・プロパティーを追加することにより、これを進行状況ビューに保持する必要があること、
および結果を表示するアクションを提供することを示すことができます。このケースでは、ジョブが進行状況ビューに表示されたままであって、ユーザーに示す結果がある場合に、状況表示行の右下隅に警告標識が出ます。
バックグラウンド操作をモニターおよび取り消すことができ、全般的に実行内容が制御下にあることを確認する。
ユーザー・ジョブは、容易に取り消すことができ、進行状況ダイアログの「詳細」タブからブロックや並行操作の実行を指示できることから、
ユーザーにとっては最も制御のしやすい対象です。「詳細」領域を示す拡張進行状況ダイアログは、プラグインが IProgressService#busyCursorWhile または IProgressService#runInUI を使用する場合にのみ表示されます。
また、進行状況ビューからは、実行中のジョブへのアクセスが可能です。
インストール済みのすべてのプラグイン別に進行状況を一貫して報告する。
進行状況サービス 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 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 メソッドを実装する必要があります。
WorkbenchJob は UIJob を拡張し、ワークベンチの実行中にのみジョブをスケジュールまたは実行できるようにします。 UI ジョブが行われている間には UI の更新が行われないため、UI スレッドでの過剰な処理は避ける必要があります。