要實現向編輯器增加活動,我們應該在面板上選一種活動(開始活動,普通活動,結束活動),拖到編輯器中。為此我們必須在面板和編輯器中分別加監聽。修改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_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;
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方法。
為了修改流程模型,在流程模型中增加一個活動,我們用命令來實現這個功能,命令都具有撤銷,重做功能,我們只需覆蓋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;
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);
}
}
接下來,我們還要修改WorkflowProcessXYLayoutEditPolicy的getCreateCommand方法,如果在編輯器中請求創建的對象是開始活動,活動,結束活動的一種,都會調用剛才新建的命令。
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));
}
return null;
}
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();
}
protectedvoid refreshVisuals() {
Rectangle bounds = new Rectangle(getCastedModel().getLocation(),
getCastedModel().getSize());
((GraphicalEditPart) getParent()).setLayoutConstraint(this, getFigure(), bounds);
}
在編輯器的GraphicalViewer加監聽
















同時我們還必須給面板加監聽,覆蓋父類的createPaletteViewerProvider()方法:








光在這兩個地方加監聽,還不夠,這里還要引出gef的重要概念:策略(Policy),用過Rose的人都知道,我們可以新建一個類圖,移動它,刪除它,這在流程設計器中也可以,只是新建活動,移動活動等操作,用戶這些操作其實是對控制器的操作,比如用戶用鼠標移動活動,其實這過程包括用戶向控制器發出移動活動的請求(Request),控制器就調用相應的命令(Command)來修改模型中活動的位置屬性,而模型的位置屬性發生變化,又會通知控制器,控制器就會刷新視圖,改變活動的位置,這樣,我們就移動了活動,那么控制器是怎么根據請求的類型調用相應的命令的,這就是策略的作用,簡單說,策略保存了請求類型和命令的映射關系,它知道什么樣的請求要調用哪個命令。
明白策略的含義之后,就可以更好的理解我們下面的程序了。我們要向流程中增加一個活動,就要向流程控制器發出請求,因此,我們要在流程控制器中安裝策略,由于我們在編輯器中采用絕對定位方式,因此安裝XYLayoutEditPolicy策略,我們定義一個類WorkflowProcessXYLayoutEditPolicy繼承它,
我們修改WorkflowProcessEditPart類的createEditPolicies方法:




其實這個策略不僅可以處理創建活動的請求,還可以處理改變活動位置和大小的請求。
接下來我們來看WorkflowProcessXYLayoutEditPolicy





















如果我們發出在編輯器中新建活動的請求,流程根據安裝的策略,就會調用這個類的getCreateCommand方法,為此我們要修改這個方法,如果我們發出改變活動大小和位置的請求,就會調用createChangeConstraintCommand方法。
為了修改流程模型,在流程模型中增加一個活動,我們用命令來實現這個功能,命令都具有撤銷,重做功能,我們只需覆蓋redo,undo方法就可以實現這功能。:






















































接下來,我們還要修改WorkflowProcessXYLayoutEditPolicy的getCreateCommand方法,如果在編輯器中請求創建的對象是開始活動,活動,結束活動的一種,都會調用剛才新建的命令。










這下,我運行這個項目,我們從面板選中一個活動,放在編輯器中,編輯器根本沒有反映,其實是我們少寫了一個地方,我們向編輯器放一個活動,向流程控制器發出在編輯器中增加活動的請求,流程編輯器根據安裝的策略,調用相應的命令修改流程模型,在流程模型中增加活動模型,而此時流程模型發生了變化,控制器應該刷新流程模型對應的視圖,而我們程序是沒有寫這段代碼的,因此我們要修改WorkflowProcessEditPart的propertyChange方法,由于在WorkflowProcess模型中,當向模型中增加活動時通知控制器流程的CHILD_ADDED_PROP發生變化的,見如下代碼:







為此我們在propertyChange應作如下修改:







以上程序的意思是,當往流程模型中增加活動或者從流程模型中刪除活動時,刷新流程模型包含子元素對應的視圖,而流程模型的子元素是活動模型,而活動模型控制器的refreshVisuals()我們也沒有實現,因此我們也應該實現這個方法,定義如下:









這個方法的含義是取得活動模型的位置,大小信息,把當前活動模型定位到編輯器的適當位置。
這下,我們再運行項目,就可以順利把活動添加到編輯器中了。
在下一節,我們將介紹如何移動,刪除活動,改變活動的大小,在活動之間新建轉移