package net.sf.openrocket.gui.components; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Component; import java.awt.Graphics; import java.awt.Graphics2D; import javax.swing.Icon; import javax.swing.JTree; import javax.swing.tree.TreeModel; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; public class BasicTree extends JTree { public BasicTree() { super(); setDefaultOptions(); } public BasicTree(TreeNode node) { super(node); setDefaultOptions(); } private void setDefaultOptions() { this.setToggleClickCount(0); javax.swing.plaf.basic.BasicTreeUI plainUI = new javax.swing.plaf.basic.BasicTreeUI(); this.setUI(plainUI); plainUI.setExpandedIcon(TreeIcon.MINUS); plainUI.setCollapsedIcon(TreeIcon.PLUS); plainUI.setLeftChildIndent(15); this.setBackground(Color.WHITE); this.setShowsRootHandles(false); } /** * Expand the entire tree structure. All nodes will be visible after the call. */ public void expandTree() { for (int i = 0; i < getRowCount(); i++) expandRow(i); } @Override public void treeDidChange() { super.treeDidChange(); /* * Expand the childless nodes to prevent leaf nodes from looking expandable. */ expandChildlessNodes(); } /** * Expand all nodes in the tree that are visible and have no children. This can be used * to avoid the situation where a non-leaf node is marked as being expandable, but when * expanding it it has no children. */ private void expandChildlessNodes() { TreeModel model = this.getModel(); if (model == null) { return; } Object root = model.getRoot(); expandChildlessNodes(model, new TreePath(root)); } private void expandChildlessNodes(TreeModel model, TreePath path) { Object object = path.getLastPathComponent(); if (this.isVisible(path)) { int count = model.getChildCount(object); if (count == 0) { this.expandPath(path); } for (int i = 0; i < count; i++) { expandChildlessNodes(model, path.pathByAddingChild(model.getChild(object, i))); } } } /** * Plain-looking tree expand/collapse icons. */ private static class TreeIcon implements Icon { public static final Icon PLUS = new TreeIcon(true); public static final Icon MINUS = new TreeIcon(false); // Implementation: private final static int width = 9; private final static int height = 9; private final static BasicStroke stroke = new BasicStroke(2); private boolean plus; private TreeIcon(boolean plus) { this.plus = plus; } @Override public void paintIcon(Component c, Graphics g, int x, int y) { Graphics2D g2 = (Graphics2D) g.create(); // Background g2.setColor(Color.WHITE); g2.fillRect(x, y, width, height); // Border g2.setColor(Color.DARK_GRAY); g2.drawRect(x, y, width, height); // Horizontal stroke g2.setStroke(stroke); g2.drawLine(x + 3, y + (height + 1) / 2, x + width - 2, y + (height + 1) / 2); // Vertical stroke if (plus) { g2.drawLine(x + (width + 1) / 2, y + 3, x + (width + 1) / 2, y + height - 2); } g2.dispose(); } @Override public int getIconWidth() { return width; } @Override public int getIconHeight() { return height; } } }