KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > puppycrawl > tools > checkstyle > gui > JTreeTable


1 ////////////////////////////////////////////////////////////////////////////////
2
// checkstyle: Checks Java source code for adherence to a set of rules.
3
// Copyright (C) 2001-2002 Oliver Burn
4
//
5
// This library is free software; you can redistribute it and/or
6
// modify it under the terms of the GNU Lesser General Public
7
// License as published by the Free Software Foundation; either
8
// version 2.1 of the License, or (at your option) any later version.
9
//
10
// This library is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
// Lesser General Public License for more details.
14
//
15
// You should have received a copy of the GNU Lesser General Public
16
// License along with this library; if not, write to the Free Software
17
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
////////////////////////////////////////////////////////////////////////////////
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 package com.puppycrawl.tools.checkstyle.gui;
35
36 import java.awt.Component JavaDoc;
37 import java.awt.Dimension JavaDoc;
38 import java.awt.Graphics JavaDoc;
39 import java.awt.event.ActionEvent JavaDoc;
40 import java.awt.event.MouseEvent JavaDoc;
41 import java.util.EventObject JavaDoc;
42 import javax.swing.Action JavaDoc;
43 import javax.swing.AbstractAction JavaDoc;
44 import javax.swing.JTable JavaDoc;
45 import javax.swing.JTree JavaDoc;
46 import javax.swing.KeyStroke JavaDoc;
47 import javax.swing.ListSelectionModel JavaDoc;
48 import javax.swing.LookAndFeel JavaDoc;
49 import javax.swing.UIManager JavaDoc;
50 import javax.swing.event.ListSelectionEvent JavaDoc;
51 import javax.swing.event.ListSelectionListener JavaDoc;
52 import javax.swing.table.TableCellEditor JavaDoc;
53 import javax.swing.table.TableCellRenderer JavaDoc;
54 import javax.swing.tree.DefaultTreeCellRenderer JavaDoc;
55 import javax.swing.tree.DefaultTreeSelectionModel JavaDoc;
56 import javax.swing.tree.TreeCellRenderer JavaDoc;
57 import javax.swing.tree.TreeModel JavaDoc;
58 import javax.swing.tree.TreePath JavaDoc;
59
60 /**
61  * This example shows how to create a simple JTreeTable component,
62  * by using a JTree as a renderer (and editor) for the cells in a
63  * particular column in the JTable.
64  *
65  * @version 1.2 10/27/98
66  *
67  * @author Philip Milne
68  * @author Scott Violet
69  * @author Lars Kühne
70  */

71 public class JTreeTable extends JTable JavaDoc
72 {
73     /** A subclass of JTree. */
74     protected TreeTableCellRenderer tree;
75
76     public JTreeTable(TreeTableModel treeTableModel)
77     {
78         super();
79
80         // Create the tree. It will be used as a renderer and editor.
81
tree = new TreeTableCellRenderer(treeTableModel);
82
83         // Install a tableModel representing the visible rows in the tree.
84
super.setModel(new TreeTableModelAdapter(treeTableModel, tree));
85
86         // Force the JTable and JTree to share their row selection models.
87
final ListToTreeSelectionModelWrapper selectionWrapper = new
88                 ListToTreeSelectionModelWrapper();
89         tree.setSelectionModel(selectionWrapper);
90         setSelectionModel(selectionWrapper.getListSelectionModel());
91
92         // Install the tree editor renderer and editor.
93
setDefaultRenderer(TreeTableModel.class, tree);
94         setDefaultEditor(TreeTableModel.class, new TreeTableCellEditor());
95
96         // No grid.
97
setShowGrid(false);
98
99         // No intercell spacing
100
setIntercellSpacing(new Dimension JavaDoc(0, 0));
101
102         // And update the height of the trees row to match that of
103
// the table.
104
if (tree.getRowHeight() < 1) {
105             // Metal looks better like this.
106
setRowHeight(getRowHeight());
107         }
108
109         final Action JavaDoc expand = new AbstractAction JavaDoc() {
110                 public void actionPerformed(ActionEvent JavaDoc e) {
111                     TreePath JavaDoc selected = tree.getSelectionPath();
112                     if (tree.isExpanded(selected)) {
113                         tree.collapsePath(selected);
114                     }
115                     else {
116                         tree.expandPath(selected);
117                     }
118                     tree.setSelectionPath(selected);
119                 }
120             };
121         final KeyStroke JavaDoc stroke = KeyStroke.getKeyStroke("ENTER");
122         final String JavaDoc command = "expand/collapse";
123         getInputMap().put(stroke, command);
124         getActionMap().put(command, expand);
125     }
126
127     /**
128      * Overridden to message super and forward the method to the tree.
129      * Since the tree is not actually in the component hierarchy it will
130      * never receive this unless we forward it in this manner.
131      */

132     public void updateUI()
133     {
134         super.updateUI();
135         if (tree != null) {
136             tree.updateUI();
137         }
138         // Use the tree's default foreground and background colors in the
139
// table.
140
LookAndFeel.installColorsAndFont(this, "Tree.background",
141                 "Tree.foreground", "Tree.font");
142     }
143
144     /* Workaround for BasicTableUI anomaly. Make sure the UI never tries to
145      * paint the editor. The UI currently uses different techniques to
146      * paint the renderers and editors and overriding setBounds() below
147      * is not the right thing to do for an editor. Returning -1 for the
148      * editing row in this case, ensures the editor is never painted.
149      */

150     public int getEditingRow()
151     {
152         final Class JavaDoc editingClass = getColumnClass(editingColumn);
153         return (editingClass == TreeTableModel.class) ? -1 : editingRow;
154     }
155
156     /**
157      * Overridden to pass the new rowHeight to the tree.
158      */

159     public void setRowHeight(int newRowHeight)
160     {
161         super.setRowHeight(newRowHeight);
162         if ((tree != null) && (tree.getRowHeight() != newRowHeight)) {
163             tree.setRowHeight(getRowHeight());
164         }
165     }
166
167     /**
168      * @return the tree that is being shared between the model.
169      */

170     public JTree JavaDoc getTree()
171     {
172         return tree;
173     }
174
175     /**
176      * A TreeCellRenderer that displays a JTree.
177      */

178     class TreeTableCellRenderer extends JTree JavaDoc implements
179             TableCellRenderer JavaDoc
180     {
181         /** Last table/tree row asked to renderer. */
182         protected int visibleRow;
183
184         /** creates a new instance */
185         public TreeTableCellRenderer(TreeModel JavaDoc model)
186         {
187             super(model);
188         }
189
190         /**
191          * updateUI is overridden to set the colors of the Tree's renderer
192          * to match that of the table.
193          */

194         public void updateUI()
195         {
196             super.updateUI();
197             // Make the tree's cell renderer use the table's cell selection
198
// colors.
199
final TreeCellRenderer JavaDoc tcr = getCellRenderer();
200             if (tcr instanceof DefaultTreeCellRenderer JavaDoc) {
201                 final DefaultTreeCellRenderer JavaDoc dtcr = ((DefaultTreeCellRenderer JavaDoc) tcr);
202                 // For 1.1 uncomment this, 1.2 has a bug that will cause an
203
// exception to be thrown if the border selection color is
204
// null.
205
// dtcr.setBorderSelectionColor(null);
206
dtcr.setTextSelectionColor(UIManager.getColor
207                         ("Table.selectionForeground"));
208                 dtcr.setBackgroundSelectionColor(UIManager.getColor
209                         ("Table.selectionBackground"));
210             }
211         }
212
213         /**
214          * Sets the row height of the tree, and forwards the row height to
215          * the table.
216          */

217         public void setRowHeight(int newRowHeight)
218         {
219             if (newRowHeight > 0) {
220                 super.setRowHeight(newRowHeight);
221                 if ((JTreeTable.this != null) &&
222                     (JTreeTable.this.getRowHeight() != newRowHeight))
223                 {
224                     JTreeTable.this.setRowHeight(getRowHeight());
225                 }
226             }
227         }
228
229         /**
230          * This is overridden to set the height to match that of the JTable.
231          */

232         public void setBounds(int x, int y, int w, int h)
233         {
234             super.setBounds(x, 0, w, JTreeTable.this.getHeight());
235         }
236
237         /**
238          * Sublcassed to translate the graphics such that the last visible
239          * row will be drawn at 0,0.
240          */

241         public void paint(Graphics JavaDoc g)
242         {
243             g.translate(0, -visibleRow * getRowHeight());
244             super.paint(g);
245         }
246
247         /**
248          * TreeCellRenderer method. Overridden to update the visible row.
249          * @see TableCellRenderer
250          */

251         public Component JavaDoc getTableCellRendererComponent(JTable JavaDoc table,
252                 Object JavaDoc value,
253                 boolean isSelected,
254                 boolean hasFocus,
255                 int row, int column)
256         {
257             if (isSelected) {
258                 setBackground(table.getSelectionBackground());
259             } else {
260                 setBackground(table.getBackground());
261             }
262
263             visibleRow = row;
264             return this;
265         }
266     }
267
268
269     /**
270      * TreeTableCellEditor implementation. Component returned is the
271      * JTree.
272      */

273     public class TreeTableCellEditor extends AbstractCellEditor implements
274             TableCellEditor JavaDoc
275     {
276         public Component JavaDoc getTableCellEditorComponent(JTable JavaDoc table,
277                 Object JavaDoc value,
278                 boolean isSelected,
279                 int r, int c)
280         {
281             return tree;
282         }
283
284         /**
285          * Overridden to return false, and if the event is a mouse event
286          * it is forwarded to the tree.<p>
287          * The behavior for this is debatable, and should really be offered
288          * as a property. By returning false, all keyboard actions are
289          * implemented in terms of the table. By returning true, the
290          * tree would get a chance to do something with the keyboard
291          * events. For the most part this is ok. But for certain keys,
292          * such as left/right, the tree will expand/collapse where as
293          * the table focus should really move to a different column. Page
294          * up/down should also be implemented in terms of the table.
295          * By returning false this also has the added benefit that clicking
296          * outside of the bounds of the tree node, but still in the tree
297          * column will select the row, whereas if this returned true
298          * that wouldn't be the case.
299          * <p>By returning false we are also enforcing the policy that
300          * the tree will never be editable (at least by a key sequence).
301          *
302          * @see TableCellEditor
303          */

304         public boolean isCellEditable(EventObject JavaDoc e)
305         {
306             if (e instanceof MouseEvent JavaDoc) {
307                 for (int counter = getColumnCount() - 1; counter >= 0;
308                      counter--) {
309                     if (getColumnClass(counter) == TreeTableModel.class) {
310                         final MouseEvent JavaDoc me = (MouseEvent JavaDoc) e;
311                         final MouseEvent JavaDoc newME = new MouseEvent JavaDoc(tree, me.getID(),
312                                 me.getWhen(), me.getModifiers(),
313                                 me.getX() - getCellRect(0, counter, true).x,
314                                 me.getY(), me.getClickCount(),
315                                 me.isPopupTrigger());
316                         tree.dispatchEvent(newME);
317                         break;
318                     }
319                 }
320             }
321
322             return false;
323         }
324     }
325
326
327     /**
328      * ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel
329      * to listen for changes in the ListSelectionModel it maintains. Once
330      * a change in the ListSelectionModel happens, the paths are updated
331      * in the DefaultTreeSelectionModel.
332      */

333     class ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel JavaDoc
334     {
335         /** Set to true when we are updating the ListSelectionModel. */
336         protected boolean updatingListSelectionModel;
337
338         public ListToTreeSelectionModelWrapper()
339         {
340             super();
341             getListSelectionModel().addListSelectionListener
342                     (createListSelectionListener());
343         }
344
345         /**
346          * Returns the list selection model. ListToTreeSelectionModelWrapper
347          * listens for changes to this model and updates the selected paths
348          * accordingly.
349          *
350          * @return the list selection model
351          */

352         ListSelectionModel JavaDoc getListSelectionModel()
353         {
354             return listSelectionModel;
355         }
356
357         /**
358          * This is overridden to set <code>updatingListSelectionModel</code>
359          * and message super. This is the only place DefaultTreeSelectionModel
360          * alters the ListSelectionModel.
361          */

362         public void resetRowSelection()
363         {
364             if (!updatingListSelectionModel) {
365                 updatingListSelectionModel = true;
366                 try {
367                     super.resetRowSelection();
368                 } finally {
369                     updatingListSelectionModel = false;
370                 }
371             }
372             // Notice how we don't message super if
373
// updatingListSelectionModel is true. If
374
// updatingListSelectionModel is true, it implies the
375
// ListSelectionModel has already been updated and the
376
// paths are the only thing that needs to be updated.
377
}
378
379         /**
380          * Creates and returns an instance of ListSelectionHandler.
381          */

382         private ListSelectionListener JavaDoc createListSelectionListener()
383         {
384             return new ListSelectionHandler();
385         }
386
387         /**
388          * If <code>updatingListSelectionModel</code> is false, this will
389          * reset the selected paths from the selected rows in the list
390          * selection model.
391          */

392         protected void updateSelectedPathsFromSelectedRows()
393         {
394             if (!updatingListSelectionModel) {
395                 updatingListSelectionModel = true;
396                 try {
397                     // This is way expensive, ListSelectionModel needs an
398
// enumerator for iterating.
399
final int min = listSelectionModel.getMinSelectionIndex();
400                     final int max = listSelectionModel.getMaxSelectionIndex();
401
402                     clearSelection();
403                     if ((min != -1) && (max != -1)) {
404                         for (int counter = min; counter <= max; counter++) {
405                             if (listSelectionModel.isSelectedIndex(counter)) {
406                                 final TreePath JavaDoc selPath = tree.getPathForRow
407                                         (counter);
408
409                                 if (selPath != null) {
410                                     addSelectionPath(selPath);
411                                 }
412                             }
413                         }
414                     }
415                 } finally {
416                     updatingListSelectionModel = false;
417                 }
418             }
419         }
420
421         /**
422          * Class responsible for calling updateSelectedPathsFromSelectedRows
423          * when the selection of the list changse.
424          */

425         class ListSelectionHandler implements ListSelectionListener JavaDoc
426         {
427             public void valueChanged(ListSelectionEvent JavaDoc e)
428             {
429                 updateSelectedPathsFromSelectedRows();
430             }
431         }
432     }
433 }
434
Popular Tags