EclipseAction深入学习笔记

 文章转自: http://macrochen.javaeye.com/blog/143441

以前做插件用到的ActionSet都只是依葫芦画瓢,没有真正理解它,现在开始好好学习学习,主要是看"Building Commercial-Quality Plug-ins"写的

Action的组成包括几个部分,一个是在plugin.xml中的声明,一个是在 Eclipse UI中会用到的IAction实例化对象, 另一个是封装在IActionDelegate中的action执行代码. action的实例化是基于plugin.xml配置文件和IActionDelegate定义的,Eclipse可以先在界面上将action显示出 来,直到用户点击了菜单或者工具条按钮才会去真正的加载插件,这也就是所谓的Eclipse的延迟加载机制

IActionDelegate有几个子类需要说明一下:
IActionDelegate2 如果实现IActionDelegate需要一些其他的信息,而这些信息在IActionDelegate销毁时需要同时被销毁时, 它可以提供相关是生命周期事件方法来处理
IEditorActionDelegate 是跟editor相关的
IObjectActionDelegate 是跟上下文菜单相关的
IViewActionDelegate 是跟view相关的
IWorkbenchWindowActionDelegate是跟menubar和toolbar相关的

Actions和Eclipse中的其他东东一样,也是通过扩展点org.eclipse.ui.actionSets来添加到Eclipse IDE的各个地方,actions的外在表现形式主要有menubar, toolbar, context menu这样几种

在actionSets的下级节点是actionSet, 它有几个属性,id,label都不用说了,还有一个visible属性,表示在打开Eclipse时是否显示该action,通常我们可以通过 Window > Customize Perspective...来设置action是否可见

在actionSet下可以添加menu节点, 它的id,label属性不用说了,其中的path是用来指定菜单的显示位置的,一般设置为additions

action并不是直接添加到menu上的, 而是跟menu内部的group关联的,所以我们必须先在menu下创建group,即新建groupMarker, 其name必须保证在当前menu下唯一, menu还有一种叫separator的group, 在separator group处添加的menu item会在这个组中的第一个菜单项上面添加一条水平线.而groupMarker则不会有线, 当其他action要添加到该menu group下时,使用水平线进行分组就显得非常必要

group只是用来标识menu的位置,即指这个位置可以添加菜单项, 而不是实际的menu item, 实际的menu item是action

因为menu会有层次关系,所以actionSet中专门用一个menu节点来表现这种层次关系, 而toolbar则没有这种情况,所以这里没有提供toolbar节点

在actionSet下添加action就是最终我们要toolbar上显示的按钮和 menubar上的menu item, 这里有几个属性, id和label不用说了,menuBarPath是menu要显示的位置, 比如"com.qualityeclipse.favorites.workbenchMenu/content",这个值就是actionSet+ "/"+group name, toolbarPath 就是toolbar item的显示位置, 比如"Normal/additions", 还有几个属性不常用到,但是有必要解释一下

allowLabelUpdate这个要在retarget属性为true的时候有效,还不是很清楚

class 是menu或button要执行的动作, 如果使用的是pulldown风格的action,还需要实现IWorkbenchWindowPulldownDelegate接口,它的构造函数是无 参数的,如果要传递参数,还需要是要实现IExecutableExtension 接口, 这个接口还不是很清楚

definitionId 这个是用来指定action对应的command唯一标识符的

enablesFor 是一个表达式,用来表示当前action是否可用

retarget 不是很理解

state主要是针对style属性为radio和toggle的,表示当前action是否被选中

style:默认是push,还有radio,表示一组menu中只能有一个被选中, toggle当它是checkbox好了, pulldown说明是子菜单项或者是下拉toolbar menu

对于action所使用的图标,我们可以从Eclipse下的plugins/org.eclipse.ui_3.1.2.jar 和 plugins/org.eclipse.jdt.ui_3.1.2.jar得到一些gif的图片

Eclipse中actionSet以及下级元素都是有id的,而且他们可以通过一种 path的方式来进行指定,比如com.qualityeclipse.favorites.workbenchMenu/content,如果上一级节 点是workbench menu bar或者是view content menu的话,那么它的上一级节点是不用指定的,只要指定group就好

为了方便其他的插件的action能添加到该插件的actionSet下, 在为插件定义group的时候, 会添加一个为additions的group, additions是eclipse使用的一个默认标识符,用来表示其他action或menu显示的位置, 在class中它的对应常量是IWorkbenchActionConstants.MB_ADDITIONS, 比如我们定义了一个menu,指定其path为additions, 这表示我们的menu将添加到window的左边,因为这个就是workbench menubar的additons所在的位置, 如果指定的是window/additions, 那么将作为子菜单项添加到window下

当一个actionSet下定义的action跟另一个actionSet下定义的 menu关联的时候将发生Invalid Menu Extension (Path is invalid): some.action.id的异常, 为了避免这种问题,menu需要在两个actionSet都定义

toolbarPath的指定也跟menuBarPath有同样的情况, 比如定义为Normal/additions, 这里的Normal指的是workbench toolbar, additions就是action要显示的group位置

action的class属性是封装了执行动作的类,它实现了 IWorkbenchWindowActionDelegate, 在它里面有几个方法需要介绍一下, 一个是selectionChanged, 用来动态修改action的state状态值, 是否可用,以及action的text属性等, 比如对于enableFor属性来说, 它根据选中对象的数量来判断action是否可用, 但是通过selectionChanged可以通过当前选定的对象的情况来调用setEnable()方法从而更精确的控制action是否可用, 有时候当插件还没有加载,在调用action的run方法时会加载插件,这时可能在调用run()方法之前没有调用selectedChange方法, 因此在run()方面里面需要写一些防护性代码,比如空值的判断之类的, 另外run()是在主UI线程中执行的,因此,如果该执行耗时较长,需要将其放到后台线程中执行.

插件运行之后在menubar和toolbar上看到定义的actionSet,可以试试下面的方法:
在Window > Customize Perspective... 下看看是不是actionSet没有选中
使用Window > Reset Perspective刷新当前视图
关闭重新打开当前视图
如果还没有出来,可以在在run或者debug的设置中将"Clear workspace data before launching "选中, 然后再启动运行

虽然通过扩展点可以非常方便的在Eclipse上添加,但是这个玩意儿多了也不是什么好 事, 可能会降低用户体验,因此需要进行控制, actionSet扩展点也有相关的设置来指定是否可见, 而且还可以调用IActionSetDescriptor.setInitiallyVisible() 来控制顶层菜单是否可见, 另一种解决办法就是在首选项中提供一个checkbox让用户决定是否显示顶层菜单,其编程实现就是在代码中调用 IActionSetDescriptor.setInitiallyVisible()和IWorkbenchPage.hideActionSet ()来进行控制

Object Action
这种Action是跟弹出的上下文菜单相关的, 因此它主要用在org.eclipse.ui.popupMenus扩展点下的objectContribution 节点中, 这里有几个属性需要做一下说明:
adaptable:true表示能将选中对象适配为objectClass中指定的类型
nameFilter:这个是用来指定哪种文件类型为当前contribution可用, 比如设置为*.java表示当前action只针对java文件
objectClass:指定contribution只用于那种对象类型
contribution的其他属性跟前面介绍的大同小异

对contribition过滤和可用性的控制
只有当前选中的文件类型是nameFilter指定的类型, 或者选中的对象是objectClass指定的类型,contribution才会在右键菜单中出现,而是否可用则要通过判断选中的对象是否和 enablesFor属性中表达式规定的数量, 表达式的定义包括:!表示选中0个, ?表示0个或1个, +表示1个或多个, multiple, 2+两个或多个, n表示具体个数, *表示任意个

objectContribution还提供visibility节点来控制 contribution可见性, 它比通过nameFilter 和objectClass控制功能更强, 比如要达到和objectClass="org.eclipse.core.resources.IResource"同样的效果可以这样写:

xml 代码
  1. <objectContribution ...   
  2.   <visibility>  
  3.       <objectClass  
  4.          name="org.eclipse.core.resources.IResource"/>  
  5.   visibility>  
  6.    ...the other stuff here...   
  7. objectContribution>  

如果当前contribution只用于可写的对象,可以这样写:

xml 代码
  1. <objectContribution ...>  
  2.    <visibility>  
  3.       <and>  
  4.          <objectClass  
  5.             name="org.eclipse.core.resources.IResource"/>  
  6.          <objectState name="readOnly" value="false"/>  
  7.       and>  
  8.     visibility>  
  9.    ... the other stuff here ...   
  10. objectContribution>  

visibility包括了not, and和or逻辑表达式节点以及adapt等Boolean表达式节点, adapt节点会先将选中对象适配为指定类型然后给其下级节点使用,比如这里:

xml 代码
  1. <adapt type="org.eclipse.core.resources.IResource">  
  2.    <objectState name="readOnly" value="false"/>  
  3. adapt>  


首先适配成IResource,然后判断其状态,该节点通常和and操作符结合使用, 如果适配器或者引用的类型没有加载,那么将返回EvaluationResult.NOT_LOADED, 如果指定的类型不存在,将抛出ExpressionException 异常
and节点只有下级子节点表达式都返回true才为true
instanceof节点 只有选中的对象是指定的名称时才为true, 和objectClass不同之处在于,它还可以与其他的元素通过and和or元素一起使用
not节点只有在下级节点返回false才为true
objectClass看上面的例子就知道了
objectState 比较选中的对象的状态是否指定的值
or节点只要下级节点中有一个为true就返回为true
pluginState节点对指定的插件的状态进行检测, 这里的状态有两种:installed或者actived, 比如这样写:

xml 代码
  1. <pluginState id="org.eclipse.pde" value="installed"/>   


表示只有org.eclipse.pde插件安装才可见
systemProperty 举个例子就知道怎么用了

xml 代码
  1. <systemProperty name="user.language" value="en"/>  


systemTest 跟systemProperty大同小异,只不过它可以通过and和or与其他的节点联合使用
test节点举个例子来说吧:

xml 代码
  1. <test  
  2.     property="org.eclipse.debug.ui.projectNature"  
  3.     value="org.eclipse.jdt.core.javanature"/>  


表示只有选中的是java项目下的对象当前contribution才可见, 如果进行比较的property没有加载,将返回EvaluationResult.NOT_LOADED, 这里指定的进行比较的属性能通过使用org.eclipse.core.expressions.propertyTesters进行扩展,具体的实现可 参考org.eclipse.debug.internal.ui.ResourceExtender类

filter元素是用来指定当前的contribution是否可用, 它的用法跟visibility中的objectState类似, 比如只有选择的对象为只写才可用, 那么可以这样写:

xml 代码
  1. <objectContribution ...>  
  2.    <filter name="readOnly" value="false"/>  
  3.    ... the other stuff here ...   
  4. objectContribution>  

和objectState 一样,filter使用的进行测试的对象必须实现IActionFilter接口或者能适配为IActionFilter, 然后调用testAttribute()方法来跟指定的name/value进行比对, 对于Resource来说, 它提供了下列属性让我们来进行比对
name,表示对文件名进行比对, 可使用*这种正则表达式
extension表示后缀名比对
path路径比对, 可使用*
readOnly只读比对
projectNature 对nature比对
persistentProperty 对选择的资源的持久属性进行比对, 如果他的值只是一个字符串,那么就对该资源已有的属性值拿出来进行比对, 如果是propertyName=propertyValue这种形式,那么先根据name从选择的对象中取出值,然后再跟指定的value进行比对
projectPersistentProperty 对选中对象所在工程的持久性属性进行比对
sessionProperty 对对象中对的session属性进行比对
projectSessionProperty 选中对象所在工程的session属性进行比对

selection 元素主要针对contribution中某个action是否可见来进行判断,比如说下面这样写:

xml 代码
  1. <objectContribution  
  2.       objectClass="java.lang.Object"  
  3.       id="com.qualityeclipse.favorites.popupMenu">  
  4.    <action  
  5.          label="Add to Favorites"  
  6.          tooltip="Add the selected resource(s) to the   
  7.                   Favorites view"   
  8.          class="com.qualityeclipse.favorites.actions.   
  9.                 AddToFavoritesActionDelegate"   
  10.          menubarPath="additions"  
  11.          enablesFor="+"  
  12.          id="com.qualityeclipse.favorites.addToFavorites">  
  13.       <selection  
  14.             class="org.eclipse.core.resources.IResource"  
  15.             name="*.java"/>  
  16.    action>  
  17. objectContribution>  

这里的意思是com.qualityeclipse.favorites.popupMenu下的action在任何情况下都是可见的,只有Add to Favorites只有在选中的对象实现了IResource接口且文件名后缀为java才可见

enablement元素 也是针对单个action的, 它集selection和visibility两个元素的强大于一身,举个例子就明白了:

 

xml 代码

 

  1. <objectContribution  
  2.       objectClass="java.lang.Object"  
  3.       id="com.qualityeclipse.favorites.popupMenu">  
  4.    <action  
  5.          label="Add to Favorites"  
  6.          tooltip="Add the selected resource(s)   
  7.                   to the Favorites view"   
  8.          class="com.qualityeclipse.favorites.actions.   
  9.                 AddToFavoritesActionDelegate"   
  10.          menubarPath="additions"  
  11.          enablesFor="+"  
  12.          id="com.qualityeclipse.favorites.addToFavorites">  
  13.       <enablement>  
  14.          <and>  
  15.             <objectClass  
  16.                name="org.eclipse.core.resources.IResource"/>  
  17.              <objectState name="name" value="*.java"/>  
  18.          and>  
  19.       enablement>  
  20.    action>  
  21. objectContribution>  

根据文件内容关联contribution
比如一般我们的Run Ant...菜单项是跟build.xml文件关联的, 如果要跟export.xml也关联, 那么我们就需要通过对xml的DTD声明进行判断是否可以关联, 为了处理这种情况org.eclipse.ant.core 定义了一种叫antBuildFile 的content type:

xml 代码
  1. <extension point="org.eclipse.core.runtime.contentTypes">  
  2.    <content-type  
  3.       id="antBuildFile"  
  4.       name="%antBuildFileContentType.name"  
  5.       base-type="org.eclipse.core.runtime.xml"  
  6.       file-names="build.xml"  
  7.       file-extensions="macrodef,ent,xml"  
  8.       priority="normal">  
  9.       <describer  
  10.          class="org.eclipse.ant.internal.core.   
  11.             contentDescriber.AntBuildfileContentDescriber">  
  12.       describer>  
  13.    content-type>  
  14. extension>  

在AntBuildfileContentDescriber 类中将判断xml文件是否是ant内容, 接下来我们就可以通过使用antBuildFile来指定contibution是否可用.
如果想了解如何自定义内容类型,可以参考:
eclipse.org > projects > The Eclipse Project > Platform > UI > Development Resources > Content Sensitive Object Contributions或者dev.eclipse.org/viewcvs/index.cgi/~checkout~/platform-ui- home/object-aware-contributions/objCont.htm
Help > Help Contents > Platform Plug-in Developer Guide > Programmer's Guide > Runtime overview > Content types
"A central content type catalog for Eclipse" at dev.eclipse.org/viewcvs/index.cgi/platform-core-home/documents/content_types.html?rev=1.11
"Content types in Eclipse" at eclipse.org/eclipse/platform-core/planning/3.0/plan_content_types.html

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
eclipse插件开发学习笔记源码是指记录学习eclipse插件开发过程中的笔记所对应的源代码。在学习eclipse插件开发时,我们通常会通过写笔记的方式记录自己的理解、遇到的问题以及对应的解决方案。而这些笔记所涉及的源码,就是指在实践过程中编写的相关代码。 在学习eclipse插件开发时,源码是非常重要的,因为它直接反映了我们对于插件开发知识的理解和实践能力。一般而言,我们的源码应该包含以下几个方面的内容。 首先,源码应该包括插件的基本结构和配置信息。这包括插件的manifest.mf文件和plugin.xml文件。manifest.mf文件用于定义插件的基本信息,包括插件的名称、版本号以及对其他插件的依赖关系等。而plugin.xml文件则用于定义插件的扩展点和扩展。 其次,源码应该包括对于eclipse平台核心概念的理解和应用。例如,我们可以编写代码来创建和管理视图、编辑器、菜单、工具栏等界面元素,以及定义和处理事件等。 另外,源码还应该包含对于第三方插件的使用和扩展。eclipse的插件生态系统非常丰富,我们可以通过使用第三方插件来快速实现一些功能。比如,我们可以使用JFace、SWT等第三方库来创建复杂的UI界面,使用EMF来定义和管理领域模型等。 总之,eclipse插件开发学习笔记的源码应该是一个不断积累和完善的过程。通过编写源码,我们可以更好地理解和掌握eclipse插件开发的知识和技术,提高自己的实践能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值