//ShowTree Tree Visualization System
//Copyright (C) 2009 Yuvi Masory
//
//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, version 3 only.
//
//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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
package display.components;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import javax.swing.JPanel;
import display.DrawTree;
import display.Start;
/*
* The component where all drawing is ultimately done.
* paintComponent() and repaint() should NOT be called directly when a _new_ tree is being displayed
* or the positioning algorithm changed. Use displayTree() instead, which takes as an argument whether
* labels are to be drawn or not.
*/
public class TreePane extends JPanel {
private static final long serialVersionUID = 1L;
private static TreePane instance;
private static RenderingHints renderHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
private boolean respectsNodeWidths;
private TreePane() {
setFont(new Font("Serif", Font.PLAIN, 18));
setLayout(null);
setOpaque(true);
setBackground(Color.WHITE);
setPreferredSize(new Dimension(0, 0));
}
public static TreePane getInstance() {
if (instance == null) {
instance = new TreePane();
}
return instance;
}
/*
* @returns a Rectangle representeing the area of the TreePane that is NOT in the edge padding area (where
* nothing should be drawn)
*/
private Rectangle getUsableArea() {
return new Rectangle(
Start.PADDING,
Start.PADDING,
(int)(getSize().getWidth() - 2* Start.PADDING),
(int)(getSize().getHeight() - 2 * Start.PADDING)
);
}
/*
* Overrides paintComponent to set up rendering hints, which make the edges pretty and smooth,
* not jagged.
* (non-Javadoc)
* @see javax.swing.JComponent#paintComponent(java.awt.Graphics)
*/
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
renderHints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHints(renderHints);
DrawTree.paintTree(g, respectsNodeWidths);
if(Start.isShowGrid() == true) {
drawBoundaries(g);
drawGrid(g);
}
}
public void displayTree(boolean handlesWidths) {
respectsNodeWidths = handlesWidths;
repaint();
}
public void unDisplayTree() {
Start.setRoot(null);
repaint();
}
/*
* Draws grid on TreePane for debugging purposes.
* The unit used is the currently saved (not the same as the displayed) minSeparation value.
* Grid begins and is confined to the usable area (meaning not in the padded borders around the TreePane.
*/
private void drawGrid(Graphics g) {
Rectangle rect = getUsableArea();
double width = rect.getWidth();
double height = rect.getHeight();
for(int i = Start.PADDING; i < width; i+=Start.getMinXSeparation()) {
g.drawLine(i, Start.PADDING, i, (int) height + Start.PADDING);
}
// for(int i = Start.PADDING; i < height; i+=Start.getMinXSeparation()) {
// g.drawLine(Start.PADDING, i, (int) width + Start.PADDING, i);
// }
}
/*
* Draws rectangle around the usable area of the TreePane (meaning area not including padded borders
* where nothing is drawn). This is really just to provide a line at the bottom and right, to give a
* visual cue that the grid ends deliberately.
*/
private void drawBoundaries(Graphics g) {
Rectangle rect = getUsableArea();
g.drawRect(
(int)(rect.getX()),
(int)(rect.getY()),
(int)(rect.getWidth()),
(int)(rect.getHeight()));
}
}