KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > sape > carbon > services > swing > treetable > JTreeTable


1 /*
2  * The contents of this file are subject to the Sapient Public License
3  * Version 1.0 (the "License"); you may not use this file except in compliance
4  * with the License. You may obtain a copy of the License at
5  * http://carbon.sf.net/License.html.
6  *
7  * Software distributed under the License is distributed on an "AS IS" basis,
8  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
9  * the specific language governing rights and limitations under the License.
10  *
11  * The Original Code is The Carbon Component Framework.
12  *
13  * The Initial Developer of the Original Code is Sapient Corporation
14  *
15  * Copyright (C) 2003 Sapient Corporation. All Rights Reserved.
16  */

17
18 package org.sape.carbon.services.swing.treetable;
19
20 /*
21  * @(#)JTreeTable.java 1.2 98/10/27
22  *
23  * Copyright 1997, 1998 by Sun Microsystems, Inc.,
24  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
25  * All rights reserved.
26  *
27  * This software is the confidential and proprietary information
28  * of Sun Microsystems, Inc. ("Confidential Information"). You
29  * shall not disclose such Confidential Information and shall use
30  * it only in accordance with the terms of the license agreement
31  * you entered into with Sun.
32  */

33
34 import java.awt.Component JavaDoc;
35 import java.awt.Dimension JavaDoc;
36 import java.awt.Graphics JavaDoc;
37 import java.awt.event.MouseEvent JavaDoc;
38 import java.util.EventObject JavaDoc;
39
40 import javax.swing.JTable JavaDoc;
41 import javax.swing.JTree JavaDoc;
42 import javax.swing.ListSelectionModel JavaDoc;
43 import javax.swing.LookAndFeel JavaDoc;
44 import javax.swing.UIManager JavaDoc;
45 import javax.swing.event.ListSelectionEvent JavaDoc;
46 import javax.swing.event.ListSelectionListener JavaDoc;
47 import javax.swing.table.TableCellEditor JavaDoc;
48 import javax.swing.table.TableCellRenderer JavaDoc;
49 import javax.swing.tree.DefaultTreeCellRenderer JavaDoc;
50 import javax.swing.tree.DefaultTreeSelectionModel JavaDoc;
51 import javax.swing.tree.TreeCellRenderer JavaDoc;
52 import javax.swing.tree.TreeModel JavaDoc;
53 import javax.swing.tree.TreePath JavaDoc;
54
55 /**
56  * This example shows how to create a simple JTreeTable component,
57  * by using a JTree as a renderer (and editor) for the cells in a
58  * particular column in the JTable.
59  *
60  * @version 1.2 10/27/98
61  *
62  * @author Philip Milne
63  * @author Scott Violet
64  */

65 public class JTreeTable extends JTable JavaDoc {
66     /** A subclass of JTree. */
67     protected TreeTableCellRenderer tree;
68
69     public JTreeTable(TreeTableModel treeTableModel) {
70     super();
71
72     // Create the tree. It will be used as a renderer and editor.
73
tree = new TreeTableCellRenderer(treeTableModel);
74
75     // Install a tableModel representing the visible rows in the tree.
76
super.setModel(new TreeTableModelAdapter(treeTableModel, tree));
77
78     // Force the JTable and JTree to share their row selection models.
79
ListToTreeSelectionModelWrapper selectionWrapper = new
80                             ListToTreeSelectionModelWrapper();
81     tree.setSelectionModel(selectionWrapper);
82     setSelectionModel(selectionWrapper.getListSelectionModel());
83
84     // Install the tree editor renderer and editor.
85
setDefaultRenderer(TreeTableModel.class, tree);
86     setDefaultEditor(TreeTableModel.class, new TreeTableCellEditor());
87
88     // No grid.
89
setShowGrid(false);
90
91     // No intercell spacing
92
setIntercellSpacing(new Dimension JavaDoc(0, 0));
93
94     // And update the height of the trees row to match that of
95
// the table.
96
if (tree.getRowHeight() < 1) {
97         // Metal looks better like this.
98
setRowHeight(18);
99     }
100     }
101
102     /**
103      * Overridden to message super and forward the method to the tree.
104      * Since the tree is not actually in the component hieachy it will
105      * never receive this unless we forward it in this manner.
106      */

107     public void updateUI() {
108     super.updateUI();
109     if(tree != null) {
110         tree.updateUI();
111     }
112     // Use the tree's default foreground and background colors in the
113
// table.
114
LookAndFeel.installColorsAndFont(this, "Tree.background",
115                                          "Tree.foreground", "Tree.font");
116     }
117
118     /* Workaround for BasicTableUI anomaly. Make sure the UI never tries to
119      * paint the editor. The UI currently uses different techniques to
120      * paint the renderers and editors and overriding setBounds() below
121      * is not the right thing to do for an editor. Returning -1 for the
122      * editing row in this case, ensures the editor is never painted.
123      */

124     public int getEditingRow() {
125         return (getColumnClass(editingColumn) == TreeTableModel.class) ? -1 :
126             editingRow;
127     }
128
129     /**
130      * Overridden to pass the new rowHeight to the tree.
131      */

132     public void setRowHeight(int rowHeight) {
133         super.setRowHeight(rowHeight);
134     if (tree != null && tree.getRowHeight() != rowHeight) {
135             tree.setRowHeight(getRowHeight());
136     }
137     }
138
139     /**
140      * Returns the tree that is being shared between the model.
141      */

142     public JTree JavaDoc getTree() {
143     return tree;
144     }
145
146     /**
147      * A TreeCellRenderer that displays a JTree.
148      */

149     public class TreeTableCellRenderer extends JTree JavaDoc implements
150              TableCellRenderer JavaDoc {
151     /** Last table/tree row asked to renderer. */
152     protected int visibleRow;
153
154     public TreeTableCellRenderer(TreeModel JavaDoc model) {
155         super(model);
156     }
157
158     /**
159      * updateUI is overridden to set the colors of the Tree's renderer
160      * to match that of the table.
161      */

162     public void updateUI() {
163         super.updateUI();
164         // Make the tree's cell renderer use the table's cell selection
165
// colors.
166
TreeCellRenderer JavaDoc tcr = getCellRenderer();
167         if (tcr instanceof DefaultTreeCellRenderer JavaDoc) {
168         DefaultTreeCellRenderer JavaDoc dtcr = ((DefaultTreeCellRenderer JavaDoc)tcr);
169         // For 1.1 uncomment this, 1.2 has a bug that will cause an
170
// exception to be thrown if the border selection color is
171
// null.
172
// dtcr.setBorderSelectionColor(null);
173
dtcr.setTextSelectionColor(UIManager.getColor
174                        ("Table.selectionForeground"));
175         dtcr.setBackgroundSelectionColor(UIManager.getColor
176                         ("Table.selectionBackground"));
177         }
178     }
179
180     /**
181      * Sets the row height of the tree, and forwards the row height to
182      * the table.
183      */

184     public void setRowHeight(int rowHeight) {
185         if (rowHeight > 0) {
186         super.setRowHeight(rowHeight);
187         if (JTreeTable.this != null &&
188             JTreeTable.this.getRowHeight() != rowHeight) {
189             JTreeTable.this.setRowHeight(getRowHeight());
190         }
191         }
192     }
193
194     /**
195      * This is overridden to set the height to match that of the JTable.
196      */

197     public void setBounds(int x, int y, int w, int h) {
198         super.setBounds(x, 0, w, JTreeTable.this.getHeight());
199     }
200
201     /**
202      * Sublcassed to translate the graphics such that the last visible
203      * row will be drawn at 0,0.
204      */

205     public void paint(Graphics JavaDoc g) {
206         g.translate(0, -visibleRow * getRowHeight());
207         super.paint(g);
208     }
209
210     /**
211      * TreeCellRenderer method. Overridden to update the visible row.
212      */

213     public Component JavaDoc getTableCellRendererComponent(JTable JavaDoc table,
214                                Object JavaDoc value,
215                                boolean isSelected,
216                                boolean hasFocus,
217                                int row, int column) {
218         if(isSelected)
219         setBackground(table.getSelectionBackground());
220         else
221         setBackground(table.getBackground());
222
223         visibleRow = row;
224         return this;
225     }
226     }
227
228
229     /**
230      * TreeTableCellEditor implementation. Component returned is the
231      * JTree.
232      */

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

260     public boolean isCellEditable(EventObject JavaDoc e) {
261         if (e instanceof MouseEvent JavaDoc) {
262         for (int counter = getColumnCount() - 1; counter >= 0;
263              counter--) {
264             if (getColumnClass(counter) == TreeTableModel.class) {
265             MouseEvent JavaDoc me = (MouseEvent JavaDoc)e;
266             MouseEvent JavaDoc newME = new MouseEvent JavaDoc(tree, me.getID(),
267                    me.getWhen(), me.getModifiers(),
268                    me.getX() - getCellRect(0, counter, true).x,
269                    me.getY(), me.getClickCount(),
270                                    me.isPopupTrigger());
271             tree.dispatchEvent(newME);
272             break;
273             }
274         }
275         }
276         return false;
277     }
278     }
279
280
281     /**
282      * ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel
283      * to listen for changes in the ListSelectionModel it maintains. Once
284      * a change in the ListSelectionModel happens, the paths are updated
285      * in the DefaultTreeSelectionModel.
286      */

287     class ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel JavaDoc {
288     /** Set to true when we are updating the ListSelectionModel. */
289     protected boolean updatingListSelectionModel;
290
291     public ListToTreeSelectionModelWrapper() {
292         super();
293         getListSelectionModel().addListSelectionListener
294                                 (createListSelectionListener());
295     }
296
297     /**
298      * Returns the list selection model. ListToTreeSelectionModelWrapper
299      * listens for changes to this model and updates the selected paths
300      * accordingly.
301      */

302     ListSelectionModel JavaDoc getListSelectionModel() {
303         return listSelectionModel;
304     }
305
306     /**
307      * This is overridden to set <code>updatingListSelectionModel</code>
308      * and message super. This is the only place DefaultTreeSelectionModel
309      * alters the ListSelectionModel.
310      */

311     public void resetRowSelection() {
312         if(!updatingListSelectionModel) {
313         updatingListSelectionModel = true;
314         try {
315             super.resetRowSelection();
316         }
317         finally {
318             updatingListSelectionModel = false;
319         }
320         }
321         // Notice how we don't message super if
322
// updatingListSelectionModel is true. If
323
// updatingListSelectionModel is true, it implies the
324
// ListSelectionModel has already been updated and the
325
// paths are the only thing that needs to be updated.
326
}
327
328     /**
329      * Creates and returns an instance of ListSelectionHandler.
330      */

331     protected ListSelectionListener JavaDoc createListSelectionListener() {
332         return new ListSelectionHandler();
333     }
334
335     /**
336      * If <code>updatingListSelectionModel</code> is false, this will
337      * reset the selected paths from the selected rows in the list
338      * selection model.
339      */

340     protected void updateSelectedPathsFromSelectedRows() {
341         if(!updatingListSelectionModel) {
342         updatingListSelectionModel = true;
343         try {
344             // This is way expensive, ListSelectionModel needs an
345
// enumerator for iterating.
346
int min = listSelectionModel.getMinSelectionIndex();
347             int max = listSelectionModel.getMaxSelectionIndex();
348
349             clearSelection();
350             if(min != -1 && max != -1) {
351             for(int counter = min; counter <= max; counter++) {
352                 if(listSelectionModel.isSelectedIndex(counter)) {
353                 TreePath JavaDoc selPath = tree.getPathForRow
354                                             (counter);
355
356                 if(selPath != null) {
357                     addSelectionPath(selPath);
358                 }
359                 }
360             }
361             }
362         }
363         finally {
364             updatingListSelectionModel = false;
365         }
366         }
367     }
368
369     /**
370      * Class responsible for calling updateSelectedPathsFromSelectedRows
371      * when the selection of the list changse.
372      */

373     class ListSelectionHandler implements ListSelectionListener JavaDoc {
374         public void valueChanged(ListSelectionEvent JavaDoc e) {
375         updateSelectedPathsFromSelectedRows();
376         }
377     }
378     }
379 }
380
Popular Tags