source: josm/trunk/src/org/openstreetmap/josm/actions/OverpassDownloadAction.java@ 11626

Last change on this file since 11626 was 10782, checked in by simon04, 8 years ago

fix #13317 - pressing enter in wizard box should create the overpass query

File size: 11.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.actions;
3
4import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
5import static org.openstreetmap.josm.tools.I18n.tr;
6
7import java.awt.BorderLayout;
8import java.awt.Component;
9import java.awt.GridLayout;
10import java.awt.Rectangle;
11import java.awt.event.ActionEvent;
12import java.awt.event.ActionListener;
13import java.awt.event.FocusEvent;
14import java.awt.event.FocusListener;
15import java.awt.event.KeyEvent;
16import java.util.ArrayList;
17import java.util.Collection;
18import java.util.Collections;
19import java.util.Deque;
20import java.util.LinkedList;
21import java.util.concurrent.Future;
22
23import javax.swing.AbstractAction;
24import javax.swing.Action;
25import javax.swing.ActionMap;
26import javax.swing.JButton;
27import javax.swing.JComponent;
28import javax.swing.JLabel;
29import javax.swing.JMenuItem;
30import javax.swing.JOptionPane;
31import javax.swing.JPanel;
32import javax.swing.JPopupMenu;
33import javax.swing.JScrollPane;
34import javax.swing.plaf.basic.BasicArrowButton;
35
36import org.openstreetmap.josm.Main;
37import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask;
38import org.openstreetmap.josm.actions.downloadtasks.PostDownloadHandler;
39import org.openstreetmap.josm.data.Bounds;
40import org.openstreetmap.josm.data.preferences.CollectionProperty;
41import org.openstreetmap.josm.data.preferences.IntegerProperty;
42import org.openstreetmap.josm.gui.HelpAwareOptionPane;
43import org.openstreetmap.josm.gui.download.DownloadDialog;
44import org.openstreetmap.josm.gui.preferences.server.OverpassServerPreference;
45import org.openstreetmap.josm.gui.util.GuiHelper;
46import org.openstreetmap.josm.gui.widgets.HistoryComboBox;
47import org.openstreetmap.josm.gui.widgets.JosmTextArea;
48import org.openstreetmap.josm.io.OverpassDownloadReader;
49import org.openstreetmap.josm.tools.GBC;
50import org.openstreetmap.josm.tools.InputMapUtils;
51import org.openstreetmap.josm.tools.OverpassTurboQueryWizard;
52import org.openstreetmap.josm.tools.Shortcut;
53import org.openstreetmap.josm.tools.UncheckedParseException;
54import org.openstreetmap.josm.tools.Utils;
55
56/**
57 * Download map data from Overpass API server.
58 * @since 8684
59 */
60public class OverpassDownloadAction extends JosmAction {
61
62 /**
63 * Constructs a new {@code OverpassDownloadAction}.
64 */
65 public OverpassDownloadAction() {
66 super(tr("Download from Overpass API ..."), "download-overpass", tr("Download map data from Overpass API server."),
67 // CHECKSTYLE.OFF: LineLength
68 Shortcut.registerShortcut("file:download-overpass", tr("File: {0}", tr("Download from Overpass API ...")), KeyEvent.VK_DOWN, Shortcut.ALT_SHIFT),
69 // CHECKSTYLE.ON: LineLength
70 true, "overpassdownload/download", true);
71 putValue("help", ht("/Action/OverpassDownload"));
72 }
73
74 @Override
75 public void actionPerformed(ActionEvent e) {
76 OverpassDownloadDialog dialog = OverpassDownloadDialog.getInstance();
77 dialog.restoreSettings();
78 dialog.setVisible(true);
79 if (!dialog.isCanceled()) {
80 dialog.rememberSettings();
81 Bounds area = dialog.getSelectedDownloadArea();
82 DownloadOsmTask task = new DownloadOsmTask();
83 Future<?> future = task.download(
84 new OverpassDownloadReader(area, OverpassServerPreference.getOverpassServer(), dialog.getOverpassQuery()),
85 dialog.isNewLayerRequired(), area, null);
86 Main.worker.submit(new PostDownloadHandler(task, future));
87 }
88 }
89
90 private static final class DisableActionsFocusListener implements FocusListener {
91
92 private final ActionMap actionMap;
93
94 private DisableActionsFocusListener(ActionMap actionMap) {
95 this.actionMap = actionMap;
96 }
97
98 @Override
99 public void focusGained(FocusEvent e) {
100 enableActions(false);
101 }
102
103 @Override
104 public void focusLost(FocusEvent e) {
105 enableActions(true);
106 }
107
108 private void enableActions(boolean enabled) {
109 Object[] allKeys = actionMap.allKeys();
110 if (allKeys != null) {
111 for (Object key : allKeys) {
112 Action action = actionMap.get(key);
113 if (action != null) {
114 action.setEnabled(enabled);
115 }
116 }
117 }
118 }
119 }
120
121 private static final class OverpassDownloadDialog extends DownloadDialog {
122
123 private HistoryComboBox overpassWizard;
124 private JosmTextArea overpassQuery;
125 private static OverpassDownloadDialog instance;
126 private static final CollectionProperty OVERPASS_WIZARD_HISTORY = new CollectionProperty("download.overpass.wizard",
127 new ArrayList<String>());
128
129 private OverpassDownloadDialog(Component parent) {
130 super(parent, ht("/Action/OverpassDownload"));
131 cbDownloadOsmData.setEnabled(false);
132 cbDownloadOsmData.setSelected(false);
133 cbDownloadGpxData.setVisible(false);
134 cbDownloadNotes.setVisible(false);
135 cbStartup.setVisible(false);
136 }
137
138 public static OverpassDownloadDialog getInstance() {
139 if (instance == null) {
140 instance = new OverpassDownloadDialog(Main.parent);
141 }
142 return instance;
143 }
144
145 @Override
146 protected void buildMainPanelAboveDownloadSelections(JPanel pnl) {
147
148 DisableActionsFocusListener disableActionsFocusListener =
149 new DisableActionsFocusListener(slippyMapChooser.getNavigationComponentActionMap());
150
151 pnl.add(new JLabel(), GBC.eol()); // needed for the invisible checkboxes cbDownloadGpxData, cbDownloadNotes
152
153 final String tooltip = tr("Builds an Overpass query using the Overpass Turbo query wizard");
154 overpassWizard = new HistoryComboBox();
155 overpassWizard.setToolTipText(tooltip);
156 overpassWizard.getEditorComponent().addFocusListener(disableActionsFocusListener);
157 final JButton buildQuery = new JButton(tr("Build query"));
158 final Action buildQueryAction = new AbstractAction() {
159 @Override
160 public void actionPerformed(ActionEvent e) {
161 final String overpassWizardText = overpassWizard.getText();
162 try {
163 overpassQuery.setText(OverpassTurboQueryWizard.getInstance().constructQuery(overpassWizardText));
164 } catch (UncheckedParseException ex) {
165 Main.error(ex);
166 HelpAwareOptionPane.showOptionDialog(
167 Main.parent,
168 tr("<html>The Overpass wizard could not parse the following query:"
169 + Utils.joinAsHtmlUnorderedList(Collections.singleton(overpassWizardText))),
170 tr("Parse error"),
171 JOptionPane.ERROR_MESSAGE,
172 null
173 );
174 }
175 }
176 };
177 buildQuery.addActionListener(buildQueryAction);
178 buildQuery.setToolTipText(tooltip);
179 pnl.add(buildQuery, GBC.std().insets(5, 5, 5, 5));
180 pnl.add(overpassWizard, GBC.eol().fill(GBC.HORIZONTAL));
181 InputMapUtils.addEnterAction(overpassWizard.getEditorComponent(), buildQueryAction);
182
183 overpassQuery = new JosmTextArea("", 8, 80);
184 overpassQuery.setFont(GuiHelper.getMonospacedFont(overpassQuery));
185 overpassQuery.addFocusListener(disableActionsFocusListener);
186 JScrollPane scrollPane = new JScrollPane(overpassQuery);
187 final JPanel pane = new JPanel(new BorderLayout());
188 final BasicArrowButton arrowButton = new BasicArrowButton(BasicArrowButton.SOUTH);
189 arrowButton.addActionListener(new AbstractAction() {
190 @Override
191 public void actionPerformed(ActionEvent e) {
192 OverpassQueryHistoryPopup.show(arrowButton, OverpassDownloadDialog.this);
193 }
194 });
195 pane.add(scrollPane, BorderLayout.CENTER);
196 pane.add(arrowButton, BorderLayout.EAST);
197 pnl.add(new JLabel(tr("Overpass query: ")), GBC.std().insets(5, 5, 5, 5));
198 GBC gbc = GBC.eol().fill(GBC.HORIZONTAL);
199 gbc.ipady = 200;
200 pnl.add(pane, gbc);
201
202 }
203
204 public String getOverpassQuery() {
205 return overpassQuery.getText();
206 }
207
208 public void setOverpassQuery(String text) {
209 overpassQuery.setText(text);
210 }
211
212 @Override
213 public void restoreSettings() {
214 super.restoreSettings();
215 overpassWizard.setPossibleItems(OVERPASS_WIZARD_HISTORY.get());
216 }
217
218 @Override
219 public void rememberSettings() {
220 super.rememberSettings();
221 overpassWizard.addCurrentItemToHistory();
222 OVERPASS_WIZARD_HISTORY.put(overpassWizard.getHistory());
223 OverpassQueryHistoryPopup.addToHistory(getOverpassQuery());
224 }
225
226 @Override
227 protected void updateSizeCheck() {
228 displaySizeCheckResult(false);
229 }
230 }
231
232 static class OverpassQueryHistoryPopup extends JPopupMenu {
233
234 static final CollectionProperty OVERPASS_QUERY_HISTORY = new CollectionProperty("download.overpass.query", new ArrayList<String>());
235 static final IntegerProperty OVERPASS_QUERY_HISTORY_SIZE = new IntegerProperty("download.overpass.query.size", 12);
236
237 OverpassQueryHistoryPopup(final OverpassDownloadDialog dialog) {
238 final Collection<String> history = OVERPASS_QUERY_HISTORY.get();
239 setLayout(new GridLayout((int) Math.ceil(history.size() / 2.), 2));
240 for (final String i : history) {
241 add(new OverpassQueryHistoryItem(i, dialog));
242 }
243 }
244
245 static void show(final JComponent parent, final OverpassDownloadDialog dialog) {
246 final OverpassQueryHistoryPopup menu = new OverpassQueryHistoryPopup(dialog);
247 final Rectangle r = parent.getBounds();
248 menu.show(parent.getParent(), r.x + r.width - (int) menu.getPreferredSize().getWidth(), r.y + r.height);
249 }
250
251 static void addToHistory(final String query) {
252 final Deque<String> history = new LinkedList<>(OVERPASS_QUERY_HISTORY.get());
253 if (!history.contains(query)) {
254 history.add(query);
255 }
256 while (history.size() > OVERPASS_QUERY_HISTORY_SIZE.get()) {
257 history.removeFirst();
258 }
259 OVERPASS_QUERY_HISTORY.put(history);
260 }
261 }
262
263 static class OverpassQueryHistoryItem extends JMenuItem implements ActionListener {
264
265 final String query;
266 final OverpassDownloadDialog dialog;
267
268 OverpassQueryHistoryItem(final String query, final OverpassDownloadDialog dialog) {
269 this.query = query;
270 this.dialog = dialog;
271 setText("<html><pre style='width:300px;'>" +
272 Utils.escapeReservedCharactersHTML(Utils.restrictStringLines(query, 7)));
273 addActionListener(this);
274 }
275
276 @Override
277 public void actionPerformed(ActionEvent e) {
278 dialog.setOverpassQuery(query);
279 }
280 }
281
282}
Note: See TracBrowser for help on using the repository browser.