1 /* 2 * Copyright (c) 2004, 2007, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.tools.jconsole.inspector; 27 28 import javax.swing.*; 29 import javax.swing.event.*; 30 import javax.swing.table.*; 31 import javax.swing.tree.*; 32 import java.awt.BorderLayout; 33 import java.awt.Color; 34 import java.awt.GridLayout; 35 import java.awt.FlowLayout; 36 import java.awt.Component; 37 import java.awt.EventQueue; 38 import java.awt.event.*; 39 import java.awt.Insets; 40 import java.awt.Dimension; 41 import java.util.*; 42 import java.io.*; 43 44 import java.lang.reflect.Array; 45 46 import javax.management.*; 47 import javax.management.openmbean.CompositeData; 48 import javax.management.openmbean.TabularData; 49 50 import sun.tools.jconsole.MBeansTab; 51 import sun.tools.jconsole.Plotter; 52 import sun.tools.jconsole.JConsole; 53 import sun.tools.jconsole.Messages; 54 import sun.tools.jconsole.ProxyClient.SnapshotMBeanServerConnection; 55 56 /*IMPORTANT : 57 There is a deadlock issue there if we don't synchronize well loadAttributes, 58 refresh attributes and empty table methods since a UI thread can call 59 loadAttributes and at the same time a JMX notification can raise an 60 emptyTable. Since there are synchronization in the JMX world it's 61 COMPULSORY to not call the JMX world in synchronized blocks */ 62 @SuppressWarnings("serial") 63 public class XMBeanAttributes extends XTable { 64 private final static String[] columnNames = 65 {Messages.NAME, 66 Messages.VALUE}; 67 68 private boolean editable = true; 69 70 private XMBean mbean; 71 private MBeanInfo mbeanInfo; 72 private MBeanAttributeInfo[] attributesInfo; 73 private HashMap<String, Object> attributes; 74 private HashMap<String, Object> unavailableAttributes; 75 private HashMap<String, Object> viewableAttributes; 76 private WeakHashMap<XMBean, HashMap<String, ZoomedCell>> viewersCache = 77 new WeakHashMap<XMBean, HashMap<String, ZoomedCell>>(); 78 private TableModelListener attributesListener; 79 private MBeansTab mbeansTab; 80 private XTable table; 81 private TableCellEditor valueCellEditor = new ValueCellEditor(); 82 private int rowMinHeight = -1; 83 private AttributesMouseListener mouseListener = new AttributesMouseListener(); 84 85 private static TableCellEditor editor = 86 new Utils.ReadOnlyTableCellEditor(new JTextField()); 87 88 public XMBeanAttributes(MBeansTab mbeansTab) { 89 super(); 90 this.mbeansTab = mbeansTab; 91 ((DefaultTableModel)getModel()).setColumnIdentifiers(columnNames); 92 getModel().addTableModelListener(attributesListener = 93 new AttributesListener(this)); 94 getColumnModel().getColumn(NAME_COLUMN).setPreferredWidth(40); 95 96 addMouseListener(mouseListener); 97 getTableHeader().setReorderingAllowed(false); 98 setColumnEditors(); 99 addKeyListener(new Utils.CopyKeyAdapter()); 100 } 101 102 public synchronized Component prepareRenderer(TableCellRenderer renderer, 103 int row, int column) { 104 //In case we have a repaint thread that is in the process of 105 //repainting an obsolete table, just ignore the call. 106 //It can happen when MBean selection is switched at a very quick rate 107 if(row >= getRowCount()) 108 return null; 109 else 110 return super.prepareRenderer(renderer, row, column); 111 } 112 113 void updateRowHeight(Object obj, int row) { 114 ZoomedCell cell = null; 115 if(obj instanceof ZoomedCell) { 116 cell = (ZoomedCell) obj; 117 if(cell.isInited()) 118 setRowHeight(row, cell.getHeight()); 119 else 120 if(rowMinHeight != - 1) 121 setRowHeight(row, rowMinHeight); 122 } else 123 if(rowMinHeight != - 1) 124 setRowHeight(row, rowMinHeight); 125 } 126 127 public synchronized TableCellRenderer getCellRenderer(int row, 128 int column) { 129 //In case we have a repaint thread that is in the process of 130 //repainting an obsolete table, just ignore the call. 131 //It can happen when MBean selection is switched at a very quick rate 132 if (row >= getRowCount()) { 133 return null; 134 } else { 135 if (column == VALUE_COLUMN) { 136 Object obj = getModel().getValueAt(row, column); 137 if (obj instanceof ZoomedCell) { 138 ZoomedCell cell = (ZoomedCell) obj; 139 if (cell.isInited()) { 140 DefaultTableCellRenderer renderer = 141 (DefaultTableCellRenderer) cell.getRenderer(); 142 renderer.setToolTipText(getToolTip(row,column)); 143 return renderer; 144 } 145 } 146 } 147 DefaultTableCellRenderer renderer = (DefaultTableCellRenderer) 148 super.getCellRenderer(row, column); 149 if (!isCellError(row, column)) { 150 if (!(isColumnEditable(column) && isWritable(row) && 151 Utils.isEditableType(getClassName(row)))) { 152 renderer.setForeground(getDefaultColor()); 153 } 154 } 155 return renderer; 156 } 157 } 158 159 private void setColumnEditors() { 160 TableColumnModel tcm = getColumnModel(); 161 for (int i = 0; i < columnNames.length; i++) { 162 TableColumn tc = tcm.getColumn(i); 163 if (isColumnEditable(i)) { 164 tc.setCellEditor(valueCellEditor); 165 } else { 166 tc.setCellEditor(editor); 167 } 168 } 169 } 170 171 public void cancelCellEditing() { 172 TableCellEditor editor = getCellEditor(); 173 if (editor != null) { 174 editor.cancelCellEditing(); 175 } 176 } 177 178 public void stopCellEditing() { 179 TableCellEditor editor = getCellEditor(); 180 if (editor != null) { 181 editor.stopCellEditing(); 182 } 183 } 184 185 public final boolean editCellAt(int row, int column, EventObject e) { 186 boolean retVal = super.editCellAt(row, column, e); 187 if (retVal) { 188 TableCellEditor editor = 189 getColumnModel().getColumn(column).getCellEditor(); 190 if (editor == valueCellEditor) { 191 ((JComponent) editor).requestFocus(); 192 } 193 } 194 return retVal; 195 } 196 197 @Override 198 public boolean isCellEditable(int row, int col) { 199 // All the cells in non-editable columns are editable 200 if (!isColumnEditable(col)) { 201 return true; 202 } 203 // Maximized zoomed cells are editable 204 Object obj = getModel().getValueAt(row, col); 205 if (obj instanceof ZoomedCell) { 206 ZoomedCell cell = (ZoomedCell) obj; 207 return cell.isMaximized(); 208 } 209 return true; 210 } 211 212 @Override 213 public void setValueAt(Object value, int row, int column) { 214 if (!isCellError(row, column) && isColumnEditable(column) && 215 isWritable(row) && Utils.isEditableType(getClassName(row))) { 216 super.setValueAt(value, row, column); 217 } 218 } 219 220 //Table methods 221 222 public boolean isTableEditable() { 223 return true; 224 } 225 226 public void setTableValue(Object value, int row) { 227 } 228 229 public boolean isColumnEditable(int column) { 230 if (column < getColumnCount()) { 231 return getColumnName(column).equals(Messages.VALUE); 232 } 233 else { 234 return false; 235 } 236 } 237 238 public String getClassName(int row) { 239 int index = convertRowToIndex(row); 240 if (index != -1) { 241 return attributesInfo[index].getType(); 242 } 243 else { 244 return null; 245 } 246 } 247 248 249 public String getValueName(int row) { 250 int index = convertRowToIndex(row); 251 if (index != -1) { 252 return attributesInfo[index].getName(); 253 } 254 else { 255 return null; 256 } 257 } 258 259 260 public Object getValue(int row) { 261 return ((DefaultTableModel) getModel()).getValueAt(row, VALUE_COLUMN); 262 } 263 264 //tool tip only for editable column 265 public String getToolTip(int row, int column) { 266 if (isCellError(row, column)) { 267 return (String) unavailableAttributes.get(getValueName(row)); 268 } 269 if (isColumnEditable(column)) { 270 Object value = getValue(row); 271 String tip = null; 272 if (value != null) { 273 tip = value.toString(); 274 if(isAttributeViewable(row, VALUE_COLUMN)) 275 tip = Messages.DOUBLE_CLICK_TO_EXPAND_FORWARD_SLASH_COLLAPSE+ 276 ". " + tip; 277 } 278 279 return tip; 280 } 281 282 if(column == NAME_COLUMN) { 283 int index = convertRowToIndex(row); 284 if (index != -1) { 285 return attributesInfo[index].getDescription(); 286 } 287 } 288 return null; 289 } 290 291 public synchronized boolean isWritable(int row) { 292 int index = convertRowToIndex(row); 293 if (index != -1) { 294 return (attributesInfo[index].isWritable()); 295 } 296 else { 297 return false; 298 } 299 } 300 301 /** 302 * Override JTable method in order to make any call to this method 303 * atomic with TableModel elements. 304 */ 305 public synchronized int getRowCount() { 306 return super.getRowCount(); 307 } 308 309 public synchronized boolean isReadable(int row) { 310 int index = convertRowToIndex(row); 311 if (index != -1) { 312 return (attributesInfo[index].isReadable()); 313 } 314 else { 315 return false; 316 } 317 } 318 319 public synchronized boolean isCellError(int row, int col) { 320 return (isColumnEditable(col) && 321 (unavailableAttributes.containsKey(getValueName(row)))); 322 } 323 324 public synchronized boolean isAttributeViewable(int row, int col) { 325 boolean isViewable = false; 326 if(col == VALUE_COLUMN) { 327 Object obj = getModel().getValueAt(row, col); 328 if(obj instanceof ZoomedCell) 329 isViewable = true; 330 } 331 332 return isViewable; 333 } 334 335 public void loadAttributes(final XMBean mbean, MBeanInfo mbeanInfo) { 336 // To avoid deadlock with events coming from the JMX side, 337 // we retrieve all JMX stuff in a non synchronized block. 338 339 if(mbean == null) return; 340 341 final MBeanAttributeInfo[] attributesInfo = mbeanInfo.getAttributes(); 342 final HashMap<String, Object> attributes = 343 new HashMap<String, Object>(attributesInfo.length); 344 final HashMap<String, Object> unavailableAttributes = 345 new HashMap<String, Object>(attributesInfo.length); 346 final HashMap<String, Object> viewableAttributes = 347 new HashMap<String, Object>(attributesInfo.length); 348 AttributeList list = null; 349 350 try { 351 list = mbean.getAttributes(attributesInfo); 352 }catch(Exception e) { 353 list = new AttributeList(); 354 //Can't load all attributes, do it one after each other. 355 for(int i = 0; i < attributesInfo.length; i++) { 356 String name = null; 357 try { 358 name = attributesInfo[i].getName(); 359 Object value = 360 mbean.getAttribute(name); 361 list.add(new Attribute(name, value)); 362 }catch(Exception ex) { 363 if(attributesInfo[i].isReadable()) { 364 unavailableAttributes.put(name, 365 Utils.getActualException(ex). 366 toString()); 367 } 368 } 369 } 370 } 371 try { 372 int att_length = list.size(); 373 for (int i=0;i<att_length;i++) { 374 Attribute attribute = (Attribute) list.get(i); 375 if(isViewable(attribute)) { 376 viewableAttributes.put(attribute.getName(), 377 attribute.getValue()); 378 } 379 else 380 attributes.put(attribute.getName(),attribute.getValue()); 381 382 } 383 // if not all attributes are accessible, 384 // check them one after the other. 385 if (att_length < attributesInfo.length) { 386 for (int i=0;i<attributesInfo.length;i++) { 387 MBeanAttributeInfo attributeInfo = attributesInfo[i]; 388 if (!attributes.containsKey(attributeInfo.getName()) && 389 !viewableAttributes.containsKey(attributeInfo. 390 getName()) && 391 !unavailableAttributes.containsKey(attributeInfo. 392 getName())) { 393 if (attributeInfo.isReadable()) { 394 // getAttributes didn't help resolving the 395 // exception. 396 // We must call it again to understand what 397 // went wrong. 398 try { 399 Object v = 400 mbean.getAttribute(attributeInfo. 401 getName()); 402 //What happens if now it is ok? 403 // Be pragmatic, add it to readable... 404 attributes.put(attributeInfo.getName(), 405 v); 406 }catch(Exception e) { 407 //Put the exception that will be displayed 408 // in tooltip 409 unavailableAttributes.put(attributeInfo. 410 getName(), 411 Utils. 412 getActualException(e) 413 .toString()); 414 } 415 } 416 } 417 } 418 } 419 } 420 catch(Exception e) { 421 //sets all attributes unavailable except the writable ones 422 for (int i=0;i<attributesInfo.length;i++) { 423 MBeanAttributeInfo attributeInfo = attributesInfo[i]; 424 if (attributeInfo.isReadable()) { 425 unavailableAttributes.put(attributeInfo.getName(), 426 Utils.getActualException(e). 427 toString()); 428 } 429 } 430 } 431 //end of retrieval 432 433 //one update at a time 434 synchronized(this) { 435 436 this.mbean = mbean; 437 this.mbeanInfo = mbeanInfo; 438 this.attributesInfo = attributesInfo; 439 this.attributes = attributes; 440 this.unavailableAttributes = unavailableAttributes; 441 this.viewableAttributes = viewableAttributes; 442 443 EventQueue.invokeLater(new Runnable() { 444 public void run() { 445 DefaultTableModel tableModel = 446 (DefaultTableModel) getModel(); 447 448 // don't listen to these events 449 tableModel.removeTableModelListener(attributesListener); 450 451 // add attribute information 452 emptyTable(); 453 454 addTableData(tableModel, 455 mbean, 456 attributesInfo, 457 attributes, 458 unavailableAttributes, 459 viewableAttributes); 460 461 // update the model with the new data 462 tableModel.newDataAvailable(new TableModelEvent(tableModel)); 463 // re-register for change events 464 tableModel.addTableModelListener(attributesListener); 465 } 466 }); 467 } 468 } 469 470 void collapse(String attributeName, final Component c) { 471 final int row = getSelectedRow(); 472 Object obj = getModel().getValueAt(row, VALUE_COLUMN); 473 if(obj instanceof ZoomedCell) { 474 cancelCellEditing(); 475 ZoomedCell cell = (ZoomedCell) obj; 476 cell.reset(); 477 setRowHeight(row, 478 cell.getHeight()); 479 editCellAt(row, 480 VALUE_COLUMN); 481 invalidate(); 482 repaint(); 483 } 484 } 485 486 ZoomedCell updateZoomedCell(int row, 487 int col) { 488 Object obj = getModel().getValueAt(row, VALUE_COLUMN); 489 ZoomedCell cell = null; 490 if(obj instanceof ZoomedCell) { 491 cell = (ZoomedCell) obj; 492 if(!cell.isInited()) { 493 Object elem = cell.getValue(); 494 String attributeName = 495 (String) getModel().getValueAt(row, 496 NAME_COLUMN); 497 Component comp = mbeansTab.getDataViewer(). 498 createAttributeViewer(elem, mbean, attributeName, this); 499 if(comp != null){ 500 if(rowMinHeight == -1) 501 rowMinHeight = getRowHeight(row); 502 503 cell.init(super.getCellRenderer(row, col), 504 comp, 505 rowMinHeight); 506 507 XDataViewer.registerForMouseEvent( 508 comp, mouseListener); 509 } else 510 return cell; 511 } 512 513 cell.switchState(); 514 setRowHeight(row, 515 cell.getHeight()); 516 517 if(!cell.isMaximized()) { 518 cancelCellEditing(); 519 //Back to simple editor. 520 editCellAt(row, 521 VALUE_COLUMN); 522 } 523 524 invalidate(); 525 repaint(); 526 } 527 return cell; 528 } 529 530 public void refreshAttributes() { 531 MBeanServerConnection mbsc = mbeansTab.getMBeanServerConnection(); 532 if (mbsc instanceof SnapshotMBeanServerConnection) { 533 ((SnapshotMBeanServerConnection) mbsc).flush(); 534 } 535 stopCellEditing(); 536 loadAttributes(mbean, mbeanInfo); 537 } 538 539 540 public void emptyTable() { 541 synchronized(this) { 542 ((DefaultTableModel) getModel()). 543 removeTableModelListener(attributesListener); 544 super.emptyTable(); 545 } 546 } 547 548 private boolean isViewable(Attribute attribute) { 549 Object data = attribute.getValue(); 550 return XDataViewer.isViewableValue(data); 551 552 } 553 554 synchronized void removeAttributes() { 555 if (attributes != null) { 556 attributes.clear(); 557 } 558 if (unavailableAttributes != null) { 559 unavailableAttributes.clear(); 560 } 561 if (viewableAttributes != null) { 562 viewableAttributes.clear(); 563 } 564 mbean = null; 565 } 566 567 private ZoomedCell getZoomedCell(XMBean mbean, String attribute, Object value) { 568 synchronized (viewersCache) { 569 HashMap<String, ZoomedCell> viewers; 570 if (viewersCache.containsKey(mbean)) { 571 viewers = viewersCache.get(mbean); 572 } else { 573 viewers = new HashMap<String, ZoomedCell>(); 574 } 575 ZoomedCell cell; 576 if (viewers.containsKey(attribute)) { 577 cell = viewers.get(attribute); 578 cell.setValue(value); 579 if (cell.isMaximized() && cell.getType() != XDataViewer.NUMERIC) { 580 // Plotters are the only viewers with auto update capabilities. 581 // Other viewers need to be updated manually. 582 Component comp = 583 mbeansTab.getDataViewer().createAttributeViewer( 584 value, mbean, attribute, XMBeanAttributes.this); 585 cell.init(cell.getMinRenderer(), comp, cell.getMinHeight()); 586 XDataViewer.registerForMouseEvent(comp, mouseListener); 587 } 588 } else { 589 cell = new ZoomedCell(value); 590 viewers.put(attribute, cell); 591 } 592 viewersCache.put(mbean, viewers); 593 return cell; 594 } 595 } 596 597 //will be called in a synchronized block 598 protected void addTableData(DefaultTableModel tableModel, 599 XMBean mbean, 600 MBeanAttributeInfo[] attributesInfo, 601 HashMap<String, Object> attributes, 602 HashMap<String, Object> unavailableAttributes, 603 HashMap<String, Object> viewableAttributes) { 604 605 Object rowData[] = new Object[2]; 606 int col1Width = 0; 607 int col2Width = 0; 608 for (int i = 0; i < attributesInfo.length; i++) { 609 rowData[0] = (attributesInfo[i].getName()); 610 if (unavailableAttributes.containsKey(rowData[0])) { 611 rowData[1] = Messages.UNAVAILABLE; 612 } else if (viewableAttributes.containsKey(rowData[0])) { 613 rowData[1] = viewableAttributes.get(rowData[0]); 614 if (!attributesInfo[i].isWritable() || 615 !Utils.isEditableType(attributesInfo[i].getType())) { 616 rowData[1] = getZoomedCell(mbean, (String) rowData[0], rowData[1]); 617 } 618 } else { 619 rowData[1] = attributes.get(rowData[0]); 620 } 621 622 tableModel.addRow(rowData); 623 624 //Update column width 625 // 626 String str = null; 627 if(rowData[0] != null) { 628 str = rowData[0].toString(); 629 if(str.length() > col1Width) 630 col1Width = str.length(); 631 } 632 if(rowData[1] != null) { 633 str = rowData[1].toString(); 634 if(str.length() > col2Width) 635 col2Width = str.length(); 636 } 637 } 638 updateColumnWidth(col1Width, col2Width); 639 } 640 641 private void updateColumnWidth(int col1Width, int col2Width) { 642 TableColumnModel colModel = getColumnModel(); 643 644 //Get the column at index pColumn, and set its preferred width. 645 col1Width = col1Width * 7; 646 col2Width = col2Width * 7; 647 if(col1Width + col2Width < 648 (int) getPreferredScrollableViewportSize().getWidth()) 649 col2Width = (int) getPreferredScrollableViewportSize().getWidth() 650 - col1Width; 651 652 colModel.getColumn(NAME_COLUMN).setPreferredWidth(50); 653 } 654 655 class AttributesMouseListener extends MouseAdapter { 656 657 public void mousePressed(MouseEvent e) { 658 if(e.getButton() == MouseEvent.BUTTON1) { 659 if(e.getClickCount() >= 2) { 660 661 int row = XMBeanAttributes.this.getSelectedRow(); 662 int col = XMBeanAttributes.this.getSelectedColumn(); 663 if(col != VALUE_COLUMN) return; 664 if(col == -1 || row == -1) return; 665 666 XMBeanAttributes.this.updateZoomedCell(row, col); 667 } 668 } 669 } 670 } 671 672 class ValueCellEditor extends XTextFieldEditor { 673 // implements javax.swing.table.TableCellEditor 674 public Component getTableCellEditorComponent(JTable table, 675 Object value, 676 boolean isSelected, 677 int row, 678 int column) { 679 Object val = value; 680 if(column == VALUE_COLUMN) { 681 Object obj = getModel().getValueAt(row, 682 column); 683 if(obj instanceof ZoomedCell) { 684 ZoomedCell cell = (ZoomedCell) obj; 685 if(cell.getRenderer() instanceof MaximizedCellRenderer) { 686 MaximizedCellRenderer zr = 687 (MaximizedCellRenderer) cell.getRenderer(); 688 return zr.getComponent(); 689 } 690 } else { 691 Component comp = super.getTableCellEditorComponent( 692 table, val, isSelected, row, column); 693 if (isCellError(row, column) || 694 !isWritable(row) || 695 !Utils.isEditableType(getClassName(row))) { 696 textField.setEditable(false); 697 } 698 return comp; 699 } 700 } 701 return super.getTableCellEditorComponent(table, 702 val, 703 isSelected, 704 row, 705 column); 706 } 707 @Override 708 public boolean stopCellEditing() { 709 int editingRow = getEditingRow(); 710 int editingColumn = getEditingColumn(); 711 if (editingColumn == VALUE_COLUMN) { 712 Object obj = getModel().getValueAt(editingRow, editingColumn); 713 if (obj instanceof ZoomedCell) { 714 ZoomedCell cell = (ZoomedCell) obj; 715 if (cell.isMaximized()) { 716 this.cancelCellEditing(); 717 return true; 718 } 719 } 720 } 721 return super.stopCellEditing(); 722 } 723 } 724 725 class MaximizedCellRenderer extends DefaultTableCellRenderer { 726 Component comp; 727 MaximizedCellRenderer(Component comp) { 728 this.comp = comp; 729 Dimension d = comp.getPreferredSize(); 730 if (d.getHeight() > 200) { 731 comp.setPreferredSize(new Dimension((int) d.getWidth(), 200)); 732 } 733 } 734 public Component getTableCellRendererComponent(JTable table, 735 Object value, 736 boolean isSelected, 737 boolean hasFocus, 738 int row, 739 int column) { 740 return comp; 741 } 742 public Component getComponent() { 743 return comp; 744 } 745 } 746 747 class ZoomedCell { 748 TableCellRenderer minRenderer; 749 MaximizedCellRenderer maxRenderer; 750 int minHeight; 751 boolean minimized = true; 752 boolean init = false; 753 int type; 754 Object value; 755 ZoomedCell(Object value) { 756 type = XDataViewer.getViewerType(value); 757 this.value = value; 758 } 759 760 boolean isInited() { 761 return init; 762 } 763 764 Object getValue() { 765 return value; 766 } 767 768 void setValue(Object value) { 769 this.value = value; 770 } 771 772 void init(TableCellRenderer minRenderer, 773 Component maxComponent, 774 int minHeight) { 775 this.minRenderer = minRenderer; 776 this.maxRenderer = new MaximizedCellRenderer(maxComponent); 777 778 this.minHeight = minHeight; 779 init = true; 780 } 781 782 int getType() { 783 return type; 784 } 785 786 void reset() { 787 init = false; 788 minimized = true; 789 } 790 791 void switchState() { 792 minimized = !minimized; 793 } 794 boolean isMaximized() { 795 return !minimized; 796 } 797 void minimize() { 798 minimized = true; 799 } 800 801 void maximize() { 802 minimized = false; 803 } 804 805 int getHeight() { 806 if(minimized) return minHeight; 807 else 808 return (int) maxRenderer.getComponent(). 809 getPreferredSize().getHeight() ; 810 } 811 812 int getMinHeight() { 813 return minHeight; 814 } 815 816 public String toString() { 817 818 if(value == null) return null; 819 820 if(value.getClass().isArray()) { 821 String name = 822 Utils.getArrayClassName(value.getClass().getName()); 823 int length = Array.getLength(value); 824 return name + "[" + length +"]"; 825 } 826 827 if(value instanceof CompositeData || 828 value instanceof TabularData) 829 return value.getClass().getName(); 830 831 return value.toString(); 832 } 833 834 TableCellRenderer getRenderer() { 835 if(minimized) return minRenderer; 836 else return maxRenderer; 837 } 838 839 TableCellRenderer getMinRenderer() { 840 return minRenderer; 841 } 842 } 843 844 class AttributesListener implements TableModelListener { 845 846 private Component component; 847 848 public AttributesListener(Component component) { 849 this.component = component; 850 } 851 852 public void tableChanged(final TableModelEvent e) { 853 final TableModel model = (TableModel)e.getSource(); 854 // only post changes to the draggable column 855 if (isColumnEditable(e.getColumn())) { 856 mbeansTab.workerAdd(new Runnable() { 857 public void run() { 858 try { 859 Object tableValue = 860 model.getValueAt(e.getFirstRow(), 861 e.getColumn()); 862 // if it's a String, try construct new value 863 // using the defined type. 864 if (tableValue instanceof String) { 865 tableValue = 866 Utils.createObjectFromString(getClassName(e.getFirstRow()), // type 867 (String)tableValue);// value 868 } 869 String attributeName = 870 getValueName(e.getFirstRow()); 871 Attribute attribute = 872 new Attribute(attributeName,tableValue); 873 mbean.setAttribute(attribute); 874 } 875 catch (Throwable ex) { 876 if (JConsole.isDebug()) { 877 ex.printStackTrace(); 878 } 879 ex = Utils.getActualException(ex); 880 881 String message = (ex.getMessage() != null) ? ex.getMessage() : ex.toString(); 882 EventQueue.invokeLater(new ThreadDialog(component, 883 message+"\n", 884 Messages.PROBLEM_SETTING_ATTRIBUTE, 885 JOptionPane.ERROR_MESSAGE)); 886 } 887 refreshAttributes(); 888 } 889 }); 890 } 891 } 892 } 893 }