001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.oauth;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.awt.Component;
007import java.awt.GridBagConstraints;
008import java.awt.GridBagLayout;
009import java.awt.Insets;
010import java.awt.event.ItemEvent;
011import java.awt.event.ItemListener;
012
013import javax.swing.BorderFactory;
014import javax.swing.JCheckBox;
015import javax.swing.JLabel;
016import javax.swing.JOptionPane;
017
018import org.openstreetmap.josm.data.Preferences;
019import org.openstreetmap.josm.data.oauth.OAuthParameters;
020import org.openstreetmap.josm.gui.HelpAwareOptionPane;
021import org.openstreetmap.josm.gui.HelpAwareOptionPane.ButtonSpec;
022import org.openstreetmap.josm.gui.help.HelpUtil;
023import org.openstreetmap.josm.gui.widgets.JosmTextField;
024import org.openstreetmap.josm.gui.widgets.SelectAllOnFocusGainedDecorator;
025import org.openstreetmap.josm.gui.widgets.VerticallyScrollablePanel;
026import org.openstreetmap.josm.tools.CheckParameterUtil;
027import org.openstreetmap.josm.tools.ImageProvider;
028
029/**
030 * Panel allowing the user to setup advanced OAuth parameters:
031 * <ul>
032 * <li>Consumer key</li>
033 * <li>Consumer secret</li>
034 * <li>Request token URL</li>
035 * <li>Access token URL</li>
036 * <li>Authorize URL</li>
037 * </ul>
038 *
039 * @see OAuthParameters
040 * @since 2746
041 */
042public class AdvancedOAuthPropertiesPanel extends VerticallyScrollablePanel {
043
044    private JCheckBox cbUseDefaults;
045    private JosmTextField tfConsumerKey;
046    private JosmTextField tfConsumerSecret;
047    private JosmTextField tfRequestTokenURL;
048    private JosmTextField tfAccessTokenURL;
049    private JosmTextField tfAuthoriseURL;
050    private transient UseDefaultItemListener ilUseDefault;
051    private String apiUrl;
052
053    protected final void build() {
054        setLayout(new GridBagLayout());
055        setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
056        GridBagConstraints gc = new GridBagConstraints();
057
058        gc.anchor = GridBagConstraints.NORTHWEST;
059        gc.fill = GridBagConstraints.HORIZONTAL;
060        gc.weightx = 1.0;
061        gc.insets = new Insets(0, 0, 3, 3);
062        gc.gridwidth = 2;
063        cbUseDefaults = new JCheckBox(tr("Use default settings"));
064        add(cbUseDefaults, gc);
065
066        // -- consumer key
067        gc.gridy = 1;
068        gc.weightx = 0.0;
069        gc.gridwidth = 1;
070        add(new JLabel(tr("Consumer Key:")), gc);
071
072        gc.gridx = 1;
073        gc.weightx = 1.0;
074        add(tfConsumerKey = new JosmTextField(), gc);
075        SelectAllOnFocusGainedDecorator.decorate(tfConsumerKey);
076
077        // -- consumer secret
078        gc.gridy = 2;
079        gc.gridx = 0;
080        gc.weightx = 0.0;
081        add(new JLabel(tr("Consumer Secret:")), gc);
082
083        gc.gridx = 1;
084        gc.weightx = 1.0;
085        add(tfConsumerSecret = new JosmTextField(), gc);
086        SelectAllOnFocusGainedDecorator.decorate(tfConsumerSecret);
087
088        // -- request token URL
089        gc.gridy = 3;
090        gc.gridx = 0;
091        gc.weightx = 0.0;
092        add(new JLabel(tr("Request Token URL:")), gc);
093
094        gc.gridx = 1;
095        gc.weightx = 1.0;
096        add(tfRequestTokenURL = new JosmTextField(), gc);
097        SelectAllOnFocusGainedDecorator.decorate(tfRequestTokenURL);
098
099        // -- access token URL
100        gc.gridy = 4;
101        gc.gridx = 0;
102        gc.weightx = 0.0;
103        add(new JLabel(tr("Access Token URL:")), gc);
104
105        gc.gridx = 1;
106        gc.weightx = 1.0;
107        add(tfAccessTokenURL = new JosmTextField(), gc);
108        SelectAllOnFocusGainedDecorator.decorate(tfAccessTokenURL);
109
110
111        // -- authorise URL
112        gc.gridy = 5;
113        gc.gridx = 0;
114        gc.weightx = 0.0;
115        add(new JLabel(tr("Authorize URL:")), gc);
116
117        gc.gridx = 1;
118        gc.weightx = 1.0;
119        add(tfAuthoriseURL = new JosmTextField(), gc);
120        SelectAllOnFocusGainedDecorator.decorate(tfAuthoriseURL);
121
122        cbUseDefaults.addItemListener(ilUseDefault = new UseDefaultItemListener());
123    }
124
125    protected boolean hasCustomSettings() {
126        OAuthParameters params = OAuthParameters.createDefault(apiUrl);
127        return
128           !tfConsumerKey.getText().equals(params.getConsumerKey())
129        || !tfConsumerSecret.getText().equals(params.getConsumerSecret())
130        || !tfRequestTokenURL.getText().equals(params.getRequestTokenUrl())
131        || !tfAccessTokenURL.getText().equals(params.getAccessTokenUrl())
132        || !tfAuthoriseURL.getText().equals(params.getAuthoriseUrl());
133    }
134
135    protected boolean confirmOverwriteCustomSettings() {
136        ButtonSpec[] buttons = new ButtonSpec[] {
137                new ButtonSpec(
138                        tr("Continue"),
139                        ImageProvider.get("ok"),
140                        tr("Click to reset the OAuth settings to default values"),
141                        null /* no dedicated help topic */
142                ),
143                new ButtonSpec(
144                        tr("Cancel"),
145                        ImageProvider.get("cancel"),
146                        tr("Click to abort resetting to the OAuth default values"),
147                        null /* no dedicated help topic */
148                )
149        };
150        int ret = HelpAwareOptionPane.showOptionDialog(
151                AdvancedOAuthPropertiesPanel.this,
152                tr(
153                        "<html>JOSM is about to reset the OAuth settings to default values.<br>"
154                        + "The current custom settings are not saved.</html>"
155                ),
156                tr("Overwrite custom OAuth settings?"),
157                JOptionPane.WARNING_MESSAGE,
158                null, /* no dedicated icon */
159                buttons,
160                buttons[0],
161                HelpUtil.ht("/Dialog/OAuthAuthorisationWizard")
162        );
163
164        return ret == 0; // OK button clicked
165    }
166
167    protected void resetToDefaultSettings() {
168        cbUseDefaults.setSelected(true);
169        OAuthParameters params = OAuthParameters.createDefault(apiUrl);
170        tfConsumerKey.setText(params.getConsumerKey());
171        tfConsumerSecret.setText(params.getConsumerSecret());
172        tfRequestTokenURL.setText(params.getRequestTokenUrl());
173        tfAccessTokenURL.setText(params.getAccessTokenUrl());
174        tfAuthoriseURL.setText(params.getAuthoriseUrl());
175
176        setChildComponentsEnabled(false);
177    }
178
179    protected void setChildComponentsEnabled(boolean enabled) {
180        for (Component c: getComponents()) {
181            if (c instanceof JosmTextField || c instanceof JLabel) {
182                c.setEnabled(enabled);
183            }
184        }
185    }
186
187    /**
188     * Replies the OAuth parameters currently edited in this properties panel.
189     *
190     * @return the OAuth parameters
191     */
192    public OAuthParameters getAdvancedParameters() {
193        if (cbUseDefaults.isSelected())
194            return OAuthParameters.createDefault(apiUrl);
195        OAuthParameters parameters = new OAuthParameters();
196        parameters.setConsumerKey(tfConsumerKey.getText());
197        parameters.setConsumerSecret(tfConsumerSecret.getText());
198        parameters.setRequestTokenUrl(tfRequestTokenURL.getText());
199        parameters.setAccessTokenUrl(tfAccessTokenURL.getText());
200        parameters.setAuthoriseUrl(tfAuthoriseURL.getText());
201        return parameters;
202    }
203
204    /**
205     * Sets the advanced parameters to be displayed
206     *
207     * @param parameters the advanced parameters. Must not be null.
208     * @throws IllegalArgumentException if parameters is null.
209     */
210    public void setAdvancedParameters(OAuthParameters parameters) {
211        CheckParameterUtil.ensureParameterNotNull(parameters, "parameters");
212        if (parameters.equals(OAuthParameters.createDefault(apiUrl))) {
213            cbUseDefaults.setSelected(true);
214            setChildComponentsEnabled(false);
215        } else {
216            cbUseDefaults.setSelected(false);
217            setChildComponentsEnabled(true);
218            tfConsumerKey.setText(parameters.getConsumerKey() == null ? "" : parameters.getConsumerKey());
219            tfConsumerSecret.setText(parameters.getConsumerSecret() == null ? "" : parameters.getConsumerSecret());
220            tfRequestTokenURL.setText(parameters.getRequestTokenUrl() == null ? "" : parameters.getRequestTokenUrl());
221            tfAccessTokenURL.setText(parameters.getAccessTokenUrl() == null ? "" : parameters.getAccessTokenUrl());
222            tfAuthoriseURL.setText(parameters.getAuthoriseUrl() == null ? "" : parameters.getAuthoriseUrl());
223        }
224    }
225
226    /**
227     * Constructs a new {@code AdvancedOAuthPropertiesPanel}.
228     */
229    public AdvancedOAuthPropertiesPanel() {
230        build();
231    }
232
233    /**
234     * Initializes the panel from the values in the preferences <code>preferences</code>.
235     *
236     * @param pref the preferences. Must not be null.
237     * @throws IllegalArgumentException if pref is null
238     */
239    public void initFromPreferences(Preferences pref) {
240        CheckParameterUtil.ensureParameterNotNull(pref, "pref");
241        setApiUrl(pref.get("osm-server.url"));
242        boolean useDefault = pref.getBoolean("oauth.settings.use-default", true);
243        ilUseDefault.setEnabled(false);
244        if (useDefault) {
245            resetToDefaultSettings();
246        } else {
247            cbUseDefaults.setSelected(false);
248            tfConsumerKey.setText(pref.get("oauth.settings.consumer-key", OAuthParameters.DEFAULT_JOSM_CONSUMER_KEY));
249            tfConsumerSecret.setText(pref.get("oauth.settings.consumer-secret", OAuthParameters.DEFAULT_JOSM_CONSUMER_SECRET));
250            tfRequestTokenURL.setText(pref.get("oauth.settings.request-token-url", OAuthParameters.DEFAULT_REQUEST_TOKEN_URL));
251            tfAccessTokenURL.setText(pref.get("oauth.settings.access-token-url", OAuthParameters.DEFAULT_ACCESS_TOKEN_URL));
252            tfAuthoriseURL.setText(pref.get("oauth.settings.authorise-url", OAuthParameters.DEFAULT_AUTHORISE_URL));
253            setChildComponentsEnabled(true);
254        }
255        ilUseDefault.setEnabled(true);
256    }
257
258    /**
259     * Remembers the current values in the preferences <code>pref</code>.
260     *
261     * @param pref the preferences. Must not be null.
262     * @throws IllegalArgumentException if pref is null.
263     */
264    public void rememberPreferences(Preferences pref) {
265        CheckParameterUtil.ensureParameterNotNull(pref, "pref");
266        pref.put("oauth.settings.use-default", cbUseDefaults.isSelected());
267        if (cbUseDefaults.isSelected()) {
268            pref.put("oauth.settings.consumer-key", null);
269            pref.put("oauth.settings.consumer-secret", null);
270            pref.put("oauth.settings.request-token-url", null);
271            pref.put("oauth.settings.access-token-url", null);
272            pref.put("oauth.settings.authorise-url", null);
273        } else {
274            pref.put("oauth.settings.consumer-key", tfConsumerKey.getText().trim());
275            pref.put("oauth.settings.consumer-secret", tfConsumerSecret.getText().trim());
276            pref.put("oauth.settings.request-token-url", tfRequestTokenURL.getText().trim());
277            pref.put("oauth.settings.access-token-url", tfAccessTokenURL.getText().trim());
278            pref.put("oauth.settings.authorise-url", tfAuthoriseURL.getText().trim());
279        }
280    }
281
282    class UseDefaultItemListener implements ItemListener {
283        private boolean enabled;
284
285        @Override
286        public void itemStateChanged(ItemEvent e) {
287            if (!enabled) return;
288            switch (e.getStateChange()) {
289            case ItemEvent.SELECTED:
290                if (hasCustomSettings() && !confirmOverwriteCustomSettings()) {
291                    cbUseDefaults.setSelected(false);
292                    return;
293                }
294                resetToDefaultSettings();
295                break;
296            case ItemEvent.DESELECTED:
297                setChildComponentsEnabled(true);
298                break;
299            }
300        }
301
302        public void setEnabled(boolean enabled) {
303            this.enabled = enabled;
304        }
305    }
306
307    /**
308     * Sets the URL of the OSM API for which this panel is currently displaying OAuth properties.
309     *
310     * @param apiUrl the api URL
311     * @since 5422
312     */
313    public void setApiUrl(String apiUrl) {
314        this.apiUrl = apiUrl;
315        if (cbUseDefaults.isSelected()) {
316            resetToDefaultSettings();
317        }
318    }
319}