Changeset 12574 in josm for trunk/src/org/openstreetmap/josm/actions/OverpassDownloadAction.java
- Timestamp:
- 2017-08-06T20:13:06+02:00 (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/actions/OverpassDownloadAction.java
r11658 r12574 7 7 import java.awt.BorderLayout; 8 8 import java.awt.Component; 9 import java.awt. GridLayout;10 import java.awt. Rectangle;9 import java.awt.Dimension; 10 import java.awt.GridBagLayout; 11 11 import java.awt.event.ActionEvent; 12 import java.awt.event.ActionListener;13 12 import java.awt.event.FocusEvent; 14 13 import java.awt.event.FocusListener; 15 14 import java.awt.event.KeyEvent; 16 15 import java.util.ArrayList; 16 import java.util.Arrays; 17 17 import java.util.Collection; 18 18 import java.util.Collections; 19 import java.util.Deque; 20 import java.util.LinkedList; 19 import java.util.Optional; 21 20 import java.util.concurrent.Future; 21 import java.util.function.Consumer; 22 22 23 23 import javax.swing.AbstractAction; … … 25 25 import javax.swing.ActionMap; 26 26 import javax.swing.JButton; 27 import javax.swing.J Component;27 import javax.swing.JEditorPane; 28 28 import javax.swing.JLabel; 29 import javax.swing.JMenuItem;30 29 import javax.swing.JOptionPane; 31 30 import javax.swing.JPanel; 32 import javax.swing.JPopupMenu;33 31 import javax.swing.JScrollPane; 32 import javax.swing.event.HyperlinkEvent; 34 33 import javax.swing.plaf.basic.BasicArrowButton; 34 import javax.swing.text.JTextComponent; 35 35 36 36 import org.openstreetmap.josm.Main; … … 38 38 import org.openstreetmap.josm.actions.downloadtasks.PostDownloadHandler; 39 39 import org.openstreetmap.josm.data.Bounds; 40 import org.openstreetmap.josm.data.preferences.BooleanProperty; 40 41 import org.openstreetmap.josm.data.preferences.CollectionProperty; 41 import org.openstreetmap.josm.data.preferences.IntegerProperty; 42 import org.openstreetmap.josm.gui.HelpAwareOptionPane; 42 import org.openstreetmap.josm.gui.ExtendedDialog; 43 43 import org.openstreetmap.josm.gui.download.DownloadDialog; 44 import org.openstreetmap.josm.gui.download.OverpassQueryList; 44 45 import org.openstreetmap.josm.gui.preferences.server.OverpassServerPreference; 45 46 import org.openstreetmap.josm.gui.util.GuiHelper; … … 48 49 import org.openstreetmap.josm.io.OverpassDownloadReader; 49 50 import org.openstreetmap.josm.tools.GBC; 50 import org.openstreetmap.josm.tools. InputMapUtils;51 import org.openstreetmap.josm.tools.OpenBrowser; 51 52 import org.openstreetmap.josm.tools.OverpassTurboQueryWizard; 52 53 import org.openstreetmap.josm.tools.Shortcut; … … 77 78 dialog.restoreSettings(); 78 79 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)); 89 129 } 90 130 … … 122 162 private static final class OverpassDownloadDialog extends DownloadDialog { 123 163 124 private HistoryComboBox overpassWizard;125 164 private JosmTextArea overpassQuery; 165 private OverpassQueryList overpassQueryList; 126 166 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); 129 169 130 170 private OverpassDownloadDialog(Component parent) { … … 146 186 @Override 147 187 protected void buildMainPanelAboveDownloadSelections(JPanel pnl) { 188 // needed for the invisible checkboxes cbDownloadGpxData, cbDownloadNotes 189 pnl.add(new JLabel(), GBC.eol()); 148 190 149 191 DisableActionsFocusListener disableActionsFocusListener = 150 192 new DisableActionsFocusListener(slippyMapChooser.getNavigationComponentActionMap()); 151 193 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() { 160 196 @Override 161 197 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(); 176 199 } 177 200 }; 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)); 187 231 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); 194 244 } 195 245 }); 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)); 201 257 pnl.add(pane, gbc); 202 203 } 204 205 public String getOverpassQuery() { 258 } 259 260 String getOverpassQuery() { 206 261 return overpassQuery.getText(); 207 262 } 208 263 209 publicvoid setOverpassQuery(String text) {264 void setOverpassQuery(String text) { 210 265 overpassQuery.setText(text); 211 266 } 212 267 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()); 225 273 } 226 274 … … 229 277 displaySizeCheckResult(false); 230 278 } 279 280 /** 281 * Triggers the download action to fire. 282 */ 283 private void triggerDownload() { 284 super.btnDownload.doClick(); 285 } 231 286 } 232 287 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(); 261 492 } 262 493 } 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 @Override278 public void actionPerformed(ActionEvent e) {279 dialog.setOverpassQuery(query);280 }281 }282 283 494 }
Note:
See TracChangeset
for help on using the changeset viewer.