source: josm/trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/query/AdvancedChangesetQueryPanel.java@ 8540

Last change on this file since 8540 was 8540, checked in by Don-vip, 9 years ago

fix remaining checkstyle issues

  • Property svn:eol-style set to native
File size: 46.5 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.dialogs.changeset.query;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.BorderLayout;
7import java.awt.Color;
8import java.awt.GridBagConstraints;
9import java.awt.GridBagLayout;
10import java.awt.Insets;
11import java.awt.event.ItemEvent;
12import java.awt.event.ItemListener;
13import java.text.DateFormat;
14import java.text.ParseException;
15import java.util.Date;
16import java.util.GregorianCalendar;
17import java.util.Locale;
18
19import javax.swing.BorderFactory;
20import javax.swing.ButtonGroup;
21import javax.swing.JCheckBox;
22import javax.swing.JLabel;
23import javax.swing.JOptionPane;
24import javax.swing.JPanel;
25import javax.swing.JRadioButton;
26import javax.swing.JScrollPane;
27import javax.swing.text.JTextComponent;
28
29import org.openstreetmap.josm.Main;
30import org.openstreetmap.josm.gui.HelpAwareOptionPane;
31import org.openstreetmap.josm.gui.JosmUserIdentityManager;
32import org.openstreetmap.josm.gui.help.HelpUtil;
33import org.openstreetmap.josm.gui.util.GuiHelper;
34import org.openstreetmap.josm.gui.widgets.AbstractTextComponentValidator;
35import org.openstreetmap.josm.gui.widgets.BoundingBoxSelectionPanel;
36import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
37import org.openstreetmap.josm.gui.widgets.JosmTextField;
38import org.openstreetmap.josm.gui.widgets.SelectAllOnFocusGainedDecorator;
39import org.openstreetmap.josm.gui.widgets.VerticallyScrollablePanel;
40import org.openstreetmap.josm.io.ChangesetQuery;
41import org.openstreetmap.josm.tools.CheckParameterUtil;
42
43
44/**
45 * This panel allows to specify a changeset query
46 *
47 */
48public class AdvancedChangesetQueryPanel extends JPanel {
49
50 private JCheckBox cbUserRestriction;
51 private JCheckBox cbOpenAndCloseRestrictions;
52 private JCheckBox cbTimeRestrictions;
53 private JCheckBox cbBoundingBoxRestriction;
54 private UserRestrictionPanel pnlUserRestriction;
55 private OpenAndCloseStateRestrictionPanel pnlOpenAndCloseRestriction;
56 private TimeRestrictionPanel pnlTimeRestriction;
57 private BBoxRestrictionPanel pnlBoundingBoxRestriction;
58
59 protected JPanel buildQueryPanel() {
60 ItemListener stateChangeHandler = new RestrictionGroupStateChangeHandler();
61 JPanel pnl = new VerticallyScrollablePanel();
62 pnl.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
63 pnl.setLayout(new GridBagLayout());
64 GridBagConstraints gc = new GridBagConstraints();
65
66 // -- select changesets by a specific user
67 //
68 gc.anchor = GridBagConstraints.NORTHWEST;
69 gc.weightx = 0.0;
70 gc.fill = GridBagConstraints.HORIZONTAL;
71 pnl.add(cbUserRestriction = new JCheckBox(), gc);
72 cbUserRestriction.addItemListener(stateChangeHandler);
73
74 gc.gridx = 1;
75 gc.weightx = 1.0;
76 pnl.add(new JMultilineLabel(tr("Select changesets owned by specific users")), gc);
77
78 gc.gridy = 1;
79 gc.gridx = 1;
80 gc.weightx = 1.0;
81 pnl.add(pnlUserRestriction = new UserRestrictionPanel(), gc);
82
83 // -- restricting the query to open and closed changesets
84 //
85 gc.gridy = 2;
86 gc.gridx = 0;
87 gc.anchor = GridBagConstraints.NORTHWEST;
88 gc.weightx = 0.0;
89 gc.fill = GridBagConstraints.HORIZONTAL;
90 pnl.add(cbOpenAndCloseRestrictions = new JCheckBox(), gc);
91 cbOpenAndCloseRestrictions.addItemListener(stateChangeHandler);
92
93 gc.gridx = 1;
94 gc.weightx = 1.0;
95 pnl.add(new JMultilineLabel(tr("Select changesets depending on whether they are open or closed")), gc);
96
97 gc.gridy = 3;
98 gc.gridx = 1;
99 gc.weightx = 1.0;
100 pnl.add(pnlOpenAndCloseRestriction = new OpenAndCloseStateRestrictionPanel(), gc);
101
102 // -- restricting the query to a specific time
103 //
104 gc.gridy = 4;
105 gc.gridx = 0;
106 gc.anchor = GridBagConstraints.NORTHWEST;
107 gc.weightx = 0.0;
108 gc.fill = GridBagConstraints.HORIZONTAL;
109 pnl.add(cbTimeRestrictions = new JCheckBox(), gc);
110 cbTimeRestrictions.addItemListener(stateChangeHandler);
111
112 gc.gridx = 1;
113 gc.weightx = 1.0;
114 pnl.add(new JMultilineLabel(tr("Select changesets based on the date/time they have been created or closed")), gc);
115
116 gc.gridy = 5;
117 gc.gridx = 1;
118 gc.weightx = 1.0;
119 pnl.add(pnlTimeRestriction = new TimeRestrictionPanel(), gc);
120
121
122 // -- restricting the query to a specific bounding box
123 //
124 gc.gridy = 6;
125 gc.gridx = 0;
126 gc.anchor = GridBagConstraints.NORTHWEST;
127 gc.weightx = 0.0;
128 gc.fill = GridBagConstraints.HORIZONTAL;
129 pnl.add(cbBoundingBoxRestriction = new JCheckBox(), gc);
130 cbBoundingBoxRestriction.addItemListener(stateChangeHandler);
131
132 gc.gridx = 1;
133 gc.weightx = 1.0;
134 pnl.add(new JMultilineLabel(tr("Select only changesets related to a specific bounding box")), gc);
135
136 gc.gridy = 7;
137 gc.gridx = 1;
138 gc.weightx = 1.0;
139 pnl.add(pnlBoundingBoxRestriction = new BBoxRestrictionPanel(), gc);
140
141
142 gc.gridy = 8;
143 gc.gridx = 0;
144 gc.gridwidth = 2;
145 gc.fill = GridBagConstraints.BOTH;
146 gc.weightx = 1.0;
147 gc.weighty = 1.0;
148 pnl.add(new JPanel(), gc);
149
150 return pnl;
151 }
152
153 protected final void build() {
154 setLayout(new BorderLayout());
155 JScrollPane spQueryPanel = GuiHelper.embedInVerticalScrollPane(buildQueryPanel());
156 add(spQueryPanel, BorderLayout.CENTER);
157 }
158
159 /**
160 * Constructs a new {@code AdvancedChangesetQueryPanel}.
161 */
162 public AdvancedChangesetQueryPanel() {
163 build();
164 }
165
166 public void startUserInput() {
167 restoreFromSettings();
168 pnlBoundingBoxRestriction.setVisible(cbBoundingBoxRestriction.isSelected());
169 pnlOpenAndCloseRestriction.setVisible(cbOpenAndCloseRestrictions.isSelected());
170 pnlTimeRestriction.setVisible(cbTimeRestrictions.isSelected());
171 pnlUserRestriction.setVisible(cbUserRestriction.isSelected());
172 pnlOpenAndCloseRestriction.startUserInput();
173 pnlUserRestriction.startUserInput();
174 pnlTimeRestriction.startUserInput();
175 }
176
177 public void displayMessageIfInvalid() {
178 if (cbUserRestriction.isSelected()) {
179 if (!pnlUserRestriction.isValidChangesetQuery()) {
180 pnlUserRestriction.displayMessageIfInvalid();
181 }
182 } else if (cbTimeRestrictions.isSelected()) {
183 if (!pnlTimeRestriction.isValidChangesetQuery()) {
184 pnlTimeRestriction.displayMessageIfInvalid();
185 }
186 } else if (cbBoundingBoxRestriction.isSelected()) {
187 if (!pnlBoundingBoxRestriction.isValidChangesetQuery()) {
188 pnlBoundingBoxRestriction.displayMessageIfInvalid();
189 }
190 }
191 }
192
193 /**
194 * Builds the changeset query based on the data entered in the form.
195 *
196 * @return the changeset query. null, if the data entered doesn't represent
197 * a valid changeset query.
198 */
199 public ChangesetQuery buildChangesetQuery() {
200 ChangesetQuery query = new ChangesetQuery();
201 if (cbUserRestriction.isSelected()) {
202 if (!pnlUserRestriction.isValidChangesetQuery())
203 return null;
204 pnlUserRestriction.fillInQuery(query);
205 }
206 if (cbOpenAndCloseRestrictions.isSelected()) {
207 // don't have to check whether it's valid. It always is.
208 pnlOpenAndCloseRestriction.fillInQuery(query);
209 }
210 if (cbBoundingBoxRestriction.isSelected()) {
211 if (!pnlBoundingBoxRestriction.isValidChangesetQuery())
212 return null;
213 pnlBoundingBoxRestriction.fillInQuery(query);
214 }
215 if (cbTimeRestrictions.isSelected()) {
216 if (!pnlTimeRestriction.isValidChangesetQuery())
217 return null;
218 pnlTimeRestriction.fillInQuery(query);
219 }
220 return query;
221 }
222
223 public void rememberSettings() {
224 Main.pref.put("changeset-query.advanced.user-restrictions", cbUserRestriction.isSelected());
225 Main.pref.put("changeset-query.advanced.open-restrictions", cbOpenAndCloseRestrictions.isSelected());
226 Main.pref.put("changeset-query.advanced.time-restrictions", cbTimeRestrictions.isSelected());
227 Main.pref.put("changeset-query.advanced.bbox-restrictions", cbBoundingBoxRestriction.isSelected());
228
229 pnlUserRestriction.rememberSettings();
230 pnlOpenAndCloseRestriction.rememberSettings();
231 pnlTimeRestriction.rememberSettings();
232 }
233
234 public void restoreFromSettings() {
235 cbUserRestriction.setSelected(Main.pref.getBoolean("changeset-query.advanced.user-restrictions", false));
236 cbOpenAndCloseRestrictions.setSelected(Main.pref.getBoolean("changeset-query.advanced.open-restrictions", false));
237 cbTimeRestrictions.setSelected(Main.pref.getBoolean("changeset-query.advanced.time-restrictions", false));
238 cbBoundingBoxRestriction.setSelected(Main.pref.getBoolean("changeset-query.advanced.bbox-restrictions", false));
239 }
240
241 class RestrictionGroupStateChangeHandler implements ItemListener {
242 protected void userRestrictionStateChanged() {
243 if (pnlUserRestriction == null) return;
244 pnlUserRestriction.setVisible(cbUserRestriction.isSelected());
245 }
246
247 protected void openCloseRestrictionStateChanged() {
248 if (pnlOpenAndCloseRestriction == null) return;
249 pnlOpenAndCloseRestriction.setVisible(cbOpenAndCloseRestrictions.isSelected());
250 }
251
252 protected void timeRestrictionsStateChanged() {
253 if (pnlTimeRestriction == null) return;
254 pnlTimeRestriction.setVisible(cbTimeRestrictions.isSelected());
255 }
256
257 protected void boundingBoxRestrictionChanged() {
258 if (pnlBoundingBoxRestriction == null) return;
259 pnlBoundingBoxRestriction.setVisible(cbBoundingBoxRestriction.isSelected());
260 }
261
262 @Override
263 public void itemStateChanged(ItemEvent e) {
264 if (e.getSource() == cbUserRestriction) {
265 userRestrictionStateChanged();
266 } else if (e.getSource() == cbOpenAndCloseRestrictions) {
267 openCloseRestrictionStateChanged();
268 } else if (e.getSource() == cbTimeRestrictions) {
269 timeRestrictionsStateChanged();
270 } else if (e.getSource() == cbBoundingBoxRestriction) {
271 boundingBoxRestrictionChanged();
272 }
273 validate();
274 repaint();
275 }
276 }
277
278 /**
279 * This is the panel for selecting whether the changeset query should be restricted to
280 * open or closed changesets
281 */
282 private static class OpenAndCloseStateRestrictionPanel extends JPanel {
283
284 private JRadioButton rbOpenOnly;
285 private JRadioButton rbClosedOnly;
286 private JRadioButton rbBoth;
287
288 protected void build() {
289 setLayout(new GridBagLayout());
290 setBorder(BorderFactory.createCompoundBorder(
291 BorderFactory.createEmptyBorder(3, 3, 3, 3),
292 BorderFactory.createCompoundBorder(
293 BorderFactory.createLineBorder(Color.GRAY),
294 BorderFactory.createEmptyBorder(5, 5, 5, 5)
295 )
296 ));
297 GridBagConstraints gc = new GridBagConstraints();
298 gc.anchor = GridBagConstraints.NORTHWEST;
299 gc.fill = GridBagConstraints.HORIZONTAL;
300 gc.weightx = 0.0;
301 add(rbOpenOnly = new JRadioButton(), gc);
302
303 gc.gridx = 1;
304 gc.weightx = 1.0;
305 add(new JMultilineLabel(tr("Query open changesets only")), gc);
306
307 gc.gridy = 1;
308 gc.gridx = 0;
309 gc.weightx = 0.0;
310 add(rbClosedOnly = new JRadioButton(), gc);
311
312 gc.gridx = 1;
313 gc.weightx = 1.0;
314 add(new JMultilineLabel(tr("Query closed changesets only")), gc);
315
316 gc.gridy = 2;
317 gc.gridx = 0;
318 gc.weightx = 0.0;
319 add(rbBoth = new JRadioButton(), gc);
320
321 gc.gridx = 1;
322 gc.weightx = 1.0;
323 add(new JMultilineLabel(tr("Query both open and closed changesets")), gc);
324
325 ButtonGroup bgRestrictions = new ButtonGroup();
326 bgRestrictions.add(rbBoth);
327 bgRestrictions.add(rbClosedOnly);
328 bgRestrictions.add(rbOpenOnly);
329 }
330
331 public OpenAndCloseStateRestrictionPanel() {
332 build();
333 }
334
335 public void startUserInput() {
336 restoreFromSettings();
337 }
338
339 public void fillInQuery(ChangesetQuery query) {
340 if (rbBoth.isSelected()) {
341 query.beingClosed(true);
342 query.beingOpen(true);
343 } else if (rbOpenOnly.isSelected()) {
344 query.beingOpen(true);
345 } else if (rbClosedOnly.isSelected()) {
346 query.beingClosed(true);
347 }
348 }
349
350 public void rememberSettings() {
351 String prefRoot = "changeset-query.advanced.open-restrictions";
352 if (rbBoth.isSelected()) {
353 Main.pref.put(prefRoot + ".query-type", "both");
354 } else if (rbOpenOnly.isSelected()) {
355 Main.pref.put(prefRoot + ".query-type", "open");
356 } else if (rbClosedOnly.isSelected()) {
357 Main.pref.put(prefRoot + ".query-type", "closed");
358 }
359 }
360
361 public void restoreFromSettings() {
362 String prefRoot = "changeset-query.advanced.open-restrictions";
363 String v = Main.pref.get(prefRoot + ".query-type", "open");
364 rbBoth.setSelected("both".equals(v));
365 rbOpenOnly.setSelected("open".equals(v));
366 rbClosedOnly.setSelected("closed".equals(v));
367 }
368 }
369
370 /**
371 * This is the panel for selecting whether the query should be restricted to a specific
372 * user
373 *
374 */
375 private static class UserRestrictionPanel extends JPanel {
376 private ButtonGroup bgUserRestrictions;
377 private JRadioButton rbRestrictToMyself;
378 private JRadioButton rbRestrictToUid;
379 private JRadioButton rbRestrictToUserName;
380 private JosmTextField tfUid;
381 private transient UidInputFieldValidator valUid;
382 private JosmTextField tfUserName;
383 private transient UserNameInputValidator valUserName;
384 private JMultilineLabel lblRestrictedToMyself;
385
386 protected JPanel buildUidInputPanel() {
387 JPanel pnl = new JPanel(new GridBagLayout());
388 GridBagConstraints gc = new GridBagConstraints();
389 gc.fill = GridBagConstraints.HORIZONTAL;
390 gc.weightx = 0.0;
391 gc.insets = new Insets(0, 0, 0, 3);
392 pnl.add(new JLabel(tr("User ID:")), gc);
393
394 gc.gridx = 1;
395 pnl.add(tfUid = new JosmTextField(10), gc);
396 SelectAllOnFocusGainedDecorator.decorate(tfUid);
397 valUid = UidInputFieldValidator.decorate(tfUid);
398
399 // grab remaining space
400 gc.gridx = 2;
401 gc.weightx = 1.0;
402 pnl.add(new JPanel(), gc);
403 return pnl;
404 }
405
406 protected JPanel buildUserNameInputPanel() {
407 JPanel pnl = new JPanel(new GridBagLayout());
408 GridBagConstraints gc = new GridBagConstraints();
409 gc.fill = GridBagConstraints.HORIZONTAL;
410 gc.weightx = 0.0;
411 gc.insets = new Insets(0, 0, 0, 3);
412 pnl.add(new JLabel(tr("User name:")), gc);
413
414 gc.gridx = 1;
415 pnl.add(tfUserName = new JosmTextField(10), gc);
416 SelectAllOnFocusGainedDecorator.decorate(tfUserName);
417 valUserName = UserNameInputValidator.decorate(tfUserName);
418
419 // grab remaining space
420 gc.gridx = 2;
421 gc.weightx = 1.0;
422 pnl.add(new JPanel(), gc);
423 return pnl;
424 }
425
426 protected void build() {
427 setLayout(new GridBagLayout());
428 setBorder(BorderFactory.createCompoundBorder(
429 BorderFactory.createEmptyBorder(3, 3, 3, 3),
430 BorderFactory.createCompoundBorder(
431 BorderFactory.createLineBorder(Color.GRAY),
432 BorderFactory.createEmptyBorder(5, 5, 5, 5)
433 )
434 ));
435
436 ItemListener userRestrictionChangeHandler = new UserRestrictionChangedHandler();
437 GridBagConstraints gc = new GridBagConstraints();
438 gc.anchor = GridBagConstraints.NORTHWEST;
439 gc.gridx = 0;
440 gc.fill = GridBagConstraints.HORIZONTAL;
441 gc.weightx = 0.0;
442 add(rbRestrictToMyself = new JRadioButton(), gc);
443 rbRestrictToMyself.addItemListener(userRestrictionChangeHandler);
444
445 gc.gridx = 1;
446 gc.fill = GridBagConstraints.HORIZONTAL;
447 gc.weightx = 1.0;
448 add(lblRestrictedToMyself = new JMultilineLabel(tr("Only changesets owned by myself")), gc);
449
450 gc.gridx = 0;
451 gc.gridy = 1;
452 gc.fill = GridBagConstraints.HORIZONTAL;
453 gc.weightx = 0.0;
454 add(rbRestrictToUid = new JRadioButton(), gc);
455 rbRestrictToUid.addItemListener(userRestrictionChangeHandler);
456
457 gc.gridx = 1;
458 gc.fill = GridBagConstraints.HORIZONTAL;
459 gc.weightx = 1.0;
460 add(new JMultilineLabel(tr("Only changesets owned by the user with the following user ID")), gc);
461
462 gc.gridx = 1;
463 gc.gridy = 2;
464 gc.fill = GridBagConstraints.HORIZONTAL;
465 gc.weightx = 1.0;
466 add(buildUidInputPanel(), gc);
467
468 gc.gridx = 0;
469 gc.gridy = 3;
470 gc.fill = GridBagConstraints.HORIZONTAL;
471 gc.weightx = 0.0;
472 add(rbRestrictToUserName = new JRadioButton(), gc);
473 rbRestrictToUserName.addItemListener(userRestrictionChangeHandler);
474
475 gc.gridx = 1;
476 gc.fill = GridBagConstraints.HORIZONTAL;
477 gc.weightx = 1.0;
478 add(new JMultilineLabel(tr("Only changesets owned by the user with the following user name")), gc);
479
480 gc.gridx = 1;
481 gc.gridy = 4;
482 gc.fill = GridBagConstraints.HORIZONTAL;
483 gc.weightx = 1.0;
484 add(buildUserNameInputPanel(), gc);
485
486 bgUserRestrictions = new ButtonGroup();
487 bgUserRestrictions.add(rbRestrictToMyself);
488 bgUserRestrictions.add(rbRestrictToUid);
489 bgUserRestrictions.add(rbRestrictToUserName);
490 }
491
492 public UserRestrictionPanel() {
493 build();
494 }
495
496 public void startUserInput() {
497 if (JosmUserIdentityManager.getInstance().isAnonymous()) {
498 lblRestrictedToMyself.setText(tr("Only changesets owned by myself (disabled. JOSM is currently run by an anonymous user)"));
499 rbRestrictToMyself.setEnabled(false);
500 if (rbRestrictToMyself.isSelected()) {
501 rbRestrictToUid.setSelected(true);
502 }
503 } else {
504 lblRestrictedToMyself.setText(tr("Only changesets owned by myself"));
505 rbRestrictToMyself.setEnabled(true);
506 rbRestrictToMyself.setSelected(true);
507 }
508 restoreFromSettings();
509 }
510
511 /**
512 * Sets the query restrictions on <code>query</code> for changeset owner based
513 * restrictions.
514 *
515 * @param query the query. Must not be null.
516 * @throws IllegalArgumentException if query is null
517 * @throws IllegalStateException if one of the available values for query parameters in
518 * this panel isn't valid
519 */
520 public void fillInQuery(ChangesetQuery query) {
521 CheckParameterUtil.ensureParameterNotNull(query, "query");
522 if (rbRestrictToMyself.isSelected()) {
523 JosmUserIdentityManager im = JosmUserIdentityManager.getInstance();
524 if (im.isPartiallyIdentified()) {
525 query.forUser(im.getUserName());
526 } else if (im.isFullyIdentified()) {
527 query.forUser(im.getUserId());
528 } else
529 throw new IllegalStateException(
530 tr("Cannot restrict changeset query to the current user because the current user is anonymous"));
531 } else if (rbRestrictToUid.isSelected()) {
532 int uid = valUid.getUid();
533 if (uid > 0) {
534 query.forUser(uid);
535 } else
536 throw new IllegalStateException(tr("Current value ''{0}'' for user ID is not valid", tfUid.getText()));
537 } else if (rbRestrictToUserName.isSelected()) {
538 if (!valUserName.isValid())
539 throw new IllegalStateException(
540 tr("Cannot restrict the changeset query to the user name ''{0}''", tfUserName.getText()));
541 query.forUser(tfUserName.getText());
542 }
543 }
544
545 public boolean isValidChangesetQuery() {
546 if (rbRestrictToUid.isSelected())
547 return valUid.isValid();
548 else if (rbRestrictToUserName.isSelected())
549 return valUserName.isValid();
550 return true;
551 }
552
553 protected void alertInvalidUid() {
554 HelpAwareOptionPane.showOptionDialog(
555 this,
556 tr("Please enter a valid user ID"),
557 tr("Invalid user ID"),
558 JOptionPane.ERROR_MESSAGE,
559 HelpUtil.ht("/Dialog/ChangesetQueryDialog#InvalidUserId")
560 );
561 }
562
563 protected void alertInvalidUserName() {
564 HelpAwareOptionPane.showOptionDialog(
565 this,
566 tr("Please enter a non-empty user name"),
567 tr("Invalid user name"),
568 JOptionPane.ERROR_MESSAGE,
569 HelpUtil.ht("/Dialog/ChangesetQueryDialog#InvalidUserName")
570 );
571 }
572
573 public void displayMessageIfInvalid() {
574 if (rbRestrictToUid.isSelected()) {
575 if (!valUid.isValid()) {
576 alertInvalidUid();
577 }
578 } else if (rbRestrictToUserName.isSelected()) {
579 if (!valUserName.isValid()) {
580 alertInvalidUserName();
581 }
582 }
583 }
584
585 public void rememberSettings() {
586 String prefRoot = "changeset-query.advanced.user-restrictions";
587 if (rbRestrictToMyself.isSelected()) {
588 Main.pref.put(prefRoot + ".query-type", "mine");
589 } else if (rbRestrictToUid.isSelected()) {
590 Main.pref.put(prefRoot + ".query-type", "uid");
591 } else if (rbRestrictToUserName.isSelected()) {
592 Main.pref.put(prefRoot + ".query-type", "username");
593 }
594 Main.pref.put(prefRoot + ".uid", tfUid.getText());
595 Main.pref.put(prefRoot + ".username", tfUserName.getText());
596 }
597
598 public void restoreFromSettings() {
599 String prefRoot = "changeset-query.advanced.user-restrictions";
600 String v = Main.pref.get(prefRoot + ".query-type", "mine");
601 if ("mine".equals(v)) {
602 JosmUserIdentityManager im = JosmUserIdentityManager.getInstance();
603 if (im.isAnonymous()) {
604 rbRestrictToUid.setSelected(true);
605 } else {
606 rbRestrictToMyself.setSelected(true);
607 }
608 } else if ("uid".equals(v)) {
609 rbRestrictToUid.setSelected(true);
610 } else if ("username".equals(v)) {
611 rbRestrictToUserName.setSelected(true);
612 }
613 tfUid.setText(Main.pref.get(prefRoot + ".uid", ""));
614 if (!valUid.isValid()) {
615 tfUid.setText("");
616 }
617 tfUserName.setText(Main.pref.get(prefRoot + ".username", ""));
618 }
619
620 class UserRestrictionChangedHandler implements ItemListener {
621 @Override
622 public void itemStateChanged(ItemEvent e) {
623 tfUid.setEnabled(rbRestrictToUid.isSelected());
624 tfUserName.setEnabled(rbRestrictToUserName.isSelected());
625 if (rbRestrictToUid.isSelected()) {
626 tfUid.requestFocusInWindow();
627 } else if (rbRestrictToUserName.isSelected()) {
628 tfUserName.requestFocusInWindow();
629 }
630 }
631 }
632 }
633
634 /**
635 * This is the panel to apply a time restriction to the changeset query
636 */
637 private static class TimeRestrictionPanel extends JPanel {
638
639 private JRadioButton rbClosedAfter;
640 private JRadioButton rbClosedAfterAndCreatedBefore;
641 private JosmTextField tfClosedAfterDate1;
642 private transient DateValidator valClosedAfterDate1;
643 private JosmTextField tfClosedAfterTime1;
644 private transient TimeValidator valClosedAfterTime1;
645 private JosmTextField tfClosedAfterDate2;
646 private transient DateValidator valClosedAfterDate2;
647 private JosmTextField tfClosedAfterTime2;
648 private transient TimeValidator valClosedAfterTime2;
649 private JosmTextField tfCreatedBeforeDate;
650 private transient DateValidator valCreatedBeforeDate;
651 private JosmTextField tfCreatedBeforeTime;
652 private transient TimeValidator valCreatedBeforeTime;
653
654 protected JPanel buildClosedAfterInputPanel() {
655 JPanel pnl = new JPanel(new GridBagLayout());
656 GridBagConstraints gc = new GridBagConstraints();
657 gc.fill = GridBagConstraints.HORIZONTAL;
658 gc.weightx = 0.0;
659 gc.insets = new Insets(0, 0, 0, 3);
660 pnl.add(new JLabel(tr("Date: ")), gc);
661
662 gc.gridx = 1;
663 gc.weightx = 0.7;
664 pnl.add(tfClosedAfterDate1 = new JosmTextField(), gc);
665 SelectAllOnFocusGainedDecorator.decorate(tfClosedAfterDate1);
666 valClosedAfterDate1 = DateValidator.decorate(tfClosedAfterDate1);
667 tfClosedAfterDate1.setToolTipText(valClosedAfterDate1.getStandardTooltipTextAsHtml());
668
669 gc.gridx = 2;
670 gc.weightx = 0.0;
671 pnl.add(new JLabel(tr("Time:")), gc);
672
673 gc.gridx = 3;
674 gc.weightx = 0.3;
675 pnl.add(tfClosedAfterTime1 = new JosmTextField(), gc);
676 SelectAllOnFocusGainedDecorator.decorate(tfClosedAfterTime1);
677 valClosedAfterTime1 = TimeValidator.decorate(tfClosedAfterTime1);
678 tfClosedAfterTime1.setToolTipText(valClosedAfterTime1.getStandardTooltipTextAsHtml());
679 return pnl;
680 }
681
682 protected JPanel buildClosedAfterAndCreatedBeforeInputPanel() {
683 JPanel pnl = new JPanel(new GridBagLayout());
684 GridBagConstraints gc = new GridBagConstraints();
685 gc.fill = GridBagConstraints.HORIZONTAL;
686 gc.weightx = 0.0;
687 gc.insets = new Insets(0, 0, 0, 3);
688 pnl.add(new JLabel(tr("Closed after - ")), gc);
689
690 gc.gridx = 1;
691 gc.fill = GridBagConstraints.HORIZONTAL;
692 gc.weightx = 0.0;
693 gc.insets = new Insets(0, 0, 0, 3);
694 pnl.add(new JLabel(tr("Date:")), gc);
695
696 gc.gridx = 2;
697 gc.weightx = 0.7;
698 pnl.add(tfClosedAfterDate2 = new JosmTextField(), gc);
699 SelectAllOnFocusGainedDecorator.decorate(tfClosedAfterDate2);
700 valClosedAfterDate2 = DateValidator.decorate(tfClosedAfterDate2);
701 tfClosedAfterDate2.setToolTipText(valClosedAfterDate2.getStandardTooltipTextAsHtml());
702 gc.gridx = 3;
703 gc.weightx = 0.0;
704 pnl.add(new JLabel(tr("Time:")), gc);
705
706 gc.gridx = 4;
707 gc.weightx = 0.3;
708 pnl.add(tfClosedAfterTime2 = new JosmTextField(), gc);
709 SelectAllOnFocusGainedDecorator.decorate(tfClosedAfterTime2);
710 valClosedAfterTime2 = TimeValidator.decorate(tfClosedAfterTime2);
711 tfClosedAfterTime2.setToolTipText(valClosedAfterTime2.getStandardTooltipTextAsHtml());
712
713 gc.gridy = 1;
714 gc.gridx = 0;
715 gc.fill = GridBagConstraints.HORIZONTAL;
716 gc.weightx = 0.0;
717 gc.insets = new Insets(0, 0, 0, 3);
718 pnl.add(new JLabel(tr("Created before - ")), gc);
719
720 gc.gridx = 1;
721 gc.fill = GridBagConstraints.HORIZONTAL;
722 gc.weightx = 0.0;
723 gc.insets = new Insets(0, 0, 0, 3);
724 pnl.add(new JLabel(tr("Date:")), gc);
725
726 gc.gridx = 2;
727 gc.weightx = 0.7;
728 pnl.add(tfCreatedBeforeDate = new JosmTextField(), gc);
729 SelectAllOnFocusGainedDecorator.decorate(tfCreatedBeforeDate);
730 valCreatedBeforeDate = DateValidator.decorate(tfCreatedBeforeDate);
731 tfCreatedBeforeDate.setToolTipText(valCreatedBeforeDate.getStandardTooltipTextAsHtml());
732
733 gc.gridx = 3;
734 gc.weightx = 0.0;
735 pnl.add(new JLabel(tr("Time:")), gc);
736
737 gc.gridx = 4;
738 gc.weightx = 0.3;
739 pnl.add(tfCreatedBeforeTime = new JosmTextField(), gc);
740 SelectAllOnFocusGainedDecorator.decorate(tfCreatedBeforeTime);
741 valCreatedBeforeTime = TimeValidator.decorate(tfCreatedBeforeTime);
742 tfCreatedBeforeTime.setToolTipText(valCreatedBeforeDate.getStandardTooltipTextAsHtml());
743
744 return pnl;
745 }
746
747 protected void build() {
748 setLayout(new GridBagLayout());
749 setBorder(BorderFactory.createCompoundBorder(
750 BorderFactory.createEmptyBorder(3, 3, 3, 3),
751 BorderFactory.createCompoundBorder(
752 BorderFactory.createLineBorder(Color.GRAY),
753 BorderFactory.createEmptyBorder(5, 5, 5, 5)
754 )
755 ));
756
757 // -- changesets closed after a specific date/time
758 //
759 GridBagConstraints gc = new GridBagConstraints();
760 gc.anchor = GridBagConstraints.NORTHWEST;
761 gc.gridx = 0;
762 gc.fill = GridBagConstraints.HORIZONTAL;
763 gc.weightx = 0.0;
764 add(rbClosedAfter = new JRadioButton(), gc);
765
766 gc.gridx = 1;
767 gc.fill = GridBagConstraints.HORIZONTAL;
768 gc.weightx = 1.0;
769 add(new JMultilineLabel(tr("Only changesets closed after the following date/time")), gc);
770
771 gc.gridx = 1;
772 gc.gridy = 1;
773 gc.fill = GridBagConstraints.HORIZONTAL;
774 gc.weightx = 1.0;
775 add(buildClosedAfterInputPanel(), gc);
776
777 // -- changesets closed after a specific date/time and created before a specific date time
778 //
779 gc = new GridBagConstraints();
780 gc.anchor = GridBagConstraints.NORTHWEST;
781 gc.gridy = 2;
782 gc.gridx = 0;
783 gc.fill = GridBagConstraints.HORIZONTAL;
784 gc.weightx = 0.0;
785 add(rbClosedAfterAndCreatedBefore = new JRadioButton(), gc);
786
787 gc.gridx = 1;
788 gc.fill = GridBagConstraints.HORIZONTAL;
789 gc.weightx = 1.0;
790 add(new JMultilineLabel(tr("Only changesets closed after and created before a specific date/time")), gc);
791
792 gc.gridx = 1;
793 gc.gridy = 3;
794 gc.fill = GridBagConstraints.HORIZONTAL;
795 gc.weightx = 1.0;
796 add(buildClosedAfterAndCreatedBeforeInputPanel(), gc);
797
798 ButtonGroup bg = new ButtonGroup();
799 bg.add(rbClosedAfter);
800 bg.add(rbClosedAfterAndCreatedBefore);
801
802 ItemListener restrictionChangeHandler = new TimeRestrictionChangedHandler();
803 rbClosedAfter.addItemListener(restrictionChangeHandler);
804 rbClosedAfterAndCreatedBefore.addItemListener(restrictionChangeHandler);
805
806 rbClosedAfter.setSelected(true);
807 }
808
809 public TimeRestrictionPanel() {
810 build();
811 }
812
813 public boolean isValidChangesetQuery() {
814 if (rbClosedAfter.isSelected())
815 return valClosedAfterDate1.isValid() && valClosedAfterTime1.isValid();
816 else if (rbClosedAfterAndCreatedBefore.isSelected())
817 return valClosedAfterDate2.isValid() && valClosedAfterTime2.isValid()
818 && valCreatedBeforeDate.isValid() && valCreatedBeforeTime.isValid();
819 // should not happen
820 return true;
821 }
822
823 class TimeRestrictionChangedHandler implements ItemListener {
824 @Override
825 public void itemStateChanged(ItemEvent e) {
826 tfClosedAfterDate1.setEnabled(rbClosedAfter.isSelected());
827 tfClosedAfterTime1.setEnabled(rbClosedAfter.isSelected());
828
829 tfClosedAfterDate2.setEnabled(rbClosedAfterAndCreatedBefore.isSelected());
830 tfClosedAfterTime2.setEnabled(rbClosedAfterAndCreatedBefore.isSelected());
831 tfCreatedBeforeDate.setEnabled(rbClosedAfterAndCreatedBefore.isSelected());
832 tfCreatedBeforeTime.setEnabled(rbClosedAfterAndCreatedBefore.isSelected());
833 }
834 }
835
836 public void startUserInput() {
837 restoreFromSettings();
838 }
839
840 public void fillInQuery(ChangesetQuery query) {
841 if (!isValidChangesetQuery())
842 throw new IllegalStateException(tr("Cannot build changeset query with time based restrictions. Input is not valid."));
843 if (rbClosedAfter.isSelected()) {
844 GregorianCalendar cal = new GregorianCalendar();
845 Date d1 = valClosedAfterDate1.getDate();
846 Date d2 = valClosedAfterTime1.getDate();
847 cal.setTimeInMillis(d1.getTime() + (d2 == null ? 0 : d2.getTime()));
848 query.closedAfter(cal.getTime());
849 } else if (rbClosedAfterAndCreatedBefore.isSelected()) {
850 GregorianCalendar cal = new GregorianCalendar();
851 Date d1 = valClosedAfterDate2.getDate();
852 Date d2 = valClosedAfterTime2.getDate();
853 cal.setTimeInMillis(d1.getTime() + (d2 == null ? 0 : d2.getTime()));
854 Date d3 = cal.getTime();
855
856 d1 = valCreatedBeforeDate.getDate();
857 d2 = valCreatedBeforeTime.getDate();
858 cal.setTimeInMillis(d1.getTime() + (d2 == null ? 0 : d2.getTime()));
859 Date d4 = cal.getTime();
860
861 query.closedAfterAndCreatedBefore(d3, d4);
862 }
863 }
864
865 public void displayMessageIfInvalid() {
866 if (isValidChangesetQuery()) return;
867 HelpAwareOptionPane.showOptionDialog(
868 this,
869 tr(
870 "<html>Please enter valid date/time values to restrict<br>"
871 + "the query to a specific time range.</html>"
872 ),
873 tr("Invalid date/time values"),
874 JOptionPane.ERROR_MESSAGE,
875 HelpUtil.ht("/Dialog/ChangesetQueryDialog#InvalidDateTimeValues")
876 );
877 }
878
879 public void rememberSettings() {
880 String prefRoot = "changeset-query.advanced.time-restrictions";
881 if (rbClosedAfter.isSelected()) {
882 Main.pref.put(prefRoot + ".query-type", "closed-after");
883 } else if (rbClosedAfterAndCreatedBefore.isSelected()) {
884 Main.pref.put(prefRoot + ".query-type", "closed-after-created-before");
885 }
886 Main.pref.put(prefRoot + ".closed-after.date", tfClosedAfterDate1.getText());
887 Main.pref.put(prefRoot + ".closed-after.time", tfClosedAfterTime1.getText());
888 Main.pref.put(prefRoot + ".closed-created.closed.date", tfClosedAfterDate2.getText());
889 Main.pref.put(prefRoot + ".closed-created.closed.time", tfClosedAfterTime2.getText());
890 Main.pref.put(prefRoot + ".closed-created.created.date", tfCreatedBeforeDate.getText());
891 Main.pref.put(prefRoot + ".closed-created.created.time", tfCreatedBeforeTime.getText());
892 }
893
894 public void restoreFromSettings() {
895 String prefRoot = "changeset-query.advanced.open-restrictions";
896 String v = Main.pref.get(prefRoot + ".query-type", "closed-after");
897 rbClosedAfter.setSelected("closed-after".equals(v));
898 rbClosedAfterAndCreatedBefore.setSelected("closed-after-created-before".equals(v));
899 if (!rbClosedAfter.isSelected() && !rbClosedAfterAndCreatedBefore.isSelected()) {
900 rbClosedAfter.setSelected(true);
901 }
902 tfClosedAfterDate1.setText(Main.pref.get(prefRoot + ".closed-after.date", ""));
903 tfClosedAfterTime1.setText(Main.pref.get(prefRoot + ".closed-after.time", ""));
904 tfClosedAfterDate2.setText(Main.pref.get(prefRoot + ".closed-created.closed.date", ""));
905 tfClosedAfterTime2.setText(Main.pref.get(prefRoot + ".closed-created.closed.time", ""));
906 tfCreatedBeforeDate.setText(Main.pref.get(prefRoot + ".closed-created.created.date", ""));
907 tfCreatedBeforeTime.setText(Main.pref.get(prefRoot + ".closed-created.created.time", ""));
908 if (!valClosedAfterDate1.isValid()) {
909 tfClosedAfterDate1.setText("");
910 }
911 if (!valClosedAfterTime1.isValid()) {
912 tfClosedAfterTime1.setText("");
913 }
914 if (!valClosedAfterDate2.isValid()) {
915 tfClosedAfterDate2.setText("");
916 }
917 if (!valClosedAfterTime2.isValid()) {
918 tfClosedAfterTime2.setText("");
919 }
920 if (!valCreatedBeforeDate.isValid()) {
921 tfCreatedBeforeDate.setText("");
922 }
923 if (!valCreatedBeforeTime.isValid()) {
924 tfCreatedBeforeTime.setText("");
925 }
926 }
927 }
928
929 private static class BBoxRestrictionPanel extends BoundingBoxSelectionPanel {
930 public BBoxRestrictionPanel() {
931 setBorder(BorderFactory.createCompoundBorder(
932 BorderFactory.createEmptyBorder(3, 3, 3, 3),
933 BorderFactory.createCompoundBorder(
934 BorderFactory.createLineBorder(Color.GRAY),
935 BorderFactory.createEmptyBorder(5, 5, 5, 5)
936 )
937 ));
938 }
939
940 public boolean isValidChangesetQuery() {
941 return getBoundingBox() != null;
942 }
943
944 public void fillInQuery(ChangesetQuery query) {
945 if (!isValidChangesetQuery())
946 throw new IllegalStateException(tr("Cannot restrict the changeset query to a specific bounding box. The input is invalid."));
947 query.inBbox(getBoundingBox());
948 }
949
950 public void displayMessageIfInvalid() {
951 if (isValidChangesetQuery()) return;
952 HelpAwareOptionPane.showOptionDialog(
953 this,
954 tr(
955 "<html>Please enter valid longitude/latitude values to restrict<br>" +
956 "the changeset query to a specific bounding box.</html>"
957 ),
958 tr("Invalid bounding box"),
959 JOptionPane.ERROR_MESSAGE,
960 HelpUtil.ht("/Dialog/ChangesetQueryDialog#InvalidBoundingBox")
961 );
962 }
963 }
964
965 /**
966 * Validator for user ids entered in a {@link JTextComponent}.
967 *
968 */
969 private static class UidInputFieldValidator extends AbstractTextComponentValidator {
970 public static UidInputFieldValidator decorate(JTextComponent tc) {
971 return new UidInputFieldValidator(tc);
972 }
973
974 public UidInputFieldValidator(JTextComponent tc) {
975 super(tc);
976 }
977
978 @Override
979 public boolean isValid() {
980 return getUid() > 0;
981 }
982
983 @Override
984 public void validate() {
985 String value = getComponent().getText();
986 if (value == null || value.trim().isEmpty()) {
987 feedbackInvalid("");
988 return;
989 }
990 try {
991 int uid = Integer.parseInt(value);
992 if (uid <= 0) {
993 feedbackInvalid(tr("The current value is not a valid user ID. Please enter an integer value > 0"));
994 return;
995 }
996 } catch (NumberFormatException e) {
997 feedbackInvalid(tr("The current value is not a valid user ID. Please enter an integer value > 0"));
998 return;
999 }
1000 feedbackValid(tr("Please enter an integer value > 0"));
1001 }
1002
1003 public int getUid() {
1004 String value = getComponent().getText();
1005 if (value == null || value.trim().isEmpty()) return 0;
1006 try {
1007 int uid = Integer.parseInt(value.trim());
1008 if (uid > 0) return uid;
1009 return 0;
1010 } catch (NumberFormatException e) {
1011 return 0;
1012 }
1013 }
1014 }
1015
1016 private static class UserNameInputValidator extends AbstractTextComponentValidator {
1017 public static UserNameInputValidator decorate(JTextComponent tc) {
1018 return new UserNameInputValidator(tc);
1019 }
1020
1021 public UserNameInputValidator(JTextComponent tc) {
1022 super(tc);
1023 }
1024
1025 @Override
1026 public boolean isValid() {
1027 return !getComponent().getText().trim().isEmpty();
1028 }
1029
1030 @Override
1031 public void validate() {
1032 String value = getComponent().getText();
1033 if (value.trim().isEmpty()) {
1034 feedbackInvalid(tr("<html>The current value is not a valid user name.<br>Please enter an non-empty user name.</html>"));
1035 return;
1036 }
1037 feedbackValid(tr("Please enter an non-empty user name"));
1038 }
1039 }
1040
1041 /**
1042 * Validates dates entered as text in a {@link JTextComponent}. Validates the input
1043 * on the fly and gives feedback about whether the date is valid or not.
1044 *
1045 * Dates can be entered in one of four standard formats defined for the current locale.
1046 */
1047 private static class DateValidator extends AbstractTextComponentValidator {
1048 public static DateValidator decorate(JTextComponent tc) {
1049 return new DateValidator(tc);
1050 }
1051
1052 public DateValidator(JTextComponent tc) {
1053 super(tc);
1054 }
1055
1056 @Override
1057 public boolean isValid() {
1058 return getDate() != null;
1059 }
1060
1061 public String getStandardTooltipTextAsHtml() {
1062 return "<html>" + getStandardTooltipText() + "</html>";
1063 }
1064
1065 public String getStandardTooltipText() {
1066 Date date = new Date();
1067 return tr(
1068 "Please enter a date in the usual format for your locale.<br>"
1069 + "Example: {0}<br>"
1070 + "Example: {1}<br>"
1071 + "Example: {2}<br>"
1072 + "Example: {3}<br>",
1073 DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault()).format(date),
1074 DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.getDefault()).format(date),
1075 DateFormat.getDateInstance(DateFormat.LONG, Locale.getDefault()).format(date),
1076 DateFormat.getDateInstance(DateFormat.FULL, Locale.getDefault()).format(date)
1077 );
1078 }
1079
1080 @Override
1081 public void validate() {
1082 if (!isValid()) {
1083 String msg = "<html>The current value isn't a valid date.<br>" + getStandardTooltipText()+ "</html>";
1084 feedbackInvalid(msg);
1085 return;
1086 } else {
1087 String msg = "<html>" + getStandardTooltipText() + "</html>";
1088 feedbackValid(msg);
1089 }
1090 }
1091
1092 public Date getDate() {
1093 for (int format: new int[] {DateFormat.SHORT, DateFormat.MEDIUM, DateFormat.LONG, DateFormat.FULL}) {
1094 DateFormat df = DateFormat.getDateInstance(format);
1095 try {
1096 return df.parse(getComponent().getText());
1097 } catch (ParseException e) {
1098 // Try next format
1099 if (Main.isTraceEnabled()) {
1100 Main.trace(e.getMessage());
1101 }
1102 }
1103 }
1104 return null;
1105 }
1106 }
1107
1108 /**
1109 * Validates time values entered as text in a {@link JTextComponent}. Validates the input
1110 * on the fly and gives feedback about whether the time value is valid or not.
1111 *
1112 * Time values can be entered in one of four standard formats defined for the current locale.
1113 */
1114 private static class TimeValidator extends AbstractTextComponentValidator {
1115 public static TimeValidator decorate(JTextComponent tc) {
1116 return new TimeValidator(tc);
1117 }
1118
1119 public TimeValidator(JTextComponent tc) {
1120 super(tc);
1121 }
1122
1123 @Override
1124 public boolean isValid() {
1125 if (getComponent().getText().trim().isEmpty()) return true;
1126 return getDate() != null;
1127 }
1128
1129 public String getStandardTooltipTextAsHtml() {
1130 return "<html>" + getStandardTooltipText() + "</html>";
1131 }
1132
1133 public String getStandardTooltipText() {
1134 Date date = new Date();
1135 return tr(
1136 "Please enter a valid time in the usual format for your locale.<br>"
1137 + "Example: {0}<br>"
1138 + "Example: {1}<br>"
1139 + "Example: {2}<br>"
1140 + "Example: {3}<br>",
1141 DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault()).format(date),
1142 DateFormat.getTimeInstance(DateFormat.MEDIUM, Locale.getDefault()).format(date),
1143 DateFormat.getTimeInstance(DateFormat.LONG, Locale.getDefault()).format(date),
1144 DateFormat.getTimeInstance(DateFormat.FULL, Locale.getDefault()).format(date)
1145 );
1146 }
1147
1148 @Override
1149 public void validate() {
1150
1151 if (!isValid()) {
1152 String msg = "<html>The current value isn't a valid time.<br>" + getStandardTooltipText() + "</html>";
1153 feedbackInvalid(msg);
1154 return;
1155 } else {
1156 String msg = "<html>" + getStandardTooltipText() + "</html>";
1157 feedbackValid(msg);
1158 }
1159 }
1160
1161 public Date getDate() {
1162 if (getComponent().getText().trim().isEmpty())
1163 return null;
1164
1165 for (int style : new int[]{DateFormat.SHORT, DateFormat.MEDIUM, DateFormat.LONG, DateFormat.FULL}) {
1166 try {
1167 return DateFormat.getTimeInstance(style, Locale.getDefault()).parse(getComponent().getText());
1168 } catch (ParseException e) {
1169 continue;
1170 }
1171 }
1172 return null;
1173 }
1174 }
1175}
Note: See TracBrowser for help on using the repository browser.