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

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

sonar - squid:AssignmentInSubExpressionCheck - Assignments should not be made from within sub-expressions

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