/*
* TouchGraph LLC. Apache-Style Software License
*
*
* Copyright (c) 2002 Alexander Shapiro. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by
* TouchGraph LLC (http://www.touchgraph.com/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "TouchGraph" or "TouchGraph LLC" must not be used to endorse
* or promote products derived from this software without prior written
* permission. For written permission, please contact
* alex@touchgraph.com
*
* 5. Products derived from this software may not be called "TouchGraph",
* nor may "TouchGraph" appear in their name, without prior written
* permission of alex@touchgraph.com.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL TOUCHGRAPH OR ITS CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
*/
/*
* Modifications by Miika Nurminen (minurmin@cc.jyu.fi) for KeyGraph.
* Fixed node label positioning to work correctly with Linux.
* 31.12.2003.
*/
package com.touchgraph.graphlayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.util.Date;
import java.util.Vector;
/** Node.
*
* @author Alexander Shapiro
* @author Murray Altheim (2001-11-06; added support for round rects and alternate Node colors)
* @version 1.20
*/
public class Node {
/** This Node's type is a Rectangle. */
public final static int TYPE_RECTANGLE = 1;
/** This Node's type is a Round Rectangle. */
public final static int TYPE_ROUNDRECT = 2;
/** This Node's type is an Ellipse. */
public final static int TYPE_ELLIPSE = 3;
public static final String AUTO_ID_STRING = "AutoID ";
public static final Font SMALL_TAG_FONT = new Font("Courier",Font.PLAIN,9);
// Variables that store default values for colors + fonts + node type
public static Color BACK_FIXED_COLOR = Color.red;
public static Color BACK_SELECT_COLOR = new Color(255, 224, 0);
public static Color BACK_DEFAULT_COLOR = new Color(208, 96, 0);
public static Color BACK_HILIGHT_COLOR = Color.decode("#ffb200"); // altheim: new
public static Color BORDER_DRAG_COLOR = Color.black;
public static Color BORDER_MOUSE_OVER_COLOR = new Color(160,160,160);
public static Color BORDER_INACTIVE_COLOR = Color.white;
public static Color TEXT_COLOR = Color.white;
public static Font TEXT_FONT = new Font("Courier",Font.PLAIN,12);
public static int DEFAULT_TYPE = 1;
/** an int indicating the Node type.
* @see TYPE_RECTANGLE
* @see TYPE_ROUNDRECT
* @see TYPE_ELLIPSE
*/
protected int typ = TYPE_RECTANGLE;
private String id;
public double drawx;
public double drawy;
protected FontMetrics fontMetrics;
protected Font font;
protected String lbl;
protected Color backColor = BACK_DEFAULT_COLOR;
protected Color textColor = TEXT_COLOR;
protected boolean visible;
public double x;
public double y;
protected double dx; //Used by layout
protected double dy; //Used by layout
protected boolean fixed;
protected int repulsion; //Used by layout
public boolean justMadeLocal = false;
public boolean markedForRemoval = false;
public int localEdgeCount;
private Vector edges;
// ............
/** Minimal constructor which will generate an ID value from Java's Date class.
* Defaults will be used for type and color. The label will be taken from the ID value.
*/
public Node()
{
initialize(null);
lbl = id;
}
/** Constructor with the required ID id, using defaults
* for type (rectangle), color (a static variable from TGPanel).
* The Node's label will be taken from the ID value.
*/
public Node( String id )
{
initialize(id);
lbl = id;
}
/** Constructor with Strings for ID id and label, using defaults
* for type (rectangle) and color (a static variable from TGPanel).
* If the label is null, it will be taken from the ID value.
*/
public Node( String id, String label )
{
initialize(id);
if ( label == null ) lbl = id;
else lbl = label;
}
/** Constructor with a String ID id, an int type, Background Color bgColor,
* and a String label. If the label is null, it will be taken from the ID value.
* @see TYPE_RECTANGLE
* @see TYPE_ROUNDRECT
*/
public Node( String id, int type, Color color, String label )
{
initialize(id);
typ = type;
backColor = color;
if ( label == null ) lbl = id;
else lbl = label;
}
private void initialize( String identifier ) {
if (identifier != null)
this.id = identifier;
else
this.id = AUTO_ID_STRING+new Date().getTime();
edges = new Vector();
x = Math.random()*2-1; // If multiple nodes are added without repositioning,
y = Math.random()*2-1; // randomizing starting location causes them to spread out nicely.
repulsion = 100;
font = TEXT_FONT;
fixed = false;
typ = DEFAULT_TYPE;
localEdgeCount=0;
}
// setters and getters ...............
public static void setNodeBackFixedColor( Color color ) { BACK_FIXED_COLOR = color; }
public static void setNodeBackSelectColor( Color color ) { BACK_SELECT_COLOR = color; }
public static void setNodeBackDefaultColor( Color color ) { BACK_DEFAULT_COLOR = color; }
public static void setNodeBackHilightColor( Color color ) { BACK_HILIGHT_COLOR = color; }
public static void setNodeBorderDragColor( Color color ) { BORDER_DRAG_COLOR = color; }
public static void setNodeBorderMouseOverColor( Color color ) { BORDER_MOUSE_OVER_COLOR = color; }
public static void setNodeBorderInactiveColor( Color color ) { BORDER_INACTIVE_COLOR = color; }
public static void setNodeTextColor( Color color ) { TEXT_COLOR = color; }
public static void setNodeTextFont( Font font ) { TEXT_FONT = font; }
public static void setNodeType( int type ) { DEFAULT_TYPE = type; }
/** Set the ID of this Node to the String id.
*/
public void setID( String id ) {
this.id = id;
}
/** Return the ID of this Node as a String.
*/
public String getID() {
return id;
}
/** Set the location of this Node provided the Point p.
*/
public void setLocation( Point p ) {
this.x = p.x;
this.y = p.y;
}
/** Return the location of this Node as a Point.
*/
public Point getLocation() {
return new Point((int)x,(int)y);
}
/** Set the visibility of this Node to the boolean v.
*/
public void setVisible( boolean v) {
visible = v;
}
/** Return the visibility of this Node as a boolean.
*/
public boolean isVisible() {
return visible;
}
/** Set the type of this Node to the int type.
* @see TYPE_RECTANGLE
* @see TYPE_ROUNDRECT
* @see TYPE_ELLIPSE
*/
public void setType( int type ) {
typ = type;
}
/** Return the type of this Node as an int.
* @see TYPE_RECTANGLE
* @see TYPE_ROUNDRECT
* @see TYPE_ELLIPSE
*/
public int getType() {
return typ;
}
/** Set the font of this Node to the Font font. */
public void setFont( Font font ) {
this.font = font;
}
/** Returns the font of this Node as a Font*/
public Font getFont() {
return font;
}
/** Set the background color of this Node to the Color bgColor. */
public void setBackColor( Color bgColor ) {
backColor = bgColor;
}
/** Return the background color of this Node as a Color.
*/
public Color getBackColor() {
return backColor;
}
/** Set the text color of this Node to the Color txtColor. */
public void setTextColor( Color txtColor ) {
textColor = txtColor;
}
/** Return the text color of this Node as a Color.
*/
public Color getTextColor() {
return textColor;
}
/** Set the label of this Node to the String label. */
public void setLabel( String label ) {
lbl = label;
}
/** Return the label of this Node as a String.
*/
public String getLabel() {
return lbl;
}
/** Set the fixed status of this Node to the boolean fixed. */
public void setFixed( boolean fixed ) {
this.fixed = fixed;
}
/** Returns true if this Node is fixed (in place).
*/
public boolean getFixed() {
return fixed;
}
// ....
/** Returns the number of Edges attached to this Node. */
public int edgeNum() {
return edges.size();
}
/** Returns the local Edge count. */
public int localEdgeNum() {
return localEdgeCount;
}
/** Return the Edge at int index. */
public Edge edgeAt( int index ) {
return (Edge)edges.elementAt(index);
}
/** Add the Edge edge to the graph. */
public void addEdge( Edge edge ) {
if ( edge == null ) return;
edges.addElement(edge);
}
/** Remove the Edge edge from the graph. */
public void removeEdge( Edge edge ) {
edges.removeElement(edge);
}
/** Return the width of this Node. */
public int getWidth() {
if ( fontMetrics != null && lbl != null ) {
return fontMetrics.stringWidth(lbl) + 12;
} else {
return 10;
}
}
/** Return the height of this Node. */
public int getHeight() {
if ( fontMetrics != null ) {
return fontMetrics.getHeight() + 6;
} else {
return 6;
}
}
/** Returns true if this Node intersects Dimension d. */
public boolean intersects( Dimension d ) {
return ( drawx > 0 && drawx < d.width && drawy>0 && drawy < d.height );
}
/** Returns true if this Node contains the Point px,py. */
public boolean containsPoint( double px, double py ) {
return (( px > drawx-getWidth()/2) && ( px < drawx+getWidth()/2)
&& ( py > drawy-getHeight()/2) && ( py < drawy+getHeight()/2));
}
/** Returns true if this Node contains the Point p. */
public boolean containsPoint( Point p ) {
return (( p.x > drawx-getWidth()/2) && ( p.x < drawx+getWidth()/2)
&& ( p.y > drawy-getHeight()/2) && ( p.y < drawy+getHeight()/2));
}
/** Paints the Node. */
public void paint( Graphics g, TGPanel tgPanel ) {
if (!intersects(tgPanel.getSize()) ) return;
paintNodeBody(g, tgPanel);
if ( localEdgeNum()