原文地址:http://www.fengfly.com/plus/view-179398-1.html
菜單是各種軟件及開(kāi)發(fā)平臺(tái)會(huì)提供的必備功能,Eclipse 也不例外,提供了豐富的菜單,包括主菜單(Main Menu),視圖 / 編輯器菜單(ViewPart/Editor Menu)和上下文菜單(Context Menu)。在 Eclipse 中,幾乎所有的 Workbench Part 提供了人性化的菜單,大大方便了用戶的操作。因此,如何擴(kuò)展 Eclipse 的菜單功能,并實(shí)現(xiàn)特定于我們自己插件的菜單,是插件開(kāi)發(fā)者必須掌握的重要技能,同時(shí),Eclipse 提供了豐富的擴(kuò)展點(diǎn)供開(kāi)發(fā)人員使用。本文將首先介紹 Eclipse 中的菜單,然后詳細(xì)說(shuō)明如何進(jìn)行擴(kuò)展,最后以一個(gè)實(shí)例的形式引導(dǎo)讀者深入理解 Eclipse 的菜單功能。
引言
Eclipse 具有豐富的菜單功能,給開(kāi)發(fā)人員提供了很好的用戶體驗(yàn)。總體而言,Eclipse 菜單種類包括視圖 / 編輯器菜單,主菜單(Main Menu),視圖 / 編輯器菜單(ViewPart/EditorPart Menu)和上下文菜單(Context Menu)。插件開(kāi)發(fā)人員通過(guò)靈活應(yīng)用這些菜單,可以給用戶提供很好的體驗(yàn)。由于視圖和編輯器菜單功能類似,因此本文重點(diǎn)講述視圖菜單(視圖下拉菜單及其工具欄菜單),除此之外,還將講述主菜單和上下文菜單。
如圖 1 所示為 Project Explorer 視圖的菜單,包括視圖下拉菜單和工具欄菜單(折疊樹(shù)節(jié)點(diǎn))。通常而言,出現(xiàn)在視圖工具欄的菜單都會(huì)出現(xiàn)在視圖的下拉菜單,也就是說(shuō),比較常用的視圖菜單放在視圖的工具欄。
圖 1. Project Explorer 視圖的菜單

如圖 2 所示為 Project Explorer 視圖中的上下文菜單,只有當(dāng)我們右鍵點(diǎn)擊時(shí)才會(huì)出現(xiàn)。通常而言,出現(xiàn)頻率較高的菜單項(xiàng)才會(huì)出現(xiàn)在菜單中。上下文菜單具有很強(qiáng)的靈活項(xiàng),它可以隨著我們點(diǎn)擊的對(duì)象不同,彈出的菜單也會(huì)有相應(yīng)的變化。
圖 2. Project Explorer 視圖中的上下文菜單

如圖 3 所示為 Eclipse 的主菜單,包括最上面的主菜單項(xiàng)(不可移動(dòng))及其下面的工具欄菜單(可以移動(dòng),并且 Eclipse 提供了顯示 / 不顯示這些菜單的功能),Eclipse 并不建議我們?yōu)槊恳粋€(gè)插件都添加新的主菜單,這樣容易造成冗余,而且不方便用戶操作。通常,我們可以把菜單項(xiàng)添加到 Eclipse 已有的菜單,如插件的查找功能可以添加一個(gè)查找菜單項(xiàng)到 Eclipse 的 Search 主菜單上。
圖 3. Eclipse 的主菜單

前面講到 Eclipse 的各種菜單,那么,如何在開(kāi)發(fā)插件或 RCP 應(yīng)用程序的時(shí)候添加這些菜單?本文下面的篇幅將詳細(xì)介紹如何擴(kuò)展 Eclipse 的菜單功能,使讀者深入了解 Eclipse 的菜單功能,并能夠開(kāi)發(fā)具有這些菜單的應(yīng)用程序。因此,必須掌握三方面的內(nèi)容:菜單種類,菜單的擴(kuò)展點(diǎn),菜單控制(顯示 / 隱藏或啟用 / 禁用菜單項(xiàng))。下面從概念上介紹這三方面內(nèi)容,下一小節(jié)將會(huì)進(jìn)行詳細(xì)介紹。
菜單種類
正如前面所講到的,Eclipse 的菜單包括視圖菜單,主菜單及上下文菜單三個(gè)種類。
菜單項(xiàng)的擴(kuò)展點(diǎn)
Eclipse 提供了兩種擴(kuò)展點(diǎn)供用戶添加菜單項(xiàng)到相應(yīng)的位置。這兩種擴(kuò)展點(diǎn)為 org.eclipse.ui.commands(本文簡(jiǎn)稱為 Commands 方式)和 org.eclipse.ui.actionSets(本文簡(jiǎn)稱為 Actions 方式)。Actions 方式為界面上不同區(qū)域的表現(xiàn)方式提供了相應(yīng)的擴(kuò)展點(diǎn),并且沒(méi)有分離其界面表現(xiàn)和內(nèi)在實(shí)現(xiàn)。恰恰相反,Commands 方式通過(guò)三步有效的達(dá)到界面表現(xiàn)和內(nèi)部實(shí)現(xiàn)的分離:首先,通過(guò) org.eclipse.ui.commands 擴(kuò)展點(diǎn)創(chuàng)建命令和類別(Category),并且可以把某些命令放在一個(gè)類別(Category)中;然后,通過(guò) org.eclipse.ui.menus 指定命令出現(xiàn)在界面的哪個(gè)區(qū)域(視圖菜單 / 主菜單 / 上下文菜單);最后通過(guò) org.eclipse.ui.handlers 指定命令的實(shí)現(xiàn)。因此,Eclipse 推薦新開(kāi)發(fā)的插件使用 Commands 來(lái)創(chuàng)建您的界面菜單。當(dāng)然,由于 Actions 在現(xiàn)有的插件中用得比較多,如果我們需要擴(kuò)展或基于之前的插件開(kāi)發(fā),也需要對(duì)其進(jìn)行了解。除此之外,針對(duì)上下文菜單,雖然 Commands 和 Actions 方式均可以創(chuàng)建上下文菜單,但是 Eclipse 還提供了另外一種創(chuàng)建上下文菜單的擴(kuò)展點(diǎn) org.eclipse.ui.popupMenus(本文簡(jiǎn)稱為 popupMenus 方式),本文將就這三種擴(kuò)展點(diǎn)做詳細(xì)的介紹。
菜單控制
菜單控制是一個(gè)非常常見(jiàn)的功能,例如,隨著選定的內(nèi)容或當(dāng)前窗口的不同,菜單中的菜單項(xiàng)會(huì)有相應(yīng)的變化(顯示 / 隱藏或啟用 / 禁用菜單項(xiàng)),因此,如何控制菜單是插件開(kāi)發(fā)人員必須掌握的知識(shí)。Eclipse 為菜單控制提供了兩種方法,一種是通過(guò)擴(kuò)展點(diǎn);另一種是通過(guò) API 的方式編寫程序控制。
Eclipse 菜單功能及其擴(kuò)展點(diǎn)
至此,我們對(duì) Eclipse 菜單有了感觀的認(rèn)識(shí)。由上一節(jié)我們可知,要深入理解 Eclipse 菜單功能,我們需要從三個(gè)方面去掌握:菜單種類,菜單的擴(kuò)展點(diǎn)和菜單控制。下面將進(jìn)行詳細(xì)講述。
菜單種類
針對(duì)各種菜單,Eclipse 提供了相應(yīng)的擴(kuò)展點(diǎn),因此,開(kāi)發(fā)人員可以通過(guò)這些擴(kuò)展點(diǎn)把菜單放到界面的不同區(qū)域,詳細(xì)內(nèi)容請(qǐng)參考 2.2 小節(jié)。
菜單的擴(kuò)展點(diǎn)
視圖菜單的擴(kuò)展點(diǎn)
采用 Commands 方式創(chuàng)建視圖菜單,需要引入 org.eclipse.ui.menus 擴(kuò)展點(diǎn);而 Actions 方式需要引入 org.eclipse.ui.actionSets.
1、視圖菜單(Commands 方式):
MenuContribution locationURI = “[Scheme]:[id]?[argument-list]”
其中,Scheme 為該菜單項(xiàng)出現(xiàn)的區(qū)域,menu 為視圖的下拉菜單,toolbar 為視圖的工具欄菜單;id 為菜單區(qū)域 ID;argument-list 為該菜單項(xiàng)出現(xiàn)在指定菜單的位置。
例如:在 ProbelmView 的下拉菜單加一個(gè)菜單項(xiàng),其 MenuContribution 的 locationURI 應(yīng)為:menu:org.eclipse.ui.views.ProblemView?after=additions;在 ProblemView 的工具欄菜單中加入一個(gè)菜單項(xiàng),其 locationURI 應(yīng)為:toolbar:org.eclipse.ui.views.ProblemView?after=additions。
2、視圖菜單(Actions 方式):
采用 Actions 方式創(chuàng)建菜單,需要引入 org.eclipse.ui.actionSets 擴(kuò)展點(diǎn),并通過(guò)設(shè)定 action 的 menubarPath 指定下拉菜單 / 菜單項(xiàng)出現(xiàn)的位置;通過(guò)設(shè)定 action 的 toolbarPath 設(shè)定工具欄菜單 / 菜單項(xiàng)出現(xiàn)的位置。
例如,添加一個(gè)下拉菜單項(xiàng)到 Problems 視圖中,其 menubarPath 應(yīng)為:
org.eclipse.ui.views.ProblemView/additions
主菜單的擴(kuò)展點(diǎn)
1、主菜單(Commands 方式)
通過(guò) Commands 方式把菜單項(xiàng)添加到主菜單及其工具欄上,和視圖菜單一樣,也是通過(guò)擴(kuò)展點(diǎn) org.eclipse.ui.menus 實(shí)現(xiàn),需要設(shè)定其 menuContribution 的 locationURI。
例如,添加一個(gè)菜單(菜單可以包含若干個(gè)菜單項(xiàng))到主菜單一欄中,其 locationURI 為:
menu:org.eclipse.ui.main.menu?after=additions
添加一個(gè)菜單到工具欄之中,其 locationURI 為:
toolbar:org.eclipse.ui.main.toolbar?after=additions
當(dāng)然,我們也可以把菜單項(xiàng)添加到已經(jīng)存在的菜單當(dāng)中,例如添加一個(gè)菜單項(xiàng)到 Eclipse 的 Search 主菜單當(dāng)中,其 locationURI 為:
menu:org.eclipse.search.menu?dialogGroup
2、主菜單(Actions 方式)
通過(guò) Actions 方式把菜單項(xiàng)添加到主菜單及其工具欄上,和視圖菜單一樣,也是通過(guò)擴(kuò)展點(diǎn) org.eclipse.ui.actionSets 實(shí)現(xiàn),需要設(shè)定 action 的 menubarPath 和 toolbarPath 實(shí)現(xiàn)。
例如,添加一個(gè)菜單項(xiàng)到 Eclipse 的 Search 主菜單中,其 menubarPath 應(yīng)為:
org.eclipse.search.menu/dialogGroup
注意:如果采用上述方式添加一個(gè)菜單項(xiàng)到 Search 主菜單,當(dāng)我們運(yùn)行時(shí)并沒(méi)有出現(xiàn)添加的菜單項(xiàng),這時(shí)候需要換一個(gè) workspace,其原因是 Eclipse 緩存了與其相關(guān)的某些信息在 workspace 當(dāng)中。
上下文菜單的擴(kuò)展點(diǎn)
上下文菜單除了通過(guò) Commands 和 Actions 方式添加,還可以使用擴(kuò)展點(diǎn) org.eclipse.ui.popupMenus 方式添加,下面分別進(jìn)行介紹。
1、上下文菜單(Commands 方式)
Commands 方式與添加視圖菜單和主菜單的方式一樣,通過(guò)設(shè)定其 menuContribution 的 locationURI 來(lái)實(shí)現(xiàn)。
例如,添加一個(gè)上下文菜單到 Problems 視圖中,其 locationURI 為:
popup:org.eclipse.ui.views.ProblemView?after=additions。
如果我們想讓某個(gè)上下文菜單項(xiàng)出現(xiàn)在任何區(qū)域,則可以使用下面的 locationURI:
popup:org.eclipse.ui.popup.any?after=additions
2、上下文菜單(Actions 方式)
Actions 方式?jīng)]有直接提供擴(kuò)展點(diǎn)添加上下文菜單,但是我們可以通過(guò)編程的方式實(shí)現(xiàn),如下代碼清單 1 為 TreeViewer 添加上下文菜單,通過(guò) IMenuManager 的 add 方法添加 actions。
清單 1. 通過(guò) Actions 方式編程實(shí)現(xiàn)添加上下文菜單
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 方式)
通過(guò) popupMenus 擴(kuò)展點(diǎn)實(shí)現(xiàn)上下文菜單,需要設(shè)定 objectContribution 的 objectClass 屬性把上下文菜單添加到相應(yīng)的區(qū)域。
例如,如果我們想當(dāng)用戶點(diǎn)擊 Eclipse 中的資源時(shí),彈出的上下文菜單包括某個(gè)菜單項(xiàng),我們可以設(shè)定 objectClass 屬性為:
org.eclipse.core.resources.IResource
通過(guò) Commands 方式創(chuàng)建菜單項(xiàng)
通過(guò) Commands 方式創(chuàng)建菜單項(xiàng),首先需要?jiǎng)?chuàng)建 Command,通過(guò)擴(kuò)展點(diǎn) org.eclipse.ui.commands,然后我們可以把這個(gè) Command 放到任何區(qū)域,上一小節(jié)已經(jīng)講到,通過(guò) org.eclipse.ui.menus 擴(kuò)展點(diǎn)確定菜單創(chuàng)建的區(qū)域,最后通過(guò)擴(kuò)展點(diǎn) org.eclipse.ui.handlers 定義這個(gè) command 的具體行為。
在創(chuàng)建 Command 時(shí),我們可以先創(chuàng)建一個(gè) Category,并把相關(guān)的一些命令放到這個(gè) Category 中,這樣有利于管理。代碼清單 2 創(chuàng)建一個(gè) Command(“Show in Glossary Explorer”),并放到一個(gè) Category 中,然后把該 Command 放到 BGSearchResultView 視圖的上下文菜單中,最后通過(guò)擴(kuò)展 org.eclipse.ui.handlers 定義該 Command 的實(shí)現(xiàn)類。
清單 2. 通過(guò) Commands 方式添加菜單項(xiàng)
<!-- 添加 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 放到界面的對(duì)應(yīng)區(qū)域 -->
<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 的實(shí)現(xiàn)類 -->
<extension
point="org.eclipse.ui.handlers">
<handler
class="com.ibm.bg.internal.ui.handlers.BGShowInBrowser"
commandId="com.ibm.bg.ui.commands.BGShowInBrowser">
</handler>
</extension>
通過(guò) Actions 方式創(chuàng)建菜單項(xiàng)
正如前面講到,Actions 方式?jīng)]有分離界面的表現(xiàn)和內(nèi)部實(shí)現(xiàn),因此,所有這些均通過(guò) action 來(lái)完成。如下代碼清單 3 為添加一個(gè) Search 菜單項(xiàng)到 Eclipse 的 Search 主菜單(通過(guò) action 的 menubarPath 指定)中,其中 class 對(duì)應(yīng)的值為該 Action 的實(shí)現(xiàn)類,該類需要實(shí)現(xiàn)接口 IWorkbenchWindowActionDelegate。
清單 3. 通過(guò) Actions 方式添加菜單項(xiàng)
<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>
通過(guò) popupMenus 方式創(chuàng)建菜單項(xiàng)
popupMenus 方式創(chuàng)建上下文菜單項(xiàng)也是通過(guò) action 來(lái)實(shí)現(xiàn),下面例子為添加一個(gè)菜單項(xiàng)到用戶右擊 IGraphicalEditPart 對(duì)象時(shí)彈出的上下文菜單,通過(guò) menubarPath 指定該 Action 出現(xiàn)的區(qū)域,通過(guò) class 指定該 action 的實(shí)現(xiàn)類,該類需要實(shí)現(xiàn)接口 IObjectActionDelegate。
清單 4. 通過(guò) popupMenus 方式添加菜單項(xiàng)
<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>
菜單控制
視圖菜單的控制主要包括啟用 / 禁用,顯示 / 隱藏菜單。
通過(guò) Command 方式創(chuàng)建的菜單,可以通過(guò) org.eclipse.ui.commands 的 visibleWhen 屬性控制菜單的隱藏和顯示,通過(guò) org.eclipse.ui.handlers 的 activewhen 或 enabledWhen 控制菜單的啟用或禁用。
通過(guò) Actions 方式創(chuàng)建的菜單,可以通過(guò) action 的 enablement 屬性控制菜單的啟用 / 禁用。
通過(guò) popupMenus 方式創(chuàng)建的菜單,可以通過(guò) objectContribution 的 visibility 和 enablement 來(lái)設(shè)置該 objectContribution 下的 action 的顯示 / 隱藏和啟用 / 禁用,我們也可以設(shè)置 action 的 enablement 來(lái)控制該菜單的啟用 / 禁用。
這里不詳細(xì)講述 enablement,visibleWhen 和 enabledWhen 的參數(shù)及如何設(shè)置,讀者可以參考第三節(jié)的例子和本文的參考文獻(xiàn)。
編程實(shí)踐
本文將結(jié)合前兩節(jié)講到的知識(shí),以例子的形式說(shuō)明如何創(chuàng)建并且控制菜單。首先創(chuàng)建一個(gè)視圖(Menu Example),然后分別通過(guò) Commands,Actions 和 popupMenus 方式創(chuàng)建若干個(gè)菜單,并添加相應(yīng)的菜單控制點(diǎn)。
創(chuàng)建 Menu Example 視圖
擴(kuò)展 org.eclipse.views 創(chuàng)建“Menu Example”視圖,如下代碼清單 5 為創(chuàng)建視圖的 xml 代碼。
清單 5. 擴(kuò)展 org.eclipse.ui.views 創(chuàng)建視圖
<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>
創(chuàng)建 Commands
采用 Command 方式創(chuàng)建“Menu Example”主菜單(包含 AngryCommand 和 JokeCommand 兩個(gè)菜單項(xiàng)),并且基于這兩個(gè)菜單項(xiàng)創(chuàng)建了 Menu Example 視圖的下拉菜單和工具欄菜單,及其 TreeViewer 的上下文菜單。
如下代碼清單 6 為擴(kuò)展 org.eclipse.ui.commands 創(chuàng)建 Menu Example 命令和類別,并且包含兩個(gè)命令:Joke Command 和 Angry Command。
清單 6. 擴(kuò)展 org.eclipse.ui.commands 創(chuàng)建命令
<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>
關(guān)聯(lián) Commands 到主菜單
如下代碼清單 7 為擴(kuò)展 org.eclipse.ui.menus,并基于前面創(chuàng)建的 Comands,添加一個(gè)主菜單 Menu Example,并且包含 Joke Command 和 Angry Command 菜單項(xiàng)。
清單 7. 創(chuàng)建 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 的實(shí)現(xiàn)類
如下代碼清單 9 所示擴(kuò)展 org.eclipse.ui.handlers 為 Joke Command 和 Angry Command 創(chuàng)建事件處理類,其中 Joke Command 通過(guò) enabledWhen 屬性控制該菜單項(xiàng)是否啟用,當(dāng)我們同時(shí)選擇了兩個(gè)對(duì)象時(shí) Joke Command 處于啟用狀態(tài),否則為禁用。
清單 9. 擴(kuò)展 org.eclipse.ui.handlers 為 Commands 創(chuàng)建實(shí)現(xiàn)類
<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>
創(chuàng)建 Action 并關(guān)聯(lián)到 Eclipse 的 Search 主菜單
采用 Actions 方式在 Eclipse 的主菜單 Search 中添加創(chuàng)建菜單項(xiàng) SmileAction。擴(kuò)展 org.eclipse.ui.actionSets 在 Eclipse 的主菜單 Search 中添加一個(gè)菜單項(xiàng) Smile Action。如下代碼清單 10 所示創(chuàng)建該 action 并添加到 search 主菜單,只有當(dāng)我們選擇至少一個(gè)對(duì)象時(shí)(設(shè)置 enablesFor 屬性為“+”),該菜單項(xiàng)才處于啟用狀態(tài)。
清單 10. 通過(guò) Actions 方式創(chuàng)建菜單項(xiàng)
<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 方式創(chuàng)建 Action 并關(guān)聯(lián)到 IResource 資源的上下文菜單
擴(kuò)展 org.eclipse.ui.popupMenus 創(chuàng)建菜單“Menu Example”,該菜單包含一個(gè)菜單項(xiàng) HelloAction。當(dāng)我們?cè)?Eclipse 任何區(qū)域右擊 org.eclipse.core.resources.IResource 資源時(shí)彈出的上下文菜單中會(huì)出現(xiàn)“Menu Example”菜單。如下代碼清單 11 為創(chuàng)建該上下文菜單的 xml 代碼。
清單 11. popupMenus 方式創(chuàng)建上下文菜單
<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 方式創(chuàng)建 Action 并關(guān)聯(lián)到 IResource 資源的上下文菜單
擴(kuò)展 org.eclipse.ui.popupMenus 創(chuàng)建菜單項(xiàng) GreetAction 和 CryAction,當(dāng)我們右擊 Menu Example 視圖中的 TreeViewer 節(jié)點(diǎn)時(shí)彈出。如下代碼清單 12 所示擴(kuò)展 org.eclipse.ui.popupMenus 為 Menu Example 視圖創(chuàng)建 GreetAction 和 CryAction 上下文菜單項(xiàng)。使用 visiblity 的 objectState 屬性控制菜單項(xiàng)的可見(jiàn)狀態(tài),使用該屬性要求其選擇的對(duì)象實(shí)現(xiàn)了 org.eclipse.ui.IActionFilter 接口,具體可參見(jiàn) Person 類的實(shí)現(xiàn)。
清單 12. 擴(kuò)展 org.eclipse.ui.popupMenus 創(chuàng)建菜單
<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 視圖的代碼實(shí)現(xiàn)類
如下代碼清單 13 所示為 Menu Example 視圖的代碼,該視圖中有一個(gè) TreeViewer,并通過(guò)函數(shù) hookContextMenu 把上下文菜單關(guān)聯(lián)到 TreeViewer。其中函數(shù) viewMenuAction 用于更新菜單的狀態(tài),它首先獲取視圖菜單,然后調(diào)用 IMenuManager 的 update 方法更新對(duì)應(yīng)菜單項(xiàng)的狀態(tài),從而達(dá)到控制菜單的目的。
清單 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 類的實(shí)現(xiàn)
如下代碼清單 14 為 Person 類的實(shí)現(xiàn),用于表示 MenuExample 視圖中 TreeViewer 的一個(gè)節(jié)點(diǎn),它實(shí)現(xiàn)了 IActionFilter 接口,通過(guò) testAttribute 來(lái)確定是否顯示 / 隱藏菜單(其中 target 表示用戶選擇的對(duì)象,name/value 對(duì)應(yīng)于 plugin.xml 文件中 objectState 的 name/value).
清單 14. Person 類實(shí)現(xiàn)
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;
}
}
總結(jié)
至此為止,已經(jīng)把 Eclipse 菜單功能及其擴(kuò)展點(diǎn)涉及到的類 / 接口 /API 進(jìn)行了詳細(xì)的說(shuō)明,相信讀者已經(jīng)有清晰的認(rèn)識(shí)了。對(duì)于前面提到 popupMenus 方式創(chuàng)建上下文菜單,要求選擇的對(duì)象實(shí)現(xiàn) IActionFilter 接口,但是,如果開(kāi)發(fā)人員正在使用 gmf 進(jìn)行開(kāi)發(fā),那么我們可以不必要求選擇的對(duì)象實(shí)現(xiàn) IActionFilter,我們可以通過(guò)擴(kuò)展 org.eclipse.gmf.runtime.common.ui.services.action.actionFilterProviders 對(duì)菜單項(xiàng)進(jìn)行控制,如下代碼清單 15 為擴(kuò)展該 extension point 的 xml 代碼,我們可以定義多個(gè)屬性(<Attribute> … </Attribute),其中 Attribute 的 name 和 value 對(duì)應(yīng)于 visibility 的 objectState 中的 name 和 value。
清單 15. 通過(guò) actionFilterProviders 擴(kuò)展點(diǎn)實(shí)現(xiàn)對(duì)菜單的控制
<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 的實(shí)現(xiàn),它繼承 AbstractActionFilterProvider,只需要實(shí)現(xiàn)其中的 testAttribute 和 provides 方法,當(dāng) testAttribute 返回 true 時(shí),那么該菜單項(xiàng)被啟用,否則禁用。其中 target 對(duì)應(yīng)于我們選擇的對(duì)象,name 和 value 參數(shù)對(duì)應(yīng)于 visiblity 中 objectState 的 name 和 value 的指定值 ( 與前面提到的 Person 類中的 testAttribute 方法類似 )。
清單 16. actionFilterProviders 擴(kuò)展點(diǎn)實(shí)現(xiàn)類
public class PopupActionFilterProvider extends AbstractActionFilterProvider {
public PopupActionFilterProvider() {
}
public boolean testAttribute(Object target, String name, String value) {
}
public boolean provides(IOperation operation) {
return false;
}
}