weka.gui.treevisualizer.TreeVisualizer Maven / Gradle / Ivy
/*
* 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.
*/
/*
* TreeVisualizer.java
* Copyright (C) 1999 University of Waikato, Hamilton, New Zealand
*
*/
package weka.gui.treevisualizer;
import weka.core.Instances;
import weka.core.Utils;
import weka.gui.visualize.PrintablePanel;
import weka.gui.visualize.VisualizePanel;
import weka.gui.visualize.VisualizeUtils;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.io.FileReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.Properties;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JRadioButton;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JTextField;
import javax.swing.Timer;
/**
* Class for displaying a Node structure in Swing.
*
* To work this class simply create an instance of it.
*
* Assign it to a window or other such object.
*
* Resize it to the desired size.
*
*
* When using the Displayer hold the left mouse button to drag the
* tree around.
*
* Click the left mouse button with ctrl to shrink the size of the tree
* by half.
*
* Click and drag with the left mouse button and shift to draw a box,
* when the left mouse button is released the contents of the box
* will be magnified
* to fill the screen.
*
* Click the right mouse button to bring up a menu.
* Most options are self explanatory.
*
* Select Auto Scale to set the tree to it's optimal display size.
*
* @author Malcolm Ware ([email protected])
* @version $Revision: 7386 $
*/
public class TreeVisualizer
extends PrintablePanel
implements MouseMotionListener, MouseListener, ActionListener, ItemListener {
/** for serialization */
private static final long serialVersionUID = -8668637962504080749L;
/** the props file. */
public final static String PROPERTIES_FILE = "weka/gui/treevisualizer/TreeVisualizer.props";
/** The placement algorithm for the Node structure. */
private NodePlace m_placer;
/** The top Node. */
private Node m_topNode;
/** The postion of the view relative to the tree. */
private Dimension m_viewPos;
/** The size of the tree in pixels. */
private Dimension m_viewSize;
/** The font used to display the tree. */
private Font m_currentFont;
/** The size information for the current font. */
private FontMetrics m_fontSize;
/** The number of Nodes in the tree. */
private int m_numNodes;
/** The number of levels in the tree. */
private int m_numLevels;
/** An array with the Nodes sorted into it and display information
* about the Nodes. */
private NodeInfo[] m_nodes;
/** An array with the Edges sorted into it and display information
* about the Edges. */
private EdgeInfo[] m_edges;
/** A timer to keep the frame rate constant. */
private Timer m_frameLimiter;
/** Describes the action the user is performing. */
private int m_mouseState;
/** A variable used to tag the start pos of a user action. */
private Dimension m_oldMousePos;
/** A variable used to tag the most current point of a user action. */
private Dimension m_newMousePos;
/** A variable used to determine for the clicked method if any other
* mouse state has already taken place. */
private boolean m_clickAvailable;
/** A variable used to remember the desired view pos. */
private Dimension m_nViewPos;
/** A variable used to remember the desired tree size. */
private Dimension m_nViewSize;
/** The number of frames left to calculate. */
private int m_scaling;
/** A right (or middle) click popup menu. */
private JPopupMenu m_winMenu;
/** An option on the win_menu */
private JMenuItem m_topN;
/** An option on the win_menu*/
private JMenuItem m_fitToScreen;
/** An option on the win_menu */
private JMenuItem m_autoScale;
/** A sub group on the win_menu */
private JMenu m_selectFont;
/** A grouping for the font choices */
private ButtonGroup m_selectFontGroup;
/** A font choice. */
private JRadioButtonMenuItem m_size24;
/** A font choice. */
private JRadioButtonMenuItem m_size22;
/** A font choice. */
private JRadioButtonMenuItem m_size20;
/** A font choice. */
private JRadioButtonMenuItem m_size18;
/** A font choice. */
private JRadioButtonMenuItem m_size16;
/** A font choice. */
private JRadioButtonMenuItem m_size14;
/** A font choice. */
private JRadioButtonMenuItem m_size12;
/** A font choice. */
private JRadioButtonMenuItem m_size10;
/** A font choice. */
private JRadioButtonMenuItem m_size8;
/** A font choice. */
private JRadioButtonMenuItem m_size6;
/** A font choice. */
private JRadioButtonMenuItem m_size4;
/** A font choice. */
private JRadioButtonMenuItem m_size2;
/** A font choice. */
private JRadioButtonMenuItem m_size1;
/** An option on the win menu. */
private JMenuItem m_accept;
/** A right or middle click popup menu for nodes. */
private JPopupMenu m_nodeMenu;
/** A visualize choice for the node, may not be available. */
private JMenuItem m_visualise;
/**
* An add children to Node choice, This is only available if the tree
* display has a treedisplay listerner added to it.
*/
private JMenuItem m_addChildren;
/** Similar to add children but now it removes children. */
private JMenuItem m_remChildren;
/** Use this to have J48 classify this node. */
private JMenuItem m_classifyChild;
/** Use this to dump the instances from this node to the vis panel. */
private JMenuItem m_sendInstances;
/** The subscript for the currently selected node (this is an internal
* thing, so the user is unaware of this). */
private int m_focusNode;
/**
* The Node the user is currently focused on , this is similar to
* focus node except that it is used by other
* classes rather than this one.
*/
private int m_highlightNode;
/* A pointer to this tree's classifier if a classifier is using it. */
//private UserClassifier classer;
private TreeDisplayListener m_listener;
private JTextField m_searchString;
private JDialog m_searchWin;
private JRadioButton m_caseSen;
/** the font color. */
protected Color m_FontColor = null;
/** the background color. */
protected Color m_BackgroundColor = null;
/** the node color. */
protected Color m_NodeColor = null;
/** the line color. */
protected Color m_LineColor = null;
/** the color of the zoombox. */
protected Color m_ZoomBoxColor = null;
/** the XOR color of the zoombox. */
protected Color m_ZoomBoxXORColor = null;
/** whether to show the border or not. */
protected boolean m_ShowBorder = true;
///////////////////
//this is the event fireing stuff
/**
* Constructs Displayer to display a tree provided in a dot format.
* Uses the NodePlacer to place the Nodes.
* @param tdl listener
* @param dot string containing the dot representation of the tree to
* display
* @param p the algorithm to be used to position the nodes.
*/
public TreeVisualizer(TreeDisplayListener tdl, String dot, NodePlace p) {
super();
initialize();
//generate the node structure in here
if (m_ShowBorder)
setBorder(BorderFactory.createTitledBorder(Messages.getInstance().getString("TreeVisualizer_BorderFactoryCreateTitledBorder_Text_First")));
m_listener = tdl;
TreeBuild builder = new TreeBuild();
Node n = null;
NodePlace arrange = new PlaceNode2();
n = builder.create(new StringReader(dot));
// System.out.println(n.getCount(n, 0));
//if the size needs to be automatically alocated I will do it here
m_highlightNode = 5;
m_topNode = n;
m_placer = p;
m_placer.place(m_topNode);
m_viewPos = new Dimension(0, 0); //will be adjusted
m_viewSize = new Dimension(800, 600); //I allocate this now so that
//the tree will be visible
//when the panel is enlarged
m_nViewPos = new Dimension(0, 0);
m_nViewSize = new Dimension(800, 600);
m_scaling = 0;
m_numNodes = m_topNode.getCount(m_topNode,0); //note the second
//argument must be a zero, this is a
//recursive function
m_numLevels = m_topNode.getHeight(m_topNode,0);
m_nodes = new NodeInfo[m_numNodes];
m_edges = new EdgeInfo[m_numNodes-1];
arrayFill(m_topNode, m_nodes, m_edges);
changeFontSize(12);
m_mouseState = 0;
m_oldMousePos = new Dimension(0, 0);
m_newMousePos = new Dimension(0, 0);
m_frameLimiter = new Timer(120, this);
m_winMenu = new JPopupMenu();
m_topN = new JMenuItem(Messages.getInstance().getString("TreeVisualizer_TopN_JMenuItem_Text_First")); //note to change
//language change this line
m_topN.setActionCommand(Messages.getInstance().getString("TreeVisualizer_TopN_JMenuItem_SetActionCommand_Text_First")); //but not this one,
//same for all menu items
m_fitToScreen = new JMenuItem(Messages.getInstance().getString("TreeVisualizer_FitToScreen_JMenuItem_Text_First"));
m_fitToScreen.setActionCommand(Messages.getInstance().getString("TreeVisualizer_FitToScreen_JMenuItem_SetActionCommand_Text_First"));
//unhide = new JMenuItem("Unhide all Nodes");
m_selectFont = new JMenu(Messages.getInstance().getString("TreeVisualizer_SelectFont_JMenu_Text_First"));
m_selectFont.setActionCommand(Messages.getInstance().getString("TreeVisualizer_SelectFont_JMenu_SetActionCommand_Text_First"));
m_autoScale = new JMenuItem(Messages.getInstance().getString("TreeVisualizer_AutoScale_JMenuItem_Text_First"));
m_autoScale.setActionCommand(Messages.getInstance().getString("TreeVisualizer_AutoScale_JMenuItem_SetActionCommand_Text_First"));
m_selectFontGroup = new ButtonGroup();
m_accept = new JMenuItem(Messages.getInstance().getString("TreeVisualizer_Accept_JMenuItem_Text_First"));
m_accept.setActionCommand(Messages.getInstance().getString("TreeVisualizer_Accept_JMenuItem_SetActionCommand_Text_First"));
m_winMenu.add(m_topN);
m_winMenu.addSeparator();
m_winMenu.add(m_fitToScreen);
m_winMenu.add(m_autoScale);
//m_winMenu.addSeparator();
//m_winMenu.add(unhide);
m_winMenu.addSeparator();
m_winMenu.add(m_selectFont);
if (m_listener != null) {
m_winMenu.addSeparator();
m_winMenu.add(m_accept);
}
m_topN.addActionListener(this);
m_fitToScreen.addActionListener(this);
//unhide.addActionListener(this);
m_autoScale.addActionListener(this);
m_accept.addActionListener(this);
m_size24 = new JRadioButtonMenuItem(Messages.getInstance().getString("TreeVisualizer_Size24_JRadioButtonMenuItem_Size24_Text_First"),false);//,select_font_group);
m_size22 = new JRadioButtonMenuItem(Messages.getInstance().getString("TreeVisualizer_Size22_JRadioButtonMenuItem_Size22_Text_First"),false);//,select_font_group);
m_size20 = new JRadioButtonMenuItem(Messages.getInstance().getString("TreeVisualizer_Size20_JRadioButtonMenuItem_Size20_Text_First"),false);//,select_font_group);
m_size18 = new JRadioButtonMenuItem(Messages.getInstance().getString("TreeVisualizer_Size18_JRadioButtonMenuItem_Size18_Text_First"),false);//,select_font_group);
m_size16 = new JRadioButtonMenuItem(Messages.getInstance().getString("TreeVisualizer_Size16_JRadioButtonMenuItem_Size16_Text_First"),false);//,select_font_group);
m_size14 = new JRadioButtonMenuItem(Messages.getInstance().getString("TreeVisualizer_Size14_JRadioButtonMenuItem_Size14_Text_First"),false);//,select_font_group);
m_size12 = new JRadioButtonMenuItem(Messages.getInstance().getString("TreeVisualizer_Size12_JRadioButtonMenuItem_Size12_Text_First"),true);//,select_font_group);
m_size10 = new JRadioButtonMenuItem(Messages.getInstance().getString("TreeVisualizer_Size10_JRadioButtonMenuItem_Size10_Text_First"),false);//,select_font_group);
m_size8 = new JRadioButtonMenuItem(Messages.getInstance().getString("TreeVisualizer_Size8_JRadioButtonMenuItem_Size8_Text_First"),false);//,select_font_group);
m_size6 = new JRadioButtonMenuItem(Messages.getInstance().getString("TreeVisualizer_Size6_JRadioButtonMenuItem_Size6_Text_First"),false);//,select_font_group);
m_size4 = new JRadioButtonMenuItem(Messages.getInstance().getString("TreeVisualizer_Size4_JRadioButtonMenuItem_Size4_Text_First"),false);//,select_font_group);
m_size2 = new JRadioButtonMenuItem(Messages.getInstance().getString("TreeVisualizer_Size2_JRadioButtonMenuItem_Size2_Text_First"),false);//,select_font_group);
m_size1 = new JRadioButtonMenuItem(Messages.getInstance().getString("TreeVisualizer_Size1_JRadioButtonMenuItem_Size1_Text_First"),false);//,select_font_group);
m_size24.setActionCommand(Messages.getInstance().getString("TreeVisualizer_Size24_JRadioButtonMenuItem_SetActionCommand_Size24_Text_First"));//,select_font_group);
m_size22.setActionCommand(Messages.getInstance().getString("TreeVisualizer_Size22_JRadioButtonMenuItem_SetActionCommand_Size22_Text_First"));//,select_font_group);
m_size20.setActionCommand(Messages.getInstance().getString("TreeVisualizer_Size20_JRadioButtonMenuItem_SetActionCommand_Size20_Text_First"));//,select_font_group);
m_size18.setActionCommand(Messages.getInstance().getString("TreeVisualizer_Size18_JRadioButtonMenuItem_SetActionCommand_Size18_Text_First"));//,select_font_group);
m_size16.setActionCommand(Messages.getInstance().getString("TreeVisualizer_Size16_JRadioButtonMenuItem_SetActionCommand_Size16_Text_First"));//,select_font_group);
m_size14.setActionCommand(Messages.getInstance().getString("TreeVisualizer_Size14_JRadioButtonMenuItem_SetActionCommand_Size14_Text_First"));//,select_font_group);
m_size12.setActionCommand(Messages.getInstance().getString("TreeVisualizer_Size12_JRadioButtonMenuItem_SetActionCommand_Size12_Text_First"));//,select_font_group);
m_size10.setActionCommand(Messages.getInstance().getString("TreeVisualizer_Size10_JRadioButtonMenuItem_SetActionCommand_Size10_Text_First"));//,select_font_group);
m_size8.setActionCommand(Messages.getInstance().getString("TreeVisualizer_Size8_JRadioButtonMenuItem_SetActionCommand_Size8_Text_First"));//,select_font_group);
m_size6.setActionCommand(Messages.getInstance().getString("TreeVisualizer_Size6_JRadioButtonMenuItem_SetActionCommand_Size6_Text_First"));//,select_font_group);
m_size4.setActionCommand(Messages.getInstance().getString("TreeVisualizer_Size4_JRadioButtonMenuItem_SetActionCommand_Size4_Text_First"));//,select_font_group);
m_size2.setActionCommand(Messages.getInstance().getString("TreeVisualizer_Size2_JRadioButtonMenuItem_SetActionCommand_Size2_Text_First"));//,select_font_group);
m_size1.setActionCommand(Messages.getInstance().getString("TreeVisualizer_Size1_JRadioButtonMenuItem_SetActionCommand_Size1_Text_First"));//,select_font_group);
m_selectFontGroup.add(m_size24);
m_selectFontGroup.add(m_size22);
m_selectFontGroup.add(m_size20);
m_selectFontGroup.add(m_size18);
m_selectFontGroup.add(m_size16);
m_selectFontGroup.add(m_size14);
m_selectFontGroup.add(m_size12);
m_selectFontGroup.add(m_size10);
m_selectFontGroup.add(m_size8);
m_selectFontGroup.add(m_size6);
m_selectFontGroup.add(m_size4);
m_selectFontGroup.add(m_size2);
m_selectFontGroup.add(m_size1);
m_selectFont.add(m_size24);
m_selectFont.add(m_size22);
m_selectFont.add(m_size20);
m_selectFont.add(m_size18);
m_selectFont.add(m_size16);
m_selectFont.add(m_size14);
m_selectFont.add(m_size12);
m_selectFont.add(m_size10);
m_selectFont.add(m_size8);
m_selectFont.add(m_size6);
m_selectFont.add(m_size4);
m_selectFont.add(m_size2);
m_selectFont.add(m_size1);
m_size24.addItemListener(this);
m_size22.addItemListener(this);
m_size20.addItemListener(this);
m_size18.addItemListener(this);
m_size16.addItemListener(this);
m_size14.addItemListener(this);
m_size12.addItemListener(this);
m_size10.addItemListener(this);
m_size8.addItemListener(this);
m_size6.addItemListener(this);
m_size4.addItemListener(this);
m_size2.addItemListener(this);
m_size1.addItemListener(this);
/*
search_string = new JTextField(22);
search_win = new JDialog();
case_sen = new JRadioButton("Case Sensitive");
search_win.getContentPane().setLayout(null);
search_win.setSize(300, 200);
search_win.getContentPane().add(search_string);
search_win.getContentPane().add(case_sen);
search_string.setLocation(50, 70);
case_sen.setLocation(50, 120);
case_sen.setSize(100, 24);
search_string.setSize(100, 24);
//search_string.setVisible(true);
//case_sen.setVisible(true);
//search_win.setVisible(true);
*/
m_nodeMenu = new JPopupMenu();
/* A visualize choice for the node, may not be available. */
m_visualise = new JMenuItem(Messages.getInstance().getString("TreeVisualizer_Visualise_JMenuItem_Text_First"));
m_visualise.setActionCommand(Messages.getInstance().getString("TreeVisualizer_Visualise_JMenuItem_SetActionCommand_Text_First"));
m_visualise.addActionListener(this);
m_nodeMenu.add(m_visualise);
if (m_listener != null) {
m_remChildren = new JMenuItem(Messages.getInstance().getString("TreeVisualizer_RemChildren_JMenuItem_Text_First"));
m_remChildren.setActionCommand(Messages.getInstance().getString("TreeVisualizer_RemChildren_JMenuItem_SetActionCommand_Text_First"));
m_remChildren.addActionListener(this);
m_nodeMenu.add(m_remChildren);
m_classifyChild = new JMenuItem(Messages.getInstance().getString("TreeVisualizer_ClassifyChild_JMenuItem_Text_First"));
m_classifyChild.setActionCommand(Messages.getInstance().getString("TreeVisualizer_ClassifyChild_JMenuItem_SetActionCommand_Text_First"));
m_classifyChild.addActionListener(this);
m_nodeMenu.add(m_classifyChild);
/*m_sendInstances = new JMenuItem("Add Instances To Viewer");
m_sendInstances.setActionCommand("send_instances");
m_sendInstances.addActionListener(this);
m_nodeMenu.add(m_sendInstances); */
}
m_focusNode = -1;
m_highlightNode = -1;
addMouseMotionListener(this);
addMouseListener(this);
//repaint();
//frame_limiter.setInitialDelay();
m_frameLimiter.setRepeats(false);
m_frameLimiter.start();
}
/**
* Constructs Displayer with the specified Node as the top
* of the tree, and uses the NodePlacer to place the Nodes.
* @param tdl listener.
* @param n the top Node of the tree to be displayed.
* @param p the algorithm to be used to position the nodes.
*/
public TreeVisualizer(TreeDisplayListener tdl, Node n, NodePlace p) {
super();
initialize();
//if the size needs to be automatically alocated I will do it here
if (m_ShowBorder)
setBorder(BorderFactory.createTitledBorder(Messages.getInstance().getString("TreeVisualizer_BorderFactoryCreateTitledBorder_Text_Second")));
m_listener = tdl;
m_topNode = n;
m_placer = p;
m_placer.place(m_topNode);
m_viewPos = new Dimension(0, 0); //will be adjusted
m_viewSize = new Dimension(800, 600); //I allocate this now so that
//the tree will be visible
//when the panel is enlarged
m_nViewPos = new Dimension(0, 0);
m_nViewSize = new Dimension(800, 600);
m_scaling = 0;
m_numNodes = m_topNode.getCount(m_topNode,0); //note the second argument
//must be a zero, this is a
//recursive function
m_numLevels = m_topNode.getHeight(m_topNode,0);
m_nodes = new NodeInfo[m_numNodes];
m_edges = new EdgeInfo[m_numNodes-1];
arrayFill(m_topNode, m_nodes, m_edges);
changeFontSize(12);
m_mouseState = 0;
m_oldMousePos = new Dimension(0, 0);
m_newMousePos = new Dimension(0, 0);
m_frameLimiter = new Timer(120, this);
m_winMenu = new JPopupMenu();
m_topN = new JMenuItem(Messages.getInstance().getString("TreeVisualizer_TopN_JMenuItem_Text_Second")); //note to change
//language change this line
m_topN.setActionCommand(Messages.getInstance().getString("TreeVisualizer_TopN_JMenuItem_SetActionCommand_Text_Second")); //but not this
//one, same for all menu items
m_fitToScreen = new JMenuItem(Messages.getInstance().getString("TreeVisualizer_FitToScreen_JMenuItem_Text_Second"));
m_fitToScreen.setActionCommand(Messages.getInstance().getString("TreeVisualizer_FitToScreen_JMenuItem_SetActionCommand_Text_Second"));
//unhide = new JMenuItem("Unhide all Nodes");
m_selectFont = new JMenu(Messages.getInstance().getString("TreeVisualizer_SelectFont_JMenu_Text_Second"));
m_selectFont.setActionCommand(Messages.getInstance().getString("TreeVisualizer_SelectFont_JMenu_SetActionCommand_Text_Second"));
m_autoScale = new JMenuItem(Messages.getInstance().getString("TreeVisualizer_AutoScale_JMenuItem_Text_Second"));
m_autoScale.setActionCommand(Messages.getInstance().getString("TreeVisualizer_AutoScale_JMenuItem_SetActionCommand_Text_Second"));
m_selectFontGroup = new ButtonGroup();
m_accept = new JMenuItem(Messages.getInstance().getString("TreeVisualizer_Accept_JMenuItem_Text_Second"));
m_accept.setActionCommand(Messages.getInstance().getString("TreeVisualizer_Accept_JMenuItem_SetActionCommand_Text_Second"));
m_winMenu.add(m_topN);
m_winMenu.addSeparator();
m_winMenu.add(m_fitToScreen);
m_winMenu.add(m_autoScale);
m_winMenu.addSeparator();
//m_winMenu.add(unhide);
m_winMenu.addSeparator();
m_winMenu.add(m_selectFont);
m_winMenu.addSeparator();
if (m_listener != null) {
m_winMenu.add(m_accept);
}
m_topN.addActionListener(this);
m_fitToScreen.addActionListener(this);
//unhide.addActionListener(this);
m_autoScale.addActionListener(this);
m_accept.addActionListener(this);
m_size24 = new JRadioButtonMenuItem(Messages.getInstance().getString("TreeVisualizer_Size24_JRadioButtonMenuItem_Size24_Text_Second"),false);//,select_font_group);
m_size22 = new JRadioButtonMenuItem(Messages.getInstance().getString("TreeVisualizer_Size24_JRadioButtonMenuItem_Size22_Text_Second"),false);//,select_font_group);
m_size20 = new JRadioButtonMenuItem(Messages.getInstance().getString("TreeVisualizer_Size24_JRadioButtonMenuItem_Size20_Text_Second"),false);//,select_font_group);
m_size18 = new JRadioButtonMenuItem(Messages.getInstance().getString("TreeVisualizer_Size24_JRadioButtonMenuItem_Size18_Text_Second"),false);//,select_font_group);
m_size16 = new JRadioButtonMenuItem(Messages.getInstance().getString("TreeVisualizer_Size24_JRadioButtonMenuItem_Size16_Text_Second"),false);//,select_font_group);
m_size14 = new JRadioButtonMenuItem(Messages.getInstance().getString("TreeVisualizer_Size24_JRadioButtonMenuItem_Size14_Text_Second"),false);//,select_font_group);
m_size12 = new JRadioButtonMenuItem(Messages.getInstance().getString("TreeVisualizer_Size24_JRadioButtonMenuItem_Size12_Text_Second"),true);//,select_font_group);
m_size10 = new JRadioButtonMenuItem(Messages.getInstance().getString("TreeVisualizer_Size24_JRadioButtonMenuItem_Size10_Text_Second"),false);//,select_font_group);
m_size8 = new JRadioButtonMenuItem(Messages.getInstance().getString("TreeVisualizer_Size24_JRadioButtonMenuItem_Size8_Text_Second"),false);//,select_font_group);
m_size6 = new JRadioButtonMenuItem(Messages.getInstance().getString("TreeVisualizer_Size24_JRadioButtonMenuItem_Size6_Text_Second"),false);//,select_font_group);
m_size4 = new JRadioButtonMenuItem(Messages.getInstance().getString("TreeVisualizer_Size24_JRadioButtonMenuItem_Size4_Text_Second"),false);//,select_font_group);
m_size2 = new JRadioButtonMenuItem(Messages.getInstance().getString("TreeVisualizer_Size24_JRadioButtonMenuItem_Size2_Text_Second"),false);//,select_font_group);
m_size1 = new JRadioButtonMenuItem(Messages.getInstance().getString("TreeVisualizer_Size24_JRadioButtonMenuItem_Size1_Text_Second"),false);//,select_font_group);
m_size24.setActionCommand(Messages.getInstance().getString("TreeVisualizer_Size1_JRadioButtonMenuItem_SetActionCommand_Size24_Text_Second"));//,select_font_group);
m_size22.setActionCommand(Messages.getInstance().getString("TreeVisualizer_Size1_JRadioButtonMenuItem_SetActionCommand_Size22_Text_Second"));//,select_font_group);
m_size20.setActionCommand(Messages.getInstance().getString("TreeVisualizer_Size1_JRadioButtonMenuItem_SetActionCommand_Size20_Text_Second"));//,select_font_group);
m_size18.setActionCommand(Messages.getInstance().getString("TreeVisualizer_Size1_JRadioButtonMenuItem_SetActionCommand_Size18_Text_Second"));//,select_font_group);
m_size16.setActionCommand(Messages.getInstance().getString("TreeVisualizer_Size1_JRadioButtonMenuItem_SetActionCommand_Size16_Text_Second"));//,select_font_group);
m_size14.setActionCommand(Messages.getInstance().getString("TreeVisualizer_Size1_JRadioButtonMenuItem_SetActionCommand_Size14_Text_Second"));//,select_font_group);
m_size12.setActionCommand(Messages.getInstance().getString("TreeVisualizer_Size1_JRadioButtonMenuItem_SetActionCommand_Size12_Text_Second"));//,select_font_group);
m_size10.setActionCommand(Messages.getInstance().getString("TreeVisualizer_Size1_JRadioButtonMenuItem_SetActionCommand_Size10_Text_Second"));//,select_font_group);
m_size8.setActionCommand(Messages.getInstance().getString("TreeVisualizer_Size1_JRadioButtonMenuItem_SetActionCommand_Size8_Text_Second"));//,select_font_group);
m_size6.setActionCommand(Messages.getInstance().getString("TreeVisualizer_Size1_JRadioButtonMenuItem_SetActionCommand_Size6_Text_Second"));//,select_font_group);
m_size4.setActionCommand(Messages.getInstance().getString("TreeVisualizer_Size1_JRadioButtonMenuItem_SetActionCommand_Size4_Text_Second"));//,select_font_group);
m_size2.setActionCommand(Messages.getInstance().getString("TreeVisualizer_Size1_JRadioButtonMenuItem_SetActionCommand_Size2_Text_Second"));//,select_font_group);
m_size1.setActionCommand(Messages.getInstance().getString("TreeVisualizer_Size1_JRadioButtonMenuItem_SetActionCommand_Size1_Text_Second"));//,select_font_group);
m_selectFontGroup.add(m_size24);
m_selectFontGroup.add(m_size22);
m_selectFontGroup.add(m_size20);
m_selectFontGroup.add(m_size18);
m_selectFontGroup.add(m_size16);
m_selectFontGroup.add(m_size14);
m_selectFontGroup.add(m_size12);
m_selectFontGroup.add(m_size10);
m_selectFontGroup.add(m_size8);
m_selectFontGroup.add(m_size6);
m_selectFontGroup.add(m_size4);
m_selectFontGroup.add(m_size2);
m_selectFontGroup.add(m_size1);
m_selectFont.add(m_size24);
m_selectFont.add(m_size22);
m_selectFont.add(m_size20);
m_selectFont.add(m_size18);
m_selectFont.add(m_size16);
m_selectFont.add(m_size14);
m_selectFont.add(m_size12);
m_selectFont.add(m_size10);
m_selectFont.add(m_size8);
m_selectFont.add(m_size6);
m_selectFont.add(m_size4);
m_selectFont.add(m_size2);
m_selectFont.add(m_size1);
m_size24.addItemListener(this);
m_size22.addItemListener(this);
m_size20.addItemListener(this);
m_size18.addItemListener(this);
m_size16.addItemListener(this);
m_size14.addItemListener(this);
m_size12.addItemListener(this);
m_size10.addItemListener(this);
m_size8.addItemListener(this);
m_size6.addItemListener(this);
m_size4.addItemListener(this);
m_size2.addItemListener(this);
m_size1.addItemListener(this);
/*
search_string = new JTextField(22);
search_win = new JDialog();
case_sen = new JRadioButton("Case Sensitive");
search_win.getContentPane().setLayout(null);
search_win.setSize(300, 200);
search_win.getContentPane().add(search_string);
search_win.getContentPane().add(case_sen);
search_string.setLocation(50, 70);
case_sen.setLocation(50, 120);
case_sen.setSize(100, 24);
search_string.setSize(100, 24);
//search_string.setVisible(true);
//case_sen.setVisible(true);
search_win.setVisible(true);
*/
m_nodeMenu = new JPopupMenu();
/* A visualize choice for the node, may not be available. */
m_visualise = new JMenuItem(Messages.getInstance().getString("TreeVisualizer_Visualise_JMenuItem_Text_Second"));
m_visualise.setActionCommand(Messages.getInstance().getString("TreeVisualizer_Visualise_JMenuItem_SetActionCommand_Text_Second"));
m_visualise.addActionListener(this);
m_nodeMenu.add(m_visualise);
if (m_listener != null) {
m_remChildren = new JMenuItem(Messages.getInstance().getString("TreeVisualizer_RemChildren_JMenuItem_Text_Second"));
m_remChildren.setActionCommand(Messages.getInstance().getString("TreeVisualizer_RemChildren_JMenuItem_SetActionCommand_Text_Second"));
m_remChildren.addActionListener(this);
m_nodeMenu.add(m_remChildren);
m_classifyChild = new JMenuItem(Messages.getInstance().getString("TreeVisualizer_ClassifyChild_JMenuItem_Text_Second"));
m_classifyChild.setActionCommand(Messages.getInstance().getString("TreeVisualizer_ClassifyChild_JMenuItem_SetActionCommand_Text_Second"));
m_classifyChild.addActionListener(this);
m_nodeMenu.add(m_classifyChild);
m_sendInstances = new JMenuItem(Messages.getInstance().getString("TreeVisualizer_SendInstances_JMenuItem_Text"));
m_sendInstances.setActionCommand(Messages.getInstance().getString("TreeVisualizer_SendInstances_JMenuItem_SetActionCommand_Text"));
m_sendInstances.addActionListener(this);
m_nodeMenu.add(m_sendInstances);
}
m_focusNode = -1;
m_highlightNode = -1;
addMouseMotionListener(this);
addMouseListener(this);
//repaint();
//frame_limiter.setInitialDelay();
m_frameLimiter.setRepeats(false);
m_frameLimiter.start();
}
/**
* Processes the color string. Returns null if empty.
*
* @param colorStr the string to process
* @return the processed color or null
*/
protected Color getColor(String colorStr) {
Color result;
result = null;
if ((colorStr != null) && (colorStr.length() > 0))
result = VisualizeUtils.processColour(colorStr, result);
return result;
}
/**
* Performs some initialization.
*/
protected void initialize() {
Properties props;
try {
props = Utils.readProperties(PROPERTIES_FILE);
}
catch (Exception e) {
e.printStackTrace();
props = new Properties();
}
m_FontColor = getColor(props.getProperty("FontColor", ""));
m_BackgroundColor = getColor(props.getProperty("BackgroundColor", ""));
m_NodeColor = getColor(props.getProperty("NodeColor", ""));
m_LineColor = getColor(props.getProperty("LineColor", ""));
m_ZoomBoxColor = getColor(props.getProperty("ZoomBoxColor", ""));
m_ZoomBoxXORColor = getColor(props.getProperty("ZoomBoxXORColor", ""));
m_ShowBorder = Boolean.parseBoolean(props.getProperty("ShowBorder", "true"));
}
/**
* Fits the tree to the current screen size. Call this after
* window has been created to get the entrire tree to be in view
* upon launch.
*/
public void fitToScreen() {
getScreenFit(m_viewPos, m_viewSize);
repaint();
}
/**
* Calculates the dimensions needed to fit the entire tree into view.
*/
private void getScreenFit(Dimension np, Dimension ns) {
int leftmost = 1000000, rightmost = -1000000;
int leftCenter = 1000000, rightCenter = -1000000, rightNode = 0;
int highest = -1000000, highTop = -1000000;
for (int noa = 0; noa < m_numNodes; noa++) {
calcScreenCoords(noa);
if (m_nodes[noa].m_center - m_nodes[noa].m_side < leftmost) {
leftmost = m_nodes[noa].m_center - m_nodes[noa].m_side;
}
if (m_nodes[noa].m_center < leftCenter) {
leftCenter = m_nodes[noa].m_center;
}
if (m_nodes[noa].m_center + m_nodes[noa].m_side > rightmost) {
rightmost = m_nodes[noa].m_center + m_nodes[noa].m_side;
}
if (m_nodes[noa].m_center > rightCenter) {
rightCenter = m_nodes[noa].m_center;
rightNode = noa;
}
if (m_nodes[noa].m_top + m_nodes[noa].m_height > highest) {
highest = m_nodes[noa].m_top + m_nodes[noa].m_height;
}
if (m_nodes[noa].m_top > highTop) {
highTop = m_nodes[noa].m_top;
}
}
ns.width = getWidth();
ns.width -= leftCenter - leftmost + rightmost - rightCenter + 30;
ns.height = getHeight() - highest + highTop - 40;
if (m_nodes[rightNode].m_node.getCenter() != 0
&& leftCenter != rightCenter) {
ns.width /= m_nodes[rightNode].m_node.getCenter();
}
if (ns.width < 10)
{
ns.width = 10;
}
if (ns.height < 10)
{
ns.height = 10;
}
np.width = (leftCenter - leftmost + rightmost - rightCenter) / 2 + 15;
np.height = (highest - highTop) / 2 + 20;
}
/**
* Performs the action associated with the ActionEvent.
*
* @param e the action event.
*/
public void actionPerformed(ActionEvent e) {
//JMenuItem m = (JMenuItem)e.getSource();
if (e.getActionCommand() == null) {
if (m_scaling == 0) {
repaint();
}
else {
animateScaling(m_nViewPos, m_nViewSize, m_scaling);
}
}
else if (e.getActionCommand().equals(Messages.getInstance().getString("TreeVisualizer_ActionPerformed_FitToScreen_Text"))) {
Dimension np = new Dimension();
Dimension ns = new Dimension();
getScreenFit(np, ns);
animateScaling(np, ns, 10);
}
else if (e.getActionCommand().equals(Messages.getInstance().getString("TreeVisualizer_ActionPerformed_CenterOnTopNode_Text"))) {
int tpx = (int)(m_topNode.getCenter() * m_viewSize.width); //calculate
//the top nodes postion but don't adjust for where
int tpy = (int)(m_topNode.getTop() * m_viewSize.height); //view is
Dimension np = new Dimension(getSize().width / 2 - tpx,
getSize().width / 6 - tpy);
animateScaling(np, m_viewSize, 10);
}
else if (e.getActionCommand().equals(Messages.getInstance().getString("TreeVisualizer_AutoScale_JMenuItem_SetActionCommand_Text_Second"))) {
autoScale(); //this will figure the best scale value
//keep the focus on the middle of the screen and call animate
}
else if (e.getActionCommand().equals(Messages.getInstance().getString("TreeVisualizer_ActionPerformed_VisualizeTheNode_Text"))) {
//send the node data to the visualizer
if (m_focusNode >= 0) {
Instances inst;
if ((inst = m_nodes[m_focusNode].m_node.getInstances()) != null) {
VisualizePanel pan = new VisualizePanel();
pan.setInstances(inst);
JFrame nf = new JFrame();
nf.setSize(400, 300);
nf.getContentPane().add(pan);
nf.setVisible(true);
}
else {
JOptionPane.showMessageDialog(this, Messages.getInstance().getString("TreeVisualizer_ActionPerformed_JOptionPaneShowMessageDialog_Text_First"),
Messages.getInstance().getString("TreeVisualizer_ActionPerformed_JOptionPaneShowMessageDialog_Text_Second"),
JOptionPane.WARNING_MESSAGE);
}
}
else {
JOptionPane.showMessageDialog(this, Messages.getInstance().getString("TreeVisualizer_ActionPerformed_JOptionPaneShowMessageDialog_Text_Third"),
Messages.getInstance().getString("TreeVisualizer_ActionPerformed_JOptionPaneShowMessageDialog_Text_Fourth"),
JOptionPane.ERROR_MESSAGE);
}
}
else if (e.getActionCommand().equals(Messages.getInstance().getString("TreeVisualizer_ActionPerformed_CreateChildNodes_Text"))) {
if (m_focusNode >= 0) {
if (m_listener != null) {
//then send message to the listener
m_listener.userCommand(new TreeDisplayEvent
(TreeDisplayEvent.ADD_CHILDREN,
m_nodes[m_focusNode].m_node.getRefer()));
}
else {
JOptionPane.showMessageDialog(this, Messages.getInstance().getString("TreeVisualizer_ActionPerformed_JOptionPaneShowMessageDialog_Text_Sixth"),
Messages.getInstance().getString("TreeVisualizer_ActionPerformed_JOptionPaneShowMessageDialog_Text_Seventh"),
JOptionPane.WARNING_MESSAGE);
}
}
else {
JOptionPane.showMessageDialog(this, Messages.getInstance().getString("TreeVisualizer_ActionPerformed_JOptionPaneShowMessageDialog_Text_Eighth"),
Messages.getInstance().getString("TreeVisualizer_ActionPerformed_JOptionPaneShowMessageDialog_Text_Eighth"),
JOptionPane.ERROR_MESSAGE);
}
}
else if (e.getActionCommand().equals(Messages.getInstance().getString("TreeVisualizer_ActionPerformed_RemoveChildNodes_Text"))) {
if (m_focusNode >= 0) {
if (m_listener != null) {
//then send message to the listener
m_listener.userCommand(new
TreeDisplayEvent(TreeDisplayEvent.REMOVE_CHILDREN,
m_nodes[m_focusNode].m_node.getRefer()));
}
else {
JOptionPane.showMessageDialog(this, Messages.getInstance().getString("TreeVisualizer_ActionPerformed_JOptionPaneShowMessageDialog_Text_Nineth"),
Messages.getInstance().getString("TreeVisualizer_ActionPerformed_JOptionPaneShowMessageDialog_Text_Tenth"),
JOptionPane.WARNING_MESSAGE);
}
}
else {
JOptionPane.showMessageDialog(this, Messages.getInstance().getString("TreeVisualizer_ActionPerformed_JOptionPaneShowMessageDialog_Text_Eleventh"),
Messages.getInstance().getString("TreeVisualizer_ActionPerformed_JOptionPaneShowMessageDialog_Text_Twelveth"),
JOptionPane.ERROR_MESSAGE);
}
}
else if (e.getActionCommand().equals(Messages.getInstance().getString("TreeVisualizer_ActionPerformed_Classify_Child_Text"))) {
if (m_focusNode >= 0) {
if (m_listener != null) {
//then send message to the listener
m_listener.userCommand(new TreeDisplayEvent
(TreeDisplayEvent.CLASSIFY_CHILD,
m_nodes[m_focusNode].m_node.getRefer()));
}
else {
JOptionPane.showMessageDialog(this, Messages.getInstance().getString("TreeVisualizer_ActionPerformed_JOptionPaneShowMessageDialog_Text_Thirteenth"),
Messages.getInstance().getString("TreeVisualizer_ActionPerformed_JOptionPaneShowMessageDialog_Text_Fourteenth"),
JOptionPane.WARNING_MESSAGE);
}
}
else {
JOptionPane.showMessageDialog(this, Messages.getInstance().getString("TreeVisualizer_ActionPerformed_JOptionPaneShowMessageDialog_Text_Fifteenth"),
" " + Messages.getInstance().getString("TreeVisualizer_ActionPerformed_JOptionPaneShowMessageDialog_Text_Sixteenth"),
JOptionPane.ERROR_MESSAGE);
}
}
else if (e.getActionCommand().equals(Messages.getInstance().getString("TreeVisualizer_ActionPerformed_Send_Instances_Text"))) {
if (m_focusNode >= 0) {
if (m_listener != null) {
//then send message to the listener
m_listener.userCommand(new TreeDisplayEvent
(TreeDisplayEvent.SEND_INSTANCES,
m_nodes[m_focusNode].m_node.getRefer()));
}
else {
JOptionPane.showMessageDialog(this, Messages.getInstance().getString("TreeVisualizer_ActionPerformed_JOptionPaneShowMessageDialog_Text_Seventeenth"),
Messages.getInstance().getString("TreeVisualizer_ActionPerformed_JOptionPaneShowMessageDialog_Text_Eighteenth"),
JOptionPane.WARNING_MESSAGE);
}
}
else {
JOptionPane.showMessageDialog(this, Messages.getInstance().getString("TreeVisualizer_ActionPerformed_JOptionPaneShowMessageDialog_Text_Nineteenth"),
Messages.getInstance().getString("TreeVisualizer_ActionPerformed_JOptionPaneShowMessageDialog_Text_Twentyth"),
JOptionPane.ERROR_MESSAGE);
}
}
else if (e.getActionCommand().equals(Messages.getInstance().getString("TreeVisualizer_ActionPerformed_AcceptTheTree_Text"))) {
if (m_listener != null) {
//then send message to the listener saying that the tree is done
m_listener.userCommand(new TreeDisplayEvent(TreeDisplayEvent.ACCEPT,
null));
}
else {
JOptionPane.showMessageDialog(this, Messages.getInstance().getString("TreeVisualizer_ActionPerformed_JOptionPaneShowMessageDialog_Text_TwentyFirst"),
Messages.getInstance().getString("TreeVisualizer_ActionPerformed_JOptionPaneShowMessageDialog_Text_TwentySecond"),
JOptionPane.WARNING_MESSAGE);
}
}
}
/**
* Performs the action associated with the ItemEvent.
*
* @param e the item event.
*/
public void itemStateChanged(ItemEvent e)
{
JRadioButtonMenuItem c = (JRadioButtonMenuItem)e.getSource();
if (c.getActionCommand().equals(Messages.getInstance().getString("TreeVisualizer_ItemStateChanged_GetActionCommand_Size24_Text"))) {
changeFontSize(24);
}
else if (c.getActionCommand().equals(Messages.getInstance().getString("TreeVisualizer_ItemStateChanged_GetActionCommand_Size22_Text"))) {
changeFontSize(22);
}
else if (c.getActionCommand().equals(Messages.getInstance().getString("TreeVisualizer_ItemStateChanged_GetActionCommand_Size20_Text"))) {
changeFontSize(20);
}
else if (c.getActionCommand().equals(Messages.getInstance().getString("TreeVisualizer_ItemStateChanged_GetActionCommand_Size18_Text"))) {
changeFontSize(18);
}
else if (c.getActionCommand().equals(Messages.getInstance().getString("TreeVisualizer_ItemStateChanged_GetActionCommand_Size16_Text"))) {
changeFontSize(16);
}
else if (c.getActionCommand().equals(Messages.getInstance().getString("TreeVisualizer_ItemStateChanged_GetActionCommand_Size14_Text"))) {
changeFontSize(14);
}
else if (c.getActionCommand().equals(Messages.getInstance().getString("TreeVisualizer_ItemStateChanged_GetActionCommand_Size12_Text"))) {
changeFontSize(12);
}
else if (c.getActionCommand().equals(Messages.getInstance().getString("TreeVisualizer_ItemStateChanged_GetActionCommand_Size10_Text"))) {
changeFontSize(10);
}
else if (c.getActionCommand().equals(Messages.getInstance().getString("TreeVisualizer_ItemStateChanged_GetActionCommand_Size8_Text"))) {
changeFontSize(8);
}
else if (c.getActionCommand().equals(Messages.getInstance().getString("TreeVisualizer_ItemStateChanged_GetActionCommand_Size6_Text"))) {
changeFontSize(6);
}
else if (c.getActionCommand().equals(Messages.getInstance().getString("TreeVisualizer_ItemStateChanged_GetActionCommand_Size4_Text"))) {
changeFontSize(4);
}
else if (c.getActionCommand().equals(Messages.getInstance().getString("TreeVisualizer_ItemStateChanged_GetActionCommand_Size2_Text"))) {
changeFontSize(2);
}
else if (c.getActionCommand().equals(Messages.getInstance().getString("TreeVisualizer_ItemStateChanged_GetActionCommand_Size1_Text"))) {
changeFontSize(1);
}
else if (c.getActionCommand().equals(Messages.getInstance().getString("TreeVisualizer_ItemStateChanged_GetActionCommand_HideDescendants_Text"))) {
//focus_node.setCVisible(!c.isSelected());
//no longer used...
}
}
/**
* Does nothing.
* @param e the mouse event.
*/
public void mouseClicked(MouseEvent e) {
//if the mouse was left clicked on
//the node then
if (m_clickAvailable) {
//determine if the click was on a node or not
int s = -1;
for (int noa = 0; noa < m_numNodes;noa++) {
if (m_nodes[noa].m_quad == 18) {
//then is on the screen
calcScreenCoords(noa);
if (e.getX() <= m_nodes[noa].m_center + m_nodes[noa].m_side
&& e.getX()
>= m_nodes[noa].m_center - m_nodes[noa].m_side &&
e.getY() >= m_nodes[noa].m_top && e.getY()
<= m_nodes[noa].m_top + m_nodes[noa].m_height) {
//then it is this node that the mouse was clicked on
s = noa;
}
m_nodes[noa].m_top = 32000;
}
}
m_focusNode = s;
if (m_focusNode != -1) {
if (m_listener != null) {
//then set this to be the selected node for editing
actionPerformed(new ActionEvent(this, 32000, Messages.getInstance().getString("TreeVisualizer_ItemStateChanged_GetActionCommand_ActionPerformed_Text_First")));
}
else {
//then open a visualize to display this nodes instances if possible
actionPerformed(new ActionEvent(this, 32000, Messages.getInstance().getString("TreeVisualizer_ItemStateChanged_GetActionCommand_ActionPerformed_Text_Second")));
}
}
}
}
/**
* Determines what action the user wants to perform.
*
* @param e the mouse event.
*/
public void mousePressed(MouseEvent e) {
m_frameLimiter.setRepeats(true);
if ((e.getModifiers() & e.BUTTON1_MASK) != 0 && !e.isAltDown() &&
m_mouseState == 0
&& m_scaling == 0) {
//then the left mouse button has been pressed
//check for modifiers
if (((e.getModifiers() & e.CTRL_MASK) != 0) && ((e.getModifiers() & e.SHIFT_MASK) == 0)) {
//then is in zoom out mode
m_mouseState = 2;
}
else if (((e.getModifiers() & e.SHIFT_MASK) != 0) && ((e.getModifiers() & e.CTRL_MASK) == 0)) {
//then is in zoom mode
//note if both are pressed default action is to zoom out
m_oldMousePos.width = e.getX();
m_oldMousePos.height = e.getY();
m_newMousePos.width = e.getX();
m_newMousePos.height = e.getY();
m_mouseState = 3;
Graphics g = getGraphics();
if (m_ZoomBoxColor == null)
g.setColor(Color.black);
else
g.setColor(m_ZoomBoxColor);
if (m_ZoomBoxXORColor == null)
g.setXORMode(Color.white);
else
g.setXORMode(m_ZoomBoxXORColor);
g.drawRect(m_oldMousePos.width, m_oldMousePos.height,
m_newMousePos.width - m_oldMousePos.width,
m_newMousePos.height - m_oldMousePos.height);
g.dispose();
}
else {
//no modifiers drag area around
m_oldMousePos.width = e.getX();
m_oldMousePos.height = e.getY();
m_newMousePos.width = e.getX();
m_newMousePos.height = e.getY();
m_mouseState = 1;
m_frameLimiter.start();
}
}
// pop up save dialog explicitly (is somehow overridden...)
else if ( (e.getButton() == MouseEvent.BUTTON1) && e.isAltDown() && e.isShiftDown() && !e.isControlDown() ) {
saveComponent();
}
else if (m_mouseState == 0 && m_scaling == 0) {
//either middle or right mouse button pushed
//determine menu to use
}
}
/**
* Performs the final stages of what the user wants to perform.
*
* @param e the mouse event.
*/
public void mouseReleased(MouseEvent e) {
if (m_mouseState == 1) {
//this is used by mouseClicked to determine if it is alright to do
//something
m_clickAvailable = true;
//note that a standard click with the left mouse is pretty much the
//only safe input left to be assigned anything.
}
else {
m_clickAvailable = false;
}
if (m_mouseState == 2 && mouseInBounds(e)) {
//then zoom out;
m_mouseState = 0;
Dimension ns = new Dimension(m_viewSize.width / 2, m_viewSize.height
/ 2);
if (ns.width < 10) {
ns.width = 10;
}
if (ns.height < 10) {
ns.height = 10;
}
Dimension d = getSize();
Dimension np = new Dimension((int)(d.width / 2
- ((double)d.width / 2
- m_viewPos.width) / 2),
(int)(d.height / 2
- ((double)d.height / 2
- m_viewPos.height) / 2));
animateScaling(np, ns, 10);
//view_pos.width += view_size.width / 2;
//view_pos.height += view_size.height / 2;
}
else if (m_mouseState == 3) {
//then zoom in
m_mouseState = 0;
Graphics g = getGraphics();
if (m_ZoomBoxColor == null)
g.setColor(Color.black);
else
g.setColor(m_ZoomBoxColor);
if (m_ZoomBoxXORColor == null)
g.setXORMode(Color.white);
else
g.setXORMode(m_ZoomBoxXORColor);
g.drawRect(m_oldMousePos.width, m_oldMousePos.height,
m_newMousePos.width - m_oldMousePos.width,
m_newMousePos.height - m_oldMousePos.height);
g.dispose();
int cw = m_newMousePos.width - m_oldMousePos.width;
int ch = m_newMousePos.height - m_oldMousePos.height;
if (cw >= 1 && ch >= 1) {
if (mouseInBounds(e) &&
(getSize().width / cw) <= 6 &&
(getSize().height / ch) <= 6) {
//now calculate new position and size
Dimension ns = new Dimension();
Dimension np = new Dimension();
double nvsw = getSize().width / (double)(cw);
double nvsh = getSize().height / (double)(ch);
np.width = (int)((m_oldMousePos.width - m_viewPos.width) * -nvsw);
np.height = (int)((m_oldMousePos.height - m_viewPos.height) * -nvsh);
ns.width = (int)(m_viewSize.width * nvsw);
ns.height = (int)(m_viewSize.height * nvsh);
animateScaling(np, ns, 10);
}
}
}
else if (m_mouseState == 0 && m_scaling == 0) {
//menu
m_mouseState = 0;
setFont(new Font("A Name", 0, 12));
//determine if the click was on a node or not
int s = -1;
for (int noa = 0; noa < m_numNodes;noa++) {
if (m_nodes[noa].m_quad == 18) {
//then is on the screen
calcScreenCoords(noa);
if (e.getX() <= m_nodes[noa].m_center + m_nodes[noa].m_side
&& e.getX()
>= m_nodes[noa].m_center - m_nodes[noa].m_side &&
e.getY() >= m_nodes[noa].m_top && e.getY()
<= m_nodes[noa].m_top + m_nodes[noa].m_height) {
//then it is this node that the mouse was clicked on
s = noa;
}
m_nodes[noa].m_top = 32000;
}
}
if (s == -1) {
//the mouse wasn't clicked on a node
m_winMenu.show(this,e.getX(),e.getY());
}
else {
//the mouse was clicked on a node
m_focusNode = s;
m_nodeMenu.show(this, e.getX(), e.getY());
}
setFont(m_currentFont);
}
else if (m_mouseState == 1) {
//dragging
m_mouseState = 0;
m_frameLimiter.stop();
repaint();
}
}
/**
* Checks to see if the coordinates of the mouse lie on this JPanel.
*
* @param e the mouse event.
* @return true if the mouse lies on this JPanel.
*/
private boolean mouseInBounds(MouseEvent e) {
//this returns true if the mouse is currently over the canvas otherwise
//false
if (e.getX() < 0 || e.getY() < 0 || e.getX() > getSize().width
|| e.getY() > getSize().height) {
return false;
}
return true;
}
/**
* Performs intermediate updates to what the user wishes to do.
*
* @param e the mouse event.
*/
public void mouseDragged(MouseEvent e) {
//use mouse state to determine what to do to the view of the tree
if (m_mouseState == 1) {
//then dragging view
m_oldMousePos.width = m_newMousePos.width;
m_oldMousePos.height = m_newMousePos.height;
m_newMousePos.width = e.getX();
m_newMousePos.height = e.getY();
m_viewPos.width += m_newMousePos.width - m_oldMousePos.width;
m_viewPos.height += m_newMousePos.height - m_oldMousePos.height;
}
else if (m_mouseState == 3) {
//then zoom box being created
//redraw the zoom box
Graphics g = getGraphics();
if (m_ZoomBoxColor == null)
g.setColor(Color.black);
else
g.setColor(m_ZoomBoxColor);
if (m_ZoomBoxXORColor == null)
g.setXORMode(Color.white);
else
g.setXORMode(m_ZoomBoxXORColor);
g.drawRect(m_oldMousePos.width, m_oldMousePos.height,
m_newMousePos.width - m_oldMousePos.width,
m_newMousePos.height - m_oldMousePos.height);
m_newMousePos.width = e.getX();
m_newMousePos.height = e.getY();
g.drawRect(m_oldMousePos.width, m_oldMousePos.height,
m_newMousePos.width - m_oldMousePos.width,
m_newMousePos.height - m_oldMousePos.height);
g.dispose();
}
}
/**
* Does nothing.
*
* @param e the mouse event.
*/
public void mouseMoved(MouseEvent e) {
}
/**
* Does nothing.
*
* @param e the mouse event.
*/
public void mouseEntered(MouseEvent e) {
}
/**
* Does nothing.
*
* @param e the mouse event.
*/
public void mouseExited(MouseEvent e) {
}
/**
* Set the highlight for the node with the given id
* @param id the id of the node to set the highlight for
*/
public void setHighlight(String id) {
//set the highlight for the node with the given id
for (int noa = 0; noa < m_numNodes; noa++) {
if (id.equals(m_nodes[noa].m_node.getRefer())) {
//then highlight this node
m_highlightNode = noa;
}
}
//System.out.println("ahuh " + highlight_node + " " +
//nodes[0].node.getRefer());
repaint();
}
/**
* Updates the screen contents.
*
* @param g the drawing surface.
*/
public void paintComponent(Graphics g) {
Color oldBackground = ((Graphics2D) g).getBackground();
if (m_BackgroundColor != null)
((Graphics2D) g).setBackground(m_BackgroundColor);
g.clearRect(0, 0, getSize().width, getSize().height);
((Graphics2D) g).setBackground(oldBackground);
g.setClip(3, 7, getWidth() - 6, getHeight() - 10);
painter(g);
g.setClip(0, 0, getWidth(), getHeight());
}
/**
* Draws the tree to the graphics context
*
* @param g the drawing surface.
*/
private void painter(Graphics g) {
//I have moved what would normally be in the paintComponent
//function to here
//for now so that if I do in fact need to do double
//buffering or the like it will be easier
//this will go through the table of edges and draw the edge if it deems the
//two nodes attached to it could cause it to cut the screen or be on it.
//in the process flagging all nodes so that they can quickly be put to the
//screen if they lie on it
//I do it in this order because in some circumstances I have seen a line
//cut through a node , to make things look better the line will
//be drawn under the node
//converting the screen edges to the node scale so that they
//can be positioned relative to the screen
//note I give a buffer around the edges of the screen.
//when seeing
//if a node is on screen I only bother to check the nodes top centre
//if it has large enough size it may still fall onto the screen
double left_clip = (double)(-m_viewPos.width - 50) / m_viewSize.width;
double right_clip = (double)(getSize().width - m_viewPos.width + 50) /
m_viewSize.width;
double top_clip = (double)(-m_viewPos.height - 50) / m_viewSize.height;
double bottom_clip = (double)(getSize().height - m_viewPos.height + 50) /
m_viewSize.height;
// 12 10 9 //the quadrants
// 20 18 17
// 36 34 33
//first the edges must be rendered
Edge e;
Node r,s;
double ncent,ntop;
int row = 0, col = 0, pq, cq;
for (int noa = 0 ; noa < m_numNodes ; noa++) {
r = m_nodes[noa].m_node;
if (m_nodes[noa].m_change) {
//then recalc row component of quadrant
ntop = r.getTop();
if (ntop < top_clip) {
row = 8;
}
else if (ntop > bottom_clip) {
row = 32;
}
else {
row = 16;
}
}
//calc the column the node falls in for the quadrant
ncent = r.getCenter();
if (ncent < left_clip) {
col = 4;
}
else if (ncent > right_clip) {
col = 1;
}
else {
col = 2;
}
m_nodes[noa].m_quad = row | col;
if (m_nodes[noa].m_parent >= 0) {
//this will draw the edge if it should be drawn
//It will do this by eliminating all edges that definitely won't enter
//the screen and then draw the rest
pq = m_nodes[m_edges[m_nodes[noa].m_parent].m_parent].m_quad;
cq = m_nodes[noa].m_quad;
//note that this will need to be altered if more than 1 parent exists
if ((cq & 8) == 8) {
//then child exists above screen
}
else if ((pq & 32) == 32) {
//then parent exists below screen
}
else if ((cq & 4) == 4 && (pq & 4) == 4) {
//then both child and parent exist to the left of the screen
}
else if ((cq & 1) == 1 && (pq & 1) == 1) {
//then both child and parent exist to the right of the screen
}
else {
//then draw the line
drawLine(m_nodes[noa].m_parent, g);
}
}
//now draw the nodes
}
for (int noa = 0 ;noa < m_numNodes; noa++) {
if (m_nodes[noa].m_quad == 18) {
//then the node is on the screen , draw it
drawNode(noa, g);
}
}
if (m_highlightNode >= 0 && m_highlightNode < m_numNodes) {
//then draw outline
if (m_nodes[m_highlightNode].m_quad == 18) {
Color acol;
if (m_NodeColor == null)
acol = m_nodes[m_highlightNode].m_node.getColor();
else
acol = m_NodeColor;
g.setColor(new Color((acol.getRed() + 125) % 256,
(acol.getGreen() + 125) % 256,
(acol.getBlue() + 125) % 256));
//g.setXORMode(Color.white);
if (m_nodes[m_highlightNode].m_node.getShape() == 1) {
g.drawRect(m_nodes[m_highlightNode].m_center
- m_nodes[m_highlightNode].m_side,
m_nodes[m_highlightNode].m_top,
m_nodes[m_highlightNode].m_width,
m_nodes[m_highlightNode].m_height);
g.drawRect(m_nodes[m_highlightNode].m_center
- m_nodes[m_highlightNode].m_side
+ 1, m_nodes[m_highlightNode].m_top + 1,
m_nodes[m_highlightNode].m_width - 2,
m_nodes[m_highlightNode].m_height - 2);
}
else if (m_nodes[m_highlightNode].m_node.getShape() == 2) {
g.drawOval(m_nodes[m_highlightNode].m_center
- m_nodes[m_highlightNode].m_side,
m_nodes[m_highlightNode].m_top,
m_nodes[m_highlightNode].m_width,
m_nodes[m_highlightNode].m_height);
g.drawOval(m_nodes[m_highlightNode].m_center
- m_nodes[m_highlightNode].m_side
+ 1, m_nodes[m_highlightNode].m_top + 1,
m_nodes[m_highlightNode].m_width - 2,
m_nodes[m_highlightNode].m_height - 2);
}
}
}
for (int noa = 0;noa < m_numNodes;noa++) {
//this resets the coords so that next time a refresh occurs
//they don't accidentally get used
//I will use 32000 to signify that they are invalid, even if this
//coordinate occurs it doesn't
//matter as it is only for the sake of the caching
m_nodes[noa].m_top = 32000;
}
}
/**
* Determines the attributes of the node and draws it.
*
* @param n A subscript identifying the node in nodes array
* @param g The drawing surface
*/
private void drawNode(int n, Graphics g) {
//this will draw a node and then print text on it
if (m_NodeColor == null)
g.setColor(m_nodes[n].m_node.getColor());
else
g.setColor(m_NodeColor);
g.setPaintMode();
calcScreenCoords(n);
int x = m_nodes[n].m_center - m_nodes[n].m_side;
int y = m_nodes[n].m_top;
if (m_nodes[n].m_node.getShape() == 1) {
g.fill3DRect(x, y, m_nodes[n].m_width, m_nodes[n].m_height, true);
drawText(x, y, n, false, g);
}
else if (m_nodes[n].m_node.getShape() == 2) {
g.fillOval(x, y, m_nodes[n].m_width, m_nodes[n].m_height);
drawText(x, y + (int)(m_nodes[n].m_height * .15), n, false, g);
}
}
/**
* Determines the attributes of the edge and draws it.
*
* @param e A subscript identifying the edge in edges array.
* @param g The drawing surface.
*/
private void drawLine(int e, Graphics g) {
//this will draw a line taking in the edge number and then getting
//the nodes subscript for the parent and child entries
//this will draw a line that has been broken in the middle
//for the edge text to be displayed
//if applicable
//first convert both parent and child node coords to screen coords
int p = m_edges[e].m_parent;
int c = m_edges[e].m_child;
calcScreenCoords(c);
calcScreenCoords(p);
if (m_LineColor == null)
g.setColor(Color.black);
else
g.setColor(m_LineColor);
g.setPaintMode();
if (m_currentFont.getSize() < 2) {
//text to small to bother cutting the edge
g.drawLine(m_nodes[p].m_center, m_nodes[p].m_top + m_nodes[p].m_height,
m_nodes[c].m_center, m_nodes[c].m_top);
}
else {
//find where to cut the edge to insert text
int e_width = m_nodes[c].m_center - m_nodes[p].m_center;
int e_height = m_nodes[c].m_top - (m_nodes[p].m_top
+ m_nodes[p].m_height);
int e_width2 = e_width / 2;
int e_height2 = e_height / 2;
int e_centerx = m_nodes[p].m_center + e_width2;
int e_centery = m_nodes[p].m_top + m_nodes[p].m_height + e_height2;
int e_offset = m_edges[e].m_tb;
int tmp = (int)(((double)e_width / e_height) *
(e_height2 - e_offset)) + m_nodes[p].m_center;
//System.out.println(edges[e].m_height);
//draw text now
drawText(e_centerx - m_edges[e].m_side, e_centery - e_offset, e, true
, g);
if (tmp > (e_centerx - m_edges[e].m_side) && tmp
< (e_centerx + m_edges[e].m_side)) {
//then cut line on top and bottom of text
g.drawLine(m_nodes[p].m_center, m_nodes[p].m_top + m_nodes[p].m_height
, tmp, e_centery - e_offset); //first segment
g.drawLine(e_centerx * 2 - tmp, e_centery + e_offset,
m_nodes[c].m_center, m_nodes[c].m_top); //second segment
}
else {
e_offset = m_edges[e].m_side;
if (e_width < 0) {
e_offset *= -1; //adjusting for direction which could otherwise
//screw up the calculation
}
tmp = (int)(((double)e_height / e_width) * (e_width2 - e_offset)) +
m_nodes[p].m_top + m_nodes[p].m_height;
g.drawLine(m_nodes[p].m_center, m_nodes[p].m_top + m_nodes[p].m_height
, e_centerx - e_offset, tmp); //first segment
g.drawLine(e_centerx + e_offset, e_centery * 2 - tmp,
m_nodes[c].m_center, m_nodes[c].m_top); //second segment
}
}
//System.out.println("here" + nodes[p].center);
}
/**
* Draws the text for either an Edge or a Node.
*
* @param x1 the left side of the text area.
* @param y1 the top of the text area.
* @param s A subscript identifying either a Node or Edge.
* @param e_or_n Distinguishes whether it is a node or edge.
* @param g The drawing surface.
*/
private void drawText(int x1, int y1, int s, boolean e_or_n, Graphics g) {
//this function will take in the rectangle that the text should be
//drawn in as well as the subscript
//for either the edge or node and a boolean variable to tell which
// backup color
Color oldColor = g.getColor();
g.setPaintMode();
if (m_FontColor == null)
g.setColor(Color.black);
else
g.setColor(m_FontColor);
String st;
if (e_or_n) {
//then paint for edge
Edge e = m_edges[s].m_edge;
for (int noa = 0;(st = e.getLine(noa)) != null; noa++) {
g.drawString(st, (m_edges[s].m_width - m_fontSize.stringWidth(st)) / 2
+ x1,
y1 + (noa + 1) * m_fontSize.getHeight());
}
}
else {
//then paint for node
Node e = m_nodes[s].m_node;
for (int noa = 0;(st = e.getLine(noa)) != null; noa++) {
g.drawString(st, (m_nodes[s].m_width - m_fontSize.stringWidth(st)) / 2
+ x1,
y1 + (noa + 1) * m_fontSize.getHeight());
}
}
// restore color
g.setColor(oldColor);
}
/**
* Converts the internal coordinates of the node found from n
* and converts them to the actual screen coordinates.
*
* @param n A subscript identifying the Node.
*/
private void calcScreenCoords(int n) {
//this converts the coordinate system the Node uses into screen coordinates
// System.out.println(n + " " + view_pos.height + " " +
//nodes[n].node.getCenter());
if (m_nodes[n].m_top == 32000) {
m_nodes[n].m_top = ((int)(m_nodes[n].m_node.getTop()
* m_viewSize.height)) + m_viewPos.height;
m_nodes[n].m_center = ((int)(m_nodes[n].m_node.getCenter()
* m_viewSize.width)) + m_viewPos.width;
}
}
/**
* This Calculates the minimum size of the tree which will prevent any text
* overlapping and make it readable, and then set the size of the tree to
* this.
*/
private void autoScale() {
//this function will determine the smallest scale value that keeps the text
//from overlapping
//it will leave the view centered
int dist;
Node ln,rn;
Dimension temp = new Dimension(10, 10);
if (m_numNodes <= 1) {
return;
}
//calc height needed by first node
dist = (m_nodes[0].m_height + 40) * m_numLevels;
if (dist > temp.height) {
temp.height = dist;
}
for (int noa = 0;noa < m_numNodes - 1;noa++) {
calcScreenCoords(noa);
calcScreenCoords(noa+1);
if (m_nodes[noa+1].m_change) {
//then on a new level so don't check width this time round
}
else {
dist = m_nodes[noa+1].m_center - m_nodes[noa].m_center;
//the distance between the node centers, along horiz
if (dist <= 0) {
dist = 1;
}
dist = ((6 + m_nodes[noa].m_side + m_nodes[noa+1].m_side)
* m_viewSize.width) / dist; //calc optimal size for width
if (dist > temp.width) {
temp.width = dist;
}
}
//now calc.. minimun hieght needed by nodes
dist = (m_nodes[noa+1].m_height + 40) * m_numLevels;
if (dist > temp.height) {
temp.height = dist;
}
}
int y1, y2, xa, xb;
y1 = m_nodes[m_edges[0].m_parent].m_top;
y2 = m_nodes[m_edges[0].m_child].m_top;
dist = y2 - y1;
if (dist <= 0) {
dist = 1;
}
dist = ((60 + m_edges[0].m_height + m_nodes[m_edges[0].m_parent].m_height)
* m_viewSize.height) / dist;
if (dist > temp.height) {
temp.height = dist;
}
for (int noa = 0;noa < m_numNodes - 2; noa++) {
//check the edges now
if (m_nodes[m_edges[noa+1].m_child].m_change) {
//then edge is on a different level , so skip this one
}
else {
//calc the width requirements of this pair of edges
xa = m_nodes[m_edges[noa].m_child].m_center
- m_nodes[m_edges[noa].m_parent].m_center;
xa /= 2;
xa += m_nodes[m_edges[noa].m_parent].m_center;
xb = m_nodes[m_edges[noa+1].m_child].m_center -
m_nodes[m_edges[noa+1].m_parent].m_center;
xb /= 2;
xb += m_nodes[m_edges[noa+1].m_parent].m_center;
dist = xb - xa;
if (dist <= 0) {
dist = 1;
}
dist = ((12 + m_edges[noa].m_side + m_edges[noa+1].m_side)
* m_viewSize.width)
/ dist;
if (dist > temp.width) {
temp.width = dist;
}
}
//now calc height need by the edges
y1 = m_nodes[m_edges[noa+1].m_parent].m_top;
y2 = m_nodes[m_edges[noa+1].m_child].m_top;
dist = y2 - y1;
if (dist <= 0) {
dist = 1;
}
dist = ((60 + m_edges[noa+1].m_height
+ m_nodes[m_edges[noa+1].m_parent].m_height)
* m_viewSize.height) / dist;
if (dist > temp.height) {
temp.height = dist;
}
}
Dimension e = getSize();
Dimension np = new Dimension();
np.width = (int)(e.width / 2 - (((double)e.width / 2) - m_viewPos.width) /
((double)m_viewSize.width) * (double)temp.width);
np.height = (int)(e.height / 2 - (((double)e.height / 2) -
m_viewPos.height) /
((double)m_viewSize.height) * (double)temp.height);
//animate_scaling(c_size,c_pos,25);
for (int noa = 0;noa < m_numNodes;noa++) {
//this resets the coords so that next time a refresh occurs they don't
//accidentally get used
//I will use 32000 to signify that they are invalid, even if this
//coordinate occurs it doesn't
//matter as it is only for the sake of the caching
m_nodes[noa].m_top = 32000;
}
animateScaling(np, temp, 10);
}
/**
* This will increment the size and position of the tree towards the
* desired size and position
* a little (depending on the value of frames) everytime it is called.
*
* @param n_pos The final position of the tree wanted.
* @param n_size The final size of the tree wanted.
* @param frames The number of frames that shall occur before the final
* size and pos is reached.
*/
private void animateScaling(Dimension n_pos,Dimension n_size,int frames) {
//this function will take new size and position coords , and incrementally
//scale the view to these
//since I will be tying it in with the framelimiter I will simply call
//this function and increment it once
//I will have to use a global variable since I am doing it proportionally
if (frames == 0) {
System.out.println(Messages.getInstance().getString("TreeVisualizer_AnimateScaling_Text"));
m_scaling = 0;
}
else {
if (m_scaling == 0) {
//new animate session
//start timer and set scaling
m_frameLimiter.start();
m_nViewPos.width = n_pos.width;
m_nViewPos.height = n_pos.height;
m_nViewSize.width = n_size.width;
m_nViewSize.height = n_size.height;
m_scaling = frames;
}
int s_w = (n_size.width - m_viewSize.width) / frames;
int s_h = (n_size.height - m_viewSize.height) / frames;
int p_w = (n_pos.width - m_viewPos.width) / frames;
int p_h = (n_pos.height - m_viewPos.height) / frames;
m_viewSize.width += s_w;
m_viewSize.height += s_h;
m_viewPos.width += p_w;
m_viewPos.height += p_h;
repaint();
m_scaling--;
if (m_scaling == 0) {
//all done
m_frameLimiter.stop();
}
}
}
/**
* This will change the font size for displaying the tree to the one
* specified.
*
* @param s The new pointsize of the font.
*/
private void changeFontSize(int s) {
//this will set up the new font that shall be used
//it will also recalculate the size of the nodes as these will change as
//a result of
//the new font size
setFont(m_currentFont = new Font("A Name", 0, s));
m_fontSize = getFontMetrics(getFont());
Dimension d;
for (int noa = 0; noa < m_numNodes; noa++) {
//this will set the size info for each node and edge
d = m_nodes[noa].m_node.stringSize(m_fontSize);
if (m_nodes[noa].m_node.getShape() == 1) {
m_nodes[noa].m_height = d.height + 10;
m_nodes[noa].m_width = d.width + 8;
m_nodes[noa].m_side = m_nodes[noa].m_width / 2;
}
else if (m_nodes[noa].m_node.getShape() == 2) {
m_nodes[noa].m_height = (int)((d.height + 2) * 1.6);
m_nodes[noa].m_width = (int)((d.width + 2) * 1.6);
m_nodes[noa].m_side = m_nodes[noa].m_width / 2;
}
if (noa < m_numNodes - 1) {
//this will do the same for edges
d = m_edges[noa].m_edge.stringSize(m_fontSize);
m_edges[noa].m_height = d.height + 8;
m_edges[noa].m_width = d.width + 8;
m_edges[noa].m_side = m_edges[noa].m_width / 2;
m_edges[noa].m_tb = m_edges[noa].m_height / 2;
}
}
}
/**
* This will fill two arrays with the Nodes and Edges from the tree
* into a particular order.
*
* @param t The top Node of the tree.
* @param l An array that has already been allocated, to be filled.
* @param k An array that has already been allocated, to be filled.
*/
private void arrayFill(Node t, NodeInfo[] l, EdgeInfo[] k) {
//this will take the top node and the array to fill
//it will go through the tree structure and and fill the array with the
//nodes
//from top to bottom left to right
//note I do not believe this function will be able to deal with multiple
//parents
if (t == null || l == null) {
System.exit(1); //this is just a preliminary safety check
//(i shouldn' need it)
}
Edge e;
Node r,s;
l[0] = new NodeInfo();
l[0].m_node = t;
l[0].m_parent = -1;
l[0].m_change = true;
int floater; //this will point at a node that has previously been
//put in the list
//all of the children that this node has shall be put in the list ,
//once this is done the floater shall point at the next node in the list
//this will allow the nodes to be put into order from closest to top node
//to furtherest from top node
int free_space = 1; //the next empty array position
double height = t.getTop(); //this will be used to determine if the node
//has a
//new height compared to the
//previous one
for (floater = 0;floater < free_space;floater++) {
r = l[floater].m_node;
for (int noa = 0;(e = r.getChild(noa)) != null;noa++) {
//this loop pulls out each child of r
//e points to a child edge, getTarget will return that edges child node
s = e.getTarget();
l[free_space] = new NodeInfo();
l[free_space].m_node = s;
l[free_space].m_parent = free_space - 1;
k[free_space - 1] = new EdgeInfo();
k[free_space - 1].m_edge = e;
k[free_space - 1].m_parent = floater;
k[free_space - 1].m_child = free_space; //note although it's child
//will always have a subscript
//of 1 more , I may not nessecarily have access to that
//and it will need the subscr.. for multiple parents
//determine if level of node has changed from previous one
if (height != s.getTop()) {
l[free_space].m_change = true;
height = s.getTop();
}
else {
l[free_space].m_change = false;
}
free_space++;
}
}
}
/**
* Internal Class for containing display information about a Node.
*/
private class NodeInfo {
//this class contains a pointer to the node itself along with extra
//information
//about the node used by the Displayer class
/** The y pos of the node on screen. */
int m_top = 32000; //the main node coords calculated out
/** The x pos of the node on screen. */
int m_center; // these coords will probably change each refresh
//and are the positioning coords
//which the rest of the offsets use
/** The offset to get to the left or right of the node. */
int m_side; //these are the screen offset for the dimensions of
//the node relative to the nodes
//internal top and center values (after they have been converted to
//screen coords
/** The width of the node. */
int m_width;
/** The height of the node. */
int m_height;
/** True if the node is at the start (left) of a new level (not sibling
* group). */
boolean m_change; //this is quickly used to identify whether the node
//has chenged height from the
//previous one to help speed up the calculation of what row it lies in
/** The subscript number of the Nodes parent. */
int m_parent; //this is the index of the nodes parent edge in an array
/** The rough position of the node relative to the screen. */
int m_quad; //what of nine quadrants is it in
/*
12 10 9
20 18 17 //18 being the screen
36 34 33 //this arrangement uses 6 bits, each bit represents a
row or column
*/
/** The Node itself. */
Node m_node;
}
/**
* Internal Class for containing display information about an Edge.
*/
private class EdgeInfo {
//this class contains a pointer to the edge along with all the other
//extra info about the edge
/** The parent subscript (for a Node). */
int m_parent; //array indexs for its two connections
/** The child subscript (for a Node). */
int m_child;
/** The distance from the center of the text to either side. */
int m_side; //these are used to describe the dimensions of the
//text
/** The distance from the center of the text to top or bottom. */
int m_tb; //tb stands for top , bottom, this is simply the
//distance from the middle to top bottom
/** The width of the text. */
int m_width;
/** The height of the text. */
int m_height;
/** The Edge itself. */
Edge m_edge;
}
/**
* Main method for testing this class.
* @param args first argument should be the name of a file that contains
* a tree discription in dot format.
*/
public static void main(String[] args) {
try {
weka.core.logging.Logger.log(weka.core.logging.Logger.Level.INFO, Messages.getInstance().getString("TreeVisualizer_Main_Logger_Text"));
//put in the random data generator right here
// this call with import java.lang gives me between 0 and 1 Math.random
TreeBuild builder = new TreeBuild();
Node top = null;
NodePlace arrange = new PlaceNode2();
//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 }"));
top = builder.create(new FileReader(args[0]));
int num = top.getCount(top,0);
//System.out.println("counter counted " + num + " nodes");
//System.out.println("there are " + num + " nodes");
TreeVisualizer a = new TreeVisualizer(null, top, arrange);
a.setSize(800 ,600);
//a.setTree(top);
JFrame f;
f = new JFrame();
//a.addMouseMotionListener(a);
//a.addMouseListener(a);
//f.add(a);
Container contentPane = f.getContentPane();
contentPane.add(a);
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setSize(800,600);
f.setVisible(true);
//f.
//find_prop(top);
//a.setTree(top,arrange);//,(num + 1000), num / 2 + 1000);
}
catch(IOException e) {
// ignored
}
}
}