package ciips.animation.tree; import java.awt.*; import ciips.animation.*; /** * This class holds the information regarding a node from the heap/complete * binary tree. This class implements the 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