/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * Node.java * Copyright (C) 1999 University of Waikato, Hamilton, New Zealand * */ package weka.gui.treevisualizer; import java.awt.*; import java.util.*; import java.io.*; import weka.core.Instances; //this is a node structure that to be useful needs the Edge class as well //note i have done an unintentional naughty thing //getHeight() returns the pixel height of the node //getHeight(Node,int) returns how many levels down the tree goes //setHeight(int) is associated to the prior /** * This class records all the data about a particular node for displaying. * * @author Malcolm Ware (mfw4@cs.waikato.ac.nz) * @version $Revision: 1.4 $ */ public class Node { /** The fill mode for the node (not in use). */ private int m_backstyle; //how the back color will fill /** The shape of the node. */ private int m_shape; /** The color of the node. */ private Color m_color; /** the text for the node. */ private String m_label; /** the text broken up into lines */ private Vector m_lines; //the coord of the left side .note all coords are //between 1-0 for scaling per Stuart's suggestion /** The center of the node (between 0 and 1). */ private double m_center; //coord of the center . main x value used /** The top of the node (between 0 and 1). */ private double m_top; //main y coord to go by /** true if this nodes descendants are visible (not in use currently). */ private boolean m_cVisible; //whether it's descendants are visible /** true if this node is visible (not currently in use). */ private boolean m_visible; //whether it's visible /** true if this is the top of the tree. ie has no parent */ private boolean m_root; //whether it is anscestor to all i.e top of tree /** An array containing references to all the parent edges * (only 1 currently). */ private Vector m_parent; //the edge to its parent edges(or itself //if true root) /** An array containing references to all the child edges. */ private Vector m_children; //a vector list of edges to the nodes children /** The ID string for this node (used for construction purposes) */ private String m_refer; /** A String containing extra information about the node. */ private String m_data; /** * An Instances variable generated from the data. * Note that if this exists then the string shall be NULL to save space. */ private Instances m_theData; /** * This will setup all the values of the node except for its top and center. * * @param label The text for the node. * @param refer The ID string for this node. * @param backstyle The backstyle of this node. * @param shape The shape of this node. * @param color The color of this node. */ public Node(String label,String refer,int backstyle,int shape, Color color,String d) { m_label = label; m_backstyle = backstyle; m_shape = shape; m_color = color; m_refer = refer; m_center = 0; m_top = 0; m_cVisible = true; m_visible = true; m_root = false; m_parent = new Vector(1,1); m_children = new Vector(20,10); m_lines = new Vector(4,2); breakupLabel(); m_data = d; m_theData = null; } /** * This will return the Instances object related to this node. * If it has not been allocated then that will be done also. * * @return The Instances object. */ public Instances getInstances() { if (m_theData == null && m_data != null) { try { m_theData = new Instances(new StringReader(m_data)); } catch(Exception e) { System.out.println("Error : " + e); } m_data = null; } return m_theData; } /** * Get If this node's childs are visible. * * @return True if the childs are visible. */ public boolean getCVisible() { return m_cVisible; } /** * Recursively goes through the tree and sets all the children and the * parent to visible. * * @param r The current node to set visible. */ private void childVis(Node r) { Edge e; r.setVisible(true); if (r.getCVisible()) { for (int noa = 0;(e = r.getChild(noa)) != null;noa++) { childVis(e.getTarget()); } } } /** * Sets all the children of this node either to visible or invisible * * @param v True if the children are to be visible */ public void setCVisible(boolean v) { m_cVisible = v; if (v) { childVis(this); } else if (!v) { childInv(this); } } /** * Recursively goes through the tree and sets all the children to invisible, * Not the parent though. * * @param r The current node from whom the children are gonna be set * invisible. */ private void childInv(Node r) { Edge e; Node s; for (int noa = 0;(e = r.getChild(noa)) != null;noa++) { s = e.getTarget(); s.setVisible(false); childInv(s); } } /** * Get the value of refer. * * @return Value of refer. */ public String getRefer() { return m_refer; } /** * Set the value of refer. * * @param v Value to assign to refer. */ public void setRefer(String v) { m_refer = v; } /** * Get the value of shape. * * @return Value of shape. */ public int getShape() { return m_shape; } /** * Set the value of shape. * * @param v Value to assign to shape. */ public void setShape(int v) { m_shape = v; } /** * Get the value of color. * * @return Value of color. */ public Color getColor() { return m_color; } /** * Set the value of color. * * @param v Value to assign to color. */ public void setColor(Color v) { m_color = v; } /** * Get the value of label. * * @return Value of label. */ public String getLabel() { return m_label; } /** * This Will break the node's text up into lines. * */ private void breakupLabel() { int prev = 0,noa; for (noa = 0;noa < m_label.length();noa++) { if (m_label.charAt(noa) == '\n') { m_lines.addElement(m_label.substring(prev,noa)); prev = noa+1; } } m_lines.addElement(m_label.substring(prev,noa)); } /** * This will return the width and height of the rectangle that the text * will fit into. * * @param f The size info for the Font. * @return A Dimension containing the size of the text. */ public Dimension stringSize(FontMetrics f) { Dimension d = new Dimension(); int old = 0; String s; int noa = 0; while ((s = getLine(noa)) != null) { noa++; old = f.stringWidth(s); if (old > d.width) { d.width = old; } } d.height = noa * f.getHeight(); return d; } /** * Returns the text String for the specfied line. * * @param n The line wanted. * @return The String corresponding to that line. */ public String getLine(int n) { if (n < m_lines.size()) { return (String)m_lines.elementAt(n); } else { return null; } } /** * Get the value of center. * * @return Value of center. */ public double getCenter() { return m_center; } /** * Set the value of center. * * @param v Value to assign to center. */ public void setCenter(double v) { m_center = v; } /** * Will increase or decrease the postion of center. * * @param v The amount to increase or decrease center by. */ public void adjustCenter(double v) { m_center += v; } /** * Get the value of top. * * @return Value of top. */ public double getTop() { return m_top; } /** * Set the value of top. * * @param v Value to assign to top. */ public void setTop(double v) { m_top = v; } /** * Get the value of visible. * * @return Value of visible. */ public boolean getVisible() { return m_visible; } /** * Set the value of visible. * * @param v Value to assign to visible. */ private void setVisible(boolean v) { m_visible = v; } /** * Get the value of root. * * @return True if has no parents. */ public boolean getRoot() { return m_root; } /** * Set the value of root. * * @param v Value to assign to root. */ public void setRoot(boolean v) { m_root = v; } /** * Get the parent edge. * * @param i The parent number to get. * @return The parent edge or NULL if it doesn't exist. */ public Edge getParent(int i) { if (i < m_parent.size()) { return (Edge)m_parent.elementAt(i); } else { return null; } } /** * Set the value of parent. * * @param v Value to assign to parent. */ public void setParent(Edge v) { m_parent.addElement(v); } /** * Get the Edge for the child number 'i'. * * @param i The child number to get. * @return The child Edge or NULL if it doesn't exist. */ public Edge getChild(int i) { if (i < m_children.size()) { return (Edge)m_children.elementAt(i); } else { return null; } } /** * Set the value of children. * * @param v Value to assign to children. */ public void addChild(Edge v) { m_children.addElement(v); } /** * Recursively finds the number of visible groups of siblings there are. * * @param r The current Node upto. * @param n The current number of groups there are. * @return The number of groups found so far. */ public static int getGCount(Node r,int n) { Edge e; if (r.getChild(0) != null && r.getCVisible()) { n++; for (int noa = 0;(e = r.getChild(noa)) != null;noa++) { n = getGCount(e.getTarget(),n); } } return n; } /** * Recursively finds the total number of groups of siblings there are. * * @param r The current Node upto. * @param n The current number of groups there are. * @return The number of groups found so far. */ public static int getTotalGCount(Node r,int n) { Edge e; if (r.getChild(0) != null) { n++; for (int noa = 0;(e = r.getChild(noa)) != null;noa++) { n = getTotalGCount(e.getTarget(),n); } } return n; } /** * Recursively finds the number of visible nodes there are (this may * accidentally count some of the invis nodes). * * @param r The current Node upto. * @param n The current number nodes there are. * @return The number of nodes found so far. */ public static int getCount(Node r,int n) { Edge e; n++; for (int noa = 0;(e = r.getChild(noa)) != null && r.getCVisible();noa++) { n = getCount(e.getTarget(),n); } return n; } /** * Recursively finds the total number of nodes there are. * * @param r The current Node upto. * @param n The current number nodes there are. * @return The number of nodes found so far. */ public static int getTotalCount(Node r,int n) { Edge e; n++; for (int noa = 0;(e = r.getChild(noa)) != null;noa++) { n = getTotalCount(e.getTarget(),n); } return n; } /** * Recursively finds the number of visible levels there are. * * @param r The current Node upto. * @param l The curent level. * @return The max number of levels found so far. */ public static int getHeight(Node r,int l) { l++; int lev = l,temp = 0; Edge e; for (int noa = 0;(e = r.getChild(noa)) != null && r.getCVisible();noa++) { temp = getHeight(e.getTarget(),l); if (temp > lev) { lev = temp; } } return lev; } /** * Recursively finds the total number of levels there are. * * @param r The current Node upto. * @param l The curent level. * @return The max number of levels found so far. */ public static int getTotalHeight(Node r,int l) { l++; int lev = l,temp = 0; Edge e; for (int noa = 0;(e = r.getChild(noa)) != null;noa++) { temp = getTotalHeight(e.getTarget(),l); if (temp > lev) { lev = temp; } } return lev; } }