Eclipse RCP: Declarative Actions

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情
在做一个Eclipse RCP的项目,遇到个问题。
客户需要在一个Tree上实现popup menu,这其中的menu item根据右键点击的树节点不同而不同。用popup menu的extension很容易实现,只要加一个objectContribution就行了。根据不同的tree node类型,显示不同的action。
另一个需求很麻烦,menu item还需要根据用户所在的perspective不同而不同。objectContribution没有这么细致的声明项,似乎只有编程完成。
Popup menu actions可以实现两个接口,除了普通的声明式Action的IWorkbenchWindowActionDelegate之外,还有 IObjectActionDelegate。Addison Wesley的Eclipse RCP书中说,这个接口的setActivePart()方法在每次打开popup menu的时候都要调用,可以在这时候把不需要的Actions disable掉。试验了一下,不好使,怪?而且普通的IWorkbenchWindowActionDelegate的 selectionChanged()方法似乎也不好使。
经过对Eclipse UI源代码的挖掘,终于搞清楚了,感觉这几乎是Eclispe RCP的一个pitfall。
IActionDelegate(IWorkbenchWindowActionDelegate的父接口)的文档中说,“The workbench will generate a proxy action object on behalf of the plug-in to avoid having to activate the plug-in until the user needs it. If the action is performed the workbench will load the class that implements this interface and create what is called an action delegate object.”这话说得似乎很有道理,然而其中一个side-effect就是写在Delegate的回调方法不能轻易被调用。先要弄清楚什么是 proxy action,什么是delegate object。Proxy action是用户实际在UI中看见的传统JFace Action。比如一个menu item和toolbar上的一个按钮。Delegate Object是我们写的IActionDelegate的,实际给Declarative Action的实现。问题在这里:无论是setActivePart(),还是selectionChanged(),都是我们写在delegate object里的,而action不perform,这个object就不会被创建,当然我们的方法就不会被执行了。
看看源代码:
org.eclipse.ui.internal.PluginAction#runWithEvent():
 
if (delegate == null{
  createDelegate();
  
// ...
}

delegate.run(
this);
 
大多数情况下是这个方法调用我们写的action delegate的。很明显,直到不得不用上我们的action delegate,框架才会去生成它。
 
然后看看IObjectActionDelegate的setActivePart(),当右键菜单将要弹出的时候,触发JFace的 MenuManager的menuAboutToShow事件,事件流到 org.eclipse.ui.internal.ObjectActionContributor#contributeObjectActions(), 这是我们关心的部分。这里先判断目前的选择(右键菜单的上下文)是否适合于objectContribution中声明的Object类型,将不适合的 action隐藏,然后尝试调用setActivePart():
if (ad.getAction() instanceof ObjectPluginAction) {
  
final ObjectPluginAction action = (ObjectPluginAction) ad.getAction();
  ISafeRunnable runnable 
= new ISafeRunnable() {
  
// ...
    public void run() throws Exception {
      action.setActivePart(part);
      action.selectionChanged(selection);
    }

  }
;
  SafeRunner.run(runnable);
}
这里头action的实际类型是org.eclipse.ui.internal.ObjectPluginAction。它的setActivePart()方法里有:
if (actionDelegate instanceof IObjectActionDelegate && activePart != null) {
  final IObjectActionDelegate objectActionDelegate 
= (IObjectActionDelegate) actionDelegate;
  final ISafeRunnable runnable 
= new ISafeRunnable() {
    
public void run() throws Exception {
      objectActionDelegate.setActivePart(ObjectPluginAction.this, activePart);
    }
  
// ...
}
成员actionDelegate就是我们写的代理action类。明显,若它是空,里面的内容,即对我们写的setActivePart()方法的调用就不能进行了,而这就是我们未触发这个action之前它的状态。
 
最后再看看IActionDelegate的selectionChanged()的情况。这个回调函数可以响应view内的 SelectionProvider提供的选择信息,只有当menu item是viewContributor的时候,回调函数才起作用,正常情况下,对view内的选择事件,回调函数都会被调用。
(在上面关于setActivePart()的讨论中,selectionChanged()也被调用了,但这个不算,只有右键菜单弹出的时候,selectionChanged()才会被调用,而我们要它对每次的选择,无论鼠标左键右键,都会有响应。)
首先要在当前的IWorkbrenchPageSite上注册SelectionProvider,以让我们的Provider的选择事件能影 响到我们的Action。一般常见的SelectionProvider就是JFace中的各种Viewer,在ViewPart的实现中调用:
getSite().setSelectionProvider(treeViewer);
这样我们的View就可以响应treeViewer的selection事件了。
事件从Viewer中发出,会一路走到org.eclipse.ui.internal.PluginAction(刚才的ObjectPluginAction是它的一个子类),在它的方法selectionChanged()中我们看到:
if (delegate == null && isOkToCreateDelegate()) {
  createDelegate();
}
 else {
  refreshEnablement();
}

似乎若我们的代理还没创建,它会帮我们创建出来,可是且慢,方法isOkToCreateDelegate()中写道:
if (getStyle() == IAction.AS_DROP_DOWN_MENU && !WWinPluginPulldown.class.isInstance(this)) {
  
return true;
}

// test if the plugin has loaded
String bundleId = configElement.getNamespace();
return BundleUtility.isActive(bundleId);
即,若我们的Action是drop down menu item,那么会被创建,或者Action所属的插件已经加载,那么会被创建。
对于缺省的Action,这些判断不会通过。所以我们的Action仍旧没有创建。而在refreshEnablement()中,有:
if (delegate != null{
  delegate.selectionChanged(
this, selection);
}

空的delegate被悲惨的忽略了。
 
总之,对于RCP中声明的Action,要小心,我们写的回调函数并不是总能被调用的。在Action真正的被激活之前,我们的代理类(大多数情况下)并不会被主动的创建。
这个问题的解决方法实际已经有了,只要让isOkToCreateDelegate()返回true就可以让代理类被主动创建,经试验,只要声 明时将Action的Style设置成pulldown即可。这样,只要右键菜单一弹出,或者selection事件一发送,代理类就会被创建,回调总能 被调用。

Perspective?

出于对声 明式编程的偏爱,我更喜欢declarative actions。但对于客户的需求,显然用declarative actions并不合适,我们需要在每一个action的回调中判断当前的perspective,然后决定是否让它可用,这是很麻烦的编程,遵从DRY 原则,我们应该对actions直接编程。
为什么会这样?对Eclipse的偏袒让我认为这是客户需求上的问题。Eclipse的declarative actions本身是自洽的系统。一个action是否可用应该只针对它当前最小的上下文,在我们的项目里就是被选择的树节点的类型有关,而整个系统的状 态,比如当前处在哪个perspective中,不应该是action主要考虑的内容。
况且,perspective不应该作为划分任务的依据。Eclipse RCP中对于perspective的定义只是一个“屏幕页面的模板”,它记录一组缺省的view和他们的布局情况,作为方便用户的一种选择。它甚至不在 Eclipse RCP的UI组件的继承结构之内,而只是集合UI组件的一个逻辑概念。真正执行功能的基础UI元件应该是View。在Eclipse中,我们随时可以看到 IDE提示我们切换perspective,但从来不会看到某一个action只能在这个perspective中使用而不能在另一个中使用。比如说启动 了Debug功能后IDE会告诉我们切换到Debug Perspective,但“这个Perspective中的”所有View和所有功能,我们一样可以在Java视图中用,在PD视图中用,在 Resources视图中用,等等。只是Debug Perspective为我们打开了一组缺省的View和保持了一组缺省的布局而已。
为了实现对用户功能的多样化,我们应该实现多种不同的View,在不同的View上实现不同的右键菜单,如果两个View功能很重复,也应该考虑使用模块化的UI组件,而不是根据Perspective来决定同一个View的不同表现。
Jenkins基础:Jenkinsfile使用实例:8:使用post进行失败处理 Jenkinsfile以stage为逻辑功能实现和划分的方式使用起来非常方便,而一旦发生异常之后应该如何处理,如何根据stage执行的结果而进行特定处理则是实际Pipeline使用中经常会碰到的问题。在Groovy或者Java语言中一般这就是try {} catch{}的使用场景,而Jenkinsfile也将执行结果的状态进行共通化,可以根据执行结果的特定状态作为触发的条件,这就是post{}。而流水线的实现则只需要在对应的状态中执行预定的处理逻辑即可,这篇文章中将通过具体的示例进行介绍和演示。 阅读详情

相关推荐

持续集成:Jenkinsfile使用方法介绍

在pipeline项目中,可以直接在jenkins的web UI上编写pipeline脚本,还有一种方法是使用Jenkinsfile,它放在源码管理库中,比如github、SVN等。为了使pipeline项目管理更加方便,推荐使用这种方式。本文将介绍pipeline项目如何使用Jenkinsfile。

测试开发小记 6874

IActionIActionDelegate PropertyTester

NULL 博文链接:https://redheart-2006.iteye.com/blog/621585

Jenkins来构建一个Pipeline项目

Jenkins 创建 Pipeline 任务

阿常呓语的专栏 1246

最详细的EclipseRcp教程

网络上能够找到的最详细的EclipseRcp教程

Jenkins高级篇之Pipeline技巧篇-5-pipeline中如何代码串联多个job的执行

这篇我来介绍下,pipeline代码中如何把两个JOB(A 和B)给串接起来。我们知道,在图形界面的jenkins中的自由风格的job的设置页眉,我们可以选择,执行完job A之后触发执行Job B, 那么pipeline又是如何实现这一过程呢。 环境准备 当前我的JobA 就是前面几篇文章一直介绍的那个ProjectA-pipeline-demo,为了演示这个过程,我基于Job A给复制了一...

Anthony_tester的博客 1万+

cicd 04--构建自动化发布流程

cicd 04--构建自动化发布流程1 简介2 构建过程2.1 功能说明2.2 jenkins & gitlab 配置2.3 测试结果3 注意事项4 说明 1 简介 在实际项目中,为了提高开发人员的服务发布效率,避免用户手动build镜像、通过脚本(或kubectl)更新服务,通常需要为重要的服务构建一套自动化发布流程。 简单来说,开发人员提交代码,MR 到 master 分支,触发 build 镜像操作,并自动推送到镜像仓库,然后更新到测试或者预发布环境,用户测试ok后通知sre团队,sre团队触

脚步不能达到的地方,眼光可以达到;眼光不能达到的地方,精神可以飞到 863

Jenkins 流水线语法 04 agent/post

agent 构建节点 参数: any: 运行在任一可用节点。 none:当pipeline全局指定agent为none,则根据每个stage中定义的agent运行(stage必须指定)。 label:在指定的标签的节点运行。(标签=分组) node:支持自定义流水线的工作目录。 ## 一 pipeline { agent any } ## 二 pipeline { agent { label "label Name" } } ## 三 自定义节点 pipeline {

小楼一夜听春雨,深巷明朝卖杏花 2463

Jenkins高级篇之Pipeline实践篇-8-Selenium和Jenkins持续集成-添加事后删除报告功能和解决报告名称硬编码

这篇,我们第一件事情来实现把html报告publish完成之后就删除报告文件。这个是很有必要的操作,虽然我们前面写死了报告名称为index.html,你跑多次测试,都会在test-output文件夹下覆盖原来的html报告文件。但是,就像我们最早的时候,报告名称是特定文字加时间戳命名,那么如果不删除,这个test-output下就有多个html文件。 1.代码优化,添加删除报告文件代码 我之前...

Anthony_tester的博客 1567

SCF场景下的DevOps实现--Jenkins篇

当前Serverless热度越来越高,越来越多的开发者们开始抛弃传统开发模式基于Serverless来搭建自己的产品服务。在享受腾讯云Serverless产品SCF的免运...

腾讯云 Serverless 359

devops实践 java_DEVOPS技术实践_20:串联多个job执行

Started by user darren ningObtained when.jenkinsfile from git http://192.168.132.132/root/pipeline-parameter-test.gitRunning inDurability level: MAX_SURVIVABILITY[Pipeline] Start of Pipeline[Pipeline]...

weixin_42462474的博客 902

Eclipse-RCP中文入门教程

详细介绍了Eclipse下开发rcp的方法步骤,并对其应用进行了详细介shoa

Scripted Pipeline 实现Declarative pipeline的类似post功能

众所周知Declarative pipeline中可以用post去实现pipeline为某个状态后执行某个动作,例如: pipeline { agent {node 'master'} stages { stage('build'){ steps { script { ...

liurizhou的博客 1608

Eclipse插件(RCP)开发环境搭建

Eclipse插件(RCP)开发在 Web 兴起以前非常热门,现已渐渐边缘化。因此许多小伙伴已不知道开发,甚至如何搭建环境。本文介绍了最新的RCP环境搭建过程。

小子宝丁的博客 4265

Eclipse插件开发中的Action

插入点用来定义菜单出现的位置。由于Eclipse由插件组成,而每个插件又都可以添加操作,这些插件直接可能不会彼此知道。为此,Eclipse仿照标示符的使用方法,使用“插入点”(insertion point)来指定菜单或操作将在工作台的什么位置出现。  Eclipse系统中定义了标准的插入标示符additions,用来将新创建的操作插入指定的位置,这个标示符作为常量定义在org.eclipse.

XiaoMaPro 3452

Eclipse遇到的问题的解决方案

如果是单个项目不显示,而不是所有的,则在eclipse里右键该项目->team->断开连接,然后再右键该项目->team->清理(或者直接断开连接时会有清理svn信息选择),然后删除项目(注意只是删除项目,而不勾选磁盘),然后再import导入就出现了。项目路径\.metadata\.plugins\org.jboss.ide.eclipse.as.core\JBoss_AS_4.01603712296328\deploy\ZiDongEar.ear。如果是jsp,则选择工程目录下的webapp;

梦夜君王 1188

Jenkins Declarative Pipeline 声明式流水线

文章目录[pipeline](https://jenkins.io/doc/book/pipeline/syntax/#pipeline)[agent](https://jenkins.io/doc/book/pipeline/syntax/#agent)[environment](https://jenkins.io/doc/book/pipeline/syntax/#environment)[...

锐意工作室 2537
上一篇: 对动态规划和贪心算法的一点理解
下一篇: IBM笔试体验
hanbf
博客等级 码龄22年 8粉丝 9原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值