viewerをビューに配置していくときに、最後に必ずと言っていいほど記述する、
getSite().registerContextMenu(menuMgr, viewer);
について、コンテキストメニューを外部に公開するときは必ず書くんですよね、と適当に理解していたのですが、ちゃんと調べてみました。ちなみにここにもまとめてありますが、このregisterContextMenuを記述すると指定したメニューをビューのIDで外部に公開しますよという意味になります。
スニペット*1として、こうやっときゃいいやってのはわかったんだけど、なんとなくスッキリしない。
ということで、viewerのところの引数をいろいろ変えてみて、どのような挙動をするのかテストしてみました。
上のように二つのviewerをビューに貼り付けて色々やってみる。
action1,action2はActionのanonymousクラス。。またviewer2は、setSelectionProviderの記述により「このビューのSelectionProviderはviewer2だよ」と宣言している。
ISelection selection = viewer.getSelection(); System.out.println(selection.getClass().getName()); System.out.println(selection);つまりviewerから値をとって表示するだけ。
ISelectionProvider selectionProvider = getSite()
.getSelectionProvider();
System.out.println(selectionProvider.getSelection().getClass()
.getName());
System.out.println(selectionProvider.getSelection());
つまりビューのSelectionProviderから値をとって表示するだけ。org.eclipse.jface.viewers.StructuredSelection [viewer1:a]
org.eclipse.jface.viewers.StructuredSelection [viewer2:a]
当たり前ですね。getSite().setSelectionProvider(viewer2)しているので「このビューのSelectionProviderから選択してるものちょうだい」といった場合、viewer2で選択されているものが取得できるわけですね。
次に、
getSite().registerContextMenu(getSite().getId(), menuMgr, viewer1);
してみる*2。特に挙動は変わらず。registする作業はプログラマティカルに追加したアクションには関係ないのかな*3???
次に、拡張ポイントでポップアップを追加する。
</viewerContribution>
<viewerContribution id="nu.mine.kino.plugin.samples.rcp.viewerContribution3"
targetID="nu.mine.kino.plugin.samples.views.ProviderSampleView">
<action ↑これはviewのIDではなく、 これ↓です。ねんのため
registerContextMenu(getSite().getId(), menuMgr, viewer1);
class="nu.mine.kino.plugin.samples.rcp.Action5" icon="icons/sample.gif"
id="nu.mine.kino.plugin.samples.rcp.action5" label="アクション5"
menubarPath="additions"/>
</viewerContribution>
IViewActionDelegateの実装クラスAction5を
public class Action5 implements IViewActionDelegate {
private ISelection selection;
private IViewPart view;
public void init(IViewPart view) {
this.view = view;
}
public void run(IAction action) {
System.out.println("selectionからとってみる");
System.out.println(selection.getClass().getName());
System.out.println(selection);
}
public void selectionChanged(IAction action, ISelection selection) {
this.selection = selection;
System.out.println("selectionからとってみる");
System.out.println(selection.getClass().getName());
System.out.println(selection);
}
}
とすると。。。
まず getSite().registerContextMenu(getSite().getId(), menuMgr, viewer1);を呼ばない場合、いくら拡張ポイントでtargetID指定で追加してもこのターゲットIDでコンテキストを登録していないので、ポップアップにアクションが追加されません。合掌。
次に
getSite().registerContextMenu(getSite().getId(), menuMgr, viewer1);
をしてからやってみると。。。
なんと
selectionからとってみる org.eclipse.jface.viewers.StructuredSelection [viewer1:b]
となった。おもしろいのはビュー側で
getSite().setSelectionProvider(viewer2);
として「このビューのSelectionProviderはviewer2だよ」と宣言しているにも関わらず、IViewActionDelegateの実装クラスselectionChangedには、viewer2ではなくviewer1が渡ってきているのだ。なるほど、
getSite().registerContextMenu(getSite().getId(), menuMgr, viewer1);
の意味はこのコンテキストメニュー(menuMgr)をgetSite().getId()というtargetIDで公開するよ、そのときのSelectionProvider(selectionChangedの引数selectionを作るヤツ)はviewer1ですよという意味なんですね。
ではつぎに
getSite().registerContextMenu(getSite().getId(), menuMgr, viewer2);
とした場合はどうなるか。この例はviewer2をregisterContextMenuしているので、拡張ポイントたちに対するSelectionProviderはviewer2となり、IViewActionDelegateの実装クラスはviewer2をリスンすることになります*4。でも、このメニューmenuMgrはviewerの方にセットされているので、アクション自体はviewer1に表示される。つまりviewer2をクリックするとselectionChangedが呼ばれるけど、viewer1のポップアップメニューに追加されるというわけわかんないことになります。こんなコトする必要はないですけど、仕組みはよく理解できました。
よってスニペットとしては
getSite().registerContextMenu(getSite().getId(), menuMgr, getSite().getSelectionProvder());
よりも
getSite().registerContextMenu(getSite().getId(), menuMgr, viewer1);
のようにmenuMgrを追加したviewerを第3引数に設定するのが間違いがないかなあ、という結論になりました。だってこのビューのSelectionProviderがmenuMgrを追加したビューワではない可能性があるからね。
ところで第三引数にnullをセットすると、拡張ポイントに対するSelectionProviderがnullなので、selectionChangedは呼ばれんだろうと思ったのですが、メニューからそのアクションを選択したとき、なぜかselectionChangedが呼ばれ、空の*5selectionがセットされていた。ナゾだ。。actionインスタンスの方はViewPluginActionというdelegateだ。。これ以上深追いはいいや。。。
現在のアクセス:15757