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

Last change on this file since 11658 was 11658, checked in by Don-vip, 9 months ago

fix #13922 - Add (expert) option to not zoom to the new downloaded data

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