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