/** * Connects the figure to the new connectableConnector. If there is no new connectableConnector * the connection reverts to its original one. */ public void trackEnd(Point anchor, Point lead, int modifiersEx) { ConnectionFigure f = getOwner(); // Change node type if ((modifiersEx & (InputEvent.META_DOWN_MASK | InputEvent.CTRL_DOWN_MASK | InputEvent.ALT_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK)) != 0 && (modifiersEx & InputEvent.BUTTON2_DOWN_MASK) == 0) { f.willChange(); int index = getBezierNodeIndex(); BezierPath.Node v = f.getNode(index); if (index > 0 && index < f.getNodeCount()) { v.mask = (v.mask + 3) % 4; } else if (index == 0) { v.mask = ((v.mask & BezierPath.C2_MASK) == 0) ? BezierPath.C2_MASK : 0; } else { v.mask = ((v.mask & BezierPath.C1_MASK) == 0) ? BezierPath.C1_MASK : 0; } f.setNode(index, v); f.changed(); fireHandleRequestSecondaryHandles(); } Point2D.Double p = view.viewToDrawing(lead); view.getConstrainer().constrainPoint(p); Connector target = findConnectionTarget(p, view.getDrawing()); if (target == null) { target = savedTarget; } setLocation(p); if (target != savedTarget) { disconnect(); connect(target); } getOwner().setLiner(savedLiner); getOwner().updateConnection(); connectableConnector = null; connectors = Collections.emptyList(); }
/** * AbstractConnectionHandle factors the common code for handles that can be used to change the * connection of a ConnectionFigure. * * <p>XXX - Undo/Redo is not implemented yet. * * @author Werner Randelshofer * @version 3.0 2007-05-18 Changed due to changes in the canConnect methods of the ConnectionFigure * interface. Shortened the name from AbstractChangeConnectionHandle to * AbstractConnectionHandle. <br> * 2.1 2006-02-16 Remove savedLiner from connection while tracking. <br> * 2.0 2006-01-14 Changed to support double coordinates. <br> * 1.0 2003-12-01 Derived from JHotDraw 5.4b1. */ public abstract class AbstractConnectionHandle extends AbstractHandle { private Connector savedTarget; private Connector connectableConnector; private Figure connectableFigure; private Point start; /** * We temporarily remove the Liner from the connection figure, while the handle is being moved. We * store the Liner here, and add it back when the user has finished the interaction. */ private Liner savedLiner; /** All connectors of the connectable Figure. */ protected Collection<Connector> connectors = Collections.emptyList(); /** Initializes the change connection handle. */ protected AbstractConnectionHandle(ConnectionFigure owner) { super(owner); } public ConnectionFigure getOwner() { return (ConnectionFigure) super.getOwner(); } public boolean isCombinableWith(Handle handle) { return false; } /** Returns the connector of the change. */ protected abstract Connector getTarget(); /** Disconnects the connection. */ protected abstract void disconnect(); /** Connect the connection with the given figure. */ protected abstract void connect(Connector c); /** Sets the location of the connectableConnector point. */ protected abstract void setLocation(Point2D.Double p); /** Returns the start point of the connection. */ protected abstract Point2D.Double getLocation(); /** Gets the side of the connection that is unaffected by the change. */ protected Connector getSource() { if (getTarget() == getOwner().getStartConnector()) { return getOwner().getEndConnector(); } return getOwner().getStartConnector(); } /** Disconnects the connection. */ public void trackStart(Point anchor, int modifiersEx) { savedTarget = getTarget(); start = anchor; savedLiner = getOwner().getLiner(); getOwner().setLiner(null); // disconnect(); fireHandleRequestSecondaryHandles(); } /** Finds a new connectableConnector of the connection. */ public void trackStep(Point anchor, Point lead, int modifiersEx) { Point2D.Double p = view.viewToDrawing(lead); view.getConstrainer().constrainPoint(p); connectableFigure = findConnectableFigure(p, view.getDrawing()); if (connectableFigure != null) { Connector aTarget = findConnectionTarget(p, view.getDrawing()); if (aTarget != null) { p = aTarget.getAnchor(); } } getOwner().willChange(); setLocation(p); getOwner().changed(); repaintConnectors(); } /** * Connects the figure to the new connectableConnector. If there is no new connectableConnector * the connection reverts to its original one. */ public void trackEnd(Point anchor, Point lead, int modifiersEx) { ConnectionFigure f = getOwner(); // Change node type if ((modifiersEx & (InputEvent.META_DOWN_MASK | InputEvent.CTRL_DOWN_MASK | InputEvent.ALT_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK)) != 0 && (modifiersEx & InputEvent.BUTTON2_DOWN_MASK) == 0) { f.willChange(); int index = getBezierNodeIndex(); BezierPath.Node v = f.getNode(index); if (index > 0 && index < f.getNodeCount()) { v.mask = (v.mask + 3) % 4; } else if (index == 0) { v.mask = ((v.mask & BezierPath.C2_MASK) == 0) ? BezierPath.C2_MASK : 0; } else { v.mask = ((v.mask & BezierPath.C1_MASK) == 0) ? BezierPath.C1_MASK : 0; } f.setNode(index, v); f.changed(); fireHandleRequestSecondaryHandles(); } Point2D.Double p = view.viewToDrawing(lead); view.getConstrainer().constrainPoint(p); Connector target = findConnectionTarget(p, view.getDrawing()); if (target == null) { target = savedTarget; } setLocation(p); if (target != savedTarget) { disconnect(); connect(target); } getOwner().setLiner(savedLiner); getOwner().updateConnection(); connectableConnector = null; connectors = Collections.emptyList(); } private Connector findConnectionTarget(Point2D.Double p, Drawing drawing) { Figure targetFigure = findConnectableFigure(p, drawing); if (getSource() == null && targetFigure != null) { return findConnector(p, targetFigure, getOwner()); } else if (targetFigure != null) { Connector target = findConnector(p, targetFigure, getOwner()); if ((targetFigure != null) && targetFigure.canConnect() && targetFigure != savedTarget && !targetFigure.includes(getOwner()) && (canConnect(getSource(), target) || getTarget() != null && getTarget().getOwner() == targetFigure)) { return target; } } return null; } protected abstract boolean canConnect(Connector existingEnd, Connector targetEnd); protected Connector findConnector(Point2D.Double p, Figure f, ConnectionFigure prototype) { return f.findConnector(p, prototype); } /** Draws this handle. */ public void draw(Graphics2D g) { Graphics2D gg = (Graphics2D) g.create(); gg.transform(view.getDrawingToViewTransform()); for (Connector c : connectors) { c.draw(gg); } gg.dispose(); drawCircle(g, (getTarget() == null) ? Color.red : Color.green, Color.black); } private Figure findConnectableFigure(Point2D.Double p, Drawing drawing) { for (Figure f : drawing.getFiguresFrontToBack()) { if (!f.includes(getOwner()) && f.canConnect() && f.contains(p)) { return f; } } return null; } protected void setPotentialTarget(Connector newTarget) { this.connectableConnector = newTarget; } protected Rectangle basicGetBounds() { // if (connection.getPointCount() == 0) return new Rectangle(0, 0, getHandlesize(), // getHandlesize()); Point center = view.drawingToView(getLocation()); return new Rectangle( center.x - getHandlesize() / 2, center.y - getHandlesize() / 2, getHandlesize(), getHandlesize()); } protected BezierFigure getBezierFigure() { return (BezierFigure) getOwner(); } protected abstract int getBezierNodeIndex(); @Override public final Collection<Handle> createSecondaryHandles() { LinkedList<Handle> list = new LinkedList<Handle>(); if (((ConnectionFigure) getOwner()).getLiner() == null && savedLiner == null) { int index = getBezierNodeIndex(); BezierFigure f = getBezierFigure(); BezierPath.Node v = f.getNode(index); if ((v.mask & BezierPath.C1_MASK) != 0 && (index != 0 || f.isClosed())) { list.add(new BezierControlPointHandle(f, index, 1)); } if ((v.mask & BezierPath.C2_MASK) != 0 && (index < f.getNodeCount() - 1 || f.isClosed())) { list.add(new BezierControlPointHandle(f, index, 2)); } if (index > 0 || f.isClosed()) { int i = (index == 0) ? f.getNodeCount() - 1 : index - 1; v = f.getNode(i); if ((v.mask & BezierPath.C2_MASK) != 0) { list.add(new BezierControlPointHandle(f, i, 2)); } } if (index < f.getNodeCount() - 2 || f.isClosed()) { int i = (index == f.getNodeCount() - 1) ? 0 : index + 1; v = f.getNode(i); if ((v.mask & BezierPath.C1_MASK) != 0) { list.add(new BezierControlPointHandle(f, i, 1)); } } } return list; } protected BezierPath.Node getBezierNode() { int index = getBezierNodeIndex(); return getBezierFigure().getNodeCount() > index ? getBezierFigure().getNode(index) : null; } public String getToolTipText(Point p) { ConnectionFigure f = (ConnectionFigure) getOwner(); if (f.getLiner() == null && savedLiner == null) { ResourceBundleUtil labels = ResourceBundleUtil.getLAFBundle("org.jhotdraw.draw.Labels"); BezierPath.Node node = getBezierNode(); return (node == null) ? null : labels.getFormatted( "bezierNodeHandle.tip", labels.getFormatted( (node.getMask() == 0) ? "bezierNode.linearNode" : ((node.getMask() == BezierPath.C1C2_MASK) ? "bezierNode.cubicNode" : "bezierNode.quadraticNode"))); } else { return null; } } /** * Updates the list of connectors that we draw when the user moves or drags the mouse over a * figure to which can connect. */ public void repaintConnectors() { Rectangle2D.Double invalidArea = null; for (Connector c : connectors) { if (invalidArea == null) { invalidArea = c.getDrawingArea(); } else { invalidArea.add(c.getDrawingArea()); } } connectors = (connectableFigure == null) ? new java.util.LinkedList<Connector>() : connectableFigure.getConnectors(getOwner()); for (Connector c : connectors) { if (invalidArea == null) { invalidArea = c.getDrawingArea(); } else { invalidArea.add(c.getDrawingArea()); } } if (invalidArea != null) { view.getComponent().repaint(view.drawingToView(invalidArea)); } } }