001 // License: GPL. For details, see LICENSE file. 002 package org.openstreetmap.josm.gui.oauth; 003 004 import static org.openstreetmap.josm.tools.I18n.tr; 005 006 import java.awt.BorderLayout; 007 import java.awt.FlowLayout; 008 import java.awt.GridBagConstraints; 009 import java.awt.GridBagLayout; 010 import java.awt.Insets; 011 import java.awt.event.ActionEvent; 012 import java.beans.PropertyChangeEvent; 013 import java.beans.PropertyChangeListener; 014 015 import javax.swing.AbstractAction; 016 import javax.swing.BorderFactory; 017 import javax.swing.JCheckBox; 018 import javax.swing.JLabel; 019 import javax.swing.JPanel; 020 import javax.swing.JTabbedPane; 021 import javax.swing.JTextField; 022 import javax.swing.event.DocumentEvent; 023 import javax.swing.event.DocumentListener; 024 import javax.swing.text.JTextComponent; 025 026 import org.openstreetmap.josm.Main; 027 import org.openstreetmap.josm.data.oauth.OAuthToken; 028 import org.openstreetmap.josm.gui.SideButton; 029 import org.openstreetmap.josm.gui.preferences.server.OAuthAccessTokenHolder; 030 import org.openstreetmap.josm.gui.widgets.AbstractTextComponentValidator; 031 import org.openstreetmap.josm.gui.widgets.HtmlPanel; 032 import org.openstreetmap.josm.gui.widgets.SelectAllOnFocusGainedDecorator; 033 import org.openstreetmap.josm.tools.ImageProvider; 034 035 /** 036 * This is an UI which supports a JOSM user to get an OAuth Access Token in a fully 037 * manual process. 038 * 039 * @since 2746 040 */ 041 public class ManualAuthorizationUI extends AbstractAuthorizationUI{ 042 043 private JTextField tfAccessTokenKey; 044 private AccessTokenKeyValidator valAccessTokenKey; 045 private JTextField tfAccessTokenSecret; 046 private AccessTokenSecretValidator valAccessTokenSecret; 047 private JCheckBox cbSaveToPreferences; 048 private HtmlPanel pnlMessage; 049 050 protected JPanel buildAccessTokenPanel() { 051 JPanel pnl = new JPanel(new GridBagLayout()); 052 pnl.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); 053 GridBagConstraints gc = new GridBagConstraints(); 054 AccessTokenBuilder accessTokenBuilder = new AccessTokenBuilder(); 055 056 // the access token key input field 057 gc.anchor = GridBagConstraints.NORTHWEST; 058 gc.fill = GridBagConstraints.HORIZONTAL; 059 gc.weightx = 0.0; 060 gc.gridwidth = 2; 061 gc.insets = new Insets(0,0,5,0); 062 pnlMessage = new HtmlPanel(); 063 pnlMessage.setText("<html><body>" 064 + tr("Please enter an OAuth Access Token which is authorized to access the OSM server " 065 + "''{0}''.", 066 getApiUrl()) + "</body></html>"); 067 pnl.add(pnlMessage, gc); 068 069 // the access token key input field 070 gc.gridy = 1; 071 gc.weightx = 0.0; 072 gc.gridwidth = 1; 073 gc.insets = new Insets(0,0,0,3); 074 pnl.add(new JLabel(tr("Access Token Key:")), gc); 075 076 gc.gridx = 1; 077 gc.weightx = 1.0; 078 pnl.add(tfAccessTokenKey = new JTextField(), gc); 079 SelectAllOnFocusGainedDecorator.decorate(tfAccessTokenKey); 080 valAccessTokenKey = new AccessTokenKeyValidator(tfAccessTokenKey); 081 valAccessTokenKey.validate(); 082 tfAccessTokenKey.getDocument().addDocumentListener(accessTokenBuilder); 083 084 // the access token key input field 085 gc.gridy = 2; 086 gc.gridx = 0; 087 gc.weightx = 0.0; 088 pnl.add(new JLabel(tr("Access Token Secret:")), gc); 089 090 gc.gridx = 1; 091 gc.weightx = 1.0; 092 pnl.add(tfAccessTokenSecret = new JTextField(), gc); 093 SelectAllOnFocusGainedDecorator.decorate(tfAccessTokenSecret); 094 valAccessTokenSecret = new AccessTokenSecretValidator(tfAccessTokenSecret); 095 valAccessTokenSecret.validate(); 096 tfAccessTokenSecret.getDocument().addDocumentListener(accessTokenBuilder); 097 098 // the checkbox for saving to preferences 099 gc.gridy = 3; 100 gc.gridx = 0; 101 gc.gridwidth =2; 102 gc.weightx = 1.0; 103 pnl.add(cbSaveToPreferences = new JCheckBox(tr("Save Access Token in preferences")), gc); 104 cbSaveToPreferences.setSelected(OAuthAccessTokenHolder.getInstance().isSaveToPreferences()); 105 106 // filler - grab remaining space 107 gc.gridy = 3; 108 gc.gridx = 0; 109 gc.gridwidth =2; 110 gc.weightx = 1.0; 111 gc.weighty = 1.0; 112 gc.fill = GridBagConstraints.BOTH; 113 pnl.add(new JPanel(), gc); 114 return pnl; 115 } 116 117 protected JPanel buildTabbedPreferencesPanel() { 118 JPanel pnl = new JPanel(new BorderLayout()); 119 120 JTabbedPane tp = new JTabbedPane(); 121 tp.add(buildAccessTokenPanel()); 122 tp.add(getAdvancedPropertiesPanel()); 123 124 tp.setTitleAt(0, tr("Access Token")); 125 tp.setTitleAt(1, tr("Advanced OAuth parameters")); 126 127 tp.setToolTipTextAt(0, tr("Enter the OAuth Access Token")); 128 tp.setToolTipTextAt(1, tr("Enter advanced OAuth properties")); 129 130 pnl.add(tp, BorderLayout.CENTER); 131 return pnl; 132 } 133 134 protected JPanel buildActionsPanel() { 135 JPanel pnl = new JPanel(new FlowLayout(FlowLayout.LEFT)); 136 TestAccessTokenAction actTestAccessToken = new TestAccessTokenAction(); 137 pnl.add(new SideButton(actTestAccessToken)); 138 this.addPropertyChangeListener(actTestAccessToken); 139 return pnl; 140 } 141 142 @Override 143 public void setApiUrl(String apiUrl) { 144 super.setApiUrl(apiUrl); 145 if (pnlMessage != null) { 146 pnlMessage.setText(tr("<html><body>" 147 + "Please enter an OAuth Access Token which is authorized to access the OSM server " 148 + "''{0}''." 149 + "</body></html>", 150 getApiUrl() 151 )); 152 } 153 } 154 155 protected void build() { 156 setLayout(new BorderLayout()); 157 setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); 158 add(buildTabbedPreferencesPanel(), BorderLayout.CENTER); 159 add(buildActionsPanel(), BorderLayout.SOUTH); 160 } 161 162 /** 163 * Constructs a new {@code ManualAuthorizationUI} for the given API URL. 164 * @param apiUrl The OSM API URL 165 * @since 5422 166 */ 167 public ManualAuthorizationUI(String apiUrl) { 168 super(apiUrl); 169 build(); 170 } 171 172 @Override 173 public boolean isSaveAccessTokenToPreferences() { 174 return cbSaveToPreferences.isSelected(); 175 } 176 177 static private class AccessTokenKeyValidator extends AbstractTextComponentValidator { 178 179 public AccessTokenKeyValidator(JTextComponent tc) throws IllegalArgumentException { 180 super(tc); 181 } 182 183 @Override 184 public boolean isValid() { 185 return ! getComponent().getText().trim().equals(""); 186 } 187 188 @Override 189 public void validate() { 190 if (isValid()) { 191 feedbackValid(tr("Please enter an Access Token Key")); 192 } else { 193 feedbackInvalid(tr("The Access Token Key must not be empty. Please enter an Access Token Key")); 194 } 195 } 196 } 197 198 static private class AccessTokenSecretValidator extends AbstractTextComponentValidator { 199 public AccessTokenSecretValidator(JTextComponent tc) throws IllegalArgumentException { 200 super(tc); 201 } 202 203 @Override 204 public boolean isValid() { 205 return ! getComponent().getText().trim().equals(""); 206 } 207 208 @Override 209 public void validate() { 210 if (isValid()) { 211 feedbackValid(tr("Please enter an Access Token Secret")); 212 } else { 213 feedbackInvalid(tr("The Access Token Secret must not be empty. Please enter an Access Token Secret")); 214 } 215 } 216 } 217 218 class AccessTokenBuilder implements DocumentListener { 219 220 public void build() { 221 if (! valAccessTokenKey.isValid() || !valAccessTokenSecret.isValid()) { 222 setAccessToken(null); 223 } else { 224 setAccessToken(new OAuthToken(tfAccessTokenKey.getText().trim(), tfAccessTokenSecret.getText().trim())); 225 } 226 } 227 public void changedUpdate(DocumentEvent e) { 228 build(); 229 } 230 231 public void insertUpdate(DocumentEvent e) { 232 build(); 233 } 234 235 public void removeUpdate(DocumentEvent e) { 236 build(); 237 } 238 } 239 240 /** 241 * Action for testing an Access Token 242 */ 243 class TestAccessTokenAction extends AbstractAction implements PropertyChangeListener { 244 public TestAccessTokenAction() { 245 putValue(NAME, tr("Test Access Token")); 246 putValue(SMALL_ICON, ImageProvider.get("oauth", "oauth")); 247 putValue(SHORT_DESCRIPTION, tr("Click to test the Access Token")); 248 updateEnabledState(); 249 } 250 251 public void actionPerformed(ActionEvent evt) { 252 TestAccessTokenTask task = new TestAccessTokenTask( 253 ManualAuthorizationUI.this, 254 getApiUrl(), 255 getAdvancedPropertiesPanel().getAdvancedParameters(), 256 getAccessToken() 257 ); 258 Main.worker.submit(task); 259 } 260 261 protected void updateEnabledState() { 262 setEnabled(hasAccessToken()); 263 } 264 265 public void propertyChange(PropertyChangeEvent evt) { 266 if (! evt.getPropertyName().equals(AbstractAuthorizationUI.ACCESS_TOKEN_PROP)) 267 return; 268 updateEnabledState(); 269 } 270 } 271 }