Posted on 2008-01-04 08:49 
笑看人生 阅读(1420) 
评论(0)  编辑  收藏  所属分类: 
Java插件开发 
			 
			
		 
		要实现向编辑器增加活动,我们应该在面板上选一种活动(开始活动,普通活动,结束活动),拖到编辑器中。为此我们必须在面板和编辑器中分别加监听。修改WorkflowProcessEditor类
在编辑器的GraphicalViewer加监听

 protectedvoid initializeGraphicalViewer()
protectedvoid initializeGraphicalViewer()  {
{
 super.initializeGraphicalViewer();
    super.initializeGraphicalViewer();
 GraphicalViewer viewer = getGraphicalViewer();
    GraphicalViewer viewer = getGraphicalViewer();
 viewer.setContents(getModel()); // set the contents of this editor
    viewer.setContents(getModel()); // set the contents of this editor
 
    
 // listen for dropped parts
    // listen for dropped parts
 viewer.addDropTargetListener(createTransferDropTargetListener());
    viewer.addDropTargetListener(createTransferDropTargetListener());
 }
}
 
 

 private TransferDropTargetListener createTransferDropTargetListener()
private TransferDropTargetListener createTransferDropTargetListener()  {
{

 returnnew TemplateTransferDropTargetListener(getGraphicalViewer())
    returnnew TemplateTransferDropTargetListener(getGraphicalViewer())  {
{

 protected CreationFactory getFactory(Object template)
       protected CreationFactory getFactory(Object template)  {
{
 returnnew SimpleFactory((Class) template);
           returnnew SimpleFactory((Class) template);
 }
       }
 };
    };
 }
}
同时我们还必须给面板加监听,覆盖父类的createPaletteViewerProvider()方法:

 protected PaletteViewerProvider createPaletteViewerProvider()
protected PaletteViewerProvider createPaletteViewerProvider()  {
{

 returnnew PaletteViewerProvider(getEditDomain())
       returnnew PaletteViewerProvider(getEditDomain())  {
{

 protectedvoid configurePaletteViewer(PaletteViewer viewer)
           protectedvoid configurePaletteViewer(PaletteViewer viewer)  {
{
 super.configurePaletteViewer(viewer);
              super.configurePaletteViewer(viewer);            
 viewer.addDragSourceListener(new TemplateTransferDragSourceListener(viewer));
           viewer.addDragSourceListener(new TemplateTransferDragSourceListener(viewer));
 }
           }
 };
       };
 }
}
光在这两个地方加监听,还不够,这里还要引出gef的重要概念:策略(Policy),用过Rose的人都知道,我们可以新建一个类图,移动它,删除它,这在流程设计器中也可以,只是新建活动,移动活动等操作,用户这些操作其实是对控制器的操作,比如用户用鼠标移动活动,其实这过程包括用户向控制器发出移动活动的请求(Request),控制器就调用相应的命令(Command)来修改模型中活动的位置属性,而模型的位置属性发生变化,又会通知控制器,控制器就会刷新视图,改变活动的位置,这样,我们就移动了活动,那么控制器是怎么根据请求的类型调用相应的命令的,这就是策略的作用,简单说,策略保存了请求类型和命令的映射关系,它知道什么样的请求要调用哪个命令。
明白策略的含义之后,就可以更好的理解我们下面的程序了。我们要向流程中增加一个活动,就要向流程控制器发出请求,因此,我们要在流程控制器中安装策略,由于我们在编辑器中采用绝对定位方式,因此安装XYLayoutEditPolicy策略,我们定义一个类WorkflowProcessXYLayoutEditPolicy继承它,
我们修改WorkflowProcessEditPart类的createEditPolicies方法:

 protectedvoid createEditPolicies()
protectedvoid createEditPolicies()  {
{ 
 installEditPolicy(EditPolicy.LAYOUT_ROLE, new WorkflowProcessXYLayoutEditPolicy());
       installEditPolicy(EditPolicy.LAYOUT_ROLE, new WorkflowProcessXYLayoutEditPolicy());
 
       
 }
}
其实这个策略不仅可以处理创建活动的请求,还可以处理改变活动位置和大小的请求。
接下来我们来看WorkflowProcessXYLayoutEditPolicy

 package com.example.workflow.policy;
package com.example.workflow.policy;
 
 
 import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPart;
 import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.Command;
 import org.eclipse.gef.editpolicies.XYLayoutEditPolicy;
import org.eclipse.gef.editpolicies.XYLayoutEditPolicy;
 import org.eclipse.gef.requests.CreateRequest;
import org.eclipse.gef.requests.CreateRequest;
 
 

 publicclass WorkflowProcessXYLayoutEditPolicy extends XYLayoutEditPolicy
publicclass WorkflowProcessXYLayoutEditPolicy extends XYLayoutEditPolicy {
{
 
 

 protected Command createChangeConstraintCommand(EditPart arg0, Object arg1)
    protected Command createChangeConstraintCommand(EditPart arg0, Object arg1)  {
{
 // TODO Auto-generated method stub
       // TODO Auto-generated method stub
 returnnull;
       returnnull;
 }
    }
 
 

 protected Command getCreateCommand(CreateRequest arg0)
    protected Command getCreateCommand(CreateRequest arg0)  {
{
 // TODO Auto-generated method stub
       // TODO Auto-generated method stub
 returnnull;
       returnnull;
 }
    }
 
 
 }
}
如果我们发出在编辑器中新建活动的请求,流程根据安装的策略,就会调用这个类的getCreateCommand方法,为此我们要修改这个方法,如果我们发出改变活动大小和位置的请求,就会调用createChangeConstraintCommand方法。
为了修改流程模型,在流程模型中增加一个活动,我们用命令来实现这个功能,命令都具有撤销,重做功能,我们只需覆盖redo,undo方法就可以实现这功能。:
 package com.example.workflow.commands;
package com.example.workflow.commands;
 
 
 import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Dimension;
 import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.draw2d.geometry.Rectangle;
 import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.Command;
 
 
 import com.example.workflow.model.AbstractActivity;
import com.example.workflow.model.AbstractActivity;
 import com.example.workflow.model.WorkflowProcess;
import com.example.workflow.model.WorkflowProcess;
 
 
 
 
 
 

 publicclass AbstractActivityCreateCommand extends Command
publicclass AbstractActivityCreateCommand extends Command {
{
 
    
 private AbstractActivity newActivity;
    private AbstractActivity newActivity;
 
    
 privatefinal WorkflowProcess parent;
    privatefinal WorkflowProcess parent;
 
    
 private Rectangle bounds;
    private Rectangle bounds;
 
 

 public AbstractActivityCreateCommand(AbstractActivity newActivity, WorkflowProcess parent, Rectangle bounds)
    public AbstractActivityCreateCommand(AbstractActivity newActivity, WorkflowProcess parent, Rectangle bounds)  {
{
 this.newActivity = newActivity;
       this.newActivity = newActivity;
 this.parent = parent;
       this.parent = parent;
 this.bounds = bounds;
       this.bounds = bounds;
 setLabel("activity creation");
       setLabel("activity creation");
 }
    }
 
 
 
    

 publicboolean canExecute()
    publicboolean canExecute()  {
{
 returnnewActivity != null && parent != null && bounds != null;
       returnnewActivity != null && parent != null && bounds != null;
 }
    }
 
 

 /**//* (non-Javadoc)
    /**//* (non-Javadoc)
 * @see org.eclipse.gef.commands.Command#execute()
     * @see org.eclipse.gef.commands.Command#execute()
 */
     */

 publicvoid execute()
    publicvoid execute()  {
{
 newActivity.setLocation(bounds.getLocation());
       newActivity.setLocation(bounds.getLocation());
 Dimension size = bounds.getSize();
       Dimension size = bounds.getSize();
 if (size.width > 0 && size.height > 0)
       if (size.width > 0 && size.height > 0)
 newActivity.setSize(size);
           newActivity.setSize(size);
 redo();
       redo();
 }
    }
 
 

 /**//* 重做
    /**//* 重做
 */
     */

 publicvoid redo()
    publicvoid redo()  {
{
 parent.addChild(newActivity);
       parent.addChild(newActivity);
 }
    }
 
 

 /**//* 撤销
    /**//* 撤销
 */
     */

 publicvoid undo()
    publicvoid undo()  {
{
 parent.removeChild(newActivity);
       parent.removeChild(newActivity);
 }
    }
 }
}
接下来,我们还要修改WorkflowProcessXYLayoutEditPolicy的getCreateCommand方法,如果在编辑器中请求创建的对象是开始活动,活动,结束活动的一种,都会调用刚才新建的命令。

 protected Command getCreateCommand(CreateRequest request)
protected Command getCreateCommand(CreateRequest request)  {
{
 Object childClass = request.getNewObjectType();
       Object childClass = request.getNewObjectType();
 if (childClass == StartActivity.class
       if (childClass == StartActivity.class
 ||childClass == Activity.class
              ||childClass == Activity.class

 ||childClass == EndActivity.class)
              ||childClass == EndActivity.class)  {
{          
 returnnew AbstractActivityCreateCommand((AbstractActivity)request.getNewObject(),
           returnnew AbstractActivityCreateCommand((AbstractActivity)request.getNewObject(), 
 (WorkflowProcess)getHost().getModel(), (Rectangle)getConstraintFor(request));
                  (WorkflowProcess)getHost().getModel(), (Rectangle)getConstraintFor(request));
 }
       }
 return null;
       return null;
 }
} 
这下,我运行这个项目,我们从面板选中一个活动,放在编辑器中,编辑器根本没有反映,其实是我们少写了一个地方,我们向编辑器放一个活动,向流程控制器发出在编辑器中增加活动的请求,流程编辑器根据安装的策略,调用相应的命令修改流程模型,在流程模型中增加活动模型,而此时流程模型发生了变化,控制器应该刷新流程模型对应的视图,而我们程序是没有写这段代码的,因此我们要修改WorkflowProcessEditPart的propertyChange方法,由于在WorkflowProcess模型中,当向模型中增加活动时通知控制器流程的CHILD_ADDED_PROP发生变化的,见如下代码:

 public boolean addChild(AbstractActivity a)
public boolean addChild(AbstractActivity a)  {
{

 if (a != null && activities.add(a))
       if (a != null && activities.add(a))  {
{
 firePropertyChange(CHILD_ADDED_PROP, null, a);
           firePropertyChange(CHILD_ADDED_PROP, null, a);
 return true;
           return true;
 }
       }
 return false;
       return false;
 }
}
为此我们在propertyChange应作如下修改:

 public void propertyChange(PropertyChangeEvent evt)
public void propertyChange(PropertyChangeEvent evt)  {
{
 String prop = evt.getPropertyName();
       String prop = evt.getPropertyName();
 if (WorkflowProcess.CHILD_ADDED_PROP.equals(prop)
       if (WorkflowProcess.CHILD_ADDED_PROP.equals(prop)

 || WorkflowProcess.CHILD_REMOVED_PROP.equals(prop))
              || WorkflowProcess.CHILD_REMOVED_PROP.equals(prop))  {
{
 refreshChildren();
           refreshChildren();
 }
        }
 }
}
以上程序的意思是,当往流程模型中增加活动或者从流程模型中删除活动时,刷新流程模型包含子元素对应的视图,而流程模型的子元素是活动模型,而活动模型控制器的refreshVisuals()我们也没有实现,因此我们也应该实现这个方法,定义如下:

 private AbstractActivity getCastedModel()
private AbstractActivity getCastedModel()  {
{
 return (AbstractActivity) getModel();
       return (AbstractActivity) getModel();
 }
    }
 
    

 protectedvoid refreshVisuals()
    protectedvoid refreshVisuals()  {
{      
 Rectangle bounds = new Rectangle(getCastedModel().getLocation(),
       Rectangle bounds = new Rectangle(getCastedModel().getLocation(),
 getCastedModel().getSize());
              getCastedModel().getSize());
 ((GraphicalEditPart) getParent()).setLayoutConstraint(this, getFigure(), bounds);
       ((GraphicalEditPart) getParent()).setLayoutConstraint(this, getFigure(), bounds);
 }
}这个方法的含义是取得活动模型的位置,大小信息,把当前活动模型定位到编辑器的适当位置。
这下,我们再运行项目,就可以顺利把活动添加到编辑器中了。
在下一节,我们将介绍如何移动,删除活动,改变活动的大小,在活动之间新建转移