TreeVisualizer.java
Upload User: rhdiban
Upload Date: 2013-08-09
Package Size: 15085k
Code Size: 63k
Category:

Windows Develop

Development Platform:

Java

  1. /*
  2.  *    This program is free software; you can redistribute it and/or modify
  3.  *    it under the terms of the GNU General Public License as published by
  4.  *    the Free Software Foundation; either version 2 of the License, or
  5.  *    (at your option) any later version.
  6.  *
  7.  *    This program is distributed in the hope that it will be useful,
  8.  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  9.  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10.  *    GNU General Public License for more details.
  11.  *
  12.  *    You should have received a copy of the GNU General Public License
  13.  *    along with this program; if not, write to the Free Software
  14.  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15.  */
  16. /*
  17.  *    Displayer.java
  18.  *    Copyright (C) 1999 Malcolm Ware
  19.  *
  20.  */
  21. package weka.gui.treevisualizer;
  22. import java.awt.*;
  23. import javax.swing.*;
  24. import java.awt.event.*;
  25. import java.io.*;
  26. import weka.core.Instances;
  27. import weka.gui.visualize.VisualizePanel;
  28. import weka.gui.visualize.VisualizePanelListener;
  29. import weka.gui.visualize.VisualizePanelEvent;
  30. /**
  31.  * Class for displaying a Node structure in Swing. <p>
  32.  *
  33.  * To work this class simply create an instance of it.<p>
  34.  *
  35.  * Assign it to a window or other such object.<p>
  36.  *
  37.  * Resize it to the desired size.<p>
  38.  *
  39.  *
  40.  * When using the Displayer hold the left mouse button to drag the 
  41.  * tree around. <p>
  42.  *
  43.  * Click the left mouse button with ctrl to shrink the size of the tree 
  44.  * by half. <p>
  45.  *
  46.  * Click and drag with the left mouse button and shift to draw a box,
  47.  * when the left mouse button is released the contents of the box 
  48.  * will be magnified 
  49.  * to fill the screen. <p> <p>
  50.  *
  51.  * Click the right mouse button to bring up a menu. <p>
  52.  * Most options are self explanatory.<p>
  53.  *
  54.  * Select Auto Scale to set the tree to it's optimal display size.
  55.  *
  56.  * @author Malcolm Ware (mfw4@cs.waikato.ac.nz)
  57.  * @version $Revision: 1.5 $
  58.  */
  59. public class TreeVisualizer extends JPanel implements MouseMotionListener,
  60.        MouseListener,ActionListener,ItemListener {
  61.   /** The placement algorithm for the Node structure. */
  62.   private NodePlace m_placer;  
  63.   /** The top Node. */
  64.   private Node m_topNode;
  65.   
  66.   /** The postion of the view relative to the tree. */
  67.   private Dimension m_viewPos;        
  68.   /** The size of the tree in pixels. */
  69.   private Dimension m_viewSize;      
  70.   
  71.   /** The font used to display the tree. */
  72.   private Font m_currentFont;        
  73.   /** The size information for the current font. */
  74.   private FontMetrics m_fontSize;    
  75.   /** The number of Nodes in the tree. */
  76.   private int m_numNodes;
  77.   /** The number of levels in the tree. */
  78.   private int m_numLevels;     
  79.   /** An array with the Nodes sorted into it and display information 
  80.    * about the Nodes. */
  81.   private NodeInfo[] m_nodes;
  82.   /** An array with the Edges sorted into it and display information 
  83.    * about the Edges. */
  84.   private EdgeInfo[] m_edges;
  85.                      
  86.   /** A timer to keep the frame rate constant. */
  87.   private Timer m_frameLimiter;      
  88.                          
  89.   /** Describes the action the user is performing. */
  90.   private int m_mouseState;           
  91.   /** A variable used to tag the start pos of a user action. */
  92.   private Dimension m_oldMousePos;
  93.   /** A variable used to tag the most current point of a user action. */
  94.   private Dimension m_newMousePos;
  95.   /** A variable used to determine for the clicked method if any other 
  96.    * mouse state has already taken place. */
  97.   private boolean m_clickAvailable;
  98.   /** A variable used to remember the desired view pos. */
  99.   private Dimension m_nViewPos;     
  100.   /** A variable used to remember the desired tree size. */
  101.   private Dimension m_nViewSize;       
  102.   /** The number of frames left to calculate. */
  103.   private int m_scaling;         
  104.   /** A right (or middle) click popup menu. */
  105.   private JPopupMenu m_winMenu;
  106.   /** An option on the win_menu */
  107.   private JMenuItem m_topN;
  108.   /** An option on the win_menu*/
  109.   private JMenuItem m_fitToScreen;
  110.   /** An option on the win_menu */
  111.   private JMenuItem m_autoScale;
  112.   /** A ub group on the win_menu */
  113.   private JMenu m_selectFont;
  114.   /** A grouping for the font choices */
  115.   private ButtonGroup m_selectFontGroup;
  116.   /** A font choice. */
  117.   private JRadioButtonMenuItem m_size24;
  118.   /** A font choice. */
  119.   private JRadioButtonMenuItem m_size22;
  120.   /** A font choice. */
  121.   private JRadioButtonMenuItem m_size20;
  122.   /** A font choice. */
  123.   private JRadioButtonMenuItem m_size18;
  124.   /** A font choice. */
  125.   private JRadioButtonMenuItem m_size16;
  126.   /** A font choice. */
  127.   private JRadioButtonMenuItem m_size14;
  128.   /** A font choice. */
  129.   private JRadioButtonMenuItem m_size12;
  130.   /** A font choice. */
  131.   private JRadioButtonMenuItem m_size10;
  132.   /** A font choice. */
  133.   private JRadioButtonMenuItem m_size8;
  134.   /** A font choice. */
  135.   private JRadioButtonMenuItem m_size6;
  136.   /** A font choice. */
  137.   private JRadioButtonMenuItem m_size4;
  138.   /** A font choice. */
  139.   private JRadioButtonMenuItem m_size2;
  140.   /** A font choice. */
  141.   private JRadioButtonMenuItem m_size1;
  142.   /** An option on the win menu. */
  143.   private JMenuItem m_accept;
  144.   /** A right or middle click popup menu for nodes. */
  145.   private JPopupMenu m_nodeMenu;
  146.   /** A visualize choice for the node, may not be available. */
  147.   private JMenuItem m_visualise;
  148.   /** 
  149.    * An add children to Node choice, This is only available if the tree
  150.    * display has a treedisplay listerner added to it.
  151.    */
  152.   private JMenuItem m_addChildren;
  153.   /** Similar to add children but now it removes children. */
  154.   private JMenuItem m_remChildren;
  155.   /** Use this to have J48 classify this node. */
  156.   private JMenuItem m_classifyChild;
  157.   
  158.   /** Use this to dump the instances from this node to the vis panel. */
  159.   private JMenuItem m_sendInstances;
  160.   /** The subscript for the currently selected node (this is an internal 
  161.    * thing, so the user is unaware of this). */
  162.   private int m_focusNode;
  163.   /**
  164.    * The Node the user is currently focused on , this is similar to 
  165.    * focus node except that it is used by other 
  166.    * classes rather than this one.
  167.    */
  168.   private int m_highlightNode;
  169.   
  170.   /* A pointer to this tree's classifier if a classifier is using it. */
  171.   //private UserClassifier classer;
  172.   private TreeDisplayListener m_listener;
  173.   private JTextField m_searchString;
  174.   private JDialog m_searchWin;
  175.   private JRadioButton m_caseSen;
  176.   ///////////////////
  177.   //this is the event fireing stuff
  178.   /**
  179.    * Constructs Displayer to display a tree provided in a dot format.
  180.    * Uses the NodePlacer to place the Nodes.
  181.    * @param tdl listener 
  182.    * @param dot string containing the dot representation of the tree to
  183.    * display
  184.    * @param p the algorithm to be used to position the nodes.
  185.    */
  186.   public TreeVisualizer(TreeDisplayListener tdl, String dot, NodePlace p) {
  187.     //generate the node structure in here
  188.     setBorder(BorderFactory.createTitledBorder("Tree View")); 
  189.     m_listener = tdl;
  190.     TreeBuild builder = new TreeBuild();
  191.     
  192.     Node n = null;
  193.     NodePlace arrange = new PlaceNode2();
  194.     n = builder.create(new StringReader(dot));
  195.     //    System.out.println(n.getCount(n, 0));
  196.     //if the size needs to be automatically alocated I will do it here
  197.     m_highlightNode = 5;
  198.     m_topNode = n;
  199.     m_placer = p;
  200.     m_placer.place(m_topNode);
  201.     m_viewPos = new Dimension(0, 0);    //will be adjusted 
  202.     m_viewSize = new Dimension(800, 600);   //I allocate this now so that
  203.     //the tree will be visible
  204.     //when the panel is enlarged
  205.     m_nViewPos = new Dimension(0, 0);            
  206.     m_nViewSize = new Dimension(800, 600);          
  207.                                       
  208.     m_scaling = 0;
  209.     
  210.     m_numNodes = m_topNode.getCount(m_topNode,0);   //note the second 
  211.     //argument must be a zero, this is a 
  212.     //recursive function
  213.     m_numLevels = m_topNode.getHeight(m_topNode,0);
  214.   
  215.     m_nodes = new NodeInfo[m_numNodes];
  216.     m_edges = new EdgeInfo[m_numNodes-1];
  217.     
  218.     arrayFill(m_topNode, m_nodes, m_edges);
  219.     
  220.     changeFontSize(12);
  221.     m_mouseState = 0;
  222.     m_oldMousePos = new Dimension(0, 0);
  223.     m_newMousePos = new Dimension(0, 0);
  224.     m_frameLimiter = new Timer(120, this);
  225.     m_winMenu = new JPopupMenu();
  226.     m_topN = new JMenuItem("Center on Top Node");           //note to change 
  227.     //language change this line
  228.     m_topN.setActionCommand("Center on Top Node");          //but not this one,
  229.     //same for all menu items
  230.     m_fitToScreen = new JMenuItem("Fit to Screen");
  231.     m_fitToScreen.setActionCommand("Fit to Screen");
  232.     //unhide = new JMenuItem("Unhide all Nodes");
  233.     m_selectFont = new JMenu("Select Font");
  234.     m_selectFont.setActionCommand("Select Font");
  235.     m_autoScale = new JMenuItem("Auto Scale");
  236.     m_autoScale.setActionCommand("Auto Scale");
  237.     m_selectFontGroup = new ButtonGroup();
  238.     
  239.     m_accept = new JMenuItem("Accept The Tree");
  240.     m_accept.setActionCommand("Accept The Tree");
  241.     
  242.     m_winMenu.add(m_topN);
  243.     m_winMenu.addSeparator();
  244.     m_winMenu.add(m_fitToScreen);
  245.     m_winMenu.add(m_autoScale);
  246.     m_winMenu.addSeparator();
  247.     //m_winMenu.add(unhide);
  248.     m_winMenu.addSeparator();
  249.     m_winMenu.add(m_selectFont);
  250.     m_winMenu.addSeparator();
  251.     if (m_listener != null) {
  252.       m_winMenu.add(m_accept);
  253.     }
  254.     
  255.     m_topN.addActionListener(this);
  256.     m_fitToScreen.addActionListener(this);
  257.     //unhide.addActionListener(this);
  258.     m_autoScale.addActionListener(this);
  259.     m_accept.addActionListener(this);
  260.         
  261.     m_size24 = new JRadioButtonMenuItem("Size 24",false);//,select_font_group);
  262.     m_size22 = new JRadioButtonMenuItem("Size 22",false);//,select_font_group);
  263.     m_size20 = new JRadioButtonMenuItem("Size 20",false);//,select_font_group);
  264.     m_size18 = new JRadioButtonMenuItem("Size 18",false);//,select_font_group);
  265.     m_size16 = new JRadioButtonMenuItem("Size 16",false);//,select_font_group);
  266.     m_size14 = new JRadioButtonMenuItem("Size 14",false);//,select_font_group);
  267.     m_size12 = new JRadioButtonMenuItem("Size 12",true);//,select_font_group);
  268.     m_size10 = new JRadioButtonMenuItem("Size 10",false);//,select_font_group);
  269.     m_size8 = new JRadioButtonMenuItem("Size 8",false);//,select_font_group);
  270.     m_size6 = new JRadioButtonMenuItem("Size 6",false);//,select_font_group);
  271.     m_size4 = new JRadioButtonMenuItem("Size 4",false);//,select_font_group);
  272.     m_size2 = new JRadioButtonMenuItem("Size 2",false);//,select_font_group);
  273.     m_size1 = new JRadioButtonMenuItem("Size 1",false);//,select_font_group);
  274.     m_size24.setActionCommand("Size 24");//,select_font_group);
  275.     m_size22.setActionCommand("Size 22");//,select_font_group);
  276.     m_size20.setActionCommand("Size 20");//,select_font_group);
  277.     m_size18.setActionCommand("Size 18");//,select_font_group);
  278.     m_size16.setActionCommand("Size 16");//,select_font_group);
  279.     m_size14.setActionCommand("Size 14");//,select_font_group);
  280.     m_size12.setActionCommand("Size 12");//,select_font_group);
  281.     m_size10.setActionCommand("Size 10");//,select_font_group);
  282.     m_size8.setActionCommand("Size 8");//,select_font_group);
  283.     m_size6.setActionCommand("Size 6");//,select_font_group);
  284.     m_size4.setActionCommand("Size 4");//,select_font_group);
  285.     m_size2.setActionCommand("Size 2");//,select_font_group);
  286.     m_size1.setActionCommand("Size 1");//,select_font_group);
  287.     
  288.     
  289.     m_selectFontGroup.add(m_size24);
  290.     m_selectFontGroup.add(m_size22);
  291.     m_selectFontGroup.add(m_size20);
  292.     m_selectFontGroup.add(m_size18);
  293.     m_selectFontGroup.add(m_size16);
  294.     m_selectFontGroup.add(m_size14);
  295.     m_selectFontGroup.add(m_size12);
  296.     m_selectFontGroup.add(m_size10);
  297.     m_selectFontGroup.add(m_size8);
  298.     m_selectFontGroup.add(m_size6);
  299.     m_selectFontGroup.add(m_size4);
  300.     m_selectFontGroup.add(m_size2);
  301.     m_selectFontGroup.add(m_size1);
  302.     
  303.     m_selectFont.add(m_size24);
  304.     m_selectFont.add(m_size22);
  305.     m_selectFont.add(m_size20);
  306.     m_selectFont.add(m_size18);
  307.     m_selectFont.add(m_size16);
  308.     m_selectFont.add(m_size14);
  309.     m_selectFont.add(m_size12);
  310.     m_selectFont.add(m_size10);
  311.     m_selectFont.add(m_size8);
  312.     m_selectFont.add(m_size6);
  313.     m_selectFont.add(m_size4);
  314.     m_selectFont.add(m_size2);
  315.     m_selectFont.add(m_size1);
  316.     m_size24.addItemListener(this);
  317.     m_size22.addItemListener(this);
  318.     m_size20.addItemListener(this);
  319.     m_size18.addItemListener(this);
  320.     m_size16.addItemListener(this);
  321.     m_size14.addItemListener(this);
  322.     m_size12.addItemListener(this);
  323.     m_size10.addItemListener(this);
  324.     m_size8.addItemListener(this);
  325.     m_size6.addItemListener(this);
  326.     m_size4.addItemListener(this);
  327.     m_size2.addItemListener(this);
  328.     m_size1.addItemListener(this);
  329.     /*
  330.       search_string = new JTextField(22);
  331.       search_win = new JDialog();
  332.       case_sen = new JRadioButton("Case Sensitive");
  333.       search_win.getContentPane().setLayout(null);
  334.       search_win.setSize(300, 200);
  335.  
  336.       search_win.getContentPane().add(search_string);
  337.       search_win.getContentPane().add(case_sen);
  338.       search_string.setLocation(50, 70);
  339.       case_sen.setLocation(50, 120);
  340.       case_sen.setSize(100, 24); 
  341.       search_string.setSize(100, 24);
  342.       //search_string.setVisible(true);
  343.       //case_sen.setVisible(true);
  344.       //search_win.setVisible(true);
  345.     */
  346.     m_nodeMenu = new JPopupMenu();
  347.     /* A visualize choice for the node, may not be available. */
  348.     m_visualise = new JMenuItem("Visualize The Node");
  349.     m_visualise.setActionCommand("Visualize The Node");
  350.     m_visualise.addActionListener(this);
  351.     m_nodeMenu.add(m_visualise);
  352.    
  353.     if (m_listener != null) {
  354.       m_remChildren = new JMenuItem("Remove Child Nodes");
  355.       m_remChildren.setActionCommand("Remove Child Nodes");
  356.       m_remChildren.addActionListener(this);
  357.       m_nodeMenu.add(m_remChildren);
  358.       
  359.       
  360.       m_classifyChild = new JMenuItem("Use Classifier...");
  361.       m_classifyChild.setActionCommand("classify_child");
  362.       m_classifyChild.addActionListener(this);
  363.       m_nodeMenu.add(m_classifyChild);
  364.       
  365.       /*m_sendInstances = new JMenuItem("Add Instances To Viewer");
  366.       m_sendInstances.setActionCommand("send_instances");
  367.       m_sendInstances.addActionListener(this);
  368.       m_nodeMenu.add(m_sendInstances); */
  369.       
  370.     }
  371.     
  372.     m_focusNode = -1;
  373.     m_highlightNode = -1;
  374.     
  375.     addMouseMotionListener(this);
  376.     addMouseListener(this);
  377.     //repaint();
  378.     //frame_limiter.setInitialDelay();
  379.     m_frameLimiter.setRepeats(false);
  380.     m_frameLimiter.start();
  381.   }
  382.   
  383.   /**
  384.    * Constructs Displayer with the specified Node as the top 
  385.    * of the tree, and uses the NodePlacer to place the Nodes.
  386.    * @param tdl listener.
  387.    * @param n the top Node of the tree to be displayed.
  388.    * @param p the algorithm to be used to position the nodes.
  389.    */  
  390.   public TreeVisualizer(TreeDisplayListener tdl, Node n, NodePlace p) {
  391.     //if the size needs to be automatically alocated I will do it here
  392.     setBorder(BorderFactory.createTitledBorder("Tree View")); 
  393.     m_listener = tdl;
  394.     m_topNode = n;
  395.     m_placer = p;
  396.     m_placer.place(m_topNode);
  397.     m_viewPos = new Dimension(0, 0);    //will be adjusted 
  398.     m_viewSize = new Dimension(800, 600);   //I allocate this now so that
  399.     //the tree will be visible
  400.     //when the panel is enlarged
  401.     m_nViewPos = new Dimension(0, 0);            
  402.     m_nViewSize = new Dimension(800, 600);          
  403.                                       
  404.     m_scaling = 0;
  405.     
  406.     m_numNodes = m_topNode.getCount(m_topNode,0);   //note the second argument 
  407.     //must be a zero, this is a 
  408.     //recursive function
  409.     m_numLevels = m_topNode.getHeight(m_topNode,0);
  410.   
  411.     m_nodes = new NodeInfo[m_numNodes];
  412.     m_edges = new EdgeInfo[m_numNodes-1];
  413.     arrayFill(m_topNode, m_nodes, m_edges);
  414.     
  415.     changeFontSize(12);
  416.     m_mouseState = 0;
  417.     m_oldMousePos = new Dimension(0, 0);
  418.     m_newMousePos = new Dimension(0, 0);
  419.     m_frameLimiter = new Timer(120, this);
  420.     m_winMenu = new JPopupMenu();
  421.     m_topN = new JMenuItem("Center on Top Node");           //note to change 
  422.     //language change this line
  423.     m_topN.setActionCommand("Center on Top Node");          //but not this 
  424.     //one, same for all menu items
  425.     m_fitToScreen = new JMenuItem("Fit to Screen");
  426.     m_fitToScreen.setActionCommand("Fit to Screen");
  427.     //unhide = new JMenuItem("Unhide all Nodes");
  428.     m_selectFont = new JMenu("Select Font");
  429.     m_selectFont.setActionCommand("Select Font");
  430.     m_autoScale = new JMenuItem("Auto Scale");
  431.     m_autoScale.setActionCommand("Auto Scale");
  432.     m_selectFontGroup = new ButtonGroup();
  433.     
  434.     m_accept = new JMenuItem("Accept The Tree");
  435.     m_accept.setActionCommand("Accept The Tree");
  436.     
  437.     m_winMenu.add(m_topN);
  438.     m_winMenu.addSeparator();
  439.     m_winMenu.add(m_fitToScreen);
  440.     m_winMenu.add(m_autoScale);
  441.     m_winMenu.addSeparator();
  442.     //m_winMenu.add(unhide);
  443.     m_winMenu.addSeparator();
  444.     m_winMenu.add(m_selectFont);
  445.     m_winMenu.addSeparator();
  446.     if (m_listener != null) {
  447.       m_winMenu.add(m_accept);
  448.     }
  449.     
  450.     m_topN.addActionListener(this);
  451.     m_fitToScreen.addActionListener(this);
  452.     //unhide.addActionListener(this);
  453.     m_autoScale.addActionListener(this);
  454.     m_accept.addActionListener(this);
  455.         
  456.     m_size24 = new JRadioButtonMenuItem("Size 24",false);//,select_font_group);
  457.     m_size22 = new JRadioButtonMenuItem("Size 22",false);//,select_font_group);
  458.     m_size20 = new JRadioButtonMenuItem("Size 20",false);//,select_font_group);
  459.     m_size18 = new JRadioButtonMenuItem("Size 18",false);//,select_font_group);
  460.     m_size16 = new JRadioButtonMenuItem("Size 16",false);//,select_font_group);
  461.     m_size14 = new JRadioButtonMenuItem("Size 14",false);//,select_font_group);
  462.     m_size12 = new JRadioButtonMenuItem("Size 12",true);//,select_font_group);
  463.     m_size10 = new JRadioButtonMenuItem("Size 10",false);//,select_font_group);
  464.     m_size8 = new JRadioButtonMenuItem("Size 8",false);//,select_font_group);
  465.     m_size6 = new JRadioButtonMenuItem("Size 6",false);//,select_font_group);
  466.     m_size4 = new JRadioButtonMenuItem("Size 4",false);//,select_font_group);
  467.     m_size2 = new JRadioButtonMenuItem("Size 2",false);//,select_font_group);
  468.     m_size1 = new JRadioButtonMenuItem("Size 1",false);//,select_font_group);
  469.     m_size24.setActionCommand("Size 24");//,select_font_group);
  470.     m_size22.setActionCommand("Size 22");//,select_font_group);
  471.     m_size20.setActionCommand("Size 20");//,select_font_group);
  472.     m_size18.setActionCommand("Size 18");//,select_font_group);
  473.     m_size16.setActionCommand("Size 16");//,select_font_group);
  474.     m_size14.setActionCommand("Size 14");//,select_font_group);
  475.     m_size12.setActionCommand("Size 12");//,select_font_group);
  476.     m_size10.setActionCommand("Size 10");//,select_font_group);
  477.     m_size8.setActionCommand("Size 8");//,select_font_group);
  478.     m_size6.setActionCommand("Size 6");//,select_font_group);
  479.     m_size4.setActionCommand("Size 4");//,select_font_group);
  480.     m_size2.setActionCommand("Size 2");//,select_font_group);
  481.     m_size1.setActionCommand("Size 1");//,select_font_group);
  482.     
  483.     
  484.     m_selectFontGroup.add(m_size24);
  485.     m_selectFontGroup.add(m_size22);
  486.     m_selectFontGroup.add(m_size20);
  487.     m_selectFontGroup.add(m_size18);
  488.     m_selectFontGroup.add(m_size16);
  489.     m_selectFontGroup.add(m_size14);
  490.     m_selectFontGroup.add(m_size12);
  491.     m_selectFontGroup.add(m_size10);
  492.     m_selectFontGroup.add(m_size8);
  493.     m_selectFontGroup.add(m_size6);
  494.     m_selectFontGroup.add(m_size4);
  495.     m_selectFontGroup.add(m_size2);
  496.     m_selectFontGroup.add(m_size1);
  497.     
  498.     m_selectFont.add(m_size24);
  499.     m_selectFont.add(m_size22);
  500.     m_selectFont.add(m_size20);
  501.     m_selectFont.add(m_size18);
  502.     m_selectFont.add(m_size16);
  503.     m_selectFont.add(m_size14);
  504.     m_selectFont.add(m_size12);
  505.     m_selectFont.add(m_size10);
  506.     m_selectFont.add(m_size8);
  507.     m_selectFont.add(m_size6);
  508.     m_selectFont.add(m_size4);
  509.     m_selectFont.add(m_size2);
  510.     m_selectFont.add(m_size1);
  511.     m_size24.addItemListener(this);
  512.     m_size22.addItemListener(this);
  513.     m_size20.addItemListener(this);
  514.     m_size18.addItemListener(this);
  515.     m_size16.addItemListener(this);
  516.     m_size14.addItemListener(this);
  517.     m_size12.addItemListener(this);
  518.     m_size10.addItemListener(this);
  519.     m_size8.addItemListener(this);
  520.     m_size6.addItemListener(this);
  521.     m_size4.addItemListener(this);
  522.     m_size2.addItemListener(this);
  523.     m_size1.addItemListener(this);
  524.     /*
  525.       search_string = new JTextField(22);
  526.       search_win = new JDialog();
  527.       case_sen = new JRadioButton("Case Sensitive");
  528.       search_win.getContentPane().setLayout(null);
  529.       search_win.setSize(300, 200);
  530.  
  531.       search_win.getContentPane().add(search_string);
  532.       search_win.getContentPane().add(case_sen);
  533.       search_string.setLocation(50, 70);
  534.       case_sen.setLocation(50, 120);
  535.       case_sen.setSize(100, 24); 
  536.       search_string.setSize(100, 24);
  537.       //search_string.setVisible(true);
  538.       //case_sen.setVisible(true);
  539.       search_win.setVisible(true);
  540.     */
  541.     m_nodeMenu = new JPopupMenu();
  542.     /* A visualize choice for the node, may not be available. */
  543.     m_visualise = new JMenuItem("Visualize The Node");
  544.     m_visualise.setActionCommand("Visualize The Node");
  545.     m_visualise.addActionListener(this);
  546.     m_nodeMenu.add(m_visualise);
  547.     if (m_listener != null) {
  548.       m_remChildren = new JMenuItem("Remove Child Nodes");
  549.       m_remChildren.setActionCommand("Remove Child Nodes");
  550.       m_remChildren.addActionListener(this);
  551.       m_nodeMenu.add(m_remChildren);
  552.       
  553.       m_classifyChild = new JMenuItem("Use Classifier...");
  554.       m_classifyChild.setActionCommand("classify_child");
  555.       m_classifyChild.addActionListener(this);
  556.       m_nodeMenu.add(m_classifyChild);
  557.       
  558.       m_sendInstances = new JMenuItem("Add Instances To Viewer");
  559.       m_sendInstances.setActionCommand("send_instances");
  560.       m_sendInstances.addActionListener(this);
  561.       m_nodeMenu.add(m_sendInstances);
  562.       
  563.       
  564.     }
  565.   
  566.     m_focusNode = -1;
  567.     m_highlightNode = -1;
  568.     
  569.     addMouseMotionListener(this);
  570.     addMouseListener(this);
  571.   
  572.     //repaint();
  573.     //frame_limiter.setInitialDelay();
  574.     m_frameLimiter.setRepeats(false);
  575.     m_frameLimiter.start();
  576.   }
  577.   /**
  578.    * Performs the action associated with the ActionEvent.
  579.    *
  580.    * @param e the action event.
  581.    */
  582.   public void actionPerformed(ActionEvent e) {
  583.     
  584.     //JMenuItem m = (JMenuItem)e.getSource();
  585.     
  586.     if (e.getActionCommand() == null) {
  587.       if (m_scaling == 0) {
  588. repaint();
  589.       }
  590.       else {
  591. animateScaling(m_nViewPos, m_nViewSize, m_scaling);
  592.       }
  593.     }
  594.     else if (e.getActionCommand().equals("Fit to Screen")) {
  595.       
  596.       Dimension np = new Dimension();
  597.       Dimension ns = new Dimension();
  598.       int leftmost = 1000000, rightmost = -1000000;
  599.       int leftCenter = 1000000, rightCenter = -1000000, rightNode = 0;
  600.       int highest = -1000000, highTop = -1000000;
  601.       for (int noa = 0; noa < m_numNodes; noa++) {
  602. calcScreenCoords(noa);
  603. if (m_nodes[noa].m_center - m_nodes[noa].m_side < leftmost) {
  604.   leftmost = m_nodes[noa].m_center - m_nodes[noa].m_side;
  605. }
  606. if (m_nodes[noa].m_center < leftCenter) {
  607.   leftCenter = m_nodes[noa].m_center;
  608. }
  609. if (m_nodes[noa].m_center + m_nodes[noa].m_side > rightmost) {
  610.   rightmost = m_nodes[noa].m_center + m_nodes[noa].m_side;   
  611. }
  612. if (m_nodes[noa].m_center > rightCenter) {
  613.   rightCenter = m_nodes[noa].m_center;
  614.   rightNode = noa;
  615. }
  616. if (m_nodes[noa].m_top + m_nodes[noa].m_height > highest) {
  617.   highest = m_nodes[noa].m_top + m_nodes[noa].m_height;
  618. }
  619. if (m_nodes[noa].m_top > highTop) {
  620.   highTop = m_nodes[noa].m_top;
  621. }
  622.       }
  623.       
  624.       ns.width = getWidth();
  625.       ns.width -= leftCenter - leftmost + rightmost - rightCenter + 30;
  626.       ns.height = getHeight() - highest + highTop - 40;
  627.       
  628.       if (m_nodes[rightNode].m_node.getCenter() != 0 
  629.   && leftCenter != rightCenter) {
  630. ns.width /= m_nodes[rightNode].m_node.getCenter();
  631.       }
  632.       if (ns.width < 10)
  633. {
  634.   ns.width = 10;
  635. }
  636.       if (ns.height < 10)
  637. {
  638.   ns.height = 10;
  639. }
  640.       
  641.       np.width = (leftCenter - leftmost + rightmost - rightCenter) / 2 + 15;
  642.       np.height = (highest - highTop) / 2 + 20;
  643.       /*for (int noa = 0; noa < m_numNodes; noa++) {
  644. calcScreenCoords(noa);
  645. if (m_nodes[noa].m_center - m_nodes[noa].m_side < leftmost) {
  646.   leftmost = m_nodes[noa].m_center - m_nodes[noa].m_side;
  647.   left_node = noa;
  648. }
  649. if (m_nodes[noa].m_center + m_nodes[noa].m_side > rightmost) {
  650.   rightmost = m_nodes[noa].m_center + m_nodes[noa].m_side;
  651.   System.out.println(rightmost + " " + noa + " " + 
  652.      m_nodes[noa].m_side);
  653. }
  654. m_nodes[noa].m_top = 32000;
  655.       }
  656.       
  657.       ns.width = (int)((getSize().width * .9) / 
  658.        (((double)(rightmost - leftmost)) / m_viewSize.width));
  659.       ns.height = (getSize().height);
  660.       
  661.       if (left_node == -1) {
  662. np.width = 0;
  663.       }
  664.       else {
  665. np.width = (int)((getSize().width * .05) - 
  666.  (m_nodes[left_node].m_node.getCenter() * 
  667.   ns.width - m_nodes[left_node].m_side));
  668.       }
  669.       np.height = 0;
  670.       
  671.       */
  672.       animateScaling(np, ns, 10);
  673.       
  674.     }
  675.     else if (e.getActionCommand().equals("Center on Top Node")) {
  676.       
  677.       int tpx = (int)(m_topNode.getCenter() * m_viewSize.width);   //calculate
  678.       //the top nodes postion but don't adjust for where 
  679.       int tpy = (int)(m_topNode.getTop() * m_viewSize.height);     //view is
  680.       
  681.       
  682.       
  683.       Dimension np = new Dimension(getSize().width / 2 - tpx, 
  684.    getSize().width / 6 - tpy);
  685.       
  686.       animateScaling(np, m_viewSize, 10);
  687.       
  688.     }
  689.     else if (e.getActionCommand().equals("Auto Scale")) {
  690.       autoScale();  //this will figure the best scale value 
  691.       //keep the focus on the middle of the screen and call animate
  692.     }
  693.     else if (e.getActionCommand().equals("Visualize The Node")) {
  694.       //send the node data to the visualizer 
  695.       if (m_focusNode >= 0) {
  696. Instances inst;
  697. if ((inst = m_nodes[m_focusNode].m_node.getInstances()) != null) {
  698.   VisualizePanel pan = new VisualizePanel();
  699.   pan.setInstances(inst);
  700.   JFrame nf = new JFrame();
  701.   nf.setSize(400, 300);
  702.   nf.getContentPane().add(pan);
  703.   nf.show();
  704. }
  705. else {
  706.   JOptionPane.showMessageDialog(this, "Sorry, there is no " + 
  707. "availble Instances data for " +
  708. "this Node.", "Sorry!",
  709. JOptionPane.WARNING_MESSAGE); 
  710. }
  711.       }
  712.       else {
  713. JOptionPane.showMessageDialog(this, "Error, there is no " + 
  714.       "selected Node to perform " +
  715.       "this operation on.", "Error!",
  716.       JOptionPane.ERROR_MESSAGE); 
  717.       }
  718.     }
  719.     else if (e.getActionCommand().equals("Create Child Nodes")) {
  720.       if (m_focusNode >= 0) {
  721. if (m_listener != null) {
  722.   //then send message to the listener
  723.   m_listener.userCommand(new TreeDisplayEvent
  724.     (TreeDisplayEvent.ADD_CHILDREN, 
  725.      m_nodes[m_focusNode].m_node.getRefer()));
  726. }
  727. else {
  728.   JOptionPane.showMessageDialog(this, "Sorry, there is no " + 
  729. "available Decision Tree to " +
  730. "perform this operation on.",
  731. "Sorry!", 
  732. JOptionPane.WARNING_MESSAGE);
  733. }
  734.       }
  735.       else {
  736. JOptionPane.showMessageDialog(this, "Error, there is no " +
  737.       "selected Node to perform this " +
  738.       "operation on.", "Error!",
  739.       JOptionPane.ERROR_MESSAGE);
  740.       }
  741.     }
  742.     else if (e.getActionCommand().equals("Remove Child Nodes")) {
  743.       if (m_focusNode >= 0) {
  744. if (m_listener != null) {
  745.   //then send message to the listener
  746.   m_listener.userCommand(new 
  747.     TreeDisplayEvent(TreeDisplayEvent.REMOVE_CHILDREN, 
  748.      m_nodes[m_focusNode].m_node.getRefer()));
  749. }
  750. else {
  751.   JOptionPane.showMessageDialog(this, "Sorry, there is no " + 
  752. "available Decsion Tree to " +
  753. "perform this operation on.",
  754. "Sorry!", 
  755. JOptionPane.WARNING_MESSAGE);
  756. }
  757.       }
  758.       else {
  759. JOptionPane.showMessageDialog(this, "Error, there is no " +
  760.       "selected Node to perform this " +
  761.       "operation on.", "Error!",
  762.       JOptionPane.ERROR_MESSAGE);
  763.       }
  764.     }
  765.     else if (e.getActionCommand().equals("classify_child")) {
  766.       if (m_focusNode >= 0) {
  767. if (m_listener != null) {
  768.   //then send message to the listener
  769.   m_listener.userCommand(new TreeDisplayEvent
  770.     (TreeDisplayEvent.CLASSIFY_CHILD, 
  771.      m_nodes[m_focusNode].m_node.getRefer()));
  772. }
  773. else {
  774.   JOptionPane.showMessageDialog(this, "Sorry, there is no " + 
  775. "available Decsion Tree to " +
  776. "perform this operation on.",
  777. "Sorry!", 
  778. JOptionPane.WARNING_MESSAGE);
  779. }
  780.       }
  781.       else {
  782. JOptionPane.showMessageDialog(this, "Error, there is no " +
  783.       "selected Node to perform this " +
  784.       "operation on.", "Error!",
  785.       JOptionPane.ERROR_MESSAGE);
  786.       }
  787.     }
  788.     else if (e.getActionCommand().equals("send_instances")) {
  789.       if (m_focusNode >= 0) {
  790. if (m_listener != null) {
  791.   //then send message to the listener
  792.   m_listener.userCommand(new TreeDisplayEvent
  793.     (TreeDisplayEvent.SEND_INSTANCES, 
  794.      m_nodes[m_focusNode].m_node.getRefer()));
  795. }
  796. else {
  797.   JOptionPane.showMessageDialog(this, "Sorry, there is no " + 
  798. "available Decsion Tree to " +
  799. "perform this operation on.",
  800. "Sorry!", 
  801. JOptionPane.WARNING_MESSAGE);
  802. }
  803.       }
  804.       else {
  805. JOptionPane.showMessageDialog(this, "Error, there is no " +
  806.       "selected Node to perform this " +
  807.       "operation on.", "Error!",
  808.       JOptionPane.ERROR_MESSAGE);
  809.       }
  810.     }
  811.     else if (e.getActionCommand().equals("Accept The Tree")) {
  812.       if (m_listener != null) {
  813. //then send message to the listener saying that the tree is done
  814. m_listener.userCommand(new TreeDisplayEvent(TreeDisplayEvent.ACCEPT,
  815.   null));
  816.       }
  817.       else {
  818. JOptionPane.showMessageDialog(this, "Sorry, there is no " +
  819.       "available Decision Tree to " +
  820.       "perform this operation on.",
  821.       "Sorry!", 
  822.       JOptionPane.WARNING_MESSAGE);
  823.       }
  824.     }
  825.   }
  826.   /**
  827.    * Performs the action associated with the ItemEvent.
  828.    *
  829.    * @param e the item event.
  830.    */
  831.   public void itemStateChanged(ItemEvent e)
  832.   {
  833.     JRadioButtonMenuItem c = (JRadioButtonMenuItem)e.getSource();
  834.     if (c.getActionCommand().equals("Size 24")) {
  835.       changeFontSize(24);
  836.     }
  837.     else if (c.getActionCommand().equals("Size 22")) {
  838.       changeFontSize(22);
  839.     }
  840.     else if (c.getActionCommand().equals("Size 20")) {
  841.       changeFontSize(20);
  842.     }
  843.     else if (c.getActionCommand().equals("Size 18")) {
  844.       changeFontSize(18);
  845.     } 
  846.     else if (c.getActionCommand().equals("Size 16")) {
  847.       changeFontSize(16);
  848.     }
  849.     else if (c.getActionCommand().equals("Size 14")) {
  850.       changeFontSize(14);
  851.     }
  852.     else if (c.getActionCommand().equals("Size 12")) {
  853.       changeFontSize(12);
  854.     }
  855.     else if (c.getActionCommand().equals("Size 10")) {
  856.       changeFontSize(10);
  857.     }
  858.     else if (c.getActionCommand().equals("Size 8")) {
  859.       changeFontSize(8);
  860.     }
  861.     else if (c.getActionCommand().equals("Size 6")) {
  862.       changeFontSize(6);
  863.     }
  864.     else if (c.getActionCommand().equals("Size 4")) {
  865.       changeFontSize(4);
  866.     }
  867.     else if (c.getActionCommand().equals("Size 2")) {
  868.       changeFontSize(2);
  869.     }
  870.     else if (c.getActionCommand().equals("Size 1")) {
  871.       changeFontSize(1);
  872.     }
  873.     else if (c.getActionCommand().equals("Hide Descendants")) {
  874.       //focus_node.setCVisible(!c.isSelected());
  875.       //no longer used...
  876.     }
  877.   }
  878.   /**
  879.    * Does nothing.
  880.    * @param e the mouse event.
  881.    */
  882.   public void mouseClicked(MouseEvent e) {
  883.     //if the mouse was left clicked on 
  884.     //the node then 
  885.     if (m_clickAvailable) {
  886.       //determine if the click was on a node or not
  887.       int s = -1;
  888.       
  889.       for (int noa = 0; noa < m_numNodes;noa++) {
  890. if (m_nodes[noa].m_quad == 18) {
  891.   //then is on the screen
  892.   calcScreenCoords(noa);
  893.   if (e.getX() <= m_nodes[noa].m_center + m_nodes[noa].m_side 
  894.       && e.getX() 
  895.       >= m_nodes[noa].m_center - m_nodes[noa].m_side &&
  896.       e.getY() >= m_nodes[noa].m_top && e.getY() 
  897.       <= m_nodes[noa].m_top + m_nodes[noa].m_height) {
  898.     //then it is this node that the mouse was clicked on
  899.     s = noa;
  900.   }
  901.   m_nodes[noa].m_top = 32000;
  902. }
  903.       }
  904.       m_focusNode = s;
  905.       
  906.       if (m_focusNode != -1) {
  907. if (m_listener != null) {
  908.   //then set this to be the selected node for editing
  909.   actionPerformed(new ActionEvent(this, 32000, "Create Child Nodes"));
  910.   
  911. }
  912. else {
  913.   //then open a visualize to display this nodes instances if possible
  914.   actionPerformed(new ActionEvent(this, 32000, "Visualize The Node"));
  915. }
  916.       }
  917.     }
  918.   }
  919.   
  920.   /**
  921.    * Determines what action the user wants to perform.
  922.    *
  923.    * @param e the mouse event.
  924.    */  
  925.   public void mousePressed(MouseEvent e) {
  926.     m_frameLimiter.setRepeats(true);
  927.     if ((e.getModifiers() & e.BUTTON1_MASK) != 0 && m_mouseState == 0 
  928. && m_scaling == 0) {
  929.       //then the left mouse button has been pressed
  930.       //check for modifiers
  931.       
  932.       if ((e.getModifiers() & e.CTRL_MASK) != 0) {
  933. //then is in zoom out mode
  934. m_mouseState = 2;
  935.       }
  936.       else if ((e.getModifiers() & e.SHIFT_MASK) != 0) {
  937. //then is in zoom mode
  938. //note if both are pressed default action is to zoom out
  939. m_oldMousePos.width = e.getX();
  940. m_oldMousePos.height = e.getY();
  941. m_newMousePos.width = e.getX();
  942. m_newMousePos.height = e.getY();
  943. m_mouseState = 3;
  944. Graphics g = getGraphics();
  945. g.setColor(Color.black);
  946. g.setXORMode(Color.white);
  947. g.drawRect(m_oldMousePos.width, m_oldMousePos.height,
  948.    m_newMousePos.width - m_oldMousePos.width, 
  949.    m_newMousePos.height - m_oldMousePos.height);
  950. g.dispose();
  951.       }
  952.       else {
  953. //no modifiers drag area around
  954. m_oldMousePos.width = e.getX();
  955. m_oldMousePos.height = e.getY();
  956. m_newMousePos.width = e.getX();
  957. m_newMousePos.height = e.getY();
  958. m_mouseState = 1;
  959. m_frameLimiter.start();
  960.       }
  961.       
  962.     }
  963.     else if (m_mouseState == 0 && m_scaling == 0) {
  964.       //either middle or right mouse button pushed
  965.       //determine menu to use
  966.       
  967.     }
  968.   }
  969.   
  970.   /**
  971.    * Performs the final stages of what the user wants to perform.
  972.    *
  973.    * @param e the mouse event.
  974.    */
  975.   public void mouseReleased(MouseEvent e) {
  976.     
  977.     if (m_mouseState == 1) {
  978.       //this is used by mouseClicked to determine if it is alright to do 
  979.       //something
  980.       m_clickAvailable = true;
  981. //note that a standard click with the left mouse is pretty much the 
  982.       //only safe input left to be assigned anything.
  983.     }
  984.     else {
  985.       m_clickAvailable = false;
  986.     }
  987.     if (m_mouseState == 2 && mouseInBounds(e)) {
  988.       //then zoom out;
  989.       m_mouseState = 0;
  990.       Dimension ns = new Dimension(m_viewSize.width / 2, m_viewSize.height 
  991.    / 2);
  992.       if (ns.width < 10) {
  993. ns.width = 10;
  994.       }
  995.       if (ns.height < 10) {
  996. ns.height = 10;
  997.       }
  998.       
  999.       Dimension d = getSize();
  1000.       Dimension np = new Dimension((int)(d.width / 2 
  1001.  - ((double)d.width / 2 
  1002.     - m_viewPos.width) / 2),
  1003.    (int)(d.height / 2 
  1004.  - ((double)d.height / 2
  1005.     - m_viewPos.height) / 2));
  1006.       
  1007.       animateScaling(np, ns, 10);
  1008.       
  1009.       //view_pos.width += view_size.width / 2;
  1010.       //view_pos.height += view_size.height / 2;
  1011.       
  1012.     }
  1013.     else if (m_mouseState == 3) {
  1014.       //then zoom in
  1015.       m_mouseState = 0;
  1016.       Graphics g = getGraphics();
  1017.       g.setColor(Color.black);
  1018.       g.setXORMode(Color.white);
  1019.       g.drawRect(m_oldMousePos.width, m_oldMousePos.height, 
  1020.  m_newMousePos.width - m_oldMousePos.width, 
  1021.  m_newMousePos.height - m_oldMousePos.height);
  1022.       g.dispose();
  1023.       
  1024.       
  1025.       
  1026.       int cw = m_newMousePos.width - m_oldMousePos.width;
  1027.       int ch = m_newMousePos.height - m_oldMousePos.height;
  1028.       if (cw >= 1 && ch >= 1) {
  1029. if (mouseInBounds(e) && 
  1030.     (getSize().width / cw) <= 6 &&
  1031.     (getSize().height / ch) <= 6) {
  1032.   
  1033.   //now calculate new position and size
  1034.   Dimension ns = new Dimension();
  1035.   Dimension np = new Dimension();
  1036.   double nvsw = getSize().width / (double)(cw);
  1037.   double nvsh = getSize().height / (double)(ch);
  1038.   np.width = (int)((m_oldMousePos.width - m_viewPos.width) * -nvsw);
  1039.   np.height = (int)((m_oldMousePos.height - m_viewPos.height) * -nvsh);
  1040.   ns.width = (int)(m_viewSize.width * nvsw);
  1041.   ns.height = (int)(m_viewSize.height * nvsh);
  1042.   
  1043.   animateScaling(np, ns, 10);
  1044.   
  1045.   
  1046. }
  1047.       }
  1048.     }
  1049.     else if (m_mouseState == 0 && m_scaling == 0) {
  1050.       //menu
  1051.       m_mouseState = 0;
  1052.       setFont(new Font("A Name", 0, 12));
  1053.       //determine if the click was on a node or not
  1054.       int s = -1;
  1055.       
  1056.       for (int noa = 0; noa < m_numNodes;noa++) {
  1057. if (m_nodes[noa].m_quad == 18) {
  1058.   //then is on the screen
  1059.   calcScreenCoords(noa);
  1060.   if (e.getX() <= m_nodes[noa].m_center + m_nodes[noa].m_side 
  1061.       && e.getX() 
  1062.       >= m_nodes[noa].m_center - m_nodes[noa].m_side &&
  1063.       e.getY() >= m_nodes[noa].m_top && e.getY() 
  1064.       <= m_nodes[noa].m_top + m_nodes[noa].m_height) {
  1065.     //then it is this node that the mouse was clicked on
  1066.     s = noa;
  1067.   }
  1068.   m_nodes[noa].m_top = 32000;
  1069. }
  1070.       }
  1071.       if (s == -1) {
  1072. //the mouse wasn't clicked on a node
  1073. m_winMenu.show(this,e.getX(),e.getY());
  1074.       }
  1075.       else {
  1076. //the mouse was clicked on a node
  1077. m_focusNode = s;
  1078. m_nodeMenu.show(this, e.getX(), e.getY());
  1079.       }
  1080.       setFont(m_currentFont);
  1081.     }
  1082.     else if (m_mouseState == 1) {
  1083.       //dragging
  1084.       m_mouseState = 0;
  1085.       m_frameLimiter.stop();
  1086.       repaint();
  1087.     }
  1088.     
  1089.   }
  1090.   
  1091.   /**
  1092.    * Checks to see if the coordinates of the mouse lie on this JPanel.
  1093.    *
  1094.    * @param e the mouse event.
  1095.    * @return true if the mouse lies on this JPanel. 
  1096.    */
  1097.   private boolean mouseInBounds(MouseEvent e) {
  1098.     //this returns true if the mouse is currently over the canvas otherwise 
  1099.     //false
  1100.     
  1101.     if (e.getX() < 0 || e.getY() < 0 || e.getX() > getSize().width 
  1102. || e.getY() > getSize().height) {
  1103.       return false;
  1104.     }
  1105.     return true;
  1106.   }
  1107.   
  1108.   /**
  1109.    * Performs intermediate updates to what the user wishes to do.
  1110.    *
  1111.    * @param e the mouse event.
  1112.    */
  1113.   public void mouseDragged(MouseEvent e) {
  1114.     //use mouse state to determine what to do to the view of the tree
  1115.     
  1116.     if (m_mouseState == 1) {
  1117.       //then dragging view
  1118.       m_oldMousePos.width = m_newMousePos.width;
  1119.       m_oldMousePos.height = m_newMousePos.height;
  1120.       m_newMousePos.width = e.getX();
  1121.       m_newMousePos.height = e.getY();
  1122.       m_viewPos.width += m_newMousePos.width - m_oldMousePos.width;
  1123.       m_viewPos.height += m_newMousePos.height - m_oldMousePos.height;
  1124.       
  1125.       
  1126.     }
  1127.     else if (m_mouseState == 3) {
  1128.       //then zoom box being created
  1129.       //redraw the zoom box
  1130.       Graphics g = getGraphics();
  1131.       g.setColor(Color.black);
  1132.       g.setXORMode(Color.white);
  1133.       g.drawRect(m_oldMousePos.width, m_oldMousePos.height,
  1134.  m_newMousePos.width - m_oldMousePos.width, 
  1135.  m_newMousePos.height - m_oldMousePos.height);
  1136.       
  1137.       m_newMousePos.width = e.getX();
  1138.       m_newMousePos.height = e.getY();
  1139.       
  1140.       g.drawRect(m_oldMousePos.width, m_oldMousePos.height,
  1141.  m_newMousePos.width - m_oldMousePos.width, 
  1142.  m_newMousePos.height - m_oldMousePos.height);
  1143.       g.dispose();
  1144.     }
  1145.     
  1146.     
  1147.   }
  1148.   
  1149.   /**
  1150.    * Does nothing.
  1151.    *
  1152.    * @param e the mouse event.
  1153.    */
  1154.   public void mouseMoved(MouseEvent e) {
  1155.   }
  1156.   /**
  1157.    * Does nothing.
  1158.    *
  1159.    * @param e the mouse event.
  1160.    */
  1161.   public void mouseEntered(MouseEvent e) {
  1162.   }
  1163.   
  1164.   /**
  1165.    * Does nothing.
  1166.    * 
  1167.    * @param e the mouse event.
  1168.    */
  1169.   public void mouseExited(MouseEvent e) {
  1170.   }
  1171.   /**
  1172.    * Set the highlight for the node with the given id
  1173.    * @param id the id of the node to set the highlight for
  1174.    */
  1175.   public void setHighlight(String id) {
  1176.     //set the highlight for the node with the given id
  1177.     
  1178.     for (int noa = 0; noa < m_numNodes; noa++) {
  1179.       if (id.equals(m_nodes[noa].m_node.getRefer())) {
  1180. //then highlight this node
  1181. m_highlightNode = noa;
  1182.       }
  1183.     }
  1184.     //System.out.println("ahuh " + highlight_node + " " + 
  1185.     //nodes[0].node.getRefer());
  1186.     repaint();
  1187.     
  1188.   }
  1189.   
  1190.   /**
  1191.    * Updates the screen contents.
  1192.    *
  1193.    * @param g the drawing surface.
  1194.    */
  1195.   public void paintComponent(Graphics g) {
  1196.     //System.out.println(nodes[0].top + "this is seriously pissing me off");
  1197.     g.clearRect(0, 0, getSize().width, getSize().height);
  1198.     g.setClip(3, 7, getWidth() - 6, getHeight() - 10);
  1199.     painter(g);
  1200.     g.setClip(0, 0, getWidth(), getHeight());
  1201.     
  1202.   }
  1203.   /**
  1204.    * Draws the tree to the graphics context
  1205.    *
  1206.    * @param g the drawing surface.
  1207.    */
  1208.   private void painter(Graphics g) {
  1209.     //I have moved what would normally be in the paintComponent 
  1210.     //function to here 
  1211.     //for now so that if I do in fact need to do double 
  1212.     //buffering or the like it will be easier
  1213.     //this will go through the table of edges and draw the edge if it deems the
  1214.     //two nodes attached to it could cause it to cut the screen or be on it.
  1215.     
  1216.     //in the process flagging all nodes so that they can quickly be put to the
  1217.     //screen if they lie on it
  1218.     //I do it in this order because in some circumstances I have seen a line
  1219.     //cut through a node , to make things look better the line will
  1220.     //be drawn under the node
  1221.     //converting the screen edges to the node scale so that they 
  1222.     //can be positioned relative to the screen
  1223.     //note I give a buffer around the edges of the screen.
  1224.     
  1225.     //when seeing
  1226.     //if a node is on screen I only bother to check the nodes top centre 
  1227.     //if it has large enough size it may still fall onto the screen
  1228.     double left_clip = (double)(-m_viewPos.width - 50) / m_viewSize.width;
  1229.     double right_clip = (double)(getSize().width - m_viewPos.width + 50) / 
  1230.       m_viewSize.width;
  1231.     double top_clip = (double)(-m_viewPos.height - 50) / m_viewSize.height;
  1232.     double bottom_clip = (double)(getSize().height - m_viewPos.height + 50) / 
  1233.       m_viewSize.height;
  1234.   
  1235.     
  1236.     //  12 10  9           //the quadrants
  1237.     //  20 18 17
  1238.     //  36 34 33
  1239.     //first the edges must be rendered
  1240.     Edge e;
  1241.     Node r,s;
  1242.     double ncent,ntop;    
  1243.     int row = 0, col = 0, pq, cq;
  1244.     for (int noa = 0 ; noa < m_numNodes ; noa++) {
  1245.       r = m_nodes[noa].m_node;
  1246.       if (m_nodes[noa].m_change) {
  1247. //then recalc row component of quadrant
  1248. ntop = r.getTop();
  1249. if (ntop < top_clip) {
  1250.   row = 8;
  1251. }
  1252. else if (ntop > bottom_clip) {
  1253.   row = 32;
  1254. }
  1255. else {
  1256.   row = 16;
  1257. }
  1258.       }
  1259.       
  1260.       //calc the column the node falls in for the quadrant
  1261.       ncent = r.getCenter();
  1262.       if (ncent < left_clip) {
  1263. col = 4;
  1264.       }
  1265.       else if (ncent > right_clip) {
  1266. col = 1;
  1267.       }
  1268.       else {
  1269. col = 2;
  1270.       }
  1271.       
  1272.       m_nodes[noa].m_quad = row | col;
  1273.       
  1274.       if (m_nodes[noa].m_parent >= 0) {
  1275. //this will draw the edge if it should be drawn 
  1276. //It will do this by eliminating all edges that definitely won't enter
  1277. //the screen and then draw the rest
  1278. pq = m_nodes[m_edges[m_nodes[noa].m_parent].m_parent].m_quad;
  1279. cq = m_nodes[noa].m_quad;
  1280. //note that this will need to be altered if more than 1 parent exists
  1281. if ((cq & 8) == 8) {
  1282.   //then child exists above screen
  1283. }
  1284. else if ((pq & 32) == 32) {
  1285.   //then parent exists below screen
  1286. }
  1287. else if ((cq & 4) == 4 && (pq & 4) == 4) {
  1288.   //then both child and parent exist to the left of the screen
  1289. }
  1290. else if ((cq & 1) == 1 && (pq & 1) == 1) {
  1291.   //then both child and parent exist to the right of the screen
  1292. }
  1293. else {
  1294.   //then draw the line
  1295.   drawLine(m_nodes[noa].m_parent, g);
  1296. }
  1297.       }
  1298.       
  1299.       //now draw the nodes
  1300.     }
  1301.     
  1302.     for (int noa = 0 ;noa < m_numNodes; noa++) {
  1303.       if (m_nodes[noa].m_quad == 18) {
  1304. //then the node is on the screen , draw it
  1305. drawNode(noa, g);
  1306.       }
  1307.     }
  1308.     
  1309.     if (m_highlightNode >= 0 && m_highlightNode < m_numNodes) {
  1310.       //then draw outline
  1311.       if (m_nodes[m_highlightNode].m_quad == 18) {
  1312. Color acol = m_nodes[m_highlightNode].m_node.getColor();
  1313. g.setColor(new Color((acol.getRed() + 125) % 256, 
  1314.      (acol.getGreen() + 125) % 256, 
  1315.      (acol.getBlue() + 125) % 256));
  1316. //g.setXORMode(Color.white);
  1317. if (m_nodes[m_highlightNode].m_node.getShape() == 1) {
  1318.   g.drawRect(m_nodes[m_highlightNode].m_center 
  1319.      - m_nodes[m_highlightNode].m_side,
  1320.      m_nodes[m_highlightNode].m_top, 
  1321.      m_nodes[m_highlightNode].m_width, 
  1322.      m_nodes[m_highlightNode].m_height);
  1323.   
  1324.   g.drawRect(m_nodes[m_highlightNode].m_center 
  1325.      - m_nodes[m_highlightNode].m_side 
  1326.      + 1, m_nodes[m_highlightNode].m_top + 1,
  1327.      m_nodes[m_highlightNode].m_width - 2, 
  1328.      m_nodes[m_highlightNode].m_height - 2);
  1329. }
  1330. else if (m_nodes[m_highlightNode].m_node.getShape() == 2) {
  1331.   g.drawOval(m_nodes[m_highlightNode].m_center 
  1332.      - m_nodes[m_highlightNode].m_side,
  1333.      m_nodes[m_highlightNode].m_top, 
  1334.      m_nodes[m_highlightNode].m_width, 
  1335.      m_nodes[m_highlightNode].m_height);
  1336.   
  1337.   g.drawOval(m_nodes[m_highlightNode].m_center 
  1338.      - m_nodes[m_highlightNode].m_side 
  1339.      + 1, m_nodes[m_highlightNode].m_top + 1,
  1340.      m_nodes[m_highlightNode].m_width - 2, 
  1341.      m_nodes[m_highlightNode].m_height - 2);
  1342. }
  1343.       }
  1344.     }
  1345.     
  1346.     for (int noa = 0;noa < m_numNodes;noa++) {
  1347.       //this resets the coords so that next time a refresh occurs 
  1348.       //they don't accidentally get used
  1349.       //I will use 32000 to signify that they are invalid, even if this 
  1350.       //coordinate occurs it doesn't
  1351.       //matter as it is only for the sake of the caching
  1352.       
  1353.       m_nodes[noa].m_top = 32000;
  1354.     }
  1355.   }
  1356.   
  1357.   /**
  1358.    * Determines the attributes of the node and draws it.
  1359.    *
  1360.    * @param n A subscript identifying the node in <i>nodes</i> array
  1361.    * @param g The drawing surface
  1362.    */
  1363.   private void drawNode(int n, Graphics g) {
  1364.     //this will draw a node and then print text on it
  1365.     
  1366.     g.setColor(m_nodes[n].m_node.getColor());
  1367.     g.setPaintMode();
  1368.     calcScreenCoords(n);
  1369.     int x = m_nodes[n].m_center - m_nodes[n].m_side;
  1370.     int y = m_nodes[n].m_top;
  1371.     if (m_nodes[n].m_node.getShape() == 1) {
  1372.       g.fill3DRect(x, y, m_nodes[n].m_width, m_nodes[n].m_height, true);
  1373.       drawText(x, y, n, false, g);
  1374.       
  1375.     }
  1376.     else if (m_nodes[n].m_node.getShape() == 2) {
  1377.       
  1378.       g.fillOval(x, y, m_nodes[n].m_width, m_nodes[n].m_height);
  1379.       drawText(x, y + (int)(m_nodes[n].m_height * .15), n, false, g);
  1380.     }
  1381.   }
  1382.   
  1383.   /**
  1384.    * Determines the attributes of the edge and draws it.
  1385.    *
  1386.    * @param e A subscript identifying the edge in <i>edges</i> array.
  1387.    * @param g The drawing surface.
  1388.    */
  1389.   private void drawLine(int e, Graphics g) {
  1390.     //this will draw a line taking in the edge number and then getting 
  1391.     //the nodes subscript for the parent and child entries
  1392.     
  1393.     //this will draw a line that has been broken in the middle 
  1394.     //for the edge text to be displayed 
  1395.     //if applicable
  1396.     
  1397.     //first convert both parent and child node coords to screen coords
  1398.     int p = m_edges[e].m_parent;
  1399.     int c = m_edges[e].m_child;
  1400.     calcScreenCoords(c);
  1401.     calcScreenCoords(p);
  1402.     
  1403.     g.setColor(Color.black);
  1404.     g.setPaintMode();
  1405.     
  1406.     if (m_currentFont.getSize() < 2) {
  1407.       //text to small to bother cutting the edge
  1408.       g.drawLine(m_nodes[p].m_center, m_nodes[p].m_top + m_nodes[p].m_height, 
  1409.  m_nodes[c].m_center, m_nodes[c].m_top); 
  1410.       
  1411.     }
  1412.     else {
  1413.       //find where to cut the edge to insert text
  1414.       int e_width = m_nodes[c].m_center - m_nodes[p].m_center;
  1415.       int e_height = m_nodes[c].m_top - (m_nodes[p].m_top 
  1416.  + m_nodes[p].m_height);
  1417.       int e_width2 = e_width / 2;
  1418.       int e_height2 = e_height / 2;
  1419.       int e_centerx = m_nodes[p].m_center + e_width2;
  1420.       int e_centery = m_nodes[p].m_top + m_nodes[p].m_height + e_height2;
  1421.       int e_offset = m_edges[e].m_tb;
  1422.       
  1423.       int tmp = (int)(((double)e_width / e_height) * 
  1424.       (e_height2 - e_offset)) + m_nodes[p].m_center;
  1425.       //System.out.println(edges[e].m_height);
  1426.       
  1427.       //draw text now
  1428.       
  1429.       drawText(e_centerx - m_edges[e].m_side, e_centery - e_offset, e, true
  1430.        , g);
  1431.       
  1432.       
  1433.       if (tmp > (e_centerx - m_edges[e].m_side) && tmp 
  1434.   < (e_centerx + m_edges[e].m_side)) {
  1435. //then cut line on top and bottom of text
  1436. g.drawLine(m_nodes[p].m_center, m_nodes[p].m_top + m_nodes[p].m_height
  1437.    , tmp, e_centery - e_offset);  //first segment
  1438. g.drawLine(e_centerx * 2 - tmp, e_centery + e_offset, 
  1439.    m_nodes[c].m_center, m_nodes[c].m_top);    //second segment
  1440.       }
  1441.       else {
  1442. e_offset = m_edges[e].m_side;
  1443. if (e_width < 0) {
  1444.   e_offset *= -1;   //adjusting for direction which could otherwise 
  1445.   //screw up the calculation
  1446. }
  1447. tmp = (int)(((double)e_height / e_width) * (e_width2 - e_offset)) + 
  1448.   m_nodes[p].m_top + m_nodes[p].m_height;
  1449. g.drawLine(m_nodes[p].m_center, m_nodes[p].m_top + m_nodes[p].m_height
  1450.    , e_centerx - e_offset, tmp);   //first segment
  1451. g.drawLine(e_centerx + e_offset, e_centery * 2 - tmp, 
  1452.    m_nodes[c].m_center, m_nodes[c].m_top);  //second segment
  1453.       }
  1454.     }
  1455.     //System.out.println("here" + nodes[p].center);
  1456.   }
  1457.   /**
  1458.    * Draws the text for either an Edge or a Node.
  1459.    *
  1460.    * @param x1 the left side of the text area.
  1461.    * @param y1 the top of the text area.
  1462.    * @param s A subscript identifying either a Node or Edge.
  1463.    * @param e_or_n Distinguishes whether it is a node or edge.
  1464.    * @param g The drawing surface.
  1465.    */
  1466.   private void drawText(int x1, int y1, int s, boolean e_or_n, Graphics g) {
  1467.     //this function will take in the rectangle that the text should be 
  1468.     //drawn in as well as the subscript
  1469.     //for either the edge or node and a boolean variable to tell which
  1470.     g.setPaintMode();
  1471.     g.setColor(Color.black);
  1472.     String st;
  1473.     if (e_or_n) {
  1474.       //then paint for edge
  1475.       Edge e = m_edges[s].m_edge;
  1476.       for (int noa = 0;(st = e.getLine(noa)) != null; noa++) {
  1477. g.drawString(st, (m_edges[s].m_width - m_fontSize.stringWidth(st)) / 2 
  1478.      + x1,
  1479.      y1 + (noa + 1) * m_fontSize.getHeight()); 
  1480.       }
  1481.     }
  1482.     else {
  1483.       //then paint for node
  1484.       Node e = m_nodes[s].m_node;
  1485.       for (int noa = 0;(st = e.getLine(noa)) != null; noa++) {
  1486. g.drawString(st, (m_nodes[s].m_width - m_fontSize.stringWidth(st)) / 2 
  1487.      + x1,
  1488.      y1 + (noa + 1) * m_fontSize.getHeight()); 
  1489.       }
  1490.     }
  1491.   }
  1492.   
  1493.   /**
  1494.    * Converts the internal coordinates of the node found from <i>n</i>
  1495.    * and converts them to the actual screen coordinates.
  1496.    *
  1497.    * @param n A subscript identifying the Node.
  1498.    */
  1499.   private void calcScreenCoords(int n) {
  1500.     //this converts the coordinate system the Node uses into screen coordinates
  1501.     // System.out.println(n + " " + view_pos.height + " " + 
  1502.     //nodes[n].node.getCenter());
  1503.     if (m_nodes[n].m_top == 32000) {
  1504.       m_nodes[n].m_top = ((int)(m_nodes[n].m_node.getTop() 
  1505. * m_viewSize.height)) + m_viewPos.height;
  1506.       m_nodes[n].m_center = ((int)(m_nodes[n].m_node.getCenter() 
  1507.    * m_viewSize.width)) + m_viewPos.width;
  1508.     }
  1509.   }
  1510.   /**
  1511.    * This Calculates the minimum size of the tree which will prevent any text
  1512.    * overlapping and make it readable, and then set the size of the tree to 
  1513.    * this.
  1514.    */
  1515.   private void autoScale() {
  1516.     //this function will determine the smallest scale value that keeps the text
  1517.     //from overlapping
  1518.     //it will leave the view centered
  1519.     
  1520.     int dist;
  1521.     Node ln,rn;
  1522.     Dimension temp = new Dimension(10, 10);
  1523.     
  1524.     if (m_numNodes <= 1) {
  1525.       return;
  1526.     }
  1527.     
  1528.     //calc height needed by first node
  1529.     dist = (m_nodes[0].m_height + 40) * m_numLevels;
  1530.     if (dist > temp.height) {
  1531.       temp.height = dist;
  1532.     }
  1533.     
  1534.     for (int noa = 0;noa < m_numNodes - 1;noa++) {
  1535.       calcScreenCoords(noa);  
  1536.       calcScreenCoords(noa+1);
  1537.       if (m_nodes[noa+1].m_change) {
  1538. //then on a new level so don't check width this time round
  1539.       }
  1540.       else {
  1541. dist = m_nodes[noa+1].m_center - m_nodes[noa].m_center; 
  1542. //the distance between the node centers, along horiz
  1543. if (dist <= 0) {
  1544.   dist = 1;
  1545. }
  1546. dist = ((6 + m_nodes[noa].m_side + m_nodes[noa+1].m_side) 
  1547. * m_viewSize.width) / dist; //calc optimal size for width
  1548. if (dist > temp.width) {
  1549.   
  1550.   temp.width = dist;
  1551. }
  1552.       }
  1553.       //now calc.. minimun hieght needed by nodes
  1554.       
  1555.       dist = (m_nodes[noa+1].m_height + 40) * m_numLevels;
  1556.       if (dist > temp.height) {
  1557. temp.height = dist;
  1558.       }
  1559.     }
  1560.     
  1561.     int y1, y2, xa, xb;
  1562.     
  1563.     y1 = m_nodes[m_edges[0].m_parent].m_top;
  1564.     y2 = m_nodes[m_edges[0].m_child].m_top;
  1565.     
  1566.     dist = y2 - y1;
  1567.     if (dist <= 0) {
  1568.       dist = 1;
  1569.     }
  1570.     dist = ((60 + m_edges[0].m_height + m_nodes[m_edges[0].m_parent].m_height) 
  1571.     * m_viewSize.height) / dist;
  1572.     if (dist > temp.height) {
  1573.       
  1574.       temp.height = dist;
  1575.     }
  1576.     
  1577.     for (int noa = 0;noa < m_numNodes - 2; noa++) {
  1578.       //check the edges now
  1579.       if (m_nodes[m_edges[noa+1].m_child].m_change) {
  1580. //then edge is on a different level , so skip this one
  1581.       }
  1582.       else {
  1583. //calc the width requirements of this pair of edges
  1584. xa = m_nodes[m_edges[noa].m_child].m_center 
  1585.   - m_nodes[m_edges[noa].m_parent].m_center;
  1586. xa /= 2;
  1587. xa += m_nodes[m_edges[noa].m_parent].m_center;
  1588. xb = m_nodes[m_edges[noa+1].m_child].m_center - 
  1589.   m_nodes[m_edges[noa+1].m_parent].m_center;
  1590. xb /= 2;
  1591. xb += m_nodes[m_edges[noa+1].m_parent].m_center;
  1592. dist = xb - xa;
  1593. if (dist <= 0) {
  1594.   dist = 1;
  1595. }
  1596. dist = ((12 + m_edges[noa].m_side + m_edges[noa+1].m_side) 
  1597. * m_viewSize.width) 
  1598.   / dist;
  1599. if (dist > temp.width) {
  1600.   
  1601.   temp.width = dist;
  1602. }
  1603.       }
  1604.       //now calc height need by the edges
  1605.       y1 = m_nodes[m_edges[noa+1].m_parent].m_top;
  1606.       y2 = m_nodes[m_edges[noa+1].m_child].m_top;
  1607.       
  1608.       dist = y2 - y1;
  1609.       if (dist <= 0) {
  1610. dist = 1;
  1611.       }
  1612.       dist = ((60 + m_edges[noa+1].m_height 
  1613.        + m_nodes[m_edges[noa+1].m_parent].m_height) 
  1614.       * m_viewSize.height) / dist;
  1615.       
  1616.       if (dist > temp.height) {
  1617. temp.height = dist;
  1618.       }
  1619.     }
  1620.     Dimension e = getSize();
  1621.     
  1622.     Dimension np = new Dimension();
  1623.     np.width = (int)(e.width / 2 -  (((double)e.width / 2) - m_viewPos.width) /
  1624.      ((double)m_viewSize.width) * (double)temp.width);
  1625.     np.height = (int)(e.height / 2 -  (((double)e.height / 2) - 
  1626.        m_viewPos.height) /       
  1627.       ((double)m_viewSize.height) * (double)temp.height);
  1628.     //animate_scaling(c_size,c_pos,25);
  1629.     
  1630.     for (int noa = 0;noa < m_numNodes;noa++) {
  1631.       //this resets the coords so that next time a refresh occurs they don't 
  1632.       //accidentally get used
  1633.       //I will use 32000 to signify that they are invalid, even if this 
  1634.       //coordinate occurs it doesn't
  1635.       //matter as it is only for the sake of the caching
  1636.       
  1637.       m_nodes[noa].m_top = 32000;
  1638.       
  1639.     }
  1640.     animateScaling(np, temp, 10);
  1641.   }
  1642.   /**
  1643.    * This will increment the size and position of the tree towards the 
  1644.    * desired size and position
  1645.    * a little (depending on the value of <i>frames</i>) everytime it is called.
  1646.    *
  1647.    * @param n_pos The final position of the tree wanted.
  1648.    * @param n_size The final size of the tree wanted.
  1649.    * @param frames The number of frames that shall occur before the final 
  1650.    * size and pos is reached.
  1651.    */
  1652.   private void animateScaling(Dimension n_pos,Dimension n_size,int frames) {
  1653.     //this function will take new size and position coords , and incrementally
  1654.     //scale the view to these
  1655.     //since I will be tying it in with the framelimiter I will simply call 
  1656.     //this function and increment it once
  1657.     //I will have to use a global variable since I am doing it proportionally
  1658.     if (frames == 0) {
  1659.       System.out.println("the timer didn't end in time");
  1660.       m_scaling = 0;
  1661.     }
  1662.     else {
  1663.       if (m_scaling == 0) {
  1664. //new animate session
  1665. //start timer and set scaling
  1666. m_frameLimiter.start();
  1667. m_nViewPos.width = n_pos.width;
  1668. m_nViewPos.height = n_pos.height;
  1669. m_nViewSize.width = n_size.width;
  1670. m_nViewSize.height = n_size.height;
  1671. m_scaling = frames;
  1672.       }
  1673.       
  1674.       int s_w = (n_size.width - m_viewSize.width) / frames;
  1675.       int s_h = (n_size.height - m_viewSize.height) / frames;
  1676.       int p_w = (n_pos.width - m_viewPos.width) / frames;
  1677.       int p_h = (n_pos.height - m_viewPos.height) / frames;
  1678.       
  1679.       m_viewSize.width += s_w;
  1680.       m_viewSize.height += s_h;
  1681.       
  1682.       m_viewPos.width += p_w;
  1683.       m_viewPos.height += p_h;
  1684.       
  1685.       repaint();
  1686.       
  1687.       m_scaling--;
  1688.       if (m_scaling == 0) {
  1689. //all done 
  1690. m_frameLimiter.stop();
  1691.       }
  1692.     }
  1693.   }
  1694.   
  1695.   /**
  1696.    * This will change the font size for displaying the tree to the one 
  1697.    * specified.
  1698.    *
  1699.    * @param s The new pointsize of the font.
  1700.    */
  1701.   private void changeFontSize(int s) {
  1702.     //this will set up the new font that shall be used
  1703.     //it will also recalculate the size of the nodes as these will change as 
  1704.     //a result of 
  1705.     //the new font size
  1706.     setFont(m_currentFont = new Font("A Name", 0, s));             
  1707.     m_fontSize = getFontMetrics(getFont());
  1708.     
  1709.     Dimension d;
  1710.     for (int noa = 0; noa < m_numNodes; noa++) {
  1711.       //this will set the size info for each node and edge
  1712.       
  1713.       d = m_nodes[noa].m_node.stringSize(m_fontSize);
  1714.       
  1715.       if (m_nodes[noa].m_node.getShape() == 1) {
  1716. m_nodes[noa].m_height = d.height + 10;
  1717. m_nodes[noa].m_width = d.width + 8;
  1718. m_nodes[noa].m_side = m_nodes[noa].m_width / 2;
  1719.       }
  1720.       else if (m_nodes[noa].m_node.getShape() == 2) {
  1721. m_nodes[noa].m_height = (int)((d.height + 2) * 1.6);
  1722. m_nodes[noa].m_width = (int)((d.width + 2) * 1.6);
  1723. m_nodes[noa].m_side = m_nodes[noa].m_width / 2;
  1724.       }
  1725.       
  1726.       if (noa < m_numNodes - 1) {
  1727. //this will do the same for edges
  1728. d = m_edges[noa].m_edge.stringSize(m_fontSize);
  1729. m_edges[noa].m_height =  d.height + 8;
  1730. m_edges[noa].m_width = d.width + 8;
  1731. m_edges[noa].m_side = m_edges[noa].m_width / 2;
  1732. m_edges[noa].m_tb = m_edges[noa].m_height / 2;
  1733.       }
  1734.     }
  1735.   }
  1736.   /**
  1737.    * This will fill two arrays with the Nodes and Edges from the tree
  1738.    * into a particular order.
  1739.    *
  1740.    * @param t The top Node of the tree.
  1741.    * @param l An array that has already been allocated, to be filled.
  1742.    * @param k An array that has already been allocated, to be filled.
  1743.    */
  1744.   private void arrayFill(Node t, NodeInfo[] l, EdgeInfo[] k) {
  1745.     
  1746.     //this will take the top node and the array to fill
  1747.     //it will go through the tree structure and and fill the array with the 
  1748.     //nodes 
  1749.     //from top to bottom left to right
  1750.     
  1751.     //note I do not believe this function will be able to deal with multiple 
  1752.     //parents
  1753.     if (t == null || l == null) {
  1754.       System.exit(1);      //this is just a preliminary safety check 
  1755.       //(i shouldn' need it)
  1756.     }
  1757.     
  1758.     Edge e;
  1759.     Node r,s;
  1760.     l[0] = new NodeInfo();
  1761.     l[0].m_node = t;
  1762.     l[0].m_parent = -1;
  1763.     l[0].m_change = true;
  1764.     
  1765.     int floater;       //this will point at a node that has previously been 
  1766.     //put in the list 
  1767.     //all of the children that this node has shall be put in the list , 
  1768.     //once this is done the floater shall point at the next node in the list
  1769.     //this will allow the nodes to be put into order from closest to top node
  1770.     //to furtherest from top node
  1771.     int free_space = 1; //the next empty array position
  1772.     double height = t.getTop(); //this will be used to determine if the node 
  1773.     //has a 
  1774.     //new height compared to the
  1775.     //previous one
  1776.     for (floater = 0;floater < free_space;floater++) {
  1777.       r = l[floater].m_node;
  1778.       for (int noa = 0;(e = r.getChild(noa)) != null;noa++) {
  1779. //this loop pulls out each child of r
  1780. //e points to a child edge, getTarget will return that edges child node
  1781. s = e.getTarget();
  1782. l[free_space] = new NodeInfo();
  1783. l[free_space].m_node = s;
  1784. l[free_space].m_parent = free_space - 1;
  1785. k[free_space - 1] = new EdgeInfo();
  1786. k[free_space - 1].m_edge = e;
  1787. k[free_space - 1].m_parent = floater;
  1788. k[free_space - 1].m_child = free_space;     //note although it's child 
  1789. //will always have a subscript
  1790. //of 1 more , I may not nessecarily have access to that
  1791. //and it will need the subscr.. for multiple parents
  1792. //determine if level of node has changed from previous one
  1793. if (height != s.getTop()) {
  1794.   l[free_space].m_change = true;
  1795.   height = s.getTop();
  1796. }
  1797. else {
  1798.   l[free_space].m_change = false;
  1799. }
  1800. free_space++;
  1801.       }
  1802.     }
  1803.   }
  1804.   /**
  1805.    * Internal Class for containing display information about a Node. 
  1806.    */
  1807.   private class NodeInfo {
  1808.     //this class contains a pointer to the node itself along with extra 
  1809.     //information
  1810.     //about the node used by the Displayer class
  1811.     /** The y pos of the node on screen. */
  1812.     int m_top = 32000;           //the main node coords calculated out
  1813.     /** The x pos of the node on screen. */
  1814.     int m_center;        // these coords will probably change each refresh 
  1815.     //and are the positioning coords
  1816.     //which the rest of the offsets use
  1817.     
  1818.     /** The offset to get to the left or right of the node. */
  1819.     int m_side;          //these are the screen offset for the dimensions of 
  1820.     //the node relative to the nodes 
  1821.     //internal top and center values (after they have been converted to 
  1822.     //screen coords
  1823.     /** The width of the node. */
  1824.     int m_width;
  1825.     /** The height of the node. */
  1826.     int m_height;
  1827.     /** True if the node is at the start (left) of a new level (not sibling 
  1828.      * group). */
  1829.     boolean m_change;    //this is quickly used to identify whether the node 
  1830.     //has chenged height from the
  1831.     //previous one to help speed up the calculation of what row it lies in
  1832.     /** The subscript number of the Nodes parent. */
  1833.     int m_parent;     //this is the index of the nodes parent edge in an array
  1834.     /** The rough position of the node relative to the screen. */
  1835.     int m_quad;       //what of nine quadrants is it in
  1836.     /*
  1837.       12 10  9
  1838.       20 18 17          //18 being the screen
  1839.       36 34 33          //this arrangement uses 6 bits, each bit represents a 
  1840.       row or column
  1841.     */
  1842.     /** The Node itself. */
  1843.     Node m_node;
  1844.   }
  1845.   /**
  1846.    * Internal Class for containing display information about an Edge. 
  1847.    */
  1848.   private class EdgeInfo {
  1849.     //this class contains a pointer to the edge along with all the other
  1850.     //extra info about the edge
  1851.     
  1852.     /** The parent subscript (for a Node). */
  1853.     int m_parent;            //array indexs for its two connections
  1854.     /** The child subscript (for a Node). */
  1855.     int m_child;
  1856.     
  1857.     /** The distance from the center of the text to either side. */
  1858.     int m_side;            //these are used to describe the dimensions of the 
  1859.     //text
  1860.     /** The distance from the center of the text to top or bottom. */
  1861.     int m_tb;              //tb stands for top , bottom, this is simply the 
  1862.     //distance from the middle to top bottom
  1863.     /** The width of the text. */
  1864.     int m_width;
  1865.     /** The height of the text. */
  1866.     int m_height;
  1867.     /** The Edge itself. */
  1868.     Edge m_edge;
  1869.   }
  1870.   /**
  1871.    * Main method for testing this class.
  1872.    * @param args first argument should be the name of a file that contains
  1873.    * a tree discription in dot format.
  1874.    */
  1875.   public static void main(String[] args)
  1876.   {
  1877.     try
  1878.       {
  1879. //put in the random data generator right here
  1880. // this call with import java.lang gives me between 0 and 1 Math.random
  1881. TreeBuild builder = new TreeBuild();
  1882. Node top = null;
  1883. NodePlace arrange = new PlaceNode2();
  1884. //top = builder.create(new StringReader("digraph atree { top [label="the top"] a [label="the first node"] b [label="the second nodes"] c [label="comes off of first"] top->a top->b b->c }"));
  1885. top = builder.create(new FileReader(args[0]));
  1886.     
  1887. int num = top.getCount(top,0);
  1888. //System.out.println("counter counted " + num + " nodes");
  1889. //System.out.println("there are " + num + " nodes");
  1890. TreeVisualizer a = new TreeVisualizer(null, top, arrange);
  1891. a.setSize(800 ,600);
  1892. //a.setTree(top);
  1893. JFrame f;
  1894. f = new JFrame();
  1895. //a.addMouseMotionListener(a);
  1896. //a.addMouseListener(a);
  1897. //f.add(a);
  1898.         Container contentPane = f.getContentPane();
  1899. contentPane.add(a);
  1900. f.setSize(800,600);
  1901. f.show();
  1902. //f.
  1903. //find_prop(top);
  1904. //a.setTree(top,arrange);//,(num + 1000), num / 2 + 1000);
  1905.       }
  1906.     catch(IOException e){}
  1907.   }
  1908. }