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