2 // An AWT component for displaying a tree-like heirachy, with each node
3 // having an icon and a name. This heirachy can be expanded or contracted
6 import java.util.Vector;
8 public class Hierarchy extends BorderPanel implements CbScrollbarCallback
10 HierarchyNode root; // the root of the tree
11 CbScrollbar sb; // scrollbar at right
12 int width, height; // usable drawing area
13 int sbwidth; // size of scrollbar
14 HierarchyCallback callback; // who to call on open / close
15 Image bim; // double-buffer image
16 Font font = new Font("courier", Font.PLAIN, 12);
17 FontMetrics fnm; // size of font used
18 Graphics bg; // back-images graphics
19 int top = 0; // top-most row displayed
20 int count = 0; // total rows in the tree
21 Insets in; // insets from border
22 HierarchyNode sel; // selected node
23 long last; // time of last mouse click
24 static boolean broken_awt = System.getProperty("os.name").
25 startsWith("Windows");
27 // Create a new Hierarchy object with the given root
28 Hierarchy(HierarchyNode r)
34 // Create a new Hierarchy object that calls back to the given object
35 // when nodes are clicked on.
36 Hierarchy(HierarchyNode r, HierarchyCallback c)
42 // Create an empty hierarchy object, with no callback
45 super(3, Util.dark_edge_hi, Util.body_hi);
49 sb = new CbScrollbar(CbScrollbar.VERTICAL, this);
53 // Create an empty hierarchy object, set to report user actions to
55 Hierarchy(HierarchyCallback c)
62 // Called by the using class when the tree passed to this object
63 // changes, to force a redraw and resizing of the scrollbar
74 // Set the root node for this hierarchy
75 void setRoot(HierarchyNode r)
82 // Return the currently selected node, or null
83 HierarchyNode selected()
89 // Selected the given node
90 void select(HierarchyNode s)
95 // force the use of some font
96 public void setFont(Font f)
104 // Called when this component gets resized
105 public void reshape(int nx, int ny, int nw, int nh)
108 sbwidth = sb.minimumSize().width;
109 width = nw-sbwidth - (in.left + in.right);
110 height = nh - (in.top + in.bottom);
111 sb.reshape(width+in.left, in.top, sbwidth, height);
113 // force creation of a new backing images
118 super.reshape(nx, ny, nw, nh);
122 // Called sometime after repaint()
123 public void update(Graphics g)
130 // Blit the backing image to the front
131 public void paint(Graphics g)
135 // This is the first rendering
136 bim = createImage(width, height);
137 bg = bim.getGraphics();
139 fnm = bg.getFontMetrics();
143 g.drawImage(bim, in.left, in.top, this);
147 // Called upon a mouseclick
148 public boolean mouseDown(Event evt, int x, int y)
151 return false; // nothing to do
152 HierarchyNode s = nodeat(root, x/16, (y/16)+top);
160 // Check for double-click
162 if (evt.when-last < 500 && sel == s)
168 if (dc && sel.ch != null) {
169 // Open or close this node
170 sel.open = !sel.open;
171 if (callback != null) {
172 // Notify callback, which MAY do something to change
173 // the structure of the tree
174 if (sel.open) callback.openNode(this, sel);
175 else callback.closeNode(this, sel);
178 else if (callback != null) {
179 // Single click on a node or double-click on leaf node
180 if (dc) callback.doubleNode(this, sel);
181 else callback.clickNode(this, sel);
188 public void moved(CbScrollbar s, int v)
193 public void moving(CbScrollbar s, int v)
201 // Draw the current tree view into the backing image
202 private void render()
205 int fh = fnm.getHeight(), // useful font metrics
206 fa = fnm.getAscent();
207 bg.setColor(Util.light_bg);
208 bg.fillRect(0, 0, width, height);
210 return; // nothing to do
211 bg.setColor(Util.text);
212 recurse(root, 0, 0, fh, fa);
217 // Render a node in the tree at the given location, maybe followed
218 // by all it's children. Return the number of rows this node took
220 private int recurse(HierarchyNode n, int x, int y, int fh, int fa)
222 int xx = x*16, yy = (y-top)*16;
227 int tw = fnm.stringWidth(n.text);
228 if (yy >= 0 && yy <= height) {
231 bg.drawImage(n.im, xx, yy, this);
234 bg.setColor(Util.body);
235 bg.fillRect(xx+17, yy+2, tw+2, 13);
236 bg.setColor(Util.text);
238 bg.drawString(n.text, xx+18, yy+12);
240 if (n.ch != null && n.open && yy <= height) {
242 bg.drawLine(xx+18, yy+14, xx+17+tw, yy+14);
246 for(int i=0; i<n.ch.size() && yy<=height; i++) {
247 int l=recurse((HierarchyNode)n.ch.elementAt(i),
249 bg.drawLine(xx+7, yy+7, xx+15, yy+7);
250 if (i == n.ch.size()-1)
251 bg.drawLine(xx+7, yy, xx+7, yy+7);
253 bg.drawLine(xx+7, yy, xx+7,yy+(l*16)-1);
262 // Re-compute scrollbar size
263 private void compscroll()
267 int ct = root!=null ? count(root) : 1;
268 int r = Math.min(ct, height/16 - 1);
270 //sb.setValues(top, r==0?1:r, c<0?0:c);
271 sb.setValues(top, r==0?1:r, ct);
275 // Returns the number of visible rows from a node
276 private int count(HierarchyNode n)
279 if (n.open && n.ch != null)
280 for(int i=0; i<n.ch.size(); i++)
281 l += count((HierarchyNode)n.ch.elementAt(i));
286 // Is the given node at the given position? If not, check its
288 private HierarchyNode nodeat(HierarchyNode n, int x, int y)
290 if (y == n.y && x >= n.x)
292 if (n.ch == null || !n.open)
294 for(int i=0; i<n.ch.size(); i++) {
295 HierarchyNode c = nodeat((HierarchyNode)n.ch.elementAt(i),x,y);
296 if (c != null) return c;
303 // One node in the tree displayed by the Hierarchy object.
306 boolean open; // is this node open?
307 Image im; // icon for this node (assumed to be 16x16!)
308 Vector ch; // sub-nodes of this one, or null
309 String text; // name of this node
310 int x, y; // row/column in list
314 HierarchyNode(boolean o, Image i, Vector c, String t)
324 // Programmers using the Hierarchy class pass an object that implements the
325 // HierarchyCallback interface to its constructor, to receive information
326 // about user actions.
327 interface HierarchyCallback
330 // Called when a node with children is opened
331 void openNode(Hierarchy h, HierarchyNode n);
334 // Called when a node is closed
335 void closeNode(Hierarchy h, HierarchyNode n);
338 // Called when the user clicks on a node
339 void clickNode(Hierarchy h, HierarchyNode n);
342 // Called when a user double-clicks on a node
343 void doubleNode(Hierarchy h, HierarchyNode n);