要實(shí)現(xiàn)向編輯器增加活動(dòng),我們應(yīng)該在面板上選一種活動(dòng)(開始活動(dòng),普通活動(dòng),結(jié)束活動(dòng)),拖到編輯器中。為此我們必須在面板和編輯器中分別加監(jiān)聽。修改WorkflowProcessEditor類
在編輯器的GraphicalViewer加監(jiān)聽

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);
}
};
}
同時(shí)我們還必須給面板加監(jiān)聽,覆蓋父類的createPaletteViewerProvider()方法:

protected PaletteViewerProvider createPaletteViewerProvider()
{

returnnew PaletteViewerProvider(getEditDomain())
{

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

protectedvoid createEditPolicies()
{
installEditPolicy(EditPolicy.LAYOUT_ROLE, new WorkflowProcessXYLayoutEditPolicy());
}
其實(shí)這個(gè)策略不僅可以處理創(chuàng)建活動(dòng)的請求,還可以處理改變活動(dòng)位置和大小的請求。
接下來我們來看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;
}
}
如果我們發(fā)出在編輯器中新建活動(dòng)的請求,流程根據(jù)安裝的策略,就會(huì)調(diào)用這個(gè)類的getCreateCommand方法,為此我們要修改這個(gè)方法,如果我們發(fā)出改變活動(dòng)大小和位置的請求,就會(huì)調(diào)用createChangeConstraintCommand方法。
為了修改流程模型,在流程模型中增加一個(gè)活動(dòng),我們用命令來實(shí)現(xiàn)這個(gè)功能,命令都具有撤銷,重做功能,我們只需覆蓋redo,undo方法就可以實(shí)現(xiàn)這功能。:
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方法,如果在編輯器中請求創(chuàng)建的對象是開始活動(dòng),活動(dòng),結(jié)束活動(dòng)的一種,都會(huì)調(diào)用剛才新建的命令。

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;
}
這下,我運(yùn)行這個(gè)項(xiàng)目,我們從面板選中一個(gè)活動(dòng),放在編輯器中,編輯器根本沒有反映,其實(shí)是我們少寫了一個(gè)地方,我們向編輯器放一個(gè)活動(dòng),向流程控制器發(fā)出在編輯器中增加活動(dòng)的請求,流程編輯器根據(jù)安裝的策略,調(diào)用相應(yīng)的命令修改流程模型,在流程模型中增加活動(dòng)模型,而此時(shí)流程模型發(fā)生了變化,控制器應(yīng)該刷新流程模型對應(yīng)的視圖,而我們程序是沒有寫這段代碼的,因此我們要修改WorkflowProcessEditPart的propertyChange方法,由于在WorkflowProcess模型中,當(dāng)向模型中增加活動(dòng)時(shí)通知控制器流程的CHILD_ADDED_PROP發(fā)生變化的,見如下代碼:

public boolean addChild(AbstractActivity a)
{

if (a != null && activities.add(a))
{
firePropertyChange(CHILD_ADDED_PROP, null, a);
return true;
}
return false;
}
為此我們在propertyChange應(yīng)作如下修改:

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

|| WorkflowProcess.CHILD_REMOVED_PROP.equals(prop))
{
refreshChildren();
}
}
以上程序的意思是,當(dāng)往流程模型中增加活動(dòng)或者從流程模型中刪除活動(dòng)時(shí),刷新流程模型包含子元素對應(yīng)的視圖,而流程模型的子元素是活動(dòng)模型,而活動(dòng)模型控制器的refreshVisuals()我們也沒有實(shí)現(xiàn),因此我們也應(yīng)該實(shí)現(xiàn)這個(gè)方法,定義如下:

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

protectedvoid refreshVisuals()
{
Rectangle bounds = new Rectangle(getCastedModel().getLocation(),
getCastedModel().getSize());
((GraphicalEditPart) getParent()).setLayoutConstraint(this, getFigure(), bounds);
}
這個(gè)方法的含義是取得活動(dòng)模型的位置,大小信息,把當(dāng)前活動(dòng)模型定位到編輯器的適當(dāng)位置。
這下,我們再運(yùn)行項(xiàng)目,就可以順利把活動(dòng)添加到編輯器中了。
在下一節(jié),我們將介紹如何移動(dòng),刪除活動(dòng),改變活動(dòng)的大小,在活動(dòng)之間新建轉(zhuǎn)移