create changelog entry
[debian/openrocket] / core / src / net / sf / openrocket / gui / components / BasicTree.java
1 package net.sf.openrocket.gui.components;
2
3 import java.awt.BasicStroke;
4 import java.awt.Color;
5 import java.awt.Component;
6 import java.awt.Graphics;
7 import java.awt.Graphics2D;
8
9 import javax.swing.Icon;
10 import javax.swing.JTree;
11 import javax.swing.tree.TreeModel;
12 import javax.swing.tree.TreeNode;
13 import javax.swing.tree.TreePath;
14
15 public class BasicTree extends JTree {
16         
17
18         public BasicTree() {
19                 super();
20                 setDefaultOptions();
21         }
22         
23         public BasicTree(TreeNode node) {
24                 super(node);
25                 setDefaultOptions();
26         }
27         
28         
29         private void setDefaultOptions() {
30                 this.setToggleClickCount(0);
31                 
32                 javax.swing.plaf.basic.BasicTreeUI plainUI = new javax.swing.plaf.basic.BasicTreeUI();
33                 this.setUI(plainUI);
34                 plainUI.setExpandedIcon(TreeIcon.MINUS);
35                 plainUI.setCollapsedIcon(TreeIcon.PLUS);
36                 plainUI.setLeftChildIndent(15);
37                 
38
39                 this.setBackground(Color.WHITE);
40                 this.setShowsRootHandles(false);
41         }
42         
43         
44         /**
45          * Expand the entire tree structure.  All nodes will be visible after the call.
46          */
47         public void expandTree() {
48                 for (int i = 0; i < getRowCount(); i++)
49                         expandRow(i);
50         }
51         
52         
53
54
55         @Override
56         public void treeDidChange() {
57                 super.treeDidChange();
58                 /*
59                  * Expand the childless nodes to prevent leaf nodes from looking expandable.
60                  */
61                 expandChildlessNodes();
62         }
63         
64         /**
65          * Expand all nodes in the tree that are visible and have no children.  This can be used
66          * to avoid the situation where a non-leaf node is marked as being expandable, but when
67          * expanding it it has no children.
68          */
69         private void expandChildlessNodes() {
70                 TreeModel model = this.getModel();
71                 if (model == null) {
72                         return;
73                 }
74                 Object root = model.getRoot();
75                 expandChildlessNodes(model, new TreePath(root));
76         }
77         
78         private void expandChildlessNodes(TreeModel model, TreePath path) {
79                 Object object = path.getLastPathComponent();
80                 if (this.isVisible(path)) {
81                         int count = model.getChildCount(object);
82                         if (count == 0) {
83                                 this.expandPath(path);
84                         }
85                         for (int i = 0; i < count; i++) {
86                                 expandChildlessNodes(model, path.pathByAddingChild(model.getChild(object, i)));
87                         }
88                 }
89         }
90         
91         
92
93         /**
94          * Plain-looking tree expand/collapse icons.
95          */
96         private static class TreeIcon implements Icon {
97                 public static final Icon PLUS = new TreeIcon(true);
98                 public static final Icon MINUS = new TreeIcon(false);
99                 
100                 // Implementation:
101                 
102                 private final static int width = 9;
103                 private final static int height = 9;
104                 private final static BasicStroke stroke = new BasicStroke(2);
105                 private boolean plus;
106                 
107                 private TreeIcon(boolean plus) {
108                         this.plus = plus;
109                 }
110                 
111                 @Override
112                 public void paintIcon(Component c, Graphics g, int x, int y) {
113                         Graphics2D g2 = (Graphics2D) g.create();
114                         
115                         // Background
116                         g2.setColor(Color.WHITE);
117                         g2.fillRect(x, y, width, height);
118                         
119                         // Border
120                         g2.setColor(Color.DARK_GRAY);
121                         g2.drawRect(x, y, width, height);
122                         
123                         // Horizontal stroke
124                         g2.setStroke(stroke);
125                         g2.drawLine(x + 3, y + (height + 1) / 2, x + width - 2, y + (height + 1) / 2);
126                         
127                         // Vertical stroke
128                         if (plus) {
129                                 g2.drawLine(x + (width + 1) / 2, y + 3, x + (width + 1) / 2, y + height - 2);
130                         }
131                         
132                         g2.dispose();
133                 }
134                 
135                 @Override
136                 public int getIconWidth() {
137                         return width;
138                 }
139                 
140                 @Override
141                 public int getIconHeight() {
142                         return height;
143                 }
144         }
145 }