// License: GPL. For details, see LICENSE file.
package org.openstreetmap.josm.gui.preferences.server;
import static org.openstreetmap.josm.tools.I18n.tr;
import static org.openstreetmap.josm.tools.I18n.trc;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.net.PasswordAuthentication;
import java.net.ProxySelector;
import java.net.Authenticator.RequestorType;
import java.util.HashMap;
import java.util.Map;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.gui.JMultilineLabel;
import org.openstreetmap.josm.gui.help.HelpUtil;
import org.openstreetmap.josm.gui.widgets.VerticallyScrollablePanel;
import org.openstreetmap.josm.io.DefaultProxySelector;
import org.openstreetmap.josm.io.auth.CredentialsManager;
import org.openstreetmap.josm.io.auth.CredentialsManagerException;
import org.openstreetmap.josm.io.auth.CredentialsManagerFactory;
import org.openstreetmap.josm.tools.GBC;
public class ProxyPreferencesPanel extends VerticallyScrollablePanel {
public enum ProxyPolicy {
NO_PROXY("no-proxy"),
USE_SYSTEM_SETTINGS("use-system-settings"),
USE_HTTP_PROXY("use-http-proxy"),
USE_SOCKS_PROXY("use-socks-proxy");
private String policyName;
ProxyPolicy(String policyName) {
this.policyName = policyName;
}
public String getName() {
return policyName;
}
static public ProxyPolicy fromName(String policyName) {
if (policyName == null) return null;
policyName = policyName.trim().toLowerCase();
for(ProxyPolicy pp: values()) {
if (pp.getName().equals(policyName))
return pp;
}
return null;
}
}
public static final String PROXY_POLICY = "proxy.policy";
public static final String PROXY_HTTP_HOST = "proxy.http.host";
public static final String PROXY_HTTP_PORT = "proxy.http.port";
public static final String PROXY_SOCKS_HOST = "proxy.socks.host";
public static final String PROXY_SOCKS_PORT = "proxy.socks.port";
public static final String PROXY_USER = "proxy.user";
public static final String PROXY_PASS = "proxy.pass";
private ButtonGroup bgProxyPolicy;
private Map<ProxyPolicy, JRadioButton> rbProxyPolicy;
private JTextField tfProxyHttpHost;
private JTextField tfProxyHttpPort;
private JTextField tfProxySocksHost;
private JTextField tfProxySocksPort;
private JTextField tfProxyHttpUser;
private JPasswordField tfProxyHttpPassword;
private JPanel pnlHttpProxyConfigurationPanel;
private JPanel pnlSocksProxyConfigurationPanel;
/**
* Builds the panel for the HTTP proxy configuration
*
* @return
*/
protected JPanel buildHttpProxyConfigurationPanel() {
JPanel pnl = new JPanel(new GridBagLayout()) {
@Override
public Dimension getMinimumSize() {
return getPreferredSize();
}
};
GridBagConstraints gc = new GridBagConstraints();
gc.anchor = GridBagConstraints.WEST;
gc.insets = new Insets(5,5,0,0);
gc.fill = GridBagConstraints.HORIZONTAL;
gc.weightx = 0.0;
pnl.add(new JLabel(tr("Host:")), gc);
gc.gridx = 1;
gc.weightx = 1.0;
pnl.add(tfProxyHttpHost = new JTextField(),gc);
gc.gridy = 1;
gc.gridx = 0;
gc.fill = GridBagConstraints.NONE;
gc.weightx = 0.0;
pnl.add(new JLabel(trc("server", "Port:")), gc);
gc.gridx = 1;
gc.weightx = 1.0;
pnl.add(tfProxyHttpPort = new JTextField(5),gc);
tfProxyHttpPort.setMinimumSize(tfProxyHttpPort.getPreferredSize());
gc.gridy = 2;
gc.gridx = 0;
gc.gridwidth = 2;
gc.fill = GridBagConstraints.HORIZONTAL;
gc.weightx = 1.0;
pnl.add(new JMultilineLabel(tr("Please enter a username and a password if your proxy requires authentication.")), gc);
gc.gridy = 3;
gc.gridx = 0;
gc.gridwidth = 1;
gc.fill = GridBagConstraints.NONE;
gc.weightx = 0.0;
pnl.add(new JLabel(tr("User:")), gc);
gc.gridy = 3;
gc.gridx = 1;
gc.weightx = 1.0;
pnl.add(tfProxyHttpUser = new JTextField(20),gc);
tfProxyHttpUser.setMinimumSize(tfProxyHttpUser.getPreferredSize());
gc.gridy = 4;
gc.gridx = 0;
gc.weightx = 0.0;
pnl.add(new JLabel(tr("Password:")), gc);
gc.gridx = 1;
gc.weightx = 1.0;
pnl.add(tfProxyHttpPassword = new JPasswordField(20),gc);
tfProxyHttpPassword.setMinimumSize(tfProxyHttpPassword.getPreferredSize());
// add an extra spacer, otherwise the layout is broken
gc.gridy = 5;
gc.gridx = 0;
gc.gridwidth = 2;
gc.fill = GridBagConstraints.BOTH;
gc.weightx = 1.0;
gc.weighty = 1.0;
pnl.add(new JPanel(), gc);
return pnl;
}
/**
* Builds the panel for the SOCKS proxy configuration
*
* @return
*/
protected JPanel buildSocksProxyConfigurationPanel() {
JPanel pnl = new JPanel(new GridBagLayout()) {
@Override
public Dimension getMinimumSize() {
return getPreferredSize();
}
};
GridBagConstraints gc = new GridBagConstraints();
gc.anchor = GridBagConstraints.WEST;
gc.insets = new Insets(5,5,0,0);
gc.fill = GridBagConstraints.HORIZONTAL;
gc.weightx = 0.0;
pnl.add(new JLabel(tr("Host:")), gc);
gc.gridx = 1;
gc.weightx = 1.0;
pnl.add(tfProxySocksHost = new JTextField(20),gc);
gc.gridy = 1;
gc.gridx = 0;
gc.weightx = 0.0;
gc.fill = GridBagConstraints.NONE;
pnl.add(new JLabel(trc("server", "Port:")), gc);
gc.gridx = 1;
gc.weightx = 1.0;
pnl.add(tfProxySocksPort = new JTextField(5), gc);
tfProxySocksPort.setMinimumSize(tfProxySocksPort.getPreferredSize());
// add an extra spacer, otherwise the layout is broken
gc.gridy = 2;
gc.gridx = 0;
gc.gridwidth = 2;
gc.fill = GridBagConstraints.BOTH;
gc.weightx = 1.0;
gc.weighty = 1.0;
pnl.add(new JPanel(), gc);
return pnl;
}
protected JPanel buildProxySettingsPanel() {
JPanel pnl = new JPanel(new GridBagLayout());
GridBagConstraints gc = new GridBagConstraints();
bgProxyPolicy = new ButtonGroup();
rbProxyPolicy = new HashMap<ProxyPolicy, JRadioButton>();
ProxyPolicyChangeListener policyChangeListener = new ProxyPolicyChangeListener();
for (ProxyPolicy pp: ProxyPolicy.values()) {
rbProxyPolicy.put(pp, new JRadioButton());
bgProxyPolicy.add(rbProxyPolicy.get(pp));
rbProxyPolicy.get(pp).addItemListener(policyChangeListener);
}
// radio button "No proxy"
gc.gridx = 0;
gc.gridy = 0;
gc.fill = GridBagConstraints.HORIZONTAL;
gc.anchor = GridBagConstraints.NORTHWEST;
gc.weightx = 0.0;
pnl.add(rbProxyPolicy.get(ProxyPolicy.NO_PROXY),gc);
gc.gridx = 1;
gc.weightx = 1.0;
pnl.add(new JLabel(tr("No proxy")), gc);
// radio button "System settings"
gc.gridx = 0;
gc.gridy = 1;
gc.weightx = 0.0;
pnl.add(rbProxyPolicy.get(ProxyPolicy.USE_SYSTEM_SETTINGS),gc);
gc.gridx = 1;
gc.weightx = 1.0;
String msg;
if (DefaultProxySelector.willJvmRetrieveSystemProxies()) {
msg = tr("Use standard system settings");
} else {
msg = tr("Use standard system settings (disabled. Start JOSM with <tt>-Djava.net.useSystemProxies=true</tt> to enable)");
}
pnl.add(new JMultilineLabel("<html>" + msg + "</html>"), gc);
// radio button http proxy
gc.gridx = 0;
gc.gridy = 2;
gc.weightx = 0.0;
pnl.add(rbProxyPolicy.get(ProxyPolicy.USE_HTTP_PROXY),gc);
gc.gridx = 1;
gc.weightx = 1.0;
pnl.add(new JLabel(tr("Manually configure a HTTP proxy")),gc);
// the panel with the http proxy configuration parameters
gc.gridx = 1;
gc.gridy = 3;
gc.fill = GridBagConstraints.HORIZONTAL;
gc.weightx = 1.0;
gc.weighty = 0.0;
pnl.add(pnlHttpProxyConfigurationPanel = buildHttpProxyConfigurationPanel(),gc);
// radio button SOCKS proxy
gc.gridx = 0;
gc.gridy = 4;
gc.weightx = 0.0;
pnl.add(rbProxyPolicy.get(ProxyPolicy.USE_SOCKS_PROXY),gc);
gc.gridx = 1;
gc.weightx = 1.0;
pnl.add(new JLabel(tr("Use a SOCKS proxy")),gc);
// the panel with the SOCKS configuration parameters
gc.gridx = 1;
gc.gridy = 5;
gc.fill = GridBagConstraints.BOTH;
gc.anchor = GridBagConstraints.WEST;
gc.weightx = 1.0;
gc.weighty = 0.0;
pnl.add(pnlSocksProxyConfigurationPanel = buildSocksProxyConfigurationPanel(),gc);
return pnl;
}
/**
* Initializes the panel with the values from the preferences
*/
public void initFromPreferences() {
String policy = Main.pref.get(PROXY_POLICY, null);
ProxyPolicy pp = ProxyPolicy.fromName(policy);
pp = pp == null? ProxyPolicy.NO_PROXY: pp;
rbProxyPolicy.get(pp).setSelected(true);
String value = Main.pref.get("proxy.host", null);
if (value != null) {
// legacy support
tfProxyHttpHost.setText(value);
Main.pref.put("proxy.host", null);
} else {
tfProxyHttpHost.setText(Main.pref.get(PROXY_HTTP_HOST, ""));
}
value = Main.pref.get("proxy.port", null);
if (value != null) {
// legacy support
tfProxyHttpPort.setText(value);
Main.pref.put("proxy.port", null);
} else {
tfProxyHttpPort.setText(Main.pref.get(PROXY_HTTP_PORT, ""));
}
tfProxySocksHost.setText(Main.pref.get(PROXY_SOCKS_HOST, ""));
tfProxySocksPort.setText(Main.pref.get(PROXY_SOCKS_PORT, ""));
if (pp.equals(ProxyPolicy.USE_SYSTEM_SETTINGS) && ! DefaultProxySelector.willJvmRetrieveSystemProxies()) {
System.err.println(tr("Warning: JOSM is configured to use proxies from the system setting, but the JVM is not configured to retrieve them. Resetting preferences to ''No proxy''"));
pp = ProxyPolicy.NO_PROXY;
rbProxyPolicy.get(pp).setSelected(true);
}
// save the proxy user and the proxy password to a credentials store managed by
// the credentials manager
CredentialsManager cm = CredentialsManagerFactory.getCredentialManager();
try {
PasswordAuthentication pa = cm.lookup(RequestorType.PROXY);
if (pa == null) {
tfProxyHttpUser.setText("");
tfProxyHttpPassword.setText("");
} else {
tfProxyHttpUser.setText(pa.getUserName() == null ? "" : pa.getUserName());
tfProxyHttpPassword.setText(pa.getPassword() == null ? "" : String.valueOf(pa.getPassword()));
}
} catch(CredentialsManagerException e) {
e.printStackTrace();
tfProxyHttpUser.setText("");
tfProxyHttpPassword.setText("");
}
}
protected void updateEnabledState() {
boolean isHttpProxy = rbProxyPolicy.get(ProxyPolicy.USE_HTTP_PROXY).isSelected();
for (Component c: pnlHttpProxyConfigurationPanel.getComponents()) {
c.setEnabled(isHttpProxy);
}
boolean isSocksProxy = rbProxyPolicy.get(ProxyPolicy.USE_SOCKS_PROXY).isSelected();
for (Component c: pnlSocksProxyConfigurationPanel.getComponents()) {
c.setEnabled(isSocksProxy);
}
rbProxyPolicy.get(ProxyPolicy.USE_SYSTEM_SETTINGS).setEnabled(DefaultProxySelector.willJvmRetrieveSystemProxies());
}
class ProxyPolicyChangeListener implements ItemListener {
public void itemStateChanged(ItemEvent arg0) {
updateEnabledState();
}
}
public ProxyPreferencesPanel() {
setLayout(new GridBagLayout());
setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
add(buildProxySettingsPanel(), GBC.eop().anchor(GridBagConstraints.NORTHWEST).fill(GridBagConstraints.BOTH));
initFromPreferences();
updateEnabledState();
HelpUtil.setHelpContext(this, HelpUtil.ht("/Preferences/Connection#ProxySettings"));
}
/**
* Saves the current values to the preferences
*/
public void saveToPreferences() {
ProxyPolicy policy = null;
for (ProxyPolicy pp: ProxyPolicy.values()) {
if (rbProxyPolicy.get(pp).isSelected()) {
policy = pp;
break;
}
}
if (policy == null) {
policy = ProxyPolicy.NO_PROXY;
}
Main.pref.put(PROXY_POLICY, policy.getName());
Main.pref.put(PROXY_HTTP_HOST, tfProxyHttpHost.getText());
Main.pref.put(PROXY_HTTP_PORT, tfProxyHttpPort.getText());
Main.pref.put(PROXY_SOCKS_HOST, tfProxySocksHost.getText());
Main.pref.put(PROXY_SOCKS_PORT, tfProxySocksPort.getText());
// update the proxy selector
ProxySelector selector = ProxySelector.getDefault();
if (selector instanceof DefaultProxySelector) {
((DefaultProxySelector)selector).initFromPreferences();
}
CredentialsManager cm = CredentialsManagerFactory.getCredentialManager();
try {
PasswordAuthentication pa = new PasswordAuthentication(
tfProxyHttpUser.getText().trim(),
tfProxyHttpPassword.getPassword()
);
cm.store(RequestorType.PROXY, pa);
} catch(CredentialsManagerException e) {
e.printStackTrace();
}
}
}