Top / Eclipse / プラグイン開発のTIPS集 / getSite().registerContextMenuを理解する

viewerをビューに配置していくときに、最後に必ずと言っていいほど記述する、

getSite().registerContextMenu(menuMgr, viewer);

について、コンテキストメニューを外部に公開するときは必ず書くんですよね、と適当に理解していたのですが、ちゃんと調べてみました。ちなみにここにもまとめてありますが、このregisterContextMenu?を記述すると指定したメニューをビューのIDで外部に公開しますよという意味になります。

スニペット*1として、こうやっときゃいいやってのはわかったんだけど、なんとなくスッキリしない。

ということで、viewerのところの引数をいろいろ変えてみて、どのような挙動をするのかテストしてみました。

設定

pic.png

上のように二つのviewerをビューに貼り付けて色々やってみる。

  • viewer1: action1,action2を追加したビュー
  • viewer2: getSite().setSelectionProvider?(viewer2)したTableViewer?

action1,action2はActionのanonymousクラス。。またviewer2は、setSelectionProvider?の記述により「このビューのSelectionProvider?はviewer2だよ」と宣言している。

SelectionProvider?から値をとってみる

  • action1#runの処理:
    ISelection selection = viewer.getSelection();
    System.out.println(selection.getClass().getName());
    System.out.println(selection);
    つまりviewerから値をとって表示するだけ。
  • action2#runの処理:
    ISelectionProvider selectionProvider = getSite()
            .getSelectionProvider();
    System.out.println(selectionProvider.getSelection().getClass()
            .getName());
    System.out.println(selectionProvider.getSelection());
    つまりビューのSelectionProvider?から値をとって表示するだけ。

結果

  • action1#runの実行結果:
    org.eclipse.jface.viewers.StructuredSelection
    [viewer1:a]
  • action2#runの実行結果:
    org.eclipse.jface.viewers.StructuredSelection
    [viewer2:a]

当たり前ですね。getSite().setSelectionProvider?(viewer2)しているので「このビューのSelectionProvider?から選択してるものちょうだい」といった場合、viewer2で選択されているものが取得できるわけですね。

つぎにregisterContextMenu?してからやってみる

次に、

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);
  }
}

とすると。。。

結果1

まず getSite().registerContextMenu?(getSite().getId(), menuMgr, viewer1);を呼ばない場合、いくら拡張ポイントでtargetID指定で追加してもこのターゲットIDでコンテキストを登録していないので、ポップアップにアクションが追加されません。合掌。

次に

getSite().registerContextMenu(getSite().getId(), menuMgr, viewer1);

をしてからやってみると。。。

結果2

なんと

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だ。。これ以上深追いはいいや。。。


Top / Eclipse / プラグイン開発のTIPS集 / getSite().registerContextMenuを理解する

現在のアクセス:13417


*1 イディオム。
*2 律儀にgetSite().getId()書いてますが、getSite().registerContextMenu?(menuMgr, viewer);と同じです
*3 ここはようわかってない
*4 つまりviewer2をクリックするとselectionChangedが反応する
*5 nullの、ではない

添付ファイル: filepic.png 1005件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2014-11-03 (月) 13:22:01 (1838d)