diff options
Diffstat (limited to 'plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.tooling.runtime/src/org/eclipse/papyrus/infra/gmfdiag/tooling/runtime/linklf/policies/ConnectionBendpointEditPolicy2.java')
-rwxr-xr-x | plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.tooling.runtime/src/org/eclipse/papyrus/infra/gmfdiag/tooling/runtime/linklf/policies/ConnectionBendpointEditPolicy2.java | 1000 |
1 files changed, 1000 insertions, 0 deletions
diff --git a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.tooling.runtime/src/org/eclipse/papyrus/infra/gmfdiag/tooling/runtime/linklf/policies/ConnectionBendpointEditPolicy2.java b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.tooling.runtime/src/org/eclipse/papyrus/infra/gmfdiag/tooling/runtime/linklf/policies/ConnectionBendpointEditPolicy2.java new file mode 100755 index 00000000000..9fe76ba1020 --- /dev/null +++ b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.tooling.runtime/src/org/eclipse/papyrus/infra/gmfdiag/tooling/runtime/linklf/policies/ConnectionBendpointEditPolicy2.java @@ -0,0 +1,1000 @@ +/***************************************************************************** + * Copyright (c) (c) 2002, 2007 IBM Corporation, 2014 CEA LIST and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * + *****************************************************************************/ + +package org.eclipse.papyrus.infra.gmfdiag.tooling.runtime.linklf.policies; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.draw2d.AbsoluteBendpoint; +import org.eclipse.draw2d.AutomaticRouter; +import org.eclipse.draw2d.Bendpoint; +import org.eclipse.draw2d.BendpointLocator; +import org.eclipse.draw2d.Connection; +import org.eclipse.draw2d.ConnectionAnchor; +import org.eclipse.draw2d.geometry.Dimension; +import org.eclipse.draw2d.geometry.Point; +import org.eclipse.draw2d.geometry.PointList; +import org.eclipse.draw2d.geometry.PrecisionPoint; +import org.eclipse.draw2d.geometry.PrecisionRectangle; +import org.eclipse.gef.AccessibleHandleProvider; +import org.eclipse.gef.ConnectionEditPart; +import org.eclipse.gef.EditPart; +import org.eclipse.gef.Request; +import org.eclipse.gef.commands.Command; +import org.eclipse.gef.editpolicies.SelectionHandlesEditPolicy; +import org.eclipse.gef.handles.BendpointCreationHandle; +import org.eclipse.gef.handles.BendpointMoveHandle; +import org.eclipse.gef.requests.BendpointRequest; +import org.eclipse.gmf.runtime.diagram.ui.editpolicies.ConnectionBendpointEditPolicy; +import org.eclipse.gmf.runtime.draw2d.ui.figures.FigureUtilities; +import org.eclipse.gmf.runtime.draw2d.ui.geometry.LineSeg; +import org.eclipse.gmf.runtime.draw2d.ui.geometry.PointListUtilities; +import org.eclipse.gmf.runtime.draw2d.ui.internal.figures.FeedbackConnection; +import org.eclipse.gmf.runtime.draw2d.ui.mapmode.MapModeUtil; +import org.eclipse.gmf.runtime.gef.ui.internal.editpolicies.LineMode; +import org.eclipse.gmf.runtime.gef.ui.internal.handles.BendpointCreationInvisibleHandle; +import org.eclipse.gmf.runtime.gef.ui.internal.handles.BendpointMoveHandleEx; +import org.eclipse.gmf.runtime.gef.ui.internal.handles.LineSegMoveInvisibleHandle; + +/** + * [GMFRT] make protected in + * {@link org.eclipse.gmf.runtime.gef.ui.internal.editpolicies.ConnectionBendpointEditPolicy} + * <p/> + * This class is a temporary workaround for bunch of private methods in the + * hierarchy of {@link ConnectionBendpointEditPolicy} we would like to override. + * <p/> + * We would like to avoid the mix of the copy-pasted now-protected code in this + * class with the actual modifications made in the + * {@link LinksLFConnectionBendpointEditPolicy}. + * <p/> + * The changes made in this class are: + * <ul> + * <li>{@link #showMoveOrthogonalBenspointFeedback()} is made protected</li> + * <li>{@link #showOutsideSourceFeedback()} is made protected</li> + * <li>{@link #showOutsideTargetFeedback()} is made protected</li> + * </ul> + * This class as a whole should be removed when the GMFT runtime will make the + * corresponding methods protected. + * <p/> + * This class is intentionally package local and should be removed after patch + * for bug 331779 is merged. + * + * @since 3.3 + * @see also {@link ConnectionBendpointEditPolicy3} which is parallel + * replacement for a similarly named + * {@link org.eclipse.gmf.runtime.diagram.ui.editpolicies.ConnectionBendpointEditPolicy} + * from gmf.runtime.diagram.ui + * @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=331779 + * + */ +@Deprecated +abstract class ConnectionBendpointEditPolicy2 extends + SelectionHandlesEditPolicy implements PropertyChangeListener { + + private static List NULL_CONSTRAINT = new ArrayList(); + private static final int STICKY_TOLERANCE_DP = 6; + + private LineMode lineSegMode = LineMode.OBLIQUE; + + static private class FeedbackState { + public List originalConstraint; + public Point ref1 = new Point(); + public Point ref2 = new Point(); + public boolean isDeleting = false; + public boolean isOutsideSource = false; + public boolean isOutsideTarget = false; + public boolean init = false; + } + + private FeedbackState feedbackState = null; + + private FeedbackState getFeedbackState() { + if (feedbackState == null) { + feedbackState = new FeedbackState(); + } + + return feedbackState; + } + + private boolean useRealtimeFeedback() { + return false; + } + + /** + * Constructor for EditPolicy + * + * @param lineSegMode + */ + public ConnectionBendpointEditPolicy2(LineMode lineSegMode) { + super(); + this.lineSegMode = lineSegMode; + } + + /** + * @return Returns the lineSegMode. + */ + public LineMode getLineSegMode() { + return lineSegMode; + } + + /** + * Adds a PropertyChangeListener to the Connection so we can react to point + * changes in the connection. + * + * @see SelectionHandlesEditPolicy#activate() + */ + public void activate() { + super.activate(); + getConnection().addPropertyChangeListener(Connection.PROPERTY_POINTS, + this); + } + + /** + * @return <code>Connection</code> representing drag source feedback + */ + protected Connection createDragSourceFeedbackConnection() { + if (useRealtimeFeedback()) { + // Use the actual figure for feedback + return getConnection(); + } else { + // Use a ghost rectangle for feedback + FeedbackConnection r = new FeedbackConnection(getConnection()); + addFeedback(r); + return r; + } + } + + /** + * Adds selection handles to the connection for the bendpoints. In this + * class, this method just decides if it is appropriate to add the handles, + * and then calls on the superclass to do the dirty work.s + */ + protected void addSelectionHandles() { + if (handles == null) + super.addSelectionHandles(); + else { + int count = handles.size(); + int points = getConnection().getPoints().size(); + if (count != points * 2 - 3) + super.addSelectionHandles(); + } + } + + /** + * @return list of manual handles + */ + protected List createManualHandles() { + List list = new ArrayList(); + ConnectionEditPart connEP = (ConnectionEditPart) getHost(); + PointList points = getConnection().getPoints(); + for (int i = 1; i < points.size() - 1; i++) { + addInvisibleCreationHandle(list, connEP, i - 1); + list.add(new BendpointMoveHandleEx(connEP, i, new BendpointLocator( + getConnection(), i))); + } + addInvisibleCreationHandle(list, connEP, points.size() - 2); + return list; + } + + /** + * Method addInvisibleCreationHandle. This handle is necessary for the + * accessibility feature to allow keyboard navigation to the add bendpoint + * feature. + * + * @param list + * @param connEP + * @param i + */ + protected void addInvisibleCreationHandle(List list, + ConnectionEditPart connEP, int i) { + if (getLineSegMode() != LineMode.OBLIQUE) { + list.add(new LineSegMoveInvisibleHandle(connEP, i)); + } else { + list.add(new BendpointCreationInvisibleHandle(connEP, i)); + } + } + + /** + * Creates selection handles for the bendpoints. Explicit (user-defined) + * bendpoints will have {@link BendpointMoveHandle}s on them with a single + * {@link BendpointCreationHandle} between 2 consecutive explicit + * bendpoints. If implicit bendpoints (such as those created by the + * {@link AutomaticRouter}) are used, one {@link BendpointCreationHandle} is + * placed in the middle of the Connection. + */ + protected List createSelectionHandles() { + return createManualHandles(); + } + + /** + * Removes this from the Connection's list of PropertyChangeListeners. + * + * @see SelectionHandlesEditPolicy#deactivate() + */ + public void deactivate() { + getConnection().removePropertyChangeListener( + Connection.PROPERTY_POINTS, this); + + super.deactivate(); + } + + /** + * Erases bendpoint feedback. Since the original figure is used for + * feedback, we just restore the original constraint that was saved before + * feedback started to show. + */ + protected void eraseConnectionFeedback(BendpointRequest request, + boolean removeFeedbackFigure) { + restoreOriginalConstraint(); + getFeedbackState().originalConstraint = null; + if (removeFeedbackFigure) + feedbackState = null; + } + + /** + * Erases feedback, when appropriate. + * + * @see #eraseConnectionFeedback(BendpointRequest, boolean) + */ + public void eraseSourceFeedback(Request request) { + if (REQ_MOVE_BENDPOINT.equals(request.getType()) + || REQ_CREATE_BENDPOINT.equals(request.getType())) + eraseConnectionFeedback((BendpointRequest) request, true); + } + + /** + * Returns the appropriate Command for the request type given. Handles + * creating, moving and deleting bendpoints. The actual creation of the + * command is taken care of by subclasses implementing the appropriate + * methods. + * + * @see #getCreateBendpointCommand(BendpointRequest) + * @see #getMoveBendpointCommand(BendpointRequest) + * @see #getDeleteBendpointCommand(BendpointRequest) + */ + public Command getCommand(Request request) { + if (REQ_MOVE_BENDPOINT.equals(request.getType())) { + if (getLineSegMode() != LineMode.OBLIQUE) { + return getMoveLineSegCommand((BendpointRequest) request); + } else { + if (getFeedbackState().isDeleting) + return getDeleteBendpointCommand((BendpointRequest) request); + return getMoveBendpointCommand((BendpointRequest) request); + } + } + if (REQ_CREATE_BENDPOINT.equals(request.getType())) + return getCreateBendpointCommand((BendpointRequest) request); + + return null; + } + + /** + * Returns the Connection associated with this EditPolicy. + */ + protected Connection getConnection() { + return (Connection) ((ConnectionEditPart) getHost()).getFigure(); + } + + /** + * @return Point cached value representing the first reference point. + */ + private Point getFirstReferencePoint() { + return getFeedbackState().ref1; + } + + /** + * @return Point cached value representing the second reference point. + */ + private Point getSecondReferencePoint() { + return getFeedbackState().ref2; + } + + /** + * Utility method to determine if point p passes through the line segment + * defined by p1 and p2. + * + * @param p1 + * Point that is the first point in the line segment to test + * against. + * @param p2 + * Point that is the second point in the line segment to test + * against. + * @param p + * Point that is tested to see if it falls in the line segment + * defined by p1 and p2. + * @return true if line segment contains Point p, false otherwise. + */ + private boolean lineContainsPoint(Point p1, Point p2, Point p) { + LineSeg line = new LineSeg(p1, p2); + return line.containsPoint(p, getStickyTolerance() / 3); + } + + /** + * Adds selection handles to the Connection, if it is selected, when the + * points property changes. Since we only listen for changes in the points + * property, this method is only called when the points of the Connection + * have changed. + */ + public void propertyChange(PropertyChangeEvent evt) { + if (getHost().getSelected() != EditPart.SELECTED_NONE) { + // int count = handles.size(); + // int points = getConnection().getPoints().size(); + // if (count != points * 2 - 3) + addSelectionHandles(); + } + } + + /** + * Restores the original constraint that was saved before feedback began to + * show. + */ + protected void restoreOriginalConstraint() { + if (getFeedbackState().originalConstraint != null) { + Assert.isTrue(getFeedbackState().originalConstraint.size() >= 2); + getConnection().setRoutingConstraint( + getFeedbackState().originalConstraint); + } + } + + /** + * Since the original figure is used for feedback, this method saves the + * original constraint, so that is can be restored when the feedback is + * erased. + */ + protected void saveOriginalConstraint() { + getFeedbackState().originalConstraint = (List) getConnection() + .getRoutingConstraint(); + if (getFeedbackState().originalConstraint == null) + getFeedbackState().originalConstraint = NULL_CONSTRAINT; + + if (getLineSegMode() != LineMode.OBLIQUE && !getFeedbackState().init) { + // Update the constraint based on the current figure + List newConstraint = new ArrayList( + getFeedbackState().originalConstraint.size()); + PointList pts = PointListUtilities.copyPoints(getConnection() + .getPoints()); + // OrthogonalRouterUtilities.resetEndPointsToCenter(getConnection(), + // pts); + + for (int i = 0; i < pts.size(); i++) { + Bendpoint abp = new AbsoluteBendpoint(pts.getPoint(i)); + newConstraint.add(abp); + } + + Assert.isTrue(getFeedbackState().originalConstraint.size() >= 2); + getConnection().setRoutingConstraint(newConstraint); + + // reset booleans + getFeedbackState().isOutsideSource = false; + getFeedbackState().isOutsideTarget = false; + } else { + // if the constraint and the connection figure points list don't + // match then reset the constraint + // based on the connection figure list. This could happen in certain + // cases - sepcifically when + // fan router detects a collision or when a self relation is routed. + int nConstraintSize = getFeedbackState().originalConstraint.size(); + PointList pts = getConnection().getPoints(); + int nPointSize = pts.size(); + + if (!getFeedbackState().init && nConstraintSize != nPointSize) { + + while (getFeedbackState().originalConstraint.size() > 0) { + getFeedbackState().originalConstraint.remove(0); + } + + for (int i = 0; i < pts.size(); i++) { + Bendpoint bpNew = new AbsoluteBendpoint(pts.getPoint(i)); + getFeedbackState().originalConstraint.add(i, bpNew); + } + } + + Assert.isTrue(getFeedbackState().originalConstraint.size() >= 2); + getConnection().setRoutingConstraint( + new ArrayList(getFeedbackState().originalConstraint)); + } + + getFeedbackState().init = true; + } + + /** + * Method setReferencePoints. This method will calculate the two end + * reference points for a point that is being moved or created. The + * reference points are used to determine if the request point can be + * deleted or not (for straight line tolerance). + * + * @param request + * BendpointRequest object containing index information. + */ + private void setReferencePoints(BendpointRequest request) { + if (getFeedbackState().originalConstraint == null) { + saveOriginalConstraint(); + } + + List constraint = (List) getConnection().getRoutingConstraint(); + Bendpoint bp = (Bendpoint) constraint.get(Math.max(0, + request.getIndex() - 1)); + getFeedbackState().ref1 = bp.getLocation(); + + bp = (Bendpoint) constraint.get(Math.min(request.getIndex() + 1, + constraint.size() - 1)); + getFeedbackState().ref2 = bp.getLocation(); + } + + private void setNewFeedbackConstraint(List constraint) { + Assert.isTrue(constraint.size() >= 2); + getConnection().setRoutingConstraint(constraint); + } + + /** + * Shows feedback when a bendpoint is being created. The original figure is + * used for feedback and the original constraint is saved, so that it can be + * restored when feedback is erased. + */ + protected void showCreateBendpointFeedback(BendpointRequest request) { + Point p = new Point(request.getLocation()); + List constraint; + + getConnection().translateToRelative(p); + + Bendpoint bp = new AbsoluteBendpoint(p); + if (getFeedbackState().originalConstraint == null) { + saveOriginalConstraint(); + constraint = (List) getConnection().getRoutingConstraint(); + constraint.add(request.getIndex() + 1, bp); + } else { + constraint = (List) getConnection().getRoutingConstraint(); + } + + stickyStraightLineFeedback(constraint, request.getIndex() + 1, bp); + + setNewFeedbackConstraint(constraint); + } + + /** + * Shows feedback when a bendpoint is being deleted. This method is only + * called once when the bendpoint is first deleted, not every mouse move. + * The original figure is used for feedback and the original constraint is + * saved, so that it can be restored when feedback is erased. + */ + protected void showDeleteBendpointFeedback(BendpointRequest request) { + if (getFeedbackState().originalConstraint == null) { + saveOriginalConstraint(); + List constraint = (List) getConnection().getRoutingConstraint(); + constraint.remove(request.getIndex()); + + setNewFeedbackConstraint(constraint); + } + } + + /** + * Shows feedback when a bendpoint is being moved. Also checks to see if the + * bendpoint should be deleted and then calls + * {@link #showDeleteBendpointFeedback(BendpointRequest)} if needed. The + * original figure is used for feedback and the original constraint is + * saved, so that it can be restored when feedback is erased. + */ + protected void showMoveBendpointFeedback(BendpointRequest request) { + Point p = new Point(request.getLocation()); + if (!getFeedbackState().isDeleting) { + setReferencePoints(request); + } + + getConnection().translateToRelative(p); + Bendpoint bp = new AbsoluteBendpoint(p); + + if (getFeedbackState().originalConstraint == null) { + saveOriginalConstraint(); + } + + if (lineContainsPoint(getFirstReferencePoint(), + getSecondReferencePoint(), p)) { + if (!getFeedbackState().isDeleting) { + getFeedbackState().isDeleting = true; + eraseConnectionFeedback(request, false); + showDeleteBendpointFeedback(request); + } + return; + } + if (getFeedbackState().isDeleting) { + getFeedbackState().isDeleting = false; + eraseConnectionFeedback(request, false); + } + + List constraint = (List) getConnection().getRoutingConstraint(); + stickyStraightLineFeedback(constraint, request.getIndex(), bp); + + setNewFeedbackConstraint(constraint); + } + + /** + * This method will set the constraint with the given bendpoint, with the + * additional behavior of "sticking" the point around a tolerance to a + * straight line. If it's within a tolerance of the previous point, stick it + * to the horizontal or vertical coordinates that make it straight. + */ + protected void stickyStraightLineFeedback(List constraint, int nIndex, + Bendpoint bp) { + Point ptLoc = new Point(bp.getLocation()); + + int sticky_tolerance = getStickyTolerance(); + + if (nIndex > 0) { + Point ptPrev; + if ((nIndex - 1) == 0) { + ptPrev = getConnection().getSourceAnchor().getReferencePoint(); + getConnection().translateToRelative(ptPrev); + } else + ptPrev = ((Bendpoint) constraint.get(nIndex - 1)).getLocation(); + + if (Math.abs(ptPrev.x - ptLoc.x) < sticky_tolerance) + ptLoc.x = ptPrev.x; + if (Math.abs(ptPrev.y - ptLoc.y) < sticky_tolerance) + ptLoc.y = ptPrev.y; + } + + if (nIndex < constraint.size() - 1) { + Point ptNext; + if ((nIndex + 1) == (constraint.size() - 1)) { + ptNext = getConnection().getTargetAnchor().getReferencePoint(); + getConnection().translateToRelative(ptNext); + } else + ptNext = ((Bendpoint) constraint.get(nIndex + 1)).getLocation(); + + if (Math.abs(ptNext.x - ptLoc.x) < sticky_tolerance) + ptLoc.x = ptNext.x; + if (Math.abs(ptNext.y - ptLoc.y) < sticky_tolerance) + ptLoc.y = ptNext.y; + } + + if (!ptLoc.equals(bp.getLocation())) { + Bendpoint bpNew = new AbsoluteBendpoint(ptLoc); + constraint.set(nIndex, bpNew); + } else { + constraint.set(nIndex, bp); + } + } + + private int getStickyTolerance() { + int sticky_tolerance = MapModeUtil.getMapMode(getConnection()).DPtoLP( + STICKY_TOLERANCE_DP); + return sticky_tolerance; + } + + /** + * Shows feedback, when appropriate. Calls a different method depending on + * the request type. + * + * @see #showCreateBendpointFeedback(BendpointRequest) + * @see #showMoveBendpointFeedback(BendpointRequest) + */ + public void showSourceFeedback(Request request) { + if (getLineSegMode() != LineMode.OBLIQUE) { + if (REQ_CREATE_BENDPOINT.equals(request.getType())) { + showMoveLineSegFeedback((BendpointRequest) request); + } else if (REQ_MOVE_BENDPOINT.equals(request.getType())) { + showMoveOrthogonalBenspointFeedback((BendpointRequest) request); + } + + } else { + if (REQ_MOVE_BENDPOINT.equals(request.getType())) + showMoveBendpointFeedback((BendpointRequest) request); + else if (REQ_CREATE_BENDPOINT.equals(request.getType())) + showCreateBendpointFeedback((BendpointRequest) request); + } + + super.showSourceFeedback(request); + } + + /** + * Method getBendpointsChangedCommand. This method will return a + * SetBendpointsCommand with the points retrieved from the user feedback in + * the figure. + * + * @param request + * BendpointRequest from the user gesture for moving / creating a + * bendpoint + * @return Command SetBendpointsCommand that contains the point changes for + * the connection. + */ + abstract protected Command getBendpointsChangedCommand( + BendpointRequest request); + + protected Command getCreateBendpointCommand(BendpointRequest request) { + return getBendpointsChangedCommand(request); + } + + protected Command getMoveBendpointCommand(BendpointRequest request) { + return getBendpointsChangedCommand(request); + } + + protected Command getDeleteBendpointCommand(BendpointRequest request) { + return getBendpointsChangedCommand(request); + } + + protected final LineSeg getLineSeg(List bendPoints, int nIndex) { + Point pt1 = new Point( + ((Bendpoint) bendPoints.get(nIndex - 1)).getLocation()); + Point pt2 = new Point( + ((Bendpoint) bendPoints.get(nIndex)).getLocation()); + + return new LineSeg(pt1, pt2); + } + + /** + * @param bendPoints + * @param nIndex + * @param newLine + */ + protected void setLineSeg(List bendPoints, int nIndex, LineSeg newLine) { + Bendpoint bp1 = new AbsoluteBendpoint(newLine.getOrigin()); + Bendpoint bp2 = new AbsoluteBendpoint(newLine.getTerminus()); + + bendPoints.set(nIndex - 1, bp1); + bendPoints.set(nIndex, bp2); + } + + /** + * @param request + * @return move line segment command + */ + protected Command getMoveLineSegCommand(BendpointRequest request) { + return getBendpointsChangedCommand(request); + } + + /** + * Method lineOutsideSource. Utility method to determine if the constraint + * needs to be adjusted becauase the line is outside of the source bounds. + * + * @param line + * LineSeg defining the new line moved by the user gesture + * @return boolean true if origin of line lies outside the starting source + * element, false otherwise. + */ + protected boolean lineOutsideSource(LineSeg line) { + + // check if end points are outside of bounds and if so - add a new point + PrecisionRectangle startRect = new PrecisionRectangle( + FigureUtilities.getAnchorableFigureBounds(getConnection() + .getSourceAnchor().getOwner())); + getConnection().getSourceAnchor().getOwner() + .translateToAbsolute(startRect); + if (getLineSegMode().equals(LineMode.ORTHOGONAL_CONSTRAINED)) { + if (line.isHorizontal()) { + startRect.shrink(0, 2); + } else { + startRect.shrink(2, 0); + } + } + + getConnection().translateToRelative(startRect); + /* + * Rectangle needs to be expanded by the "odd" number below because the + * number after translations could be N.999999999... + */ + if (!startRect.expand(0.000001, 0.000001).contains( + new PrecisionPoint(line.getOrigin()))) { + return true; + } + + return false; + } + + /** + * Method lineOutsideTarget. Utility method to determine if the constraint + * needs to be adjusted because the line is outside of the target bounds. + * + * @param line + * LineSeg defining the new line moved by the user gesture. + * @return boolean true if terminus of line lies outside the target element, + * false otherwise. + */ + protected boolean lineOutsideTarget(LineSeg line) { + + // check if end points are outside of bounds and if so - add a new point + PrecisionRectangle endRect = new PrecisionRectangle( + FigureUtilities.getAnchorableFigureBounds(getConnection() + .getTargetAnchor().getOwner())); + getConnection().getTargetAnchor().getOwner() + .translateToAbsolute(endRect); + if (getLineSegMode().equals(LineMode.ORTHOGONAL_CONSTRAINED)) { + if (line.isHorizontal()) { + endRect.shrink(0, 2); + } else { + endRect.shrink(2, 0); + } + } + + /* + * Rectangle needs to be expanded by the "odd" number below because the + * number after translations could be N.999999999... + */ + getConnection().translateToRelative(endRect); + if (!endRect.expand(0.00001, 0.00001).contains( + new PrecisionPoint(line.getTerminus()))) { + return true; + } + + return false; + } + + /** + * Method removeOutsideSourceFeedback. Removes a bendpoint from the + * beginning of the constraint. + * + * @param constraint + * List of bendpoints that the source point will be added too. + */ + protected void removeOutsideSourceFeedback(List constraint) { + constraint.remove(0); + } + + /** + * Method removeOutsideTargetFeedback. Removes a bendpoint from the end of + * the constraint. + * + * @param constraint + * List of bendpoints that the target point will be added too. + */ + protected void removeOutsideTargetFeedback(List constraint) { + constraint.remove(constraint.size() - 1); + } + + /** + * Draws feedback for moving a bend point of a rectilinear connection + * + * @param request + * Benndpoint request + */ + protected void showMoveOrthogonalBenspointFeedback(BendpointRequest request) { + if (getFeedbackState().originalConstraint == null) { + saveOriginalConstraint(); + } + + Point ptLoc = new Point(request.getLocation()); + List constraint = (List) getConnection().getRoutingConstraint(); + + getConnection().translateToRelative(ptLoc); + + int index = getFeedbackState().isOutsideSource ? request.getIndex() + 1 + : request.getIndex(); + + Point previous = ((Bendpoint) constraint.get(index - 1)).getLocation(); + Point moving = ((Bendpoint) constraint.get(index)).getLocation(); + Point next = ((Bendpoint) constraint.get(index + 1)).getLocation(); + + LineSeg originalFirst = new LineSeg(previous.getCopy(), + moving.getCopy()); + LineSeg originalSecond = new LineSeg(moving.getCopy(), next.getCopy()); + + Dimension diff = ptLoc.getDifference(moving); + + if (originalFirst.isHorizontal()) { + previous.y += diff.height; + next.x += diff.width; + } else { + previous.x += diff.width; + next.y += diff.height; + } + + LineSeg movedFirst = new LineSeg(previous, ptLoc.getCopy()); + LineSeg movedSecond = new LineSeg(ptLoc.getCopy(), next); + + index = adjustOutsideBoundsLineFeedback(movedFirst, index - 1, + constraint, originalFirst); + constraint.set(index, new AbsoluteBendpoint(movedFirst.getOrigin())); + constraint.set(index + 1, + new AbsoluteBendpoint(movedFirst.getTerminus())); + + index = adjustOutsideBoundsLineFeedback(movedSecond, index + 1, + constraint, originalSecond); + constraint.set(index + 1, + new AbsoluteBendpoint(movedSecond.getTerminus())); + + getConnection().setRoutingConstraint(constraint); + } + + /** + * Shows feedback when a line segment is being moved. Also checks to see if + * the bendpoint should be deleted and then calls + * {@link #showDeleteBendpointFeedback(BendpointRequest)} if needed. The + * original figure is used for feedback and the original constraint is + * saved, so that it can be restored when feedback is erased. + */ + protected void showMoveLineSegFeedback(BendpointRequest request) { + + if (getFeedbackState().originalConstraint == null) { + saveOriginalConstraint(); + } + + Point ptLoc = new Point(request.getLocation()); + List constraint = (List) getConnection().getRoutingConstraint(); + + getConnection().translateToRelative(ptLoc); + + // adjust request index to account for source bendpoint if needed + int index = getFeedbackState().isOutsideSource ? request.getIndex() + 1 + : request.getIndex(); + + LineSeg moveLine = getLineSeg(constraint, index + 1); + LineSeg newLine = moveLine.getParallelLineSegThroughPoint(ptLoc); + + index = adjustOutsideBoundsLineFeedback(newLine, index, constraint, + moveLine); + + setLineSeg(constraint, index + 1, newLine); + + getConnection().setRoutingConstraint(constraint); + } + + /** + * adjustOutsideBoundsLineFeedback Method to handle feedback where the line + * is dragged outside of the source or target shapes bounding box. + * + * @param newLine + * LineSeg representing the line currently being manipulated. + * @param index + * the index + * @param constraint + * List of Bendpoint objects that is the constraint to the + * gesture. + * @param moveLine + * original segment that is being manipulated + * @return int new index value after the constraint and feedback have been + * adjusted. + */ + private int adjustOutsideBoundsLineFeedback(LineSeg newLine, int index, + List constraint, LineSeg moveLine) { + if (getLineSegMode().equals(LineMode.ORTHOGONAL_CONSTRAINED)) { + // merely enforce the fact that we can't adjust the line outside the + // bounds of the source and target. + if ((index == 0 && lineOutsideSource(newLine)) + || ((index + 1 == constraint.size() - 1) && lineOutsideTarget(newLine))) { + newLine.setOrigin(moveLine.getOrigin()); + newLine.setTerminus(moveLine.getTerminus()); + } + + return index; + } + + boolean bRemoveSource = false; + boolean bRemoveTarget = false; + boolean bSetNewSource = false; + boolean bSetNewTarget = false; + + // Check source to see if we need to add a bendpoint + if (index == 0 && lineOutsideSource(newLine)) { + if (!getFeedbackState().isOutsideSource) { + getFeedbackState().isOutsideSource = true; + bSetNewSource = true; + } + } else if (index == 1 && getFeedbackState().isOutsideSource + && !lineOutsideSource(newLine)) { + getFeedbackState().isOutsideSource = false; + bRemoveSource = true; + } + + // Check target to see if we need to add a bendpoint + int checkTargetIndex = index + 1 + + (getFeedbackState().isOutsideTarget ? 1 : 0); + if ((checkTargetIndex == constraint.size() - 1) + && lineOutsideTarget(newLine)) { + if (!getFeedbackState().isOutsideTarget) { + getFeedbackState().isOutsideTarget = true; + bSetNewTarget = true; + } + } else if (checkTargetIndex == constraint.size() - 2 + && getFeedbackState().isOutsideTarget + && !lineOutsideTarget(newLine)) { + getFeedbackState().isOutsideTarget = false; + bRemoveTarget = true; + } + if (bRemoveSource) { + removeOutsideSourceFeedback(constraint); + index--; + } + + if (bRemoveTarget) { + removeOutsideTargetFeedback(constraint); + } + + if (bSetNewSource) { + showOutsideSourceFeedback(newLine, moveLine, constraint); + index++; + } + + if (bSetNewTarget) { + showOutsideTargetFeedback(newLine, moveLine, constraint); + } + return index; + } + + /** + * Method showOutsideSourceFeedback. Adds a bendpoint to the beginning of + * the constraint. Also adjusts the new segment with respect to added + * constraint + * + * @param constraint + * List of bendpoints that the source point will be added too. + */ + protected void showOutsideSourceFeedback(LineSeg newLine, LineSeg moveLine, + List constraint) { + Connection conn = (Connection) getHostFigure(); + ConnectionAnchor anchor = conn.getSourceAnchor(); + PrecisionPoint startPoint = new PrecisionPoint(anchor.getOwner() + .getBounds().getCenter()); + anchor.getOwner().translateToAbsolute(startPoint); + conn.translateToRelative(startPoint); + PrecisionRectangle bounds = new PrecisionRectangle(anchor.getOwner() + .getBounds()); + anchor.getOwner().translateToAbsolute(bounds); + conn.translateToRelative(bounds); + Point origin = new Point(newLine.getOrigin()); + if (moveLine.isHorizontal()) { + origin.x = startPoint.x; + } else { + origin.y = startPoint.y; + } + newLine.setOrigin(origin); + constraint.add(0, new AbsoluteBendpoint(startPoint)); + + } + + /** + * Method showOutsideTargetFeedback. Adds a bendpoint to the end of the + * constraint. Also adjusts the new segment with respect to added constraint + * + * @param constraint + * List of bendpoints that the target point will be added too. + */ + protected void showOutsideTargetFeedback(LineSeg newLine, LineSeg moveLine, + List constraint) { + Connection conn = (Connection) getHostFigure(); + ConnectionAnchor anchor = conn.getTargetAnchor(); + PrecisionPoint endPoint = new PrecisionPoint(anchor.getOwner() + .getBounds().getCenter()); + anchor.getOwner().translateToAbsolute(endPoint); + conn.translateToRelative(endPoint); + PrecisionRectangle bounds = new PrecisionRectangle(anchor.getOwner() + .getBounds()); + anchor.getOwner().translateToAbsolute(bounds); + conn.translateToRelative(bounds); + Point terminus = new Point(newLine.getTerminus()); + if (moveLine.isHorizontal()) { + terminus.x = endPoint.x; + } else { + terminus.y = endPoint.y; + } + newLine.setTerminus(terminus); + constraint.add(new AbsoluteBendpoint(endPoint)); + } + + /** + * Override for AccessibleHandleProvider when deactivated + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=69316 + * + * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class) + */ + public Object getAdapter(Class key) { + if (key == AccessibleHandleProvider.class) + // handles == null when deactivated + if (handles == null) { + return null; + } + return super.getAdapter(key); + } +} |