Modify ↓
Opened 10 years ago
Closed 5 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 )
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
33 33 import javax.swing.JPopupMenu; 34 34 import javax.swing.JScrollPane; 35 35 import javax.swing.plaf.basic.BasicArrowButton; 36 import javax.swing.text.JTextComponent; 36 37 37 38 import org.openstreetmap.josm.Main; 38 39 import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask; 39 40 import org.openstreetmap.josm.actions.downloadtasks.PostDownloadHandler; 41 import org.openstreetmap.josm.actions.search.SearchAction.SearchSetting; 42 import org.openstreetmap.josm.actions.search.SearchCompiler; 43 import org.openstreetmap.josm.actions.search.SearchCompiler.ParseError; 40 44 import org.openstreetmap.josm.data.Bounds; 41 45 import org.openstreetmap.josm.data.preferences.CollectionProperty; 42 46 import org.openstreetmap.josm.data.preferences.IntegerProperty; … … 44 48 import org.openstreetmap.josm.gui.HelpAwareOptionPane; 45 49 import org.openstreetmap.josm.gui.download.DownloadDialog; 46 50 import org.openstreetmap.josm.gui.util.GuiHelper; 51 import org.openstreetmap.josm.gui.widgets.AbstractTextComponentValidator; 47 52 import org.openstreetmap.josm.gui.widgets.HistoryComboBox; 48 53 import org.openstreetmap.josm.gui.widgets.JosmTextArea; 49 54 import org.openstreetmap.josm.io.OverpassDownloadReader; … … 153 158 final String tooltip = tr("Builds an Overpass query using the Overpass Turbo query wizard"); 154 159 overpassWizard = new HistoryComboBox(); 155 160 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 }); 157 190 final JButton buildQuery = new JButton(tr("Build query")); 158 191 buildQuery.addActionListener(new AbstractAction() { 159 192 @Override -
src/org/openstreetmap/josm/tools/OverpassTurboQueryWizard.java
27 27 /** 28 28 * An exception to indicate a failed parse. 29 29 */ 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 } 31 39 } 32 40 33 41 /** … … 44 52 45 53 private OverpassTurboQueryWizard() { 46 54 // overpass-turbo is MIT Licensed 47 48 55 try (final Reader reader = new InputStreamReader( 49 56 getClass().getResourceAsStream("/data/overpass-turbo-ffs.js"), StandardCharsets.UTF_8)) { 50 57 engine.eval("var console = {log: function(){}};"); … … 55 62 } 56 63 } 57 64 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 58 75 /** 59 76 * Builds an Overpass QL from a {@link org.openstreetmap.josm.actions.search.SearchAction} like query. 60 77 * @param search the {@link org.openstreetmap.josm.actions.search.SearchAction} like query … … 62 79 * @throws ParseException when the parsing fails 63 80 */ 64 81 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); 79 85 } 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; 80 91 } 81 92 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 } 82 101 } -
test/unit/org/openstreetmap/josm/tools/OverpassTurboQueryWizardTest.java
6 6 import org.junit.BeforeClass; 7 7 import org.junit.Test; 8 8 import org.openstreetmap.josm.JOSMFixture; 9 import org.openstreetmap.josm.tools.OverpassTurboQueryWizard.ParseException; 9 10 10 11 /** 11 12 * Unit tests of {@link OverpassTurboQueryWizard} class. … … 23 24 24 25 /** 25 26 * Test key=value. 27 * @throws ParseException in case of invalid syntax 26 28 */ 27 29 @Test 28 public void testKeyValue() {30 public void testKeyValue() throws ParseException { 29 31 final String query = OverpassTurboQueryWizard.getInstance().constructQuery("amenity=drinking_water"); 30 32 assertEquals("" + 31 33 "[timeout:25];\n" + … … 44 46 45 47 /** 46 48 * Test erroneous value. 49 * @throws ParseException in case of invalid syntax 47 50 */ 48 @Test(expected = OverpassTurboQueryWizard.ParseException.class)49 public void testErroneous() {51 @Test(expected = ParseException.class) 52 public void testErroneous() throws ParseException { 50 53 OverpassTurboQueryWizard.getInstance().constructQuery("foo"); 51 54 } 52 55 }
Attachments (0)
Change History (2)
comment:1 by , 9 years ago
Description: | modified (diff) |
---|
comment:2 by , 5 years ago
Resolution: | → wontfix |
---|---|
Status: | new → closed |
Note:
See TracTickets
for help on using tickets.
Obsolete due to #18164 / r16262.