Modify

Opened 7 years ago

Closed 3 years ago

#12037 closed enhancement (wontfix)

[Alpha patch] Feedback on valid/invalid Overpass Turbo queries

Reported by: Don-vip Owned by: team
Priority: normal Milestone:
Component: Core Version:
Keywords: overpass turbo feedback Cc: simon04

Description (last modified by Don-vip)

In the "Download from Overpass" dialog, the first text field allowing to build Overpass queries does not provide real-time feedback on the validity of the query being typed.

I came up with two solutions, but none of them is good enough:

  • the first one calls Overpass Turbo in JavaScript. It's too slow!
  • the second one calls our Search syntax validator. It's fast, but wrong!

Does anyone have a better idea?

Here's my patch:

  • src/org/openstreetmap/josm/actions/OverpassDownloadAction.java

     
    3333import javax.swing.JPopupMenu;
    3434import javax.swing.JScrollPane;
    3535import javax.swing.plaf.basic.BasicArrowButton;
     36import javax.swing.text.JTextComponent;
    3637
    3738import org.openstreetmap.josm.Main;
    3839import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask;
    3940import org.openstreetmap.josm.actions.downloadtasks.PostDownloadHandler;
     41import org.openstreetmap.josm.actions.search.SearchAction.SearchSetting;
     42import org.openstreetmap.josm.actions.search.SearchCompiler;
     43import org.openstreetmap.josm.actions.search.SearchCompiler.ParseError;
    4044import org.openstreetmap.josm.data.Bounds;
    4145import org.openstreetmap.josm.data.preferences.CollectionProperty;
    4246import org.openstreetmap.josm.data.preferences.IntegerProperty;
     
    4448import org.openstreetmap.josm.gui.HelpAwareOptionPane;
    4549import org.openstreetmap.josm.gui.download.DownloadDialog;
    4650import org.openstreetmap.josm.gui.util.GuiHelper;
     51import org.openstreetmap.josm.gui.widgets.AbstractTextComponentValidator;
    4752import org.openstreetmap.josm.gui.widgets.HistoryComboBox;
    4853import org.openstreetmap.josm.gui.widgets.JosmTextArea;
    4954import org.openstreetmap.josm.io.OverpassDownloadReader;
     
    153158            final String tooltip = tr("Builds an Overpass query using the Overpass Turbo query wizard");
    154159            overpassWizard = new HistoryComboBox();
    155160            overpassWizard.setToolTipText(tooltip);
    156             overpassWizard.getEditor().getEditorComponent().addFocusListener(disableActionsFocusListener);
     161            JTextComponent editorComponent = (JTextComponent) overpassWizard.getEditor().getEditorComponent();
     162            editorComponent.addFocusListener(disableActionsFocusListener);
     163            editorComponent.getDocument().addDocumentListener(new AbstractTextComponentValidator(editorComponent) {
     164
     165                @Override
     166                public void validate() {
     167                    if (!isValid()) {
     168                        feedbackInvalid(tr("Invalid Overpass Turbo query"));
     169                    } else {
     170                        feedbackValid(tooltip);
     171                    }
     172                }
     173
     174                @Override
     175                public boolean isValid() {
     176                    // SOLUTION 1: terribly slow
     177                    //return OverpassTurboQueryWizard.getInstance().testQuery(overpassWizard.getText());
     178
     179                    // SOLUTION 2: fast but incorrect
     180                    try {
     181                        SearchSetting ss = new SearchSetting();
     182                        ss.text = overpassWizard.getText();
     183                        SearchCompiler.compile(ss);
     184                        return true;
     185                    } catch (ParseError e) {
     186                        return false;
     187                    }
     188                }
     189            });
    157190            final JButton buildQuery = new JButton(tr("Build query"));
    158191            buildQuery.addActionListener(new AbstractAction() {
    159192                @Override
  • src/org/openstreetmap/josm/tools/OverpassTurboQueryWizard.java

     
    2727    /**
    2828     * An exception to indicate a failed parse.
    2929     */
    30     public static class ParseException extends RuntimeException {
     30    public static class ParseException extends Exception {
     31
     32        /**
     33         * Constructs a new {@code ParseException}.
     34         * @param message the error message
     35         */
     36        public ParseException(String message) {
     37            super(message);
     38        }
    3139    }
    3240
    3341    /**
     
    4452
    4553    private OverpassTurboQueryWizard() {
    4654        // overpass-turbo is MIT Licensed
    47 
    4855        try (final Reader reader = new InputStreamReader(
    4956                getClass().getResourceAsStream("/data/overpass-turbo-ffs.js"), StandardCharsets.UTF_8)) {
    5057            engine.eval("var console = {log: function(){}};");
     
    5562        }
    5663    }
    5764
     65    private Object doConstructQuery(String search) {
     66        try {
     67            return ((Invocable) engine).invokeFunction("construct_query", search);
     68        } catch (NoSuchMethodException e) {
     69            throw new IllegalStateException(e);
     70        } catch (ScriptException e) {
     71            throw new RuntimeException("Failed to execute OverpassTurboQueryWizard", e);
     72        }
     73    }
     74
    5875    /**
    5976     * Builds an Overpass QL from a {@link org.openstreetmap.josm.actions.search.SearchAction} like query.
    6077     * @param search the {@link org.openstreetmap.josm.actions.search.SearchAction} like query
     
    6279     * @throws ParseException when the parsing fails
    6380     */
    6481    public String constructQuery(String search) throws ParseException {
    65         try {
    66             final Object result = ((Invocable) engine).invokeFunction("construct_query", search);
    67             if (result == Boolean.FALSE) {
    68                 throw new ParseException();
    69             }
    70             String query = (String) result;
    71             query = Pattern.compile("^.*\\[out:json\\]", Pattern.DOTALL).matcher(query).replaceFirst("");
    72             query = Pattern.compile("^out.*", Pattern.MULTILINE).matcher(query).replaceAll("out meta;");
    73             query = query.replace("({{bbox}})", "");
    74             return query;
    75         } catch (NoSuchMethodException e) {
    76             throw new IllegalStateException();
    77         } catch (ScriptException e) {
    78             throw new RuntimeException("Failed to execute OverpassTurboQueryWizard", e);
     82        final Object result = doConstructQuery(search);
     83        if (Boolean.FALSE.equals(result)) {
     84            throw new ParseException("Cannot parse: " + search);
    7985        }
     86        String query = (String) result;
     87        query = Pattern.compile("^.*\\[out:json\\]", Pattern.DOTALL).matcher(query).replaceFirst("");
     88        query = Pattern.compile("^out.*", Pattern.MULTILINE).matcher(query).replaceAll("out meta;");
     89        query = query.replace("({{bbox}})", "");
     90        return query;
    8091    }
    8192
     93    /**
     94     * Test validity of an Overpass Turbo query.
     95     * @param search the {@link org.openstreetmap.josm.actions.search.SearchAction} like query
     96     * @return {@code true} if the query is valid
     97     */
     98    public boolean testQuery(String search) {
     99        return !Boolean.FALSE.equals(doConstructQuery(search));
     100    }
    82101}
  • test/unit/org/openstreetmap/josm/tools/OverpassTurboQueryWizardTest.java

     
    66import org.junit.BeforeClass;
    77import org.junit.Test;
    88import org.openstreetmap.josm.JOSMFixture;
     9import org.openstreetmap.josm.tools.OverpassTurboQueryWizard.ParseException;
    910
    1011/**
    1112 * Unit tests of {@link OverpassTurboQueryWizard} class.
     
    2324
    2425    /**
    2526     * Test key=value.
     27     * @throws ParseException in case of invalid syntax
    2628     */
    2729    @Test
    28     public void testKeyValue() {
     30    public void testKeyValue() throws ParseException {
    2931        final String query = OverpassTurboQueryWizard.getInstance().constructQuery("amenity=drinking_water");
    3032        assertEquals("" +
    3133                "[timeout:25];\n" +
     
    4446
    4547    /**
    4648     * Test erroneous value.
     49     * @throws ParseException in case of invalid syntax
    4750     */
    48     @Test(expected = OverpassTurboQueryWizard.ParseException.class)
    49     public void testErroneous() {
     51    @Test(expected = ParseException.class)
     52    public void testErroneous() throws ParseException {
    5053        OverpassTurboQueryWizard.getInstance().constructQuery("foo");
    5154    }
    5255}

Attachments (0)

Change History (2)

comment:1 Changed 7 years ago by Don-vip

Description: modified (diff)

comment:2 Changed 3 years ago by simon04

Resolution: wontfix
Status: newclosed

Obsolete due to #18164 / r16262.

Modify Ticket

Change Properties
Set your email in Preferences
Action
as closed The owner will remain team.
as The resolution will be set.
The resolution will be deleted.

Add Comment


E-mail address and name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.