DrawingObj
interface
* and hence can be freely added to the drawing panel using the
* addDrawingObj
method. e.g.
* TreeNode node = new TreeNode();
* drawingPanel.addDrawingObj(node);
*
* Any added drawing object can be remove from the panel by using the
* removeObj
method. e.g.
* drawingPanel.removeObj(node);
*
* @see DrawingPanel#addDrawingObj
* @see DrawingPanel#removeObj
*/
public class TreeNode extends Drawable {
protected int weight;
protected TreeNode left, right;
protected int depth = -1;
private boolean red; // Used by red-black trees
public static final Color DEF_TREENODE_COL = Color.red;
private Dimension node_size = new Dimension( 20, 30 );
/**
* Attribute to indicate if the left branch is to be highlighted.
*/
protected boolean highlightLeft = false;
/**
* Attribute to indicate if the right branch is to be highlighted.
*/
protected boolean highlightRight = false;
private static final boolean DEBUG = false;
/**
* Create a node with the left node as set and weight of the current node
* set to 0.
* @param node The left node of the newly created node.
*/
public TreeNode( TreeNode node ) {
left = node;
right = null;
weight = 0;
colour = DEF_TREENODE_COL;
}
/**
* Create a new node with weight 0.
*/
public TreeNode() {
// label = new String();
weight = 0;
left = right = null;
colour = DEF_TREENODE_COL;
}
/**
* Create a new leaf node with label and weight as specified in the
* parameters.
* @param label The label of the new node.
* @param weight The weight of the new node.
*/
public TreeNode(String label, int weight) {
this.label = label;
this.weight = weight;
left = right = null;
colour = DEF_TREENODE_COL;
} // Constructor 2
/**
* Create a new leaf node with the specified weight.
* @param weight The weight of the new node.
*/
public TreeNode( int weight ) {
// this.label = new String();
this.weight = weight;
left = right = null;
} // Constructor 3
/**
* Create a new leaf node with 0 weight and label as specified.
* @param label Label of the new node.
*/
public TreeNode( String label ) {
this.label = new String(label);
this.weight = 0;
left = right = null;
} // Constructor 4
/**
* Set the weight of this node.
* @param weight The weight to be assigned to this node.
*/
public void setWeight(int weight) {
this.weight = weight;
}
/**
* Set the label of this node.
* @param label The label to be assigned to this node.
*/
public void setLabel(String label) {
this.label = new String(label);
}
/**
* Get the weight of this node.
* @return Weight of this node.
*/
public int getWeight() {
return weight;
}
/**
* Get the label of this node.
* @return Label of this node.
*/
public String getLabel() {
return new String(label);
}
/**
* Link the left branch of this node to the node passed in as the parameter.
* @param node The new left child of this node.
*/
public void setLeft(TreeNode node) { left = node; }
public void setLeftTreeNode(TreeNode node) { left = node; }
/**
* Link the right branch of this node to
* the node passed in as the parameter.
* @param node The new right child of this node.
*
*/
public void setRight( TreeNode node ) { right = node; }
public void setRightTreeNode(TreeNode node) { right = node; }
/**
* Get the left child of this node.
* @return the left child this this node.
*/
public TreeNode getLeft() { return left; }
public TreeNode getLeftTreeNode() { return left; }
/**
* Get the right child of this node.
* @return the right child this this node.
*
*/
public TreeNode getRight() { return right; }
public TreeNode getRightTreeNode() { return right; }
/**
* Check if this node is a leaf node. A leaf node has both left and right
* nodes null.
* @return true if the node is a leaf node; false otherwise.
*/
public boolean isLeaf() {
return ((right==null) && (left==null));
}
public int getHeight() {
int lh = 0, rh = 0;
if ( left != null ) lh = left.getHeight();
if ( right != null ) rh = right.getHeight();
return (lh>rh)?lh:rh + 1;
}
/**
* Get the depth of his node.
* @return The depth of this node in a tree.
*/
public int getDepth() { return depth; }
// Somewhat of a hack to allow the position of a new child to be
// computed
public static int last_dy, last_dx;
/** Start at a node and set the positions for the sub-tree elements **/
public void setPosition( int x, int y, int dx, int dy ) {
this.x = x; this.y = y;
last_dx = dx; last_dy = dy;
int dx2 = dx/2;
if( left != null ) {
left.setPosition( x-dx2, y+dy, dx2, dy );
}
if( right != null ) {
right.setPosition( x+dx2, y+dy, dx2, dy );
}
}
/**
* Sets the depth of this node corresponding to the root node of the tree.
* @param depth Depth of the node.
*/
public void setDepth(int depth) {
this.depth = depth;
}
/**
* Move the node and all its branches based on the parameters.
* @param x The horizontal destination position of this node.
* @param y The vertical destination position of this node.
*/
public void move(int x, int y) {
int dx = x - this.x;
int dy = y - this.y;
moveTreeNode(dx, dy);
}
/**
* Move the tree starting with node dx pixels to the right and dy
* pixels down.
* @param node The root node of the tree to be moved.
* @param dx The change in x direction.
* @param dy The change in y direction.
*/
public void moveTreeNode(int dx, int dy) {
x += dx;
y += dy;
if (!isLeaf()) {
if (getLeftTreeNode() != null)
getLeftTreeNode().moveTreeNode(dx, dy);
if (getRightTreeNode() != null)
getRightTreeNode().moveTreeNode(dx, dy);
}
}
Font hugeFont, bigFont;
/**
* Assign some font instances to reduce initialization over during
* redraw.
*/
public void initFonts(Font hugeFont, Font bigFont) {
this.hugeFont = hugeFont;
this.bigFont = bigFont;
}
protected Color nodeColor = Color.red;
protected Color labelColor = Color.yellow;
/**
* Set the color of the node.
* @param nodeColor new color of the node.
*/
public void initColors(Color nodeColor) {
this.nodeColor = nodeColor;
}
public void setColour( Color x ) {
nodeColor = x;
}
public void setLabelColour( Color x ) {
labelColor = x;
}
/** Adjust the node size by a factor
* @param factor - expansion factor: factor > 1.0 => expansion,
factor < 1.0 => shrinkage
**/
public void expandSize( float factor ) {
float x = (float)(node_size.width) * factor;
node_size.width = Math.round( x );
x = (float)(node_size.height) * factor;
node_size.height = Math.round( x );
}
/** Return the current node size - used by other routines, eg, TreeEdge,
* to control their drawing
**/
public Dimension getNodeSize() { return node_size; }
/**
* This method draws the node on the corresponding graphical context
* normally passed in from the drawing panel.
*/
public void draw( Graphics g ) {
if( DEBUG ) System.out.println("TreeNode:draw " + getWeight() );
g.setColor(getCurrentColour());
g.fillRect( x, y, node_size.width, node_size.height );
g.setColor(Color.black);
g.drawRect( x, y, node_size.width, node_size.height );
if ( label != null ) {
if (getLabel().length() > 0) {
g.setColor( labelColor );
g.setFont( hugeFont );
g.drawString(getLabel(), x + 5, y + 12);
}
}
g.setColor( Color.white );
g.setFont( bigFont );
g.drawString("" + getWeight(), x + 2, y+27);
if( DEBUG ) System.out.println("TreeNode:draw " + getWeight() + " exit" );
}
} // class TreeNode