/*
* Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.visualvm.jvmstat.application;
import com.sun.tools.visualvm.core.options.GlobalPreferences;
import com.sun.tools.visualvm.core.properties.PropertiesPanel;
import com.sun.tools.visualvm.core.ui.components.ScrollableContainer;
import com.sun.tools.visualvm.core.ui.components.Spacer;
import com.sun.tools.visualvm.uisupport.UISupport;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.NumberFormat;
import java.util.EventObject;
import java.util.HashSet;
import java.util.Set;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFormattedTextField;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import org.openide.awt.Mnemonics;
import org.openide.util.NbBundle;
/**
*
* @author Jiri Sedlacek
*/
class ConnectionsCustomizer extends PropertiesPanel {
private static final Border SELECTED_BORDER = selectedBorder();
private static final Border EMPTY_BORDER = emptyBorder(SELECTED_BORDER);
private static final ConnectionDescriptor DEFAULT_CONNECTION =
ConnectionDescriptor.createDefault();
private static final String DATA_VIEW = "DATA_VIEW"; // NOI18N
private static final String NO_DATA_VIEW = "NO_DATA_VIEW"; // NOI18N
private static int TABLE_WIDTH = -1;
private static int ROW_HEIGHT = -1;
private final DefaultTableModel model;
public ConnectionsCustomizer(Set<ConnectionDescriptor> descriptors) {
this.model = getModel(descriptors);
initComponents();
update();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (model.getRowCount() > 0)
table.getSelectionModel().setSelectionInterval(0, 0);
}
});
}
public Set<ConnectionDescriptor> getDescriptors() {
return getDescriptors(model);
}
private static DefaultTableModel getModel(Set<ConnectionDescriptor> descriptors) {
DefaultTableModel model = new DefaultTableModel(new Object[] { "Connections" }, 0); // NOI18N
for (ConnectionDescriptor descriptor : descriptors)
model.addRow(new Object[] { descriptor });
return model;
}
private static Set<ConnectionDescriptor> getDescriptors(DefaultTableModel model) {
Set<ConnectionDescriptor> descriptors = new HashSet();
for (int i = 0; i < model.getRowCount(); i++)
descriptors.add((ConnectionDescriptor)model.getValueAt(i, 0));
return descriptors;
}
private static Border selectedBorder() {
Border b = UIManager.getBorder("Table.focusSelectedCellHighlightBorder"); // NOI18N
if (b == null) b = UIManager.getBorder("Table.focusCellHighlightBorder"); // NOI18N
if (b != null) b = new SafeBorder(b); // #372, workarounds null from Border.getBorderInsets
return b;
}
private static Border emptyBorder(Border border) {
Insets i = border == null ? null : border.getBorderInsets(new JTextField());
return i == null ? BorderFactory.createEmptyBorder() :
BorderFactory.createEmptyBorder(i.top, i.left, i.bottom, i.right);
}
private void addDefault() {
model.addRow(new Object[] { ConnectionDescriptor.createDefault() });
int row = table.getRowCount() - 1;
table.getSelectionModel().setSelectionInterval(row, row);
}
private void addCustom() {
ConnectionDescriptor d = new ConnectionDescriptor(getUnusedPort(), GlobalPreferences.sharedInstance().getMonitoredHostPoll());
model.addRow(new Object[] { d });
int row = table.getRowCount() - 1;
table.getSelectionModel().setSelectionInterval(row, row);
}
private void removeSelected() {
int selectedRow = table.getSelectedRow();
if (selectedRow == -1) return;
table.clearSelection();
model.removeRow(selectedRow);
if (selectedRow < table.getRowCount()) table.getSelectionModel().setSelectionInterval(selectedRow, selectedRow);
else if (selectedRow > 0) table.getSelectionModel().setSelectionInterval(selectedRow - 1, selectedRow - 1);
}
private void update() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
CardLayout cl = (CardLayout)viewPanel.getLayout();
cl.show(viewPanel, model.getRowCount() > 0 ? DATA_VIEW : NO_DATA_VIEW);
addDefault.setEnabled(!containsConnection(DEFAULT_CONNECTION));
remove.setEnabled(table.getSelectedRow() != -1);
}
});
}
private boolean containsConnection(ConnectionDescriptor d) {
for (int i = 0; i < table.getRowCount(); i++)
if (table.getValueAt(i, 0).equals(d)) return true;
return false;
}
private int getUnusedPort() {
Set<Integer> ports = new HashSet();
for (int i = 0; i < table.getRowCount(); i++)
ports.add(((ConnectionDescriptor)table.getValueAt(i, 0)).getPort());
for (int i = ConnectionDescriptor.createDefault().getPort() + 1; i < 65536; i++)
if (!ports.contains(i)) return i;
return -1;
}
private void initComponents() {
setLayout(new GridBagLayout());
GridBagConstraints c;
CellRenderer renderer = new CellRenderer();
CellEditor editor = new CellEditor(new Runnable() {
public void run() { update(); }
});
table = new ConnectionsTable(model, renderer, editor) {
public int getRowHeight() {
return ROW_HEIGHT;
}
public Dimension getPreferredSize() {
Dimension ps = super.getPreferredSize();
ps.width = TABLE_WIDTH;
return ps;
}
public Dimension getMinimumSize() {
Dimension ms = super.getMinimumSize();
ms.width = TABLE_WIDTH;
return ms;
}
};
table.setShowGrid(false);
table.setIntercellSpacing(new Dimension());
table.setOpaque(false);
table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
update();
}
});
if (TABLE_WIDTH == -1) {
TABLE_WIDTH = editor.getTableCellEditorComponent(table, new
ConnectionDescriptor(1, 1), false, 1, 1).
getPreferredSize().width;
editor.stopCellEditing();
}
if (ROW_HEIGHT == -1) {
ROW_HEIGHT = renderer.getTableCellRendererComponent(table,
new ConnectionDescriptor(1, 1), false, false,
1, 1).getPreferredSize().height;
}
JScrollPane impl = new JScrollPane();
JScrollPane scroll = new ScrollableContainer(table);
scroll.setBorder(impl.getBorder());
if (!UISupport.isNimbusLookAndFeel())
scroll.setViewportBorder(impl.getViewportBorder());
scroll.getViewport().setOpaque(true);
scroll.getViewport().setBackground(UISupport.getDefaultBackground());
scroll.setPreferredSize(new Dimension(TABLE_WIDTH + 20, 1));
JLabel noConnection = new JLabel(NbBundle.getMessage(
ConnectionsCustomizer.class, "LBL_NoConnection"), JLabel.CENTER); // NOI18N
noConnection.setEnabled(false);
noConnection.setOpaque(false);
noConnection.setMinimumSize(new Dimension());
JScrollPane emptyScroll = new JScrollPane(noConnection,
JScrollPane.VERTICAL_SCROLLBAR_NEVER, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
emptyScroll.getViewport().setOpaque(true);
emptyScroll.getViewport().setBackground(UISupport.getDefaultBackground());
emptyScroll.setOpaque(false);
if (UISupport.isNimbusLookAndFeel())
emptyScroll.setViewportBorder(BorderFactory.createEmptyBorder());
viewPanel = new JPanel(new CardLayout());
viewPanel.setOpaque(false);
viewPanel.add(emptyScroll, NO_DATA_VIEW);
viewPanel.add(scroll, DATA_VIEW);
c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 0;
c.gridwidth = 1;
c.gridheight = GridBagConstraints.REMAINDER;
c.weightx = 1;
c.weighty = 1;
c.anchor = GridBagConstraints.NORTHWEST;
c.fill = GridBagConstraints.BOTH;
c.insets = new Insets(0, 0, 0, 10);
add(viewPanel, c);
addDefault = new JButton() {
protected void fireActionPerformed(ActionEvent e) {
addDefault();
}
};
Mnemonics.setLocalizedText(addDefault, NbBundle.getMessage(
ConnectionsCustomizer.class, "BTN_AddDefault")); // NOI18N
c = new GridBagConstraints();
c.gridx = 1;
c.gridy = 0;
c.anchor = GridBagConstraints.NORTHWEST;
c.fill = GridBagConstraints.HORIZONTAL;
c.insets = new Insets(0, 0, 3, 0);
add(addDefault, c);
JButton addCustom = new JButton() {
protected void fireActionPerformed(ActionEvent e) {
addCustom();
}
};
Mnemonics.setLocalizedText(addCustom, NbBundle.getMessage(
ConnectionsCustomizer.class, "BTN_AddCustom")); // NOI18N
c = new GridBagConstraints();
c.gridx = 1;
c.gridy = 1;
c.anchor = GridBagConstraints.NORTHWEST;
c.fill = GridBagConstraints.HORIZONTAL;
c.insets = new Insets(3, 0, 3, 0);
add(addCustom, c);
remove = new JButton() {
protected void fireActionPerformed(ActionEvent e) {
removeSelected();
}
};
Mnemonics.setLocalizedText(remove, NbBundle.getMessage(
ConnectionsCustomizer.class, "BTN_Remove")); // NOI18N
c = new GridBagConstraints();
c.gridx = 1;
c.gridy = 2;
c.anchor = GridBagConstraints.NORTHWEST;
c.fill = GridBagConstraints.HORIZONTAL;
c.insets = new Insets(3, 0, 0, 0);
add(remove, c);
}
private JPanel viewPanel;
private ConnectionsTable table;
private JButton addDefault;
private JButton remove;
private static class SafeBorder implements Border {
private final Border impl;
SafeBorder(Border impl) { this.impl = impl; }
public void paintBorder(Component cmpnt, Graphics grphcs, int i, int i1, int i2, int i3) {
impl.paintBorder(cmpnt, grphcs, i, i1, i2, i3);
}
public Insets getBorderInsets(Component cmpnt) {
Insets insets = impl.getBorderInsets(cmpnt);
if (insets == null) insets = new Insets(0, 0, 0, 0);
return insets;
}
public boolean isBorderOpaque() {
return impl.isBorderOpaque();
}
}
private static class CellRenderer extends JPanel implements TableCellRenderer {
private static final int BORDER_HEIGHT = 4;
private static final Color BACKGROUND;
private static final Color DARKER_BACKGROUND;
static {
BACKGROUND = UISupport.getDefaultBackground();
int darkerR = BACKGROUND.getRed() - 11;
if (darkerR < 0) darkerR += 26;
int darkerG = BACKGROUND.getGreen() - 11;
if (darkerG < 0) darkerG += 26;
int darkerB = BACKGROUND.getBlue() - 11;
if (darkerB < 0) darkerB += 26;
DARKER_BACKGROUND = new Color(darkerR, darkerG, darkerB);
}
private JLabel portLabel;
private JLabel portValueLabel;
private JLabel refreshLabel;
private JLabel refreshValueLabel;
private JLabel refreshUnitsLabel;
private final NumberFormat format = NumberFormat.getInstance();
public CellRenderer() {
initComponents();
}
private void initComponents() {
portLabel = new JLabel(NbBundle.getMessage(
ConnectionsCustomizer.class, "LBL_Port1")); // NOI18N
portLabel.setFont(portLabel.getFont().deriveFont(Font.BOLD));
final int w = new JSpinner(new SpinnerNumberModel(0, 0, 65535, 0)).
getPreferredSize().width;
portValueLabel = new JLabel() {
public Dimension getPreferredSize() {
Dimension ps = super.getPreferredSize();
ps.width = w;
return ps;
}
};
refreshLabel = new JLabel(NbBundle.getMessage(
ConnectionsCustomizer.class, "LBL_Refresh1")); // NOI18N
refreshLabel.setFont(refreshLabel.getFont().deriveFont(Font.BOLD));
refreshValueLabel = new JLabel();
refreshUnitsLabel = new JLabel(NbBundle.getMessage(
ConnectionsCustomizer.class, "LBL_RefreshUnits")); // NOI18N
setLayout(new GridBagLayout());
GridBagConstraints c;
c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 0;
c.fill = GridBagConstraints.NONE;
c.anchor = GridBagConstraints.WEST;
c.insets = new Insets(BORDER_HEIGHT, 5, BORDER_HEIGHT, 0);
add(portLabel, c);
c = new GridBagConstraints();
c.gridx = 1;
c.gridy = 0;
c.fill = GridBagConstraints.NONE;
c.anchor = GridBagConstraints.WEST;
c.insets = new Insets(BORDER_HEIGHT, 5, BORDER_HEIGHT, 0);
add(portValueLabel, c);
c = new GridBagConstraints();
c.gridx = 2;
c.gridy = 0;
c.fill = GridBagConstraints.NONE;
c.anchor = GridBagConstraints.WEST;
c.insets = new Insets(BORDER_HEIGHT, 15, BORDER_HEIGHT, 0);
add(refreshLabel, c);
c = new GridBagConstraints();
c.gridx = 3;
c.gridy = 0;
c.fill = GridBagConstraints.NONE;
c.anchor = GridBagConstraints.WEST;
c.insets = new Insets(BORDER_HEIGHT, 5, BORDER_HEIGHT, 0);
add(refreshValueLabel, c);
c = new GridBagConstraints();
c.gridx = 4;
c.gridy = 0;
c.fill = GridBagConstraints.NONE;
c.anchor = GridBagConstraints.WEST;
c.insets = new Insets(BORDER_HEIGHT, 5, BORDER_HEIGHT, 0);
add(refreshUnitsLabel, c);
c = new GridBagConstraints();
c.gridx = 5;
c.gridy = 0;
c.gridwidth = GridBagConstraints.REMAINDER;
c.gridheight = GridBagConstraints.REMAINDER;
c.weightx = 1;
c.weighty = 1;
c.fill = GridBagConstraints.BOTH;
c.anchor = GridBagConstraints.NORTHWEST;
c.insets = new Insets(0, 5, 0, 0);
add(Spacer.create(), c);
setOpaque(true);
setBorder(EMPTY_BORDER);
}
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus,
int row, int column) {
ConnectionDescriptor cd = (ConnectionDescriptor)value;
portValueLabel.setText(format.format(cd.getPort()));
refreshValueLabel.setText(format.format(cd.getRefreshRate()));
if (!isSelected) {
boolean oddRow = row % 2 == 0;
setBackground(oddRow ? DARKER_BACKGROUND : BACKGROUND);
}
return this;
}
private static Color darker(Color c) {
if (c == null) return null;
int r = Math.abs(c.getRed() - 11);
int g = Math.abs(c.getGreen() - 11);
int b = Math.abs(c.getBlue() - 11);
int a = c.getAlpha();
return new Color(r, g, b, a);
}
}
private static class CellEditor extends JPanel implements TableCellEditor {
private static final int BORDER_HEIGHT = 6;
private static final Color BACKGROUND_COLOR =
UIManager.getColor("Tree.selectionBackground"); // NOI18N
private static final Color FOREGROUND_COLOR =
UIManager.getColor("Tree.selectionForeground"); // NOI18N
private Runnable updater;
private JTable table;
private ConnectionDescriptor cd;
private JLabel portLabel;
private JSpinner portSpinner;
private JLabel refreshLabel;
private JSpinner refreshSpinner;
private JLabel refreshUnitsLabel;
public CellEditor(Runnable updater) {
this.updater = updater;
initComponents();
}
private PropertyChangeListener listener = new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
updateBorder();
}
});
}
};
private void updateBorder() {
if (displayFocus()) setBorder(SELECTED_BORDER);
else setBorder(EMPTY_BORDER);
}
private boolean displayFocus() {
if (table == null) return false;
Component focusOwner = KeyboardFocusManager.
getCurrentKeyboardFocusManager().getFocusOwner();
return focusOwner != null ? focusOwner == table || SwingUtilities.
isDescendingFrom(focusOwner, this) : false;
}
private void initComponents() {
portLabel = new JLabel();
Mnemonics.setLocalizedText(portLabel, NbBundle.getMessage(
ConnectionsCustomizer.class, "LBL_Port2")); // NOI18N
portLabel.setFont(portLabel.getFont().deriveFont(Font.BOLD));
portSpinner = new JSpinner(new SpinnerNumberModel(0, 0, 65535, 1));
portLabel.setLabelFor(portSpinner);
refreshLabel = new JLabel();
Mnemonics.setLocalizedText(refreshLabel, NbBundle.getMessage(
ConnectionsCustomizer.class, "LBL_Refresh2")); // NOI18N
refreshLabel.setFont(refreshLabel.getFont().deriveFont(Font.BOLD));
refreshSpinner = new JSpinner(new SpinnerNumberModel(3.0, 1.0, 9999.0, 1.0));
refreshLabel.setLabelFor(refreshSpinner);
refreshUnitsLabel = new JLabel(NbBundle.getMessage(
ConnectionsCustomizer.class, "LBL_RefreshUnits")); // NOI18N
setLayout(new GridBagLayout());
GridBagConstraints c;
c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 0;
c.fill = GridBagConstraints.NONE;
c.anchor = GridBagConstraints.WEST;
c.insets = new Insets(BORDER_HEIGHT, 5, BORDER_HEIGHT, 0);
add(portLabel, c);
c = new GridBagConstraints();
c.gridx = 1;
c.gridy = 0;
c.fill = GridBagConstraints.NONE;
c.anchor = GridBagConstraints.WEST;
c.insets = new Insets(BORDER_HEIGHT, 5, BORDER_HEIGHT, 0);
add(portSpinner, c);
c = new GridBagConstraints();
c.gridx = 2;
c.gridy = 0;
c.fill = GridBagConstraints.NONE;
c.anchor = GridBagConstraints.WEST;
c.insets = new Insets(BORDER_HEIGHT, 15, BORDER_HEIGHT, 0);
add(refreshLabel, c);
c = new GridBagConstraints();
c.gridx = 3;
c.gridy = 0;
c.fill = GridBagConstraints.NONE;
c.anchor = GridBagConstraints.WEST;
c.insets = new Insets(BORDER_HEIGHT, 5, BORDER_HEIGHT, 0);
add(refreshSpinner, c);
c = new GridBagConstraints();
c.gridx = 4;
c.gridy = 0;
c.fill = GridBagConstraints.NONE;
c.anchor = GridBagConstraints.WEST;
c.insets = new Insets(BORDER_HEIGHT, 5, BORDER_HEIGHT, 5);
add(refreshUnitsLabel, c);
c = new GridBagConstraints();
c.gridx = 5;
c.gridy = 0;
c.gridwidth = GridBagConstraints.REMAINDER;
c.gridheight = GridBagConstraints.REMAINDER;
c.weightx = 1;
c.weighty = 1;
c.fill = GridBagConstraints.BOTH;
c.anchor = GridBagConstraints.NORTHWEST;
c.insets = new Insets(0, 5, 0, 0);
add(Spacer.create(), c);
setOpaque(true);
setBackground(BACKGROUND_COLOR);
portLabel.setForeground(FOREGROUND_COLOR);
refreshLabel.setForeground(FOREGROUND_COLOR);
refreshUnitsLabel.setForeground(FOREGROUND_COLOR);
JComponent portEditor = portSpinner.getEditor();
if (portEditor instanceof JSpinner.DefaultEditor) {
final JFormattedTextField tf = ((JSpinner.DefaultEditor)portEditor).getTextField();
tf.getDocument().addDocumentListener(new DocumentListener() {
public void insertUpdate(DocumentEvent e) { commitEdit(); }
public void removeUpdate(DocumentEvent e) { commitEdit(); }
public void changedUpdate(DocumentEvent e) { commitEdit(); }
private void commitEdit() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
int val = (Integer)tf.getFormatter().
stringToValue(tf.getText().trim());
if (cd != null) {
cd.setPort(val);
updater.run();
}
} catch (Exception ex) {}
}
});
}
});
} else {
portSpinner.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
if (cd != null) cd.setPort((Integer)portSpinner.getValue());
}
});
}
JComponent refreshEditor = refreshSpinner.getEditor();
if (refreshEditor instanceof JSpinner.DefaultEditor) {
final JFormattedTextField tf = ((JSpinner.DefaultEditor)refreshEditor).getTextField();
tf.getDocument().addDocumentListener(new DocumentListener() {
public void insertUpdate(DocumentEvent e) { commitEdit(); }
public void removeUpdate(DocumentEvent e) { commitEdit(); }
public void changedUpdate(DocumentEvent e) { commitEdit(); }
private void commitEdit() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
int val = (Integer)tf.getFormatter().
stringToValue(tf.getText().trim());
if (cd != null) cd.setRefreshRate(val);
} catch (Exception ex) {}
}
});
}
});
} else {
refreshSpinner.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
if (cd != null) cd.setRefreshRate((Integer)refreshSpinner.getValue());
}
});
}
}
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
this.table = table;
cd = (ConnectionDescriptor)value;
portSpinner.setValue(cd.getPort());
refreshSpinner.setValue(cd.getRefreshRate());
updateBorder();
KeyboardFocusManager.getCurrentKeyboardFocusManager().
addPropertyChangeListener("focusOwner", listener); // NOI18N
return this;
}
public Object getCellEditorValue() { return cd; }
public boolean stopCellEditing() { cleanup(); return true; }
public boolean isCellEditable(EventObject anEvent) { return true; }
public boolean shouldSelectCell(EventObject anEvent) { return true; }
public void cancelCellEditing() { cleanup(); }
public void addCellEditorListener(CellEditorListener l) {}
public void removeCellEditorListener(CellEditorListener l) {}
private void cleanup() {
KeyboardFocusManager.getCurrentKeyboardFocusManager().
removePropertyChangeListener("focusOwner", listener); // NOI18N
table = null;
cd = null;
}
}
}