流程设计器开发三(策略和命令部分)

来源:互联网 发布:mysql 触发器 死锁 编辑:程序博客网 时间:2024/06/05 06:29
 
要实现向编辑器增加活动,我们应该在面板上选一种活动(开始活动,普通活动,结束活动),拖到编辑器中。为此我们必须在面板和编辑器中分别加监听。修改WorkflowProcessEditor类
在编辑器的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);
       }
    };
}
同时我们还必须给面板加监听,覆盖父类的createPaletteViewerProvider()方法:
protected PaletteViewerProvider createPaletteViewerProvider() {
       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_ROLEnew 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方法。
为了修改流程模型,在流程模型中增加一个活动,我们用命令来实现这个功能,命令都具有撤销,重做功能,我们只需覆盖redoundo方法就可以实现这功能。:
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);
    }
}
接下来,我们还要修改WorkflowProcessXYLayoutEditPolicygetCreateCommand方法,如果在编辑器中请求创建的对象是开始活动,活动,结束活动的一种,都会调用刚才新建的命令。
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));
       }
       returnnull;
}
这下,我运行这个项目,我们从面板选中一个活动,放在编辑器中,编辑器根本没有反映,其实是我们少写了一个地方,我们向编辑器放一个活动,向流程控制器发出在编辑器中增加活动的请求,流程编辑器根据安装的策略,调用相应的命令修改流程模型,在流程模型中增加活动模型,而此时流程模型发生了变化,控制器应该刷新流程模型对应的视图,而我们程序是没有写这段代码的,因此我们要修改WorkflowProcessEditPartpropertyChange方法,由于在WorkflowProcess模型中,当向模型中增加活动时通知控制器流程的CHILD_ADDED_PROP发生变化的,见如下代码:
publicboolean addChild(AbstractActivity a) {
       if (a != null && activities.add(a)) {
           firePropertyChange(CHILD_ADDED_PROP, null, a);
           returntrue;
       }
       returnfalse;
}
 
为此我们在propertyChange应作如下修改:
publicvoid 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();
    }
   
    protectedvoid refreshVisuals() {     
       Rectangle bounds = new Rectangle(getCastedModel().getLocation(),
              getCastedModel().getSize());
       ((GraphicalEditPart) getParent()).setLayoutConstraint(this, getFigure(), bounds);
}
这个方法的含义是取得活动模型的位置,大小信息,把当前活动模型定位到编辑器的适当位置。
这下,我们再运行项目,就可以顺利把活动添加到编辑器中了。
在下一节,我们将介绍如何移动,删除活动,改变活动的大小,在活动之间新建转移 
原创粉丝点击