source: josm/trunk/src/org/openstreetmap/josm/gui/download/OverpassDownloadSource.java@ 12707

Last change on this file since 12707 was 12707, checked in by michael2402, 7 years ago

Fix checkstyle warnings.

File size: 14.8 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.download;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.BorderLayout;
7import java.awt.Dimension;
8import java.awt.GridBagLayout;
9import java.awt.event.ActionEvent;
10import java.awt.event.FocusEvent;
11import java.awt.event.FocusListener;
12import java.util.Collection;
13import java.util.concurrent.Future;
14import java.util.function.Consumer;
15
16import javax.swing.AbstractAction;
17import javax.swing.Action;
18import javax.swing.Icon;
19import javax.swing.JButton;
20import javax.swing.JLabel;
21import javax.swing.JOptionPane;
22import javax.swing.JPanel;
23import javax.swing.JScrollPane;
24import javax.swing.event.ListSelectionEvent;
25import javax.swing.event.ListSelectionListener;
26import javax.swing.plaf.basic.BasicArrowButton;
27
28import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask;
29import org.openstreetmap.josm.actions.downloadtasks.PostDownloadHandler;
30import org.openstreetmap.josm.data.Bounds;
31import org.openstreetmap.josm.data.preferences.AbstractProperty;
32import org.openstreetmap.josm.data.preferences.BooleanProperty;
33import org.openstreetmap.josm.data.preferences.IntegerProperty;
34import org.openstreetmap.josm.gui.ConditionalOptionPaneUtil;
35import org.openstreetmap.josm.gui.MainApplication;
36import org.openstreetmap.josm.gui.download.DownloadSourceSizingPolicy.AdjustableDownloadSizePolicy;
37import org.openstreetmap.josm.gui.preferences.server.OverpassServerPreference;
38import org.openstreetmap.josm.gui.util.GuiHelper;
39import org.openstreetmap.josm.gui.widgets.JosmTextArea;
40import org.openstreetmap.josm.io.OverpassDownloadReader;
41import org.openstreetmap.josm.tools.GBC;
42import org.openstreetmap.josm.tools.ImageProvider;
43
44/**
45 * Class defines the way data is fetched from Overpass API.
46 * @since 12652
47 */
48public class OverpassDownloadSource implements DownloadSource<OverpassDownloadSource.OverpassDownloadData> {
49
50 @Override
51 public AbstractDownloadSourcePanel<OverpassDownloadData> createPanel() {
52 return new OverpassDownloadSourcePanel(this);
53 }
54
55 @Override
56 public void doDownload(OverpassDownloadData data, DownloadSettings settings) {
57 /*
58 * In order to support queries generated by the Overpass Turbo Query Wizard tool
59 * which do not require the area to be specified.
60 */
61 Bounds area = settings.getDownloadBounds().orElse(new Bounds(0, 0, 0, 0));
62 DownloadOsmTask task = new DownloadOsmTask();
63 task.setZoomAfterDownload(settings.zoomToData());
64 Future<?> future = task.download(
65 new OverpassDownloadReader(area, OverpassServerPreference.getOverpassServer(), data.getQuery()),
66 settings.asNewLayer(), area, null);
67 MainApplication.worker.submit(new PostDownloadHandler(task, future, data.getErrorReporter()));
68 }
69
70 @Override
71 public String getLabel() {
72 return tr("Download from Overpass API");
73 }
74
75 @Override
76 public boolean onlyExpert() {
77 return true;
78 }
79
80 /**
81 * The GUI representation of the Overpass download source.
82 * @since 12652
83 */
84 public static class OverpassDownloadSourcePanel extends AbstractDownloadSourcePanel<OverpassDownloadData> {
85
86 private static final String SIMPLE_NAME = "overpassdownloadpanel";
87 private static final AbstractProperty<Integer> PANEL_SIZE_PROPERTY =
88 new IntegerProperty(TAB_SPLIT_NAMESPACE + SIMPLE_NAME, 150).cached();
89 private static final BooleanProperty OVERPASS_QUERY_LIST_OPENED =
90 new BooleanProperty("download.overpass.query-list.opened", false);
91 private static final String ACTION_IMG_SUBDIR = "dialogs";
92
93 private JosmTextArea overpassQuery;
94 private OverpassQueryList overpassQueryList;
95
96 /**
97 * Create a new {@link OverpassDownloadSourcePanel}
98 * @param ds The download source to create the panel for
99 */
100 public OverpassDownloadSourcePanel(OverpassDownloadSource ds) {
101 super(ds);
102 setLayout(new BorderLayout());
103
104 String tooltip = tr("Build an Overpass query using the Overpass Turbo Query Wizard tool");
105 Action queryWizardAction = new AbstractAction() {
106 @Override
107 public void actionPerformed(ActionEvent e) {
108 new OverpassQueryWizardDialog(OverpassDownloadSourcePanel.this).showDialog();
109 }
110 };
111
112 JButton openQueryWizard = new JButton(tr("Query Wizard"));
113 openQueryWizard.setToolTipText(tooltip);
114 openQueryWizard.addActionListener(queryWizardAction);
115
116 // CHECKSTYLE.OFF: LineLength
117 this.overpassQuery = new JosmTextArea(
118 "/*\n" +
119 tr("Place your Overpass query below or generate one using the Overpass Turbo Query Wizard")
120 + "\n*/",
121 8, 80);
122 // CHECKSTYLE.ON: LineLength
123 this.overpassQuery.setFont(GuiHelper.getMonospacedFont(overpassQuery));
124 this.overpassQuery.addFocusListener(new FocusListener() {
125 @Override
126 public void focusGained(FocusEvent e) {
127 overpassQuery.selectAll();
128 }
129
130 @Override
131 public void focusLost(FocusEvent e) {
132 // ignored
133 }
134 });
135
136
137 this.overpassQueryList = new OverpassQueryList(this, this.overpassQuery);
138 this.overpassQueryList.setPreferredSize(new Dimension(350, 300));
139
140 EditSnippetAction edit = new EditSnippetAction();
141 RemoveSnippetAction remove = new RemoveSnippetAction();
142 this.overpassQueryList.addSelectionListener(edit);
143 this.overpassQueryList.addSelectionListener(remove);
144
145 JPanel listPanel = new JPanel(new GridBagLayout());
146 listPanel.add(new JLabel(tr("Your saved queries:")), GBC.eol().insets(2).anchor(GBC.CENTER));
147 listPanel.add(this.overpassQueryList, GBC.eol().fill(GBC.BOTH));
148 listPanel.add(new JButton(new AddSnippetAction()), GBC.std().fill(GBC.HORIZONTAL));
149 listPanel.add(new JButton(edit), GBC.std().fill(GBC.HORIZONTAL));
150 listPanel.add(new JButton(remove), GBC.std().fill(GBC.HORIZONTAL));
151 listPanel.setVisible(OVERPASS_QUERY_LIST_OPENED.get());
152
153 JScrollPane scrollPane = new JScrollPane(overpassQuery);
154 BasicArrowButton arrowButton = new BasicArrowButton(listPanel.isVisible()
155 ? BasicArrowButton.EAST
156 : BasicArrowButton.WEST);
157 arrowButton.setToolTipText(tr("Show/hide Overpass snippet list"));
158 arrowButton.addActionListener(e -> {
159 if (listPanel.isVisible()) {
160 listPanel.setVisible(false);
161 arrowButton.setDirection(BasicArrowButton.WEST);
162 OVERPASS_QUERY_LIST_OPENED.put(Boolean.FALSE);
163 } else {
164 listPanel.setVisible(true);
165 arrowButton.setDirection(BasicArrowButton.EAST);
166 OVERPASS_QUERY_LIST_OPENED.put(Boolean.TRUE);
167 }
168 });
169
170 JPanel innerPanel = new JPanel(new BorderLayout());
171 innerPanel.add(scrollPane, BorderLayout.CENTER);
172 innerPanel.add(arrowButton, BorderLayout.EAST);
173
174 JPanel leftPanel = new JPanel(new GridBagLayout());
175 leftPanel.add(new JLabel(tr("Overpass query:")), GBC.eol().insets(5, 1, 5, 1).anchor(GBC.NORTHWEST));
176 leftPanel.add(new JLabel(), GBC.eol().fill(GBC.VERTICAL));
177 leftPanel.add(openQueryWizard, GBC.eol().anchor(GBC.CENTER));
178 leftPanel.add(new JLabel(), GBC.eol().fill(GBC.VERTICAL));
179
180 add(leftPanel, BorderLayout.WEST);
181 add(innerPanel, BorderLayout.CENTER);
182 add(listPanel, BorderLayout.EAST);
183
184 setMinimumSize(new Dimension(450, 240));
185 }
186
187 @Override
188 public OverpassDownloadData getData() {
189 String query = overpassQuery.getText();
190 /*
191 * A callback that is passed to PostDownloadReporter that is called once the download task
192 * has finished. According to the number of errors happened, their type we decide whether we
193 * want to save the last query in OverpassQueryList.
194 */
195 Consumer<Collection<Object>> errorReporter = errors -> {
196
197 boolean onlyNoDataError = errors.size() == 1 &&
198 errors.contains("No data found in this area.");
199
200 if (errors.isEmpty() || onlyNoDataError) {
201 overpassQueryList.saveHistoricItem(query);
202 }
203 };
204
205 return new OverpassDownloadData(query, errorReporter);
206 }
207
208 @Override
209 public void rememberSettings() {
210 // nothing
211 }
212
213 @Override
214 public void restoreSettings() {
215 // nothing
216 }
217
218 @Override
219 public boolean checkDownload(DownloadSettings settings) {
220 String query = getData().getQuery();
221
222 /*
223 * Absence of the selected area can be justified only if the overpass query
224 * is not restricted to bbox.
225 */
226 if (!settings.getDownloadBounds().isPresent() && query.contains("{{bbox}}")) {
227 JOptionPane.showMessageDialog(
228 this.getParent(),
229 tr("Please select a download area first."),
230 tr("Error"),
231 JOptionPane.ERROR_MESSAGE
232 );
233 return false;
234 }
235
236 /*
237 * Check for an empty query. User might want to download everything, if so validation is passed,
238 * otherwise return false.
239 */
240 if (query.matches("(/\\*(\\*[^/]|[^\\*/])*\\*/|\\s)*")) {
241 boolean doFix = ConditionalOptionPaneUtil.showConfirmationDialog(
242 "download.overpass.fix.emptytoall",
243 this,
244 tr("You entered an empty query. Do you want to download all data in this area instead?"),
245 tr("Download all data?"),
246 JOptionPane.YES_NO_OPTION,
247 JOptionPane.QUESTION_MESSAGE,
248 JOptionPane.YES_OPTION);
249 if (doFix) {
250 String repairedQuery = "[out:xml]; \n"
251 + query + "\n"
252 + "(\n"
253 + " node({{bbox}});\n"
254 + "<;\n"
255 + ");\n"
256 + "(._;>;);"
257 + "out meta;";
258 this.overpassQuery.setText(repairedQuery);
259 } else {
260 return false;
261 }
262 }
263
264 return true;
265 }
266
267 /**
268 * Sets query to the query text field.
269 * @param query The query to set.
270 */
271 public void setOverpassQuery(String query) {
272 this.overpassQuery.setText(query);
273 }
274
275 @Override
276 public Icon getIcon() {
277 return ImageProvider.get("download-overpass");
278 }
279
280 @Override
281 public String getSimpleName() {
282 return SIMPLE_NAME;
283 }
284
285 @Override
286 public DownloadSourceSizingPolicy getSizingPolicy() {
287 return new AdjustableDownloadSizePolicy(PANEL_SIZE_PROPERTY);
288 }
289
290 /**
291 * Action that delegates snippet creation to {@link OverpassQueryList#createNewItem()}.
292 */
293 private class AddSnippetAction extends AbstractAction {
294
295 /**
296 * Constructs a new {@code AddSnippetAction}.
297 */
298 AddSnippetAction() {
299 super();
300 putValue(SMALL_ICON, ImageProvider.get(ACTION_IMG_SUBDIR, "add"));
301 putValue(SHORT_DESCRIPTION, tr("Add new snippet"));
302 }
303
304 @Override
305 public void actionPerformed(ActionEvent e) {
306 overpassQueryList.createNewItem();
307 }
308 }
309
310 /**
311 * Action that delegates snippet removal to {@link OverpassQueryList#removeSelectedItem()}.
312 */
313 private class RemoveSnippetAction extends AbstractAction implements ListSelectionListener {
314
315 /**
316 * Constructs a new {@code RemoveSnippetAction}.
317 */
318 RemoveSnippetAction() {
319 super();
320 putValue(SMALL_ICON, ImageProvider.get(ACTION_IMG_SUBDIR, "delete"));
321 putValue(SHORT_DESCRIPTION, tr("Delete selected snippet"));
322 checkEnabled();
323 }
324
325 @Override
326 public void actionPerformed(ActionEvent e) {
327 overpassQueryList.removeSelectedItem();
328 }
329
330 /**
331 * Disables the action if no items are selected.
332 */
333 void checkEnabled() {
334 setEnabled(overpassQueryList.getSelectedItem().isPresent());
335 }
336
337 @Override
338 public void valueChanged(ListSelectionEvent e) {
339 checkEnabled();
340 }
341 }
342
343 /**
344 * Action that delegates snippet edit to {@link OverpassQueryList#editSelectedItem()}.
345 */
346 private class EditSnippetAction extends AbstractAction implements ListSelectionListener {
347
348 /**
349 * Constructs a new {@code EditSnippetAction}.
350 */
351 EditSnippetAction() {
352 super();
353 putValue(SMALL_ICON, ImageProvider.get(ACTION_IMG_SUBDIR, "edit"));
354 putValue(SHORT_DESCRIPTION, tr("Edit selected snippet"));
355 checkEnabled();
356 }
357
358 @Override
359 public void actionPerformed(ActionEvent e) {
360 overpassQueryList.editSelectedItem();
361 }
362
363 /**
364 * Disables the action if no items are selected.
365 */
366 void checkEnabled() {
367 setEnabled(overpassQueryList.getSelectedItem().isPresent());
368 }
369
370 @Override
371 public void valueChanged(ListSelectionEvent e) {
372 checkEnabled();
373 }
374 }
375 }
376
377 /**
378 * Encapsulates data that is required to preform download from Overpass API.
379 */
380 static class OverpassDownloadData {
381 private String query;
382 private Consumer<Collection<Object>> errorReporter;
383
384 OverpassDownloadData(String query, Consumer<Collection<Object>> errorReporter) {
385 this.query = query;
386 this.errorReporter = errorReporter;
387 }
388
389 String getQuery() {
390 return this.query;
391 }
392
393 Consumer<Collection<Object>> getErrorReporter() {
394 return this.errorReporter;
395 }
396 }
397}
Note: See TracBrowser for help on using the repository browser.