流程設計器開發三(策略和命令部分)

 
要實現向編輯器增加活動,我們應該在面板上選一種活動(開始活動,普通活動,結束活動),拖到編輯器中。爲此我們必須在面板和編輯器中分別加監聽。修改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);
}
這個方法的含義是取得活動模型的位置,大小信息,把當前活動模型定位到編輯器的適當位置。
這下,我們再運行項目,就可以順利把活動添加到編輯器中了。
在下一節,我們將介紹如何移動,刪除活動,改變活動的大小,在活動之間新建轉移 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章