001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.preferences.server; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.BorderLayout; 007import java.awt.Color; 008import java.awt.FlowLayout; 009import java.awt.Font; 010import java.awt.GridBagConstraints; 011import java.awt.GridBagLayout; 012import java.awt.Insets; 013import java.awt.event.ActionEvent; 014import java.awt.event.ItemEvent; 015import java.awt.event.ItemListener; 016import java.beans.PropertyChangeEvent; 017import java.beans.PropertyChangeListener; 018 019import javax.swing.AbstractAction; 020import javax.swing.BorderFactory; 021import javax.swing.JCheckBox; 022import javax.swing.JLabel; 023import javax.swing.JPanel; 024 025import org.openstreetmap.josm.Main; 026import org.openstreetmap.josm.data.oauth.OAuthParameters; 027import org.openstreetmap.josm.data.oauth.OAuthToken; 028import org.openstreetmap.josm.gui.SideButton; 029import org.openstreetmap.josm.gui.oauth.AdvancedOAuthPropertiesPanel; 030import org.openstreetmap.josm.gui.oauth.OAuthAuthorizationWizard; 031import org.openstreetmap.josm.gui.oauth.TestAccessTokenTask; 032import org.openstreetmap.josm.gui.widgets.JMultilineLabel; 033import org.openstreetmap.josm.gui.widgets.JosmTextField; 034import org.openstreetmap.josm.io.OsmApi; 035import org.openstreetmap.josm.io.auth.CredentialsManager; 036import org.openstreetmap.josm.tools.ImageProvider; 037import org.openstreetmap.josm.tools.UserCancelException; 038 039/** 040 * The preferences panel for the OAuth preferences. This just a summary panel 041 * showing the current Access Token Key and Access Token Secret, if the 042 * user already has an Access Token. 043 * 044 * For initial authorisation see {@link OAuthAuthorizationWizard}. 045 * @since 2745 046 */ 047public class OAuthAuthenticationPreferencesPanel extends JPanel implements PropertyChangeListener { 048 private final JCheckBox cbShowAdvancedParameters = new JCheckBox(); 049 private final JCheckBox cbSaveToPreferences = new JCheckBox(tr("Save to preferences")); 050 private final JPanel pnlAuthorisationMessage = new JPanel(new BorderLayout()); 051 private final NotYetAuthorisedPanel pnlNotYetAuthorised = new NotYetAuthorisedPanel(); 052 private final AdvancedOAuthPropertiesPanel pnlAdvancedProperties = new AdvancedOAuthPropertiesPanel(); 053 private final AlreadyAuthorisedPanel pnlAlreadyAuthorised = new AlreadyAuthorisedPanel(); 054 private String apiUrl; 055 056 /** 057 * Create the panel 058 */ 059 public OAuthAuthenticationPreferencesPanel() { 060 build(); 061 refreshView(); 062 } 063 064 /** 065 * Builds the panel for entering the advanced OAuth parameters 066 * 067 * @return panel with advanced settings 068 */ 069 protected JPanel buildAdvancedPropertiesPanel() { 070 JPanel pnl = new JPanel(new GridBagLayout()); 071 GridBagConstraints gc = new GridBagConstraints(); 072 073 gc.anchor = GridBagConstraints.NORTHWEST; 074 gc.fill = GridBagConstraints.HORIZONTAL; 075 gc.weightx = 0.0; 076 gc.insets = new Insets(0, 0, 0, 3); 077 pnl.add(cbShowAdvancedParameters, gc); 078 cbShowAdvancedParameters.setSelected(false); 079 cbShowAdvancedParameters.addItemListener( 080 new ItemListener() { 081 @Override 082 public void itemStateChanged(ItemEvent evt) { 083 pnlAdvancedProperties.setVisible(evt.getStateChange() == ItemEvent.SELECTED); 084 } 085 } 086 ); 087 088 gc.gridx = 1; 089 gc.weightx = 1.0; 090 JMultilineLabel lbl = new JMultilineLabel(tr("Display Advanced OAuth Parameters")); 091 lbl.setFont(lbl.getFont().deriveFont(Font.PLAIN)); 092 pnl.add(lbl, gc); 093 094 gc.gridy = 1; 095 gc.gridx = 1; 096 gc.insets = new Insets(3, 0, 3, 0); 097 gc.fill = GridBagConstraints.BOTH; 098 gc.weightx = 1.0; 099 gc.weighty = 1.0; 100 pnl.add(pnlAdvancedProperties, gc); 101 pnlAdvancedProperties.initFromPreferences(Main.pref); 102 pnlAdvancedProperties.setBorder( 103 BorderFactory.createCompoundBorder( 104 BorderFactory.createLineBorder(Color.GRAY, 1), 105 BorderFactory.createEmptyBorder(3, 3, 3, 3) 106 ) 107 ); 108 pnlAdvancedProperties.setVisible(false); 109 return pnl; 110 } 111 112 /** 113 * builds the UI 114 */ 115 protected final void build() { 116 setLayout(new GridBagLayout()); 117 setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); 118 GridBagConstraints gc = new GridBagConstraints(); 119 120 // the panel for the OAuth parameters. pnlAuthorisationMessage is an 121 // empty panel. It is going to be filled later, depending on the 122 // current OAuth state in JOSM. 123 gc.fill = GridBagConstraints.BOTH; 124 gc.anchor = GridBagConstraints.NORTHWEST; 125 gc.weighty = 1.0; 126 gc.weightx = 1.0; 127 gc.insets = new Insets(10, 0, 0, 0); 128 add(pnlAuthorisationMessage, gc); 129 } 130 131 protected void refreshView() { 132 pnlAuthorisationMessage.removeAll(); 133 if (OAuthAccessTokenHolder.getInstance().containsAccessToken()) { 134 pnlAuthorisationMessage.add(pnlAlreadyAuthorised, BorderLayout.CENTER); 135 pnlAlreadyAuthorised.refreshView(); 136 pnlAlreadyAuthorised.revalidate(); 137 } else { 138 pnlAuthorisationMessage.add(pnlNotYetAuthorised, BorderLayout.CENTER); 139 pnlNotYetAuthorised.revalidate(); 140 } 141 repaint(); 142 } 143 144 /** 145 * Sets the URL of the OSM API for which this panel is currently displaying OAuth properties. 146 * 147 * @param apiUrl the api URL 148 */ 149 public void setApiUrl(String apiUrl) { 150 this.apiUrl = apiUrl; 151 pnlAdvancedProperties.setApiUrl(apiUrl); 152 } 153 154 /** 155 * Initializes the panel from preferences 156 */ 157 public void initFromPreferences() { 158 setApiUrl(OsmApi.getOsmApi().getServerUrl().trim()); 159 refreshView(); 160 } 161 162 /** 163 * Saves the current values to preferences 164 */ 165 public void saveToPreferences() { 166 OAuthAccessTokenHolder.getInstance().setSaveToPreferences(cbSaveToPreferences.isSelected()); 167 OAuthAccessTokenHolder.getInstance().save(Main.pref, CredentialsManager.getInstance()); 168 pnlAdvancedProperties.rememberPreferences(Main.pref); 169 } 170 171 /** 172 * The preferences panel displayed if there is currently no Access Token available. 173 * This means that the user didn't run through the OAuth authorisation procedure yet. 174 * 175 */ 176 private class NotYetAuthorisedPanel extends JPanel { 177 /** 178 * Constructs a new {@code NotYetAuthorisedPanel}. 179 */ 180 NotYetAuthorisedPanel() { 181 build(); 182 } 183 184 protected void build() { 185 setLayout(new GridBagLayout()); 186 GridBagConstraints gc = new GridBagConstraints(); 187 188 // A message explaining that the user isn't authorised yet 189 gc.anchor = GridBagConstraints.NORTHWEST; 190 gc.insets = new Insets(0, 0, 3, 0); 191 gc.fill = GridBagConstraints.HORIZONTAL; 192 gc.weightx = 1.0; 193 JMultilineLabel lbl = new JMultilineLabel( 194 tr("You do not have an Access Token yet to access the OSM server using OAuth. Please authorize first.")); 195 add(lbl, gc); 196 lbl.setFont(lbl.getFont().deriveFont(Font.PLAIN)); 197 198 // Action for authorising now 199 gc.gridy = 1; 200 gc.fill = GridBagConstraints.NONE; 201 gc.weightx = 0.0; 202 add(new SideButton(new AuthoriseNowAction()), gc); 203 204 // filler - grab remaining space 205 gc.gridy = 2; 206 gc.fill = GridBagConstraints.BOTH; 207 gc.weightx = 1.0; 208 gc.weighty = 1.0; 209 add(new JPanel(), gc); 210 } 211 } 212 213 /** 214 * The preferences panel displayed if there is currently an AccessToken available. 215 * 216 */ 217 private class AlreadyAuthorisedPanel extends JPanel { 218 private final JosmTextField tfAccessTokenKey = new JosmTextField(); 219 private final JosmTextField tfAccessTokenSecret = new JosmTextField(); 220 221 /** 222 * Constructs a new {@code AlreadyAuthorisedPanel}. 223 */ 224 AlreadyAuthorisedPanel() { 225 build(); 226 refreshView(); 227 } 228 229 protected void build() { 230 setLayout(new GridBagLayout()); 231 GridBagConstraints gc = new GridBagConstraints(); 232 gc.anchor = GridBagConstraints.NORTHWEST; 233 gc.insets = new Insets(0, 0, 3, 3); 234 gc.fill = GridBagConstraints.HORIZONTAL; 235 gc.weightx = 1.0; 236 gc.gridwidth = 2; 237 JMultilineLabel lbl = new JMultilineLabel(tr("You already have an Access Token to access the OSM server using OAuth.")); 238 add(lbl, gc); 239 lbl.setFont(lbl.getFont().deriveFont(Font.PLAIN)); 240 241 // -- access token key 242 gc.gridy = 1; 243 gc.gridx = 0; 244 gc.gridwidth = 1; 245 gc.weightx = 0.0; 246 add(new JLabel(tr("Access Token Key:")), gc); 247 248 gc.gridx = 1; 249 gc.weightx = 1.0; 250 add(tfAccessTokenKey, gc); 251 tfAccessTokenKey.setEditable(false); 252 253 // -- access token secret 254 gc.gridy = 2; 255 gc.gridx = 0; 256 gc.gridwidth = 1; 257 gc.weightx = 0.0; 258 add(new JLabel(tr("Access Token Secret:")), gc); 259 260 gc.gridx = 1; 261 gc.weightx = 1.0; 262 add(tfAccessTokenSecret, gc); 263 tfAccessTokenSecret.setEditable(false); 264 265 // -- access token secret 266 gc.gridy = 3; 267 gc.gridx = 0; 268 gc.gridwidth = 2; 269 gc.weightx = 1.0; 270 add(cbSaveToPreferences, gc); 271 cbSaveToPreferences.setSelected(OAuthAccessTokenHolder.getInstance().isSaveToPreferences()); 272 273 // -- action buttons 274 JPanel btns = new JPanel(new FlowLayout(FlowLayout.LEFT)); 275 btns.add(new SideButton(new RenewAuthorisationAction())); 276 btns.add(new SideButton(new TestAuthorisationAction())); 277 gc.gridy = 4; 278 gc.gridx = 0; 279 gc.gridwidth = 2; 280 gc.weightx = 1.0; 281 add(btns, gc); 282 283 // the panel with the advanced options 284 gc.gridy = 5; 285 gc.gridx = 0; 286 gc.gridwidth = 2; 287 gc.weightx = 1.0; 288 add(buildAdvancedPropertiesPanel(), gc); 289 290 // filler - grab the remaining space 291 gc.gridy = 6; 292 gc.fill = GridBagConstraints.BOTH; 293 gc.weightx = 1.0; 294 gc.weighty = 1.0; 295 add(new JPanel(), gc); 296 } 297 298 protected final void refreshView() { 299 String v = OAuthAccessTokenHolder.getInstance().getAccessTokenKey(); 300 tfAccessTokenKey.setText(v == null ? "" : v); 301 v = OAuthAccessTokenHolder.getInstance().getAccessTokenSecret(); 302 tfAccessTokenSecret.setText(v == null ? "" : v); 303 cbSaveToPreferences.setSelected(OAuthAccessTokenHolder.getInstance().isSaveToPreferences()); 304 } 305 } 306 307 /** 308 * Action to authorise the current user 309 */ 310 private class AuthoriseNowAction extends AbstractAction { 311 AuthoriseNowAction() { 312 putValue(NAME, tr("Authorize now")); 313 putValue(SHORT_DESCRIPTION, tr("Click to step through the OAuth authorization process")); 314 putValue(SMALL_ICON, ImageProvider.get("oauth", "oauth-small")); 315 } 316 317 @Override 318 public void actionPerformed(ActionEvent arg0) { 319 OAuthAuthorizationWizard wizard = new OAuthAuthorizationWizard( 320 OAuthAuthenticationPreferencesPanel.this, 321 apiUrl, 322 Main.worker); 323 try { 324 wizard.showDialog(); 325 } catch (UserCancelException ignore) { 326 Main.trace(ignore.toString()); 327 return; 328 } 329 pnlAdvancedProperties.setAdvancedParameters(wizard.getOAuthParameters()); 330 refreshView(); 331 } 332 } 333 334 /** 335 * Launches the OAuthAuthorisationWizard to generate a new Access Token 336 */ 337 private class RenewAuthorisationAction extends AuthoriseNowAction { 338 /** 339 * Constructs a new {@code RenewAuthorisationAction}. 340 */ 341 RenewAuthorisationAction() { 342 putValue(NAME, tr("New Access Token")); 343 putValue(SHORT_DESCRIPTION, tr("Click to step through the OAuth authorization process and generate a new Access Token")); 344 putValue(SMALL_ICON, ImageProvider.get("oauth", "oauth-small")); 345 } 346 } 347 348 /** 349 * Runs a test whether we can access the OSM server with the current Access Token 350 */ 351 private class TestAuthorisationAction extends AbstractAction { 352 /** 353 * Constructs a new {@code TestAuthorisationAction}. 354 */ 355 TestAuthorisationAction() { 356 putValue(NAME, tr("Test Access Token")); 357 putValue(SHORT_DESCRIPTION, tr("Click test access to the OSM server with the current access token")); 358 putValue(SMALL_ICON, ImageProvider.get("oauth", "oauth-small")); 359 360 } 361 362 @Override 363 public void actionPerformed(ActionEvent evt) { 364 OAuthToken token = OAuthAccessTokenHolder.getInstance().getAccessToken(); 365 OAuthParameters parameters = OAuthParameters.createFromPreferences(Main.pref); 366 TestAccessTokenTask task = new TestAccessTokenTask( 367 OAuthAuthenticationPreferencesPanel.this, 368 apiUrl, 369 parameters, 370 token 371 ); 372 Main.worker.submit(task); 373 } 374 } 375 376 @Override 377 public void propertyChange(PropertyChangeEvent evt) { 378 if (!evt.getPropertyName().equals(OsmApiUrlInputPanel.API_URL_PROP)) 379 return; 380 setApiUrl((String) evt.getNewValue()); 381 } 382}