分类:
2009-10-13 00:09:29
当我们点击tool栏的创建连接时,Tool就会是ConnectionCreationTool,
当我们选择一个节点单击时:
protected boolean handleButtonDown(int button) {
if (button == 1 && stateTransition(STATE_CONNECTION_STARTED, STATE_TERMINAL))
return handleCreateConnection();
//这个是指连线执行,即选择了连线的两端原件。
super.handleButtonDown(button);
//这个是选择连线开始端时调用:
if (isInState(STATE_CONNECTION_STARTED))
//Fake a drag to cause feedback to be displayed immediately on mouse down.
handleDrag();
return true;
}
protected boolean handleButtonDown(int button) {
if (isInState(STATE_INITIAL) && button == 1) {
updateTargetRequest();
updateTargetUnderMouse();
setConnectionSource(getTargetEditPart());
Command command = getCommand();
((CreateConnectionRequest)getTargetRequest()).setSourceEditPart(
getTargetEditPart());
//设置requst的sourceTarget
if (command != null) {
setState(STATE_CONNECTION_STARTED);
setCurrentCommand(command);
viewer = getCurrentViewer();
}
}
if (isInState(STATE_INITIAL) && button != 1) {
setState(STATE_INVALID);
handleInvalidInput();
}
return true;
}
//这个函数将state设置为STATE_CONNECTION_STARTED,并并将request的source设置为TargetEditPart,这个就是点击时的节点。
同时执行
getCommand(REQ_CONNECTION_START);//
这个其实会调用editpart(作为connect的source的)的getCommand(REQ_CONNECTION_START),即
public abstract class TargetTooling{
protected Command getCommand() {
if (getTargetEditPart() == null)
return null;
return getTargetEditPart().
getCommand(getTargetRequest());
}
}
然后会调用
public abstract class GraphicalNodeEditPolicy
extends GraphicalEditPolicy
{
public Command getCommand(Request request) {
if (REQ_CONNECTION_START.equals(request.getType()))
return getConnectionCreateCommand((CreateConnectionRequest)request);
if (REQ_CONNECTION_END.equals(request.getType()))
return getConnectionCompleteCommand((CreateConnectionRequest)request);
if (REQ_RECONNECT_TARGET.equals(request.getType()))
return getReconnectTargetCommand((ReconnectRequest)request);
if (REQ_RECONNECT_SOURCE.equals(request.getType()))
return getReconnectSourceCommand((ReconnectRequest)request);
return null;
}
}
然后就会fake一次handleDrag,其实以后鼠标运动也是调用这个函数,直到再次单击鼠标.
protected boolean handleDrag() {
if (isInState(STATE_CONNECTION_STARTED))
return handleMove();
return false;
}
protected boolean handleMove() {
if (isInState(STATE_CONNECTION_STARTED) && viewer != getCurrentViewer())
return false;
if (isInState(STATE_CONNECTION_STARTED | STATE_INITIAL
| STATE_ACCESSIBLE_DRAG_IN_PROGRESS)) {
updateTargetRequest();
//这时request为REQ_CONNECTION_END
updateTargetUnderMouse();
showSourceFeedback();
showTargetFeedback();
//feedback,其实只有showSourceFeedback()是真正画线的,showTargetFeedback可能无用。
setCurrentCommand(getCommand());//这个没有多大用。
}
return true;
}
下面我们看看showSourceFeedback()如何画线的:
protected void showSourceFeedback() {
if (connectionSource != null) {
connectionSource.showSourceFeedback(getSourceRequest());
}
setFlag(FLAG_SOURCE_FEEDBACK, true);
}
connectionSource就是connect的开始editpart(NodeEditpart结构)。
上面执行的就是NodeEditpart的showSourceFeedback(REQ_CONNECTION_END);
然后就到NodeEditPart,其实会执行policy的showSourceFeedback,即一般是GraphicalNodeEditPolicy的showSourceFeedback。
public void showSourceFeedback(Request request) {
if (REQ_CONNECTION_END.equals(request.getType()))
showCreationFeedback((CreateConnectionRequest)request);
}
protected void showCreationFeedback(CreateConnectionRequest request) {
FeedbackHelper helper = getFeedbackHelper(request);
Point p = new Point(request.getLocation());
helper.update(getTargetConnectionAnchor(request), p);
}
protected FeedbackHelper getFeedbackHelper(CreateConnectionRequest request) {
if (feedbackHelper == null) {
feedbackHelper = new FeedbackHelper();
Point p = request.getLocation();
connectionFeedback = createDummyConnection(request);
connectionFeedback.setConnectionRouter(getDummyConnectionRouter(request));
connectionFeedback.setSourceAnchor(getSourceConnectionAnchor(request));
feedbackHelper.setConnection(connectionFeedback);
addFeedback(connectionFeedback);
feedbackHelper.update(null, p);
}
return feedbackHelper;
}
getFeedbackHelper第一次调用会创建一个feedbackHelper类实例,这个其实就是一个包含connection的类,用来管理这个connect。
然后update,每次鼠标move都是会执行一次。
protected ConnectionAnchor getTargetConnectionAnchor(CreateConnectionRequest request) {
EditPart target = request.getTargetEditPart();
//获取connect的末端节点editpart,如果不是NodeEditPart,则可知返回null.
return target instanceof NodeEditPart
? ((NodeEditPart) target).getTargetConnectionAnchor(request)
: null;
}
public void update(ConnectionAnchor anchor, Point p) {
if (anchor != null)
setAnchor(anchor);
else {
dummyAnchor.setLocation(p);
setAnchor(dummyAnchor);
}
}
从上面可知,当末端节点是NodeEditPart,则调用这个editpart的getTargetConnectionAnchor,否则用当前鼠标值作为末端anchor,这样connect的两个anchor都定了,连线的开始断点是定的,是第一次点击时鼠标所在editpart返回的anchor。
当第二次单击鼠标完成画线。
protected boolean handleCreateConnection() {
eraseSourceFeedback();
Command endCommand = getCommand();
// REQ_CONNECTION_END command
setCurrentCommand(endCommand);
executeCurrentCommand();
return true;
}
//上面红色部分就会执行editpart端的getConnectionCompleteCommand
if (REQ_CONNECTION_END.equals(request.getType()))
return getConnectionCompleteCommand((CreateConnectionRequest)request);
protected Command getConnectionCompleteCommand(CreateConnectionRequest request) {
CreateConnectionCommand command = (CreateConnectionCommand) request.getStartCommand();
command.setTarget((Node) getHost().getModel());
return command;
}
这个就是将target也赋给command,这样当command执行时就会将connect放到sourceEditpart和targetEditpart相关项中,这样就好了。
大家可能为想request的TargetEditPart在哪赋值的吧:
这个是在updateTargetUnderMouse时
protected boolean updateTargetUnderMouse() {
if (!isTargetLocked()) {
EditPart editPart = getCurrentViewer().findObjectAtExcluding(
getLocation(),
getExclusionSet(),
getTargetingConditional());
if (editPart != null)
editPart = editPart.getTargetEditPart(getTargetRequest());
boolean changed = getTargetEditPart() != editPart;
setTargetEditPart(editPart);
//将targetEditpart赋给request
return changed;
} else
return false;
}
到现在思路能清楚了:
下面我从应用的角度来说下,我们对可以画线的节点的相关函数进行解释:
一个节点要想能被连线连接:必须绑定GraphicalNodeEditPolicy相关的policy,必须继承NodeEditPart,也就是必须包含如下函数:
public ConnectionAnchor getSourceConnectionAnchor(ConnectionEditPart connection) {
System.out.println("in source editpart");
return new ChopboxAnchor(getFigure());
}
//这个是editpart的policy(一般是GraphicalNodeEditPolicy)的showSourceFeedBack时用到,只调用一次,且被放到feedHelp里的dummyConnect的开始端点,当第一次单击鼠标时执行。
public ConnectionAnchor getSourceConnectionAnchor(Request request) {
System.out.println("in source");
return new ChopboxAnchor(getFigure());
}
//这个是真正画线的时候由GEF画图系统调用
public ConnectionAnchor getTargetConnectionAnchor(ConnectionEditPart connection) {
System.out.println("in target editpart");
return new ChopboxAnchor(getFigure());
}
public ConnectionAnchor getTargetConnectionAnchor(Request request) {
System.out.println("intarget");
return new ChopboxAnchor(getFigure());
}
//这个是sourceEditPart的policy的showSourceFeedBack函数从request取出TargetEditpart,然后调用TargetEditpart. getTargetConnectionAnchor时会调用的,这个返回值用来update feedbackHelp的connection的另一端点,单击后鼠标运动时调用。
protected List getModelSourceConnections() {
return ((Node) this.getModel()).getOutgoingConnections();
}
protected List getModelTargetConnections() {
return ((Node) this.getModel()).getIncomingConnections();
}
//上面两个是gef在绘制图形的时候,调用每个节点editpart的getModelTargetConnections,getModelSourceConnections来画线时用到的。
GraphicalNodeEditPolicy
public class NodeGraphicalNodeEditPolicy extends GraphicalNodeEditPolicy {
protected Command getConnectionCompleteCommand(CreateConnectionRequest request) {
CreateConnectionCommand command = (CreateConnectionCommand) request.getStartCommand();
command.setTarget((Node) getHost().getModel());
return command;
}
//这个是当单击了一次到单击第二次之间调用:
protected Command getConnectionCreateCommand(CreateConnectionRequest request) {
CreateConnectionCommand command = new CreateConnectionCommand();
command.setSource((Node) getHost().getModel());
request.setStartCommand(command);
return command;
}
//这个是开始移动到第一次单击开始连线之间调用:
protected Command getReconnectSourceCommand(ReconnectRequest request) {
ReconnectSourceCommand cmd = new ReconnectSourceCommand();
cmd.setConnection((Connection)request.getConnectionEditPart().getModel());
cmd.setSource((Node)getHost().getModel());
return cmd;
}
protected Command getReconnectTargetCommand(ReconnectRequest request) {
return null;
}
}