/* 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; } }