Mercurial > hg > truffle
annotate agent/src/share/classes/sun/jvm/hotspot/ui/treetable/JTreeTable.java @ 650:54782a4cd321
6812971: SA: re-attaching to process fails
Summary: After attaching, de-attaching SA from a process, the second time attach() call fails. This happens because in VM.initialize(), Universe does not get re-initialized before it is accessed.
Reviewed-by: swamyv
author | poonam |
---|---|
date | Sun, 15 Mar 2009 18:11:46 -0700 |
parents | d1605aabd0a1 |
children | c18cbe5936b8 |
rev | line source |
---|---|
0 | 1 /* |
196 | 2 * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. |
0 | 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 | |
152
c70a245cad3a
6670684: 4/5 SA command universe did not print out CMS space information
dcubed
parents:
0
diff
changeset
|
480 public void setBounds(int x, int y, int w, int h) { |
0 | 481 int newX = Math.max(x, offset); |
152
c70a245cad3a
6670684: 4/5 SA command universe did not print out CMS space information
dcubed
parents:
0
diff
changeset
|
482 super.setBounds(newX, y, w - (newX - x), h); |
0 | 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 } |