哪个模型的控制器能接受在活动之间建立转移的请求呢,只有活动模型的控制器了,因为活动模型中维护着活动的输入和输出转移的列表,在活动控制器增加策略,使该控制器能接受建立转移的请求,代码如下:
protected
void
createEditPolicies() {
//allow removal of the associated model element
installEditPolicy(EditPolicy.
COMPONENT_ROLE
,
new
AbstractActivityComponentEditPolicy());
//allow the creation of transitions and
// and the reconnection of transitions between AbstractActivity instances
installEditPolicy(EditPolicy.
GRAPHICAL_NODE_ROLE
,
new
TransitionGraphicalNodeEditPolicy());
}
这里安装了
TransitionGraphicalNodeEditPolicy
策略,这个策略的代码如下:
package com.example.workflow.policy;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.editpolicies.GraphicalNodeEditPolicy;
import org.eclipse.gef.requests.CreateConnectionRequest;
import org.eclipse.gef.requests.ReconnectRequest;
import com.example.workflow.commands.TransitionCreateCommand;
import com.example.workflow.model.AbstractActivity;
public class TransitionGraphicalNodeEditPolicy extends GraphicalNodeEditPolicy{
protected Command getConnectionCompleteCommand(CreateConnectionRequest request) {
TransitionCreateCommand cmd =
(TransitionCreateCommand)request.getStartCommand();
cmd.setTarget((AbstractActivity)getHost().getModel());
return cmd;
}
protected Command getConnectionCreateCommand(CreateConnectionRequest request) {
AbstractActivity source = (AbstractActivity)getHost().getModel();
TransitionCreateCommand cmd = new TransitionCreateCommand(source);
request.setStartCommand(cmd);
return cmd;
}
protected Command getReconnectSourceCommand(ReconnectRequest request) {
// TODO Auto-generated method stub
return null;
}
protected Command getReconnectTargetCommand(ReconnectRequest request) {
// TODO Auto-generated method stub
return null;
}
}
这个类继承了GraphicalNodeEditPolicy,并且覆盖了getConnectionCreateCommand和getConnectionCompleteCommand,从这两个方法的字面意思就明白它们在什么时候执行,在getConnectionCreateCommand方法中,新建一个TransitionCreateCommand命令对象,并且把转移的起始活动放入该命令对象中,在getConnectionCompleteCommand方法中,得到在getConnectionCreateCommand方法中创建的命令,并且把转移的目标活动放入命令中。TransitionCreateCommand命令的代码如下:
package com.example.workflow.commands;
import java.util.Iterator;
import org.eclipse.gef.commands.Command;
import com.example.workflow.model.AbstractActivity;
import com.example.workflow.model.Transition;
public class TransitionCreateCommand extends Command{
/** The Transition instance. */
private Transition transition;
/** Start endpoint for the Transition. */
private final AbstractActivity source;
/** Target endpoint for the Transition. */
private AbstractActivity target;
public TransitionCreateCommand(AbstractActivity source){
if (source == null) {
throw new IllegalArgumentException();
}
setLabel("connection creation");
this.source = source;
}
public boolean canExecute() {
// disallow source -> source connections
if (source.equals(target)) {
return false;
}
// return false, if the source -> target connection exists already
for (Iterator iter = source.getSourceTransitions().iterator(); iter.hasNext();) {
Transition tran = (Transition) iter.next();
if (tran.getTarget().equals(target)) {
return false;
}
}
return true;
}
public void execute() {
// create a new transition between source and target
transition = new Transition(source, target);
}
public void redo() {
transition.reconnect();
}
public void setTarget(AbstractActivity target) {
if (target == null) {
throw new IllegalArgumentException();
}
this.target = target;
}
public void undo() {
transition.disconnect();
}
}
在这个命令中,用刚才放入的两个活动构建一个转移对象,其实通过代码我们知道最终执行的是在起始活动的输入转移列表中加入刚才新建的转移对象,在目标活动的输入转移列表中加入新建的转移对象。代码如下:
void
addTransition(Transition tran) {
if
(tran ==
null
|| tran.getSource() == tran.getTarget()) {
throw
new
IllegalArgumentException();
}
if
(tran.getSource() ==
this
) {
sourceTransitions
.add(tran);
firePropertyChange(
SOURCE_CONNECTIONS_PROP
,
null
, tran);
}
else
if
(tran.getTarget() ==
this
) {
targetTransitions
.add(tran);
firePropertyChange(
TARGET_CONNECTIONS_PROP
,
null
, tran);
}
}
我们看到,向活动维护的转移列表中加入转移时,活动模型通知控制器它的
SOURCE_CONNECTIONS_PROP
和
TARGET_CONNECTIONS_PROP
属性发生变化了,因此在活动控制器中应该根据这两个属性来属性活动的视图,代码如下:
public
void
propertyChange(PropertyChangeEvent evt) {
String prop = evt.getPropertyName();
if
(AbstractActivity.
SIZE_PROP
.equals(prop)
||AbstractActivity.
LOCATION_PROP
.equals(prop)){
refreshVisuals();
}
else
if
(AbstractActivity.
SOURCE_TRANSITIONS_PROP
.equals(prop)){
refreshSourceConnections();
}
else
if
(AbstractActivity.
TARGET_TRANSITIONS_PROP
.equals(prop)){
refreshTargetConnections();
}
}
这里刷新的不是活动的视图,而是活动的输入和输入转移对应的视图。
只修改这些代码,还不能在编辑器中展示出新建的转移,还应该让活动控制器实现
NodeEditPart
接口,同时要实现这接口中的四个方法,代码如下:
private ConnectionAnchor anchor;
protected
ConnectionAnchor getConnectionAnchor(){
if
(
anchor
==
null
) {
anchor
=
new
ChopboxAnchor(getFigure());;
}
return
anchor
;
}
public
ConnectionAnchor getSourceConnectionAnchor(ConnectionEditPart arg0) {
return
getConnectionAnchor();
}
public
ConnectionAnchor getSourceConnectionAnchor(Request arg0) {
return
getConnectionAnchor();
}
public
ConnectionAnchor getTargetConnectionAnchor(ConnectionEditPart arg0) {
return
getConnectionAnchor();
}
public
ConnectionAnchor getTargetConnectionAnchor(Request arg0) {
return
getConnectionAnchor();
}
这四个方法就是实现转移和活动连接的锚点。
另外我们还要覆盖父类中的两个方法,得到活动模型维护的输入转移和输出转移,代码如下:
protected
List getModelSourceConnections() {
return
getCastedModel().getSourceTransitions();
}
protected
List getModelTargetConnections() {
return
getCastedModel().getTargetTransitions();
}
这样我们就可以在活动之间建立转移了,效果下图:
这样我们就在两个活动之间建立了转移。那么如何删除转移呢,要删除活动之间的转移,应该在转移控制器中安装策略,代码如下:
private
Transition getCastedModel(){
return
(Transition)getModel();
}
protected
void
createEditPolicies() {
//Allows the removal of the transition model element
installEditPolicy(EditPolicy.
CONNECTION_ROLE
,
new
ConnectionEditPolicy() {
protected
Command getDeleteCommand(GroupRequest request) {
return
new
TransitionDeleteCommand(getCastedModel());
}
});
}
这里安装的是
gef
框架提供的策略,我们没有创建自己的策略,而是直接覆盖其中的
getDeleteCommand
,方法,在这个方法中新建了一个
TransitionDeleteCommand
命令,这个命令的代码如下:
package com.example.workflow.commands;
import org.eclipse.gef.commands.Command;
import com.example.workflow.model.Transition;
public class TransitionDeleteCommand extends Command {
/** Transition instance to disconnect. */
private final Transition transition;
public TransitionDeleteCommand(Transition tran) {
if (tran == null) {
throw new IllegalArgumentException();
}
setLabel("Transition deletion");
this.transition = tran;
}
public void execute() {
transition.disconnect();
}
public void undo() {
transition.reconnect();
}
}
这个类最终执行的其实活动模型中的
removeTransition
方法,从活动模型维护的转移列表中删除它,而此时活动模型通知控制器自己的
SOURCE_CONNECTIONS_PROP
和
TARGET_CONNECTIONS_PROP
属性发生变化了,要刷新视图,而这个我们在新建转移时,已经实现,因而这儿不用在实现了
。这样运行程序,我们就可以删除活动之间的转移了。
接下来我们再给转移控制器安装一个策略,目的是当选择转移,转移有个反馈,给用户感觉是已经选择了转移,要不然,选择和不选择转移,效果一样,代码如下:
protected
void
createEditPolicies() {
//Selection handle edit policy.
// Makes the transition show a feedback, when selected by the user.
installEditPolicy(EditPolicy.
CONNECTION_ENDPOINTS_ROLE
,
new
ConnectionEndpointEditPolicy());
//Allows the removal of the transition model element
installEditPolicy(EditPolicy.
CONNECTION_ROLE
,
new
ConnectionEditPolicy() {
protected
Command getDeleteCommand(GroupRequest request) {
return
new
TransitionDeleteCommand(getCastedModel());
}
});
}
下一节我们介绍如何在转移上新建,删除和移动拐点。