レベル: 中級 Karsten Voigt (kvoigt@de.ibm.com), IT Architect, IBM
2008年 2月 19日 Eclipse の以前のバージョンでは、コマンドをメニューやポップアップ・メニュー、あるいはツールバーに追加するのは厄介な作業でしたが、それはもう過去の話になりました。Eclipse V3.3 には今までになく簡単なメカニズムが導入されているからです。この記事で、org.eclipse.ui.menus の使い方を学んでください。
メニュー、ポップアップ・メニュー、そしてツールバーは、ほとんどすべての Eclipse プラグインあるいは Eclipse RCP (Rich Client Platform) アプリケーションに必要なものです。Eclipse V3.3 にはこれらのメニュー項目をより一般的な方法で構成し、追加するための機能が導入されています。この記事では、この新しいメニューの仕組みを使用してプラグインと RCP の開発を迅速化する方法を説明します。
Eclipse V3.2 以前のバージョンでコマンドをメニュー、ポップアップ・メニュー、またはツールバーに追加するには、複数の拡張ポイントを使用しなければなりませんでした。拡張ポイントとしてあったのは実際には org.eclipse.ui.actionSets、org.eclipse.ui.viewActions、org.eclipse.ui.editorActions、org.eclipse.ui.popupMenus の 4 種類です。しかし残念ながら、あらゆる類のコントリビューションにはそれぞれ固有の拡張ポイントが必要となり、アクションの配置と表示制御とを切り離すこともできませんでした。
Eclipse V3.3 には新しい仕組みである、org.eclipse.ui.menus が導入されています。この拡張ポイントは、メニュー項目を配置する新たな手段です。
この記事では新しいメニューの概念を説明し、簡単な Eclipse RCP アプリケーションの作成手順を案内しながら新機能の大部分を取り上げていきます。対象読者は、Eclipse RCP またはプラグイン・フレームワークの基本的な使い方を理解している方となります。まずは最初のステップとして、Eclipse.org から PDE (Plug-in Development Environment) を備えた Eclipse ディストリビューションをダウンロードしてください。最新バージョンの Eclipse Classic をダウンロードすることをお薦めします (Eclipse を使うのが初めての方には、「参考文献」でEclipse についての情報、そして予備知識を調べるための資料を紹介しています)。
プラットフォーム・コマンド・フレームワーク
新しいメニューの仕組みを使ったプラグインの実装を始める前に、コマンド・フレームワークについて理解しておく必要があります。コマンドとはコンポーネントの宣言的記述のことで、実装の詳細とは別のものです。コマンドはカテゴリー別に分類してキー・バインディングを割り当てることができます。こうすると、汎用のキー・バインディングを定義することができ、コンテキストによっては特定の実装を選択することもできます。図 1 は、コマンドのクラス図を簡略化したものです。
図 1. コマンドのクラス図
コマンドの定義には拡張ポイント、org.eclipse.ui.commands を使用してください。コマンドはプログラムによって作成することも可能で、その場合には ICommandService インターフェースを使用することができます。コマンドを処理することができるハンドラーはいくつかありますが、コマンドの具体的なランタイム・インスタンスを処理するのは 1 つのハンドラーだけです。Eclipse ワークスペース内で統合を行う場合には、コマンドに対して画像、メニュー項目、そしてバインディングを割り当てる必要があります。この際に賢い方法となるのは、カテゴリー別にコマンドをグループ分けすることです。カテゴリー別にすることで、複雑なリッチ・クライアント・アプリケーションでのナビゲーションが簡単になります。
メニュー・コントリビューションの追加
早速、メニュー・コントリビューションを使ってみましょう。この例では、メニュー・エントリーが 1 つしかない簡単な RCP アプリケーションを実装するところから始めます。このメニュー・エントリーが行うことは、メッセージ・ダイアログを開くことのみです。この簡単なサンプル・アプリケーションを使って、コマンド、ハンドラー、そしてメニューを使用する上で中心となる概念を説明します。
MenuContribution という名前の新規プラグイン・プロジェクトを作成し、Eclipse バージョンを 3.3 に設定してください。「Would you like to create a rich client application? (リッチ・クライアント・アプリケーションを作成)」という項目では「Yes (はい)」を選択し、Hello RCP テンプレートを使用します。この例がベースとするのは、パッケージ名 com.ibm.de.eclipse.menu です。その他すべての設定はデフォルトのままで構いません。これで新規プロジェクトを Eclipse Application として実行すると、以下のウィンドウが表示されます。
図 2. Hello RCP の例
このアプリケーションを通じて、さまざまなメニュー・コントリビューションを説明していきます。plugin.xml を開き、Extensions に切り替えて org.eclipse.ui.commands 拡張を追加してください。すべてのコマンドを 1 つのカテゴリーに分類するため、コマンド拡張を選択し、右クリックで New > category の順に選択してカテゴリーを新規に作成します。この新規カテゴリーのフィールドには、図 3 のように入力します。
図 3. コマンド・カテゴリーの詳細
コマンド拡張を右クリックして New > command の順に選択し、新しいコマンドを追加します。ID を com.ibm.de.eclipse.menu.command.testCmd に設定し、Test Command という名前を付け、categoryId を com.ibm.de.eclipse.menu.command.cat1 に設定します。このコマンドには、関連するビジネス・ロジックを実行するハンドラーが必要です。そのため、拡張ポイント org.eclipse.ui.handlers を追加し、新しいハンドラーを作成します。このハンドラーの commandId は com.ibm.de.eclipse.menu.command.testCmd です。ハンドラー・クラスを作成するには、クラスのリンクをクリックします (図 4 を参照)。図 5 に、必須パラメーターが入力された状態のウィザードを示します。
ヒント: クラスへのリンクを複数の拡張で使用する場合は、選択した拡張ポイント用の必要なインターフェースを含む新規クラスを作成してください。
図 4. 新規ハンドラー・クラスへのリンク
図 5. ウィザード
このハンドラーは execute メソッドを実装する必要があります。リスト 1 に示す行を追加してメッセージ・ダイアログを表示できるようにしてください。
リスト 1. ハンドラーの execute メソッド
public Object execute(ExecutionEvent event) throws ExecutionException {
IWorkbenchWindow window =
HandlerUtil.getActiveWorkbenchWindowChecked(event);
MessageDialog.openInformation(
window.getShell(), "MenuEclipseArticle Plug-in",
"Hello, Eclipse world");
return null;
}
|
クラスを保管し、plugin.xml に戻ってこのファイルを保管します。次に作成するのは、新しいコマンドとハンドラーのメニュー・コントリビューションです。org.eclipse.ui.menus 拡張を追加して新規 menuContribution を作成します。このメニュー・コントリビューションには locationURI という名前のプロパティーが 1 つあるだけです。このプロパティーが、包含する項目を追加する挿入ポイントを定義します。locationURI には menu:org.eclipse.ui.main.menu を指定してください。この URI が定義するメニューは、標準 Eclipse メニューに配置されます。
ここまでのところで定義したのは、挿入ポイントだけです。具体的なメニューを追加するには、メニュー・コントリビューションを選択し、新規メニューを作成します。このメニューのラベルは TestMenu という名前にし、ID には com.ibm.de.eclipse.menu.test を使用します。
最後のステップは、メニュー項目と事前に定義されたコマンドとの間にリンクを定義することです。TestMenu をクリックして新しいコマンドを追加します。commandId は com.ibm.de.eclipse.menu.command.testCmd に、ラベルは Do something にします。この時点で、plugin.xml の拡張は図 6 のようになっているはずです。Eclipse アプリケーションを実行する前に、ApplicationWorkbenchWindowAdvisor クラスを開いて preWindowOpen メソッドに configurer.setShowMenuBar(true); という行を追加してください。その上で Eclipse アプリケーションを実行し、新しいメニュー項目をテストします。
図 6. 全拡張の概要
メニューのロケーション URI
前のセクションの例でメニューに定義した locationURI はメニュー項目をアプリケーションのメニュー・バーに直接追加しますが、locationURI は他のメニュー・コントリビューションもサポートします。メニュー挿入ポイントを特徴付けるのは、<scheme>:<menu-id>[?<placement-modifier>] というパターンです。
-
<scheme> メニュー
- コントリビューションをメイン・メニュー、またはビューのメニューに追加します。
<menu-id> には既存のビュー ID、あるいは標準 Eclipse メニュー org.eclipse.ui.main.menu を指定する必要があります。<placement-modifier> により、<placement>=<id> のパターンを使ったメニュー・コントリビューションの配置が可能になります。配置を指定する際に、前後にタグを使用したり、<id> を既存のセパレーター名、メニュー ID、または項目 ID にしたりすることができます。
ヒント: MenuUtil クラスには、メニュー URI に共通の定数値がいくつか含まれています。
-
<scheme> ツールバー
- コントリビューションを任意のツールバーに追加します。この
<scheme> の <menu-id> には、任意のビュー ID (ビューのツールバーの場合)、org.eclipse.ui.main.toolbar、あるいはメイン・ツールバーに含まれる任意のツールバー ID を指定することができます。また、<placement-modifier> を使用することもできます。
-
<scheme> ポップアップ
- 登録されたすべてのコンテキスト・メニューの登録済みコンテキスト ID および
org.eclipse.ui.popup.any のメニューを追加します。<placement-modifier> も使用することができます。
ここからは前述の簡単なサンプル・アプリケーションを拡張して、メニュー・コントリビューションのさまざまなタイプを使用してみましょう。
ビューとビュー・コントリビューションの追加
続いて、簡単なアプリケーションを拡張して、ツールバーにアクションのアイコンが含まれるビューを含めることにします。このビューを開くように、既存のメイン・メニューのアクションを変更します。
まずはビュー拡張ポイント (org.eclipse.ui.views) を追加し、図 7 のプロパティーを使って新規ビューを作成します。次に TestHandler を開いて、この新しいビューを開くように実行メソッドを変更します。
リスト 2. ビューを開くための execute メソッドの変更
public Object execute(ExecutionEvent event) throws ExecutionException {
try {
HandlerUtil.getActiveWorkbenchWindow(event)
.getActivePage()
.showView("com.ibm.de.eclipse.menu.view.testview");
} catch (PartInitException e) {
throw new ExecutionException("Error while opening view", e);
}
return null;
}
|
図 7. ビュー要素の詳細の作成
このビューには、提案されたコントリビューションを追加するための新しいコマンドとハンドラーが必要です。そこで、新規コマンドと新規ハンドラーを作成します。使用するプロパティーは以下の表に記載するとおりです。ハンドラーは、org.eclipse.core.commands.AbstractHandler を継承する必要があります。ハンドラーの実行メソッドの内容を実装する際には、リスト 1 を使用してください。
表 1. 新規コマンドおよびハンドラーの追加
| コマンド/ハンドラー | 説明 | プロパティー |
|---|
| コマンド | id | com.ibm.de.eclipse.menu.command.viewCmd |
|---|
| name | View command | | description | A view command example | | categoryId | com.ibm.de.eclipse.menu.command.cat1 | | Handler | commandId | com.ibm.de.eclipse.menu.command.viewCmd |
|---|
| class | com.ibm.de.eclipse.menu.handler.ViewHandler |
今度は 2 つのメニュー・コントリビューションを追加します。最初に追加するのは、URI を menu:com.ibm.de.eclipse.menu.view.testview に設定した menuContribution (ビューのメニュー・バー用) で、このビューの ID は <menu-id> です。commandId を com.ibm.de.eclipse.menu.command.viewCmd に、ラベルを Do something に設定したコマンドをメニューに直接追加します。ここではサブメニュー構造は必要ないので、このメニュー・コントリビューションにメニューは必要ありません。次に、URI を toolbar:com.ibm.de.eclipse.menu.view.testview に設定したツールバー用の menuContribution を追加します。ツールバーでも同じコマンドが参照されますが、アイコンを選択する必要はありません。デフォルト・プラグイン・アイコンのいずれか (icons/alt_window_16.gif など) を使用してください。アプリケーションを実行し、メイン・メニューのコマンドを実行して表示されたビューを見ると、そこにはツールバーとコマンドを選択できるメニューが組み込まれているはずです。
図 8. ツールバーおよびメニュー・コントリビューションを表示するサンプル・ビュー
条件付きポップアップ・コントリビューションの追加
最後にサンプル・アプリケーションに追加するのは、条件付きポップアップ・コントリビューションです。この場合、まずビューを拡張して要素のリストを含めます。これらの要素に対してコンテキスト・メニューが表示されることになります。TestView クラスを開いて、createPartControl メソッドを以下のように変更してください。
リスト 3. TestView へのリストおよびコンテキスト・メニューの追加
public void createPartControl(Composite parent) {
ListViewer lViewer = new ListViewer(new List(parent, SWT.MULTI));
lViewer.setContentProvider(new ArrayContentProvider());
lViewer.setInput(new String[] { "1", "2", "3", "4" });
MenuManager menuMgr = new MenuManager();
menuMgr.add(
new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
getSite().registerContextMenu(menuMgr, lViewer);
Control control = lViewer.getControl();
Menu menu = menuMgr.createContextMenu(control);
control.setMenu(menu);
}
|
標準 ArrayContentProvider は ListViewer を作成し、ストリングの配列だけを表示します。このリストの場合、MenuManager が作成され、新規 GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS) により plugin.xml に定義されたすべてのコンテンツが追加されます。コンテキスト・メニューはサイトに登録され、ListViewer のコントロールにアタッチされます。
plugin.xml にはポップアップと条件付きステートメントを追加します。条件としては、リストに含まれる 2 つの要素を選択した場合にだけコンテキスト・メニューが表示されるというものです。この条件はプラグインの複数の箇所で役立つことが考えられるため、org.eclipse.core.expressions.definitions 拡張を使って共通ルールを定義します。この拡張は org.eclipse.core.expression プラグインの一部なので、このプラグインの要件に従って追加しなければなりません。plugin.xml の依存関係セクションにプラグインを追加し、それから拡張セクションに戻って org.eclipse.core.expressions.definitions を追加します。新しく作成した定義の id は twoSelectedCheck に設定します。この拡張を追加する際に定義が 1 つも作成されていない場合は、ここで定義を作成してください。作成する定義には with 要素を追加し、変数を activeMenuSelectionに設定します。with 要素が指定するのは、チェックに使用する変数名です。この変数を解決できない場合、ルールの評価中に ExpressionException がスローされることになります。
Eclipse にはいくつかの標準変数が定義されています。使用可能な変数の完全なリストは、ウィキペディアの Command Core Expressions (「参考文献」を参照) で調べてください。この例では activeMenuSelection を使用します。この変数は、コンテキスト・メニューが表示されているときに有効になる選択項目です。要素にカウントを追加し、値を 2 に設定してください。つまりこのルールは、選択されている要素の数をカウントし、選択されている要素が 2 つであれば true を返すように定義されるということです。plugin.xml でこの定義に対応する部分は、リスト 4 のようになります。
リスト 4. plugin.xml での定義の拡張
<extension point="org.eclipse.core.expressions.definitions">
<definition id="twoSelectedCheck">
<with variable="activeMenuSelection">
<count value="2"></count>
</with>
</definition>
</extension>
|
定義が作成できたら、新しいメニュー・コントリビューションを追加します。org.eclipse.ui.menus 拡張ポイントに進み、locationURI ポップアップを設定したメニュー、org.eclipse.ui.popup.any を追加してください。さらに、このメニューには commandId を com.ibm.de.eclipse.menu.command.viewCmd に設定したコマンドを追加します。今まではコンテキスト・メニューが常に表示されることになっていましたが、この動作をオン/オフするために visibleWhen 要素をこのコマンドに追加します。続いて definitionId を twoSelectedCheck に設定した参照要素を visibleWhen 要素に追加します。これでアプリケーションをテストしてみてください。現在、TestView には要素のリストが含まれているため、2 つの要素を選択するとコンテキスト・メニューが表示されます。
設計時または実行時にメニュー・コントリビューションの表示/非表示を制限するとっておきの方法は、プラグインの構成ファイルで visibleWhen 要素を使用することです。その威力を示すのに、別のルール定義を使ってこの要素の使用方法を拡張したサンプル・アプリケーションを使用します。そこで、TestView にテキスト・フィールドを追加し、このテキスト・フィールドにフォーカスがある場合にのみツールバーのコマンドを選択できるようにします。まずはリスト 5 のコードで TestView を拡張してください。このコードでは、IFocusService を使ってテキスト・フィールドを登録することによって、アプリケーションがテキスト・フィールドのフォーカスの変更を処理できるようにしています。
リスト 5. テキスト・フィールドを IFocusService に登録した TestView
public void createPartControl(Composite parent) {
parent.setLayout(new FillLayout(SWT.VERTICAL));
Text text = new Text(parent, SWT.BORDER);
IFocusService focusService =
(IFocusService) PlatformUI.getWorkbench()
.getService(IFocusService.class);
focusService.addFocusTracker(text, "textControlId");
ListViewer lViewer = new ListViewer(new List(parent, SWT.MULTI));
...
}
|
次のステップは、新しい定義の作成です。org.eclipse.core.expressions.definitions に、focusDefinition という名前の定義を追加します。with 要素には activeFocusControlId 変数を使用してください。フォーカスが置かれたコントロールの ID を含むこの変数は、IFocusService を使って登録されています。equals 要素は、値を textControlId にして追加します。このルールは、フォーカスされているアクティブ・コンポーネントの ID が textControlId の場合、true を返すというものです。リスト 6 に、plugin.xml 内でのこの定義を示します。この定義をツールバー・メニューに追加するには、参照要素を持つ visibleWhen を使用します (リスト 7 を参照)。最後にサンプル・アプリケーションを実行してテストしてください。
リスト 6. フォーカス・コントロール・ルールの定義
<definition id="focusDefinition">
<with variable="activeFocusControlId">
<equals value="textControlId"></equals>
</with>
</definition>
|
リスト 7. visibleWhen を設定したツールバーのメニュー・コントリビューション
<menuContribution
locationURI="toolbar:com.ibm.de.eclipse.menu.view.testview">
<command
commandId="com.ibm.de.eclipse.menu.command.viewCmd"
icon="icons/alt_window_16.gif" label="Do something"
tooltip="Do something">
<visibleWhen>
<reference definitionId="focusDefinition"></reference>
</visibleWhen>
</command>
</menuContribution>
|
まとめ
メニューの変更と追加を一貫した賢い方法で定義するには、この新しい org.eclipse.ui.menus が便利な手段となります。locationURI の使い方さえ覚えてしまえば、使用するのは簡単です。通常のメニュー定義に加え、さらにルールを定義してメニュー・エントリーを条件付きで表示させることもできます。既存のアプリケーションとプラグインについてはどう対処すればいいのか疑問に思われるかもしれませんが、新しいメカニズムを使用できるように、アプリケーションのマイグレーションをすればいいだけの話です。何故マイグレーションをするのかと言えば、頼りにしている Eclipse の機能のいくつかは、今後のリリースで使用できないかもしれないからです。今後予定されているメニュー・コントリビューションの変更に関する詳細は、「参考文献」を参照してください。
ダウンロード | 内容 | ファイル名 | サイズ | ダウンロード形式 |
|---|
| Sample Perl scripts | os-eclipse-3.3menuContribution.zip | 65KB | HTTP |
|---|
参考文献 学ぶために
製品や技術を入手するために
議論するために
著者について  | |  | Karsten Voigt は、ドイツ IBM Global Business Services の IT アーキテクト兼コンサルタントとして、主に自動車産業の IBM カスタマーに協力しています。彼が専門分野としているのは、Lotus Expeditor を始めとする J2EE および Java リッチ・クライアント・アプリケーションの統合ソリューションの定義です。余暇は、Java Swing と Eclipse Rich Client Platform でアプリケーションを設計、開発し、そのアプリケーションを使用することに費やしています。 |
記事の評価
|