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