Adding a Connection using Draw2d
Draw2d offers a special type of figure, called a connection, for connecting two figures. To create a connection in Draw2d, it is first necessary to establish the two endpoints of the connection. These endpoints are called the source and the target anchors. Endpoints are created using objects that implement the ConnectionAnchor interface. Once these anchors are created, they are set as endpoints via calls to the connection's setSourceAnchor(ConnectionAnchor) and setTargetAnchor(ConnectionAnchor) methods. This is demonstrated below
using a ChopboxAnchor. This type of anchor places the connection endpoint on the edge of the figure and causes it to point towards the figure's center.
PolylineConnection c = new PolylineConnection(); ChopboxAnchor sourceAnchor = new ChopboxAnchor(sourceFigure); ChopboxAnchor targetAnchor = new ChopboxAnchor(targetFigure); c.setSourceAnchor(sourceAnchor); c.setTargetAnchor(targetAnchor);
In this way, you can add a connection between two figures.
But now the case is that we want to connect not only two figures, but also two model nodes in GEF.
Reference:
[1] Display a UML Diagram using Draw2D (Eclipse)
Creating a Connection Model
Connection.java
public class Connection extends Node { private Node startPoint; private Node endPoint; private boolean connected; public Node getStartPoint() { return startPoint; } public void setStartPoint(Node startPoint) { this.startPoint = startPoint; } public Node getEndPoint() { return endPoint; } public void setEndPoint(Node endPoint) { this.endPoint = endPoint; } public boolean isConnected() { return connected; } public void setConnected(boolean connected) { this.connected = connected; } public void disconnect() { if (connected) { startPoint.removeConnection(this); endPoint.removeConnection(this); setConnected(false); } } public void reconnect() { if (!connected) { startPoint.addConnection(this); endPoint.addConnection(this); setConnected(true); } } public void reconnect(Node start, Node end) { if (start == null || end == null || start == end) { throw new IllegalArgumentException(); } disconnect(); this.startPoint = start; this.endPoint = end; reconnect(); } }
Creating Connection EditPart
ConnectionPart inherits from Class AbstractConnectionPart of GEF.
ConnectionPart.java
public class ConnectionPart extends AbstractConnectionEditPart { @Override protected IFigure createFigure() { PolylineConnection connection = new PolylineConnection(); // connection.setForegroundColor(ColorConstants.darkGray); // connection.setLineWidth(2); // Anti-jagged // ConnectionLayer connectionLayer = (ConnectionLayer) getLayer(LayerConstants.CONNECTION_LAYER); // connectionLayer.setConnectionRouter(null); // connectionLayer.setAntialias(SWT.ON); // Arrow at target endpoint // connection.setTargetDecoration(new PolygonDecoration()); // connection.setConnectionRouter(new BendpointConnectionRouter()); return connection; } ... }
Reference:
[1] Anti-jagged in GEF Connection
[2] Connection Properties Setting
[3] Custom Anchor (To avoid overlapped lines by dragging anchors) (IBM)
Adding anchor support to the "node" EditPart
NodeEditPart.java
public class NodeEditPart extends AbstractGraphicalEditPart implements NodeEditPart { ... public ConnectionAnchor getSourceConnectionAnchor( ConnectionEditPart connection) { return new ChopboxAnchor(getFigure()); } public ConnectionAnchor getSourceConnectionAnchor(Request request) { return new ChopboxAnchor(getFigure()); } public ConnectionAnchor getTargetConnectionAnchor( ConnectionEditPart connection) { return new ChopboxAnchor(getFigure()); } public ConnectionAnchor getTargetConnectionAnchor(Request request) { return new ChopboxAnchor(getFigure()); } /* * (non-Javadoc) * * @see * org.eclipse.gef.editparts.AbstractGraphicalEditPart#getModelSourceConnections() */ protected List getModelSourceConnections() { return (Node)getModel().getSourceConnections(); } /* * (non-Javadoc) * * @see * org.eclipse.gef.editparts.AbstractGraphicalEditPart#getModelTargetConnections() */ protected List getModelTargetConnections() { return (Node)getModel().getTargetConnections(); } ... }
Editing "node"
Node.java
public class Node { private transient PropertyChangeSupport listeners = new PropertyChangeSupport(this); /** Property ID to use when the list of outgoing connections is modified. */ public static final String SOURCE_CONNECTIONS_PROP = "SourceConnection"; /** Property ID to use when the list of incoming connections is modified. */ public static final String TARGET_CONNECTIONS_PROP = "TargetConnection"; /** List of outgoing Connections. */ private List<Connection> sourceConnections = new ArrayList<Connection>(); /** List of incoming Connections. */ private List<Connection> targetConnections = new ArrayList<Connection>(); ... public List<Connection> getSourceConnections() { return sourceConnections; } public List<Connection> getTargetConnections() { return targetConnections; } public void addConnection(Connection connection) { if (connection == null) { throw new IllegalArgumentException(); } if (connection.getStartPoint() == this) { sourceConnections.add(connection); firePropertyChange(SOURCE_CONNECTIONS_PROP, null, connection); } else if (connection.getEndPoint() == this) { targetConnections.add(connection); firePropertyChange(TARGET_CONNECTIONS_PROP, null, connection); } } public void removeConnection(Connection connection) { if (connection == null) { throw new IllegalArgumentException(); } if (connection.getStartPoint() == this) { sourceConnections.remove(connection); firePropertyChange(SOURCE_CONNECTIONS_PROP, null, connection); } else if (connection.getEndPoint() == this) { targetConnections.remove(connection); firePropertyChange(TARGET_CONNECTIONS_PROP, null, connection); } } /** * Report a property change to registered listeners (for example edit parts). * * @param property * the programmatic name of the property that changed * @param oldValue * the old value of this property * @param newValue * the new value of this property */ protected void firePropertyChange(String property, Object oldValue, Object newValue) { if (listeners.hasListeners(property)) { listeners.firePropertyChange(property, oldValue, newValue); } } public void addPropertyChangeListener(PropertyChangeListener listener) { if (listener == null) { throw new IllegalArgumentException(); } listeners.addPropertyChangeListener(listener); } public void removePropertyChangeListener(PropertyChangeListener listener) { if (listener != null) { listeners.removePropertyChangeListener(listener); } } ... }
Make Connections
Connection connection = new Connection(); connection.setStartPoint(startNode); connection.setEndPoint(endNode); startNode.addConnection(connection); endNode.addConnection(connection);
Listener
@Override public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equals(Node.SOURCE_CONNECTIONS_PROP)) refreshSourceConnections(); if (evt.getPropertyName().equals(Node.TARGET_CONNECTIONS_PROP)) refreshTargetConnections(); }