KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mc4j > console > swing > treetable > JTreeTableOrig


1 package org.mc4j.console.swing.treetable;
2
3 /*
4  * @(#)JTreeTable.java 1.2 98/10/27
5  *
6  * Copyright 1997, 1998 by Sun Microsystems, Inc.,
7  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
8  * All rights reserved.
9  *
10  * This software is the confidential and proprietary information
11  * of Sun Microsystems, Inc. ("Confidential Information"). You
12  * shall not disclose such Confidential Information and shall use
13  * it only in accordance with the terms of the license agreement
14  * you entered into with Sun.
15  */

16
17 import java.awt.Component JavaDoc;
18 import java.awt.Dimension JavaDoc;
19 import java.awt.Graphics JavaDoc;
20 import java.awt.event.MouseEvent JavaDoc;
21 import java.util.EventObject JavaDoc;
22
23 import javax.swing.JTable JavaDoc;
24 import javax.swing.JTree JavaDoc;
25 import javax.swing.ListSelectionModel JavaDoc;
26 import javax.swing.LookAndFeel JavaDoc;
27 import javax.swing.UIManager JavaDoc;
28 import javax.swing.event.ListSelectionEvent JavaDoc;
29 import javax.swing.event.ListSelectionListener JavaDoc;
30 import javax.swing.table.TableCellEditor JavaDoc;
31 import javax.swing.table.TableCellRenderer JavaDoc;
32 import javax.swing.tree.DefaultTreeCellRenderer JavaDoc;
33 import javax.swing.tree.DefaultTreeSelectionModel JavaDoc;
34 import javax.swing.tree.TreeCellRenderer JavaDoc;
35 import javax.swing.tree.TreeModel JavaDoc;
36 import javax.swing.tree.TreePath JavaDoc;
37
38 /**
39  * This example shows how to create a simple JTreeTable component,
40  * by using a JTree as a renderer (and editor) for the cells in a
41  * particular column in the JTable.
42  *
43  * @author Philip Milne
44  * @author Scott Violet
45  * @version 1.2 10/27/98
46  */

47 public class JTreeTableOrig extends JTable JavaDoc {
48     /**
49      * A subclass of JTree.
50      */

51     protected TreeTableCellRenderer tree;
52
53     public JTreeTableOrig(TreeTableModel treeTableModel) {
54         super();
55
56         // Create the tree. It will be used as a renderer and editor.
57
tree = new TreeTableCellRenderer(this, treeTableModel);
58
59         // Install a tableModel representing the visible rows in the tree.
60
super.setModel(new TreeTableModelAdapter(treeTableModel, tree));
61
62         // Force the JTable and JTree to share their row selection models.
63
ListToTreeSelectionModelWrapper selectionWrapper = new
64             ListToTreeSelectionModelWrapper();
65         tree.setSelectionModel(selectionWrapper);
66         setSelectionModel(selectionWrapper.getListSelectionModel());
67
68         // Install the tree editor renderer and editor.
69
setDefaultRenderer(TreeTableModel.class, tree);
70         setDefaultEditor(TreeTableModel.class, new TreeTableCellEditor());
71
72         // No grid.
73
setShowGrid(false);
74
75         // No intercell spacing
76
setIntercellSpacing(new Dimension JavaDoc(0, 0));
77
78         // And update the height of the trees row to match that of
79
// the table.
80
if (tree.getRowHeight() < 1) {
81             // Metal looks better like this.
82
setRowHeight(18);
83         }
84     }
85
86     /**
87      * Overridden to message super and forward the method to the tree.
88      * Since the tree is not actually in the component hieachy it will
89      * never receive this unless we forward it in this manner.
90      */

91     public void updateUI() {
92         super.updateUI();
93         if (tree != null) {
94             tree.updateUI();
95         }
96         // Use the tree's default foreground and background colors in the
97
// table.
98
LookAndFeel.installColorsAndFont(this, "Tree.background",
99             "Tree.foreground", "Tree.font");
100     }
101
102     /* Workaround for BasicTableUI anomaly. Make sure the UI never tries to
103      * paint the editor. The UI currently uses different techniques to
104      * paint the renderers and editors and overriding setBounds() below
105      * is not the right thing to do for an editor. Returning -1 for the
106      * editing row in this case, ensures the editor is never painted.
107      */

108     public int getEditingRow() {
109         return (getColumnClass(editingColumn) == TreeTableModel.class) ? -1 :
110             editingRow;
111     }
112
113     /**
114      * Overridden to pass the new rowHeight to the tree.
115      */

116     public void setRowHeight(int rowHeight) {
117         super.setRowHeight(rowHeight);
118         if (tree != null && tree.getRowHeight() != rowHeight) {
119             tree.setRowHeight(getRowHeight());
120         }
121     }
122
123     /**
124      * Returns the tree that is being shared between the model.
125      */

126     public JTree JavaDoc getTree() {
127         return tree;
128     }
129
130     /**
131      * A TreeCellRenderer that displays a JTree.
132      */

133     public static class TreeTableCellRenderer extends JTree JavaDoc implements TableCellRenderer JavaDoc {
134
135         /**
136          * Last table/tree row asked to renderer.
137          */

138         protected int visibleRow;
139
140         protected JTreeTableOrig treeTable;
141
142         public TreeTableCellRenderer(JTreeTableOrig treeTable, TreeModel JavaDoc model) {
143             super(model);
144             this.treeTable = treeTable;
145         }
146
147         /**
148          * updateUI is overridden to set the colors of the Tree's renderer
149          * to match that of the table.
150          */

151         public void updateUI() {
152             super.updateUI();
153             // Make the tree's cell renderer use the table's cell selection
154
// colors.
155
TreeCellRenderer JavaDoc tcr = getCellRenderer();
156             if (tcr instanceof DefaultTreeCellRenderer JavaDoc) {
157                 DefaultTreeCellRenderer JavaDoc dtcr = ((DefaultTreeCellRenderer JavaDoc) tcr);
158                 // For 1.1 uncomment this, 1.2 has a bug that will cause an
159
// exception to be thrown if the border selection color is
160
// null.
161
// dtcr.setBorderSelectionColor(null);
162
dtcr.setTextSelectionColor(UIManager.getColor
163                     ("Table.selectionForeground"));
164                 dtcr.setBackgroundSelectionColor(UIManager.getColor
165                     ("Table.selectionBackground"));
166             }
167         }
168
169         /**
170          * Sets the row height of the tree, and forwards the row height to
171          * the table.
172          */

173         public void setRowHeight(int rowHeight) {
174             if (rowHeight > 0) {
175                 super.setRowHeight(rowHeight);
176                 if (this.treeTable != null &&
177                     treeTable.getRowHeight() != rowHeight) {
178                     treeTable.setRowHeight(getRowHeight());
179                 }
180             }
181         }
182
183         /**
184          * This is overridden to set the height to match that of the JTable.
185          */

186         public void setBounds(int x, int y, int w, int h) {
187             super.setBounds(x, 0, w, treeTable.getHeight());
188         }
189
190         /**
191          * Sublcassed to translate the graphics such that the last visible
192          * row will be drawn at 0,0.
193          */

194         public void paint(Graphics JavaDoc g) {
195             g.translate(0, -visibleRow * getRowHeight());
196             super.paint(g);
197         }
198
199         /**
200          * TreeCellRenderer method. Overridden to update the visible row.
201          */

202         public Component JavaDoc getTableCellRendererComponent(JTable JavaDoc table,
203                                                        Object JavaDoc value,
204                                                        boolean isSelected,
205                                                        boolean hasFocus,
206                                                        int row, int column) {
207             if (isSelected)
208                 setBackground(table.getSelectionBackground());
209             else
210                 setBackground(table.getBackground());
211
212             visibleRow = row;
213             return this;
214         }
215     }
216
217
218     /**
219      * TreeTableCellEditor implementation. Component returned is the
220      * JTree.
221      */

222     public class TreeTableCellEditor extends AbstractCellEditor implements
223         TableCellEditor JavaDoc {
224         public Component JavaDoc getTableCellEditorComponent(JTable JavaDoc table,
225                                                      Object JavaDoc value,
226                                                      boolean isSelected,
227                                                      int r, int c) {
228             return tree;
229         }
230
231         /**
232          * Overridden to return false, and if the event is a mouse event
233          * it is forwarded to the tree.<p>
234          * The behavior for this is debatable, and should really be offered
235          * as a property. By returning false, all keyboard actions are
236          * implemented in terms of the table. By returning true, the
237          * tree would get a chance to do something with the keyboard
238          * events. For the most part this is ok. But for certain keys,
239          * such as left/right, the tree will expand/collapse where as
240          * the table focus should really move to a different column. Page
241          * up/down should also be implemented in terms of the table.
242          * By returning false this also has the added benefit that clicking
243          * outside of the bounds of the tree node, but still in the tree
244          * column will select the row, whereas if this returned true
245          * that wouldn't be the case.
246          * <p>By returning false we are also enforcing the policy that
247          * the tree will never be editable (at least by a key sequence).
248          */

249         public boolean isCellEditable(EventObject JavaDoc e) {
250             if (e instanceof MouseEvent JavaDoc) {
251                 for (int counter = getColumnCount() - 1; counter >= 0;
252                      counter--) {
253                     if (getColumnClass(counter) == TreeTableModel.class) {
254                         MouseEvent JavaDoc me = (MouseEvent JavaDoc) e;
255                         MouseEvent JavaDoc newME = new MouseEvent JavaDoc(tree, me.getID(),
256                             me.getWhen(), me.getModifiers(),
257                             me.getX() - getCellRect(0, counter, true).x,
258                             me.getY(), me.getClickCount(),
259                             me.isPopupTrigger());
260                         tree.dispatchEvent(newME);
261                         break;
262                     }
263                 }
264             }
265             return false;
266         }
267     }
268
269
270     /**
271      * ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel
272      * to listen for changes in the ListSelectionModel it maintains. Once
273      * a change in the ListSelectionModel happens, the paths are updated
274      * in the DefaultTreeSelectionModel.
275      */

276     class ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel JavaDoc {
277         /**
278          * Set to true when we are updating the ListSelectionModel.
279          */

280         protected boolean updatingListSelectionModel;
281
282         public ListToTreeSelectionModelWrapper() {
283             super();
284             getListSelectionModel().addListSelectionListener
285                 (createListSelectionListener());
286         }
287
288         /**
289          * Returns the list selection model. ListToTreeSelectionModelWrapper
290          * listens for changes to this model and updates the selected paths
291          * accordingly.
292          */

293         ListSelectionModel JavaDoc getListSelectionModel() {
294             return listSelectionModel;
295         }
296
297         /**
298          * This is overridden to set <code>updatingListSelectionModel</code>
299          * and message super. This is the only place DefaultTreeSelectionModel
300          * alters the ListSelectionModel.
301          */

302         public void resetRowSelection() {
303             if (!updatingListSelectionModel) {
304                 updatingListSelectionModel = true;
305                 try {
306                     super.resetRowSelection();
307                 } finally {
308                     updatingListSelectionModel = false;
309                 }
310             }
311             // Notice how we don't message super if
312
// updatingListSelectionModel is true. If
313
// updatingListSelectionModel is true, it implies the
314
// ListSelectionModel has already been updated and the
315
// paths are the only thing that needs to be updated.
316
}
317
318         /**
319          * Creates and returns an instance of ListSelectionHandler.
320          */

321         protected ListSelectionListener JavaDoc createListSelectionListener() {
322             return new ListSelectionHandler();
323         }
324
325         /**
326          * If <code>updatingListSelectionModel</code> is false, this will
327          * reset the selected paths from the selected rows in the list
328          * selection model.
329          */

330         protected void updateSelectedPathsFromSelectedRows() {
331             if (!updatingListSelectionModel) {
332                 updatingListSelectionModel = true;
333                 try {
334                     // This is way expensive, ListSelectionModel needs an
335
// enumerator for iterating.
336
int min = listSelectionModel.getMinSelectionIndex();
337                     int max = listSelectionModel.getMaxSelectionIndex();
338
339                     clearSelection();
340                     if (min != -1 && max != -1) {
341                         for (int counter = min; counter <= max; counter++) {
342                             if (listSelectionModel.isSelectedIndex(counter)) {
343                                 TreePath JavaDoc selPath = tree.getPathForRow
344                                     (counter);
345
346                                 if (selPath != null) {
347                                     addSelectionPath(selPath);
348                                 }
349                             }
350                         }
351                     }
352                 } finally {
353                     updatingListSelectionModel = false;
354                 }
355             }
356         }
357
358         /**
359          * Class responsible for calling updateSelectedPathsFromSelectedRows
360          * when the selection of the list changse.
361          */

362         class ListSelectionHandler implements ListSelectionListener JavaDoc {
363             public void valueChanged(ListSelectionEvent JavaDoc e) {
364                 updateSelectedPathsFromSelectedRows();
365             }
366         }
367     }
368 }
369
Popular Tags