/*
This file is part of the algoviz@vt collection of algorithm
visualizations.
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 3
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 distribution. If not, see
.
*/
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JPanel;
import javax.swing.Timer;
/**
* A JPanel with a graphical BST drawn on it. The BST lies underneath and this
* class interacts with it, telling it to draw itself.
*
* @author Andrew Whitaker (aawhitak@vt.edu)
*
*/
public class TreePanel extends JPanel
{
/**
*
*/
private static final long serialVersionUID = -2064047929713235997L;
public static final int NODE_VERTICAL_DISTANCE = 100;
private static final int ANIMATION_TIME = 10;
private BST bst;
private static int NODE_SPACING = 30;
private int lowestLevel = -1;
private boolean repaintBST, recalculateBST;
private int Y_ANIMATION_INCREMENT = 1;
private int X_ANIMATION_INCREMENT = 1;
private Timer timer;
/**
* Creates a new TreePanel, with a parent TreeApplet.
* @param a
*/
public TreePanel(TreeApplet a)
{
super();
repaintBST = recalculateBST = true;
bst = new BST(this);
/*
* Uncomment this section to automatically add nodes to the BST when the
* app starts .
*/
// bst.insert(40, new GraphicalNode(40));
// bst.insert(10, new GraphicalNode(10));
// bst.insert(3, new GraphicalNode(3));
// bst.insert(11, new GraphicalNode(11));
// bst.insert(50, new GraphicalNode(50));
// bst.insert(49, new GraphicalNode(49));
// bst.insert(18, new GraphicalNode(18));
// bst.insert(19, new GraphicalNode(19));
// bst.insert(21, new GraphicalNode(21));
// bst.insert(35, new GraphicalNode(35));
// bst.insert(47, new GraphicalNode(47));
// bst.insert(46, new GraphicalNode(46));
// bst.insert(48, new GraphicalNode(48));
// bst.insert(50, new GraphicalNode(50));
// bst.insert(49, new GraphicalNode(49));
// bst.insert(51, new GraphicalNode(51));
// bst.insert(36, new GraphicalNode(36));
// bst.insert(33, new GraphicalNode(33));
// bst.insert(32, new GraphicalNode(32));
// bst.insert(34, new GraphicalNode(34));
// bst.insert(42, new GraphicalNode(42));
// bst.insert(44, new GraphicalNode(44));
// bst.insert(43, new GraphicalNode(43));
// bst.insert(45, new GraphicalNode(45));
// bst.insert(22, new GraphicalNode(22));
// bst.insert(37, new GraphicalNode(37));
// bst.insert(36, new GraphicalNode(36));
// bst.insert(38, new GraphicalNode(38));
// bst.insert(35, new GraphicalNode(35));
}
/**
* Insert an integer to the tree.
*
* @param i
*/
public void insert(int i)
{
GraphicalNode insertMe = new GraphicalNode(i);
insertMe.setHidden(true);
bst.insert(i, insertMe);
}
public void find(int i)
{
bst.find(i);
}
/**
* Animate the entry of a new node to the TreePanel.
*
* @param n
* The node to animate.
*/
public void animateNodeEntry(final GraphicalNode n)
{
// repaintBST = false;
// recalculateBST = true;
bst.drawPostOrder(getGraphics(), true, false);
System.out.println("Animating: " + n);
if (n.getAbstractX() == 0 && n.getAbstractY() == 0)
{
n.setHidden(false);
System.out.println("returning");
recalculateBST = true;
repaintBST = true;
repaint();
return;
}
if (n.isHidden()) n.setHidden(false);
n.select();
final int finalX = n.getX();
final int finalY = n.getY();
final int initialX = getPhysicalX(getParentX(n.getAbstractX()), n
.getAbstractY() - 1);
final int initialY = n.getY() - NODE_VERTICAL_DISTANCE;
int d = finalX - initialX;
n.setXPos(initialX);
n.setYPos(initialY);
int incr = X_ANIMATION_INCREMENT;
if (finalX < initialX)
{
incr = -1;
d *= -1;
}
final int increment = incr;
System.out.println("initialX = " + initialX);
System.out.println("initialY = " + initialY);
System.out.println("FinalX = " + finalX);
System.out.println("FinalY = " + finalY);
ActionListener a = new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
System.out.println("TIMER");
if (n.getX() == finalX && n.getY() == finalY)
{
System.out.println("returning");
timer.stop();
return;
}
System.out.println("Animation looping...");
if (n.getX() != finalX) n.setXPos(n.getX() + increment);
if (n.getY() != finalY)
n.setYPos(n.getY() + Y_ANIMATION_INCREMENT);
System.out.println("n.getX() : " + n.getX());
System.out.println("n.getY() : " + n.getY());
repaintBST = true;
recalculateBST = false;
repaint();
}
};
/*
* Timer fires and animates node.
*/
timer = new Timer(ANIMATION_TIME, a);
timer.start();
}
public void paintComponent(Graphics g)
{
// if (recalculateBST == true && timer != null && timer.isRunning())
// {
//
// }
// else
// {
System.out.println("REPAINTING");
super.paintComponent(g);
System.out.println("Repaint: " + repaintBST);
System.out.println("Recalc: " + recalculateBST);
bst.drawPostOrder(g, recalculateBST, repaintBST);
// }
}
/**
* @return The BST's state list for the last operation.
*/
public ArrayList getStateList()
{
return bst.getStateList();
}
public Timer getTimer()
{
return timer;
}
/**
* Draws a line between two nodes.
*
* @param x1
* @param y1
* @param x2
* @param y2
* @param g
*/
public void drawLine(int x1, int y1, int x2, int y2, Graphics g)
{
g.drawLine(getPhysicalX(x1, y1) + 15, y1 * 100 + 15, getPhysicalX(x2,
y2) + 15, y2 * 100);
}
/**
* Gets the parent abstract position of an x value.
*
* @param x
* @return
*/
public int getParentX(int x)
{
return x / 2;
}
/**
* Get the physical X position of a node based on its abstract x and y.
*
* @param x
* @param y
* @return
*/
public int getPhysicalX(int x, int y)
{
int w = getWidth();
int base = w / (y + 2);
// int parent = w / (y + 1);
// int spacing = NODE_SPACING * ((lowestLevel - y) + 1);
if (y == lowestLevel)
{
if (x % 2 != 1)
{
return base + ((x * NODE_SPACING)) / 2;
}
else
{
return getPhysicalX(x - 1, y) + NODE_SPACING;
}
}
else
{
int pos = (getPhysicalX(x * 2, y + 1) + getPhysicalX(x * 2 + 1,
y + 1)) / 2;
return pos;
}
}
public void setRepaint(boolean r)
{
repaintBST = r;
}
public void setRecalculateTree(boolean r)
{
recalculateBST = r;
}
public void setLevels(int levels)
{
lowestLevel = levels;
}
}