blob: 045473742677d2228bfca98aeba5de46ee6206bc [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2010 IBM Corporation 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.draw2d;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.draw2d.geometry.Transposer;
/**
* Used to place IFigures along the endpoint or starting point of a
* {@link Connection}. <code>uDistance</code> represents the distance from the
* Connection's owner to the IFigure. <code>vDistance</code> represents the
* distance from the IFigure to the Connection itself.
*/
public class ConnectionEndpointLocator implements Locator {
private boolean end;
private Connection conn;
private int uDistance;
private int vDistance;
private static Rectangle figureBounds;
/**
* Transposes the location if the connection point is along the top or
* bottom of its owner figure.
*/
protected Transposer transposer = new Transposer();
/**
* Constructs a ConnectionEndpointLocator using the given {@link Connection}
* . If <i>isEnd</i> is <code>true</code>, the location is relative to the
* Connection's end (or target) point. If <i>isEnd</i> is <code>false</code>
* , the location is relative to the Connection's start (or source) point.
*
* @param c
* The Connection
* @param isEnd
* <code>true</code> is location is relative to end point
* @since 2.0
*/
public ConnectionEndpointLocator(Connection c, boolean isEnd) {
end = isEnd;
conn = c;
uDistance = 14;
vDistance = 4;
figureBounds = new Rectangle();
}
/*
* Returns an integer representing the side of the passed Rectangle that a
* point lies on. 1 == Top 2 == Right 3 == Bottom 4 == Left
*
* @param loc The point that is to be located
*/
private int calculateConnectionLocation(Point loc, Point topLeft,
Point center) {
double m1, m2 = 0;
m1 = (double) (topLeft.y - center.y) / (double) (topLeft.x - center.x);
if (loc.x - center.x != 0)
m2 = (double) (loc.y - center.y) / (double) (loc.x - center.x);
if (loc.x == center.x) {
// Case where m2 is vertical
if (loc.y < center.y)
return 3;
else
return 1;
} else if (Math.abs(m2) <= Math.abs(m1)) {
// Connection start point along left or right side
if (loc.x < center.x)
return 4;
else
return 2;
} else {
// Connection start point along top or bottom
if (loc.y < center.y)
return 3;
else
return 1;
}
}
/*
* This method is used to calculate the "quadrant" value of a connection
* that does not have an owner on its starting point.
*
* 1 == Top 2 == Right 3 == Bottom 4 == Left
*
* @param startPoint The starting point of the connection.
*
* @param endPoint The end point of the connection.
*/
private int calculateConnectionLocation(Point startPoint, Point endPoint) {
if (Math.abs(endPoint.x - startPoint.x) > Math.abs(endPoint.y
- startPoint.y)) {
if (endPoint.x > startPoint.x)
return 2;
else
return 4;
} else {
if (endPoint.y > startPoint.y)
return 1;
else
return 3;
}
}
/*
* Calculates 'tan' which is used as a factor for y adjustment when placing
* the connection label. 'tan' is capped at 1.0 in the positive direction
* and -1.0 in the negative direction.
*
* @param startPoint The starting point of the connection.
*
* @param endPoint The end point of the connection.
*
* @since 2.0
*/
private double calculateTan(Point startPoint, Point endPoint) {
double tan = 0;
if (endPoint.x == startPoint.x)
tan = 1.0;
else
tan = (double) (endPoint.y - startPoint.y)
/ (double) (endPoint.x - startPoint.x);
if (tan > 1)
tan = 1.0;
else if (tan < -1)
tan = -1.0;
return tan;
}
private int calculateYShift(int figureWidth, int figureHeight) {
int yShift = 0;
if (vDistance < 0)
yShift = -figureHeight;
else if (vDistance == 0)
yShift = -figureHeight / 2;
return yShift;
}
private Connection getConnection() {
return conn;
}
private IFigure getConnectionOwner() {
IFigure connOwner;
if (isEnd())
connOwner = conn.getTargetAnchor().getOwner();
else
connOwner = conn.getSourceAnchor().getOwner();
return connOwner;
}
/**
* Returns the distance in pixels from the anchor's owner.
*
* @return the offset distance from the endpoint figure
*/
public int getUDistance() {
return uDistance;
}
/**
* Returns the distance in pixels from the connection
*
* @return the offset from the connection itself
*/
public int getVDistance() {
return vDistance;
}
private boolean isEnd() {
return end;
}
/**
* Relocates the given IFigure at either the source or target end of the
* Connection, based on the <code>boolean</code> given in the constructor
* {@link #ConnectionEndpointLocator(Connection, boolean)}.
*
* @param figure
* The figure to relocate
*/
public void relocate(IFigure figure) {
Connection conn = getConnection();
Point startPoint = Point.SINGLETON;
Point endPoint = new Point();
int startPointPosition = 0;
int endPointPosition = 1;
if (isEnd()) {
startPointPosition = conn.getPoints().size() - 1;
endPointPosition = startPointPosition - 1;
}
conn.getPoints().getPoint(startPoint, startPointPosition);
conn.getPoints().getPoint(endPoint, endPointPosition);
IFigure connOwner = getConnectionOwner();
int quadrant;
if (connOwner != null) {
Rectangle connOwnerBounds = connOwner.getBounds();
Point connOwnerCenter = connOwnerBounds.getCenter();
Point connOwnerTL = connOwnerBounds.getTopLeft();
quadrant = calculateConnectionLocation(startPoint, connOwnerTL,
connOwnerCenter);
} else
quadrant = calculateConnectionLocation(startPoint, endPoint);
int cos = 1;
transposer.setEnabled(false);
/*
* Label placement calculations are done as if the connection point is
* along the left or right side of the figure. If the connection point
* is along the top or bottom, values are transposed.
*/
if (quadrant == 1 || quadrant == 3)
transposer.setEnabled(true);
if (quadrant == 3 || quadrant == 4)
cos = -1;
Dimension figureSize = transposer.t(figure.getPreferredSize());
startPoint = transposer.t(startPoint);
endPoint = transposer.t(endPoint);
double tan = calculateTan(startPoint, endPoint);
int figureWidth = figureSize.width;
int figureHeight = figureSize.height;
int yShift = calculateYShift(figureWidth, figureHeight);
Point figurePoint = new Point(startPoint.x + (uDistance * cos)
+ figureWidth * ((cos - 1) / 2), (int) (startPoint.y + cos
* uDistance * tan + vDistance + yShift));
figureBounds.setSize(transposer.t(figureSize));
figureBounds.setLocation(transposer.t(figurePoint));
figure.setBounds(figureBounds);
}
/**
* Sets the distance in pixels from the Connection's owner.
*
* @param distance
* Number of pixels to place the ConnectionEndpointLocator from
* its owner.
* @since 2.0
*/
public void setUDistance(int distance) {
uDistance = distance;
}
/**
* Sets the distance in pixels from the Connection.
*
* @param distance
* Number of pixels to place the ConnectionEndpointLocator from
* its Connection.
* @since 2.0
*/
public void setVDistance(int distance) {
vDistance = distance;
}
}