要实现向编辑器增加活动,我们应该在面板上选一种活动(开始活动,普通活动,结束活动),拖到编辑器中。为此我们必须在面板和编辑器中分别加监听。修改WorkflowProcessEditor类
在编辑器的GraphicalViewer加监听
同时我们还必须给面板加监听,覆盖父类的createPaletteViewerProvider()方法:
光在这两个地方加监听,还不够,这里还要引出gef的重要概念:策略(Policy),用过Rose的人都知道,我们可以新建一个类图,移动它,删除它,这在流程设计器中也可以,只是新建活动,移动活动等操作,用户这些操作其实是对控制器的操作,比如用户用鼠标移动活动,其实这过程包括用户向控制器发出移动活动的请求(Request),控制器就调用相应的命令(Command)来修改模型中活动的位置属性,而模型的位置属性发生变化,又会通知控制器,控制器就会刷新视图,改变活动的位置,这样,我们就移动了活动,那么控制器是怎么根据请求的类型调用相应的命令的,这就是策略的作用,简单说,策略保存了请求类型和命令的映射关系,它知道什么样的请求要调用哪个命令。
明白策略的含义之后,就可以更好的理解我们下面的程序了。我们要向流程中增加一个活动,就要向流程控制器发出请求,因此,我们要在流程控制器中安装策略,由于我们在编辑器中采用绝对定位方式,因此安装XYLayoutEditPolicy策略,我们定义一个类WorkflowProcessXYLayoutEditPolicy继承它,
我们修改WorkflowProcessEditPart类的createEditPolicies方法:
其实这个策略不仅可以处理创建活动的请求,还可以处理改变活动位置和大小的请求。
接下来我们来看WorkflowProcessXYLayoutEditPolicy
package com.example.workflow.policy;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.editpolicies.XYLayoutEditPolicy;
import org.eclipse.gef.requests.CreateRequest;
publicclass WorkflowProcessXYLayoutEditPolicy extends XYLayoutEditPolicy {
protected Command createChangeConstraintCommand(EditPart arg0, Object arg1) {
// TODO Auto-generated method stub
returnnull;
}
protected Command getCreateCommand(CreateRequest arg0) {
// TODO Auto-generated method stub
returnnull;
}
}
如果我们发出在编辑器中新建活动的请求,流程根据安装的策略,就会调用这个类的getCreateCommand方法,为此我们要修改这个方法,如果我们发出改变活动大小和位置的请求,就会调用createChangeConstraintCommand方法。
为了修改流程模型,在流程模型中增加一个活动,我们用命令来实现这个功能,命令都具有撤销,重做功能,我们只需覆盖redo,undo方法就可以实现这功能。:
接下来,我们还要修改WorkflowProcessXYLayoutEditPolicy的getCreateCommand方法,如果在编辑器中请求创建的对象是开始活动,活动,结束活动的一种,都会调用刚才新建的命令。
为此我们在propertyChange应作如下修改:
以上程序的意思是,当往流程模型中增加活动或者从流程模型中删除活动时,刷新流程模型包含子元素对应的视图,而流程模型的子元素是活动模型,而活动模型控制器的refreshVisuals()我们也没有实现,因此我们也应该实现这个方法,定义如下:
在编辑器的GraphicalViewer加监听
protectedvoid initializeGraphicalViewer()
{
super.initializeGraphicalViewer();
GraphicalViewer viewer = getGraphicalViewer();
viewer.setContents(getModel()); // set the contents of this editor
// listen for dropped parts
viewer.addDropTargetListener(createTransferDropTargetListener());
}
private TransferDropTargetListener createTransferDropTargetListener() {
returnnew TemplateTransferDropTargetListener(getGraphicalViewer()) {
protected CreationFactory getFactory(Object template) {
returnnew SimpleFactory((Class) template);
}
};
}
super.initializeGraphicalViewer();
GraphicalViewer viewer = getGraphicalViewer();
viewer.setContents(getModel()); // set the contents of this editor
// listen for dropped parts
viewer.addDropTargetListener(createTransferDropTargetListener());
}
private TransferDropTargetListener createTransferDropTargetListener() {
returnnew TemplateTransferDropTargetListener(getGraphicalViewer()) {
protected CreationFactory getFactory(Object template) {
returnnew SimpleFactory((Class) template);
}
};
}
同时我们还必须给面板加监听,覆盖父类的createPaletteViewerProvider()方法:
protected
PaletteViewerProvider createPaletteViewerProvider()
{
returnnew PaletteViewerProvider(getEditDomain()) {
protectedvoid configurePaletteViewer(PaletteViewer viewer) {
super.configurePaletteViewer(viewer);
viewer.addDragSourceListener(new TemplateTransferDragSourceListener(viewer));
}
};
}
returnnew PaletteViewerProvider(getEditDomain()) {
protectedvoid configurePaletteViewer(PaletteViewer viewer) {
super.configurePaletteViewer(viewer);
viewer.addDragSourceListener(new TemplateTransferDragSourceListener(viewer));
}
};
}
光在这两个地方加监听,还不够,这里还要引出gef的重要概念:策略(Policy),用过Rose的人都知道,我们可以新建一个类图,移动它,删除它,这在流程设计器中也可以,只是新建活动,移动活动等操作,用户这些操作其实是对控制器的操作,比如用户用鼠标移动活动,其实这过程包括用户向控制器发出移动活动的请求(Request),控制器就调用相应的命令(Command)来修改模型中活动的位置属性,而模型的位置属性发生变化,又会通知控制器,控制器就会刷新视图,改变活动的位置,这样,我们就移动了活动,那么控制器是怎么根据请求的类型调用相应的命令的,这就是策略的作用,简单说,策略保存了请求类型和命令的映射关系,它知道什么样的请求要调用哪个命令。
明白策略的含义之后,就可以更好的理解我们下面的程序了。我们要向流程中增加一个活动,就要向流程控制器发出请求,因此,我们要在流程控制器中安装策略,由于我们在编辑器中采用绝对定位方式,因此安装XYLayoutEditPolicy策略,我们定义一个类WorkflowProcessXYLayoutEditPolicy继承它,
我们修改WorkflowProcessEditPart类的createEditPolicies方法:
protectedvoid createEditPolicies()
{
installEditPolicy(EditPolicy.LAYOUT_ROLE, new WorkflowProcessXYLayoutEditPolicy());
}
installEditPolicy(EditPolicy.LAYOUT_ROLE, new WorkflowProcessXYLayoutEditPolicy());
}
其实这个策略不仅可以处理创建活动的请求,还可以处理改变活动位置和大小的请求。
接下来我们来看WorkflowProcessXYLayoutEditPolicy
package com.example.workflow.policy;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.editpolicies.XYLayoutEditPolicy;
import org.eclipse.gef.requests.CreateRequest;
publicclass WorkflowProcessXYLayoutEditPolicy extends XYLayoutEditPolicy {
protected Command createChangeConstraintCommand(EditPart arg0, Object arg1) {
// TODO Auto-generated method stub
returnnull;
}
protected Command getCreateCommand(CreateRequest arg0) {
// TODO Auto-generated method stub
returnnull;
}
}
如果我们发出在编辑器中新建活动的请求,流程根据安装的策略,就会调用这个类的getCreateCommand方法,为此我们要修改这个方法,如果我们发出改变活动大小和位置的请求,就会调用createChangeConstraintCommand方法。
为了修改流程模型,在流程模型中增加一个活动,我们用命令来实现这个功能,命令都具有撤销,重做功能,我们只需覆盖redo,undo方法就可以实现这功能。:
package
com.example.workflow.commands;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.commands.Command;
import com.example.workflow.model.AbstractActivity;
import com.example.workflow.model.WorkflowProcess;
publicclass AbstractActivityCreateCommand extends Command {
private AbstractActivity newActivity;
privatefinal WorkflowProcess parent;
private Rectangle bounds;
public AbstractActivityCreateCommand(AbstractActivity newActivity, WorkflowProcess parent, Rectangle bounds) {
this.newActivity = newActivity;
this.parent = parent;
this.bounds = bounds;
setLabel("activity creation");
}
publicboolean canExecute() {
returnnewActivity != null && parent != null && bounds != null;
}
/**//* (non-Javadoc)
* @see org.eclipse.gef.commands.Command#execute()
*/
publicvoid execute() {
newActivity.setLocation(bounds.getLocation());
Dimension size = bounds.getSize();
if (size.width > 0 && size.height > 0)
newActivity.setSize(size);
redo();
}
/**//* 重做
*/
publicvoid redo() {
parent.addChild(newActivity);
}
/**//* 撤销
*/
publicvoid undo() {
parent.removeChild(newActivity);
}
}
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.commands.Command;
import com.example.workflow.model.AbstractActivity;
import com.example.workflow.model.WorkflowProcess;
publicclass AbstractActivityCreateCommand extends Command {
private AbstractActivity newActivity;
privatefinal WorkflowProcess parent;
private Rectangle bounds;
public AbstractActivityCreateCommand(AbstractActivity newActivity, WorkflowProcess parent, Rectangle bounds) {
this.newActivity = newActivity;
this.parent = parent;
this.bounds = bounds;
setLabel("activity creation");
}
publicboolean canExecute() {
returnnewActivity != null && parent != null && bounds != null;
}
/**//* (non-Javadoc)
* @see org.eclipse.gef.commands.Command#execute()
*/
publicvoid execute() {
newActivity.setLocation(bounds.getLocation());
Dimension size = bounds.getSize();
if (size.width > 0 && size.height > 0)
newActivity.setSize(size);
redo();
}
/**//* 重做
*/
publicvoid redo() {
parent.addChild(newActivity);
}
/**//* 撤销
*/
publicvoid undo() {
parent.removeChild(newActivity);
}
}
接下来,我们还要修改WorkflowProcessXYLayoutEditPolicy的getCreateCommand方法,如果在编辑器中请求创建的对象是开始活动,活动,结束活动的一种,都会调用刚才新建的命令。
protected
Command getCreateCommand(CreateRequest request)
{
Object childClass = request.getNewObjectType();
if (childClass == StartActivity.class
||childClass == Activity.class
||childClass == EndActivity.class) {
returnnew AbstractActivityCreateCommand((AbstractActivity)request.getNewObject(),
(WorkflowProcess)getHost().getModel(), (Rectangle)getConstraintFor(request));
}
return null;
}
Object childClass = request.getNewObjectType();
if (childClass == StartActivity.class
||childClass == Activity.class
||childClass == EndActivity.class) {
returnnew AbstractActivityCreateCommand((AbstractActivity)request.getNewObject(),
(WorkflowProcess)getHost().getModel(), (Rectangle)getConstraintFor(request));
}
return null;
}
这下,我运行这个项目,我们从面板选中一个活动,放在编辑器中,编辑器根本没有反映,其实是我们少写了一个地方,我们向编辑器放一个活动,向流程控制器发出在编辑器中增加活动的请求,流程编辑器根据安装的策略,调用相应的命令修改流程模型,在流程模型中增加活动模型,而此时流程模型发生了变化,控制器应该刷新流程模型对应的视图,而我们程序是没有写这段代码的,因此我们要修改WorkflowProcessEditPart的propertyChange方法,由于在WorkflowProcess模型中,当向模型中增加活动时通知控制器流程的CHILD_ADDED_PROP发生变化的,见如下代码:
public
boolean
addChild(AbstractActivity a)
{
if (a != null && activities.add(a)) {
firePropertyChange(CHILD_ADDED_PROP, null, a);
return true;
}
return false;
}
if (a != null && activities.add(a)) {
firePropertyChange(CHILD_ADDED_PROP, null, a);
return true;
}
return false;
}
为此我们在propertyChange应作如下修改:
public
void
propertyChange(PropertyChangeEvent evt)
{
String prop = evt.getPropertyName();
if (WorkflowProcess.CHILD_ADDED_PROP.equals(prop)
|| WorkflowProcess.CHILD_REMOVED_PROP.equals(prop)) {
refreshChildren();
}
}
String prop = evt.getPropertyName();
if (WorkflowProcess.CHILD_ADDED_PROP.equals(prop)
|| WorkflowProcess.CHILD_REMOVED_PROP.equals(prop)) {
refreshChildren();
}
}
以上程序的意思是,当往流程模型中增加活动或者从流程模型中删除活动时,刷新流程模型包含子元素对应的视图,而流程模型的子元素是活动模型,而活动模型控制器的refreshVisuals()我们也没有实现,因此我们也应该实现这个方法,定义如下:
private
AbstractActivity getCastedModel()
{
return (AbstractActivity) getModel();
}
protectedvoid refreshVisuals() {
Rectangle bounds = new Rectangle(getCastedModel().getLocation(),
getCastedModel().getSize());
((GraphicalEditPart) getParent()).setLayoutConstraint(this, getFigure(), bounds);
}
return (AbstractActivity) getModel();
}
protectedvoid refreshVisuals() {
Rectangle bounds = new Rectangle(getCastedModel().getLocation(),
getCastedModel().getSize());
((GraphicalEditPart) getParent()).setLayoutConstraint(this, getFigure(), bounds);
}
这个方法的含义是取得活动模型的位置,大小信息,把当前活动模型定位到编辑器的适当位置。
这下,我们再运行项目,就可以顺利把活动添加到编辑器中了。
在下一节,我们将介绍如何移动,删除活动,改变活动的大小,在活动之间新建转移