1 /*
   2  * Copyright (c) 2004, 2013, 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;
  27 
  28 import java.util.List;
  29 import java.awt.*;
  30 import java.awt.event.*;
  31 import java.util.*;
  32 
  33 import javax.swing.*;
  34 import javax.swing.border.*;
  35 import javax.swing.event.*;
  36 import javax.swing.plaf.basic.BasicRadioButtonUI;
  37 import javax.swing.table.*;
  38 
  39 
  40 
  41 import static java.awt.BorderLayout.*;
  42 import static javax.swing.ListSelectionModel.*;
  43 import static sun.tools.jconsole.Utilities.*;
  44 
  45 @SuppressWarnings("serial")
  46 public class ConnectDialog extends InternalDialog
  47                 implements DocumentListener, FocusListener,
  48                            ItemListener, ListSelectionListener, KeyListener {
  49 
  50     private static final int COL_NAME = 0;
  51     private static final int COL_PID  = 1;
  52 
  53 
  54     JConsole jConsole;
  55     JTextField userNameTF, passwordTF;
  56     JRadioButton localRadioButton, remoteRadioButton;
  57     JLabel localMessageLabel, remoteMessageLabel;
  58     JTextField remoteTF;
  59     JButton connectButton, cancelButton;
  60     JPanel radioButtonPanel;
  61 
  62     private Icon mastheadIcon =
  63         new MastheadIcon(Messages.CONNECT_DIALOG_MASTHEAD_TITLE);
  64     private Color hintTextColor, disabledTableCellColor;
  65 
  66     // The table of managed VM (local process)
  67     JTable vmTable;
  68     ManagedVmTableModel vmModel = null;
  69 
  70     JScrollPane localTableScrollPane = null;
  71 
  72     private Action connectAction, cancelAction;
  73 
  74 
  75     public ConnectDialog(JConsole jConsole) {
  76         super(jConsole, Messages.CONNECT_DIALOG_TITLE, true);
  77 
  78         this.jConsole = jConsole;
  79         setAccessibleDescription(this,
  80                                  Messages.CONNECT_DIALOG_ACCESSIBLE_DESCRIPTION);
  81         setDefaultCloseOperation(HIDE_ON_CLOSE);
  82         setResizable(false);
  83         Container cp = (JComponent)getContentPane();
  84 
  85         radioButtonPanel = new JPanel(new BorderLayout(0, 12));
  86         radioButtonPanel.setBorder(new EmptyBorder(6, 12, 12, 12));
  87         ButtonGroup radioButtonGroup = new ButtonGroup();
  88         JPanel bottomPanel = new JPanel(new BorderLayout());
  89 
  90         statusBar = new JLabel(" ", JLabel.CENTER);
  91         setAccessibleName(statusBar,
  92                           Messages.CONNECT_DIALOG_STATUS_BAR_ACCESSIBLE_NAME);
  93 
  94         Font normalLabelFont = statusBar.getFont();
  95         Font boldLabelFont = normalLabelFont.deriveFont(Font.BOLD);
  96         Font smallLabelFont = normalLabelFont.deriveFont(normalLabelFont.getSize2D() - 1);
  97 
  98         JLabel mastheadLabel = new JLabel(mastheadIcon);
  99         setAccessibleName(mastheadLabel,
 100                           Messages.CONNECT_DIALOG_MASTHEAD_ACCESSIBLE_NAME);
 101 
 102         cp.add(mastheadLabel, NORTH);
 103         cp.add(radioButtonPanel, CENTER);
 104         cp.add(bottomPanel, SOUTH);
 105 
 106         createActions();
 107 
 108         remoteTF = new JTextField();
 109         remoteTF.addActionListener(connectAction);
 110         remoteTF.getDocument().addDocumentListener(this);
 111         remoteTF.addFocusListener(this);
 112         remoteTF.setPreferredSize(remoteTF.getPreferredSize());
 113         setAccessibleName(remoteTF,
 114                           Messages.REMOTE_PROCESS_TEXT_FIELD_ACCESSIBLE_NAME);
 115 
 116         //
 117         // If the VM supports the local attach mechanism (is: Sun
 118         // implementation) then the Local Process panel is created.
 119         //
 120         if (JConsole.isLocalAttachAvailable()) {
 121             vmModel = new ManagedVmTableModel();
 122             vmTable = new LocalTabJTable(vmModel);
 123             vmTable.setSelectionMode(SINGLE_SELECTION);
 124             vmTable.setPreferredScrollableViewportSize(new Dimension(400, 250));
 125             vmTable.setColumnSelectionAllowed(false);
 126             vmTable.addFocusListener(this);
 127             vmTable.getSelectionModel().addListSelectionListener(this);
 128 
 129             TableColumnModel columnModel = vmTable.getColumnModel();
 130 
 131             TableColumn pidColumn = columnModel.getColumn(COL_PID);
 132             pidColumn.setMaxWidth(getLabelWidth("9999999"));
 133             pidColumn.setResizable(false);
 134 
 135             TableColumn cmdLineColumn = columnModel.getColumn(COL_NAME);
 136             cmdLineColumn.setResizable(false);
 137 
 138             localRadioButton = new JRadioButton(Messages.LOCAL_PROCESS_COLON);
 139             localRadioButton.setMnemonic(Resources.getMnemonicInt(Messages.LOCAL_PROCESS_COLON));
 140             localRadioButton.setFont(boldLabelFont);
 141             localRadioButton.addItemListener(this);
 142             radioButtonGroup.add(localRadioButton);
 143 
 144             JPanel localPanel = new JPanel(new BorderLayout());
 145 
 146             JPanel localTablePanel = new JPanel(new BorderLayout());
 147 
 148             radioButtonPanel.add(localPanel, NORTH);
 149 
 150             localPanel.add(localRadioButton, NORTH);
 151             localPanel.add(new Padder(localRadioButton), LINE_START);
 152             localPanel.add(localTablePanel, CENTER);
 153 
 154             localTableScrollPane = new JScrollPane(vmTable);
 155 
 156             localTablePanel.add(localTableScrollPane, NORTH);
 157 
 158             localMessageLabel = new JLabel(" ");
 159             localMessageLabel.setFont(smallLabelFont);
 160             localMessageLabel.setForeground(hintTextColor);
 161             localTablePanel.add(localMessageLabel, SOUTH);
 162         }
 163 
 164         remoteRadioButton = new JRadioButton(Messages.REMOTE_PROCESS_COLON);
 165         remoteRadioButton.setMnemonic(Resources.getMnemonicInt(Messages.REMOTE_PROCESS_COLON));
 166         remoteRadioButton.setFont(boldLabelFont);
 167         radioButtonGroup.add(remoteRadioButton);
 168 
 169         JPanel remotePanel = new JPanel(new BorderLayout());
 170         if (localRadioButton != null) {
 171             remotePanel.add(remoteRadioButton, NORTH);
 172             remotePanel.add(new Padder(remoteRadioButton), LINE_START);
 173 
 174             Action nextRadioButtonAction =
 175                 new AbstractAction("nextRadioButton") {
 176                     public void actionPerformed(ActionEvent ev) {
 177                         JRadioButton rb =
 178                             (ev.getSource() == localRadioButton) ? remoteRadioButton
 179                                                                  : localRadioButton;
 180                         rb.doClick();
 181                         rb.requestFocus();
 182                     }
 183                 };
 184 
 185             localRadioButton.getActionMap().put("nextRadioButton", nextRadioButtonAction);
 186             remoteRadioButton.getActionMap().put("nextRadioButton", nextRadioButtonAction);
 187 
 188             localRadioButton.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0),
 189                                                "nextRadioButton");
 190             remoteRadioButton.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0),
 191                                                 "nextRadioButton");
 192         } else {
 193             JLabel remoteLabel = new JLabel(remoteRadioButton.getText());
 194             remoteLabel.setFont(boldLabelFont);
 195             remotePanel.add(remoteLabel, NORTH);
 196         }
 197         radioButtonPanel.add(remotePanel, SOUTH);
 198 
 199         JPanel remoteTFPanel = new JPanel(new BorderLayout());
 200         remotePanel.add(remoteTFPanel, CENTER);
 201 
 202         remoteTFPanel.add(remoteTF, NORTH);
 203 
 204         remoteMessageLabel = new JLabel("<html>" + Messages.REMOTE_TF_USAGE + "</html>");
 205         remoteMessageLabel.setFont(smallLabelFont);
 206         remoteMessageLabel.setForeground(hintTextColor);
 207         remoteTFPanel.add(remoteMessageLabel, CENTER);
 208 
 209         JPanel userPwdPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0));
 210         userPwdPanel.setBorder(new EmptyBorder(12, 0, 0, 0)); // top padding
 211 
 212         int tfWidth = JConsole.IS_WIN ? 12 : 8;
 213 
 214         userNameTF = new JTextField(tfWidth);
 215         userNameTF.addActionListener(connectAction);
 216         userNameTF.getDocument().addDocumentListener(this);
 217         userNameTF.addFocusListener(this);
 218         setAccessibleName(userNameTF,
 219             Messages.USERNAME_ACCESSIBLE_NAME);
 220         LabeledComponent lc;
 221         lc = new LabeledComponent(Messages.USERNAME_COLON_,
 222                                   Resources.getMnemonicInt(Messages.USERNAME_COLON_),
 223                                   userNameTF);
 224         lc.label.setFont(boldLabelFont);
 225         userPwdPanel.add(lc);
 226 
 227         passwordTF = new JPasswordField(tfWidth);
 228         // Heights differ, so fix here
 229         passwordTF.setPreferredSize(userNameTF.getPreferredSize());
 230         passwordTF.addActionListener(connectAction);
 231         passwordTF.getDocument().addDocumentListener(this);
 232         passwordTF.addFocusListener(this);
 233         setAccessibleName(passwordTF,
 234             Messages.PASSWORD_ACCESSIBLE_NAME);
 235 
 236         lc = new LabeledComponent(Messages.PASSWORD_COLON_,
 237                                   Resources.getMnemonicInt(Messages.PASSWORD_COLON_),
 238                                   passwordTF);
 239         lc.setBorder(new EmptyBorder(0, 12, 0, 0)); // Left padding
 240         lc.label.setFont(boldLabelFont);
 241         userPwdPanel.add(lc);
 242 
 243         remoteTFPanel.add(userPwdPanel, SOUTH);
 244 
 245         String connectButtonToolTipText =
 246             Messages.CONNECT_DIALOG_CONNECT_BUTTON_TOOLTIP;
 247         connectButton = new JButton(connectAction);
 248         connectButton.setToolTipText(connectButtonToolTipText);
 249 
 250         cancelButton = new JButton(cancelAction);
 251 
 252         JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING));
 253         buttonPanel.setBorder(new EmptyBorder(12, 12, 2, 12));
 254         if (JConsole.IS_GTK) {
 255             buttonPanel.add(cancelButton);
 256             buttonPanel.add(connectButton);
 257         } else {
 258             buttonPanel.add(connectButton);
 259             buttonPanel.add(cancelButton);
 260         }
 261         bottomPanel.add(buttonPanel, NORTH);
 262 
 263         bottomPanel.add(statusBar, SOUTH);
 264 
 265         updateButtonStates();
 266         Utilities.updateTransparency(this);
 267     }
 268 
 269     public void revalidate() {
 270         // Adjust some colors
 271         Color disabledForeground = UIManager.getColor("Label.disabledForeground");
 272         if (disabledForeground == null) {
 273             // fall back for Nimbus that doesn't support 'Label.disabledForeground'
 274             disabledForeground = UIManager.getColor("Label.disabledText");
 275         }
 276         hintTextColor =
 277             ensureContrast(disabledForeground,
 278                            UIManager.getColor("Panel.background"));
 279         disabledTableCellColor =
 280             ensureContrast(new Color(0x808080),
 281                            UIManager.getColor("Table.background"));
 282 
 283         if (remoteMessageLabel != null) {
 284             remoteMessageLabel.setForeground(hintTextColor);
 285             // Update html color setting
 286             String colorStr =
 287                 String.format("%06x", hintTextColor.getRGB() & 0xFFFFFF);
 288             remoteMessageLabel.setText("<html><font color=#" + colorStr + ">" +
 289                                        Messages.REMOTE_TF_USAGE);
 290         }
 291         if (localMessageLabel != null) {
 292             localMessageLabel.setForeground(hintTextColor);
 293             // Update html color setting
 294             valueChanged(null);
 295         }
 296 
 297         super.revalidate();
 298     }
 299 
 300     private void createActions() {
 301         connectAction = new AbstractAction(Messages.CONNECT) {
 302             /* init */ {
 303                 putValue(Action.MNEMONIC_KEY, Resources.getMnemonicInt(Messages.CONNECT));
 304             }
 305 
 306             public void actionPerformed(ActionEvent ev) {
 307                 if (!isEnabled() || !isVisible()) {
 308                     return;
 309                 }
 310                 setVisible(false);
 311                 statusBar.setText("");
 312 
 313                 if (remoteRadioButton.isSelected()) {
 314                     String txt = remoteTF.getText().trim();
 315                     String userName = userNameTF.getText().trim();
 316                     userName = userName.equals("") ? null : userName;
 317                     String password = passwordTF.getText();
 318                     password = password.equals("") ? null : password;
 319                     try {
 320                         if (txt.startsWith(JConsole.ROOT_URL)) {
 321                             String url = txt;
 322                             jConsole.addUrl(url, userName, password, false);
 323                             remoteTF.setText(JConsole.ROOT_URL);
 324                             return;
 325                         } else {
 326                             String host = remoteTF.getText().trim();
 327                             String port = "0";
 328                             int index = host.lastIndexOf(':');
 329                             if (index >= 0) {
 330                                 port = host.substring(index + 1);
 331                                 host = host.substring(0, index);
 332                             }
 333                             if (host.length() > 0 && port.length() > 0) {
 334                                 int p = Integer.parseInt(port.trim());
 335                                 jConsole.addHost(host, p, userName, password);
 336                                 remoteTF.setText("");
 337                                 userNameTF.setText("");
 338                                 passwordTF.setText("");
 339                                 return;
 340                             }
 341                         }
 342                     } catch (Exception ex) {
 343                         statusBar.setText(ex.toString());
 344                     }
 345                     setVisible(true);
 346                 } else if (localRadioButton != null && localRadioButton.isSelected()) {
 347                     // Try to connect to selected VM. If a connection
 348                     // cannot be established for some reason (the process has
 349                     // terminated for example) then keep the dialog open showing
 350                     // the connect error.
 351                     //
 352                     int row = vmTable.getSelectedRow();
 353                     if (row >= 0) {
 354                         jConsole.addVmid(vmModel.vmAt(row));
 355                     }
 356                     refresh();
 357                 }
 358             }
 359         };
 360 
 361         cancelAction = new AbstractAction(Messages.CANCEL) {
 362             public void actionPerformed(ActionEvent ev) {
 363                 setVisible(false);
 364                 statusBar.setText("");
 365             }
 366         };
 367     }
 368 
 369 
 370     // a label used solely for calculating the width
 371     private static JLabel tmpLabel = new JLabel();
 372     public static int getLabelWidth(String text) {
 373         tmpLabel.setText(text);
 374         return (int) tmpLabel.getPreferredSize().getWidth() + 1;
 375     }
 376 
 377     private class LocalTabJTable extends JTable {
 378         ManagedVmTableModel vmModel;
 379         Border rendererBorder = new EmptyBorder(0, 6, 0, 6);
 380 
 381         public LocalTabJTable(ManagedVmTableModel model) {
 382             super(model);
 383             this.vmModel = model;
 384 
 385             // Remove vertical lines, expect for GTK L&F.
 386             // (because GTK doesn't show header dividers)
 387             if (!JConsole.IS_GTK) {
 388                 setShowVerticalLines(false);
 389                 setIntercellSpacing(new Dimension(0, 1));
 390             }
 391 
 392             // Double-click handler
 393             addMouseListener(new MouseAdapter() {
 394                 public void mouseClicked(MouseEvent evt) {
 395                     if (evt.getClickCount() == 2) {
 396                         connectButton.doClick();
 397                     }
 398                 }
 399             });
 400 
 401             // Enter should call default action
 402             getActionMap().put("connect", connectAction);
 403             InputMap inputMap = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
 404             inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "connect");
 405         }
 406 
 407         public String getToolTipText(MouseEvent e) {
 408             String tip = null;
 409             java.awt.Point p = e.getPoint();
 410             int rowIndex = rowAtPoint(p);
 411             int colIndex = columnAtPoint(p);
 412             int realColumnIndex = convertColumnIndexToModel(colIndex);
 413 
 414             if (realColumnIndex == COL_NAME) {
 415                 LocalVirtualMachine vmd = vmModel.vmAt(rowIndex);
 416                 tip = vmd.toString();
 417             }
 418             return tip;
 419         }
 420 
 421         public TableCellRenderer getCellRenderer(int row, int column) {
 422             return new DefaultTableCellRenderer() {
 423                 public Component getTableCellRendererComponent(JTable table,
 424                                                                Object value,
 425                                                                boolean isSelected,
 426                                                                boolean hasFocus,
 427                                                                int row,
 428                                                                int column) {
 429                     Component comp =
 430                         super.getTableCellRendererComponent(table, value, isSelected,
 431                                                             hasFocus, row, column);
 432 
 433                     if (!isSelected) {
 434                         LocalVirtualMachine lvm = vmModel.vmAt(row);
 435                         if (!lvm.isManageable() && !lvm.isAttachable()) {
 436                             comp.setForeground(disabledTableCellColor);
 437                         }
 438                     }
 439 
 440                     if (comp instanceof JLabel) {
 441                         JLabel label = (JLabel)comp;
 442                         label.setBorder(rendererBorder);
 443 
 444                         if (value instanceof Integer) {
 445                             label.setHorizontalAlignment(JLabel.RIGHT);
 446                         }
 447                     }
 448 
 449                     return comp;
 450                 }
 451             };
 452         }
 453     }
 454 
 455     public void setConnectionParameters(String url,
 456                                         String host,
 457                                         int port,
 458                                         String userName,
 459                                         String password,
 460                                         String msg) {
 461         if ((url != null && url.length() > 0) ||
 462             (host != null && host.length() > 0 && port > 0)) {
 463 
 464             remoteRadioButton.setSelected(true);
 465             if (url != null && url.length() > 0) {
 466                 remoteTF.setText(url);
 467             } else {
 468                 remoteTF.setText(host+":"+port);
 469             }
 470             userNameTF.setText((userName != null) ? userName : "");
 471             passwordTF.setText((password != null) ? password : "");
 472 
 473             statusBar.setText((msg != null) ? msg : "");
 474             if (getPreferredSize().width > getWidth()) {
 475                 pack();
 476             }
 477             remoteTF.requestFocus();
 478             remoteTF.selectAll();
 479         }
 480     }
 481 
 482 
 483     public void itemStateChanged(ItemEvent ev) {
 484         if (!localRadioButton.isSelected()) {
 485             vmTable.getSelectionModel().clearSelection();
 486         }
 487         updateButtonStates();
 488     }
 489 
 490     private void updateButtonStates() {
 491         boolean connectEnabled = false;
 492 
 493         if (remoteRadioButton.isSelected()) {
 494             connectEnabled = JConsole.isValidRemoteString(remoteTF.getText());
 495         } else if (localRadioButton != null && localRadioButton.isSelected()) {
 496             int row = vmTable.getSelectedRow();
 497             if (row >= 0) {
 498                 LocalVirtualMachine lvm = vmModel.vmAt(row);
 499                 connectEnabled = (lvm.isManageable() || lvm.isAttachable());
 500             }
 501         }
 502 
 503         connectAction.setEnabled(connectEnabled);
 504     }
 505 
 506     public void insertUpdate(DocumentEvent e) {
 507         updateButtonStates();
 508     }
 509 
 510     public void removeUpdate(DocumentEvent e) {
 511         updateButtonStates();
 512     }
 513 
 514     public void changedUpdate(DocumentEvent e) {
 515         updateButtonStates();
 516     }
 517 
 518     public void focusGained(FocusEvent e) {
 519         Object source = e.getSource();
 520         Component opposite = e.getOppositeComponent();
 521 
 522         if (!e.isTemporary() &&
 523             source instanceof JTextField &&
 524             opposite instanceof JComponent &&
 525             SwingUtilities.getRootPane(opposite) == getRootPane()) {
 526 
 527             ((JTextField)source).selectAll();
 528         }
 529 
 530         if (source == remoteTF) {
 531             remoteRadioButton.setSelected(true);
 532         } else if (source == vmTable) {
 533             localRadioButton.setSelected(true);
 534             if (vmModel.getRowCount() == 1) {
 535                 // if there's only one process then select the row
 536                 vmTable.setRowSelectionInterval(0, 0);
 537             }
 538         }
 539         updateButtonStates();
 540     }
 541 
 542     public void focusLost(FocusEvent e) {
 543     }
 544 
 545     public void keyTyped(KeyEvent e) {
 546         char c = e.getKeyChar();
 547         if (c == KeyEvent.VK_ESCAPE) {
 548             setVisible(false);
 549         } else if (!(Character.isDigit(c) ||
 550                      c == KeyEvent.VK_BACK_SPACE ||
 551                      c == KeyEvent.VK_DELETE)) {
 552             getToolkit().beep();
 553             e.consume();
 554         }
 555     }
 556 
 557     public void setVisible(boolean b) {
 558         boolean wasVisible = isVisible();
 559         super.setVisible(b);
 560         if (b && !wasVisible) {
 561             SwingUtilities.invokeLater(new Runnable() {
 562                 public void run() {
 563                     if (remoteRadioButton.isSelected()) {
 564                         remoteTF.requestFocus();
 565                         remoteTF.selectAll();
 566                     }
 567                 }
 568             });
 569         }
 570     }
 571 
 572     public void keyPressed(KeyEvent e) {
 573     }
 574 
 575     public void keyReleased(KeyEvent e) {
 576     }
 577 
 578 
 579     // ListSelectionListener interface
 580     public void valueChanged(ListSelectionEvent e) {
 581         updateButtonStates();
 582         String labelText = " "; // Non-empty to reserve vertical space
 583         int row = vmTable.getSelectedRow();
 584         if (row >= 0) {
 585             LocalVirtualMachine lvm = vmModel.vmAt(row);
 586             if (!lvm.isManageable()) {
 587                 if (lvm.isAttachable()) {
 588                     labelText = Messages.MANAGEMENT_WILL_BE_ENABLED;
 589                 } else {
 590                     labelText = Messages.MANAGEMENT_NOT_ENABLED;
 591                 }
 592             }
 593         }
 594         String colorStr =
 595             String.format("%06x", hintTextColor.getRGB() & 0xFFFFFF);
 596         localMessageLabel.setText("<html><font color=#" + colorStr + ">" + labelText);
 597     }
 598     // ----
 599 
 600 
 601     // Refresh the list of managed VMs
 602     public void refresh() {
 603         if (vmModel != null) {
 604             // Remember selection
 605             LocalVirtualMachine selected = null;
 606             int row = vmTable.getSelectedRow();
 607             if (row >= 0) {
 608                 selected = vmModel.vmAt(row);
 609             }
 610 
 611             vmModel.refresh();
 612 
 613             int selectRow = -1;
 614             int n = vmModel.getRowCount();
 615             if (selected != null) {
 616                 for (int i = 0; i < n; i++) {
 617                     LocalVirtualMachine lvm = vmModel.vmAt(i);
 618                     if (selected.vmid() == lvm.vmid() &&
 619                         selected.toString().equals(lvm.toString())) {
 620 
 621                         selectRow = i;
 622                         break;
 623                     }
 624                 }
 625             }
 626             if (selectRow > -1) {
 627                 vmTable.setRowSelectionInterval(selectRow, selectRow);
 628             } else {
 629                 vmTable.getSelectionModel().clearSelection();
 630             }
 631 
 632             Dimension dim = vmTable.getPreferredSize();
 633 
 634             // Tricky. Reduce height by one to avoid double line at bottom,
 635             // but that causes a scroll bar to appear, so remove it.
 636             dim.height = Math.min(dim.height-1, 100);
 637             localTableScrollPane.setVerticalScrollBarPolicy((dim.height < 100)
 638                                                 ? JScrollPane.VERTICAL_SCROLLBAR_NEVER
 639                                                 : JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
 640             localTableScrollPane.getViewport().setMinimumSize(dim);
 641             localTableScrollPane.getViewport().setPreferredSize(dim);
 642         }
 643         pack();
 644         setLocationRelativeTo(jConsole);
 645     }
 646 
 647     // Represents the list of managed VMs as a tabular data model.
 648     private static class ManagedVmTableModel extends AbstractTableModel {
 649         private static String[] columnNames = {
 650             Messages.COLUMN_NAME,
 651             Messages.COLUMN_PID,
 652         };
 653 
 654         private List<LocalVirtualMachine> vmList;
 655 
 656         public int getColumnCount() {
 657             return columnNames.length;
 658         }
 659 
 660         public String getColumnName(int col) {
 661             return columnNames[col];
 662         }
 663 
 664         public synchronized int getRowCount() {
 665             return vmList.size();
 666         }
 667 
 668         public synchronized Object getValueAt(int row, int col) {
 669             assert col >= 0 && col <= columnNames.length;
 670             LocalVirtualMachine vm = vmList.get(row);
 671             switch (col) {
 672                 case COL_NAME: return vm.displayName();
 673                 case COL_PID:  return vm.vmid();
 674                 default: return null;
 675             }
 676         }
 677 
 678         public Class<?> getColumnClass(int column) {
 679             switch (column) {
 680                 case COL_NAME: return String.class;
 681                 case COL_PID:  return Integer.class;
 682                 default: return super.getColumnClass(column);
 683             }
 684         }
 685 
 686         public ManagedVmTableModel() {
 687             refresh();
 688         }
 689 
 690 
 691         public synchronized LocalVirtualMachine vmAt(int pos) {
 692             return vmList.get(pos);
 693         }
 694 
 695         public synchronized void refresh() {
 696             Map<Integer, LocalVirtualMachine> map =
 697                 LocalVirtualMachine.getAllVirtualMachines();
 698             vmList = new ArrayList<LocalVirtualMachine>();
 699             vmList.addAll(map.values());
 700 
 701             // data has changed
 702             fireTableDataChanged();
 703         }
 704     }
 705 
 706     // A blank component that takes up as much space as the
 707     // button part of a JRadioButton.
 708     private static class Padder extends JPanel {
 709         JRadioButton radioButton;
 710 
 711         Padder(JRadioButton radioButton) {
 712             this.radioButton = radioButton;
 713 
 714             setAccessibleName(this, Messages.BLANK);
 715         }
 716 
 717         public Dimension getPreferredSize() {
 718             Rectangle r = getTextRectangle(radioButton);
 719             int w = (r != null && r.x > 8) ? r.x : 22;
 720 
 721             return new Dimension(w, 0);
 722         }
 723 
 724         private static Rectangle getTextRectangle(AbstractButton button) {
 725             String text = button.getText();
 726             Icon icon = (button.isEnabled()) ? button.getIcon() : button.getDisabledIcon();
 727 
 728             if (icon == null && button.getUI() instanceof BasicRadioButtonUI) {
 729                 icon = ((BasicRadioButtonUI)button.getUI()).getDefaultIcon();
 730             }
 731 
 732             if ((icon == null) && (text == null)) {
 733                 return null;
 734             }
 735 
 736             Rectangle paintIconR = new Rectangle();
 737             Rectangle paintTextR = new Rectangle();
 738             Rectangle paintViewR = new Rectangle();
 739             Insets paintViewInsets = new Insets(0, 0, 0, 0);
 740 
 741             paintViewInsets = button.getInsets(paintViewInsets);
 742             paintViewR.x = paintViewInsets.left;
 743             paintViewR.y = paintViewInsets.top;
 744             paintViewR.width = button.getWidth() - (paintViewInsets.left + paintViewInsets.right);
 745             paintViewR.height = button.getHeight() - (paintViewInsets.top + paintViewInsets.bottom);
 746 
 747             Graphics g = button.getGraphics();
 748             if (g == null) {
 749                 return null;
 750             }
 751                 SwingUtilities.layoutCompoundLabel(button,
 752                                                    g.getFontMetrics(),
 753                                                    text,
 754                                                    icon,
 755                                                    button.getVerticalAlignment(),
 756                                                    button.getHorizontalAlignment(),
 757                                                    button.getVerticalTextPosition(),
 758                                                    button.getHorizontalTextPosition(),
 759                                                    paintViewR,
 760                                                    paintIconR,
 761                                                    paintTextR,
 762                                                    button.getIconTextGap());
 763 
 764             return paintTextR;
 765         }
 766     }
 767 
 768 }