Changeset 12574 in josm for trunk/src/org


Ignore:
Timestamp:
2017-08-06T20:13:06+02:00 (7 years ago)
Author:
michael2402
Message:

Apply #15057: Improve the over pass turbo dialog

Adds the ability to add favorites and a new wizard dialog with examples.

Location:
trunk/src/org/openstreetmap/josm
Files:
1 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/actions/DownloadAction.java

    r11774 r12574  
    99import java.util.ArrayList;
    1010import java.util.List;
     11import java.util.Optional;
    1112import java.util.concurrent.ExecutionException;
    1213import java.util.concurrent.Future;
     14
     15import javax.swing.JOptionPane;
    1316
    1417import org.openstreetmap.josm.Main;
     
    5154        dialog.restoreSettings();
    5255        dialog.setVisible(true);
    53         if (!dialog.isCanceled()) {
    54             dialog.rememberSettings();
    55             final Bounds area = dialog.getSelectedDownloadArea();
    56             final boolean zoom = dialog.isZoomToDownloadedDataRequired();
    57             final List<Pair<AbstractDownloadTask<?>, Future<?>>> tasks = new ArrayList<>();
    58             if (dialog.isDownloadOsmData()) {
    59                 DownloadOsmTask task = new DownloadOsmTask();
    60                 task.setZoomAfterDownload(zoom && !dialog.isDownloadGpxData() && !dialog.isDownloadNotes());
    61                 Future<?> future = task.download(dialog.isNewLayerRequired(), area, null);
    62                 Main.worker.submit(new PostDownloadHandler(task, future));
    63                 if (zoom) {
    64                     tasks.add(new Pair<>(task, future));
     56
     57        if (dialog.isCanceled()) {
     58            return;
     59        }
     60
     61        dialog.rememberSettings();
     62
     63        Optional<Bounds> selectedArea = dialog.getSelectedDownloadArea();
     64        if (!selectedArea.isPresent()) {
     65            JOptionPane.showMessageDialog(
     66                    dialog,
     67                    tr("Please select a download area first."),
     68                    tr("Error"),
     69                    JOptionPane.ERROR_MESSAGE
     70            );
     71            return;
     72        }
     73
     74        final Bounds area = selectedArea.get();
     75        final boolean zoom = dialog.isZoomToDownloadedDataRequired();
     76        final List<Pair<AbstractDownloadTask<?>, Future<?>>> tasks = new ArrayList<>();
     77
     78        if (dialog.isDownloadOsmData()) {
     79            DownloadOsmTask task = new DownloadOsmTask();
     80            task.setZoomAfterDownload(zoom && !dialog.isDownloadGpxData() && !dialog.isDownloadNotes());
     81            Future<?> future = task.download(dialog.isNewLayerRequired(), area, null);
     82            Main.worker.submit(new PostDownloadHandler(task, future));
     83            if (zoom) {
     84                tasks.add(new Pair<>(task, future));
     85            }
     86        }
     87
     88        if (dialog.isDownloadGpxData()) {
     89            DownloadGpsTask task = new DownloadGpsTask();
     90            task.setZoomAfterDownload(zoom && !dialog.isDownloadOsmData() && !dialog.isDownloadNotes());
     91            Future<?> future = task.download(dialog.isNewLayerRequired(), area, null);
     92            Main.worker.submit(new PostDownloadHandler(task, future));
     93            if (zoom) {
     94                tasks.add(new Pair<>(task, future));
     95            }
     96        }
     97
     98        if (dialog.isDownloadNotes()) {
     99            DownloadNotesTask task = new DownloadNotesTask();
     100            task.setZoomAfterDownload(zoom && !dialog.isDownloadOsmData() && !dialog.isDownloadGpxData());
     101            Future<?> future = task.download(false, area, null);
     102            Main.worker.submit(new PostDownloadHandler(task, future));
     103            if (zoom) {
     104                tasks.add(new Pair<>(task, future));
     105            }
     106        }
     107
     108        if (zoom && tasks.size() > 1) {
     109            Main.worker.submit(() -> {
     110                ProjectionBounds bounds = null;
     111                // Wait for completion of download jobs
     112                for (Pair<AbstractDownloadTask<?>, Future<?>> p : tasks) {
     113                    try {
     114                        p.b.get();
     115                        ProjectionBounds b = p.a.getDownloadProjectionBounds();
     116                        if (bounds == null) {
     117                            bounds = b;
     118                        } else if (b != null) {
     119                            bounds.extend(b);
     120                        }
     121                    } catch (InterruptedException | ExecutionException ex) {
     122                        Main.warn(ex);
     123                    }
    65124                }
    66             }
    67             if (dialog.isDownloadGpxData()) {
    68                 DownloadGpsTask task = new DownloadGpsTask();
    69                 task.setZoomAfterDownload(zoom && !dialog.isDownloadOsmData() && !dialog.isDownloadNotes());
    70                 Future<?> future = task.download(dialog.isNewLayerRequired(), area, null);
    71                 Main.worker.submit(new PostDownloadHandler(task, future));
    72                 if (zoom) {
    73                     tasks.add(new Pair<>(task, future));
     125                // Zoom to the larger download bounds
     126                if (Main.map != null && bounds != null) {
     127                    final ProjectionBounds pb = bounds;
     128                    GuiHelper.runInEDTAndWait(() -> Main.map.mapView.zoomTo(new ViewportData(pb)));
    74129                }
    75             }
    76             if (dialog.isDownloadNotes()) {
    77                 DownloadNotesTask task = new DownloadNotesTask();
    78                 task.setZoomAfterDownload(zoom && !dialog.isDownloadOsmData() && !dialog.isDownloadGpxData());
    79                 Future<?> future = task.download(false, area, null);
    80                 Main.worker.submit(new PostDownloadHandler(task, future));
    81                 if (zoom) {
    82                     tasks.add(new Pair<>(task, future));
    83                 }
    84             }
    85             if (zoom && tasks.size() > 1) {
    86                 Main.worker.submit(() -> {
    87                     ProjectionBounds bounds = null;
    88                     // Wait for completion of download jobs
    89                     for (Pair<AbstractDownloadTask<?>, Future<?>> p : tasks) {
    90                         try {
    91                             p.b.get();
    92                             ProjectionBounds b = p.a.getDownloadProjectionBounds();
    93                             if (bounds == null) {
    94                                 bounds = b;
    95                             } else if (b != null) {
    96                                 bounds.extend(b);
    97                             }
    98                         } catch (InterruptedException | ExecutionException ex) {
    99                             Main.warn(ex);
    100                         }
    101                     }
    102                     // Zoom to the larger download bounds
    103                     if (Main.map != null && bounds != null) {
    104                         final ProjectionBounds pb = bounds;
    105                         GuiHelper.runInEDTAndWait(() -> Main.map.mapView.zoomTo(new ViewportData(pb)));
    106                     }
    107                 });
    108             }
     130            });
    109131        }
    110132    }
  • trunk/src/org/openstreetmap/josm/actions/OverpassDownloadAction.java

    r11658 r12574  
    77import java.awt.BorderLayout;
    88import java.awt.Component;
    9 import java.awt.GridLayout;
    10 import java.awt.Rectangle;
     9import java.awt.Dimension;
     10import java.awt.GridBagLayout;
    1111import java.awt.event.ActionEvent;
    12 import java.awt.event.ActionListener;
    1312import java.awt.event.FocusEvent;
    1413import java.awt.event.FocusListener;
    1514import java.awt.event.KeyEvent;
    1615import java.util.ArrayList;
     16import java.util.Arrays;
    1717import java.util.Collection;
    1818import java.util.Collections;
    19 import java.util.Deque;
    20 import java.util.LinkedList;
     19import java.util.Optional;
    2120import java.util.concurrent.Future;
     21import java.util.function.Consumer;
    2222
    2323import javax.swing.AbstractAction;
     
    2525import javax.swing.ActionMap;
    2626import javax.swing.JButton;
    27 import javax.swing.JComponent;
     27import javax.swing.JEditorPane;
    2828import javax.swing.JLabel;
    29 import javax.swing.JMenuItem;
    3029import javax.swing.JOptionPane;
    3130import javax.swing.JPanel;
    32 import javax.swing.JPopupMenu;
    3331import javax.swing.JScrollPane;
     32import javax.swing.event.HyperlinkEvent;
    3433import javax.swing.plaf.basic.BasicArrowButton;
     34import javax.swing.text.JTextComponent;
    3535
    3636import org.openstreetmap.josm.Main;
     
    3838import org.openstreetmap.josm.actions.downloadtasks.PostDownloadHandler;
    3939import org.openstreetmap.josm.data.Bounds;
     40import org.openstreetmap.josm.data.preferences.BooleanProperty;
    4041import org.openstreetmap.josm.data.preferences.CollectionProperty;
    41 import org.openstreetmap.josm.data.preferences.IntegerProperty;
    42 import org.openstreetmap.josm.gui.HelpAwareOptionPane;
     42import org.openstreetmap.josm.gui.ExtendedDialog;
    4343import org.openstreetmap.josm.gui.download.DownloadDialog;
     44import org.openstreetmap.josm.gui.download.OverpassQueryList;
    4445import org.openstreetmap.josm.gui.preferences.server.OverpassServerPreference;
    4546import org.openstreetmap.josm.gui.util.GuiHelper;
     
    4849import org.openstreetmap.josm.io.OverpassDownloadReader;
    4950import org.openstreetmap.josm.tools.GBC;
    50 import org.openstreetmap.josm.tools.InputMapUtils;
     51import org.openstreetmap.josm.tools.OpenBrowser;
    5152import org.openstreetmap.josm.tools.OverpassTurboQueryWizard;
    5253import org.openstreetmap.josm.tools.Shortcut;
     
    7778        dialog.restoreSettings();
    7879        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         }
     80
     81        if (dialog.isCanceled()) {
     82            return;
     83        }
     84
     85        dialog.rememberSettings();
     86        Optional<Bounds> selectedArea = dialog.getSelectedDownloadArea();
     87        String overpassQuery = dialog.getOverpassQuery();
     88
     89        /*
     90         * Absence of the selected area can be justified only if the overpass query
     91         * is not restricted to bbox.
     92         */
     93        if (!selectedArea.isPresent() && overpassQuery.contains("{{bbox}}")) {
     94            JOptionPane.showMessageDialog(
     95                    dialog,
     96                    tr("Please select a download area first."),
     97                    tr("Error"),
     98                    JOptionPane.ERROR_MESSAGE
     99            );
     100            return;
     101        }
     102
     103        /*
     104         * A callback that is passed to PostDownloadReporter that is called once the download task
     105         * has finished. According to the number of errors happened, their type we decide whether we
     106         * want to save the last query in OverpassQueryList.
     107         */
     108        Consumer<Collection> errorReporter = (errors) -> {
     109
     110            boolean onlyNoDataError = errors.size() == 1 &&
     111                    errors.contains("No data found in this area.");
     112
     113            if (errors.isEmpty() || onlyNoDataError) {
     114                dialog.saveHistoricItemOnSuccess();
     115            }
     116        };
     117
     118        /*
     119         * In order to support queries generated by the Overpass Turbo Query Wizard tool
     120         * which do not require the area to be specified.
     121         */
     122        Bounds area = selectedArea.orElseGet(() -> new Bounds(0, 0, 0, 0));
     123        DownloadOsmTask task = new DownloadOsmTask();
     124        task.setZoomAfterDownload(dialog.isZoomToDownloadedDataRequired());
     125        Future<?> future = task.download(
     126                new OverpassDownloadReader(area, OverpassServerPreference.getOverpassServer(), dialog.getOverpassQuery()),
     127                dialog.isNewLayerRequired(), area, null);
     128        Main.worker.submit(new PostDownloadHandler(task, future, errorReporter));
    89129    }
    90130
     
    122162    private static final class OverpassDownloadDialog extends DownloadDialog {
    123163
    124         private HistoryComboBox overpassWizard;
    125164        private JosmTextArea overpassQuery;
     165        private OverpassQueryList overpassQueryList;
    126166        private static OverpassDownloadDialog instance;
    127         private static final CollectionProperty OVERPASS_WIZARD_HISTORY = new CollectionProperty("download.overpass.wizard",
    128                 new ArrayList<String>());
     167        private static final BooleanProperty OVERPASS_QUERY_LIST_OPENED =
     168                new BooleanProperty("download.overpass.query-list.opened", false);
    129169
    130170        private OverpassDownloadDialog(Component parent) {
     
    146186        @Override
    147187        protected void buildMainPanelAboveDownloadSelections(JPanel pnl) {
     188            // needed for the invisible checkboxes cbDownloadGpxData, cbDownloadNotes
     189            pnl.add(new JLabel(), GBC.eol());
    148190
    149191            DisableActionsFocusListener disableActionsFocusListener =
    150192                    new DisableActionsFocusListener(slippyMapChooser.getNavigationComponentActionMap());
    151193
    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() {
     194            String tooltip = tr("Build an Overpass query using the Overpass Turbo Query Wizard tool");
     195            Action queryWizardAction = new AbstractAction() {
    160196                @Override
    161197                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                     }
     198                    QueryWizardDialog.getInstance().showDialog();
    176199                }
    177200            };
    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);
     201
     202            JButton openQueryWizard = new JButton("Query Wizard");
     203            openQueryWizard.setToolTipText(tooltip);
     204            openQueryWizard.addActionListener(queryWizardAction);
     205
     206            // CHECKSTYLE.OFF: LineLength
     207            this.overpassQuery = new JosmTextArea(
     208                    "/*\n" +
     209                    tr("Place your Overpass query below or generate one using the Overpass Turbo Query Wizard")
     210                    + "\n*/",
     211                    8, 80);
     212            // CHECKSTYLE.ON: LineLength
     213            this.overpassQuery.setFont(GuiHelper.getMonospacedFont(overpassQuery));
     214            this.overpassQuery.addFocusListener(disableActionsFocusListener);
     215            this.overpassQuery.addFocusListener(new FocusListener() {
     216                @Override
     217                public void focusGained(FocusEvent e) {
     218                    overpassQuery.selectAll();
     219                }
     220
     221                @Override
     222                public void focusLost(FocusEvent e) {
     223
     224                }
     225            });
     226
     227            this.overpassQueryList = new OverpassQueryList(this, this.overpassQuery);
     228            overpassQueryList.setToolTipText(tr("Show/hide Overpass snippet list"));
     229            overpassQueryList.setVisible(OVERPASS_QUERY_LIST_OPENED.get());
     230            overpassQueryList.setPreferredSize(new Dimension(350, 300));
    187231            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);
     232            BasicArrowButton arrowButton = new BasicArrowButton(overpassQueryList.isVisible()
     233                ? BasicArrowButton.EAST
     234                : BasicArrowButton.WEST);
     235            arrowButton.addActionListener(e ->  {
     236                if (overpassQueryList.isVisible()) {
     237                    overpassQueryList.setVisible(false);
     238                    arrowButton.setDirection(BasicArrowButton.WEST);
     239                    OVERPASS_QUERY_LIST_OPENED.put(false);
     240                } else {
     241                    overpassQueryList.setVisible(true);
     242                    arrowButton.setDirection(BasicArrowButton.EAST);
     243                    OVERPASS_QUERY_LIST_OPENED.put(false);
    194244                }
    195245            });
    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;
     246
     247            JPanel innerPanel = new JPanel(new BorderLayout());
     248            innerPanel.add(scrollPane, BorderLayout.CENTER);
     249            innerPanel.add(arrowButton, BorderLayout.EAST);
     250
     251            JPanel pane = new JPanel(new BorderLayout());
     252            pane.add(innerPanel, BorderLayout.CENTER);
     253            pane.add(overpassQueryList, BorderLayout.EAST);
     254
     255            GBC gbc = GBC.eol().fill(GBC.HORIZONTAL); gbc.ipady = 200;
     256            pnl.add(openQueryWizard, GBC.std().insets(5, 5, 5, 5));
    201257            pnl.add(pane, gbc);
    202 
    203         }
    204 
    205         public String getOverpassQuery() {
     258        }
     259
     260        String getOverpassQuery() {
    206261            return overpassQuery.getText();
    207262        }
    208263
    209         public void setOverpassQuery(String text) {
     264        void setOverpassQuery(String text) {
    210265            overpassQuery.setText(text);
    211266        }
    212267
    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());
     268        /**
     269         * Adds the current query to {@link OverpassQueryList}.
     270         */
     271        void saveHistoricItemOnSuccess() {
     272            overpassQueryList.saveHistoricItem(overpassQuery.getText());
    225273        }
    226274
     
    229277            displaySizeCheckResult(false);
    230278        }
     279
     280        /**
     281         * Triggers the download action to fire.
     282         */
     283        private void triggerDownload() {
     284            super.btnDownload.doClick();
     285        }
    231286    }
    232287
    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);
     288    private static final class QueryWizardDialog extends ExtendedDialog {
     289
     290        private static QueryWizardDialog dialog;
     291        private final HistoryComboBox queryWizard;
     292        private final OverpassTurboQueryWizard overpassQueryBuilder;
     293        private static final CollectionProperty OVERPASS_WIZARD_HISTORY =
     294                new CollectionProperty("download.overpass.wizard", new ArrayList<String>());
     295
     296        // dialog buttons
     297        private static final int BUILD_QUERY = 0;
     298        private static final int BUILD_AN_EXECUTE_QUERY = 1;
     299        private static final int CANCEL = 2;
     300
     301        /**
     302         * Get an instance of {@link QueryWizardDialog}.
     303         * @return The instance
     304         */
     305        public static QueryWizardDialog getInstance() {
     306            if (dialog == null) {
     307                dialog = new QueryWizardDialog();
     308            }
     309
     310            return dialog;
     311        }
     312
     313        private static final String DESCRIPTION_STYLE =
     314                "<style type=\"text/css\">\n"
     315                + "table { border-spacing: 0pt;}\n"
     316                + "h3 {text-align: center; padding: 8px;}\n"
     317                + "td {border: 1px solid #dddddd; text-align: left; padding: 8px;}\n"
     318                + "#desc {width: 350px;}"
     319                + "</style>\n";
     320
     321        private QueryWizardDialog() {
     322            super(OverpassDownloadDialog.getInstance(), tr("Overpass Turbo Query Wizard"),
     323                    tr("Build query"), tr("Build query and execute"), tr("Cancel"));
     324
     325            this.queryWizard = new HistoryComboBox();
     326            this.overpassQueryBuilder = OverpassTurboQueryWizard.getInstance();
     327
     328            JPanel panel = new JPanel(new GridBagLayout());
     329
     330            JLabel searchLabel = new JLabel(tr("Search :"));
     331            JTextComponent descPane = this.buildDescriptionSection();
     332            JScrollPane scroll = GuiHelper.embedInVerticalScrollPane(descPane);
     333            scroll.getVerticalScrollBar().setUnitIncrement(10); // make scrolling smooth
     334
     335            panel.add(searchLabel, GBC.std().insets(0, 0, 0, 20).anchor(GBC.SOUTHEAST));
     336            panel.add(queryWizard, GBC.eol().insets(0, 0, 0, 15).fill(GBC.HORIZONTAL).anchor(GBC.SOUTH));
     337            panel.add(scroll, GBC.eol().fill(GBC.BOTH).anchor(GBC.CENTER));
     338
     339            queryWizard.setPossibleItems(OVERPASS_WIZARD_HISTORY.get());
     340
     341            setCancelButton(CANCEL);
     342            setDefaultButton(BUILD_AN_EXECUTE_QUERY + 1); // Build and execute button
     343            setContent(panel, false);
     344        }
     345
     346        @Override
     347        public void buttonAction(int buttonIndex, ActionEvent evt) {
     348            switch (buttonIndex) {
     349                case BUILD_QUERY:
     350                    if (this.buildQueryAction()) {
     351                        this.saveHistory();
     352                        super.buttonAction(BUILD_QUERY, evt);
     353                    }
     354                    break;
     355                case BUILD_AN_EXECUTE_QUERY:
     356                    if (this.buildQueryAction()) {
     357                        this.saveHistory();
     358                        super.buttonAction(BUILD_AN_EXECUTE_QUERY, evt);
     359
     360                        OverpassDownloadDialog.getInstance().triggerDownload();
     361                    }
     362                    break;
     363                default:
     364                    super.buttonAction(buttonIndex, evt);
     365
     366            }
     367        }
     368
     369        /**
     370         * Saves the latest, successfully parsed search term.
     371         */
     372        private void saveHistory() {
     373            queryWizard.addCurrentItemToHistory();
     374            OVERPASS_WIZARD_HISTORY.put(queryWizard.getHistory());
     375        }
     376
     377        /**
     378         * Tries to process a search term using {@link OverpassTurboQueryWizard}. If the term cannot
     379         * be parsed, the the corresponding dialog is shown.
     380         * @param searchTerm The search term to parse.
     381         * @return {@link Optional#empty()} if an exception was thrown when parsing, meaning
     382         * that the term cannot be processed, or non-empty {@link Optional} containing the result
     383         * of parsing.
     384         */
     385        private Optional<String> tryParseSearchTerm(String searchTerm) {
     386            try {
     387                String query = this.overpassQueryBuilder.constructQuery(searchTerm);
     388
     389                return Optional.of(query);
     390            } catch (UncheckedParseException ex) {
     391                Main.error(ex);
     392                JOptionPane.showMessageDialog(
     393                        OverpassDownloadDialog.getInstance(),
     394                        "<html>" +
     395                         tr("The Overpass wizard could not parse the following query:") +
     396                         Utils.joinAsHtmlUnorderedList(Collections.singleton(searchTerm)) +
     397                         "</html>",
     398                        tr("Parse error"),
     399                        JOptionPane.ERROR_MESSAGE
     400                );
     401
     402                return Optional.empty();
     403            }
     404        }
     405
     406        /**
     407         * Builds an Overpass query out from {@link QueryWizardDialog#queryWizard} contents.
     408         * @return {@code true} if the query successfully built, {@code false} otherwise.
     409         */
     410        private boolean buildQueryAction() {
     411            final String wizardSearchTerm = this.queryWizard.getText();
     412
     413            Optional<String> q = this.tryParseSearchTerm(wizardSearchTerm);
     414            if (q.isPresent()) {
     415                String query = q.get();
     416                OverpassDownloadDialog.getInstance().setOverpassQuery(query);
     417
     418                return true;
     419            }
     420
     421            return false;
     422        }
     423
     424        private JTextComponent buildDescriptionSection() {
     425            JEditorPane descriptionSection = new JEditorPane("text/html", this.getDescriptionContent());
     426            descriptionSection.setEditable(false);
     427            descriptionSection.addHyperlinkListener(e -> {
     428                if (HyperlinkEvent.EventType.ACTIVATED.equals(e.getEventType())) {
     429                    OpenBrowser.displayUrl(e.getURL().toString());
     430                }
     431            });
     432
     433            return descriptionSection;
     434        }
     435
     436        private String getDescriptionContent() {
     437            return new StringBuilder("<html>")
     438                    .append(DESCRIPTION_STYLE)
     439                    .append("<body>")
     440                    .append("<h3>")
     441                    .append(tr("Query Wizard"))
     442                    .append("</h3>")
     443                    .append("<p>")
     444                    .append(tr("Allows you to interact with <i>Overpass API</i> by writing declarative, human-readable terms."))
     445                    .append(tr("The <i>Query Wizard</i> tool will transform those to a valid overpass query."))
     446                    .append(tr("For more detailed description see "))
     447                    .append(tr("<a href=\"{0}\">OSM Wiki</a>.", Main.getOSMWebsite() + "/wiki/Overpass_turbo/Wizard"))
     448                    .append("</p>")
     449                    .append("<h3>").append(tr("Hints")).append("</h3>")
     450                    .append("<table>").append("<tr>").append("<td>")
     451                    .append(Utils.joinAsHtmlUnorderedList(Arrays.asList("<i>type:node</i>", "<i>type:relation</i>", "<i>type:way</i>")))
     452                    .append("</td>").append("<td>")
     453                    .append("<span>").append(tr("Download objects of a certain type.")).append("</span>")
     454                    .append("</td>").append("</tr>")
     455                    .append("<tr>").append("<td>")
     456                    .append(Utils.joinAsHtmlUnorderedList(
     457                            Arrays.asList("<i>key=value in <u>location</u></i>",
     458                                    "<i>key=value around <u>location</u></i>",
     459                                    "<i>key=value in bbox</i>")))
     460                    .append("</td>").append("<td>")
     461                    .append(tr("Download object by specifying a specific location. For example,"))
     462                    .append(Utils.joinAsHtmlUnorderedList(Arrays.asList(
     463                            tr("{0} all objects having {1} as attribute are downloaded.", "<i>tourism=hotel in Berlin</i> -", "'tourism=hotel'"),
     464                            tr("{0} all object with the corresponding key/value pair located around Berlin. Note, the default value for radius "+
     465                                    "is set to 1000m, but it can be changed in the generated query.", "<i>tourism=hotel around Berlin</i> -"),
     466                            tr("{0} all objects within the current selection that have {1} as attribute.", "<i>tourism=hotel in bbox</i> -",
     467                                    "'tourism=hotel'"))))
     468                    .append("<span>")
     469                    .append(tr("Instead of <i>location</i> any valid place name can be used like address, city, etc."))
     470                    .append("</span>")
     471                    .append("</td>").append("</tr>")
     472                    .append("<tr>").append("<td>")
     473                    .append(Utils.joinAsHtmlUnorderedList(Arrays.asList("<i>key=value</i>", "<i>key=*</i>", "<i>key~regex</i>",
     474                            "<i>key!=value</i>", "<i>key!~regex</i>", "<i>key=\"combined value\"</i>")))
     475                    .append("</td>").append("<td>")
     476                    .append(tr("<span>Download objects that have some concrete key/value pair, only the key with any contents for the value, " +
     477                            "the value matching some regular expression. 'Not equal' operators are supported as well.</span>"))
     478                    .append("</td>").append("</tr>")
     479                    .append("<tr>").append("<td>")
     480                    .append(Utils.joinAsHtmlUnorderedList(Arrays.asList(
     481                            tr("<i>expression1 {0} expression2</i>", "or"),
     482                            tr("<i>expression1 {0} expression2</i>", "and"))))
     483                    .append("</td>").append("<td>")
     484                    .append("<span>")
     485                    .append(tr("Basic logical operators can be used to create more sophisticated queries. Instead of 'or' - '|', '||' " +
     486                            "can be used, and instead of 'and' - '&', '&&'."))
     487                    .append("</span>")
     488                    .append("</td>").append("</tr>").append("</table>")
     489                    .append("</body>")
     490                    .append("</html>")
     491                    .toString();
    261492        }
    262493    }
    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 
    283494}
  • trunk/src/org/openstreetmap/josm/actions/downloadtasks/PostDownloadHandler.java

    r12307 r12574  
    1212import java.util.concurrent.ExecutionException;
    1313import java.util.concurrent.Future;
     14import java.util.function.Consumer;
    1415
    1516import javax.swing.JOptionPane;
     
    2930    private final DownloadTask task;
    3031    private final Future<?> future;
     32    private Consumer<Collection> errorReporter;
    3133
    3234    /**
     
    3840        this.task = task;
    3941        this.future = future;
     42    }
     43
     44    /**
     45     * constructor
     46     * @param task the asynchronous download task
     47     * @param future the future on which the completion of the download task can be synchronized
     48     * @param errorReporter a callback to inform about the number errors happened during the download
     49     *                      task
     50     */
     51    public PostDownloadHandler(DownloadTask task, Future<?> future, Consumer<Collection> errorReporter) {
     52        this(task, future);
     53        this.errorReporter = errorReporter;
    4054    }
    4155
     
    5468        //
    5569        Set<Object> errors = new LinkedHashSet<>(task.getErrorObjects());
    56         if (errors.isEmpty())
     70        if (this.errorReporter != null) {
     71            errorReporter.accept(errors);
     72        }
     73
     74        if (errors.isEmpty()) {
    5775            return;
     76        }
    5877
    5978        // just one error object?
  • trunk/src/org/openstreetmap/josm/gui/download/DownloadDialog.java

    r12523 r12574  
    2020import java.util.ArrayList;
    2121import java.util.List;
     22import java.util.Optional;
    2223
    2324import javax.swing.AbstractAction;
     
    458459
    459460    /**
    460      * Replies the currently selected download area.
    461      * @return the currently selected download area. May be {@code null}, if no download area is selected yet.
    462      */
    463     public Bounds getSelectedDownloadArea() {
    464         return currentBounds;
     461     * Returns an {@link Optional} of the currently selected download area.
     462     * @return An {@link Optional} of the currently selected download area.
     463     * @since 12574 Return type changed to optional
     464     */
     465    public Optional<Bounds> getSelectedDownloadArea() {
     466        return Optional.ofNullable(currentBounds);
    465467    }
    466468
     
    525527
    526528        public void run() {
    527             if (currentBounds == null) {
    528                 JOptionPane.showMessageDialog(
    529                         DownloadDialog.this,
    530                         tr("Please select a download area first."),
    531                         tr("Error"),
    532                         JOptionPane.ERROR_MESSAGE
    533                 );
    534                 return;
    535             }
     529            /*
     530             * Checks if the user selected the type of data to download. At least one the following
     531             * must be chosen : raw osm data, gpx data, notes.
     532             * If none of those are selected, then the corresponding dialog is shown to inform the user.
     533             */
    536534            if (!isDownloadOsmData() && !isDownloadGpxData() && !isDownloadNotes()) {
    537535                JOptionPane.showMessageDialog(
    538536                        DownloadDialog.this,
    539537                        tr("<html>Neither <strong>{0}</strong> nor <strong>{1}</strong> nor <strong>{2}</strong> is enabled.<br>"
    540                                 + "Please choose to either download OSM data, or GPX data, or Notes, or all.</html>",
     538                                        + "Please choose to either download OSM data, or GPX data, or Notes, or all.</html>",
    541539                                cbDownloadOsmData.getText(),
    542540                                cbDownloadGpxData.getText(),
     
    548546                return;
    549547            }
     548
    550549            setCanceled(false);
    551550            setVisible(false);
Note: See TracChangeset for help on using the changeset viewer.