source: josm/trunk/src/org/openstreetmap/josm/gui/preferences/server/ProxyPreferencesPanel.java@ 17312

Last change on this file since 17312 was 17312, checked in by Don-vip, 3 years ago

see #7548 - fix UI issues in proxy preferences panel

  • Property svn:eol-style set to native
File size: 12.6 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.preferences.server;
3
4import static java.awt.GridBagConstraints.HORIZONTAL;
5import static org.openstreetmap.josm.tools.I18n.tr;
6import static org.openstreetmap.josm.tools.I18n.trc;
7
8import java.awt.Component;
9import java.awt.Dimension;
10import java.awt.GridBagConstraints;
11import java.awt.GridBagLayout;
12import java.awt.Insets;
13import java.awt.event.ItemEvent;
14import java.awt.event.ItemListener;
15import java.net.Authenticator.RequestorType;
16import java.net.PasswordAuthentication;
17import java.net.ProxySelector;
18import java.util.Arrays;
19import java.util.EnumMap;
20import java.util.Map;
21import java.util.Optional;
22
23import javax.swing.BorderFactory;
24import javax.swing.Box;
25import javax.swing.ButtonGroup;
26import javax.swing.JLabel;
27import javax.swing.JPanel;
28import javax.swing.JRadioButton;
29
30import org.openstreetmap.josm.gui.help.HelpUtil;
31import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
32import org.openstreetmap.josm.gui.widgets.JosmPasswordField;
33import org.openstreetmap.josm.gui.widgets.JosmTextField;
34import org.openstreetmap.josm.gui.widgets.VerticallyScrollablePanel;
35import org.openstreetmap.josm.io.DefaultProxySelector;
36import org.openstreetmap.josm.io.ProxyPolicy;
37import org.openstreetmap.josm.io.auth.CredentialsAgent;
38import org.openstreetmap.josm.io.auth.CredentialsAgentException;
39import org.openstreetmap.josm.io.auth.CredentialsManager;
40import org.openstreetmap.josm.spi.preferences.Config;
41import org.openstreetmap.josm.spi.preferences.IPreferences;
42import org.openstreetmap.josm.tools.GBC;
43import org.openstreetmap.josm.tools.Logging;
44
45/**
46 * Component allowing input of proxy settings.
47 */
48public class ProxyPreferencesPanel extends VerticallyScrollablePanel {
49
50 static final class AutoSizePanel extends JPanel {
51 AutoSizePanel() {
52 super(new GridBagLayout());
53 }
54
55 @Override
56 public Dimension getMinimumSize() {
57 return getPreferredSize();
58 }
59 }
60
61 private transient Map<ProxyPolicy, JRadioButton> rbProxyPolicy;
62 private final JosmTextField tfProxyHttpHost = new JosmTextField();
63 private final JosmTextField tfProxyHttpPort = new JosmTextField(5);
64 private final JosmTextField tfProxySocksHost = new JosmTextField(20);
65 private final JosmTextField tfProxySocksPort = new JosmTextField(5);
66 private final JosmTextField tfProxyHttpUser = new JosmTextField(20);
67 private final JosmPasswordField tfProxyHttpPassword = new JosmPasswordField(20);
68
69 private JPanel pnlHttpProxyConfigurationPanel;
70 private JPanel pnlSocksProxyConfigurationPanel;
71
72 /**
73 * Builds the panel for the HTTP proxy configuration
74 *
75 * @return panel with HTTP proxy configuration
76 */
77 protected final JPanel buildHttpProxyConfigurationPanel() {
78 JPanel pnl = new AutoSizePanel();
79 GridBagConstraints gc = new GridBagConstraints();
80
81 gc.anchor = GridBagConstraints.WEST;
82 gc.insets = new Insets(5, 5, 0, 0);
83 gc.fill = HORIZONTAL;
84 gc.weightx = 0.0;
85 pnl.add(new JLabel(tr("Host:")), gc);
86
87 gc.gridx = 1;
88 gc.weightx = 1.0;
89 pnl.add(tfProxyHttpHost, gc);
90
91 gc.gridy = 1;
92 gc.gridx = 0;
93 gc.fill = GridBagConstraints.NONE;
94 gc.weightx = 0.0;
95 pnl.add(new JLabel(trc("server", "Port:")), gc);
96
97 gc.gridx = 1;
98 gc.weightx = 1.0;
99 pnl.add(tfProxyHttpPort, gc);
100 tfProxyHttpPort.setMinimumSize(tfProxyHttpPort.getPreferredSize());
101
102 gc.gridy = 2;
103 gc.gridx = 0;
104 gc.gridwidth = 2;
105 gc.fill = HORIZONTAL;
106 gc.weightx = 1.0;
107 pnl.add(new JMultilineLabel(tr("Please enter a username and a password if your proxy requires authentication.")), gc);
108
109 gc.gridy = 3;
110 gc.gridx = 0;
111 gc.gridwidth = 1;
112 gc.fill = GridBagConstraints.NONE;
113 gc.weightx = 0.0;
114 pnl.add(new JLabel(tr("User:")), gc);
115
116 gc.gridy = 3;
117 gc.gridx = 1;
118 gc.weightx = 1.0;
119 pnl.add(tfProxyHttpUser, gc);
120 tfProxyHttpUser.setMinimumSize(tfProxyHttpUser.getPreferredSize());
121
122 gc.gridy = 4;
123 gc.gridx = 0;
124 gc.weightx = 0.0;
125 pnl.add(new JLabel(tr("Password:")), gc);
126
127 gc.gridx = 1;
128 gc.weightx = 1.0;
129 pnl.add(tfProxyHttpPassword, gc);
130 tfProxyHttpPassword.setMinimumSize(tfProxyHttpPassword.getPreferredSize());
131
132 // add an extra spacer, otherwise the layout is broken
133 gc.gridy = 5;
134 gc.gridx = 0;
135 gc.gridwidth = 2;
136 gc.fill = GridBagConstraints.BOTH;
137 gc.weightx = 1.0;
138 gc.weighty = 1.0;
139 pnl.add(new JPanel(), gc);
140 return pnl;
141 }
142
143 /**
144 * Builds the panel for the SOCKS proxy configuration
145 *
146 * @return panel with SOCKS proxy configuration
147 */
148 protected final JPanel buildSocksProxyConfigurationPanel() {
149 JPanel pnl = new AutoSizePanel();
150 GridBagConstraints gc = new GridBagConstraints();
151 gc.anchor = GridBagConstraints.WEST;
152 gc.insets = new Insets(5, 5, 0, 0);
153 gc.fill = HORIZONTAL;
154 gc.weightx = 0.0;
155 pnl.add(new JLabel(tr("Host:")), gc);
156
157 gc.gridx = 1;
158 gc.weightx = 1.0;
159 pnl.add(tfProxySocksHost, gc);
160
161 gc.gridy = 1;
162 gc.gridx = 0;
163 gc.weightx = 0.0;
164 gc.fill = GridBagConstraints.NONE;
165 pnl.add(new JLabel(trc("server", "Port:")), gc);
166
167 gc.gridx = 1;
168 gc.weightx = 1.0;
169 pnl.add(tfProxySocksPort, gc);
170 tfProxySocksPort.setMinimumSize(tfProxySocksPort.getPreferredSize());
171
172 // add an extra spacer, otherwise the layout is broken
173 gc.gridy = 2;
174 gc.gridx = 0;
175 gc.gridwidth = 2;
176 gc.fill = GridBagConstraints.BOTH;
177 gc.weightx = 1.0;
178 gc.weighty = 1.0;
179 pnl.add(new JPanel(), gc);
180 return pnl;
181 }
182
183 protected final JPanel buildProxySettingsPanel() {
184 JPanel pnl = new JPanel(new GridBagLayout());
185
186 ButtonGroup bgProxyPolicy = new ButtonGroup();
187 rbProxyPolicy = new EnumMap<>(ProxyPolicy.class);
188 ProxyPolicyChangeListener policyChangeListener = new ProxyPolicyChangeListener();
189 for (ProxyPolicy pp: ProxyPolicy.values()) {
190 rbProxyPolicy.put(pp, new JRadioButton());
191 bgProxyPolicy.add(rbProxyPolicy.get(pp));
192 rbProxyPolicy.get(pp).addItemListener(policyChangeListener);
193 }
194
195 // radio button "No proxy"
196 pnl.add(newRadioButton(ProxyPolicy.NO_PROXY, tr("No proxy")), GBC.eop().anchor(GBC.NORTHWEST));
197
198 // radio button "System settings"
199 pnl.add(newRadioButton(ProxyPolicy.USE_SYSTEM_SETTINGS, tr("Use standard system settings")), GBC.eol());
200 if (!DefaultProxySelector.willJvmRetrieveSystemProxies()) {
201 String msg = tr("Use standard system settings (disabled. Start JOSM with <tt>-Djava.net.useSystemProxies=true</tt> to enable)");
202 pnl.add(new JMultilineLabel("<html>" + msg + "</html>"), GBC.eop().fill(HORIZONTAL));
203 }
204
205 // radio button http proxy
206 pnl.add(newRadioButton(ProxyPolicy.USE_HTTP_PROXY, tr("Manually configure a HTTP proxy")), GBC.eol());
207
208 // the panel with the http proxy configuration parameters
209 pnlHttpProxyConfigurationPanel = buildHttpProxyConfigurationPanel();
210 pnl.add(pnlHttpProxyConfigurationPanel, GBC.eop().fill(HORIZONTAL));
211
212 // radio button SOCKS proxy
213 pnl.add(newRadioButton(ProxyPolicy.USE_SOCKS_PROXY, tr("Use a SOCKS proxy")), GBC.eol());
214
215 // the panel with the SOCKS configuration parameters
216 pnlSocksProxyConfigurationPanel = buildSocksProxyConfigurationPanel();
217 pnl.add(pnlSocksProxyConfigurationPanel, GBC.eop().fill(HORIZONTAL));
218
219 pnl.add(Box.createVerticalGlue(), GBC.eol().fill());
220
221 return pnl;
222 }
223
224 private JRadioButton newRadioButton(ProxyPolicy policy, String text) {
225 JRadioButton radioButton = rbProxyPolicy.get(policy);
226 radioButton.setText(text);
227 return radioButton;
228 }
229
230 /**
231 * Initializes the panel with the values from the preferences
232 */
233 public final void initFromPreferences() {
234 IPreferences pref = Config.getPref();
235 ProxyPolicy pp = Optional.ofNullable(ProxyPolicy.fromName(pref.get(DefaultProxySelector.PROXY_POLICY, null)))
236 .orElse(ProxyPolicy.NO_PROXY);
237 rbProxyPolicy.get(pp).setSelected(true);
238 tfProxyHttpHost.setText(pref.get(DefaultProxySelector.PROXY_HTTP_HOST, ""));
239 tfProxyHttpPort.setText(pref.get(DefaultProxySelector.PROXY_HTTP_PORT, ""));
240 tfProxySocksHost.setText(pref.get(DefaultProxySelector.PROXY_SOCKS_HOST, ""));
241 tfProxySocksPort.setText(pref.get(DefaultProxySelector.PROXY_SOCKS_PORT, ""));
242
243 if (pp == ProxyPolicy.USE_SYSTEM_SETTINGS && !DefaultProxySelector.willJvmRetrieveSystemProxies()) {
244 Logging.warn(tr("JOSM is configured to use proxies from the system setting, but the JVM is not configured to retrieve them. " +
245 "Resetting preferences to ''No proxy''"));
246 pp = ProxyPolicy.NO_PROXY;
247 rbProxyPolicy.get(pp).setSelected(true);
248 }
249
250 // save the proxy user and the proxy password to a credentials store managed by
251 // the credentials manager
252 CredentialsAgent cm = CredentialsManager.getInstance();
253 try {
254 PasswordAuthentication pa = cm.lookup(RequestorType.PROXY, tfProxyHttpHost.getText());
255 if (pa == null) {
256 tfProxyHttpUser.setText("");
257 tfProxyHttpPassword.setText("");
258 } else {
259 tfProxyHttpUser.setText(pa.getUserName() == null ? "" : pa.getUserName());
260 tfProxyHttpPassword.setText(pa.getPassword() == null ? "" : String.valueOf(pa.getPassword()));
261 }
262 } catch (CredentialsAgentException e) {
263 Logging.error(e);
264 tfProxyHttpUser.setText("");
265 tfProxyHttpPassword.setText("");
266 }
267 }
268
269 protected final void updateEnabledState() {
270 boolean isHttpProxy = rbProxyPolicy.get(ProxyPolicy.USE_HTTP_PROXY).isSelected();
271 for (Component c: pnlHttpProxyConfigurationPanel.getComponents()) {
272 c.setEnabled(isHttpProxy);
273 }
274
275 boolean isSocksProxy = rbProxyPolicy.get(ProxyPolicy.USE_SOCKS_PROXY).isSelected();
276 for (Component c: pnlSocksProxyConfigurationPanel.getComponents()) {
277 c.setEnabled(isSocksProxy);
278 }
279
280 rbProxyPolicy.get(ProxyPolicy.USE_SYSTEM_SETTINGS).setEnabled(DefaultProxySelector.willJvmRetrieveSystemProxies());
281 }
282
283 class ProxyPolicyChangeListener implements ItemListener {
284 @Override
285 public void itemStateChanged(ItemEvent e) {
286 updateEnabledState();
287 }
288 }
289
290 /**
291 * Constructs a new {@code ProxyPreferencesPanel}.
292 */
293 public ProxyPreferencesPanel() {
294 setLayout(new GridBagLayout());
295 setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
296 add(buildProxySettingsPanel(), GBC.eop().anchor(GridBagConstraints.NORTHWEST).fill(GridBagConstraints.BOTH));
297
298 initFromPreferences();
299 updateEnabledState();
300
301 HelpUtil.setHelpContext(this, HelpUtil.ht("/Preferences/Connection#ProxySettings"));
302 }
303
304 /**
305 * Saves the current values to the preferences
306 */
307 public void saveToPreferences() {
308 ProxyPolicy policy = Arrays.stream(ProxyPolicy.values())
309 .filter(pp -> rbProxyPolicy.get(pp).isSelected())
310 .findFirst().orElse(null);
311 IPreferences pref = Config.getPref();
312 pref.put(DefaultProxySelector.PROXY_POLICY, Optional.ofNullable(policy).orElse(ProxyPolicy.NO_PROXY).getName());
313 pref.put(DefaultProxySelector.PROXY_HTTP_HOST, tfProxyHttpHost.getText());
314 pref.put(DefaultProxySelector.PROXY_HTTP_PORT, tfProxyHttpPort.getText());
315 pref.put(DefaultProxySelector.PROXY_SOCKS_HOST, tfProxySocksHost.getText());
316 pref.put(DefaultProxySelector.PROXY_SOCKS_PORT, tfProxySocksPort.getText());
317
318 // update the proxy selector
319 ProxySelector selector = ProxySelector.getDefault();
320 if (selector instanceof DefaultProxySelector) {
321 ((DefaultProxySelector) selector).initFromPreferences();
322 }
323
324 CredentialsAgent cm = CredentialsManager.getInstance();
325 try {
326 PasswordAuthentication pa = new PasswordAuthentication(
327 tfProxyHttpUser.getText().trim(),
328 tfProxyHttpPassword.getPassword()
329 );
330 cm.store(RequestorType.PROXY, tfProxyHttpHost.getText(), pa);
331 } catch (CredentialsAgentException e) {
332 Logging.error(e);
333 }
334 }
335}
Note: See TracBrowser for help on using the repository browser.