RCP UNDO和Redo
来源:互联网 发布:低价位耳机推荐知乎 编辑:程序博客网 时间:2024/05/01 09:35
RCP中undo/redo的实现
研究了一个多星期终于算是比较清楚了,现在写下来当作笔记。关于这些东西资料并不是很多,主要就是靠源代码和eclipse自带的帮助了,论坛方面我觉得也就是eclipse的新闻组和EZ比较有用,当然还有水木的eclipse版,有很多大牛,比如cloudor和surfeit,总是很热心地解决大家的问题。
首先要了解RetargetAction的概念,这个说起来很简单,就是一些常用action的抽象,比如copy/paste、delete以及本文的主题undo/redo,platform认为这是各个part的常用功能,如果每个part都创建自己的action是比较浪费资源的,所以就弄出了RetargetAction这个概念,它们从UI角度看只创建一遍,没有具体的功能;每个part可以提供自己的handler注册到这些RetargetAction上,这样当不同的part处于活动状态时就能够通过相同的菜单/按钮提供不同的功能。具体的类有两个,org.eclipse.ui.actions.RetargetAction
和它的子类org.eclipse.ui.actions.LabelRetargetAction
,主要用的是后者,因为可以动态的改变action的标签。undo/redo都有自己对应的现成的RetargetAction,就是用org.eclipse.ui.actions.ActionFactory
的静态工厂方法生成,还附赠图标。
至于undo/redo所对应的handler就比较简单了,调用一次就undo/redo一次,但一些细节却困扰了我好一阵子,就是二者之间的状态转化:初始化的时候二者都应该是disabled的,然后有了undoable操作之后undo应该就要被enable了,而一旦有了undo操作之后redo也应该相应的被enable,同时当不可undo/redo的时候,而这又应该相应的被disable掉。这是一种简单的线性关系,还没有考虑到undo操作的作用域。当时我一直想不通的就是undo/redo之间状态互动应该如何实现,比如第一次undo之后如何刷新redo的状态?如果二者之间互相持有对方的引用未免使得耦合度太高了,显然应该有一个“中央控制机构”的存在。在翻遍互联网之后我终于在一个角落里找到了答案:eclipse已经为undo操作专门实现了org.eclipse.ui.operations
这整整一个包的类,里面的UndoActionHandler
就是现成的handler...神奇之处在于它们的父类有boolean shouldBeEnabled()
这么一个抽象方法,简单用一句话就能实现状态的转化。不过我还没有搞清楚这是怎么一个调用层次,后面的机制太复杂了。
有了这些东西之后我们的工作只剩下生成undoable操作了,这些在帮助里写得很直白,也是我唯一看了一遍就理解了的部分- -0每当出现有产生undo需要的操作时,就在editor里面实现一个org.eclipse.core.commands.operations.AbstractOperation
的匿名子类,其中execute
方法直接把原来的操作搬进来就是了,要注意把相应的块级变量声明成final;undo就是逆操作了,这涉及到程序的具体逻辑,要仔细考虑;而redo则是undo的匿操作,我是直接return execute( monitor, info );
了。
有了undoable操作之后就可以用IOperationHistory执行它了,后面的入栈操作以及状态转化都会自动搞定。这里需要注意的是之前要给操作tag一个context:所谓的context其实只是一个标签,帮助里面花了很大篇幅解释为什么要搞出这么一个玩意儿,其实也就是一句话:有些操作要求全局可逆,而另外一些则是每个part私有的,所以需要有一个context来标记作用范围。这个也是跟具体逻辑有关的,比如我搞得东西就需要操作只限于在各个editor内可逆,所以就要为每个editor搞一个自己的ObjectUndoContext
。
说到这里好像已经万事俱备了,UI上面放RetargetAction,通过相应的handler调用我们自己搞出来的undoable operation,不过最后的问题是:这些代码都要放在哪里。 我觉得这也是插件开发里面一个比较棘手的问题,很多类都是互相持有引用,但由于调用栈的关系会有问题,比如在我的程序里,我想让undo/redo成为editor自己的按钮,也就是说要放在EditorActionBarContributor
里面,而在它被初始化时page成员的activeEditorReference和actionPartReference都是空的,花了一大把时间研究源码和调用栈之后我放弃了在contributor里面注册action的想法;看起来为时过早。但是不注册的话就无法使用快捷键;一个程序的undo操作如果不和Ctrl+Z绑定的话是很不方便的,起码多我来说是这样。这些常用的快捷键在org.eclipse.ui
的插件描述中已经预置了,只要key binding用的是org.eclipse.ui.defaultAcceleratorConfiguration这个scheme,并且action是工厂造出来的(设置了对应的command id),那么只需注册他们,绑定工作就完成了。到底这些contribute-by-editor的action该怎么注册?痛苦了数日之后我终于发现只要在ActionBarAdvisor
里面生成action并注册就可以了,虽然他们和添加到UI上的action并不是相同的对象,具体的原理我还没搞清楚,不过从WorkbenchWindow
类的源码里面看来注册action显然不仅仅用到了id。至于handler,我也放在了editor里面生成,虽然这样好像会有很多重复,但是没办法:contributor那时候好像site这个参数也还拿不到= =
- RCP UNDO和Redo
- Undo和Redo机制
- redo和undo
- oracle redo 和undo
- redo 和 undo 之一
- ORACLE UNDO和REDO
- redo和undo
- 关于Undo和Redo
- Redo和Undo
- redo 和 undo
- redo和undo
- redo和undo 详解
- redo 和 undo log
- oracle 的redo和undo
- oracle 的redo和undo
- redo 和 undo 之二
- redo 和 undo 之三
- redo 和 undo 之四
- 用汇编的眼光看C++(之算术符重载陷阱)
- retargetAction
- 【原】php自动生成带图片附件的word文档类
- 同步/异步与阻塞/非阻塞的区别
- assert用法总结
- RCP UNDO和Redo
- 数据库的一些用法2
- 上下文敏感帮助
- 【原】解决 ie6下select 控件的selected属性无效
- 程序员面试题精选100题(21)-左旋转字符串
- 大型RCP项目降低插件依赖度
- 【整理】mysql一些特殊情况的处理
- “拒绝使用开源技术的10大理由”
- 如果能不分别,就一直在一起吧