0
|
1 /*
|
|
2 * Copyright 2001 Sun Microsystems, Inc. All Rights Reserved.
|
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
4 *
|
|
5 * This code is free software; you can redistribute it and/or modify it
|
|
6 * under the terms of the GNU General Public License version 2 only, as
|
|
7 * published by the Free Software Foundation.
|
|
8 *
|
|
9 * This code is distributed in the hope that it will be useful, but WITHOUT
|
|
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
12 * version 2 for more details (a copy is included in the LICENSE file that
|
|
13 * accompanied this code).
|
|
14 *
|
|
15 * You should have received a copy of the GNU General Public License version
|
|
16 * 2 along with this work; if not, write to the Free Software Foundation,
|
|
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
18 *
|
|
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
|
20 * CA 95054 USA or visit www.sun.com if you need additional information or
|
|
21 * have any questions.
|
|
22 *
|
|
23 */
|
|
24
|
|
25 package sun.jvm.hotspot.ui.treetable;
|
|
26
|
|
27 import java.awt.*;
|
|
28
|
|
29 import javax.swing.*;
|
|
30 import javax.swing.border.*;
|
|
31 import javax.swing.event.*;
|
|
32 import javax.swing.tree.*;
|
|
33 import javax.swing.table.*;
|
|
34
|
|
35 import java.awt.event.*;
|
|
36
|
|
37 import java.util.EventObject;
|
|
38
|
|
39 /**
|
|
40 * This example shows how to create a simple JTreeTable component,
|
|
41 * by using a JTree as a renderer (and editor) for the cells in a
|
|
42 * particular column in the JTable.
|
|
43 *
|
|
44 *
|
|
45 * @author Philip Milne
|
|
46 * @author Scott Violet
|
|
47 */
|
|
48 public class JTreeTable extends JTable {
|
|
49 /** A subclass of JTree. */
|
|
50 protected TreeTableCellRenderer tree;
|
|
51
|
|
52 //////////////////////////
|
|
53 // Convenience routines //
|
|
54 //////////////////////////
|
|
55
|
|
56 private boolean treeEditable = true;
|
|
57 private boolean showsIcons = true;
|
|
58
|
|
59 public boolean getTreeEditable() {
|
|
60 return treeEditable;
|
|
61 }
|
|
62
|
|
63 public void setTreeEditable(boolean editable) {
|
|
64 treeEditable = editable;
|
|
65 }
|
|
66
|
|
67 public boolean getShowsIcons() {
|
|
68 return showsIcons;
|
|
69 }
|
|
70
|
|
71 public void setShowsIcons(boolean show) {
|
|
72 showsIcons = show;
|
|
73 }
|
|
74
|
|
75 public void setRootVisible(boolean visible) {
|
|
76 tree.setRootVisible(visible);
|
|
77 }
|
|
78
|
|
79 public boolean getShowsRootHandles() {
|
|
80 return tree.getShowsRootHandles();
|
|
81 }
|
|
82
|
|
83 public void setShowsRootHandles(boolean newValue) {
|
|
84 tree.setShowsRootHandles(newValue);
|
|
85 }
|
|
86
|
|
87 public JTreeTable(TreeTableModel treeTableModel) {
|
|
88 super();
|
|
89
|
|
90 // Create the tree. It will be used as a renderer and editor.
|
|
91 tree = new TreeTableCellRenderer(treeTableModel);
|
|
92
|
|
93 // Install a tableModel representing the visible rows in the tree.
|
|
94 super.setModel(new TreeTableModelAdapter(treeTableModel, tree));
|
|
95
|
|
96 // Force the JTable and JTree to share their row selection models.
|
|
97 ListToTreeSelectionModelWrapper selectionWrapper = new
|
|
98 ListToTreeSelectionModelWrapper();
|
|
99 tree.setSelectionModel(selectionWrapper);
|
|
100 setSelectionModel(selectionWrapper.getListSelectionModel());
|
|
101
|
|
102 // Install the tree editor renderer and editor.
|
|
103 setDefaultRenderer(TreeTableModel.class, tree);
|
|
104 setDefaultEditor(TreeTableModel.class, new TreeTableCellEditor());
|
|
105
|
|
106 // No grid.
|
|
107 setShowGrid(false);
|
|
108
|
|
109 // No intercell spacing
|
|
110 setIntercellSpacing(new Dimension(0, 0));
|
|
111
|
|
112 // And update the height of the trees row to match that of
|
|
113 // the table.
|
|
114 if (tree.getRowHeight() < 1) {
|
|
115 // Metal looks better like this.
|
|
116 setRowHeight(20);
|
|
117 }
|
|
118 }
|
|
119
|
|
120 /**
|
|
121 * Overridden to message super and forward the method to the tree.
|
|
122 * Since the tree is not actually in the component hieachy it will
|
|
123 * never receive this unless we forward it in this manner.
|
|
124 */
|
|
125 public void updateUI() {
|
|
126 super.updateUI();
|
|
127 if(tree != null) {
|
|
128 tree.updateUI();
|
|
129 // Do this so that the editor is referencing the current renderer
|
|
130 // from the tree. The renderer can potentially change each time
|
|
131 // laf changes.
|
|
132 setDefaultEditor(TreeTableModel.class, new TreeTableCellEditor());
|
|
133 }
|
|
134 // Use the tree's default foreground and background colors in the
|
|
135 // table.
|
|
136 LookAndFeel.installColorsAndFont(this, "Tree.background",
|
|
137 "Tree.foreground", "Tree.font");
|
|
138 }
|
|
139
|
|
140 /**
|
|
141 * Workaround for BasicTableUI anomaly. Make sure the UI never tries to
|
|
142 * resize the editor. The UI currently uses different techniques to
|
|
143 * paint the renderers and editors and overriding setBounds() below
|
|
144 * is not the right thing to do for an editor. Returning -1 for the
|
|
145 * editing row in this case, ensures the editor is never painted.
|
|
146 */
|
|
147 public int getEditingRow() {
|
|
148 return (getColumnClass(editingColumn) == TreeTableModel.class) ? -1 :
|
|
149 editingRow;
|
|
150 }
|
|
151
|
|
152 /**
|
|
153 * Returns the actual row that is editing as <code>getEditingRow</code>
|
|
154 * will always return -1.
|
|
155 */
|
|
156 private int realEditingRow() {
|
|
157 return editingRow;
|
|
158 }
|
|
159
|
|
160 /**
|
|
161 * This is overriden to invoke supers implementation, and then,
|
|
162 * if the receiver is editing a Tree column, the editors bounds is
|
|
163 * reset. The reason we have to do this is because JTable doesn't
|
|
164 * think the table is being edited, as <code>getEditingRow</code> returns
|
|
165 * -1, and therefore doesn't automaticly resize the editor for us.
|
|
166 */
|
|
167 public void sizeColumnsToFit(int resizingColumn) {
|
|
168 super.sizeColumnsToFit(resizingColumn);
|
|
169 if (getEditingColumn() != -1 && getColumnClass(editingColumn) ==
|
|
170 TreeTableModel.class) {
|
|
171 Rectangle cellRect = getCellRect(realEditingRow(),
|
|
172 getEditingColumn(), false);
|
|
173 Component component = getEditorComponent();
|
|
174 component.setBounds(cellRect);
|
|
175 component.validate();
|
|
176 }
|
|
177 }
|
|
178
|
|
179 /**
|
|
180 * Overridden to pass the new rowHeight to the tree.
|
|
181 */
|
|
182 public void setRowHeight(int rowHeight) {
|
|
183 super.setRowHeight(rowHeight);
|
|
184 if (tree != null && tree.getRowHeight() != rowHeight) {
|
|
185 tree.setRowHeight(getRowHeight());
|
|
186 }
|
|
187 }
|
|
188
|
|
189 /**
|
|
190 * Returns the tree that is being shared between the model.
|
|
191 */
|
|
192 public JTree getTree() {
|
|
193 return tree;
|
|
194 }
|
|
195
|
|
196 /**
|
|
197 * Overriden to invoke repaint for the particular location if
|
|
198 * the column contains the tree. This is done as the tree editor does
|
|
199 * not fill the bounds of the cell, we need the renderer to paint
|
|
200 * the tree in the background, and then draw the editor over it.
|
|
201 */
|
|
202 public boolean editCellAt(int row, int column, EventObject e){
|
|
203 boolean retValue = super.editCellAt(row, column, e);
|
|
204 if (retValue && getColumnClass(column) == TreeTableModel.class) {
|
|
205 repaint(getCellRect(row, column, false));
|
|
206 }
|
|
207 return retValue;
|
|
208 }
|
|
209
|
|
210 /** A DefaultTreeCellRenderer which can optionally skip drawing
|
|
211 all icons. */
|
|
212 class JTreeTableCellRenderer extends DefaultTreeCellRenderer {
|
|
213 public Icon getClosedIcon() { return (showsIcons ? super.getClosedIcon() : null); }
|
|
214 public Icon getDefaultClosedIcon() { return (showsIcons ? super.getDefaultClosedIcon() : null); }
|
|
215 public Icon getDefaultLeafIcon() { return (showsIcons ? super.getDefaultLeafIcon() : null); }
|
|
216 public Icon getDefaultOpenIcon() { return (showsIcons ? super.getDefaultOpenIcon() : null); }
|
|
217 public Icon getLeafIcon() { return (showsIcons ? super.getLeafIcon() : null); }
|
|
218 public Icon getOpenIcon() { return (showsIcons ? super.getOpenIcon() : null); }
|
|
219 }
|
|
220
|
|
221 /**
|
|
222 * A TreeCellRenderer that displays a JTree.
|
|
223 */
|
|
224 public class TreeTableCellRenderer extends JTree implements
|
|
225 TableCellRenderer {
|
|
226 /** Last table/tree row asked to renderer. */
|
|
227 protected int visibleRow;
|
|
228 /** Border to draw around the tree, if this is non-null, it will
|
|
229 * be painted. */
|
|
230 protected Border highlightBorder;
|
|
231
|
|
232 public TreeTableCellRenderer(TreeModel model) {
|
|
233 super(model);
|
|
234 setCellRenderer(new JTreeTableCellRenderer());
|
|
235 }
|
|
236
|
|
237 /**
|
|
238 * updateUI is overridden to set the colors of the Tree's renderer
|
|
239 * to match that of the table.
|
|
240 */
|
|
241 public void updateUI() {
|
|
242 super.updateUI();
|
|
243 // Make the tree's cell renderer use the table's cell selection
|
|
244 // colors.
|
|
245 TreeCellRenderer tcr = getCellRenderer();
|
|
246 if (tcr instanceof DefaultTreeCellRenderer) {
|
|
247 DefaultTreeCellRenderer dtcr = ((DefaultTreeCellRenderer)tcr);
|
|
248 // For 1.1 uncomment this, 1.2 has a bug that will cause an
|
|
249 // exception to be thrown if the border selection color is
|
|
250 // null.
|
|
251 // dtcr.setBorderSelectionColor(null);
|
|
252 dtcr.setTextSelectionColor(UIManager.getColor
|
|
253 ("Table.selectionForeground"));
|
|
254 dtcr.setBackgroundSelectionColor(UIManager.getColor
|
|
255 ("Table.selectionBackground"));
|
|
256 }
|
|
257 }
|
|
258
|
|
259 /**
|
|
260 * Sets the row height of the tree, and forwards the row height to
|
|
261 * the table.
|
|
262 */
|
|
263 public void setRowHeight(int rowHeight) {
|
|
264 if (rowHeight > 0) {
|
|
265 super.setRowHeight(rowHeight);
|
|
266 if (JTreeTable.this != null &&
|
|
267 JTreeTable.this.getRowHeight() != rowHeight) {
|
|
268 JTreeTable.this.setRowHeight(getRowHeight());
|
|
269 }
|
|
270 }
|
|
271 }
|
|
272
|
|
273 /**
|
|
274 * This is overridden to set the height to match that of the JTable.
|
|
275 */
|
|
276 public void setBounds(int x, int y, int w, int h) {
|
|
277 super.setBounds(x, 0, w, JTreeTable.this.getHeight());
|
|
278 }
|
|
279
|
|
280 /**
|
|
281 * Sublcassed to translate the graphics such that the last visible
|
|
282 * row will be drawn at 0,0.
|
|
283 */
|
|
284 public void paint(Graphics g) {
|
|
285 g.translate(0, -visibleRow * getRowHeight());
|
|
286 super.paint(g);
|
|
287 // Draw the Table border if we have focus.
|
|
288 if (highlightBorder != null) {
|
|
289 highlightBorder.paintBorder(this, g, 0, visibleRow *
|
|
290 getRowHeight(), getWidth(),
|
|
291 getRowHeight());
|
|
292 }
|
|
293 }
|
|
294
|
|
295 /**
|
|
296 * TreeCellRenderer method. Overridden to update the visible row.
|
|
297 */
|
|
298 public Component getTableCellRendererComponent(JTable table,
|
|
299 Object value,
|
|
300 boolean isSelected,
|
|
301 boolean hasFocus,
|
|
302 int row, int column) {
|
|
303 Color background;
|
|
304 Color foreground;
|
|
305
|
|
306 if(isSelected) {
|
|
307 background = table.getSelectionBackground();
|
|
308 foreground = table.getSelectionForeground();
|
|
309 }
|
|
310 else {
|
|
311 background = table.getBackground();
|
|
312 foreground = table.getForeground();
|
|
313 }
|
|
314 highlightBorder = null;
|
|
315 if (realEditingRow() == row && getEditingColumn() == column) {
|
|
316 background = UIManager.getColor("Table.focusCellBackground");
|
|
317 foreground = UIManager.getColor("Table.focusCellForeground");
|
|
318 }
|
|
319 else if (hasFocus) {
|
|
320 highlightBorder = UIManager.getBorder
|
|
321 ("Table.focusCellHighlightBorder");
|
|
322 if (isCellEditable(row, column)) {
|
|
323 background = UIManager.getColor
|
|
324 ("Table.focusCellBackground");
|
|
325 foreground = UIManager.getColor
|
|
326 ("Table.focusCellForeground");
|
|
327 }
|
|
328 }
|
|
329
|
|
330 visibleRow = row;
|
|
331 setBackground(background);
|
|
332
|
|
333 TreeCellRenderer tcr = getCellRenderer();
|
|
334 if (tcr instanceof DefaultTreeCellRenderer) {
|
|
335 DefaultTreeCellRenderer dtcr = ((DefaultTreeCellRenderer)tcr);
|
|
336 if (isSelected) {
|
|
337 dtcr.setTextSelectionColor(foreground);
|
|
338 dtcr.setBackgroundSelectionColor(background);
|
|
339 }
|
|
340 else {
|
|
341 dtcr.setTextNonSelectionColor(foreground);
|
|
342 dtcr.setBackgroundNonSelectionColor(background);
|
|
343 }
|
|
344 }
|
|
345 return this;
|
|
346 }
|
|
347 }
|
|
348
|
|
349
|
|
350 /**
|
|
351 * An editor that can be used to edit the tree column. This extends
|
|
352 * DefaultCellEditor and uses a JTextField (actually, TreeTableTextField)
|
|
353 * to perform the actual editing.
|
|
354 * <p>To support editing of the tree column we can not make the tree
|
|
355 * editable. The reason this doesn't work is that you can not use
|
|
356 * the same component for editing and renderering. The table may have
|
|
357 * the need to paint cells, while a cell is being edited. If the same
|
|
358 * component were used for the rendering and editing the component would
|
|
359 * be moved around, and the contents would change. When editing, this
|
|
360 * is undesirable, the contents of the text field must stay the same,
|
|
361 * including the caret blinking, and selections persisting. For this
|
|
362 * reason the editing is done via a TableCellEditor.
|
|
363 * <p>Another interesting thing to be aware of is how tree positions
|
|
364 * its render and editor. The render/editor is responsible for drawing the
|
|
365 * icon indicating the type of node (leaf, branch...). The tree is
|
|
366 * responsible for drawing any other indicators, perhaps an additional
|
|
367 * +/- sign, or lines connecting the various nodes. So, the renderer
|
|
368 * is positioned based on depth. On the other hand, table always makes
|
|
369 * its editor fill the contents of the cell. To get the allusion
|
|
370 * that the table cell editor is part of the tree, we don't want the
|
|
371 * table cell editor to fill the cell bounds. We want it to be placed
|
|
372 * in the same manner as tree places it editor, and have table message
|
|
373 * the tree to paint any decorations the tree wants. Then, we would
|
|
374 * only have to worry about the editing part. The approach taken
|
|
375 * here is to determine where tree would place the editor, and to override
|
|
376 * the <code>reshape</code> method in the JTextField component to
|
|
377 * nudge the textfield to the location tree would place it. Since
|
|
378 * JTreeTable will paint the tree behind the editor everything should
|
|
379 * just work. So, that is what we are doing here. Determining of
|
|
380 * the icon position will only work if the TreeCellRenderer is
|
|
381 * an instance of DefaultTreeCellRenderer. If you need custom
|
|
382 * TreeCellRenderers, that don't descend from DefaultTreeCellRenderer,
|
|
383 * and you want to support editing in JTreeTable, you will have
|
|
384 * to do something similiar.
|
|
385 */
|
|
386 public class TreeTableCellEditor extends DefaultCellEditor {
|
|
387 public TreeTableCellEditor() {
|
|
388 super(new TreeTableTextField());
|
|
389 }
|
|
390
|
|
391 /**
|
|
392 * Overriden to determine an offset that tree would place the
|
|
393 * editor at. The offset is determined from the
|
|
394 * <code>getRowBounds</code> JTree method, and additionaly
|
|
395 * from the icon DefaultTreeCellRenderer will use.
|
|
396 * <p>The offset is then set on the TreeTableTextField component
|
|
397 * created in the constructor, and returned.
|
|
398 */
|
|
399 public Component getTableCellEditorComponent(JTable table,
|
|
400 Object value,
|
|
401 boolean isSelected,
|
|
402 int r, int c) {
|
|
403 Component component = super.getTableCellEditorComponent
|
|
404 (table, value, isSelected, r, c);
|
|
405 JTree t = getTree();
|
|
406 boolean rv = t.isRootVisible();
|
|
407 int offsetRow = rv ? r : r - 1;
|
|
408 Rectangle bounds = t.getRowBounds(offsetRow);
|
|
409 int offset = bounds.x;
|
|
410 TreeCellRenderer tcr = t.getCellRenderer();
|
|
411 if (tcr instanceof DefaultTreeCellRenderer) {
|
|
412 Object node = t.getPathForRow(offsetRow).
|
|
413 getLastPathComponent();
|
|
414 Icon icon;
|
|
415 if (t.getModel().isLeaf(node))
|
|
416 icon = ((DefaultTreeCellRenderer)tcr).getLeafIcon();
|
|
417 else if (tree.isExpanded(offsetRow))
|
|
418 icon = ((DefaultTreeCellRenderer)tcr).getOpenIcon();
|
|
419 else
|
|
420 icon = ((DefaultTreeCellRenderer)tcr).getClosedIcon();
|
|
421 if (icon != null) {
|
|
422 offset += ((DefaultTreeCellRenderer)tcr).getIconTextGap() +
|
|
423 icon.getIconWidth();
|
|
424 }
|
|
425 }
|
|
426 ((TreeTableTextField)getComponent()).offset = offset;
|
|
427 return component;
|
|
428 }
|
|
429
|
|
430 /**
|
|
431 * This is overriden to forward the event to the tree. This will
|
|
432 * return true if the click count >= 3, or the event is null.
|
|
433 */
|
|
434 public boolean isCellEditable(EventObject e) {
|
|
435 if (e instanceof MouseEvent) {
|
|
436 MouseEvent me = (MouseEvent)e;
|
|
437 // If the modifiers are not 0 (or the left mouse button),
|
|
438 // tree may try and toggle the selection, and table
|
|
439 // will then try and toggle, resulting in the
|
|
440 // selection remaining the same. To avoid this, we
|
|
441 // only dispatch when the modifiers are 0 (or the left mouse
|
|
442 // button).
|
|
443 if (me.getModifiers() == 0 ||
|
|
444 me.getModifiers() == InputEvent.BUTTON1_MASK) {
|
|
445 for (int counter = getColumnCount() - 1; counter >= 0;
|
|
446 counter--) {
|
|
447 if (getColumnClass(counter) == TreeTableModel.class) {
|
|
448 MouseEvent newME = new MouseEvent
|
|
449 (JTreeTable.this.tree, me.getID(),
|
|
450 me.getWhen(), me.getModifiers(),
|
|
451 me.getX() - getCellRect(0, counter, true).x,
|
|
452 me.getY(), me.getClickCount(),
|
|
453 me.isPopupTrigger());
|
|
454 JTreeTable.this.tree.dispatchEvent(newME);
|
|
455 break;
|
|
456 }
|
|
457 }
|
|
458 }
|
|
459 if (me.getClickCount() >= 3) {
|
|
460 return treeEditable;
|
|
461 }
|
|
462 return false;
|
|
463 }
|
|
464 if (e == null) {
|
|
465 return treeEditable;
|
|
466 }
|
|
467 return false;
|
|
468 }
|
|
469 }
|
|
470
|
|
471
|
|
472 /**
|
|
473 * Component used by TreeTableCellEditor. The only thing this does
|
|
474 * is to override the <code>reshape</code> method, and to ALWAYS
|
|
475 * make the x location be <code>offset</code>.
|
|
476 */
|
|
477 static class TreeTableTextField extends JTextField {
|
|
478 public int offset;
|
|
479
|
|
480 public void reshape(int x, int y, int w, int h) {
|
|
481 int newX = Math.max(x, offset);
|
|
482 super.reshape(newX, y, w - (newX - x), h);
|
|
483 }
|
|
484 }
|
|
485
|
|
486
|
|
487 /**
|
|
488 * ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel
|
|
489 * to listen for changes in the ListSelectionModel it maintains. Once
|
|
490 * a change in the ListSelectionModel happens, the paths are updated
|
|
491 * in the DefaultTreeSelectionModel.
|
|
492 */
|
|
493 class ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel {
|
|
494 /** Set to true when we are updating the ListSelectionModel. */
|
|
495 protected boolean updatingListSelectionModel;
|
|
496
|
|
497 public ListToTreeSelectionModelWrapper() {
|
|
498 super();
|
|
499 getListSelectionModel().addListSelectionListener
|
|
500 (createListSelectionListener());
|
|
501 }
|
|
502
|
|
503 /**
|
|
504 * Returns the list selection model. ListToTreeSelectionModelWrapper
|
|
505 * listens for changes to this model and updates the selected paths
|
|
506 * accordingly.
|
|
507 */
|
|
508 ListSelectionModel getListSelectionModel() {
|
|
509 return listSelectionModel;
|
|
510 }
|
|
511
|
|
512 /**
|
|
513 * This is overridden to set <code>updatingListSelectionModel</code>
|
|
514 * and message super. This is the only place DefaultTreeSelectionModel
|
|
515 * alters the ListSelectionModel.
|
|
516 */
|
|
517 public void resetRowSelection() {
|
|
518 if(!updatingListSelectionModel) {
|
|
519 updatingListSelectionModel = true;
|
|
520 try {
|
|
521 super.resetRowSelection();
|
|
522 }
|
|
523 finally {
|
|
524 updatingListSelectionModel = false;
|
|
525 }
|
|
526 }
|
|
527 // Notice how we don't message super if
|
|
528 // updatingListSelectionModel is true. If
|
|
529 // updatingListSelectionModel is true, it implies the
|
|
530 // ListSelectionModel has already been updated and the
|
|
531 // paths are the only thing that needs to be updated.
|
|
532 }
|
|
533
|
|
534 /**
|
|
535 * Creates and returns an instance of ListSelectionHandler.
|
|
536 */
|
|
537 protected ListSelectionListener createListSelectionListener() {
|
|
538 return new ListSelectionHandler();
|
|
539 }
|
|
540
|
|
541 /**
|
|
542 * If <code>updatingListSelectionModel</code> is false, this will
|
|
543 * reset the selected paths from the selected rows in the list
|
|
544 * selection model.
|
|
545 */
|
|
546 protected void updateSelectedPathsFromSelectedRows() {
|
|
547 if(!updatingListSelectionModel) {
|
|
548 updatingListSelectionModel = true;
|
|
549 try {
|
|
550 // This is way expensive, ListSelectionModel needs an
|
|
551 // enumerator for iterating.
|
|
552 int min = listSelectionModel.getMinSelectionIndex();
|
|
553 int max = listSelectionModel.getMaxSelectionIndex();
|
|
554
|
|
555 clearSelection();
|
|
556 if(min != -1 && max != -1) {
|
|
557 for(int counter = min; counter <= max; counter++) {
|
|
558 if(listSelectionModel.isSelectedIndex(counter)) {
|
|
559 TreePath selPath = tree.getPathForRow
|
|
560 (counter);
|
|
561
|
|
562 if(selPath != null) {
|
|
563 addSelectionPath(selPath);
|
|
564 }
|
|
565 }
|
|
566 }
|
|
567 }
|
|
568 }
|
|
569 finally {
|
|
570 updatingListSelectionModel = false;
|
|
571 }
|
|
572 }
|
|
573 }
|
|
574
|
|
575 /**
|
|
576 * Class responsible for calling updateSelectedPathsFromSelectedRows
|
|
577 * when the selection of the list changse.
|
|
578 */
|
|
579 class ListSelectionHandler implements ListSelectionListener {
|
|
580 public void valueChanged(ListSelectionEvent e) {
|
|
581 updateSelectedPathsFromSelectedRows();
|
|
582 }
|
|
583 }
|
|
584 }
|
|
585 }
|