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