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