要实现向编辑器增加活动,我们应该在面板上选一种活动(开始活动,普通活动,结束活动),拖到编辑器中。为此我们必须在面板和编辑器中分别加监听。修改WorkflowProcessEditor类
在编辑器的
GraphicalViewer
加监听
protected
void
initializeGraphicalViewer() {
super
.initializeGraphicalViewer();
GraphicalViewer viewer = getGraphicalViewer();
viewer.setContents(getModel());
// set the contents of this editor
// listen for dropped parts
viewer.
addDropTargetListener
(createTransferDropTargetListener())
;
}
private
TransferDropTargetListener createTransfer
DropTarget
Listener
() {
return
new
TemplateTransferDropTargetListener(getGraphicalViewer()) {
protected
CreationFactory getFactory(Object template) {
return
new
SimpleFactory((Class) template);
}
};
}
同时我们还必须给面板加监听,覆盖父类的
createPaletteViewerProvider()
方法:
protected
PaletteViewerProvider createPaletteViewerProvider() {
return
new
PaletteViewerProvider(getEditDomain()) {
protected
void
configurePaletteViewer(PaletteViewer viewer) {
super
.configurePaletteViewer(viewer);
viewer.add
DragSource
Listener(
new
TemplateTransferDragSourceListener(viewer));
}
};
}
光在这两个地方加监听,还不够,这里还要引出gef的重要概念:策略(Policy),用过Rose的人都知道,我们可以新建一个类图,移动它,删除它,这在流程设计器中也可以,只是新建活动,移动活动等操作,用户这些操作其实是对控制器的操作,比如用户用鼠标移动活动,其实这过程包括用户向控制器发出移动活动的请求(Request),控制器就调用相应的命令(Command)来修改模型中活动的位置属性,而模型的位置属性发生变化,又会通知控制器,控制器就会刷新视图,改变活动的位置,这样,我们就移动了活动,那么控制器是怎么根据请求的类型调用相应的命令的,这就是策略的作用,简单说,策略保存了请求类型和命令的映射关系,它知道什么样的请求要调用哪个命令。
明白策略的含义之后,就可以更好的理解我们下面的程序了。我们要向流程中增加一个活动,就要向流程控制器发出请求,因此,我们要在流程控制器中安装策略,由于我们在编辑器中采用绝对定位方式,因此安装XYLayoutEditPolicy策略,我们定义一个类WorkflowProcessXYLayoutEditPolicy继承它,
我们修改WorkflowProcessEditPart类的createEditPolicies方法:
protected
void
createEditPolicies() {
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;
public
class
WorkflowProcessXYLayoutEditPolicy
extends
XYLayoutEditPolicy{
protected
Command createChangeConstraintCommand(EditPart arg0, Object arg1) {
//
TODO
Auto-generated method stub
return
null
;
}
protected
Command getCreateCommand(CreateRequest arg0) {
//
TODO
Auto-generated method stub
return
null
;
}
}
如果我们发出在编辑器中新建活动的请求,流程根据安装的策略,就会调用这个类的
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;
public
class
AbstractActivityCreateCommand
extends
Command{
private
AbstractActivity
newActivity
;
private
final
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"
);
}
public
boolean
canExecute() {
return
newActivity
!=
null
&&
parent
!=
null
&&
bounds
!=
null
;
}
/* (non-Javadoc)
* @see org.eclipse.gef.commands.Command#execute()
*/
public
void
execute() {
newActivity
.setLocation(
bounds
.getLocation());
Dimension size =
bounds
.getSize();
if
(size.
width
> 0 && size.
height
> 0)
newActivity
.setSize(size);
redo();
}
/*
重做
*/
public
void
redo() {
parent
.addChild(
newActivity
);
}
/*
撤销
*/
public
void
undo() {
parent
.removeChild(
newActivity
);
}
}
接下来,我们还要修改
WorkflowProcessXYLayoutEditPolicy
的
getCreateCommand
方法,如果在编辑器中请求创建的对象是开始活动,活动,结束活动的一种,都会调用刚才新建的命令。
protected
Command getCreateCommand(CreateRequest request) {
Object childClass = request.getNewObjectType();
if
(childClass == StartActivity.
class
||childClass == Activity.
class
||childClass == EndActivity.
cl
ass
) {
return
new
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
;
}
为此我们在
propertyChange
应作如下修改:
public
void
propertyChange(PropertyChangeEvent evt) {
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();
}
protected
void
refreshVisuals() {
Rectangle bounds =
new
Rectangle(getCastedModel().getLocation(),
getCastedModel().getSize());
((GraphicalEditPart)
getParent
()).setLayoutConstraint(
this
, getFigure(), bounds);
}
这个方法的含义是取得活动模型的位置,大小信息,把当前活动模型定位到编辑器的适当位置。
这下,我们再运行项目,就可以顺利把活动添加到编辑器中了。
![](https://p-blog.csdn.net/images/p_blog_csdn_net/jacky9881/9e0e35d9de514941babb547af77193f2.jpg)
在下一节,我们将介绍如何移动,删除活动,改变活动的大小,在活动之间新建转移