Commands Part 2: 選択によるHandlerの有効化

Eclipse Tipsの翻訳Commandについてのシリーズ第2段です。Part2ではIHandlerの活性、非活性に関して解説がかかれています。IHandlerにメニューを押したときなどの実際の振る舞いを実装します。同じコマンドでも選んでいるオブジェクトによって振る舞いを変える、と言うのはこの解説を斜め読むとなんとなく分かるでしょう。ちなみに訳者も勉強中><。翻訳しているのは、その辺の知見を得たいから、と言う事もあるのです。

原文

著者:Prakash G.R.
2009/01/05に記す

前回、私たちは一つのCommandからいくつかに分けられた定義によって、handlerが定義される事を見てきました。こうする事で複数のHandlerを同じコマンドから有効にできます。私たちはplugin.xmlに書くことでhandlerの活性化や可視化をカスタマイズすることができました。handlerに"デフォルトhandler"と呼べるような状態はありません。特定のコンテキストの中でcommandとその他のhandlerに関係がないときは、デフォルトのhandlerとしてそのhandlerが選ばれ、実行されます。覚えていて欲しいのですが、commandにはほとんどの場合一つのhandlerが割り当てられます。
それでは与えられたコンテキストによってどうやったら特定のhandlerが割り当てられるか見ていきましょう。
handlerははactiveWhen状態を特定の式言語によって定義するが出来ます。例えば2つの異なるhandlerを例にとって説明しましょう。一つはIFileが現在選択されている時に活性化するようにしたもの、もう一方はIFolderを現在選択した時に活性化するようにしたものです。これらの式は下記のようになります。

<handler
      class="com.eclipse_tips.commads.SomeCommandHandler1"
      commandId="com.eclipse-tips.commands.someCommand"><!-- (1) -->
   <activeWhen>
      <with
            variable="selection">
         <iterate
               operator="or">
            <instanceof
                  value="org.eclipse.core.resources.IFile">
            </instanceof>
         </iterate>
      </with>
   </activeWhen>
</handler>
<handler
      class="com.eclipse_tips.commads.SomeCommandHandler2"
      commandId="com.eclipse-tips.commands.someCommand"><!-- (2) -->
   <activeWhen>
      <with
            variable="selection">
         <iterate
               operator="or">
            <instanceof
                  value="org.eclipse.core.resources.IFolder">
            </instanceof>
         </iterate>
      </with>
   </activeWhen>
</handler> 

式言語についての説明は別のチップにお任せしますが、簡単に説明します。(1),(2)どちらも同じcommandIdで宣言しているので同じcommandのためのhandlerとして宣言されています。最初のhandlerは少なくとも一つのIFileオブジェクト*1が選択されているときに活性化され、二つ目のhandlerは少なくとも一つ一つのIFolderオブジェクト*2が選択されている時に活性化されます。さてここで二つの疑問がうかびました。

(1)IProject*3だけを選択している場合はどうなるの?

この場合は、どのhandlerも該当しません。よってcommandは無効化されます。これはデフォルトのhandlerを提供していないためです。もしcommandにデフォルトのhandlerが提供されていれば、このcommandは有効になるでしょう。

(2)IFileとIFolderを両方共選択に含んでいる場合はどうなるの?

この場合はどちらのhandleも有効化されます。しかしフレームワークはどちらかを単純に無効化することができません。もしデフォルトのhandlerを提供されている場合、デフォルトのhandlerはcommandと関連付けられる事はありません。なぜならどちらのhandlerもデフォルトのものよりもより特定しているためです。

それではどうやって"あいまい"なhandlerを定義するのでしょうか。それはactiveWhen句の中の状態によります。この例ではISourcesクラスを定義します。あなたはこの例を一通り見ることで定義の優先順位を理解できるはずです。

  • アクティブなコンテキスト(activeContexts)
  • アクティブなアクションセット(メニューやツールバー)(activeActionSets)
  • アクティブなShell(activeShell)
  • アクティブなWorkbench Window(activeWorkbenchWindow)
  • アクティブなエディタのid(activeEditorId)
  • アクティブなパートのId(activePartId)
  • 現在選択しているオブジェクト(selection)

もしhandlerに、activeWhenがアクティブなコンテキスト(activeContext)の場合と定義されていて、一方では現在選択しているオブジェクト(selection)の場合と定義されている場合、二つめの例の方がより明確に定義されています。activeWhenは全てのhandlerから評価されます。そしてより特化した状態が選ばれ、trueと返します。
commandに一つもデフォルトのhandlerが関連しておらず、二つのhandlerがtrueを返したとき、より状態が特化している方が有効になります。(例えば私たちの例ではIFileとIFolderの両方を選択している時のように)これはすべてメモリにhandlerを読み込まずに行われます。そうあなたのPluginが読み込まれなくてもです!

ここまでのtipで、私たちは一つ以上のhandlerが宣言されているとき、activeWhen式でどのようにhandlerが選択されるのかを学びました。ここまでhandlerが選ばれていると仮定しましたが、commandが有効になるか、どうかはenabledWhen式によって定義されます。私たちの以前の例では、handlerは選択しているものの中に少なくとも一つのIFileが含まれ、活性化されているものを示しました。

それでは二つのオブジェクトが選ばれているときだけ有効になる例を見てみましょう。

<handler
      class="com.eclipse_tips.commads.SomeCommandHandler1"
      commandId="com.eclipse-tips.commands.someCommand">
   <activeWhen>
      <with
            variable="selection">
         <iterate
               operator="or">
            <instanceof
                  value="org.eclipse.core.resources.IFile">
            </instanceof>
         </iterate>
      </with>
   </activeWhen>
   <enabledWhen>
      <with
            variable="selection">
         <count
               value="2">
         </count>
      </with>
   </enabledWhen>
</handler>

少なくともIFileオブジェクトが一つでも選ばれているいれば、handlerはコマンドに関連付けられ、活性化しています。しかしコマンドは2つのオブジェクトが選ばれているときだけ有効になります。

activeWhenとenabledWhenは似ています。

  • 式言語と共に定義され、commandが実行されるまでpluginは遅延ロードされます。

しかし小さな違いがあります。

  • handlerはenabledWhen式がtrueを返すとロードされ、pluginもロードされます。

有効化は下記のように動作します。

  • enabledWhenが特定されていない状態で、pluginはロードされていない。 - コマンドは有効になっています。
  • enabledWhenが定義されていない状態でpluginがロードされている場合 - handler.isEnabled()を参照し、commandはそれに応じて設定されます。
  • enabledWhenが定義され、falseが返される場合、commandは無効になっています。(pluginがロードされていてもいなくても変わりません。)
  • enabledWhenが定義され、trueが返され、pluginはロードされていない場合、コマンドは有効になっています。
  • enabledWhenが定義され、trueが返され、pluginがロードされている場合、handler.isEnabled()を参照し、commandはそれに応じて設定されます。

ここまでcommand、handlerと有効化をみてきました。それではより一般的なcommandはどう表現されるでしょうか?次回のtipではcommandにparameterを追加してできることを見ていきましょう。

  • Part 1: Actions対Commands
  • Part 3: コマンドのパラメータ
  • Part 4: 様々なアイテム
  • Part 5: ISourceProviderとコマンドを動的に更新する
  • Part 6: 'toggle'と'radio'スタイルのメニューへの追加

*1:例えばパッケージエクスプローラー上のファイル

*2:同じくパッケージエクスプローラー上のフォルダ

*3:同上でプロジェクト