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 }