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

Last change on this file since 9293 was 9242, checked in by simon04, 8 years ago

fix #7670 - Add Overpass settings to main preference

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