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.Container;
008    import java.awt.Dialog;
009    import java.awt.Dimension;
010    import java.awt.FlowLayout;
011    import java.awt.Frame;
012    import java.awt.event.ActionEvent;
013    import java.awt.event.KeyEvent;
014    import java.awt.event.WindowAdapter;
015    import java.awt.event.WindowEvent;
016    
017    import javax.swing.AbstractAction;
018    import javax.swing.JComponent;
019    import javax.swing.JDialog;
020    import javax.swing.JOptionPane;
021    import javax.swing.JPanel;
022    import javax.swing.JTabbedPane;
023    import javax.swing.KeyStroke;
024    
025    import org.openstreetmap.josm.gui.HelpAwareOptionPane;
026    import org.openstreetmap.josm.gui.SideButton;
027    import org.openstreetmap.josm.gui.help.ContextSensitiveHelpAction;
028    import org.openstreetmap.josm.gui.help.HelpUtil;
029    import org.openstreetmap.josm.io.ChangesetQuery;
030    import org.openstreetmap.josm.tools.ImageProvider;
031    import org.openstreetmap.josm.tools.WindowGeometry;
032    
033    /**
034     * This is a modal dialog for entering query criteria to search for changesets.
035     *
036     */
037    public class ChangesetQueryDialog extends JDialog {
038    
039        private JTabbedPane tpQueryPanels;
040        private BasicChangesetQueryPanel pnlBasicChangesetQueries;
041        private UrlBasedQueryPanel pnlUrlBasedQueries;
042        private AdvancedChangesetQueryPanel pnlAdvancedQueries;
043        private boolean canceled;
044    
045        protected JPanel buildContentPanel() {
046            tpQueryPanels = new JTabbedPane();
047            tpQueryPanels.add(pnlBasicChangesetQueries = new BasicChangesetQueryPanel());
048            tpQueryPanels.add(pnlUrlBasedQueries = new UrlBasedQueryPanel());
049            tpQueryPanels.add(pnlAdvancedQueries = new AdvancedChangesetQueryPanel());
050    
051            tpQueryPanels.setTitleAt(0, tr("Basic"));
052            tpQueryPanels.setToolTipTextAt(0, tr("Download changesets using predefined queries"));
053    
054            tpQueryPanels.setTitleAt(1, tr("From URL"));
055            tpQueryPanels.setToolTipTextAt(1, tr("Query changesets from a server URL"));
056    
057            tpQueryPanels.setTitleAt(2, tr("Advanced"));
058            tpQueryPanels.setToolTipTextAt(2, tr("Use a custom changeset query"));
059    
060            JPanel pnl = new JPanel(new BorderLayout());
061            pnl.add(tpQueryPanels, BorderLayout.CENTER);
062            return pnl;
063        }
064    
065        protected JPanel buildButtonPanel() {
066            JPanel pnl = new JPanel(new FlowLayout(FlowLayout.CENTER));
067    
068            // -- query action
069            pnl.add(new SideButton(new QueryAction()));
070    
071            // -- cancel action
072            pnl.add(new SideButton(new CancelAction()));
073    
074            // -- help action
075            pnl.add(new SideButton(new ContextSensitiveHelpAction(HelpUtil.ht("/Dialog/ChangesetQueryDialog"))));
076    
077            return pnl;
078        }
079    
080    
081        protected void build() {
082            setTitle(tr("Query changesets"));
083            Container cp = getContentPane();
084            cp.setLayout(new BorderLayout());
085            cp.add(buildContentPanel(), BorderLayout.CENTER);
086            cp.add(buildButtonPanel(), BorderLayout.SOUTH);
087    
088            // cancel on ESC
089            getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "cancel");
090            getRootPane().getActionMap().put("cancel", new CancelAction());
091    
092            // context sensitive help
093            HelpUtil.setHelpContext(getRootPane(), HelpUtil.ht("/Dialog/ChangesetQueryDialog"));
094    
095            addWindowListener(new WindowEventHandler());
096        }
097    
098    
099        public ChangesetQueryDialog(Dialog parent) {
100            super(parent, ModalityType.DOCUMENT_MODAL);
101            build();
102        }
103    
104        public ChangesetQueryDialog(Frame parent) {
105            super(parent, ModalityType.DOCUMENT_MODAL);
106            build();
107        }
108    
109        public boolean isCanceled() {
110            return canceled;
111        }
112    
113        public void initForUserInput() {
114            pnlBasicChangesetQueries.init();
115        }
116    
117        protected void setCanceled(boolean canceled) {
118            this.canceled = canceled;
119        }
120    
121        public ChangesetQuery getChangesetQuery() {
122            if (isCanceled())
123                return null;
124            switch(tpQueryPanels.getSelectedIndex()) {
125            case 0:
126                return pnlBasicChangesetQueries.buildChangesetQuery();
127            case 1:
128                return pnlUrlBasedQueries.buildChangesetQuery();
129            case 2:
130                return pnlAdvancedQueries.buildChangesetQuery();
131            default:
132                // FIXME: extend with advanced queries
133                return null;
134            }
135        }
136    
137        public void startUserInput() {
138            pnlUrlBasedQueries.startUserInput();
139            pnlAdvancedQueries.startUserInput();
140        }
141    
142        @Override
143        public void setVisible(boolean visible) {
144            if (visible) {
145                new WindowGeometry(
146                        getClass().getName() + ".geometry",
147                        WindowGeometry.centerInWindow(
148                                getParent(),
149                                new Dimension(400,400)
150                        )
151                ).applySafe(this);
152                setCanceled(false);
153                startUserInput();
154            } else if (!visible && isShowing()){
155                new WindowGeometry(this).remember(getClass().getName() + ".geometry");
156                pnlAdvancedQueries.rememberSettings();
157            }
158            super.setVisible(visible);
159        }
160    
161        class QueryAction extends AbstractAction {
162            public QueryAction() {
163                putValue(NAME, tr("Query"));
164                putValue(SMALL_ICON, ImageProvider.get("dialogs", "search"));
165                putValue(SHORT_DESCRIPTION, tr("Query and download changesets"));
166            }
167    
168            protected void alertInvalidChangesetQuery() {
169                HelpAwareOptionPane.showOptionDialog(
170                        ChangesetQueryDialog.this,
171                        tr("Please enter a valid changeset query URL first."),
172                        tr("Illegal changeset query URL"),
173                        JOptionPane.WARNING_MESSAGE,
174                        HelpUtil.ht("/Dialog/ChangesetQueryDialog#EnterAValidChangesetQueryUrlFirst")
175                );
176            }
177    
178            public void actionPerformed(ActionEvent arg0) {
179                try {
180                    switch(tpQueryPanels.getSelectedIndex()) {
181                    case 0:
182                        // currently, query specifications can't be invalid in the basic query panel.
183                        // We select from a couple of predefined queries and there is always a query
184                        // selected
185                        break;
186                    case 1:
187                        if (getChangesetQuery() == null) {
188                            alertInvalidChangesetQuery();
189                            pnlUrlBasedQueries.startUserInput();
190                            return;
191                        }
192                        break;
193        
194                    case 2:
195                        if (getChangesetQuery() == null) {
196                            pnlAdvancedQueries.displayMessageIfInvalid();
197                            return;
198                        }
199                    }
200                    setCanceled(false);
201                    setVisible(false);
202                } catch (IllegalStateException e) {
203                    JOptionPane.showMessageDialog(ChangesetQueryDialog.this, e.getMessage(), tr("Error"), JOptionPane.ERROR_MESSAGE);
204                }
205            }
206        }
207    
208        class CancelAction extends AbstractAction {
209    
210            public CancelAction() {
211                putValue(NAME, tr("Cancel"));
212                putValue(SMALL_ICON, ImageProvider.get("cancel"));
213                putValue(SHORT_DESCRIPTION, tr("Close the dialog and abort querying of changesets"));
214            }
215    
216            public void cancel() {
217                setCanceled(true);
218                setVisible(false);
219            }
220    
221            public void actionPerformed(ActionEvent arg0) {
222                cancel();
223            }
224        }
225    
226        class WindowEventHandler extends WindowAdapter {
227            @Override
228            public void windowClosing(WindowEvent arg0) {
229                new CancelAction().cancel();
230            }
231        }
232    }