0
|
1 // Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
|
|
2 // All rights reserved.
|
|
3 //
|
|
4 //-------------------------------------------------------------------------
|
|
5 // This file is part of the TightVNC software. Please visit our Web site:
|
|
6 //
|
|
7 // http://www.tightvnc.com/
|
|
8 //
|
|
9 // This program is free software; you can redistribute it and/or modify
|
|
10 // it under the terms of the GNU General Public License as published by
|
|
11 // the Free Software Foundation; either version 2 of the License, or
|
|
12 // (at your option) any later version.
|
|
13 //
|
|
14 // This program is distributed in the hope that it will be useful,
|
|
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
17 // GNU General Public License for more details.
|
|
18 //
|
|
19 // You should have received a copy of the GNU General Public License along
|
|
20 // with this program; if not, write to the Free Software Foundation, Inc.,
|
|
21 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
22 //-------------------------------------------------------------------------
|
|
23 //
|
|
24
|
|
25 package com.glavsoft.viewer.swing.gui;
|
|
26
|
|
27 import com.glavsoft.viewer.mvp.View;
|
|
28 import com.glavsoft.viewer.swing.ConnectionParams;
|
|
29 import com.glavsoft.viewer.ConnectionPresenter;
|
|
30 import com.glavsoft.viewer.swing.Utils;
|
|
31 import com.glavsoft.viewer.swing.WrongParameterException;
|
|
32
|
|
33 import javax.swing.*;
|
|
34 import javax.swing.border.Border;
|
|
35 import javax.swing.border.EmptyBorder;
|
|
36 import java.awt.*;
|
|
37 import java.awt.event.*;
|
|
38 import java.util.LinkedList;
|
|
39
|
|
40 /**
|
|
41 * Dialog window for connection parameters get from.
|
|
42 */
|
|
43 @SuppressWarnings("serial")
|
|
44 public class ConnectionView extends JPanel implements View {
|
|
45 private static final int PADDING = 4;
|
|
46 public static final int COLUMNS_HOST_FIELD = 30;
|
|
47 public static final int COLUMNS_PORT_USER_FIELD = 13;
|
|
48 public static final String CLOSE = "Close";
|
|
49 public static final String CANCEL = "Cancel";
|
|
50 private WindowListener appWindowListener;
|
|
51 private final boolean hasSshSupport;
|
|
52 private final JTextField serverPortField;
|
|
53 private JCheckBox useSshTunnelingCheckbox;
|
|
54 private final JComboBox serverNameCombo;
|
|
55 private JTextField sshUserField;
|
|
56 private JTextField sshHostField;
|
|
57 private JTextField sshPortField;
|
|
58 private JLabel sshUserLabel;
|
|
59 private JLabel sshHostLabel;
|
|
60 private JLabel sshPortLabel;
|
|
61 private JLabel ssUserWarningLabel;
|
|
62 private JButton clearHistoryButton;
|
|
63 private JButton connectButton;
|
|
64 private final JFrame view;
|
|
65 private final ConnectionPresenter presenter;
|
|
66 private final StatusBar statusBar;
|
|
67 private boolean connectionInProgress;
|
|
68 private JButton closeCancelButton;
|
|
69
|
|
70 public ConnectionView(final WindowListener appWindowListener,
|
|
71 final ConnectionPresenter presenter, boolean useSsh) {
|
|
72 this.appWindowListener = appWindowListener;
|
|
73 this.hasSshSupport = useSsh;
|
|
74 this.presenter = presenter;
|
|
75
|
|
76 setLayout(new BorderLayout(0, 0));
|
|
77 JPanel optionsPane = new JPanel(new GridBagLayout());
|
|
78 add(optionsPane, BorderLayout.CENTER);
|
|
79 optionsPane.setBorder(new EmptyBorder(PADDING, PADDING, PADDING, PADDING));
|
|
80
|
|
81 setLayout(new GridBagLayout());
|
|
82
|
|
83 int gridRow = 0;
|
|
84
|
|
85 serverNameCombo = new JComboBox();
|
|
86 initConnectionsHistoryCombo();
|
|
87 serverNameCombo.addItemListener(new ItemListener() {
|
|
88 @Override
|
|
89 public void itemStateChanged(ItemEvent e) {
|
|
90 Object item = serverNameCombo.getSelectedItem();
|
|
91 if (item instanceof ConnectionParams) {
|
|
92 presenter.populateFromHistoryItem((ConnectionParams) item);
|
|
93 }
|
|
94 }
|
|
95 });
|
|
96
|
|
97 addFormFieldRow(optionsPane, gridRow, new JLabel("Remote Host:"), serverNameCombo, true);
|
|
98 ++gridRow;
|
|
99
|
|
100 serverPortField = new JTextField(COLUMNS_PORT_USER_FIELD);
|
|
101
|
|
102 addFormFieldRow(optionsPane, gridRow, new JLabel("Port:"), serverPortField, false);
|
|
103 ++gridRow;
|
|
104
|
|
105 if (this.hasSshSupport) {
|
|
106 gridRow = createSshOptions(optionsPane, gridRow);
|
|
107 }
|
|
108
|
|
109 JPanel buttonPanel = createButtons();
|
|
110
|
|
111 GridBagConstraints cButtons = new GridBagConstraints();
|
|
112 cButtons.gridx = 0; cButtons.gridy = gridRow;
|
|
113 cButtons.weightx = 100; cButtons.weighty = 100;
|
|
114 cButtons.gridwidth = 2; cButtons.gridheight = 1;
|
|
115 optionsPane.add(buttonPanel, cButtons);
|
|
116
|
|
117 view = new JFrame("New TightVNC Connection");
|
|
118 view.add(this, BorderLayout.CENTER);
|
|
119 statusBar = new StatusBar();
|
|
120 view.add(statusBar, BorderLayout.SOUTH);
|
|
121
|
|
122 view.getRootPane().setDefaultButton(connectButton);
|
|
123 view.addWindowListener(appWindowListener);
|
|
124 // view.setResizable(false);
|
|
125 Utils.decorateDialog(view);
|
|
126 Utils.centerWindow(view);
|
|
127 }
|
|
128
|
|
129 private void initConnectionsHistoryCombo() {
|
|
130 serverNameCombo.setEditable(true);
|
|
131
|
|
132 new AutoCompletionComboEditorDocument(serverNameCombo); // use autocompletion feature for ComboBox
|
|
133 serverNameCombo.setRenderer(new HostnameComboboxRenderer());
|
|
134
|
|
135 ConnectionParams prototypeDisplayValue = new ConnectionParams();
|
|
136 prototypeDisplayValue.hostName = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXЧЧ";
|
|
137 serverNameCombo.setPrototypeDisplayValue(prototypeDisplayValue);
|
|
138 }
|
|
139
|
|
140 public void showReconnectDialog(final String title, final String message) {
|
|
141 JOptionPane reconnectPane = new JOptionPane(message + "\nTry another connection?",
|
|
142 JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_OPTION);
|
|
143 final JDialog reconnectDialog = reconnectPane.createDialog(ConnectionView.this, title);
|
|
144 Utils.decorateDialog(reconnectDialog);
|
|
145 reconnectDialog.setVisible(true);
|
|
146 if (reconnectPane.getValue() == null ||
|
|
147 (Integer)reconnectPane.getValue() == JOptionPane.NO_OPTION) {
|
|
148 presenter.setNeedReconnection(false);
|
|
149 closeView();
|
|
150 view.dispose();
|
|
151 closeApp();
|
|
152 } else {
|
|
153 // TODO return when allowInteractive, close window otherwise
|
|
154 // forceConnectionDialog = allowInteractive;
|
|
155 }
|
|
156 }
|
|
157
|
|
158 public void setConnectionInProgress(boolean enable) {
|
|
159 if (enable) {
|
|
160 connectionInProgress = true;
|
|
161 closeCancelButton.setText(CANCEL);
|
|
162 connectButton.setEnabled(false);
|
|
163 } else {
|
|
164 connectionInProgress = false;
|
|
165 closeCancelButton.setText(CLOSE);
|
|
166 connectButton.setEnabled(true);
|
|
167 }
|
|
168 }
|
|
169
|
|
170 private JPanel createButtons() {
|
|
171 JPanel buttonPanel = new JPanel();
|
|
172
|
|
173 closeCancelButton = new JButton(CLOSE);
|
|
174 closeCancelButton.addActionListener(new ActionListener() {
|
|
175 @Override
|
|
176 public void actionPerformed(ActionEvent e) {
|
|
177 if (connectionInProgress) {
|
|
178 presenter.cancelConnection();
|
|
179 setConnectionInProgress(false);
|
|
180 } else {
|
|
181 closeView();
|
|
182 closeApp();
|
|
183 }
|
|
184 }
|
|
185 });
|
|
186
|
|
187 connectButton = new JButton("Connect");
|
|
188 buttonPanel.add(connectButton);
|
|
189 connectButton.addActionListener(new ActionListener() {
|
|
190 @Override
|
|
191 public void actionPerformed(ActionEvent e) {
|
|
192 setMessage("");
|
|
193 Object item = serverNameCombo.getSelectedItem();
|
|
194 String hostName = item instanceof ConnectionParams ?
|
|
195 ((ConnectionParams) item).hostName :
|
|
196 (String) item;
|
|
197 try {
|
|
198 setConnectionInProgress(true);
|
|
199 presenter.submitConnection(hostName);
|
|
200 } catch (WrongParameterException wpe) {
|
|
201 if (ConnectionPresenter.PROPERTY_HOST_NAME.equals(wpe.getPropertyName())) {
|
|
202 serverNameCombo.requestFocusInWindow();
|
|
203 }
|
|
204 if (ConnectionPresenter.PROPERTY_RFB_PORT_NUMBER.equals(wpe.getPropertyName())) {
|
|
205 serverPortField.requestFocusInWindow();
|
|
206 }
|
|
207 showConnectionErrorDialog(wpe.getMessage());
|
|
208 setConnectionInProgress(false);
|
|
209 }
|
|
210 }
|
|
211 });
|
|
212
|
|
213 JButton optionsButton = new JButton("Options...");
|
|
214 buttonPanel.add(optionsButton);
|
|
215 optionsButton.addActionListener(new ActionListener() {
|
|
216 @Override
|
|
217 public void actionPerformed(ActionEvent e) {
|
|
218 OptionsDialog od = new OptionsDialog(view);
|
|
219 od.initControlsFromSettings(presenter.getRfbSettings(), presenter.getUiSettings(), true);
|
|
220 od.setVisible(true);
|
|
221 view.toFront();
|
|
222 }
|
|
223 });
|
|
224
|
|
225 clearHistoryButton = new JButton("Clear history");
|
|
226 clearHistoryButton.setToolTipText("Clear connections history");
|
|
227 buttonPanel.add(clearHistoryButton);
|
|
228 clearHistoryButton.addActionListener(new ActionListener() {
|
|
229 @Override
|
|
230 public void actionPerformed(ActionEvent e) {
|
|
231 presenter.clearHistory();
|
|
232 clearHistoryButton.setEnabled(false);
|
|
233 view.toFront();
|
|
234 }
|
|
235 });
|
|
236 buttonPanel.add(closeCancelButton);
|
|
237 return buttonPanel;
|
|
238 }
|
|
239
|
|
240 private int createSshOptions(JPanel pane, int gridRow) {
|
|
241 GridBagConstraints cUseSshTunnelLabel = new GridBagConstraints();
|
|
242 cUseSshTunnelLabel.gridx = 0; cUseSshTunnelLabel.gridy = gridRow;
|
|
243 cUseSshTunnelLabel.weightx = 100; cUseSshTunnelLabel.weighty = 100;
|
|
244 cUseSshTunnelLabel.gridwidth = 2; cUseSshTunnelLabel.gridheight = 1;
|
|
245 cUseSshTunnelLabel.anchor = GridBagConstraints.LINE_START;
|
|
246 cUseSshTunnelLabel.ipadx = PADDING;
|
|
247 cUseSshTunnelLabel.ipady = 10;
|
|
248 useSshTunnelingCheckbox = new JCheckBox("Use SSH tunneling");
|
|
249 pane.add(useSshTunnelingCheckbox, cUseSshTunnelLabel);
|
|
250 ++gridRow;
|
|
251
|
|
252 sshHostLabel = new JLabel("SSH Server:");
|
|
253 sshHostField = new JTextField(COLUMNS_HOST_FIELD);
|
|
254 addFormFieldRow(pane, gridRow, sshHostLabel, sshHostField, true);
|
|
255 ++gridRow;
|
|
256
|
|
257 sshPortLabel = new JLabel("SSH Port:");
|
|
258 sshPortField = new JTextField(COLUMNS_PORT_USER_FIELD);
|
|
259 addFormFieldRow(pane, gridRow, sshPortLabel, sshPortField, false);
|
|
260 ++gridRow;
|
|
261
|
|
262 sshUserLabel = new JLabel("SSH User:");
|
|
263 sshUserField = new JTextField(COLUMNS_PORT_USER_FIELD);
|
|
264 JPanel sshUserFieldPane = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
|
|
265 sshUserFieldPane.add(sshUserField);
|
|
266 ssUserWarningLabel = new JLabel(" (will be asked if not specified)");
|
|
267 sshUserFieldPane.add(ssUserWarningLabel);
|
|
268 addFormFieldRow(pane, gridRow, sshUserLabel, sshUserFieldPane, false);
|
|
269 ++gridRow;
|
|
270
|
|
271 useSshTunnelingCheckbox.addItemListener(new ItemListener() {
|
|
272 @Override
|
|
273 public void itemStateChanged(ItemEvent e) {
|
|
274 final boolean useSsh = e.getStateChange() == ItemEvent.SELECTED;
|
|
275 setUseSsh(useSsh);
|
|
276 presenter.setUseSsh(useSsh);
|
|
277 }
|
|
278 });
|
|
279
|
|
280 return gridRow;
|
|
281 }
|
|
282
|
|
283 private void addFormFieldRow(JPanel pane, int gridRow, JLabel label, JComponent field, boolean fill) {
|
|
284 GridBagConstraints cLabel = new GridBagConstraints();
|
|
285 cLabel.gridx = 0; cLabel.gridy = gridRow;
|
|
286 cLabel.weightx = 0;
|
|
287 cLabel.weighty = 100;
|
|
288 cLabel.gridwidth = cLabel.gridheight = 1;
|
|
289 cLabel.anchor = GridBagConstraints.LINE_END;
|
|
290 cLabel.ipadx = PADDING;
|
|
291 cLabel.ipady = 10;
|
|
292 pane.add(label, cLabel);
|
|
293
|
|
294 GridBagConstraints cField = new GridBagConstraints();
|
|
295 cField.gridx = 1; cField.gridy = gridRow;
|
|
296 cField.weightx = 0; cField.weighty = 100;
|
|
297 cField.gridwidth = cField.gridheight = 1;
|
|
298 cField.anchor = GridBagConstraints.LINE_START;
|
|
299 if (fill) cField.fill = GridBagConstraints.HORIZONTAL;
|
|
300 pane.add(field, cField);
|
|
301 }
|
|
302
|
|
303 /*
|
|
304 * Implicit View interface
|
|
305 */
|
|
306 public void setMessage(String message) {
|
|
307 statusBar.setMessage(message);
|
|
308 }
|
|
309
|
|
310 @SuppressWarnings("UnusedDeclaration")
|
|
311 public void setPortNumber(int portNumber) {
|
|
312 serverPortField.setText(String.valueOf(portNumber));
|
|
313 }
|
|
314
|
|
315 @SuppressWarnings("UnusedDeclaration")
|
|
316 public String getPortNumber() {
|
|
317 return serverPortField.getText();
|
|
318 }
|
|
319
|
|
320 @SuppressWarnings("UnusedDeclaration")
|
|
321 public void setSshHostName(String sshHostName) {
|
|
322 if (hasSshSupport) {
|
|
323 sshHostField.setText(sshHostName);
|
|
324 }
|
|
325 }
|
|
326
|
|
327 @SuppressWarnings("UnusedDeclaration")
|
|
328 public String getSshHostName() {
|
|
329 if (hasSshSupport) {
|
|
330 return sshHostField.getText();
|
|
331 } else { return ""; }
|
|
332 }
|
|
333
|
|
334 @SuppressWarnings("UnusedDeclaration")
|
|
335 public void setSshPortNumber(int sshPortNumber) {
|
|
336 if (hasSshSupport) {
|
|
337 sshPortField.setText(String.valueOf(sshPortNumber));
|
|
338 }
|
|
339 }
|
|
340
|
|
341 @SuppressWarnings("UnusedDeclaration")
|
|
342 public String getSshPortNumber() {
|
|
343 if (hasSshSupport) {
|
|
344 return sshPortField.getText();
|
|
345 } else { return ""; }
|
|
346 }
|
|
347
|
|
348 @SuppressWarnings("UnusedDeclaration")
|
|
349 public void setSshUserName(String sshUserName) {
|
|
350 if (hasSshSupport) {
|
|
351 sshUserField.setText(sshUserName);
|
|
352 }
|
|
353 }
|
|
354
|
|
355 @SuppressWarnings("UnusedDeclaration")
|
|
356 public String getSshUserName() {
|
|
357 if (hasSshSupport) {
|
|
358 return sshUserField.getText();
|
|
359 } else { return ""; }
|
|
360 }
|
|
361
|
|
362 @SuppressWarnings("UnusedDeclaration")
|
|
363 public void setUseSsh(boolean useSsh) {
|
|
364 if (hasSshSupport) {
|
|
365 useSshTunnelingCheckbox.setSelected(useSsh);
|
|
366 sshUserLabel.setEnabled(useSsh);
|
|
367 sshUserField.setEnabled(useSsh);
|
|
368 ssUserWarningLabel.setEnabled(useSsh);
|
|
369 sshHostLabel.setEnabled(useSsh);
|
|
370 sshHostField.setEnabled(useSsh);
|
|
371 sshPortLabel.setEnabled(useSsh);
|
|
372 sshPortField.setEnabled(useSsh);
|
|
373 }
|
|
374 }
|
|
375
|
|
376 @SuppressWarnings("UnusedDeclaration")
|
|
377 public boolean getUseSsh() {
|
|
378 return useSshTunnelingCheckbox.isSelected();
|
|
379 }
|
|
380
|
|
381 @SuppressWarnings("UnusedDeclaration")
|
|
382 public void setConnectionsList(LinkedList<ConnectionParams> connections) {
|
|
383 serverNameCombo.removeAllItems();
|
|
384 for (ConnectionParams cp : connections) {
|
|
385 serverNameCombo.addItem(new ConnectionParams(cp));
|
|
386 }
|
|
387 serverNameCombo.setPopupVisible(false);
|
|
388 clearHistoryButton.setEnabled(serverNameCombo.getItemCount() > 0);
|
|
389 }
|
|
390 /*
|
|
391 * /Implicit View interface
|
|
392 */
|
|
393
|
|
394 @Override
|
|
395 public void showView() {
|
|
396 view.setVisible(true);
|
|
397 view.toFront();
|
|
398 view.repaint();
|
|
399 }
|
|
400
|
|
401 @Override
|
|
402 public void closeView() {
|
|
403 view.setVisible(false);
|
|
404 }
|
|
405
|
|
406 public void showConnectionErrorDialog(final String message) {
|
|
407 JOptionPane errorPane = new JOptionPane(message, JOptionPane.ERROR_MESSAGE);
|
|
408 final JDialog errorDialog = errorPane.createDialog(view, "Connection error");
|
|
409 Utils.decorateDialog(errorDialog);
|
|
410 errorDialog.setVisible(true);
|
|
411 if ( ! presenter.allowInteractive()) {
|
|
412 presenter.cancelConnection();
|
|
413 closeApp();
|
|
414 }
|
|
415 }
|
|
416
|
|
417 public void closeApp() {
|
|
418 appWindowListener.windowClosing(null);
|
|
419 }
|
|
420
|
|
421 public JFrame getFrame() {
|
|
422 return view;
|
|
423 }
|
|
424
|
|
425 }
|
|
426
|
|
427 class StatusBar extends JPanel {
|
|
428
|
|
429 private JLabel messageLabel;
|
|
430
|
|
431 public StatusBar() {
|
|
432 setLayout(new BorderLayout());
|
|
433 setPreferredSize(new Dimension(10, 23));
|
|
434
|
|
435 messageLabel = new JLabel("");
|
|
436 final Font f = messageLabel.getFont();
|
|
437 messageLabel.setFont(f.deriveFont(f.getStyle() & ~Font.BOLD));
|
|
438 add(messageLabel, BorderLayout.CENTER);
|
|
439
|
|
440 JPanel rightPanel = new JPanel(new BorderLayout());
|
|
441 rightPanel.setOpaque(false);
|
|
442
|
|
443
|
|
444 add(rightPanel, BorderLayout.EAST);
|
|
445 setBorder(new Border() {
|
|
446 @Override
|
|
447 public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
|
|
448 Color oldColor = g.getColor();
|
|
449 g.translate(x, y);
|
|
450 g.setColor(c.getBackground().darker());
|
|
451 g.drawLine(0, 0, width -1, 0);
|
|
452 g.setColor(c.getBackground().brighter());
|
|
453 g.drawLine(0, 1, width -1, 1);
|
|
454 g.translate(-x, -y);
|
|
455 g.setColor(oldColor);
|
|
456 }
|
|
457 @Override
|
|
458 public Insets getBorderInsets(Component c) {
|
|
459 return new Insets(2, 2, 2, 2);
|
|
460 }
|
|
461 @Override
|
|
462 public boolean isBorderOpaque() {
|
|
463 return false;
|
|
464 }
|
|
465 });
|
|
466 }
|
|
467
|
|
468 public void setMessage(String message) {
|
|
469 messageLabel.setText(message);
|
|
470 }
|
|
471 }
|