1. 程式人生 > >Eclipse 外掛開發 -- 深入理解選單(Menu)功能及其擴充套件點

Eclipse 外掛開發 -- 深入理解選單(Menu)功能及其擴充套件點

選單是各種軟體及開發平臺會提供的必備功能,Eclipse 也不例外,提供了豐富的選單,包括主選單(Main Menu),檢視 / 編輯器選單(ViewPart/Editor Menu)和上下文選單(Context Menu)。在 Eclipse 中,幾乎所有的 Workbench Part 提供了人性化的選單,大大方便了使用者的操作。因此,如何擴充套件 Eclipse 的選單功能,並實現特定於我們自己外掛的選單,是外掛開發者必須掌握的重要技能,同時,Eclipse 提供了豐富的擴充套件點供開發人員使用。本文將首先介紹 Eclipse 中的選單,然後詳細說明如何進行擴充套件,最後以一個例項的形式引導讀者深入理解 Eclipse 的選單功能。

引言

Eclipse 具有豐富的選單功能,給開發人員提供了很好的使用者體驗。總體而言,Eclipse 選單種類包括檢視 / 編輯器選單,主選單(Main Menu),檢視 / 編輯器選單(ViewPart/EditorPart Menu)和上下文選單(Context Menu)。外掛開發人員通過靈活應用這些選單,可以給使用者提供很好的體驗。由於檢視和編輯器選單功能類似,因此本文重點講述檢視選單(檢視下拉選單及其工具欄選單),除此之外,還將講述主選單和上下文選單。

如圖 1 所示為 Project Explorer 檢視的選單,包括檢視下拉選單和工具欄選單(摺疊樹節點)。通常而言,出現在檢視工具欄的選單都會出現在檢視的下拉選單,也就是說,比較常用的檢視選單放在檢視的工具欄。

圖 1. Project Explorer 檢視的選單
圖 1. Project Explorer 檢視的選單

如圖 2 所示為 Project Explorer 檢視中的上下文選單,只有當我們右鍵點選時才會出現。通常而言,出現頻率較高的選單項才會出現在選單中。上下文選單具有很強的靈活項,它可以隨著我們點選的物件不同,彈出的選單也會有相應的變化。

圖 2. Project Explorer 檢視中的上下文選單
圖 2. Project Explorer 檢視中的上下文選單

如圖 3 所示為 Eclipse 的主選單,包括最上面的主選單項(不可移動)及其下面的工具欄選單(可以移動,並且 Eclipse 提供了顯示 / 不顯示這些選單的功能),Eclipse 並不建議我們為每一個外掛都新增新的主選單,這樣容易造成冗餘,而且不方便使用者操作。通常,我們可以把選單項新增到 Eclipse 已有的選單,如外掛的查詢功能可以新增一個查詢選單項到 Eclipse 的 Search 主選單上。

圖 3. Eclipse 的主選單
圖 3. Eclipse 的主選單

前面講到 Eclipse 的各種選單,那麼,如何在開發外掛或 RCP 應用程式的時候新增這些選單?本文下面的篇幅將詳細介紹如何擴充套件 Eclipse 的選單功能,使讀者深入瞭解 Eclipse 的選單功能,並能夠開發具有這些選單的應用程式。因此,必須掌握三方面的內容:選單種類,選單的擴充套件點,選單控制(顯示 / 隱藏或啟用 / 禁用選單項)。下面從概念上介紹這三方面內容,下一小節將會進行詳細介紹。

選單種類

正如前面所講到的,Eclipse 的選單包括檢視選單,主選單及上下文選單三個種類。

選單項的擴充套件點

Eclipse 提供了兩種擴充套件點供使用者新增選單項到相應的位置。這兩種擴充套件點為 org.eclipse.ui.commands(本文簡稱為 Commands 方式)和 org.eclipse.ui.actionSets(本文簡稱為 Actions 方式)。Actions 方式為介面上不同區域的表現方式提供了相應的擴充套件點,並且沒有分離其介面表現和內在實現。恰恰相反,Commands 方式通過三步有效的達到介面表現和內部實現的分離:首先,通過 org.eclipse.ui.commands 擴充套件點建立命令和類別(Category),並且可以把某些命令放在一個類別(Category)中;然後,通過 org.eclipse.ui.menus 指定命令出現在介面的哪個區域(檢視選單 / 主選單 / 上下文選單);最後通過 org.eclipse.ui.handlers 指定命令的實現。因此,Eclipse 推薦新開發的外掛使用 Commands 來建立您的介面選單。當然,由於 Actions 在現有的外掛中用得比較多,如果我們需要擴充套件或基於之前的外掛開發,也需要對其進行了解。除此之外,針對上下文選單,雖然 Commands 和 Actions 方式均可以建立上下文選單,但是 Eclipse 還提供了另外一種建立上下文選單的擴充套件點 org.eclipse.ui.popupMenus(本文簡稱為 popupMenus 方式),本文將就這三種擴充套件點做詳細的介紹。

選單控制

選單控制是一個非常常見的功能,例如,隨著選定的內容或當前視窗的不同,選單中的選單項會有相應的變化(顯示 / 隱藏或啟用 / 禁用選單項),因此,如何控制選單是外掛開發人員必須掌握的知識。Eclipse 為選單控制提供了兩種方法,一種是通過擴充套件點;另一種是通過 API 的方式編寫程式控制。

Eclipse 選單功能及其擴充套件點

至此,我們對 Eclipse 選單有了感觀的認識。由上一節我們可知,要深入理解 Eclipse 選單功能,我們需要從三個方面去掌握:選單種類,選單的擴充套件點和選單控制。下面將進行詳細講述。

選單種類

針對各種選單,Eclipse 提供了相應的擴充套件點,因此,開發人員可以通過這些擴充套件點把選單放到介面的不同區域,詳細內容請參考 2.2 小節。

選單的擴充套件點

檢視選單的擴充套件點

採用 Commands 方式建立檢視選單,需要引入 org.eclipse.ui.menus 擴充套件點;而 Actions 方式需要引入 org.eclipse.ui.actionSets.

1、檢視選單(Commands 方式):

MenuContribution locationURI = “[Scheme]:[id]?[argument-list]”

其中,Scheme 為該選單項出現的區域,menu 為檢視的下拉選單,toolbar 為檢視的工具欄選單;id 為選單區域 ID;argument-list 為該選單項出現在指定選單的位置。

例如:在 ProbelmView 的下拉選單加一個選單項,其 MenuContribution 的 locationURI 應為:menu:org.eclipse.ui.views.ProblemView?after=additions;在 ProblemView 的工具欄選單中加入一個選單項,其 locationURI 應為:toolbar:org.eclipse.ui.views.ProblemView?after=additions。

2、檢視選單(Actions 方式):

採用 Actions 方式建立選單,需要引入 org.eclipse.ui.actionSets 擴充套件點,並通過設定 action 的 menubarPath 指定下拉選單 / 選單項出現的位置;通過設定 action 的 toolbarPath 設定工具欄選單 / 選單項出現的位置。

例如,新增一個下拉選單項到 Problems 檢視中,其 menubarPath 應為:

org.eclipse.ui.views.ProblemView/additions

主選單的擴充套件點

1、主選單(Commands 方式)

通過 Commands 方式把選單項新增到主選單及其工具欄上,和檢視選單一樣,也是通過擴充套件點 org.eclipse.ui.menus 實現,需要設定其 menuContribution 的 locationURI。

例如,新增一個選單(選單可以包含若干個選單項)到主選單一欄中,其 locationURI 為:

menu:org.eclipse.ui.main.menu?after=additions

新增一個選單到工具欄之中,其 locationURI 為:

toolbar:org.eclipse.ui.main.toolbar?after=additions

當然,我們也可以把選單項新增到已經存在的選單當中,例如新增一個選單項到 Eclipse 的 Search 主選單當中,其 locationURI 為:

menu:org.eclipse.search.menu?dialogGroup

2、主選單(Actions 方式)

通過 Actions 方式把選單項新增到主選單及其工具欄上,和檢視選單一樣,也是通過擴充套件點 org.eclipse.ui.actionSets 實現,需要設定 action 的 menubarPath 和 toolbarPath 實現。

例如,新增一個選單項到 Eclipse 的 Search 主選單中,其 menubarPath 應為:

org.eclipse.search.menu/dialogGroup

注意:如果採用上述方式新增一個選單項到 Search 主選單,當我們執行時並沒有出現新增的選單項,這時候需要換一個 workspace,其原因是 Eclipse 快取了與其相關的某些資訊在 workspace 當中。

上下文選單的擴充套件點

上下文選單除了通過 Commands 和 Actions 方式新增,還可以使用擴充套件點 org.eclipse.ui.popupMenus 方式新增,下面分別進行介紹。

1、上下文選單(Commands 方式)

Commands 方式與新增檢視選單和主選單的方式一樣,通過設定其 menuContribution 的 locationURI 來實現。

例如,新增一個上下文選單到 Problems 檢視中,其 locationURI 為:

popup:org.eclipse.ui.views.ProblemView?after=additions。

如果我們想讓某個上下文選單項出現在任何區域,則可以使用下面的 locationURI:

popup:org.eclipse.ui.popup.any?after=additions

2、上下文選單(Actions 方式)

Actions 方式沒有直接提供擴充套件點新增上下文選單,但是我們可以通過程式設計的方式實現,如下程式碼清單 1 為 TreeViewer 新增上下文選單,通過 IMenuManager 的 add 方法新增 actions。

清單 1. 通過 Actions 方式程式設計實現新增上下文選單
 private void hookContextMenu() { 
    IMenuManager fMenuMgr = new MenuManager(“#PopupMenu”); 
    fMenuMgr.setRemoveAllWhenShown(true); 
    // 新增 Actions 
    fMenuMgr.add(action … ) 
    fMenuMgr.createContextMenu(treeViewer.getControl()); 
    treeViewer.getControl().setMenu(fMenu); 
    getSite().registerContextMenu(fMenuMgr, treeViewer); 
 }

3、上下文選單(popupMenus 方式)

通過 popupMenus 擴充套件點實現上下文選單,需要設定 objectContribution 的 objectClass 屬性把上下文選單新增到相應的區域。

例如,如果我們想當用戶點選 Eclipse 中的資源時,彈出的上下文選單包括某個選單項,我們可以設定 objectClass 屬性為:

org.eclipse.core.resources.IResource

通過 Commands 方式建立選單項

通過 Commands 方式建立選單項,首先需要建立 Command,通過擴充套件點 org.eclipse.ui.commands,然後我們可以把這個 Command 放到任何區域,上一小節已經講到,通過 org.eclipse.ui.menus 擴充套件點確定選單建立的區域,最後通過擴充套件點 org.eclipse.ui.handlers 定義這個 command 的具體行為。

在建立 Command 時,我們可以先建立一個 Category,並把相關的一些命令放到這個 Category 中,這樣有利於管理。程式碼清單 2 建立一個 Command(“Show in Glossary Explorer”),並放到一個 Category 中,然後把該 Command 放到 BGSearchResultView 檢視的上下文選單中,最後通過擴充套件 org.eclipse.ui.handlers 定義該 Command 的實現類。

清單 2. 通過 Commands 方式新增選單項
 <!-- 新增 command --> 
 <extension 
      point="org.eclipse.ui.commands"> 
   <category 
      description="Business Glossary"
      id="com.ibm.bg.ui.commands.category"
      name="%category.BusinessGlossary.name"> 
   </category> 
   <command 
      categoryId="com.ibm.bg.ui.commands.category"
      description="Show in Glossary Explorer"
      id="com.ibm.bg.ui.commands.BGShowInBrowser"
      name="%command.ShowInGE.name"> 
    </command> 
 </extension> 
 <!-- 把 Command 放到介面的對應區域 --> 
 <extension 
       point="org.eclipse.ui.menus"> 
   <menuContribution locationURI= 
   "popup:com.ibm.bg.internal.ui.search.BGSearchResultView?after=additions"> 
      <command 
            commandId="com.ibm.bg.ui.commands.BGShowInBrowser"
            style="push"
            tooltip="%command.ShowInGE.tooltip"> 
      </command> 
   </menuContribution> 
 </extension> 
 <!-- 定義 command 的實現類 --> 
 <extension 
      point="org.eclipse.ui.handlers"> 
   <handler 
         class="com.ibm.bg.internal.ui.handlers.BGShowInBrowser"
         commandId="com.ibm.bg.ui.commands.BGShowInBrowser"> 
   </handler> 
 </extension>

通過 Actions 方式建立選單項

正如前面講到,Actions 方式沒有分離介面的表現和內部實現,因此,所有這些均通過 action 來完成。如下程式碼清單 3 為新增一個 Search 選單項到 Eclipse 的 Search 主選單(通過 action 的 menubarPath 指定)中,其中 class 對應的值為該 Action 的實現類,該類需要實現介面 IWorkbenchWindowActionDelegate。

清單 3. 通過 Actions 方式新增選單項
 <extension 
      point="org.eclipse.ui.actionSets"> 
   <actionSet 
         id="com.ibm.bg.ui.workbenchActionSet"
         label="%category.name.0"
         visible="true"> 
      <action 
            class="com.ibm.bg.internal.ui.handlers.BGSearchHandler"
            definitionId="com.ibm.bg.ui.commands.BGSearch"
            icon="icons/search.png"
            id="com.ibm.bg.ui.commands.BGSearch"
            label="%action.searchGlossayInMainMenu.label"
            menubarPath="org.eclipse.search.menu/dialogGroup"
            style="push"> 
      </action> 
   </actionSet> 
 </extension>

通過 popupMenus 方式建立選單項

popupMenus 方式建立上下文選單項也是通過 action 來實現,下面例子為新增一個選單項到使用者右擊 IGraphicalEditPart 物件時彈出的上下文選單,通過 menubarPath 指定該 Action 出現的區域,通過 class 指定該 action 的實現類,該類需要實現介面 IObjectActionDelegate。

清單 4. 通過 popupMenus 方式新增選單項
 <extension 
      point="org.eclipse.ui.popupMenus"> 
   <objectContribution 
         adaptable="false"
         id="com.ibm.bg.uml.objectContributions.BGAssignToGlossary"
         objectClass="org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart"> 
      <action 
            class="com.ibm.bg.internal.uml.actions.BGAssignToGlossary"
            enablesFor="+"
            icon="icons/assign.png"
            id="com.ibm.bg.internal.uml.actions.BGAssignToGlossary"
            label="%BGAssignToGlossary.item"
            menubarPath="com.ibm.bg.uml.popupMenuGroup"> 
      </action> 
   </objectContribution> 
 </extension>

選單控制

檢視選單的控制主要包括啟用 / 禁用,顯示 / 隱藏選單。

通過 Command 方式建立的選單,可以通過 org.eclipse.ui.commands 的 visibleWhen 屬性控制選單的隱藏和顯示,通過 org.eclipse.ui.handlers 的 activewhen 或 enabledWhen 控制選單的啟用或禁用。

通過 Actions 方式建立的選單,可以通過 action 的 enablement 屬性控制選單的啟用 / 禁用。

通過 popupMenus 方式建立的選單,可以通過 objectContribution 的 visibility 和 enablement 來設定該 objectContribution 下的 action 的顯示 / 隱藏和啟用 / 禁用,我們也可以設定 action 的 enablement 來控制該選單的啟用 / 禁用。

這裡不詳細講述 enablement,visibleWhen 和 enabledWhen 的引數及如何設定,讀者可以參考第三節的例子和本文的參考文獻。

程式設計實踐

本文將結合前兩節講到的知識,以例子的形式說明如何建立並且控制選單。首先建立一個檢視(Menu Example),然後分別通過 Commands,Actions 和 popupMenus 方式建立若干個選單,並新增相應的選單控制點。

建立 Menu Example 檢視

擴充套件 org.eclipse.views 建立“Menu Example”檢視,如下程式碼清單 5 為建立檢視的 xml 程式碼。

清單 5. 擴充套件 org.eclipse.ui.views 建立檢視
 <extension 
      point="org.eclipse.ui.views"> 
   <category 
         id="com.free.menu.category"
         name="Menu Example View"> 
   </category> 
   <view 
         category="com.free.menu.category"
         class="com.free.menu.view.MenuExplorer"
         id="com.free.menu.view.MenuExplorer"
         name="Menu Explorer"
         restorable="true"> 
   </view> 
 </extension>

建立 Commands

採用 Command 方式建立“Menu Example”主選單(包含 AngryCommand 和 JokeCommand 兩個選單項),並且基於這兩個選單項建立了 Menu Example 檢視的下拉選單和工具欄選單,及其 TreeViewer 的上下文選單。

如下程式碼清單 6 為擴充套件 org.eclipse.ui.commands 建立 Menu Example 命令和類別,並且包含兩個命令:Joke Command 和 Angry Command。

清單 6. 擴充套件 org.eclipse.ui.commands 建立命令
 <extension 
      point="org.eclipse.ui.commands"> 
   <category 
         id="com.free.menu.category"
         name="Menu Example"> 
   </category> 
   <command 
         categoryId="com.free.menu.category"
         id="com.free.menu.commands.jokeCommand"
         name="Joke Command"> 
   </command> 
   <command 
         categoryId="com.free.menu.category"
         id="com.free.menu.commands.angryCommand"
         name="Angry Command"> 
   </command> 
 </extension>

關聯 Commands 到主選單

如下程式碼清單 7 為擴充套件 org.eclipse.ui.menus,並基於前面建立的 Comands,新增一個主選單 Menu Example,並且包含 Joke Command 和 Angry Command 選單項。

清單 7. 建立 Menu Example 主選單
 <menuContribution 
      locationURI="menu:org.eclipse.ui.main.menu?after=additions"> 
   <menu 
     id="com.free.menu.MenuExample"
          label="Menu Example"> 
      <command 
            commandId="com.free.menu.commands.jokeCommand"
            style="push"> 
      </command> 
      <command 
            commandId="com.free.menu.commands.angryCommand"
            style="push"> 
      </command> 
   </menu> 
 </menuContribution>

關聯 Commands 到檢視選單

如下程式碼清單 8 為擴充套件 org.eclipse.ui.menus,並基於 Commands 方式建立 Menu Example 檢視的下拉選單,工具欄選單和上下文選單,通過 locationURI 來設定。Joke Command 即為下拉選單也是工具欄選單,只有當我們選擇了 TreeViewer 中的節點時該選單項才是可見的,參考下面的 visibleWhen->with->iterate->or->instanceof。

清單 8. 通過 Commands 方式建立檢視選單
 <extension 
       point="org.eclipse.ui.menus"> 
    <menuContribution 
          locationURI="menu:com.free.menu.view.MenuExplorer?after=additions"> 
       <command 
             commandId="com.free.menu.commands.jokeCommand"
             icon="icons/searchres.gif"
             style="push"> 
             <visibleWhen 
                   checkEnabled="false"> 
                <with 
                     variable="selection"> 
                   <iterate 
                        ifEmpty="true"
                        operator="or"> 
                    <or> 
                        <instanceof 
                                value="com.free.menu.model.Person"> 
                        </instanceof>                                             
                    </or> 
                  </iterate> 
                  </with> 
               </visibleWhen>                 
         </command> 
      </menuContribution> 
      <menuContribution 
            locationURI="toolbar:com.free.menu.view.MenuExplorer?after=additions"> 
         <command 
               commandId="com.free.menu.commands.jokeCommand"
               icon="icons/searchres.gif"
               style="push"> 
               <visibleWhen 
                     checkEnabled="false"> 
                  <with 
                        variable="selection"> 
                     <iterate 
                           ifEmpty="true"
                           operator="or"> 
                        <or> 
                              <instanceof 
                                    value="com.free.menu.model.Person"> 
                              </instanceof>                                             
                        </or> 
                     </iterate> 
                  </with> 
               </visibleWhen>  
         </command> 
      </menuContribution> 
      <menuContribution 
            locationURI="popup:com.free.menu.view.MenuExplorer?after=additions"> 
         <command 
               commandId="com.free.menu.commands.jokeCommand"
               icon="icons/searchres.gif"
               style="push"> 
         </command> 
         <command 
               commandId="com.free.menu.commands.angryCommand"
               style="push"> 
         </command>      
      </menuContribution> 
 </extension>

Commands 的實現類

如下程式碼清單 9 所示擴充套件 org.eclipse.ui.handlers 為 Joke Command 和 Angry Command 建立事件處理類,其中 Joke Command 通過 enabledWhen 屬性控制該選單項是否啟用,當我們同時選擇了兩個物件時 Joke Command 處於啟用狀態,否則為禁用。

清單 9. 擴充套件 org.eclipse.ui.handlers 為 Commands 建立實現類
 <extension 
      point="org.eclipse.ui.handlers"> 
   <handler 
         class="com.free.menu.actions.JokeCommand"
         commandId="com.free.menu.commands.jokeCommand"> 
      <enabledWhen> 
         <count 
               value="2"> 
         </count> 
      </enabledWhen> 
   </handler> 
   <handler 
         class="com.free.menu.actions.AngryCommand"
         commandId="com.free.menu.commands.angryCommand"> 
   </handler> 
 </extension>

建立 Action 並關聯到 Eclipse 的 Search 主選單

採用 Actions 方式在 Eclipse 的主選單 Search 中新增建立選單項 SmileAction。擴充套件 org.eclipse.ui.actionSets 在 Eclipse 的主選單 Search 中新增一個選單項 Smile Action。如下程式碼清單 10 所示建立該 action 並新增到 search 主選單,只有當我們選擇至少一個物件時(設定 enablesFor 屬性為“+”),該選單項才處於啟用狀態。

清單 10. 通過 Actions 方式建立選單項
 <extension 
      point="org.eclipse.ui.actionSets"> 
   <actionSet 
         id="com.free.menu.actionSet.MenuExample"
         label="Menu Example"
         visible="true"> 
      <action 
            class="com.free.menu.actions.SmileAction"
            enablesFor="+"
            icon="icons/searchres.gif"
            id="com.free.menu.actions.smileAction"
            label="Smile Action"
            menubarPath="org.eclipse.search.menu/dialogGroup"
            style="push"> 
      </action> 
   </actionSet> 
 </extension>

pupupMenus 方式建立 Action 並關聯到 IResource 資源的上下文選單

擴充套件 org.eclipse.ui.popupMenus 建立選單“Menu Example”,該選單包含一個選單項 HelloAction。當我們在 Eclipse 任何區域右擊 org.eclipse.core.resources.IResource 資源時彈出的上下文選單中會出現“Menu Example”選單。如下程式碼清單 11 為建立該上下文選單的 xml 程式碼。

清單 11. popupMenus 方式建立上下文選單
 <extension 
      point="org.eclipse.ui.popupMenus"> 
   <objectContribution 
         adaptable="true"
         id="com.free.menu.popupMenu"
         objectClass="org.eclipse.core.resources.IResource"> 
      <menu 
            label="Menu Example"
            path="additions"
            id="com.free.menu.popupSubMenu"> 
         <separator 
               name="additions"> 
         </separator> 
      </menu> 
      <action 
            label="Hello Action"
            class="com.free.menu.popup.actions.HelloAction"
            menubarPath="com.free.menu.popupSubMenu/additions"
            enablesFor="1"
            id="com.free.menu.newAction"> 
      </action> 
   </objectContribution> 
 </extension>

pupupMenus 方式建立 Action 並關聯到 IResource 資源的上下文選單

擴充套件 org.eclipse.ui.popupMenus 建立選單項 GreetAction 和 CryAction,當我們右擊 Menu Example 檢視中的 TreeViewer 節點時彈出。如下程式碼清單 12 所示擴充套件 org.eclipse.ui.popupMenus 為 Menu Example 檢視建立 GreetAction 和 CryAction 上下文選單項。使用 visiblity 的 objectState 屬性控制選單項的可見狀態,使用該屬性要求其選擇的物件實現了 org.eclipse.ui.IActionFilter 介面,具體可參見 Person 類的實現。

清單 12. 擴充套件 org.eclipse.ui.popupMenus 建立選單
 <extension 
      point="org.eclipse.ui.popupMenus"> 
   <objectContribution 
         adaptable="false"
         id="com.free.menu.views.popupMenu"
         objectClass="com.free.menu.model.Person"> 
      <action 
            class="com.free.menu.actions.GreetAction"
            enablesFor="+"
            id="com.free.menu.actions.greetAction"
            label="Greet Action"
            menubarPath="additions"> 
      </action> 
      <visibility> 
         <objectState 
               name="firstName"
               value="Dan"> 
         </objectState> 
      </visibility> 
   </objectContribution> 
 </extension> 
 <extension 
      point="org.eclipse.ui.popupMenus"> 
   <objectContribution 
         adaptable="false"
         id="com.free.menu.views.popupMenu2"
         objectClass="com.free.menu.model.Person"> 
      <action 
            class="com.free.menu.actions.CryAction"
            enablesFor="+"
            id="com.free.menu.actions.cryAction"
            label="Cry Action"
            menubarPath="additions"> 
         <enablement> 
            <objectState 
                  name="firstName"
                  value="David"> 
            </objectState> 
         </enablement> 
      </action> 
      <visibility> 
         <objectState 
               name="lastName"
               value="Rubel"> 
        </objectState> 
      </visibility> 
   </objectContribution> 
 </extension>

Menu Example 檢視的程式碼實現類

如下程式碼清單 13 所示為 Menu Example 檢視的程式碼,該檢視中有一個 TreeViewer,並通過函式 hookContextMenu 把上下文選單關聯到 TreeViewer。其中函式 viewMenuAction 用於更新選單的狀態,它首先獲取檢視選單,然後呼叫 IMenuManager 的 update 方法更新對應選單項的狀態,從而達到控制選單的目的。

清單 13. Menu Example 檢視程式碼
 public class MenuExplorer extends ViewPart { 
    private TreeViewer treeViewer; 
    private MenuManager fMenuMgr; 
    private Menu fMenu; 
    private static MenuExplorer fInstance = null; 
    public MenuExplorer() { 
        fInstance = this; 
    } 
    public static MenuExplorer getInstance(){ 
        return fInstance; 
    } 
    public void createPartControl(Composite parent) { 
        treeViewer = new TreeViewer (parent, SWT.MULTI); 
        treeViewer.setLabelProvider(new PersonListLabelProvider()); 
        treeViewer.setContentProvider(new PersonTreeContentProvider()); 
        treeViewer.setInput(Person.example()); 
        this.getSite().setSelectionProvider(treeViewer); 
        hookContextMenu(); 
        fInstance = this; 
        
    } 
    public void setViewMenuActionState(boolean state){        
        JokeCommand.setState(state); 
        viewMenuAction(); 
    } 
    private  void viewMenuAction() { 
        IActionBars bars= getViewSite().getActionBars(); 
        final IMenuManager menu= bars.getMenuManager();    
        
        UIOperation.asyncExecCommand(new Runnable(){ 
            public void run() { 
                menu.update("com.free.menu.commands.jokeAction"); 
            }            
        });        
    } 
    private void hookContextMenu() { 
        fMenuMgr = new MenuManager("#PopupMenu"); 
        fMenuMgr.setRemoveAllWhenShown(true); 
        fMenuMgr.addMenuListener(new IMenuListener() { 
            public void menuAboutToShow(IMenuManager manager) {                
            } 
        }); 
        fMenu = fMenuMgr.createContextMenu(treeViewer.getControl()); 

        treeViewer.getControl().setMenu(fMenu); 
        getSite().registerContextMenu(fMenuMgr, treeViewer);              
    }    
    public void setFocus() { 
        treeViewer.getTree().setFocus(); 

    } 
 }

Person 類的實現

如下程式碼清單 14 為 Person 類的實現,用於表示 MenuExample 檢視中 TreeViewer 的一個節點,它實現了 IActionFilter 介面,通過 testAttribute 來確定是否顯示 / 隱藏選單(其中 target 表示使用者選擇的物件,name/value 對應於 plugin.xml 檔案中 objectState 的 name/value).

清單 14. Person 類實現
 public class Person implements IActionFilter { 

    private String firstName = "John"; 
    private String lastName = "Doe"; 
    protected int age = 37; 
    public Person[] children = new Person[0]; 
    public Person parent = null; 
    public Person(String firstName, String lastName, int age) { 
        this.firstName = firstName; 
        this.lastName = lastName; 
        this.age = age; 
    } 
    public Person(String firstName, String lastName, int age, Person[] children) { 
        this(firstName, lastName, age); 
        this.children = children; 
        for (int i = 0; i < children.length; i++) { 
            children[i].parent = this; 
        } 
    } 
    public String getFirstName() { 
        return this.firstName; 
    } 
    public String getLastName() { 
        return this.lastName; 
    } 
    public static Person[] example() { 
        return new Person[] { 
                new Person("Dan", "Rubel", 38, new Person[] { 
                        new Person("Beth", "Rubel", 8), 
                        new Person("David", "Rubel", 3) }), 
                new Person("Eric", "Clayberg", 39, new Person[] { 
                        new Person("Lauren", "Clayberg", 6), 
                        new Person("Lee", "Clayberg", 4) }), 
                new Person("Mike", "Taylor", 52) }; 
    } 
    public String toString() { 
        return firstName + " " + lastName; 
    } 
    public boolean testAttribute(Object target, String name, String value) { 

        if (target instanceof Person) { 
            Person person = (Person) target; 
            if (name.equals("firstName") && value.equals(person.getFirstName())) { 
                return true; 
            } 

            if (name.equals("lastName") && value.equals(person.getLastName())) { 
                return true; 
            } 
        } 
        return false; 
    } 
 }

總結

至此為止,已經把 Eclipse 選單功能及其擴充套件點涉及到的類 / 介面 /API 進行了詳細的說明,相信讀者已經有清晰的認識了。對於前面提到 popupMenus 方式建立上下文選單,要求選擇的物件實現 IActionFilter 介面,但是,如果開發人員正在使用 gmf 進行開發,那麼我們可以不必要求選擇的物件實現 IActionFilter,我們可以通過擴充套件 org.eclipse.gmf.runtime.common.ui.services.action.actionFilterProviders 對選單項進行控制,如下程式碼清單 15 為擴充套件該 extension point 的 xml 程式碼,我們可以定義多個屬性(<Attribute> … </Attribute),其中 Attribute 的 name 和 value 對應於 visibility 的 objectState 中的 name 和 value。

清單 15. 通過 actionFilterProviders 擴充套件點實現對選單的控制
 <extension 
 point="org.eclipse.gmf.runtime.common.ui.services.action.actionFilterProviders"> 
     <ActionFilterProvider 
           class="com.free.menu.PopupActionFilterProvider"> 
        <Priority 
              name="Medium"> 
        </Priority> 
        <Attribute 
              name="com.ibm.bg.uml.search.isSupportedType"
              value="supported"> 
        </Attribute> 
     </ActionFilterProvider> 
 </extension>

如下程式碼清單 16 所示 PopupActionFilterProvider 的實現,它繼承 AbstractActionFilterProvider,只需要實現其中的 testAttribute 和 provides 方法,當 testAttribute 返回 true 時,那麼該選單項被啟用,否則禁用。其中 target 對應於我們選擇的物件,name 和 value 引數對應於 visiblity 中 objectState 的 name 和 value 的指定值 ( 與前面提到的 Person 類中的 testAttribute 方法類似 )。

清單 16. actionFilterProviders 擴充套件點實現類
 public class PopupActionFilterProvider extends AbstractActionFilterProvider { 


    public PopupActionFilterProvider() { 
    } 

    public boolean testAttribute(Object target, String name, String value) { 
            
    } 

    public boolean provides(IOperation operation) { 
        return false; 
    } 

 }