1 /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. 2 * Copyright (C) 2011-2019 Brian P. Hinz 3 * 4 * This is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This software is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this software; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 * USA. 18 */ 19 20 package com.tigervnc.vncviewer; 21 22 import java.awt.*; 23 import java.awt.event.*; 24 import java.io.File; 25 import java.lang.reflect.*; 26 import java.text.Format; 27 import java.text.NumberFormat; 28 import javax.swing.*; 29 import javax.swing.border.*; 30 import javax.swing.filechooser.*; 31 import javax.swing.UIManager.*; 32 import javax.swing.text.*; 33 import java.util.*; 34 import java.util.List; 35 import java.util.Map.Entry; 36 import java.util.prefs.*; 37 38 import com.tigervnc.rfb.*; 39 40 import static java.awt.GridBagConstraints.BOTH; 41 import static java.awt.GridBagConstraints.CENTER; 42 import static java.awt.GridBagConstraints.HORIZONTAL; 43 import static java.awt.GridBagConstraints.LINE_END; 44 import static java.awt.GridBagConstraints.LINE_START; 45 import static java.awt.GridBagConstraints.PAGE_START; 46 import static java.awt.GridBagConstraints.NONE; 47 import static java.awt.GridBagConstraints.RELATIVE; 48 import static java.awt.GridBagConstraints.REMAINDER; 49 import static java.awt.GridBagConstraints.VERTICAL; 50 51 import static com.tigervnc.vncviewer.Parameters.*; 52 53 class OptionsDialog extends Dialog { 54 55 private class IntegerDocument extends PlainDocument { 56 private int limit; 57 IntegerDocument(int max)58 public IntegerDocument(int max) { 59 super(); 60 limit = max; 61 } 62 insertString(int offset, String str, AttributeSet a)63 public void insertString(int offset, String str, AttributeSet a) 64 throws BadLocationException { 65 if (str == null || !str.matches("^[0-9]+$")) return; 66 if ((getLength() + str.length()) > limit) 67 Toolkit.getDefaultToolkit().beep(); 68 else 69 super.insertString(offset, str, a); 70 } 71 } 72 73 private class IntegerTextField extends JFormattedTextField { IntegerTextField(int digits)74 public IntegerTextField(int digits) { 75 super(); 76 setDocument(new IntegerDocument(digits)); 77 Font f = getFont(); 78 String template = String.format("%0"+digits+"d", 0); 79 int w = getFontMetrics(f).stringWidth(template) + 80 getMargin().left + getMargin().right + 81 getInsets().left + getInsets().right; 82 int h = getPreferredSize().height; 83 setPreferredSize(new Dimension(w, h)); 84 } 85 86 @Override processFocusEvent(final FocusEvent e)87 protected void processFocusEvent(final FocusEvent e) { 88 if (e.isTemporary()) 89 return; 90 if (e.getID() == FocusEvent.FOCUS_LOST) 91 if (getText() == null || getText().isEmpty()) 92 setValue(null); 93 super.processFocusEvent(e); 94 } 95 } 96 97 private static Map<Object, String> callbacks = new HashMap<Object, String>(); 98 /* Compression */ 99 JCheckBox autoselectCheckbox; 100 101 ButtonGroup encodingGroup; 102 JRadioButton tightButton; 103 JRadioButton zrleButton; 104 JRadioButton hextileButton; 105 JRadioButton rawButton; 106 107 ButtonGroup colorlevelGroup; 108 JRadioButton fullcolorButton; 109 JRadioButton mediumcolorButton; 110 JRadioButton lowcolorButton; 111 JRadioButton verylowcolorButton; 112 113 JCheckBox compressionCheckbox; 114 JCheckBox jpegCheckbox; 115 JComboBox compressionInput; 116 JComboBox jpegInput; 117 118 /* Security */ 119 JCheckBox encNoneCheckbox; 120 JCheckBox encTLSCheckbox; 121 JCheckBox encX509Checkbox; 122 JTextField caInput; 123 JTextField crlInput; 124 JButton caChooser; 125 JButton crlChooser; 126 127 JCheckBox authNoneCheckbox; 128 JCheckBox authVncCheckbox; 129 JCheckBox authPlainCheckbox; 130 JCheckBox authIdentCheckbox; 131 JCheckBox sendLocalUsernameCheckbox; 132 133 /* Input */ 134 JCheckBox viewOnlyCheckbox; 135 JCheckBox acceptClipboardCheckbox; 136 JCheckBox sendClipboardCheckbox; 137 JComboBox menuKeyChoice; 138 139 /* Screen */ 140 JCheckBox desktopSizeCheckbox; 141 JTextField desktopWidthInput; 142 JTextField desktopHeightInput; 143 144 ButtonGroup sizingGroup; 145 JRadioButton remoteResizeButton; 146 JRadioButton remoteScaleButton; 147 JComboBox scalingFactorInput; 148 149 JCheckBox fullScreenCheckbox; 150 JCheckBox fullScreenAllMonitorsCheckbox; 151 152 /* Misc. */ 153 JCheckBox sharedCheckbox; 154 JCheckBox dotWhenNoCursorCheckbox; 155 JCheckBox acceptBellCheckbox; 156 157 /* SSH */ 158 JCheckBox tunnelCheckbox; 159 JCheckBox viaCheckbox; 160 JTextField viaUserInput; 161 JTextField viaHostInput; 162 JTextField viaPortInput; 163 JCheckBox extSSHCheckbox; 164 JTextField sshClientInput; 165 JButton sshClientChooser; 166 JRadioButton sshArgsDefaultButton; 167 JRadioButton sshArgsCustomButton; 168 JTextField sshArgsInput; 169 JTextField sshConfigInput; 170 JTextField sshKeyFileInput; 171 JButton sshConfigChooser; 172 JButton sshKeyFileChooser; 173 174 @SuppressWarnings({"rawtypes","unchecked"}) OptionsDialog()175 public OptionsDialog() { 176 super(true); 177 setTitle("VNC Viewer Options"); 178 setResizable(false); 179 180 getContentPane().setLayout( 181 new BoxLayout(getContentPane(), BoxLayout.PAGE_AXIS)); 182 183 JTabbedPane tabPane = new JTabbedPane(); 184 tabPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT); 185 186 encodingGroup = new ButtonGroup(); 187 colorlevelGroup = new ButtonGroup(); 188 189 // tabPane 190 tabPane.addTab("Compression", createCompressionPanel()); 191 tabPane.addTab("Security", createSecurityPanel()); 192 tabPane.addTab("Input", createInputPanel()); 193 tabPane.addTab("Screen", createScreenPanel()); 194 tabPane.addTab("Misc", createMiscPanel()); 195 tabPane.addTab("SSH", createSshPanel()); 196 tabPane.setBorder(BorderFactory.createEmptyBorder()); 197 // Resize the tabPane if necessary to prevent scrolling 198 int minWidth = 0; 199 Object tpi = UIManager.get("TabbedPane:TabbedPaneTabArea.contentMargins"); 200 if (tpi != null) 201 minWidth += ((Insets)tpi).left + ((Insets)tpi).right; 202 for (int i = 0; i < tabPane.getTabCount(); i++) 203 minWidth += tabPane.getBoundsAt(i).width; 204 int minHeight = tabPane.getPreferredSize().height; 205 if (tabPane.getPreferredSize().width < minWidth) 206 tabPane.setPreferredSize(new Dimension(minWidth, minHeight)); 207 208 // button pane 209 JButton okButton = new JButton("OK \u21B5"); 210 okButton.addActionListener(new ActionListener() { 211 public void actionPerformed(ActionEvent e) { 212 storeOptions(); 213 endDialog(); 214 } 215 }); 216 JButton cancelButton = new JButton("Cancel"); 217 cancelButton.addActionListener(new ActionListener() { 218 public void actionPerformed(ActionEvent e) { 219 endDialog(); 220 } 221 }); 222 223 JPanel buttonPane = new JPanel(new GridLayout(1, 5, 10, 10)); 224 buttonPane.setBorder(BorderFactory.createEmptyBorder(10, 5, 5, 5)); 225 buttonPane.add(Box.createRigidArea(new Dimension())); 226 buttonPane.add(Box.createRigidArea(new Dimension())); 227 buttonPane.add(Box.createRigidArea(new Dimension())); 228 buttonPane.add(cancelButton); 229 buttonPane.add(okButton); 230 231 this.add(tabPane); 232 this.add(buttonPane); 233 addListeners(this); 234 pack(); 235 } 236 showDialog(Container c)237 public static void showDialog(Container c) { 238 OptionsDialog dialog = new OptionsDialog(); 239 dialog.show(c); 240 } 241 show(Container c)242 public void show(Container c) { 243 loadOptions(); 244 super.showDialog(c); 245 } 246 addCallback(String cb, Object obj)247 public static void addCallback(String cb, Object obj) 248 { 249 callbacks.put(obj, cb); 250 } 251 removeCallback(Object obj)252 public static void removeCallback(Object obj) 253 { 254 callbacks.remove(obj); 255 } 256 endDialog()257 public void endDialog() { 258 super.endDialog(); 259 // Making a new dialog is so cheap that it's not worth keeping 260 this.dispose(); 261 } 262 loadOptions()263 private void loadOptions() 264 { 265 /* Compression */ 266 autoselectCheckbox.setSelected(autoSelect.getValue()); 267 268 int encNum = Encodings.encodingNum(preferredEncoding.getValueStr()); 269 270 switch (encNum) { 271 case Encodings.encodingTight: 272 tightButton.setSelected(true); 273 break; 274 case Encodings.encodingZRLE: 275 zrleButton.setSelected(true); 276 break; 277 case Encodings.encodingHextile: 278 hextileButton.setSelected(true); 279 break; 280 case Encodings.encodingRaw: 281 rawButton.setSelected(true); 282 break; 283 } 284 285 if (fullColor.getValue()) 286 fullcolorButton.setSelected(true); 287 else { 288 switch (lowColorLevel.getValue()) { 289 case 0: 290 verylowcolorButton.setSelected(true); 291 break; 292 case 1: 293 lowcolorButton.setSelected(true); 294 break; 295 case 2: 296 mediumcolorButton.setSelected(true); 297 break; 298 } 299 } 300 301 int digit = 0; 302 303 compressionCheckbox.setSelected(customCompressLevel.getValue()); 304 jpegCheckbox.setSelected(!noJpeg.getValue()); 305 digit = 0 + compressLevel.getValue(); 306 compressionInput.setSelectedItem(digit); 307 digit = 0 + qualityLevel.getValue(); 308 jpegInput.setSelectedItem(digit); 309 310 handleAutoselect(); 311 handleCompression(); 312 handleJpeg(); 313 314 /* Security */ 315 Security security = new Security(SecurityClient.secTypes); 316 317 List<Integer> secTypes; 318 Iterator<Integer> iter; 319 320 List<Integer> secTypesExt; 321 Iterator<Integer> iterExt; 322 323 encNoneCheckbox.setSelected(false); 324 encTLSCheckbox.setSelected(false); 325 encX509Checkbox.setSelected(false); 326 327 authNoneCheckbox.setSelected(false); 328 authVncCheckbox.setSelected(false); 329 authPlainCheckbox.setSelected(false); 330 authIdentCheckbox.setSelected(false); 331 sendLocalUsernameCheckbox.setSelected(sendLocalUsername.getValue()); 332 333 secTypes = security.GetEnabledSecTypes(); 334 for (iter = secTypes.iterator(); iter.hasNext(); ) { 335 switch ((Integer)iter.next()) { 336 case Security.secTypeNone: 337 encNoneCheckbox.setSelected(true); 338 authNoneCheckbox.setSelected(true); 339 break; 340 case Security.secTypeVncAuth: 341 encNoneCheckbox.setSelected(true); 342 authVncCheckbox.setSelected(true); 343 break; 344 } 345 } 346 347 secTypesExt = security.GetEnabledExtSecTypes(); 348 for (iterExt = secTypesExt.iterator(); iterExt.hasNext(); ) { 349 switch ((Integer)iterExt.next()) { 350 case Security.secTypePlain: 351 encNoneCheckbox.setSelected(true); 352 authPlainCheckbox.setSelected(true); 353 break; 354 case Security.secTypeIdent: 355 encNoneCheckbox.setSelected(true); 356 authIdentCheckbox.setSelected(true); 357 break; 358 case Security.secTypeTLSNone: 359 encTLSCheckbox.setSelected(true); 360 authNoneCheckbox.setSelected(true); 361 break; 362 case Security.secTypeTLSVnc: 363 encTLSCheckbox.setSelected(true); 364 authVncCheckbox.setSelected(true); 365 break; 366 case Security.secTypeTLSPlain: 367 encTLSCheckbox.setSelected(true); 368 authPlainCheckbox.setSelected(true); 369 break; 370 case Security.secTypeTLSIdent: 371 encTLSCheckbox.setSelected(true); 372 authIdentCheckbox.setSelected(true); 373 break; 374 case Security.secTypeX509None: 375 encX509Checkbox.setSelected(true); 376 authNoneCheckbox.setSelected(true); 377 break; 378 case Security.secTypeX509Vnc: 379 encX509Checkbox.setSelected(true); 380 authVncCheckbox.setSelected(true); 381 break; 382 case Security.secTypeX509Plain: 383 encX509Checkbox.setSelected(true); 384 authPlainCheckbox.setSelected(true); 385 break; 386 case Security.secTypeX509Ident: 387 encX509Checkbox.setSelected(true); 388 authIdentCheckbox.setSelected(true); 389 break; 390 } 391 } 392 393 File caFile = new File(CSecurityTLS.X509CA.getValueStr()); 394 if (caFile.exists() && caFile.canRead()) 395 caInput.setText(caFile.getAbsolutePath()); 396 File crlFile = new File(CSecurityTLS.X509CRL.getValueStr()); 397 if (crlFile.exists() && crlFile.canRead()) 398 crlInput.setText(crlFile.getAbsolutePath()); 399 400 handleX509(); 401 handleSendLocalUsername(); 402 403 /* Input */ 404 viewOnlyCheckbox.setSelected(viewOnly.getValue()); 405 acceptClipboardCheckbox.setSelected(acceptClipboard.getValue()); 406 sendClipboardCheckbox.setSelected(sendClipboard.getValue()); 407 408 menuKeyChoice.setSelectedIndex(0); 409 410 String menuKeyStr = menuKey.getValueStr(); 411 for (int i = 0; i < menuKeyChoice.getItemCount(); i++) 412 if (menuKeyStr.equals(menuKeyChoice.getItemAt(i))) 413 menuKeyChoice.setSelectedIndex(i); 414 415 /* Screen */ 416 String width, height; 417 418 if (desktopSize.getValueStr().isEmpty() || 419 desktopSize.getValueStr().split("x").length != 2) { 420 desktopSizeCheckbox.setSelected(false); 421 desktopWidthInput.setText("1024"); 422 desktopHeightInput.setText("768"); 423 } else { 424 desktopSizeCheckbox.setSelected(true); 425 width = desktopSize.getValueStr().split("x")[0]; 426 desktopWidthInput.setText(width); 427 height = desktopSize.getValueStr().split("x")[1]; 428 desktopHeightInput.setText(height); 429 } 430 if (remoteResize.getValue()) 431 remoteResizeButton.setSelected(true); 432 else 433 remoteScaleButton.setSelected(true); 434 fullScreenCheckbox.setSelected(fullScreen.getValue()); 435 fullScreenAllMonitorsCheckbox.setSelected(fullScreenAllMonitors.getValue()); 436 437 scalingFactorInput.setSelectedItem("100%"); 438 String scaleStr = scalingFactor.getValueStr(); 439 if (scaleStr.matches("^[0-9]+$")) 440 scaleStr = scaleStr.concat("%"); 441 if (scaleStr.matches("^FixedRatio$")) 442 scaleStr = new String("Fixed Aspect Ratio"); 443 for (int i = 0; i < scalingFactorInput.getItemCount(); i++) 444 if (scaleStr.equals(scalingFactorInput.getItemAt(i))) 445 scalingFactorInput.setSelectedIndex(i); 446 447 handleDesktopSize(); 448 449 /* Misc. */ 450 sharedCheckbox.setSelected(shared.getValue()); 451 dotWhenNoCursorCheckbox.setSelected(dotWhenNoCursor.getValue()); 452 acceptBellCheckbox.setSelected(acceptBell.getValue()); 453 454 /* SSH */ 455 File f; 456 tunnelCheckbox.setSelected(tunnel.getValue() || !via.getValueStr().isEmpty()); 457 viaCheckbox.setSelected(!via.getValueStr().isEmpty()); 458 if (viaCheckbox.isSelected()) { 459 viaUserInput.setText(Tunnel.getSshUser()); 460 viaHostInput.setText(Tunnel.getSshHost()); 461 viaPortInput.setText(Integer.toString(Tunnel.getSshPort())); 462 } 463 extSSHCheckbox.setSelected(extSSH.getValue()); 464 f = new File(extSSHClient.getValueStr()); 465 if (f.exists() && f.isFile() && f.canExecute()) 466 sshClientInput.setText(f.getAbsolutePath()); 467 if (extSSHArgs.getValueStr().isEmpty()) { 468 sshArgsDefaultButton.setSelected(true); 469 } else { 470 sshArgsCustomButton.setSelected(true); 471 sshArgsInput.setText(extSSHArgs.getValueStr()); 472 } 473 f = new File(sshKeyFile.getValueStr()); 474 if (f.exists() && f.isFile() && f.canRead()) 475 sshKeyFileInput.setText(f.getAbsolutePath()); 476 f = new File(sshConfig.getValueStr()); 477 if (f.exists() && f.isFile() && f.canRead()) 478 sshConfigInput.setText(f.getAbsolutePath()); 479 480 handleTunnel(); 481 handleVia(); 482 handleExtSSH(); 483 handleRfbState(); 484 } 485 storeOptions()486 private void storeOptions() { 487 /* Compression */ 488 autoSelect.setParam(autoselectCheckbox.isSelected()); 489 490 if (tightButton.isSelected()) 491 preferredEncoding.setParam(Encodings.encodingName(Encodings.encodingTight)); 492 else if (zrleButton.isSelected()) 493 preferredEncoding.setParam(Encodings.encodingName(Encodings.encodingZRLE)); 494 else if (hextileButton.isSelected()) 495 preferredEncoding.setParam(Encodings.encodingName(Encodings.encodingHextile)); 496 else if (rawButton.isSelected()) 497 preferredEncoding.setParam(Encodings.encodingName(Encodings.encodingRaw)); 498 499 fullColor.setParam(fullcolorButton.isSelected()); 500 if (verylowcolorButton.isSelected()) 501 lowColorLevel.setParam(0); 502 else if (lowcolorButton.isSelected()) 503 lowColorLevel.setParam(1); 504 else if (mediumcolorButton.isSelected()) 505 lowColorLevel.setParam(2); 506 507 customCompressLevel.setParam(compressionCheckbox.isSelected()); 508 noJpeg.setParam(!jpegCheckbox.isSelected()); 509 compressLevel.setParam((Integer)compressionInput.getSelectedItem()); 510 qualityLevel.setParam((Integer)jpegInput.getSelectedItem()); 511 512 /* Security */ 513 Security security = new Security(); 514 515 /* Process security types which don't use encryption */ 516 if (encNoneCheckbox.isSelected()) { 517 if (authNoneCheckbox.isSelected()) 518 security.EnableSecType(Security.secTypeNone); 519 if (authVncCheckbox.isSelected()) 520 security.EnableSecType(Security.secTypeVncAuth); 521 if (authPlainCheckbox.isSelected()) 522 security.EnableSecType(Security.secTypePlain); 523 if (authIdentCheckbox.isSelected()) 524 security.EnableSecType(Security.secTypeIdent); 525 } 526 527 /* Process security types which use TLS encryption */ 528 if (encTLSCheckbox.isSelected()) { 529 if (authNoneCheckbox.isSelected()) 530 security.EnableSecType(Security.secTypeTLSNone); 531 if (authVncCheckbox.isSelected()) 532 security.EnableSecType(Security.secTypeTLSVnc); 533 if (authPlainCheckbox.isSelected()) 534 security.EnableSecType(Security.secTypeTLSPlain); 535 if (authIdentCheckbox.isSelected()) 536 security.EnableSecType(Security.secTypeTLSIdent); 537 } 538 539 /* Process security types which use X509 encryption */ 540 if (encX509Checkbox.isSelected()) { 541 if (authNoneCheckbox.isSelected()) 542 security.EnableSecType(Security.secTypeX509None); 543 if (authVncCheckbox.isSelected()) 544 security.EnableSecType(Security.secTypeX509Vnc); 545 if (authPlainCheckbox.isSelected()) 546 security.EnableSecType(Security.secTypeX509Plain); 547 if (authIdentCheckbox.isSelected()) 548 security.EnableSecType(Security.secTypeX509Ident); 549 } 550 551 if (authIdentCheckbox.isSelected() || 552 authPlainCheckbox.isSelected()) { 553 sendLocalUsername.setParam(sendLocalUsernameCheckbox.isSelected()); 554 } 555 556 SecurityClient.secTypes.setParam(security.ToString()); 557 558 File caFile = new File(caInput.getText()); 559 if (caFile.exists() && caFile.canRead()) 560 CSecurityTLS.X509CA.setParam(caFile.getAbsolutePath()); 561 File crlFile = new File(crlInput.getText()); 562 if (crlFile.exists() && crlFile.canRead()) 563 CSecurityTLS.X509CRL.setParam(crlFile.getAbsolutePath()); 564 565 /* Input */ 566 viewOnly.setParam(viewOnlyCheckbox.isSelected()); 567 acceptClipboard.setParam(acceptClipboardCheckbox.isSelected()); 568 sendClipboard.setParam(sendClipboardCheckbox.isSelected()); 569 570 String menuKeyStr = 571 MenuKey.getMenuKeySymbols()[menuKeyChoice.getSelectedIndex()].name; 572 menuKey.setParam(menuKeyStr); 573 574 /* Screen */ 575 if (desktopSizeCheckbox.isSelected() && 576 !desktopWidthInput.getText().isEmpty() && 577 !desktopHeightInput.getText().isEmpty()) { 578 String width = desktopWidthInput.getText(); 579 String height = desktopHeightInput.getText(); 580 desktopSize.setParam(width.concat("x").concat(height)); 581 } else { 582 desktopSize.setParam(""); 583 } 584 remoteResize.setParam(remoteResizeButton.isSelected()); 585 fullScreen.setParam(fullScreenCheckbox.isSelected()); 586 fullScreenAllMonitors.setParam(fullScreenAllMonitorsCheckbox.isSelected()); 587 588 String scaleStr = 589 ((String)scalingFactorInput.getSelectedItem()).replace("%", ""); 590 scaleStr.replace("Fixed Aspect Ratio", "FixedRatio"); 591 scalingFactor.setParam(scaleStr); 592 593 /* Misc. */ 594 shared.setParam(sharedCheckbox.isSelected()); 595 dotWhenNoCursor.setParam(dotWhenNoCursorCheckbox.isSelected()); 596 acceptBell.setParam(acceptBellCheckbox.isSelected()); 597 598 /* SSH */ 599 tunnel.setParam(tunnelCheckbox.isSelected()); 600 if (viaCheckbox.isSelected() && 601 !viaUserInput.getText().isEmpty() && 602 !viaHostInput.getText().isEmpty() && 603 !viaPortInput.getText().isEmpty()) { 604 String sshUser = viaUserInput.getText(); 605 String sshHost = viaHostInput.getText(); 606 String sshPort = viaPortInput.getText(); 607 String viaStr = sshUser.concat("@").concat(sshHost).concat(":").concat(sshPort); 608 via.setParam(viaStr); 609 } else { 610 via.setParam(""); 611 } 612 extSSH.setParam(extSSHCheckbox.isSelected()); 613 if (!sshClientInput.getText().isEmpty()) 614 extSSHClient.setParam(sshClientInput.getText()); 615 if (sshArgsCustomButton.isSelected() && 616 !sshArgsInput.getText().isEmpty()) { 617 extSSHArgs.setParam(sshArgsInput.getText()); 618 } else { 619 extSSHArgs.setParam(new String()); 620 } 621 if (!sshConfigInput.getText().isEmpty()) 622 sshConfig.setParam(sshConfigInput.getText()); 623 if (!sshKeyFileInput.getText().isEmpty()) 624 sshKeyFile.setParam(sshKeyFileInput.getText()); 625 626 try { 627 for (Map.Entry<Object, String> iter : callbacks.entrySet()) { 628 Object obj = iter.getKey(); 629 Method cb = obj.getClass().getMethod(iter.getValue(), new Class[]{}); 630 if (cb == null) 631 vlog.info(obj.getClass().getName()); 632 cb.invoke(obj); 633 } 634 } catch (NoSuchMethodException e) { 635 vlog.error("NoSuchMethodException: "+e.getMessage()); 636 } catch (IllegalAccessException e) { 637 vlog.error("IllegalAccessException: "+e.getMessage()); 638 } catch (InvocationTargetException e) { 639 vlog.error("InvocationTargetException: "+e.getMessage()); 640 } 641 } 642 createCompressionPanel()643 private JPanel createCompressionPanel() { 644 JPanel FormatPanel = new JPanel(); 645 FormatPanel.setLayout(new BoxLayout(FormatPanel, 646 BoxLayout.PAGE_AXIS)); 647 FormatPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5)); 648 649 JPanel autoSelectPane = new JPanel(); 650 autoSelectPane.setLayout(new BoxLayout(autoSelectPane, 651 BoxLayout.LINE_AXIS)); 652 autoSelectPane.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0)); 653 autoselectCheckbox = new JCheckBox("Auto Select"); 654 autoselectCheckbox.addItemListener(new ItemListener() { 655 public void itemStateChanged(ItemEvent e) { 656 handleAutoselect(); 657 } 658 }); 659 autoSelectPane.add(autoselectCheckbox); 660 autoSelectPane.add(Box.createHorizontalGlue()); 661 662 JPanel encodingPanel = new JPanel(new GridLayout(4, 1)); 663 encodingPanel.setBorder(BorderFactory.createTitledBorder("Preferred encoding")); 664 tightButton = new GroupedJRadioButton("Tight", encodingGroup, encodingPanel); 665 zrleButton = new GroupedJRadioButton("ZRLE", encodingGroup, encodingPanel); 666 hextileButton = new GroupedJRadioButton("Hextile", encodingGroup, encodingPanel); 667 rawButton = new GroupedJRadioButton("Raw", encodingGroup, encodingPanel); 668 669 JPanel colorPanel = new JPanel(new GridLayout(4, 1)); 670 colorPanel.setBorder(BorderFactory.createTitledBorder("Color level")); 671 fullcolorButton = new GroupedJRadioButton("Full", colorlevelGroup, colorPanel); 672 mediumcolorButton = new GroupedJRadioButton("Medium", colorlevelGroup, colorPanel); 673 lowcolorButton = new GroupedJRadioButton("Low", colorlevelGroup, colorPanel); 674 verylowcolorButton = new GroupedJRadioButton("Very low", colorlevelGroup, colorPanel); 675 676 JPanel encodingPane = new JPanel(new GridLayout(1, 2, 5, 0)); 677 encodingPane.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0)); 678 encodingPane.add(encodingPanel); 679 encodingPane.add(colorPanel); 680 681 JPanel tightPanel = new JPanel(new GridBagLayout()); 682 compressionCheckbox = new JCheckBox("Custom Compression Level"); 683 compressionCheckbox.addItemListener(new ItemListener() { 684 public void itemStateChanged(ItemEvent e) { 685 handleCompression(); 686 } 687 }); 688 Object[] compressionLevels = { 1, 2, 3, 4, 5, 6 }; 689 compressionInput = new MyJComboBox(compressionLevels); 690 ((MyJComboBox)compressionInput).setDocument(new IntegerDocument(1)); 691 compressionInput.setPrototypeDisplayValue("0."); 692 compressionInput.setEditable(true); 693 JLabel compressionLabel = 694 new JLabel("Level (0=fast, 9=best)"); 695 jpegCheckbox = new JCheckBox("Allow JPEG Compression"); 696 jpegCheckbox.addItemListener(new ItemListener() { 697 public void itemStateChanged(ItemEvent e) { 698 handleJpeg(); 699 } 700 }); 701 Object[] qualityLevels = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 702 jpegInput = new MyJComboBox(qualityLevels); 703 jpegInput.setPrototypeDisplayValue("0."); 704 JLabel qualityLabel = new JLabel("Quality (0=poor, 9=best)"); 705 706 tightPanel.add(compressionCheckbox, 707 new GridBagConstraints(0, 0, 708 REMAINDER, 1, 709 LIGHT, LIGHT, 710 LINE_START, NONE, 711 new Insets(0, 0, 0, 0), 712 NONE, NONE)); 713 int indent = getButtonLabelInset(compressionCheckbox); 714 tightPanel.add(compressionInput, 715 new GridBagConstraints(0, 1, 716 1, 1, 717 LIGHT, LIGHT, 718 LINE_START, NONE, 719 new Insets(0, indent, 0, 0), 720 NONE, NONE)); 721 tightPanel.add(compressionLabel, 722 new GridBagConstraints(1, 1, 723 1, 1, 724 HEAVY, LIGHT, 725 LINE_START, HORIZONTAL, 726 new Insets(0, 5, 0, 0), 727 NONE, NONE)); 728 tightPanel.add(jpegCheckbox, 729 new GridBagConstraints(0, 2, 730 REMAINDER, 1, 731 LIGHT, LIGHT, 732 LINE_START, NONE, 733 new Insets(5, 0, 0, 0), 734 NONE, NONE)); 735 indent = getButtonLabelInset(jpegCheckbox); 736 tightPanel.add(jpegInput, 737 new GridBagConstraints(0, 3, 738 1, 1, 739 LIGHT, LIGHT, 740 LINE_START, NONE, 741 new Insets(0, indent, 0, 0), 742 NONE, NONE)); 743 tightPanel.add(qualityLabel, 744 new GridBagConstraints(1, 3, 745 1, 1, 746 HEAVY, NONE, 747 LINE_START, HORIZONTAL, 748 new Insets(0, 5, 0, 0), 749 NONE, NONE)); 750 tightPanel.add(Box.createRigidArea(new Dimension(5,0)), 751 new GridBagConstraints(0, 4, 752 REMAINDER, REMAINDER, 753 HEAVY, HEAVY, 754 LINE_START, BOTH, 755 new Insets(0, 0, 0, 0), 756 NONE, NONE)); 757 FormatPanel.add(autoSelectPane); 758 FormatPanel.add(encodingPane); 759 FormatPanel.add(tightPanel); 760 return FormatPanel; 761 } 762 createSecurityPanel()763 private JPanel createSecurityPanel() { 764 JPanel SecPanel = new JPanel(); 765 SecPanel.setLayout(new BoxLayout(SecPanel, 766 BoxLayout.PAGE_AXIS)); 767 SecPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5)); 768 769 JPanel vencryptPane = new JPanel(); 770 vencryptPane.setLayout(new BoxLayout(vencryptPane, 771 BoxLayout.LINE_AXIS)); 772 vencryptPane.setBorder(BorderFactory.createEmptyBorder(0,0,5,0)); 773 774 JPanel encrPanel = new JPanel(new GridBagLayout()); 775 encrPanel.setBorder(BorderFactory.createTitledBorder("Encryption")); 776 encNoneCheckbox = new JCheckBox("None"); 777 encTLSCheckbox = new JCheckBox("Anonymous TLS"); 778 encX509Checkbox = new JCheckBox("TLS with X.509 certificates"); 779 encX509Checkbox.addItemListener(new ItemListener() { 780 public void itemStateChanged(ItemEvent e) { 781 handleX509(); 782 } 783 }); 784 JLabel caLabel = new JLabel("X.509 CA Certificate"); 785 caInput = new JTextField(); 786 caChooser = new JButton("Browse"); 787 caChooser.addActionListener(new ActionListener() { 788 public void actionPerformed(ActionEvent e) { 789 JComponent c = ((JButton)e.getSource()).getRootPane(); 790 File dflt = new File(CSecurityTLS.X509CA.getValueStr()); 791 FileNameExtensionFilter filter = 792 new FileNameExtensionFilter("X.509 certificate", "crt", "cer", "pem"); 793 File f = showChooser("Path to X509 CA certificate", dflt, c, filter); 794 if (f != null && f.exists() && f.canRead()) 795 caInput.setText(f.getAbsolutePath()); 796 } 797 }); 798 JLabel crlLabel = new JLabel("X.509 CRL file"); 799 crlInput = new JTextField(); 800 crlChooser = new JButton("Browse"); 801 crlChooser.addActionListener(new ActionListener() { 802 public void actionPerformed(ActionEvent e) { 803 JComponent c = ((JButton)e.getSource()).getRootPane(); 804 File dflt = new File(CSecurityTLS.X509CRL.getValueStr()); 805 FileNameExtensionFilter filter = 806 new FileNameExtensionFilter("X.509 CRL", "crl"); 807 File f = showChooser("Path to X509 CRL file", dflt, c, filter); 808 if (f != null && f.exists() && f.canRead()) 809 crlInput.setText(f.getAbsolutePath()); 810 } 811 }); 812 encrPanel.add(encNoneCheckbox, 813 new GridBagConstraints(0, 0, 814 REMAINDER, 1, 815 HEAVY, LIGHT, 816 LINE_START, NONE, 817 new Insets(0, 0, 4, 0), 818 NONE, NONE)); 819 encrPanel.add(encTLSCheckbox, 820 new GridBagConstraints(0, 1, 821 REMAINDER, 1, 822 HEAVY, LIGHT, 823 LINE_START, NONE, 824 new Insets(0, 0, 4, 0), 825 NONE, NONE)); 826 encrPanel.add(encX509Checkbox, 827 new GridBagConstraints(0, 2, 828 3, 1, 829 HEAVY, LIGHT, 830 LINE_START, NONE, 831 new Insets(0, 0, 0, 0), 832 NONE, NONE)); 833 int indent = getButtonLabelInset(encX509Checkbox); 834 encrPanel.add(caLabel, 835 new GridBagConstraints(0, 3, 836 1, 1, 837 LIGHT, LIGHT, 838 LINE_END, NONE, 839 new Insets(0, indent, 5, 0), 840 0, 0)); 841 encrPanel.add(caInput, 842 new GridBagConstraints(1, 3, 843 1, 1, 844 HEAVY, LIGHT, 845 LINE_START, HORIZONTAL, 846 new Insets(0, 5, 5, 0), 847 0, 0)); 848 encrPanel.add(caChooser, 849 new GridBagConstraints(2, 3, 850 1, 1, 851 LIGHT, LIGHT, 852 LINE_START, VERTICAL, 853 new Insets(0, 5, 5, 0), 854 0, 0)); 855 encrPanel.add(crlLabel, 856 new GridBagConstraints(0, 4, 857 1, 1, 858 LIGHT, LIGHT, 859 LINE_END, NONE, 860 new Insets(0, indent, 0, 0), 861 0, 0)); 862 encrPanel.add(crlInput, 863 new GridBagConstraints(1, 4, 864 1, 1, 865 HEAVY, LIGHT, 866 LINE_START, HORIZONTAL, 867 new Insets(0, 5, 0, 0), 868 0, 0)); 869 encrPanel.add(crlChooser, 870 new GridBagConstraints(2, 4, 871 1, 1, 872 LIGHT, LIGHT, 873 LINE_START, VERTICAL, 874 new Insets(0, 5, 0, 0), 875 0, 0)); 876 877 JPanel authPanel = new JPanel(new GridBagLayout()); 878 authPanel.setBorder(BorderFactory.createTitledBorder("Authentication")); 879 880 authNoneCheckbox = new JCheckBox("None"); 881 authVncCheckbox = new JCheckBox("Standard VNC"); 882 authPlainCheckbox = new JCheckBox("Plaintext"); 883 authPlainCheckbox.addItemListener(new ItemListener() { 884 public void itemStateChanged(ItemEvent e) { 885 handleSendLocalUsername(); 886 } 887 }); 888 authIdentCheckbox = new JCheckBox("Ident"); 889 authIdentCheckbox.addItemListener(new ItemListener() { 890 public void itemStateChanged(ItemEvent e) { 891 handleSendLocalUsername(); 892 } 893 }); 894 sendLocalUsernameCheckbox = new JCheckBox("Send Local Username"); 895 authPanel.add(authNoneCheckbox, 896 new GridBagConstraints(0, 0, 897 REMAINDER, 1, 898 LIGHT, LIGHT, 899 LINE_START, NONE, 900 new Insets(0, 0, 4, 0), 901 NONE, NONE)); 902 authPanel.add(authVncCheckbox, 903 new GridBagConstraints(0, 1, 904 REMAINDER, 1, 905 LIGHT, LIGHT, 906 LINE_START, NONE, 907 new Insets(0, 0, 4, 0), 908 NONE, NONE)); 909 authPanel.add(authPlainCheckbox, 910 new GridBagConstraints(0, 2, 911 1, 1, 912 LIGHT, LIGHT, 913 LINE_START, NONE, 914 new Insets(0, 0, 2, 0), 915 NONE, NONE)); 916 authPanel.add(authIdentCheckbox, 917 new GridBagConstraints(0, 3, 918 1, 1, 919 LIGHT, LIGHT, 920 LINE_START, NONE, 921 new Insets(2, 0, 0, 0), 922 NONE, NONE)); 923 authPanel.add(sendLocalUsernameCheckbox, 924 new GridBagConstraints(1, 2, 925 1, 2, 926 HEAVY, LIGHT, 927 LINE_START, NONE, 928 new Insets(2, 20, 2, 0), 929 NONE, NONE)); 930 931 SecPanel.add(vencryptPane, 932 new GridBagConstraints(0, 0, 933 REMAINDER, 1, 934 LIGHT, LIGHT, 935 LINE_START, HORIZONTAL, 936 new Insets(0, 0, 4, 0), 937 NONE, NONE)); 938 SecPanel.add(encrPanel, 939 new GridBagConstraints(0, 1, 940 REMAINDER, 1, 941 LIGHT, LIGHT, 942 LINE_START, HORIZONTAL, 943 new Insets(0, 0, 4, 0), 944 NONE, NONE)); 945 SecPanel.add(authPanel, 946 new GridBagConstraints(0, 2, 947 REMAINDER, 1, 948 LIGHT, LIGHT, 949 LINE_START, HORIZONTAL, 950 new Insets(0, 0, 4, 0), 951 NONE, NONE)); 952 SecPanel.add(Box.createRigidArea(new Dimension(0,0)), 953 new GridBagConstraints(0, RELATIVE, 954 REMAINDER, REMAINDER, 955 HEAVY, HEAVY, 956 LINE_START, BOTH, 957 new Insets(0, 0, 0, 0), 958 NONE, NONE)); 959 return SecPanel; 960 } 961 createInputPanel()962 private JPanel createInputPanel() { 963 JPanel inputPanel = new JPanel(new GridBagLayout()); 964 inputPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5)); 965 966 viewOnlyCheckbox = new JCheckBox("View only (ignore mouse and keyboard)"); 967 acceptClipboardCheckbox = new JCheckBox("Accept clipboard from server"); 968 sendClipboardCheckbox = new JCheckBox("Send clipboard to server"); 969 JLabel menuKeyLabel = new JLabel("Menu key"); 970 String[] menuKeys = new String[MenuKey.getMenuKeySymbolCount()]; 971 //menuKeys[0] = "None"; 972 for (int i = 0; i < MenuKey.getMenuKeySymbolCount(); i++) 973 menuKeys[i] = MenuKey.getKeyText(MenuKey.getMenuKeySymbols()[i]); 974 menuKeyChoice = new JComboBox(menuKeys); 975 976 inputPanel.add(viewOnlyCheckbox, 977 new GridBagConstraints(0, 0, 978 REMAINDER, 1, 979 HEAVY, LIGHT, 980 LINE_START, NONE, 981 new Insets(0, 0, 4, 0), 982 NONE, NONE)); 983 inputPanel.add(acceptClipboardCheckbox, 984 new GridBagConstraints(0, 1, 985 REMAINDER, 1, 986 HEAVY, LIGHT, 987 LINE_START, NONE, 988 new Insets(0, 0, 4, 0), 989 NONE, NONE)); 990 inputPanel.add(sendClipboardCheckbox, 991 new GridBagConstraints(0, 2, 992 REMAINDER, 1, 993 HEAVY, LIGHT, 994 LINE_START, NONE, 995 new Insets(0, 0, 4, 0), 996 NONE, NONE)); 997 inputPanel.add(menuKeyLabel, 998 new GridBagConstraints(0, 3, 999 1, 1, 1000 LIGHT, LIGHT, 1001 LINE_START, NONE, 1002 new Insets(0, 0, 0, 0), 1003 NONE, NONE)); 1004 inputPanel.add(menuKeyChoice, 1005 new GridBagConstraints(1, 3, 1006 1, 1, 1007 HEAVY, LIGHT, 1008 LINE_START, NONE, 1009 new Insets(0, 5, 0, 0), 1010 NONE, NONE)); 1011 inputPanel.add(Box.createRigidArea(new Dimension(5, 0)), 1012 new GridBagConstraints(0, 4, 1013 REMAINDER, REMAINDER, 1014 HEAVY, HEAVY, 1015 LINE_START, BOTH, 1016 new Insets(0, 0, 0, 0), 1017 NONE, NONE)); 1018 return inputPanel; 1019 } 1020 createScreenPanel()1021 private JPanel createScreenPanel() { 1022 JPanel ScreenPanel = new JPanel(new GridBagLayout()); 1023 ScreenPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5)); 1024 1025 JPanel SizingPanel = new JPanel(new GridBagLayout()); 1026 SizingPanel.setBorder(BorderFactory.createTitledBorder("Desktop Sizing")); 1027 desktopSizeCheckbox = new JCheckBox("Resize remote session on connect"); 1028 desktopSizeCheckbox.addItemListener(new ItemListener() { 1029 public void itemStateChanged(ItemEvent e) { 1030 handleDesktopSize(); 1031 } 1032 }); 1033 desktopWidthInput = new IntegerTextField(5); 1034 desktopHeightInput = new IntegerTextField(5); 1035 JPanel desktopSizePanel = 1036 new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0)); 1037 desktopSizePanel.add(desktopWidthInput); 1038 desktopSizePanel.add(new JLabel(" x ")); 1039 desktopSizePanel.add(desktopHeightInput); 1040 sizingGroup = new ButtonGroup(); 1041 remoteResizeButton = 1042 new JRadioButton("Resize remote session to the local window"); 1043 sizingGroup.add(remoteResizeButton); 1044 remoteScaleButton = 1045 new JRadioButton("Scale remote session to the local window"); 1046 sizingGroup.add(remoteScaleButton); 1047 remoteResizeButton.addItemListener(new ItemListener() { 1048 public void itemStateChanged(ItemEvent e) { 1049 handleRemoteResize(); 1050 } 1051 }); 1052 JLabel scalingFactorLabel = new JLabel("Scaling Factor"); 1053 Object[] scalingFactors = { 1054 "Auto", "Fixed Aspect Ratio", "50%", "75%", "95%", "100%", "105%", 1055 "125%", "150%", "175%", "200%", "250%", "300%", "350%", "400%" }; 1056 scalingFactorInput = new MyJComboBox(scalingFactors); 1057 scalingFactorInput.setEditable(true); 1058 fullScreenCheckbox = new JCheckBox("Full-screen mode"); 1059 fullScreenAllMonitorsCheckbox = 1060 new JCheckBox("Enable full-screen mode over all monitors"); 1061 SizingPanel.add(desktopSizeCheckbox, 1062 new GridBagConstraints(0, 0, 1063 REMAINDER, 1, 1064 LIGHT, LIGHT, 1065 LINE_START, NONE, 1066 new Insets(0, 0, 0, 0), 1067 NONE, NONE)); 1068 int indent = getButtonLabelInset(desktopSizeCheckbox); 1069 SizingPanel.add(desktopSizePanel, 1070 new GridBagConstraints(0, 1, 1071 REMAINDER, 1, 1072 LIGHT, LIGHT, 1073 LINE_START, NONE, 1074 new Insets(0, indent, 0, 0), 1075 NONE, NONE)); 1076 SizingPanel.add(remoteResizeButton, 1077 new GridBagConstraints(0, 2, 1078 REMAINDER, 1, 1079 LIGHT, LIGHT, 1080 LINE_START, NONE, 1081 new Insets(0, 0, 4, 0), 1082 NONE, NONE)); 1083 SizingPanel.add(remoteScaleButton, 1084 new GridBagConstraints(0, 3, 1085 REMAINDER, 1, 1086 LIGHT, LIGHT, 1087 LINE_START, NONE, 1088 new Insets(0, 0, 4, 0), 1089 NONE, NONE)); 1090 indent = getButtonLabelInset(remoteScaleButton); 1091 SizingPanel.add(scalingFactorLabel, 1092 new GridBagConstraints(0, 4, 1093 1, 1, 1094 LIGHT, LIGHT, 1095 LINE_START, NONE, 1096 new Insets(0, indent, 4, 0), 1097 NONE, NONE)); 1098 SizingPanel.add(scalingFactorInput, 1099 new GridBagConstraints(1, 4, 1100 1, 1, 1101 HEAVY, LIGHT, 1102 LINE_START, NONE, 1103 new Insets(0, 5, 4, 0), 1104 NONE, NONE)); 1105 ScreenPanel.add(SizingPanel, 1106 new GridBagConstraints(0, 0, 1107 REMAINDER, 1, 1108 LIGHT, LIGHT, 1109 LINE_START, HORIZONTAL, 1110 new Insets(0, 0, 4, 0), 1111 NONE, NONE)); 1112 ScreenPanel.add(fullScreenCheckbox, 1113 new GridBagConstraints(0, 1, 1114 REMAINDER, 1, 1115 LIGHT, LIGHT, 1116 LINE_START, NONE, 1117 new Insets(0, 0, 4, 0), 1118 NONE, NONE)); 1119 indent = getButtonLabelInset(fullScreenCheckbox); 1120 ScreenPanel.add(fullScreenAllMonitorsCheckbox, 1121 new GridBagConstraints(0, 2, 1122 REMAINDER, 1, 1123 LIGHT, LIGHT, 1124 LINE_START, NONE, 1125 new Insets(0, indent, 4, 0), 1126 NONE, NONE)); 1127 ScreenPanel.add(Box.createRigidArea(new Dimension(5, 0)), 1128 new GridBagConstraints(0, 3, 1129 REMAINDER, REMAINDER, 1130 HEAVY, HEAVY, 1131 LINE_START, BOTH, 1132 new Insets(0, 0, 0, 0), 1133 NONE, NONE)); 1134 return ScreenPanel; 1135 } 1136 createMiscPanel()1137 private JPanel createMiscPanel() { 1138 JPanel MiscPanel = new JPanel(new GridBagLayout()); 1139 MiscPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5)); 1140 sharedCheckbox = 1141 new JCheckBox("Shared (don't disconnect other viewers)"); 1142 dotWhenNoCursorCheckbox = new JCheckBox("Show dot when no cursor"); 1143 acceptBellCheckbox = new JCheckBox("Beep when requested by the server"); 1144 MiscPanel.add(sharedCheckbox, 1145 new GridBagConstraints(0, 0, 1146 1, 1, 1147 LIGHT, LIGHT, 1148 LINE_START, NONE, 1149 new Insets(0, 0, 4, 0), 1150 NONE, NONE)); 1151 MiscPanel.add(dotWhenNoCursorCheckbox, 1152 new GridBagConstraints(0, 1, 1153 1, 1, 1154 LIGHT, LIGHT, 1155 LINE_START, NONE, 1156 new Insets(0, 0, 4, 0), 1157 NONE, NONE)); 1158 MiscPanel.add(acceptBellCheckbox, 1159 new GridBagConstraints(0, 2, 1160 1, 1, 1161 LIGHT, LIGHT, 1162 LINE_START, NONE, 1163 new Insets(0, 0, 4, 0), 1164 NONE, NONE)); 1165 MiscPanel.add(Box.createRigidArea(new Dimension(5, 0)), 1166 new GridBagConstraints(0, 3, 1167 REMAINDER, REMAINDER, 1168 HEAVY, HEAVY, 1169 LINE_START, BOTH, 1170 new Insets(0, 0, 0, 0), 1171 NONE, NONE)); 1172 return MiscPanel; 1173 } 1174 createSshPanel()1175 private JPanel createSshPanel() { 1176 JPanel sshPanel = new JPanel(new GridBagLayout()); 1177 sshPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5)); 1178 ButtonGroup sshArgsGroup = new ButtonGroup(); 1179 tunnelCheckbox = new JCheckBox("Tunnel VNC over SSH"); 1180 tunnelCheckbox.addItemListener(new ItemListener() { 1181 public void itemStateChanged(ItemEvent e) { 1182 handleTunnel(); 1183 } 1184 }); 1185 1186 JPanel tunnelPanel = new JPanel(new GridBagLayout()); 1187 1188 viaCheckbox = new JCheckBox("Use SSH gateway"); 1189 viaCheckbox.addItemListener(new ItemListener() { 1190 public void itemStateChanged(ItemEvent e) { 1191 handleVia(); 1192 } 1193 }); 1194 JLabel sshUserLabel = new JLabel("Username"); 1195 viaUserInput = new JTextField(); 1196 JLabel sshUserAtLabel = new JLabel("@"); 1197 JLabel sshHostLabel = new JLabel("Hostname (or IP address)"); 1198 viaHostInput = new JTextField(""); 1199 JLabel sshPortLabel = new JLabel("Port"); 1200 viaPortInput = new IntegerTextField(5); 1201 1202 extSSHCheckbox = new JCheckBox("Use external SSH client"); 1203 extSSHCheckbox.addItemListener(new ItemListener() { 1204 public void itemStateChanged(ItemEvent e) { 1205 handleExtSSH(); 1206 } 1207 }); 1208 sshClientInput = new JTextField(); 1209 sshClientChooser = new JButton("Browse"); 1210 sshClientChooser.addActionListener(new ActionListener() { 1211 public void actionPerformed(ActionEvent e) { 1212 JComponent c = ((JButton)e.getSource()).getRootPane(); 1213 File dflt = new File(extSSHClient.getValueStr()); 1214 File f = showChooser("Path to external SSH client", dflt, c); 1215 if (f != null && f.exists() && f.isFile() && f.canExecute()) 1216 sshClientInput.setText(f.getAbsolutePath()); 1217 } 1218 }); 1219 JLabel sshConfigLabel = new JLabel("SSH config file"); 1220 sshConfigInput = new JTextField(); 1221 sshConfigChooser = new JButton("Browse"); 1222 sshConfigChooser.addActionListener(new ActionListener() { 1223 public void actionPerformed(ActionEvent e) { 1224 JComponent c = ((JButton)e.getSource()).getRootPane(); 1225 File dflt = new File(sshConfig.getValueStr()); 1226 File f = showChooser("Path to OpenSSH client config file", dflt, c); 1227 if (f != null && f.exists() && f.isFile() && f.canRead()) 1228 sshConfigInput.setText(f.getAbsolutePath()); 1229 } 1230 }); 1231 JLabel sshKeyFileLabel = new JLabel("SSH identity file"); 1232 sshKeyFileInput = new JTextField(); 1233 sshKeyFileChooser = new JButton("Browse"); 1234 sshKeyFileChooser.addActionListener(new ActionListener() { 1235 public void actionPerformed(ActionEvent e) { 1236 JComponent c = ((JButton)e.getSource()).getRootPane(); 1237 File f = showChooser("Path to SSH key file", null, c); 1238 if (f != null && f.exists() && f.isFile() && f.canRead()) 1239 sshKeyFileInput.setText(f.getAbsolutePath()); 1240 } 1241 }); 1242 JPanel sshArgsPanel = new JPanel(new GridBagLayout()); 1243 JLabel sshArgsLabel = new JLabel("Arguments:"); 1244 sshArgsDefaultButton = new GroupedJRadioButton("Default", sshArgsGroup, sshArgsPanel); 1245 sshArgsDefaultButton.addActionListener(new ActionListener() { 1246 public void actionPerformed(ActionEvent e) { 1247 sshArgsInput.setEnabled(sshArgsCustomButton.isSelected()); 1248 } 1249 }); 1250 sshArgsCustomButton = new GroupedJRadioButton("Custom", sshArgsGroup, sshArgsPanel); 1251 sshArgsCustomButton.addActionListener(new ActionListener() { 1252 public void actionPerformed(ActionEvent e) { 1253 sshArgsInput.setEnabled(sshArgsCustomButton.isSelected()); 1254 } 1255 }); 1256 sshArgsInput = new JTextField(); 1257 1258 JPanel gatewayPanel = new JPanel(new GridBagLayout()); 1259 gatewayPanel.add(viaCheckbox, 1260 new GridBagConstraints(0, 0, 1261 REMAINDER, 1, 1262 LIGHT, LIGHT, 1263 LINE_START, NONE, 1264 new Insets(0, 0, 4, 0), 1265 NONE, NONE)); 1266 int indent = getButtonLabelInset(viaCheckbox); 1267 gatewayPanel.add(sshUserLabel, 1268 new GridBagConstraints(0, 1, 1269 1, 1, 1270 LIGHT, LIGHT, 1271 LINE_START, HORIZONTAL, 1272 new Insets(0, indent, 4, 0), 1273 NONE, NONE)); 1274 gatewayPanel.add(sshHostLabel, 1275 new GridBagConstraints(2, 1, 1276 1, 1, 1277 HEAVY, LIGHT, 1278 LINE_START, HORIZONTAL, 1279 new Insets(0, 0, 4, 0), 1280 NONE, NONE)); 1281 gatewayPanel.add(sshPortLabel, 1282 new GridBagConstraints(3, 1, 1283 1, 1, 1284 LIGHT, LIGHT, 1285 LINE_START, HORIZONTAL, 1286 new Insets(0, 5, 4, 0), 1287 NONE, NONE)); 1288 gatewayPanel.add(viaUserInput, 1289 new GridBagConstraints(0, 2, 1290 1, 1, 1291 LIGHT, LIGHT, 1292 LINE_START, HORIZONTAL, 1293 new Insets(0, indent, 0, 0), 1294 NONE, NONE)); 1295 gatewayPanel.add(sshUserAtLabel, 1296 new GridBagConstraints(1, 2, 1297 1, 1, 1298 LIGHT, LIGHT, 1299 LINE_START, HORIZONTAL, 1300 new Insets(0, 2, 0, 2), 1301 NONE, NONE)); 1302 gatewayPanel.add(viaHostInput, 1303 new GridBagConstraints(2, 2, 1304 1, 1, 1305 HEAVY, LIGHT, 1306 LINE_START, HORIZONTAL, 1307 new Insets(0, 0, 0, 0), 1308 NONE, NONE)); 1309 gatewayPanel.add(viaPortInput, 1310 new GridBagConstraints(3, 2, 1311 1, 1, 1312 LIGHT, LIGHT, 1313 LINE_START, HORIZONTAL, 1314 new Insets(0, 5, 0, 0), 1315 NONE, NONE)); 1316 1317 JPanel clientPanel = new JPanel(new GridBagLayout()); 1318 clientPanel.add(extSSHCheckbox, 1319 new GridBagConstraints(0, 0, 1320 1, 1, 1321 LIGHT, LIGHT, 1322 LINE_START, NONE, 1323 new Insets(0, 0, 0, 0), 1324 NONE, NONE)); 1325 clientPanel.add(sshClientInput, 1326 new GridBagConstraints(1, 0, 1327 1, 1, 1328 HEAVY, LIGHT, 1329 LINE_START, HORIZONTAL, 1330 new Insets(0, 5, 0, 0), 1331 NONE, NONE)); 1332 clientPanel.add(sshClientChooser, 1333 new GridBagConstraints(2, 0, 1334 1, 1, 1335 LIGHT, LIGHT, 1336 LINE_START, NONE, 1337 new Insets(0, 5, 0, 0), 1338 NONE, NONE)); 1339 sshArgsPanel.add(sshArgsLabel, 1340 new GridBagConstraints(0, 1, 1341 1, 1, 1342 LIGHT, LIGHT, 1343 LINE_START, NONE, 1344 new Insets(0, 0, 0, 0), 1345 NONE, NONE)); 1346 sshArgsPanel.add(sshArgsDefaultButton, 1347 new GridBagConstraints(1, 1, 1348 1, 1, 1349 LIGHT, LIGHT, 1350 LINE_START, NONE, 1351 new Insets(0, 5, 0, 0), 1352 NONE, NONE)); 1353 sshArgsPanel.add(sshArgsCustomButton, 1354 new GridBagConstraints(2, 1, 1355 1, 1, 1356 LIGHT, LIGHT, 1357 LINE_START, NONE, 1358 new Insets(0, 5, 0, 0), 1359 NONE, NONE)); 1360 sshArgsPanel.add(sshArgsInput, 1361 new GridBagConstraints(3, 1, 1362 1, 1, 1363 HEAVY, LIGHT, 1364 LINE_START, HORIZONTAL, 1365 new Insets(0, 5, 0, 0), 1366 NONE, NONE)); 1367 indent = getButtonLabelInset(extSSHCheckbox); 1368 clientPanel.add(sshArgsPanel, 1369 new GridBagConstraints(0, 1, 1370 REMAINDER, 1, 1371 LIGHT, LIGHT, 1372 LINE_START, HORIZONTAL, 1373 new Insets(4, indent, 0, 0), 1374 NONE, NONE)); 1375 1376 JPanel opensshPanel = new JPanel(new GridBagLayout()); 1377 TitledBorder border = 1378 BorderFactory.createTitledBorder("Embedded SSH client configuration"); 1379 opensshPanel.setBorder(border); 1380 opensshPanel.add(sshConfigLabel, 1381 new GridBagConstraints(0, 0, 1382 1, 1, 1383 LIGHT, LIGHT, 1384 LINE_START, NONE, 1385 new Insets(0, 0, 5, 0), 1386 NONE, NONE)); 1387 opensshPanel.add(sshConfigInput, 1388 new GridBagConstraints(1, 0, 1389 1, 1, 1390 HEAVY, LIGHT, 1391 LINE_START, HORIZONTAL, 1392 new Insets(0, 5, 5, 0), 1393 NONE, NONE)); 1394 opensshPanel.add(sshConfigChooser, 1395 new GridBagConstraints(2, 0, 1396 1, 1, 1397 LIGHT, LIGHT, 1398 LINE_START, VERTICAL, 1399 new Insets(0, 5, 5, 0), 1400 NONE, NONE)); 1401 opensshPanel.add(sshKeyFileLabel, 1402 new GridBagConstraints(0, 1, 1403 1, 1, 1404 LIGHT, LIGHT, 1405 LINE_START, NONE, 1406 new Insets(0, 0, 0, 0), 1407 NONE, NONE)); 1408 opensshPanel.add(sshKeyFileInput, 1409 new GridBagConstraints(1, 1, 1410 1, 1, 1411 HEAVY, LIGHT, 1412 LINE_START, HORIZONTAL, 1413 new Insets(0, 5, 0, 0), 1414 NONE, NONE)); 1415 opensshPanel.add(sshKeyFileChooser, 1416 new GridBagConstraints(2, 1, 1417 1, 1, 1418 LIGHT, LIGHT, 1419 LINE_START, VERTICAL, 1420 new Insets(0, 5, 0, 0), 1421 NONE, NONE)); 1422 tunnelPanel.add(gatewayPanel, 1423 new GridBagConstraints(0, 0, 1424 REMAINDER, 1, 1425 HEAVY, LIGHT, 1426 LINE_START, HORIZONTAL, 1427 new Insets(0, 0, 4, 0), 1428 NONE, NONE)); 1429 tunnelPanel.add(clientPanel, 1430 new GridBagConstraints(0, 1, 1431 REMAINDER, 1, 1432 HEAVY, LIGHT, 1433 LINE_START, HORIZONTAL, 1434 new Insets(0, 0, 4, 0), 1435 NONE, NONE)); 1436 tunnelPanel.add(opensshPanel, 1437 new GridBagConstraints(0, 2, 1438 REMAINDER, 1, 1439 HEAVY, LIGHT, 1440 LINE_START, HORIZONTAL, 1441 new Insets(0, 0, 0, 0), 1442 NONE, NONE)); 1443 1444 sshPanel.add(tunnelCheckbox, 1445 new GridBagConstraints(0, 0, 1446 REMAINDER, 1, 1447 LIGHT, LIGHT, 1448 LINE_START, NONE, 1449 new Insets(0, 0, 4, 0), 1450 NONE, NONE)); 1451 indent = getButtonLabelInset(tunnelCheckbox); 1452 sshPanel.add(tunnelPanel, 1453 new GridBagConstraints(0, 2, 1454 REMAINDER, 1, 1455 LIGHT, LIGHT, 1456 LINE_START, HORIZONTAL, 1457 new Insets(0, indent, 4, 0), 1458 NONE, NONE)); 1459 sshPanel.add(Box.createRigidArea(new Dimension(5, 0)), 1460 new GridBagConstraints(0, RELATIVE, 1461 REMAINDER, REMAINDER, 1462 HEAVY, HEAVY, 1463 LINE_START, BOTH, 1464 new Insets(0, 0, 0, 0), 1465 NONE, NONE)); 1466 return sshPanel; 1467 } 1468 handleAutoselect()1469 private void handleAutoselect() 1470 { 1471 ButtonGroup[] groups = { encodingGroup, colorlevelGroup }; 1472 for (ButtonGroup grp : groups) { 1473 Enumeration<AbstractButton> elems = grp.getElements(); 1474 while (elems.hasMoreElements()) 1475 elems.nextElement().setEnabled(!autoselectCheckbox.isSelected()); 1476 } 1477 1478 // JPEG setting is also affected by autoselection 1479 jpegCheckbox.setEnabled(!autoselectCheckbox.isSelected()); 1480 handleJpeg(); 1481 } 1482 handleCompression()1483 private void handleCompression() 1484 { 1485 compressionInput.setEnabled(compressionCheckbox.isSelected()); 1486 } 1487 handleJpeg()1488 private void handleJpeg() 1489 { 1490 if (jpegCheckbox.isSelected() && 1491 !autoselectCheckbox.isSelected()) 1492 jpegInput.setEnabled(true); 1493 else 1494 jpegInput.setEnabled(false); 1495 } 1496 handleX509()1497 private void handleX509() 1498 { 1499 caInput.setEnabled(encX509Checkbox.isSelected()); 1500 caChooser.setEnabled(encX509Checkbox.isSelected()); 1501 crlInput.setEnabled(encX509Checkbox.isSelected()); 1502 crlChooser.setEnabled(encX509Checkbox.isSelected()); 1503 } 1504 handleSendLocalUsername()1505 private void handleSendLocalUsername() 1506 { 1507 boolean value = authIdentCheckbox.isSelected() || 1508 authPlainCheckbox.isSelected(); 1509 sendLocalUsernameCheckbox.setEnabled(value); 1510 } 1511 handleDesktopSize()1512 private void handleDesktopSize() 1513 { 1514 desktopWidthInput.setEnabled(desktopSizeCheckbox.isSelected()); 1515 desktopHeightInput.setEnabled(desktopSizeCheckbox.isSelected()); 1516 } 1517 handleRemoteResize()1518 private void handleRemoteResize() 1519 { 1520 scalingFactorInput.setEnabled(!remoteResizeButton.isSelected()); 1521 } 1522 handleTunnel()1523 private void handleTunnel() 1524 { 1525 viaCheckbox.setEnabled(tunnelCheckbox.isSelected()); 1526 extSSHCheckbox.setEnabled(tunnelCheckbox.isSelected()); 1527 if (tunnelCheckbox.isSelected()) { 1528 JComponent[] components = { viaUserInput, viaHostInput, viaPortInput }; 1529 for (JComponent c : components) 1530 c.setEnabled(viaCheckbox.isSelected()); 1531 sshClientInput.setEnabled(extSSHCheckbox.isSelected()); 1532 sshClientChooser.setEnabled(extSSHCheckbox.isSelected()); 1533 sshArgsDefaultButton.setEnabled(extSSHCheckbox.isSelected()); 1534 sshArgsCustomButton.setEnabled(extSSHCheckbox.isSelected()); 1535 sshArgsInput.setEnabled(extSSHCheckbox.isSelected()); 1536 sshConfigInput.setEnabled(!extSSHCheckbox.isSelected()); 1537 sshConfigChooser.setEnabled(!extSSHCheckbox.isSelected()); 1538 sshKeyFileInput.setEnabled(!extSSHCheckbox.isSelected()); 1539 sshKeyFileChooser.setEnabled(!extSSHCheckbox.isSelected()); 1540 } else { 1541 JComponent[] components = { 1542 viaUserInput, viaHostInput, viaPortInput, sshClientInput, 1543 sshClientChooser, sshArgsDefaultButton, sshArgsCustomButton, 1544 sshArgsInput, sshConfigInput, sshConfigChooser, sshKeyFileInput, 1545 sshKeyFileChooser, }; 1546 for (JComponent c : components) 1547 c.setEnabled(false); 1548 } 1549 } 1550 handleVia()1551 private void handleVia() 1552 { 1553 if (tunnelCheckbox.isSelected()) { 1554 viaUserInput.setEnabled(viaCheckbox.isSelected()); 1555 viaHostInput.setEnabled(viaCheckbox.isSelected()); 1556 viaPortInput.setEnabled(viaCheckbox.isSelected()); 1557 } 1558 } 1559 handleExtSSH()1560 private void handleExtSSH() 1561 { 1562 if (tunnelCheckbox.isSelected()) { 1563 sshClientInput.setEnabled(extSSHCheckbox.isSelected()); 1564 sshClientChooser.setEnabled(extSSHCheckbox.isSelected()); 1565 sshArgsDefaultButton.setEnabled(extSSHCheckbox.isSelected()); 1566 sshArgsCustomButton.setEnabled(extSSHCheckbox.isSelected()); 1567 sshConfigInput.setEnabled(!extSSHCheckbox.isSelected()); 1568 sshConfigChooser.setEnabled(!extSSHCheckbox.isSelected()); 1569 sshKeyFileInput.setEnabled(!extSSHCheckbox.isSelected()); 1570 sshKeyFileChooser.setEnabled(!extSSHCheckbox.isSelected()); 1571 if (sshArgsCustomButton.isSelected()) 1572 sshArgsInput.setEnabled(extSSHCheckbox.isSelected()); 1573 else 1574 sshArgsInput.setEnabled(false); 1575 } 1576 } 1577 handleRfbState()1578 private void handleRfbState() 1579 { 1580 CConn cc = VncViewer.cc; 1581 if (cc != null && cc.state() == CConnection.stateEnum.RFBSTATE_NORMAL) { 1582 JComponent[] components = { 1583 encNoneCheckbox, encTLSCheckbox, encX509Checkbox, authNoneCheckbox, 1584 authVncCheckbox, authVncCheckbox, authIdentCheckbox, authPlainCheckbox, 1585 sendLocalUsernameCheckbox, caInput, caChooser, crlInput, crlChooser, 1586 sharedCheckbox, tunnelCheckbox, viaCheckbox, viaUserInput, viaHostInput, 1587 viaPortInput, extSSHCheckbox, sshClientInput, sshClientChooser, 1588 sshArgsDefaultButton, sshArgsCustomButton, sshArgsInput, sshConfigInput, 1589 sshKeyFileInput, sshConfigChooser, sshKeyFileChooser, 1590 }; 1591 for (JComponent c : components) 1592 c.setEnabled(false); 1593 } 1594 } 1595 1596 static LogWriter vlog = new LogWriter("OptionsDialog"); 1597 } 1598