Ticket #7928: josm-overpass-downloadselection.patch

File josm-overpass-downloadselection.patch, 15.1 KB (added by cmuelle8, 13 years ago)

add an Overpass DownloadSelection to JOSM

  • src/org/openstreetmap/josm/gui/download/OverpassSelection.java

     
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.gui.download;
     3
     4import static org.openstreetmap.josm.tools.I18n.tr;
     5
     6import java.awt.BorderLayout;
     7import java.awt.FlowLayout;
     8import java.awt.event.ActionEvent;
     9import java.awt.event.ActionListener;
     10import java.awt.event.ComponentAdapter;
     11import java.awt.event.ComponentEvent;
     12import java.beans.PropertyChangeEvent;
     13import java.beans.PropertyChangeListener;
     14import java.util.Collections;
     15import java.util.LinkedList;
     16import java.util.List;
     17
     18import javax.swing.ButtonGroup;
     19import javax.swing.JCheckBox;
     20import javax.swing.JComboBox;
     21import javax.swing.JPanel;
     22import javax.swing.JRadioButton;
     23
     24import org.openstreetmap.josm.Main;
     25import org.openstreetmap.josm.data.Bounds;
     26import org.openstreetmap.josm.gui.bbox.BBoxChooser;
     27import org.openstreetmap.josm.gui.bbox.SlippyMapBBoxChooser;
     28import org.openstreetmap.josm.gui.widgets.HistoryComboBox;
     29
     30
     31public class OverpassSelection implements DownloadSelection {
     32    private DownloadDialog parent;
     33    private Bounds area;
     34
     35    private final JRadioButton cNodes = new JRadioButton(tr("Nodes"));
     36    private final JRadioButton cWays = new JRadioButton(tr("Ways"));
     37    private final JRadioButton cRels = new JRadioButton(tr("Relations"));
     38    private final JCheckBox cBackwards = new JCheckBox(tr("Backward"));
     39    private static final Server[] servers = new Server[]{
     40        new Server("Overpass Production Server", "http://overpass.osm.rambler.ru/cgi/interpreter?data="),
     41        new Server("Overpass Dev Server", "http://www.overpass-api.de/api/interpreter?data="),
     42    };
     43    private final JComboBox cbServer = new JComboBox(servers);
     44    private final ActionListener al = new ActionListener() {
     45        @Override
     46        public void actionPerformed(ActionEvent e) {
     47            Object o = e.getSource();
     48            if (o.equals(cNodes) || o.equals(cWays)) {
     49                cBackwards.setSelected(true);
     50            } else if (o.equals(cRels)) {
     51                cBackwards.setSelected(false);
     52            }
     53
     54            cbOverpassURL.setText(getURL());
     55        }
     56    };
     57
     58    private final SlippyMapBBoxChooser nestedSlippyMap = new SlippyMapBBoxChooser();
     59    private static final String HISTORY_FILTER = "download.overpass.filter.history";
     60
     61    private static final String HISTORY_URL = "download.overpass.history";
     62    private HistoryComboBox cbOverpassFilter;
     63    private HistoryComboBox cbOverpassURL;
     64
     65
     66    /**
     67     * Adds a new tab to the download dialog in JOSM.
     68     *
     69     * This method is, for all intents and purposes, the constructor for this class.
     70     */
     71    public void addGui(final DownloadDialog gui) {
     72        parent = gui;
     73
     74
     75        // north
     76        cNodes.addActionListener(al);
     77        cWays.addActionListener(al);
     78        cRels.addActionListener(al);
     79        cBackwards.addActionListener(al);
     80        cbServer.addActionListener(al);
     81
     82        ButtonGroup rbGroup = new ButtonGroup();
     83        rbGroup.add(cNodes);
     84        rbGroup.add(cWays);
     85        rbGroup.add(cRels);
     86
     87        JPanel northPane = new JPanel(new FlowLayout());
     88        northPane.add(cNodes);
     89        northPane.add(cWays);
     90        northPane.add(cRels);
     91        northPane.add(cBackwards);
     92        northPane.add(cbServer);
     93
     94        cNodes.setSelected(true);
     95        cBackwards.setSelected(true);
     96        cBackwards.setToolTipText(tr("BE CAREFUL! You will get incomplete DataSets disabling this!"));
     97
     98
     99        // center
     100        //JPanel posFilter = new JPanel(new BorderLayout());
     101        //JPanel negFilter = new JPanel(new BorderLayout());
     102        //JSplitPane centerPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, posFilter, negFilter);
     103
     104        /* TODO use TaggingPreset Dialog to add filter presets, currently it needs a valid DataSet though */
     105        /* -intermediate-solution------------------ */
     106        nestedSlippyMap.addPropertyChangeListener(new PropertyChangeListener() {
     107            @Override
     108            public void propertyChange(PropertyChangeEvent e) {
     109                if (e.getPropertyName().equals(BBoxChooser.BBOX_PROP)) {
     110                    parent.boundingBoxChanged((Bounds)e.getNewValue(), OverpassSelection.this);
     111                    OverpassSelection.this.area = new Bounds((Bounds)e.getNewValue());
     112                    cbOverpassURL.setText(getURL());
     113                }
     114            }
     115        });
     116        cbOverpassFilter = new HistoryComboBox();
     117        cbOverpassFilter.setToolTipText(tr("QL filter, e.g. " +
     118                "\n[\"route\"=\"bicycle\"] or [\"route\"!=\"bicycle\"] or "+
     119                "\n[\"route\"~\".*cycle\"] or [\"key\"!~\".*cycle\"]"+
     120                "\nConcatenations of filters are AND'd, e.g. [\"highway\"=\"trunk\"][\"ref\"=\"B 2\"]"));
     121        List<String> hist_OF = new LinkedList<String>(Main.pref.getCollection(HISTORY_FILTER, new LinkedList<String>()));
     122        Collections.reverse(hist_OF);
     123        if (hist_OF.isEmpty()) {
     124            hist_OF.add("[\"amenity\"=\"recycling\"]");
     125            hist_OF.add("[\"type\"=\"route\"][\"route\"=\"bicycle\"]");
     126            hist_OF.add("[\"highway\"=\"bus_stop\"][\"shelter\"][\"shelter\"!=\"no\"]");
     127            hist_OF.add("[\"name\"~\"Leipzig|Köln\"]");
     128        }
     129        cbOverpassFilter.setPossibleItems(hist_OF);
     130        cbOverpassFilter.addActionListener(al);
     131        JPanel centerPane = new JPanel(new BorderLayout());
     132        centerPane.add(nestedSlippyMap, BorderLayout.CENTER);
     133        centerPane.add(cbOverpassFilter, BorderLayout.SOUTH);
     134        /* ---------------------------------------- */
     135
     136
     137        // south
     138        cbOverpassURL = new HistoryComboBox();
     139        cbOverpassURL.setToolTipText(tr("enter a valid Overpass QL URL"));
     140        List<String> hist_OU = new LinkedList<String>(Main.pref.getCollection(HISTORY_URL, new LinkedList<String>()));
     141        Collections.reverse(hist_OU);
     142        cbOverpassURL.setPossibleItems(hist_OU);
     143        cbOverpassURL.addActionListener(new ActionListener() {
     144
     145            @Override
     146            public void actionPerformed(ActionEvent e) {
     147                String s = cbOverpassURL.getText();
     148                String bbox = s.replaceAll("^.*(.*?).*$", "\1");
     149                System.out.println(bbox);
     150
     151                if ("comboBoxEdited".equals(e.getActionCommand())) {
     152                }
     153                //parent.boundingBoxChanged(area, OverpassSelection.this);
     154                //al.actionPerformed(e);
     155            }
     156        });
     157
     158
     159        // assemble border layout panel
     160        JPanel panel = new JPanel();
     161        panel.setLayout(new BorderLayout());
     162        panel.add(northPane, BorderLayout.NORTH);
     163        panel.add(centerPane, BorderLayout.CENTER);
     164        panel.add(cbOverpassURL, BorderLayout.SOUTH);
     165
     166
     167        // add ourselves as tab to the download dialog
     168        parent.addDownloadAreaSelector(panel, tr("Overpass Filter"));
     169        parent.addComponentListener(new ComponentAdapter() {
     170            @Override
     171            public void componentHidden(ComponentEvent e) {
     172                if (!((DownloadDialog)e.getSource()).isCanceled()) {
     173                    cbOverpassFilter.addCurrentItemToHistory();
     174                    cbOverpassURL.addCurrentItemToHistory();
     175                    Main.pref.putCollection(HISTORY_FILTER, cbOverpassFilter.getHistory());
     176                    Main.pref.putCollection(HISTORY_URL, cbOverpassURL.getHistory());
     177                }
     178            }
     179        });
     180
     181        centerPane.setPreferredSize(centerPane.getPreferredSize());
     182        centerPane.repaint();
     183    }
     184
     185    public void setDownloadArea(Bounds area) {
     186        this.area = new Bounds(area);
     187        nestedSlippyMap.setBoundingBox(area);
     188        cbOverpassURL.setText(getURL());
     189    }
     190
     191    public String getOverpassURL() {
     192        return !isValidURL() ? "" : cbOverpassURL.getText();
     193    }
     194
     195    private boolean isValidURL() {
     196        // TODO find a regex to check the QL query..
     197        return cbOverpassURL.getText().matches(".*");
     198    }
     199
     200    private String getURL() {
     201        Server srv = (Server) cbServer.getSelectedItem();
     202
     203        return srv.url +
     204                "[timeout:600];(" +
     205                (cNodes.isSelected() ? "node" + getFilter() + getBounds() : "") +
     206                (cWays.isSelected() ? "way" + getFilter() + getBounds() : "") +
     207                (cRels.isSelected() ? "rel" + getFilter() + getBounds() : "") +
     208                ");" +
     209
     210                (cWays.isSelected() ? "(._;node(w););" : "") +
     211                (cRels.isSelected() ? "(._;node(r)->.x;way(r);node(w););" : "") +
     212
     213                (cBackwards.isSelected() && cNodes.isSelected() ? "(._;way(bn);node(w););" : "") +
     214                (cBackwards.isSelected() ? "(._;rel(bn)->.x;rel(bw););" : "") +
     215
     216                "out meta;";
     217    }
     218
     219    private boolean isValidFilter() {
     220        // TODO check filter query for correctness..
     221        //return cbOverpassFilter.getText().matches("(\\[\".\\+\\?\"!?[=~]\".\\+\\?\"\\])\\+");
     222        return true;
     223    }
     224
     225    private String getFilter() {
     226        return !isValidFilter() ? "" : cbOverpassFilter.getText();
     227    }
     228
     229    private String getBounds() {
     230        return "(" + area.encodeAsString(",") + ");";
     231    }
     232
     233    private static class Server {
     234        public String name;
     235        public String url;
     236
     237        public Server(String n, String u) {
     238            name = n;
     239            url = u;
     240        }
     241
     242        @Override
     243        public String toString() {
     244            return name;
     245        }
     246    }
     247}
  • src/org/openstreetmap/josm/gui/download/DownloadDialog.java

     
    7575
    7676    protected JCheckBox cbDownloadOsmData;
    7777    protected JCheckBox cbDownloadGpxData;
     78
    7879    /** the download action and button */
    7980    private DownloadAction actDownload;
    8081    protected SideButton btnDownload;
     
    106107        downloadSelections.add(new BoundingBoxSelection());
    107108        downloadSelections.add(new PlaceSelection());
    108109        downloadSelections.add(new TileSelection());
     110        if (ExpertToggleAction.isExpert()) {
     111            downloadSelections.add(new OverpassSelection());
     112        }
    109113
    110114        // add selections from plugins
    111115        PluginHandler.addDownloadSelection(downloadSelections);
     
    152156    }
    153157
    154158    /* This should not be necessary, but if not here, repaint is not always correct in SlippyMap! */
     159    @Override
    155160    public void paint(Graphics g) {
    156161        tpDownloadAreaSelectors.getSelectedComponent().paint(g);
    157162        super.paint(g);
     
    199204        getRootPane().getActionMap().put("checkClipboardContents", new AbstractAction() {
    200205            public void actionPerformed(ActionEvent e) {
    201206                String clip = Utils.getClipboardContent();
    202                 if (clip == null) {
     207                if (clip == null)
    203208                    return;
    204                 }
    205209                Bounds b = OsmUrlToBounds.parse(clip);
    206210                if (b != null) {
    207211                    boundingBoxChanged(new Bounds(b), null);
     
    355359        return currentBounds;
    356360    }
    357361
     362    public String getSelectedURL() {
     363        for (DownloadSelection s : downloadSelections) {
     364            if (s instanceof OverpassSelection)
     365                return ((OverpassSelection)s).getOverpassURL();
     366        }
     367
     368        return "";
     369    }
     370
    358371    @Override
    359372    public void setVisible(boolean visible) {
    360373        if (visible) {
  • src/org/openstreetmap/josm/actions/DownloadAction.java

     
    3838        if (! dialog.isCanceled()) {
    3939            dialog.rememberSettings();
    4040            Bounds area = dialog.getSelectedDownloadArea();
     41            String url = dialog.getSelectedURL();
     42
    4143            if (dialog.isDownloadOsmData()) {
    4244                DownloadOsmTask task = new DownloadOsmTask();
    43                 Future<?> future = task.download(dialog.isNewLayerRequired(), area, null);
     45                Future<?> future;
     46                if (!url.isEmpty()) {
     47                    future = task.loadUrl(dialog.isNewLayerRequired(), url, null);
     48                } else {
     49                    future = task.download(dialog.isNewLayerRequired(), area, null);
     50                }
    4451                Main.worker.submit(new PostDownloadHandler(task, future));
    4552            }
    4653            if (dialog.isDownloadGpxData()) {
  • src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTask.java

     
    1515import java.util.regex.Pattern;
    1616
    1717import javax.swing.JOptionPane;
     18
    1819import org.openstreetmap.josm.Main;
    1920import org.openstreetmap.josm.data.Bounds;
    2021import org.openstreetmap.josm.data.coor.LatLon;
     
    8182     * @param url The URL as String
    8283     */
    8384    public Future<?> loadUrl(boolean new_layer, String url, ProgressMonitor progressMonitor) {
    84         downloadTask = new DownloadTask(new_layer,
     85        return loadUrl(new_layer, null, url, progressMonitor);
     86    }
     87
     88    public Future<?> loadUrl(boolean new_layer, Bounds downloadArea, String url, ProgressMonitor progressMonitor) {
     89        this.downloadTask = new DownloadTask(new_layer,
    8590                new OsmServerLocationReader(url),
    8691                progressMonitor);
    87         currentBounds = null;
     92        this.currentBounds = (downloadArea != null ? new Bounds(downloadArea) : null);
    8893        // Extract .osm filename from URL to set the new layer name
    8994        extractOsmFilename("http://.*/(.*\\.osm)", url);
    9095        return Main.worker.submit(downloadTask);
     
    248253        }
    249254
    250255        protected void suggestImageryLayers() {
     256            if (currentBounds == null)
     257                return;
     258
    251259            final LatLon center = currentBounds.getCenter();
    252260            final Set<ImageryInfo> layers = new HashSet<ImageryInfo>();
    253261
     
    272280                }
    273281            }
    274282
    275             if (layers.isEmpty()) {
     283            if (layers.isEmpty())
    276284                return;
    277             }
    278285
    279286            final List<String> layerNames = new ArrayList<String>();
    280287            for (ImageryInfo i : layers) {
     
    291298                    tr("Add imagery layers?"),
    292299                    JOptionPane.YES_NO_OPTION,
    293300                    JOptionPane.QUESTION_MESSAGE,
    294                     JOptionPane.YES_OPTION)) {
     301                            JOptionPane.YES_OPTION))
    295302                return;
    296             }
    297303
    298304            ImageryLayerInfo.addLayers(layers);
    299305        }