目标:使HelloWorld label可以在XYLayout布局中自由移动和改变大小
控制器逻辑:
模型发生改变(HelloWorld改变尺寸或位置)
--->产生请求(Request)
与GEF应用程序有关的事件,比如鼠标事件mouseUp,最终会被派发到EditDomain类去处理。EditDomain类使用active tool将低级事件(low-level events)转化为高级操作(higher-level operations),这些高级操作由org.eclipse.gef.Request来封装。PS:tool实现org.eclipse.gef.Tool接口,EditDomain类拥有一个active tool和一个default tool的引用,active tool默认为default tool,而default tool默认为selection tool。
--->请求发送给相应的EditPart
EditPart接口定义了getCommand方法,该方法负责创建一个Command来执行指定Request。但实际上创建Command的任务是委托(delegate)给EditPolicies的,EditPart不直接处理这个任务。
--->EditPart委托EditPolicies创建Command
查看AbstractEditPart的getCommand方法的实现可知,EditPart将创建Command的任务委托给了EditPolicies,即遍历所有已安装的EditPolicies,调用每个EditPolicy的getCommand方法(可能返回null,表示无对应操作),并把返回的Command组装起来(如果有多个Command就使用CompoundCommand)。
--->执行Command实现请求
一般经由EditDomain通过取得CommandStack实例并调用其execute(Command)方法实现。CommandStack实现了redo/undo,核心算法就是同时维护了两个栈redoable和undoable。execute(Command)方法清空redoable栈,调用参数command的execute方法执行命令,最后把command压入undoable栈。undo()方法就是执行undoable栈弹出的command的undo()方法,并将该command压入redoable栈。redo()与undo()正好相反,它执行redoable栈弹出的command的redo()方法,并将该command压入undoable栈。
步骤:
1. 创建edit policy
创建一个CustomXYLayoutEditPolicy,继承org.eclipse.gef.editpolicies.XYLayoutEditPolicy。
2. 安装edit policy到EditPart
在ContentsEditPart的createEditPolicies()方法中添加
installEditPolicy(EditPolicy.LAYOUT_ROLE, new CustomXYLayoutEditPolicy());
EditPolicy.LAYOUT_ROLE是一个字符串常量,它指定了安装的edit policy的角色(Role)。一个EditPart可以安装很多edit policies,如果角色相同,那么就只有最后一个policy是有效的。理论上来说,角色可以是任何值,用EditPolicy的常量只是为了统一,清楚。
3. 创建Command
创建ChangeConstraintCommand用来处理改变约束条件(大小、位置)的请求。
public void execute() {
helloModel.setConstraint(constraint);
}
4. 修改Edit Policy
接下来要做的是让我们创建的EditPolicy遇到改变约束条件的请求时,能正确的生成ChangeConstraintCommand去处理请求。
当我们移动HelloWorld label或改变它的大小时,会产生请求REQ_MOVE_CHILDREN或REQ_RESIZE_CHILDREN。对于这两种请求,XYLayoutEditPolicy的getCommand()方法最终都是调用createChangeConstraintCommand()创建Command。所以我们只要在CustomXYLayoutEditPolicy中重载createChangeConstraintCommand()方法,让它返回ChangeConstraintCommand即可。
5. 在模型中设置监听器
以上4步实现了控制器部分的逻辑,但是还没有完成所有的工作,因为模型虽然改变了,但是视图并不知道,所以要通知EditPart模型已经改变,再由EditPart改变视图。5、6两步就是为了实现监听机制。
我们要把模型定义为事件源,使用java.beans.PropertyChangeSupport类就可以完成这个任务。
为了把事件机制与模型剥离,我们需要创建一个基类AbstractModel来处理与监听有关的代码。
6. 在EditPart中注册监听器
EditPart需要在activate()方法中把自己注册为模型的监听器,在deactivate()方法中删除。同时EditPart要实现PropertyChangeListener接口,处理所有propertyChangeEvent。
同样创建一个基类EditPartWithListener来处理注册与删除监听器的代码。
7. Redo/Undo
让Command保存操作前的状态,undo时恢复原状态即可,而redo其实就是重新执行execute。
8. 增加Undo/Redo工具按钮
照做,最后要改ApplicationWorkbenchWindowAdvisor类的preWindowOpen()方法,configurer.setShowCoolBar(true),否则工具栏不显示。