/* * JBoss, Home of Professional Open Source. * * See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing. * * See the AUTHORS.txt file distributed with this work for a full listing of individual contributors. */ package org.teiid.designer.diagram.ui.figure; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.eclipse.draw2d.AnchorListener; import org.eclipse.draw2d.ArrowLocator; import org.eclipse.draw2d.ColorConstants; import org.eclipse.draw2d.Connection; import org.eclipse.draw2d.ConnectionAnchor; import org.eclipse.draw2d.ConnectionLocator; import org.eclipse.draw2d.ConnectionRouter; import org.eclipse.draw2d.DelegatingLayout; import org.eclipse.draw2d.Figure; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.Polyline; import org.eclipse.draw2d.RotatableDecoration; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.swt.graphics.Color; import org.teiid.designer.diagram.ui.util.ToolTipUtil; /** * Connection based on polyline. The layout of the connection is handled by routers. * * @since 8.0 */ public class DiagramPolylineConnection extends Polyline implements Connection, AnchorListener { private Color defaultLineColor = ColorConstants.black; private ConnectionAnchor startAnchor, endAnchor; private ConnectionRouter connectionRouter = ConnectionRouter.NULL; private RotatableDecoration startArrow, endArrow; { setLayoutManager(new DelegatingLayout()); addPoint(new Point(0, 0)); addPoint(new Point(100, 100)); } /** * Hooks the source and target anchors. * @see Figure#addNotify() */ @Override public void addNotify() { super.addNotify(); hookSourceAnchor(); hookTargetAnchor(); } /** * Called by the anchors of this connection when they have moved, revalidating this * polyline connection. * @param anchor the anchor that moved */ @Override public void anchorMoved(ConnectionAnchor anchor) { revalidate(); } /** * Returns the bounds which holds all the points in this polyline connection. Returns any * previously existing bounds, else calculates by unioning all the children's * dimensions. * @return the bounds */ @Override public Rectangle getBounds() { if (bounds == null) { super.getBounds(); for (int i = 0; i < getChildren().size(); i++) { IFigure child = (IFigure)getChildren().get(i); bounds.union(child.getBounds()); } } return bounds; } /** * Returns the <code>ConnectionRouter</code> used to layout this connection. Will not * return <code>null</code>. * @return this connection's router */ @Override public ConnectionRouter getConnectionRouter() { return connectionRouter; } /** * Returns this connection's routing constraint from its connection router. May return * <code>null</code>. * @return the connection's routing constraint */ @Override public Object getRoutingConstraint() { if (getConnectionRouter() != null) return getConnectionRouter().getConstraint(this); return null; } /** * @return the anchor at the start of this polyline connection (may be null) */ @Override public ConnectionAnchor getSourceAnchor() { return startAnchor; } /** * @return the source decoration (may be null) */ protected RotatableDecoration getSourceDecoration() { return startArrow; } /** * @return the anchor at the end of this polyline connection (may be null) */ @Override public ConnectionAnchor getTargetAnchor() { return endAnchor; } /** * @return the target decoration (may be null) * * @since 2.0 */ protected RotatableDecoration getTargetDecoration() { return endArrow; } private void hookSourceAnchor() { if (getSourceAnchor() != null) getSourceAnchor().addAnchorListener(this); } private void hookTargetAnchor() { if (getTargetAnchor() != null) getTargetAnchor().addAnchorListener(this); } /** * Layouts this polyline. If the start and end anchors are present, the connection router * is used to route this, after which it is laid out. It also fires a moved method. */ @Override public void layout() { if (getSourceAnchor() != null && getTargetAnchor() != null) getConnectionRouter().route(this); super.layout(); bounds = null; repaint(); fireFigureMoved(); } /** * Called just before the receiver is being removed from its parent. Results in removing * itself from the connection router. * * @since 2.0 */ @Override public void removeNotify() { unhookSourceAnchor(); unhookTargetAnchor(); getConnectionRouter().remove(this); super.removeNotify(); } /** * Sets the connection router which handles the layout of this polyline. Generally set by * the parent handling the polyline connection. * @param cr the connection router */ @Override public void setConnectionRouter(ConnectionRouter cr) { if (cr == null) cr = ConnectionRouter.NULL; if (connectionRouter != cr) { connectionRouter.remove(this); Object old = connectionRouter; connectionRouter = cr; firePropertyChange(Connection.PROPERTY_CONNECTION_ROUTER, old, cr); revalidate(); } } /** * Sets the routing constraint for this connection. * @param cons the constraint */ @Override public void setRoutingConstraint(Object cons) { if (getConnectionRouter() != null) getConnectionRouter().setConstraint(this, cons); revalidate(); } /** * Sets the anchor to be used at the start of this polyline connection. * @param anchor the new source anchor */ @Override public void setSourceAnchor(ConnectionAnchor anchor) { unhookSourceAnchor(); getConnectionRouter().invalidate(this); startAnchor = anchor; if (getParent() != null) hookSourceAnchor(); revalidate(); } /** * Sets the decoration to be used at the start of the {@link Connection}. * @param dec the new source decoration * @since 2.0 */ public void setSourceDecoration(RotatableDecoration dec) { if (getSourceDecoration() != null) remove(getSourceDecoration()); startArrow = dec; if (dec != null) add(dec, new ArrowLocator(this, ConnectionLocator.SOURCE)); } /** * Sets the anchor to be used at the end of the polyline connection. Removes this listener * from the old anchor and adds it to the new anchor. * @param anchor the new target anchor */ @Override public void setTargetAnchor(ConnectionAnchor anchor) { unhookTargetAnchor(); getConnectionRouter().invalidate(this); endAnchor = anchor; if (getParent() != null) hookTargetAnchor(); revalidate(); } /** * Sets the decoration to be used at the end of the {@link Connection}. * @param dec the new target decoration */ public void setTargetDecoration(RotatableDecoration dec) { if (getTargetDecoration() != null) remove(getTargetDecoration()); endArrow = dec; if (dec != null) add(dec, new ArrowLocator(this, ConnectionLocator.TARGET)); } private void unhookSourceAnchor() { if (getSourceAnchor() != null) getSourceAnchor().removeAnchorListener(this); } private void unhookTargetAnchor() { if (getTargetAnchor() != null) getTargetAnchor().removeAnchorListener(this); } /* (non-Javadoc) * @see org.eclipse.draw2d.Figure#useLocalCoordinates() */ @Override protected boolean useLocalCoordinates() { return false; } /** * @see org.eclipse.draw2d.IFigure#setToolTip(IFigure) */ public void setToolTip(String toolTipString) { super.setToolTip(createToolTip(toolTipString)); } public IFigure createToolTip(List toolTipStrings) { return ToolTipUtil.createToolTip(toolTipStrings); } public IFigure createToolTip(String toolTipString) { return ToolTipUtil.createToolTip(toolTipString); } public void hilite(boolean value) { if( value ) { super.setForegroundColor(ColorConstants.darkBlue); setLineWidth(3); } else { super.setForegroundColor(defaultLineColor); setLineWidth(1); } } /* (non-Javadoc) * @see org.eclipse.draw2d.IFigure#setBackgroundColor(org.eclipse.swt.graphics.Color) */ @Override public void setForegroundColor(Color bg) { defaultLineColor = bg; super.setForegroundColor(bg); } public List getInternalPoints() { if( getPoints().size() > 0 ) { List ptList = new ArrayList(getPoints().size()/2); int[] points = getPoints().toIntArray(); for(int i=2; i<points.length-2; i++) { ptList.add( new Point(points[i], points[i+1])); i++; } return ptList; } return Collections.EMPTY_LIST; } }