blob: 41a74580ddbd5a271b801c40992b6efed23d77ea [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2004-2007 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.tools.jconsole.inspector;
27
28import javax.swing.*;
29import javax.swing.event.*;
30import javax.swing.table.*;
31import javax.swing.tree.*;
32import java.awt.BorderLayout;
33import java.awt.Color;
34import java.awt.GridLayout;
35import java.awt.FlowLayout;
36import java.awt.Component;
37import java.awt.EventQueue;
38import java.awt.event.*;
39import java.awt.Insets;
40import java.awt.Dimension;
41import java.util.*;
42import java.io.*;
43
44import java.lang.reflect.Array;
45
46import javax.management.*;
47import javax.management.openmbean.CompositeData;
48import javax.management.openmbean.TabularData;
49
50import sun.tools.jconsole.Resources;
51import sun.tools.jconsole.MBeansTab;
52import sun.tools.jconsole.Plotter;
53import sun.tools.jconsole.JConsole;
54import 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")
63public class XMBeanAttributes extends XTable {
64 private final static String[] columnNames =
65 {Resources.getText("Name"),
66 Resources.getText("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(Resources.getText("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 = Resources.getText("Double click to expand/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 mbeansTab.getDataViewer().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 mbeansTab.getDataViewer().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 synchronzed 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] = Resources.getText("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 Resources.getText("Problem setting attribute"),
885 JOptionPane.ERROR_MESSAGE));
886 }
887 refreshAttributes();
888 }
889 });
890 }
891 }
892 }
893}