KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > tree > AbstractLayoutCache


1 /*
2  * @(#)AbstractLayoutCache.java 1.17 04/05/05
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.swing.tree;
9
10 import javax.swing.event.TreeModelEvent JavaDoc;
11 import java.awt.Dimension JavaDoc;
12 import java.awt.Rectangle JavaDoc;
13 import java.util.Enumeration JavaDoc;
14
15 /**
16  * <strong>Warning:</strong>
17  * Serialized objects of this class will not be compatible with
18  * future Swing releases. The current serialization support is
19  * appropriate for short term storage or RMI between applications running
20  * the same version of Swing. As of 1.4, support for long term storage
21  * of all JavaBeans<sup><font size="-2">TM</font></sup>
22  * has been added to the <code>java.beans</code> package.
23  * Please see {@link java.beans.XMLEncoder}.
24  *
25  * @version 1.17 05/05/04
26  * @author Scott Violet
27  */

28
29 public abstract class AbstractLayoutCache implements RowMapper JavaDoc {
30     /** Object responsible for getting the size of a node. */
31     protected NodeDimensions nodeDimensions;
32
33     /** Model providing information. */
34     protected TreeModel JavaDoc treeModel;
35
36     /** Selection model. */
37     protected TreeSelectionModel JavaDoc treeSelectionModel;
38
39     /**
40      * True if the root node is displayed, false if its children are
41      * the highest visible nodes.
42      */

43     protected boolean rootVisible;
44
45     /**
46       * Height to use for each row. If this is <= 0 the renderer will be
47       * used to determine the height for each row.
48       */

49     protected int rowHeight;
50
51
52     /**
53      * Sets the renderer that is responsible for drawing nodes in the tree
54      * and which is threfore responsible for calculating the dimensions of
55      * individual nodes.
56      *
57      * @param nd a <code>NodeDimensions</code> object
58      */

59     public void setNodeDimensions(NodeDimensions nd) {
60     this.nodeDimensions = nd;
61     }
62
63     /**
64      * Returns the object that renders nodes in the tree, and which is
65      * responsible for calculating the dimensions of individual nodes.
66      *
67      * @return the <code>NodeDimensions</code> object
68      */

69     public NodeDimensions getNodeDimensions() {
70     return nodeDimensions;
71     }
72
73     /**
74      * Sets the <code>TreeModel</code> that will provide the data.
75      *
76      * @param newModel the <code>TreeModel</code> that is to
77      * provide the data
78      */

79     public void setModel(TreeModel JavaDoc newModel) {
80         treeModel = newModel;
81     }
82
83     /**
84      * Returns the <code>TreeModel</code> that is providing the data.
85      *
86      * @return the <code>TreeModel</code> that is providing the data
87      */

88     public TreeModel JavaDoc getModel() {
89         return treeModel;
90     }
91
92     /**
93      * Determines whether or not the root node from
94      * the <code>TreeModel</code> is visible.
95      *
96      * @param rootVisible true if the root node of the tree is to be displayed
97      * @see #rootVisible
98      * @beaninfo
99      * bound: true
100      * description: Whether or not the root node
101      * from the TreeModel is visible.
102      */

103     public void setRootVisible(boolean rootVisible) {
104         this.rootVisible = rootVisible;
105     }
106
107     /**
108      * Returns true if the root node of the tree is displayed.
109      *
110      * @return true if the root node of the tree is displayed
111      * @see #rootVisible
112      */

113     public boolean isRootVisible() {
114         return rootVisible;
115     }
116
117     /**
118      * Sets the height of each cell. If the specified value
119      * is less than or equal to zero the current cell renderer is
120      * queried for each row's height.
121      *
122      * @param rowHeight the height of each cell, in pixels
123      * @beaninfo
124      * bound: true
125      * description: The height of each cell.
126      */

127     public void setRowHeight(int rowHeight) {
128         this.rowHeight = rowHeight;
129     }
130
131     /**
132      * Returns the height of each row. If the returned value is less than
133      * or equal to 0 the height for each row is determined by the
134      * renderer.
135      */

136     public int getRowHeight() {
137         return rowHeight;
138     }
139
140     /**
141      * Sets the <code>TreeSelectionModel</code> used to manage the
142      * selection to new LSM.
143      *
144      * @param newLSM the new <code>TreeSelectionModel</code>
145      */

146     public void setSelectionModel(TreeSelectionModel JavaDoc newLSM) {
147     if(treeSelectionModel != null)
148         treeSelectionModel.setRowMapper(null);
149     treeSelectionModel = newLSM;
150     if(treeSelectionModel != null)
151         treeSelectionModel.setRowMapper(this);
152     }
153
154     /**
155      * Returns the model used to maintain the selection.
156      *
157      * @return the <code>treeSelectionModel</code>
158      */

159     public TreeSelectionModel JavaDoc getSelectionModel() {
160     return treeSelectionModel;
161     }
162
163     /**
164      * Returns the preferred height.
165      *
166      * @return the preferred height
167      */

168     public int getPreferredHeight() {
169     // Get the height
170
int rowCount = getRowCount();
171
172     if(rowCount > 0) {
173         Rectangle JavaDoc bounds = getBounds(getPathForRow(rowCount - 1),
174                          null);
175
176         if(bounds != null)
177         return bounds.y + bounds.height;
178     }
179     return 0;
180     }
181
182     /**
183      * Returns the preferred width for the passed in region.
184      * The region is defined by the path closest to
185      * <code>(bounds.x, bounds.y)</code> and
186      * ends at <code>bounds.height + bounds.y</code>.
187      * If <code>bounds</code> is <code>null</code>,
188      * the preferred width for all the nodes
189      * will be returned (and this may be a VERY expensive
190      * computation).
191      *
192      * @param bounds the region being queried
193      * @return the preferred width for the passed in region
194      */

195     public int getPreferredWidth(Rectangle JavaDoc bounds) {
196     int rowCount = getRowCount();
197
198     if(rowCount > 0) {
199         // Get the width
200
TreePath JavaDoc firstPath;
201         int endY;
202
203         if(bounds == null) {
204         firstPath = getPathForRow(0);
205         endY = Integer.MAX_VALUE;
206         }
207         else {
208         firstPath = getPathClosestTo(bounds.x, bounds.y);
209         endY = bounds.height + bounds.y;
210         }
211
212         Enumeration JavaDoc paths = getVisiblePathsFrom(firstPath);
213
214         if(paths != null && paths.hasMoreElements()) {
215         Rectangle JavaDoc pBounds = getBounds((TreePath JavaDoc)paths.nextElement(),
216                         null);
217         int width;
218
219         if(pBounds != null) {
220             width = pBounds.x + pBounds.width;
221             if (pBounds.y >= endY) {
222             return width;
223             }
224         }
225         else
226             width = 0;
227         while (pBounds != null && paths.hasMoreElements()) {
228             pBounds = getBounds((TreePath JavaDoc)paths.nextElement(),
229                     pBounds);
230             if (pBounds != null && pBounds.y < endY) {
231             width = Math.max(width, pBounds.x + pBounds.width);
232             }
233             else {
234             pBounds = null;
235             }
236         }
237         return width;
238         }
239     }
240     return 0;
241     }
242
243     //
244
// Abstract methods that must be implemented to be concrete.
245
//
246

247     /**
248       * Returns true if the value identified by row is currently expanded.
249       */

250     public abstract boolean isExpanded(TreePath JavaDoc path);
251
252     /**
253      * Returns a rectangle giving the bounds needed to draw path.
254      *
255      * @param path a <code>TreePath</code> specifying a node
256      * @param placeIn a <code>Rectangle</code> object giving the
257      * available space
258      * @return a <code>Rectangle</code> object specifying the space to be used
259      */

260     public abstract Rectangle JavaDoc getBounds(TreePath JavaDoc path, Rectangle JavaDoc placeIn);
261
262     /**
263       * Returns the path for passed in row. If row is not visible
264       * <code>null</code> is returned.
265       *
266       * @param row the row being queried
267       * @return the <code>TreePath</code> for the given row
268       */

269     public abstract TreePath JavaDoc getPathForRow(int row);
270
271     /**
272       * Returns the row that the last item identified in path is visible
273       * at. Will return -1 if any of the elements in path are not
274       * currently visible.
275       *
276       * @param path the <code>TreePath</code> being queried
277       * @return the row where the last item in path is visible or -1
278       * if any elements in path aren't currently visible
279       */

280     public abstract int getRowForPath(TreePath JavaDoc path);
281
282     /**
283       * Returns the path to the node that is closest to x,y. If
284       * there is nothing currently visible this will return <code>null</code>,
285       * otherwise it'll always return a valid path.
286       * If you need to test if the
287       * returned object is exactly at x, y you should get the bounds for
288       * the returned path and test x, y against that.
289       *
290       * @param x the horizontal component of the desired location
291       * @param y the vertical component of the desired location
292       * @return the <code>TreePath</code> closest to the specified point
293       */

294     public abstract TreePath JavaDoc getPathClosestTo(int x, int y);
295
296     /**
297      * Returns an <code>Enumerator</code> that increments over the visible
298      * paths starting at the passed in location. The ordering of the
299      * enumeration is based on how the paths are displayed.
300      * The first element of the returned enumeration will be path,
301      * unless it isn't visible,
302      * in which case <code>null</code> will be returned.
303      *
304      * @param path the starting location for the enumeration
305      * @return the <code>Enumerator</code> starting at the desired location
306      */

307     public abstract Enumeration JavaDoc<TreePath JavaDoc> getVisiblePathsFrom(TreePath JavaDoc path);
308
309     /**
310      * Returns the number of visible children for row.
311      *
312      * @param path the path being queried
313      * @return the number of visible children for the specified path
314      */

315     public abstract int getVisibleChildCount(TreePath JavaDoc path);
316
317     /**
318      * Marks the path <code>path</code> expanded state to
319      * <code>isExpanded</code>.
320      *
321      * @param path the path being expanded or collapsed
322      * @param isExpanded true if the path should be expanded, false otherwise
323      */

324     public abstract void setExpandedState(TreePath JavaDoc path, boolean isExpanded);
325
326     /**
327      * Returns true if the path is expanded, and visible.
328      *
329      * @param path the path being queried
330      * @return true if the path is expanded and visible, false otherwise
331      */

332     public abstract boolean getExpandedState(TreePath JavaDoc path);
333
334     /**
335      * Number of rows being displayed.
336      *
337      * @return the number of rows being displayed
338      */

339     public abstract int getRowCount();
340
341     /**
342      * Informs the <code>TreeState</code> that it needs to recalculate
343      * all the sizes it is referencing.
344      */

345     public abstract void invalidateSizes();
346
347     /**
348      * Instructs the <code>LayoutCache</code> that the bounds for
349      * <code>path</code> are invalid, and need to be updated.
350      *
351      * @param path the path being updated
352      */

353     public abstract void invalidatePathBounds(TreePath JavaDoc path);
354
355     //
356
// TreeModelListener methods
357
// AbstractTreeState does not directly become a TreeModelListener on
358
// the model, it is up to some other object to forward these methods.
359
//
360

361     /**
362      * <p>
363      * Invoked after a node (or a set of siblings) has changed in some
364      * way. The node(s) have not changed locations in the tree or
365      * altered their children arrays, but other attributes have
366      * changed and may affect presentation. Example: the name of a
367      * file has changed, but it is in the same location in the file
368      * system.</p>
369      *
370      * <p>e.path() returns the path the parent of the changed node(s).</p>
371      *
372      * <p>e.childIndices() returns the index(es) of the changed node(s).</p>
373      *
374      * @param e the <code>TreeModelEvent</code>
375      */

376     public abstract void treeNodesChanged(TreeModelEvent JavaDoc e);
377
378     /**
379      * <p>Invoked after nodes have been inserted into the tree.</p>
380      *
381      * <p>e.path() returns the parent of the new nodes</p>
382      * <p>e.childIndices() returns the indices of the new nodes in
383      * ascending order.</p>
384      *
385      * @param e the <code>TreeModelEvent</code>
386      */

387     public abstract void treeNodesInserted(TreeModelEvent JavaDoc e);
388
389     /**
390      * <p>Invoked after nodes have been removed from the tree. Note that
391      * if a subtree is removed from the tree, this method may only be
392      * invoked once for the root of the removed subtree, not once for
393      * each individual set of siblings removed.</p>
394      *
395      * <p>e.path() returns the former parent of the deleted nodes.</p>
396      *
397      * <p>e.childIndices() returns the indices the nodes had before they were deleted in ascending order.</p>
398      *
399      * @param e the <code>TreeModelEvent</code>
400      */

401     public abstract void treeNodesRemoved(TreeModelEvent JavaDoc e);
402
403     /**
404      * <p>Invoked after the tree has drastically changed structure from a
405      * given node down. If the path returned by <code>e.getPath()</code>
406      * is of length one and the first element does not identify the
407      * current root node the first element should become the new root
408      * of the tree.</p>
409      *
410      * <p>e.path() holds the path to the node.</p>
411      * <p>e.childIndices() returns null.</p>
412      *
413      * @param e the <code>TreeModelEvent</code>
414      */

415     public abstract void treeStructureChanged(TreeModelEvent JavaDoc e);
416
417     //
418
// RowMapper
419
//
420

421     /**
422      * Returns the rows that the <code>TreePath</code> instances in
423      * <code>path</code> are being displayed at.
424      * This method should return an array of the same length as that passed
425      * in, and if one of the <code>TreePaths</code>
426      * in <code>path</code> is not valid its entry in the array should
427      * be set to -1.
428      *
429      * @param paths the array of <code>TreePath</code>s being queried
430      * @return an array of the same length that is passed in containing
431      * the rows that each corresponding where each
432      * <code>TreePath</code> is displayed; if <code>paths</code>
433      * is <code>null</code>, <code>null</code> is returned
434      */

435     public int[] getRowsForPaths(TreePath JavaDoc[] paths) {
436     if(paths == null)
437         return null;
438
439     int numPaths = paths.length;
440     int[] rows = new int[numPaths];
441
442     for(int counter = 0; counter < numPaths; counter++)
443         rows[counter] = getRowForPath(paths[counter]);
444     return rows;
445     }
446
447     //
448
// Local methods that subclassers may wish to use that are primarly
449
// convenience methods.
450
//
451

452     /**
453      * Returns, by reference in <code>placeIn</code>,
454      * the size needed to represent <code>value</code>.
455      * If <code>inPlace</code> is <code>null</code>, a newly created
456      * <code>Rectangle</code> should be returned, otherwise the value
457      * should be placed in <code>inPlace</code> and returned. This will
458      * return <code>null</code> if there is no renderer.
459      *
460      * @param value the <code>value</code> to be represented
461      * @param row row being queried
462      * @param depth the depth of the row
463      * @param expanded true if row is expanded, false otherwise
464      * @param placeIn a <code>Rectangle</code> containing the size needed
465      * to represent <code>value</code>
466      * @return a <code>Rectangle</code> containing the node dimensions,
467      * or <code>null</code> if node has no dimension
468      */

469     protected Rectangle JavaDoc getNodeDimensions(Object JavaDoc value, int row, int depth,
470                       boolean expanded,
471                       Rectangle JavaDoc placeIn) {
472     NodeDimensions nd = getNodeDimensions();
473
474     if(nd != null) {
475         return nd.getNodeDimensions(value, row, depth, expanded, placeIn);
476     }
477     return null;
478     }
479
480     /**
481       * Returns true if the height of each row is a fixed size.
482       */

483     protected boolean isFixedRowHeight() {
484     return (rowHeight > 0);
485     }
486
487
488     /**
489      * Used by <code>AbstractLayoutCache</code> to determine the size
490      * and x origin of a particular node.
491      */

492     static public abstract class NodeDimensions {
493     /**
494      * Returns, by reference in bounds, the size and x origin to
495      * place value at. The calling method is responsible for determining
496      * the Y location. If bounds is <code>null</code>, a newly created
497      * <code>Rectangle</code> should be returned,
498          * otherwise the value should be placed in bounds and returned.
499          *
500          * @param value the <code>value</code> to be represented
501          * @param row row being queried
502      * @param depth the depth of the row
503      * @param expanded true if row is expanded, false otherwise
504          * @param bounds a <code>Rectangle</code> containing the size needed
505          * to represent <code>value</code>
506      * @return a <code>Rectangle</code> containing the node dimensions,
507      * or <code>null</code> if node has no dimension
508      */

509     public abstract Rectangle JavaDoc getNodeDimensions(Object JavaDoc value, int row,
510                             int depth,
511                             boolean expanded,
512                             Rectangle JavaDoc bounds);
513     }
514 }
515
Popular Tags