source: src/main/java/genius/core/jtreetable/JTreeTable.java

Last change on this file was 1, checked in by Wouter Pasman, 7 years ago

Initial import : Genius 9.0.0

File size: 10.7 KB
Line 
1package genius.core.jtreetable;
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
17import javax.swing.*;
18import javax.swing.event.*;
19import javax.swing.tree.*;
20import javax.swing.table.*;
21
22import java.awt.Dimension;
23import java.awt.Component;
24import java.awt.Graphics;
25import java.awt.Rectangle;
26
27import java.awt.event.MouseEvent;
28
29import java.util.EventObject;
30
31/**
32 * This example shows how to create a simple JTreeTable component,
33 * by using a JTree as a renderer (and editor) for the cells in a
34 * particular column in the JTable.
35 *
36 * @version 1.2 10/27/98
37 *
38 * @author Philip Milne
39 * @author Scott Violet
40 */
41public class JTreeTable extends JTable {
42 /** A subclass of JTree. */
43 protected TreeTableCellRenderer tree;
44
45 public JTreeTable(TreeTableModel treeTableModel) {
46 super();
47
48 // Create the tree. It will be used as a renderer and editor.
49 tree = new TreeTableCellRenderer(treeTableModel);
50
51 // Install a tableModel representing the visible rows in the tree.
52 super.setModel(new TreeTableModelAdapter(treeTableModel, tree));
53
54 // Force the JTable and JTree to share their row selection models.
55 ListToTreeSelectionModelWrapper selectionWrapper = new
56 ListToTreeSelectionModelWrapper();
57 tree.setSelectionModel(selectionWrapper);
58 setSelectionModel(selectionWrapper.getListSelectionModel());
59
60 // Install the tree editor renderer and editor.
61 setDefaultRenderer(TreeTableModel.class, tree);
62 setDefaultEditor(TreeTableModel.class, new TreeTableCellEditor());
63
64 // No grid.
65 setShowGrid(false);
66
67 // No intercell spacing
68 setIntercellSpacing(new Dimension(0, 0));
69
70 // And update the height of the trees row to match that of
71 // the table.
72 if (tree.getRowHeight() < 1) {
73 // Metal looks better like this.
74 setRowHeight(18);
75 }
76 }
77
78 /**
79 * Overridden to message super and forward the method to the tree.
80 * Since the tree is not actually in the component hieachy it will
81 * never receive this unless we forward it in this manner.
82 */
83 public void updateUI() {
84 super.updateUI();
85 if(tree != null) {
86 tree.updateUI();
87 }
88 // Use the tree's default foreground and background colors in the
89 // table.
90 LookAndFeel.installColorsAndFont(this, "Tree.background",
91 "Tree.foreground", "Tree.font");
92 }
93
94 /* Workaround for BasicTableUI anomaly. Make sure the UI never tries to
95 * paint the editor. The UI currently uses different techniques to
96 * paint the renderers and editors and overriding setBounds() below
97 * is not the right thing to do for an editor. Returning -1 for the
98 * editing row in this case, ensures the editor is never painted.
99 */
100 public int getEditingRow() {
101 return (getColumnClass(editingColumn) == TreeTableModel.class) ? -1 :
102 editingRow;
103 }
104
105 /**
106 * Overridden to pass the new rowHeight to the tree.
107 */
108 public void setRowHeight(int rowHeight) {
109 super.setRowHeight(rowHeight);
110 if (tree != null && tree.getRowHeight() != rowHeight) {
111 tree.setRowHeight(getRowHeight());
112 }
113 }
114
115 /**
116 * Returns the tree that is being shared between the model.
117 */
118 public JTree getTree() {
119 return tree;
120 }
121
122 /**
123 * A TreeCellRenderer that displays a JTree.
124 */
125 public class TreeTableCellRenderer extends JTree implements
126 TableCellRenderer {
127 /** Last table/tree row asked to renderer. */
128 protected int visibleRow;
129
130 public TreeTableCellRenderer(TreeModel model) {
131 super(model);
132 }
133
134 /**
135 * updateUI is overridden to set the colors of the Tree's renderer
136 * to match that of the table.
137 */
138 public void updateUI() {
139 super.updateUI();
140 // Make the tree's cell renderer use the table's cell selection
141 // colors.
142 TreeCellRenderer tcr = getCellRenderer();
143 if (tcr instanceof DefaultTreeCellRenderer) {
144 DefaultTreeCellRenderer dtcr = ((DefaultTreeCellRenderer)tcr);
145 // For 1.1 uncomment this, 1.2 has a bug that will cause an
146 // exception to be thrown if the border selection color is
147 // null.
148 // dtcr.setBorderSelectionColor(null);
149 dtcr.setTextSelectionColor(UIManager.getColor
150 ("Table.selectionForeground"));
151 dtcr.setBackgroundSelectionColor(UIManager.getColor
152 ("Table.selectionBackground"));
153 }
154 }
155
156 /**
157 * Sets the row height of the tree, and forwards the row height to
158 * the table.
159 */
160 public void setRowHeight(int rowHeight) {
161 if (rowHeight > 0) {
162 super.setRowHeight(rowHeight);
163 if (JTreeTable.this != null &&
164 JTreeTable.this.getRowHeight() != rowHeight) {
165 JTreeTable.this.setRowHeight(getRowHeight());
166 }
167 }
168 }
169
170 /**
171 * This is overridden to set the height to match that of the JTable.
172 */
173 public void setBounds(int x, int y, int w, int h) {
174 super.setBounds(x, 0, w, JTreeTable.this.getHeight());
175 }
176
177 /**
178 * Sublcassed to translate the graphics such that the last visible
179 * row will be drawn at 0,0.
180 */
181 public void paint(Graphics g) {
182 g.translate(0, -visibleRow * getRowHeight());
183 super.paint(g);
184 }
185
186 /**
187 * TreeCellRenderer method. Overridden to update the visible row.
188 */
189 public Component getTableCellRendererComponent(JTable table,
190 Object value,
191 boolean isSelected,
192 boolean hasFocus,
193 int row, int column) {
194 if(isSelected)
195 setBackground(table.getSelectionBackground());
196 else
197 setBackground(table.getBackground());
198
199 visibleRow = row;
200 return this;
201 }
202 }
203
204
205 /**
206 * TreeTableCellEditor implementation. Component returned is the
207 * JTree.
208 */
209 public class TreeTableCellEditor extends AbstractCellEditor implements
210 TableCellEditor {
211 public Component getTableCellEditorComponent(JTable table,
212 Object value,
213 boolean isSelected,
214 int r, int c) {
215 return tree;
216 }
217
218 /**
219 * Overridden to return false, and if the event is a mouse event
220 * it is forwarded to the tree.<p>
221 * The behavior for this is debatable, and should really be offered
222 * as a property. By returning false, all keyboard actions are
223 * implemented in terms of the table. By returning true, the
224 * tree would get a chance to do something with the keyboard
225 * events. For the most part this is ok. But for certain keys,
226 * such as left/right, the tree will expand/collapse where as
227 * the table focus should really move to a different column. Page
228 * up/down should also be implemented in terms of the table.
229 * By returning false this also has the added benefit that clicking
230 * outside of the bounds of the tree node, but still in the tree
231 * column will select the row, whereas if this returned true
232 * that wouldn't be the case.
233 * <p>By returning false we are also enforcing the policy that
234 * the tree will never be editable (at least by a key sequence).
235 */
236 public boolean isCellEditable(EventObject e) {
237 if (e instanceof MouseEvent) {
238 for (int counter = getColumnCount() - 1; counter >= 0;
239 counter--) {
240 if (getColumnClass(counter) == TreeTableModel.class) {
241 MouseEvent me = (MouseEvent)e;
242 MouseEvent newME = new MouseEvent(tree, me.getID(),
243 me.getWhen(), me.getModifiers(),
244 me.getX() - getCellRect(0, counter, true).x,
245 me.getY(), me.getClickCount(),
246 me.isPopupTrigger());
247 tree.dispatchEvent(newME);
248 break;
249 }
250 }
251 }
252 return false;
253 }
254 }
255
256
257 /**
258 * ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel
259 * to listen for changes in the ListSelectionModel it maintains. Once
260 * a change in the ListSelectionModel happens, the paths are updated
261 * in the DefaultTreeSelectionModel.
262 */
263 class ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel {
264 /** Set to true when we are updating the ListSelectionModel. */
265 protected boolean updatingListSelectionModel;
266
267 public ListToTreeSelectionModelWrapper() {
268 super();
269 getListSelectionModel().addListSelectionListener
270 (createListSelectionListener());
271 }
272
273 /**
274 * Returns the list selection model. ListToTreeSelectionModelWrapper
275 * listens for changes to this model and updates the selected paths
276 * accordingly.
277 */
278 ListSelectionModel getListSelectionModel() {
279 return listSelectionModel;
280 }
281
282 /**
283 * This is overridden to set <code>updatingListSelectionModel</code>
284 * and message super. This is the only place DefaultTreeSelectionModel
285 * alters the ListSelectionModel.
286 */
287 public void resetRowSelection() {
288 if(!updatingListSelectionModel) {
289 updatingListSelectionModel = true;
290 try {
291 super.resetRowSelection();
292 }
293 finally {
294 updatingListSelectionModel = false;
295 }
296 }
297 // Notice how we don't message super if
298 // updatingListSelectionModel is true. If
299 // updatingListSelectionModel is true, it implies the
300 // ListSelectionModel has already been updated and the
301 // paths are the only thing that needs to be updated.
302 }
303
304 /**
305 * Creates and returns an instance of ListSelectionHandler.
306 */
307 protected ListSelectionListener createListSelectionListener() {
308 return new ListSelectionHandler();
309 }
310
311 /**
312 * If <code>updatingListSelectionModel</code> is false, this will
313 * reset the selected paths from the selected rows in the list
314 * selection model.
315 */
316 protected void updateSelectedPathsFromSelectedRows() {
317 if(!updatingListSelectionModel) {
318 updatingListSelectionModel = true;
319 try {
320 // This is way expensive, ListSelectionModel needs an
321 // enumerator for iterating.
322 int min = listSelectionModel.getMinSelectionIndex();
323 int max = listSelectionModel.getMaxSelectionIndex();
324
325 clearSelection();
326 if(min != -1 && max != -1) {
327 for(int counter = min; counter <= max; counter++) {
328 if(listSelectionModel.isSelectedIndex(counter)) {
329 TreePath selPath = tree.getPathForRow
330 (counter);
331
332 if(selPath != null) {
333 addSelectionPath(selPath);
334 }
335 }
336 }
337 }
338 }
339 finally {
340 updatingListSelectionModel = false;
341 }
342 }
343 }
344
345 /**
346 * Class responsible for calling updateSelectedPathsFromSelectedRows
347 * when the selection of the list changse.
348 */
349 class ListSelectionHandler implements ListSelectionListener {
350 public void valueChanged(ListSelectionEvent e) {
351 updateSelectedPathsFromSelectedRows();
352 }
353 }
354 }
355}
Note: See TracBrowser for help on using the repository browser.