viewerをビューに配置していくときに、最後に必ずと言っていいほど記述する、
getSite().registerContextMenu(menuMgr, viewer);
について、コンテキストメニューをレジストすんのね、と適当に理解していたのですが、ちゃんと調べてみました。
スニペット*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だ。。これ以上深追いはいいや。。。
この記事は
現在のアクセス:15055