source: josm/trunk/src/org/openstreetmap/josm/gui/io/CredentialDialog.java@ 12799

Last change on this file since 12799 was 12678, checked in by Don-vip, 7 years ago

see #15182 - move WindowGeometry from tools to gui.util

  • Property svn:eol-style set to native
File size: 15.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.io;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.BorderLayout;
7import java.awt.Dimension;
8import java.awt.FlowLayout;
9import java.awt.Font;
10import java.awt.GridBagConstraints;
11import java.awt.GridBagLayout;
12import java.awt.Insets;
13import java.awt.event.ActionEvent;
14import java.awt.event.FocusAdapter;
15import java.awt.event.FocusEvent;
16import java.awt.event.KeyAdapter;
17import java.awt.event.KeyEvent;
18import java.awt.event.WindowAdapter;
19import java.awt.event.WindowEvent;
20import java.util.Objects;
21
22import javax.swing.AbstractAction;
23import javax.swing.BorderFactory;
24import javax.swing.JCheckBox;
25import javax.swing.JDialog;
26import javax.swing.JLabel;
27import javax.swing.JPanel;
28import javax.swing.JTextField;
29
30import org.openstreetmap.josm.Main;
31import org.openstreetmap.josm.gui.SideButton;
32import org.openstreetmap.josm.gui.help.ContextSensitiveHelpAction;
33import org.openstreetmap.josm.gui.help.HelpUtil;
34import org.openstreetmap.josm.gui.preferences.server.ProxyPreferencesPanel;
35import org.openstreetmap.josm.gui.util.WindowGeometry;
36import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
37import org.openstreetmap.josm.gui.widgets.JosmPasswordField;
38import org.openstreetmap.josm.gui.widgets.JosmTextField;
39import org.openstreetmap.josm.io.OsmApi;
40import org.openstreetmap.josm.tools.ImageProvider;
41import org.openstreetmap.josm.tools.InputMapUtils;
42import org.openstreetmap.josm.tools.Logging;
43
44/**
45 * Dialog box to request username and password from the user.
46 *
47 * The credentials can be for the OSM API (basic authentication), a different
48 * host or an HTTP proxy.
49 */
50public class CredentialDialog extends JDialog {
51
52 public static CredentialDialog getOsmApiCredentialDialog(String username, String password, String host,
53 String saveUsernameAndPasswordCheckboxText) {
54 CredentialDialog dialog = new CredentialDialog(saveUsernameAndPasswordCheckboxText);
55 if (Objects.equals(OsmApi.getOsmApi().getHost(), host)) {
56 dialog.prepareForOsmApiCredentials(username, password);
57 } else {
58 dialog.prepareForOtherHostCredentials(username, password, host);
59 }
60 dialog.pack();
61 return dialog;
62 }
63
64 public static CredentialDialog getHttpProxyCredentialDialog(String username, String password, String host,
65 String saveUsernameAndPasswordCheckboxText) {
66 CredentialDialog dialog = new CredentialDialog(saveUsernameAndPasswordCheckboxText);
67 dialog.prepareForProxyCredentials(username, password);
68 dialog.pack();
69 return dialog;
70 }
71
72 private boolean canceled;
73 protected CredentialPanel pnlCredentials;
74 private final String saveUsernameAndPasswordCheckboxText;
75
76 public boolean isCanceled() {
77 return canceled;
78 }
79
80 protected void setCanceled(boolean canceled) {
81 this.canceled = canceled;
82 }
83
84 @Override
85 public void setVisible(boolean visible) {
86 if (visible) {
87 WindowGeometry.centerInWindow(Main.parent, new Dimension(350, 300)).applySafe(this);
88 }
89 super.setVisible(visible);
90 }
91
92 protected JPanel createButtonPanel() {
93 JPanel pnl = new JPanel(new FlowLayout());
94 pnl.add(new SideButton(new OKAction()));
95 pnl.add(new SideButton(new CancelAction()));
96 pnl.add(new SideButton(new ContextSensitiveHelpAction(HelpUtil.ht("/Dialog/Password"))));
97 return pnl;
98 }
99
100 protected void build() {
101 getContentPane().setLayout(new BorderLayout());
102 getContentPane().add(createButtonPanel(), BorderLayout.SOUTH);
103
104 addWindowListener(new WindowEventHander());
105 InputMapUtils.addEscapeAction(getRootPane(), new CancelAction());
106
107 getRootPane().setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
108 }
109
110 public CredentialDialog(String saveUsernameAndPasswordCheckboxText) {
111 this.saveUsernameAndPasswordCheckboxText = saveUsernameAndPasswordCheckboxText;
112 setModalityType(ModalityType.DOCUMENT_MODAL);
113 try {
114 setAlwaysOnTop(true);
115 } catch (SecurityException e) {
116 Logging.log(Logging.LEVEL_WARN, tr("Failed to put Credential Dialog always on top. Caught security exception."), e);
117 }
118 build();
119 }
120
121 public void prepareForOsmApiCredentials(String username, String password) {
122 setTitle(tr("Enter credentials for OSM API"));
123 pnlCredentials = new OsmApiCredentialsPanel(this);
124 getContentPane().add(pnlCredentials, BorderLayout.CENTER);
125 pnlCredentials.init(username, password);
126 validate();
127 }
128
129 public void prepareForOtherHostCredentials(String username, String password, String host) {
130 setTitle(tr("Enter credentials for host"));
131 pnlCredentials = new OtherHostCredentialsPanel(this, host);
132 getContentPane().add(pnlCredentials, BorderLayout.CENTER);
133 pnlCredentials.init(username, password);
134 validate();
135 }
136
137 public void prepareForProxyCredentials(String username, String password) {
138 setTitle(tr("Enter credentials for HTTP proxy"));
139 pnlCredentials = new HttpProxyCredentialsPanel(this);
140 getContentPane().add(pnlCredentials, BorderLayout.CENTER);
141 pnlCredentials.init(username, password);
142 validate();
143 }
144
145 public String getUsername() {
146 if (pnlCredentials == null)
147 return null;
148 return pnlCredentials.getUserName();
149 }
150
151 public char[] getPassword() {
152 if (pnlCredentials == null)
153 return null;
154 return pnlCredentials.getPassword();
155 }
156
157 public boolean isSaveCredentials() {
158 if (pnlCredentials == null)
159 return false;
160 return pnlCredentials.isSaveCredentials();
161 }
162
163 protected static class CredentialPanel extends JPanel {
164 protected JosmTextField tfUserName;
165 protected JosmPasswordField tfPassword;
166 protected JCheckBox cbSaveCredentials;
167 protected final JMultilineLabel lblHeading = new JMultilineLabel("");
168 protected final JMultilineLabel lblWarning = new JMultilineLabel("");
169 protected CredentialDialog owner; // owner Dependency Injection to use Key listeners for username and password text fields
170
171 protected void build() {
172 tfUserName = new JosmTextField(20);
173 tfPassword = new JosmPasswordField(20);
174 tfUserName.addFocusListener(new SelectAllOnFocusHandler());
175 tfPassword.addFocusListener(new SelectAllOnFocusHandler());
176 tfUserName.addKeyListener(new TFKeyListener(owner, tfUserName, tfPassword));
177 tfPassword.addKeyListener(new TFKeyListener(owner, tfPassword, tfUserName));
178 cbSaveCredentials = new JCheckBox(owner != null ? owner.saveUsernameAndPasswordCheckboxText : "");
179
180 setLayout(new GridBagLayout());
181 GridBagConstraints gc = new GridBagConstraints();
182 gc.gridwidth = 2;
183 gc.gridheight = 1;
184 gc.fill = GridBagConstraints.HORIZONTAL;
185 gc.weightx = 1.0;
186 gc.weighty = 0.0;
187 gc.insets = new Insets(0, 0, 10, 0);
188 add(lblHeading, gc);
189
190 gc.gridx = 0;
191 gc.gridy = 1;
192 gc.gridwidth = 1;
193 gc.gridheight = 1;
194 gc.fill = GridBagConstraints.HORIZONTAL;
195 gc.weightx = 0.0;
196 gc.weighty = 0.0;
197 gc.insets = new Insets(0, 0, 10, 10);
198 add(new JLabel(tr("Username")), gc);
199 gc.gridx = 1;
200 gc.gridy = 1;
201 gc.weightx = 1.0;
202 add(tfUserName, gc);
203 gc.gridx = 0;
204 gc.gridy = 2;
205 gc.weightx = 0.0;
206 add(new JLabel(tr("Password")), gc);
207
208 gc.gridx = 1;
209 gc.gridy = 2;
210 gc.weightx = 0.0;
211 add(tfPassword, gc);
212
213 gc.gridx = 0;
214 gc.gridy = 3;
215 gc.gridwidth = 2;
216 gc.gridheight = 1;
217 gc.fill = GridBagConstraints.BOTH;
218 gc.weightx = 1.0;
219 gc.weighty = 0.0;
220 lblWarning.setFont(lblWarning.getFont().deriveFont(Font.ITALIC));
221 add(lblWarning, gc);
222
223 gc.gridx = 0;
224 gc.gridy = 4;
225 gc.weighty = 0.0;
226 add(cbSaveCredentials, gc);
227
228 // consume the remaining space
229 gc.gridx = 0;
230 gc.gridy = 5;
231 gc.weighty = 1.0;
232 add(new JPanel(), gc);
233
234 }
235
236 public CredentialPanel(CredentialDialog owner) {
237 this.owner = owner;
238 }
239
240 public void init(String username, String password) {
241 username = username == null ? "" : username;
242 password = password == null ? "" : password;
243 tfUserName.setText(username);
244 tfPassword.setText(password);
245 cbSaveCredentials.setSelected(!username.isEmpty() && !password.isEmpty());
246 }
247
248 public void startUserInput() {
249 tfUserName.requestFocusInWindow();
250 }
251
252 public String getUserName() {
253 return tfUserName.getText();
254 }
255
256 public char[] getPassword() {
257 return tfPassword.getPassword();
258 }
259
260 public boolean isSaveCredentials() {
261 return cbSaveCredentials.isSelected();
262 }
263
264 protected final void updateWarningLabel(String url) {
265 boolean https = url != null && url.startsWith("https");
266 if (https) {
267 lblWarning.setText(null);
268 } else {
269 lblWarning.setText(tr("Warning: The password is transferred unencrypted."));
270 }
271 lblWarning.setVisible(!https);
272 }
273 }
274
275 private static class OsmApiCredentialsPanel extends CredentialPanel {
276
277 @Override
278 protected void build() {
279 super.build();
280 tfUserName.setToolTipText(tr("Please enter the user name of your OSM account"));
281 tfPassword.setToolTipText(tr("Please enter the password of your OSM account"));
282 String apiUrl = OsmApi.getOsmApi().getBaseUrl();
283 lblHeading.setText(
284 "<html>" + tr("Authenticating at the OSM API ''{0}'' failed. Please enter a valid username and a valid password.",
285 apiUrl) + "</html>");
286 updateWarningLabel(apiUrl);
287 }
288
289 OsmApiCredentialsPanel(CredentialDialog owner) {
290 super(owner);
291 build();
292 }
293 }
294
295 private static class OtherHostCredentialsPanel extends CredentialPanel {
296
297 private final String host;
298
299 @Override
300 protected void build() {
301 super.build();
302 tfUserName.setToolTipText(tr("Please enter the user name of your account"));
303 tfPassword.setToolTipText(tr("Please enter the password of your account"));
304 lblHeading.setText(
305 "<html>" + tr("Authenticating at the host ''{0}'' failed. Please enter a valid username and a valid password.",
306 host) + "</html>");
307 updateWarningLabel(host);
308 }
309
310 OtherHostCredentialsPanel(CredentialDialog owner, String host) {
311 super(owner);
312 this.host = host;
313 build();
314 }
315 }
316
317 private static class HttpProxyCredentialsPanel extends CredentialPanel {
318 @Override
319 protected void build() {
320 super.build();
321 tfUserName.setToolTipText(tr("Please enter the user name for authenticating at your proxy server"));
322 tfPassword.setToolTipText(tr("Please enter the password for authenticating at your proxy server"));
323 lblHeading.setText(
324 "<html>" + tr("Authenticating at the HTTP proxy ''{0}'' failed. Please enter a valid username and a valid password.",
325 Main.pref.get(ProxyPreferencesPanel.PROXY_HTTP_HOST) + ':' +
326 Main.pref.get(ProxyPreferencesPanel.PROXY_HTTP_PORT)) + "</html>");
327 lblWarning.setText("<html>" +
328 tr("Warning: depending on the authentication method the proxy server uses the password may be transferred unencrypted.")
329 + "</html>");
330 }
331
332 HttpProxyCredentialsPanel(CredentialDialog owner) {
333 super(owner);
334 build();
335 }
336 }
337
338 private static class SelectAllOnFocusHandler extends FocusAdapter {
339 @Override
340 public void focusGained(FocusEvent e) {
341 if (e.getSource() instanceof JTextField) {
342 JTextField tf = (JTextField) e.getSource();
343 tf.selectAll();
344 }
345 }
346 }
347
348 /**
349 * Listener for username and password text fields key events.
350 * When user presses Enter:
351 * If current text field is empty (or just contains a sequence of spaces), nothing happens (or all spaces become selected).
352 * If current text field is not empty, but the next one is (or just contains a sequence of spaces), focuses the next text field.
353 * If both text fields contain characters, submits the form by calling owner's {@link OKAction}.
354 */
355 private static class TFKeyListener extends KeyAdapter {
356 protected CredentialDialog owner; // owner Dependency Injection to call OKAction
357 protected JTextField currentTF;
358 protected JTextField nextTF;
359
360 TFKeyListener(CredentialDialog owner, JTextField currentTF, JTextField nextTF) {
361 this.owner = owner;
362 this.currentTF = currentTF;
363 this.nextTF = nextTF;
364 }
365
366 @Override
367 public void keyPressed(KeyEvent e) {
368 if (e.getKeyChar() == KeyEvent.VK_ENTER) {
369 if (currentTF.getText().trim().isEmpty()) {
370 currentTF.selectAll();
371 return;
372 } else if (nextTF.getText().trim().isEmpty()) {
373 nextTF.requestFocusInWindow();
374 nextTF.selectAll();
375 return;
376 } else {
377 OKAction okAction = owner.new OKAction();
378 okAction.actionPerformed(null);
379 }
380 }
381 }
382 }
383
384 class OKAction extends AbstractAction {
385 OKAction() {
386 putValue(NAME, tr("Authenticate"));
387 putValue(SHORT_DESCRIPTION, tr("Authenticate with the supplied username and password"));
388 putValue(SMALL_ICON, ImageProvider.get("ok"));
389 }
390
391 @Override
392 public void actionPerformed(ActionEvent arg0) {
393 setCanceled(false);
394 setVisible(false);
395 }
396 }
397
398 class CancelAction extends AbstractAction {
399 CancelAction() {
400 putValue(NAME, tr("Cancel"));
401 putValue(SHORT_DESCRIPTION, tr("Cancel authentication"));
402 putValue(SMALL_ICON, ImageProvider.get("cancel"));
403 }
404
405 public void cancel() {
406 setCanceled(true);
407 setVisible(false);
408 }
409
410 @Override
411 public void actionPerformed(ActionEvent arg0) {
412 cancel();
413 }
414 }
415
416 class WindowEventHander extends WindowAdapter {
417
418 @Override
419 public void windowActivated(WindowEvent e) {
420 if (pnlCredentials != null) {
421 pnlCredentials.startUserInput();
422 }
423 }
424
425 @Override
426 public void windowClosing(WindowEvent e) {
427 new CancelAction().cancel();
428 }
429 }
430}
Note: See TracBrowser for help on using the repository browser.