//Copyright (c)2005 Holobloc Inc.
//Contributed to the OOONEIDA FBench project under the Common Public License.
package fbench.graph;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import org.w3c.dom.Element;
/**
* An edge of a directed graph.
*
* @author JHC
* @version 20051010/JHC - Made path a polyline.
* @version 20050630/JHC
*/
public abstract class GraphEdge extends GraphElement {
/**
* The x-coordinates of the path to be used to draw the element in the
* parent GraphView's coordinate system.
*/
protected int[] pathx = { 0, 0 };
/**
* The y-coordinates of the path to be used to draw the element in the
* parent GraphView's coordinate system.
*/
protected int[] pathy = { 0, 0 };
/** The cached source component for this edge. */
protected Component source = null;
/** The cached destination component for this edge. */
protected Component dest = null;
/**
* Initializes an edge of a directed graph corresponding to the given DOM
* Element.
*/
public GraphEdge() {
super();
setOpaque(false);
setBorder(GraphElement.emborder);
}
/** The color for selected elements of this type. */
protected Color getSelectionColor() {
return Color.red;
}
/** The color for deselected elements of this type. */
protected Color getDeselectedColor() {
return Color.black;
}
/**
* Returns the source node of this edge with lazy initialization, or <TT>
* null</TT> if none is found.
*/
protected Component getSource() {
if (source == null)
source = getEndPtComponent(true);
return source;
}
/**
* Searches for and answers the component at the specified end point of this
* edge, or <TT>null</TT> if none is found.
*
* @param findSource <TT>true</TT> if searching for source, <TT>false
* </TT> if searching for destination.
*/
protected abstract Component getEndPtComponent(boolean findSource);
/**
* Returns the destination node of this edge with lazy initialization, or
* <TT>null</TT> if none is found.
*/
protected Component getDest() {
if (dest == null)
dest = getEndPtComponent(false);
return dest;
}
/**
* Gets the node with the given name from the parent container. If no node
* exists with the given name, returns <TT>null</TT>.
*/
protected GraphNode getNodeNamed(String nname) {
Component[] comps = getParent().getComponents();
for (int i = 0; i < comps.length; i++) {
Component ge = comps[i];
if (!(ge instanceof GraphNode))
continue;
GraphNode gn = (GraphNode) ge;
if (gn.model.getName().equals(nname))
return gn;
}
return null;
}
/**
* Returns the point from which to begin drawing the edge. Default is the
* center of the source element, or <TT>null</TT> if the source does not
* exist.
*/
public Point getSourcePoint() {
return GraphElement.getCenter(GraphEdge.getBounds(getSource()));
}
/**
* Returns the point from which to end drawing the edge. Default is the
* center of the destination element, or <TT>null</TT> if the destination
* does not exist.
*/
public Point getDestPoint() {
return GraphElement.getCenter(GraphEdge.getBounds(getDest()));
}
/**
* Returns the preferred bounds of the graph element. Default is the bounds
* of the drawn path.
*/
public Rectangle getPreferredBounds() {
updatePath();
int maxx = pathx[0], minx = maxx, maxy = pathy[0], miny = maxy;
for (int i = 1; i < pathx.length; i++) {
maxx = Math.max(maxx, pathx[i]);
minx = Math.min(minx, pathx[i]);
maxy = Math.max(maxy, pathy[i]);
miny = Math.min(miny, pathy[i]);
}
return new Rectangle(minx - 2, miny - 2, maxx - minx + 5, maxy - miny
+ 5);
}
/**
* Returns <TT>true</TT> if the given point is within 3 units of the path
* from source to destination.
*/
public boolean contains(int x, int y) {
Point p = getLocation();
Rectangle r = new Rectangle(x + p.x - 3, y + p.y - 3, 6, 6);
for (int i = 0; i < (pathx.length - 1); i++) {
if (r
.intersectsLine(pathx[i], pathy[i], pathx[i + 1],
pathy[i + 1]))
return true;
}
return false;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Point p = getLocation();
g.translate(-p.x, -p.y);
Color oldcolor = g.getColor();
g.setColor(isSelected() ? getSelectionColor() : getDeselectedColor());
g.drawPolyline(pathx, pathy, pathx.length);
g.setColor(oldcolor);
g.translate(p.x, p.y);
}
/**
* Updates the path used to draw the element. By default, this is a straight
* line from source to destination.
*/
public void updatePath() {
Point src = getSourcePoint();
if (src != null) {
pathx[0] = src.x;
pathy[0] = src.y;
}
Point dst = getDestPoint();
if (dst != null) {
int n = pathx.length - 1;
pathx[n] = dst.x;
pathy[n] = dst.y;
}
}
public Integer getPreferredLayer() {
return GraphView.EDGE_LAYER;
}
public void setElement(Element el) {
super.setElement(el);
source = null;
dest = null;
}
/**
* Computes the bounds in graph space of the given Component, which may be
* contained in a hierarchy of GraphNodes.
*
* @return The computed bounds, or <TT>null</TT> if the given Component is
* <TT>null</TT>.
*/
/*public static final Rectangle getBounds(Component c) {
if (c == null)
return null;
Rectangle ans = c.getBounds();
for (Container p = c.getParent(); p instanceof GraphNode; p = p
.getParent()) {
ans.x += p.getX();
ans.y += p.getY();
}
return ans;
}*/
/**
* Computes the bounds in graph space of the given Component, which may be
* contained in a hierarchy of GraphNodes.
*
* @return The computed bounds, or <TT>null</TT> if the given Component is
* <TT>null</TT>.
*/
public static final Rectangle getBounds(Component c) {
if (c == null)
return null;
Rectangle ans = c.getBounds();
for (Container p = c.getParent(); p instanceof GraphNode; p = p
.getParent())
{
if( p instanceof GraphNode )
{
if( ((GraphNode)p).superGraphNode == true ) // stop moving up list if this is set to be the top most
break;
//if( ((GraphNode)p).getName() == null) // stop moving up list if this has no name ("not important enough for a name... = no dice!") // TODO: gsha041.. this seems to work... and alternative work arounds are not nice
// break;
//System.out.println(((GraphNode)p).getName());
ans.x += p.getX();
ans.y += p.getY();
}
}
return ans;
}
}