001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.dialogs.changeset.query;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.awt.Color;
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.ButtonGroup;
015import javax.swing.JLabel;
016import javax.swing.JOptionPane;
017import javax.swing.JPanel;
018import javax.swing.JRadioButton;
019
020import org.openstreetmap.josm.Main;
021import org.openstreetmap.josm.gui.HelpAwareOptionPane;
022import org.openstreetmap.josm.gui.JosmUserIdentityManager;
023import org.openstreetmap.josm.gui.help.HelpUtil;
024import org.openstreetmap.josm.gui.preferences.server.UserNameValidator;
025import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
026import org.openstreetmap.josm.gui.widgets.JosmTextField;
027import org.openstreetmap.josm.gui.widgets.SelectAllOnFocusGainedDecorator;
028import org.openstreetmap.josm.io.ChangesetQuery;
029import org.openstreetmap.josm.tools.CheckParameterUtil;
030
031/**
032 * This is the panel for selecting whether the query should be restricted to a specific user.
033 * @since 11326 (extracted from AdvancedChangesetQueryPanel)
034 */
035public class UserRestrictionPanel extends JPanel implements RestrictionPanel {
036    private static final String PREF_ROOT = "changeset-query.advanced.user-restrictions";
037    private static final String PREF_QUERY_TYPE = PREF_ROOT + ".query-type";
038
039    private final ButtonGroup bgUserRestrictions = new ButtonGroup();
040    private final JRadioButton rbRestrictToMyself = new JRadioButton();
041    private final JRadioButton rbRestrictToUid = new JRadioButton();
042    private final JRadioButton rbRestrictToUserName = new JRadioButton();
043    private final JosmTextField tfUid = new JosmTextField(10);
044    private transient UidInputFieldValidator valUid;
045    private final JosmTextField tfUserName = new JosmTextField(10);
046    private transient UserNameValidator valUserName;
047    private final JMultilineLabel lblRestrictedToMyself = new JMultilineLabel(tr("Only changesets owned by myself"));
048
049    /**
050     * Constructs a new {@code UserRestrictionPanel}.
051     */
052    public UserRestrictionPanel() {
053        build();
054    }
055
056    protected JPanel buildUidInputPanel() {
057        JPanel pnl = new JPanel(new GridBagLayout());
058        GridBagConstraints gc = new GridBagConstraints();
059        gc.fill = GridBagConstraints.HORIZONTAL;
060        gc.weightx = 0.0;
061        gc.insets = new Insets(0, 0, 0, 3);
062        pnl.add(new JLabel(tr("User ID:")), gc);
063
064        gc.gridx = 1;
065        pnl.add(tfUid, gc);
066        SelectAllOnFocusGainedDecorator.decorate(tfUid);
067        valUid = UidInputFieldValidator.decorate(tfUid);
068
069        // grab remaining space
070        gc.gridx = 2;
071        gc.weightx = 1.0;
072        pnl.add(new JPanel(), gc);
073        return pnl;
074    }
075
076    protected JPanel buildUserNameInputPanel() {
077        JPanel pnl = new JPanel(new GridBagLayout());
078        GridBagConstraints gc = new GridBagConstraints();
079        gc.fill = GridBagConstraints.HORIZONTAL;
080        gc.weightx = 0.0;
081        gc.insets = new Insets(0, 0, 0, 3);
082        pnl.add(new JLabel(tr("User name:")), gc);
083
084        gc.gridx = 1;
085        pnl.add(tfUserName, gc);
086        SelectAllOnFocusGainedDecorator.decorate(tfUserName);
087        valUserName = new UserNameValidator(tfUserName);
088
089        // grab remaining space
090        gc.gridx = 2;
091        gc.weightx = 1.0;
092        pnl.add(new JPanel(), gc);
093        return pnl;
094    }
095
096    protected void build() {
097        setLayout(new GridBagLayout());
098        setBorder(BorderFactory.createCompoundBorder(
099                BorderFactory.createEmptyBorder(3, 3, 3, 3),
100                BorderFactory.createCompoundBorder(
101                        BorderFactory.createLineBorder(Color.GRAY),
102                        BorderFactory.createEmptyBorder(5, 5, 5, 5)
103                )
104        ));
105
106        ItemListener userRestrictionChangeHandler = new UserRestrictionChangedHandler();
107        GridBagConstraints gc = new GridBagConstraints();
108        gc.anchor = GridBagConstraints.NORTHWEST;
109        gc.gridx = 0;
110        gc.fill = GridBagConstraints.HORIZONTAL;
111        gc.weightx = 0.0;
112        add(rbRestrictToMyself, gc);
113        rbRestrictToMyself.addItemListener(userRestrictionChangeHandler);
114
115        gc.gridx = 1;
116        gc.fill = GridBagConstraints.HORIZONTAL;
117        gc.weightx = 1.0;
118        add(lblRestrictedToMyself, gc);
119
120        gc.gridx = 0;
121        gc.gridy = 1;
122        gc.fill = GridBagConstraints.HORIZONTAL;
123        gc.weightx = 0.0;
124        add(rbRestrictToUid, gc);
125        rbRestrictToUid.addItemListener(userRestrictionChangeHandler);
126
127        gc.gridx = 1;
128        gc.fill = GridBagConstraints.HORIZONTAL;
129        gc.weightx = 1.0;
130        add(new JMultilineLabel(tr("Only changesets owned by the user with the following user ID")), gc);
131
132        gc.gridx = 1;
133        gc.gridy = 2;
134        gc.fill = GridBagConstraints.HORIZONTAL;
135        gc.weightx = 1.0;
136        add(buildUidInputPanel(), gc);
137
138        gc.gridx = 0;
139        gc.gridy = 3;
140        gc.fill = GridBagConstraints.HORIZONTAL;
141        gc.weightx = 0.0;
142        add(rbRestrictToUserName, gc);
143        rbRestrictToUserName.addItemListener(userRestrictionChangeHandler);
144
145        gc.gridx = 1;
146        gc.fill = GridBagConstraints.HORIZONTAL;
147        gc.weightx = 1.0;
148        add(new JMultilineLabel(tr("Only changesets owned by the user with the following user name")), gc);
149
150        gc.gridx = 1;
151        gc.gridy = 4;
152        gc.fill = GridBagConstraints.HORIZONTAL;
153        gc.weightx = 1.0;
154        add(buildUserNameInputPanel(), gc);
155
156        bgUserRestrictions.add(rbRestrictToMyself);
157        bgUserRestrictions.add(rbRestrictToUid);
158        bgUserRestrictions.add(rbRestrictToUserName);
159    }
160
161    /**
162     * Initializes HMI for user input.
163     */
164    public void startUserInput() {
165        if (JosmUserIdentityManager.getInstance().isAnonymous()) {
166            lblRestrictedToMyself.setText(tr("Only changesets owned by myself (disabled. JOSM is currently run by an anonymous user)"));
167            rbRestrictToMyself.setEnabled(false);
168            if (rbRestrictToMyself.isSelected()) {
169                rbRestrictToUid.setSelected(true);
170            }
171        } else {
172            lblRestrictedToMyself.setText(tr("Only changesets owned by myself"));
173            rbRestrictToMyself.setEnabled(true);
174            rbRestrictToMyself.setSelected(true);
175        }
176        restoreFromSettings();
177    }
178
179    /**
180     * Sets the query restrictions on <code>query</code> for changeset owner based restrictions.
181     *
182     * @param query the query. Must not be null.
183     * @throws IllegalArgumentException if query is null
184     * @throws IllegalStateException if one of the available values for query parameters in this panel isn't valid
185     */
186    @Override
187    public void fillInQuery(ChangesetQuery query) {
188        CheckParameterUtil.ensureParameterNotNull(query, "query");
189        if (rbRestrictToMyself.isSelected()) {
190            JosmUserIdentityManager im = JosmUserIdentityManager.getInstance();
191            if (im.isPartiallyIdentified()) {
192                query.forUser(im.getUserName());
193            } else if (im.isFullyIdentified()) {
194                query.forUser(im.getUserId());
195            } else
196                throw new IllegalStateException(
197                        tr("Cannot restrict changeset query to the current user because the current user is anonymous"));
198        } else if (rbRestrictToUid.isSelected()) {
199            int uid = valUid.getUid();
200            if (uid > 0) {
201                query.forUser(uid);
202            } else
203                throw new IllegalStateException(tr("Current value ''{0}'' for user ID is not valid", tfUid.getText()));
204        } else if (rbRestrictToUserName.isSelected()) {
205            if (!valUserName.isValid())
206                throw new IllegalStateException(
207                        tr("Cannot restrict the changeset query to the user name ''{0}''", tfUserName.getText()));
208            query.forUser(tfUserName.getText());
209        }
210    }
211
212    /**
213     * Determines if the changeset query time information is valid.
214     * @return {@code true} if the changeset query time information is valid.
215     */
216    @Override
217    public boolean isValidChangesetQuery() {
218        if (rbRestrictToUid.isSelected())
219            return valUid.isValid();
220        else if (rbRestrictToUserName.isSelected())
221            return valUserName.isValid();
222        return true;
223    }
224
225    protected void alertInvalidUid() {
226        HelpAwareOptionPane.showOptionDialog(
227                this,
228                tr("Please enter a valid user ID"),
229                tr("Invalid user ID"),
230                JOptionPane.ERROR_MESSAGE,
231                HelpUtil.ht("/Dialog/ChangesetQueryDialog#InvalidUserId")
232        );
233    }
234
235    protected void alertInvalidUserName() {
236        HelpAwareOptionPane.showOptionDialog(
237                this,
238                tr("Please enter a non-empty user name"),
239                tr("Invalid user name"),
240                JOptionPane.ERROR_MESSAGE,
241                HelpUtil.ht("/Dialog/ChangesetQueryDialog#InvalidUserName")
242        );
243    }
244
245    @Override
246    public void displayMessageIfInvalid() {
247        if (rbRestrictToUid.isSelected()) {
248            if (!valUid.isValid()) {
249                alertInvalidUid();
250            }
251        } else if (rbRestrictToUserName.isSelected()) {
252            if (!valUserName.isValid()) {
253                alertInvalidUserName();
254            }
255        }
256    }
257
258    /**
259     * Remember settings in preferences.
260     */
261    public void rememberSettings() {
262        if (rbRestrictToMyself.isSelected()) {
263            Main.pref.put(PREF_QUERY_TYPE, "mine");
264        } else if (rbRestrictToUid.isSelected()) {
265            Main.pref.put(PREF_QUERY_TYPE, "uid");
266        } else if (rbRestrictToUserName.isSelected()) {
267            Main.pref.put(PREF_QUERY_TYPE, "username");
268        }
269        Main.pref.put(PREF_ROOT + ".uid", tfUid.getText());
270        Main.pref.put(PREF_ROOT + ".username", tfUserName.getText());
271    }
272
273    /**
274     * Restore settings from preferences.
275     */
276    public void restoreFromSettings() {
277        String v = Main.pref.get(PREF_QUERY_TYPE, "mine");
278        if ("mine".equals(v)) {
279            JosmUserIdentityManager im = JosmUserIdentityManager.getInstance();
280            if (im.isAnonymous()) {
281                rbRestrictToUid.setSelected(true);
282            } else {
283                rbRestrictToMyself.setSelected(true);
284            }
285        } else if ("uid".equals(v)) {
286            rbRestrictToUid.setSelected(true);
287        } else if ("username".equals(v)) {
288            rbRestrictToUserName.setSelected(true);
289        }
290        tfUid.setText(Main.pref.get(PREF_ROOT + ".uid", ""));
291        if (!valUid.isValid()) {
292            tfUid.setText("");
293        }
294        tfUserName.setText(Main.pref.get(PREF_ROOT + ".username", ""));
295    }
296
297    class UserRestrictionChangedHandler implements ItemListener {
298        @Override
299        public void itemStateChanged(ItemEvent e) {
300            tfUid.setEnabled(rbRestrictToUid.isSelected());
301            tfUserName.setEnabled(rbRestrictToUserName.isSelected());
302            if (rbRestrictToUid.isSelected()) {
303                tfUid.requestFocusInWindow();
304            } else if (rbRestrictToUserName.isSelected()) {
305                tfUserName.requestFocusInWindow();
306            }
307        }
308    }
309}