Index: src/org/openstreetmap/josm/gui/download/OverpassSelection.java
===================================================================
--- src/org/openstreetmap/josm/gui/download/OverpassSelection.java	(revision 0)
+++ src/org/openstreetmap/josm/gui/download/OverpassSelection.java	(working copy)
@@ -0,0 +1,247 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.download;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.BorderLayout;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.swing.ButtonGroup;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.gui.bbox.BBoxChooser;
+import org.openstreetmap.josm.gui.bbox.SlippyMapBBoxChooser;
+import org.openstreetmap.josm.gui.widgets.HistoryComboBox;
+
+
+public class OverpassSelection implements DownloadSelection {
+    private DownloadDialog parent;
+    private Bounds area;
+
+    private final JRadioButton cNodes = new JRadioButton(tr("Nodes"));
+    private final JRadioButton cWays = new JRadioButton(tr("Ways"));
+    private final JRadioButton cRels = new JRadioButton(tr("Relations"));
+    private final JCheckBox cBackwards = new JCheckBox(tr("Backward"));
+    private static final Server[] servers = new Server[]{
+        new Server("Overpass Production Server", "http://overpass.osm.rambler.ru/cgi/interpreter?data="),
+        new Server("Overpass Dev Server", "http://www.overpass-api.de/api/interpreter?data="),
+    };
+    private final JComboBox cbServer = new JComboBox(servers);
+    private final ActionListener al = new ActionListener() {
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            Object o = e.getSource();
+            if (o.equals(cNodes) || o.equals(cWays)) {
+                cBackwards.setSelected(true);
+            } else if (o.equals(cRels)) {
+                cBackwards.setSelected(false);
+            }
+
+            cbOverpassURL.setText(getURL());
+        }
+    };
+
+    private final SlippyMapBBoxChooser nestedSlippyMap = new SlippyMapBBoxChooser();
+    private static final String HISTORY_FILTER = "download.overpass.filter.history";
+
+    private static final String HISTORY_URL = "download.overpass.history";
+    private HistoryComboBox cbOverpassFilter;
+    private HistoryComboBox cbOverpassURL;
+
+
+    /**
+     * Adds a new tab to the download dialog in JOSM.
+     *
+     * This method is, for all intents and purposes, the constructor for this class.
+     */
+    public void addGui(final DownloadDialog gui) {
+        parent = gui;
+
+
+        // north
+        cNodes.addActionListener(al);
+        cWays.addActionListener(al);
+        cRels.addActionListener(al);
+        cBackwards.addActionListener(al);
+        cbServer.addActionListener(al);
+
+        ButtonGroup rbGroup = new ButtonGroup();
+        rbGroup.add(cNodes);
+        rbGroup.add(cWays);
+        rbGroup.add(cRels);
+
+        JPanel northPane = new JPanel(new FlowLayout());
+        northPane.add(cNodes);
+        northPane.add(cWays);
+        northPane.add(cRels);
+        northPane.add(cBackwards);
+        northPane.add(cbServer);
+
+        cNodes.setSelected(true);
+        cBackwards.setSelected(true);
+        cBackwards.setToolTipText(tr("BE CAREFUL! You will get incomplete DataSets disabling this!"));
+
+
+        // center
+        //JPanel posFilter = new JPanel(new BorderLayout());
+        //JPanel negFilter = new JPanel(new BorderLayout());
+        //JSplitPane centerPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, posFilter, negFilter);
+
+        /* TODO use TaggingPreset Dialog to add filter presets, currently it needs a valid DataSet though */
+        /* -intermediate-solution------------------ */
+        nestedSlippyMap.addPropertyChangeListener(new PropertyChangeListener() {
+            @Override
+            public void propertyChange(PropertyChangeEvent e) {
+                if (e.getPropertyName().equals(BBoxChooser.BBOX_PROP)) {
+                    parent.boundingBoxChanged((Bounds)e.getNewValue(), OverpassSelection.this);
+                    OverpassSelection.this.area = new Bounds((Bounds)e.getNewValue());
+                    cbOverpassURL.setText(getURL());
+                }
+            }
+        });
+        cbOverpassFilter = new HistoryComboBox();
+        cbOverpassFilter.setToolTipText(tr("QL filter, e.g. " +
+                "\n[\"route\"=\"bicycle\"] or [\"route\"!=\"bicycle\"] or "+
+                "\n[\"route\"~\".*cycle\"] or [\"key\"!~\".*cycle\"]"+
+                "\nConcatenations of filters are AND'd, e.g. [\"highway\"=\"trunk\"][\"ref\"=\"B 2\"]"));
+        List<String> hist_OF = new LinkedList<String>(Main.pref.getCollection(HISTORY_FILTER, new LinkedList<String>()));
+        Collections.reverse(hist_OF);
+        if (hist_OF.isEmpty()) {
+            hist_OF.add("[\"amenity\"=\"recycling\"]");
+            hist_OF.add("[\"type\"=\"route\"][\"route\"=\"bicycle\"]");
+            hist_OF.add("[\"highway\"=\"bus_stop\"][\"shelter\"][\"shelter\"!=\"no\"]");
+            hist_OF.add("[\"name\"~\"Leipzig|Köln\"]");
+        }
+        cbOverpassFilter.setPossibleItems(hist_OF);
+        cbOverpassFilter.addActionListener(al);
+        JPanel centerPane = new JPanel(new BorderLayout());
+        centerPane.add(nestedSlippyMap, BorderLayout.CENTER);
+        centerPane.add(cbOverpassFilter, BorderLayout.SOUTH);
+        /* ---------------------------------------- */
+
+
+        // south
+        cbOverpassURL = new HistoryComboBox();
+        cbOverpassURL.setToolTipText(tr("enter a valid Overpass QL URL"));
+        List<String> hist_OU = new LinkedList<String>(Main.pref.getCollection(HISTORY_URL, new LinkedList<String>()));
+        Collections.reverse(hist_OU);
+        cbOverpassURL.setPossibleItems(hist_OU);
+        cbOverpassURL.addActionListener(new ActionListener() {
+
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                String s = cbOverpassURL.getText();
+                String bbox = s.replaceAll("^.*(.*?).*$", "\1");
+                System.out.println(bbox);
+
+                if ("comboBoxEdited".equals(e.getActionCommand())) {
+                }
+                //parent.boundingBoxChanged(area, OverpassSelection.this);
+                //al.actionPerformed(e);
+            }
+        });
+
+
+        // assemble border layout panel
+        JPanel panel = new JPanel();
+        panel.setLayout(new BorderLayout());
+        panel.add(northPane, BorderLayout.NORTH);
+        panel.add(centerPane, BorderLayout.CENTER);
+        panel.add(cbOverpassURL, BorderLayout.SOUTH);
+
+
+        // add ourselves as tab to the download dialog
+        parent.addDownloadAreaSelector(panel, tr("Overpass Filter"));
+        parent.addComponentListener(new ComponentAdapter() {
+            @Override
+            public void componentHidden(ComponentEvent e) {
+                if (!((DownloadDialog)e.getSource()).isCanceled()) {
+                    cbOverpassFilter.addCurrentItemToHistory();
+                    cbOverpassURL.addCurrentItemToHistory();
+                    Main.pref.putCollection(HISTORY_FILTER, cbOverpassFilter.getHistory());
+                    Main.pref.putCollection(HISTORY_URL, cbOverpassURL.getHistory());
+                }
+            }
+        });
+
+        centerPane.setPreferredSize(centerPane.getPreferredSize());
+        centerPane.repaint();
+    }
+
+    public void setDownloadArea(Bounds area) {
+        this.area = new Bounds(area);
+        nestedSlippyMap.setBoundingBox(area);
+        cbOverpassURL.setText(getURL());
+    }
+
+    public String getOverpassURL() {
+        return !isValidURL() ? "" : cbOverpassURL.getText();
+    }
+
+    private boolean isValidURL() {
+        // TODO find a regex to check the QL query..
+        return cbOverpassURL.getText().matches(".*");
+    }
+
+    private String getURL() {
+        Server srv = (Server) cbServer.getSelectedItem();
+
+        return srv.url +
+                "[timeout:600];(" +
+                (cNodes.isSelected() ? "node" + getFilter() + getBounds() : "") +
+                (cWays.isSelected() ? "way" + getFilter() + getBounds() : "") +
+                (cRels.isSelected() ? "rel" + getFilter() + getBounds() : "") +
+                ");" +
+
+                (cWays.isSelected() ? "(._;node(w););" : "") +
+                (cRels.isSelected() ? "(._;node(r)->.x;way(r);node(w););" : "") +
+
+                (cBackwards.isSelected() && cNodes.isSelected() ? "(._;way(bn);node(w););" : "") +
+                (cBackwards.isSelected() ? "(._;rel(bn)->.x;rel(bw););" : "") +
+
+                "out meta;";
+    }
+
+    private boolean isValidFilter() {
+        // TODO check filter query for correctness..
+        //return cbOverpassFilter.getText().matches("(\\[\".\\+\\?\"!?[=~]\".\\+\\?\"\\])\\+");
+        return true;
+    }
+
+    private String getFilter() {
+        return !isValidFilter() ? "" : cbOverpassFilter.getText();
+    }
+
+    private String getBounds() {
+        return "(" + area.encodeAsString(",") + ");";
+    }
+
+    private static class Server {
+        public String name;
+        public String url;
+
+        public Server(String n, String u) {
+            name = n;
+            url = u;
+        }
+
+        @Override
+        public String toString() {
+            return name;
+        }
+    }
+}
Index: src/org/openstreetmap/josm/gui/download/DownloadDialog.java
===================================================================
--- src/org/openstreetmap/josm/gui/download/DownloadDialog.java	(revision 5389)
+++ src/org/openstreetmap/josm/gui/download/DownloadDialog.java	(working copy)
@@ -75,6 +75,7 @@

     protected JCheckBox cbDownloadOsmData;
     protected JCheckBox cbDownloadGpxData;
+
     /** the download action and button */
     private DownloadAction actDownload;
     protected SideButton btnDownload;
@@ -106,6 +107,9 @@
         downloadSelections.add(new BoundingBoxSelection());
         downloadSelections.add(new PlaceSelection());
         downloadSelections.add(new TileSelection());
+        if (ExpertToggleAction.isExpert()) {
+            downloadSelections.add(new OverpassSelection());
+        }

         // add selections from plugins
         PluginHandler.addDownloadSelection(downloadSelections);
@@ -152,6 +156,7 @@
     }

     /* This should not be necessary, but if not here, repaint is not always correct in SlippyMap! */
+    @Override
     public void paint(Graphics g) {
         tpDownloadAreaSelectors.getSelectedComponent().paint(g);
         super.paint(g);
@@ -199,9 +204,8 @@
         getRootPane().getActionMap().put("checkClipboardContents", new AbstractAction() {
             public void actionPerformed(ActionEvent e) {
                 String clip = Utils.getClipboardContent();
-                if (clip == null) {
+                if (clip == null)
                     return;
-                }
                 Bounds b = OsmUrlToBounds.parse(clip);
                 if (b != null) {
                     boundingBoxChanged(new Bounds(b), null);
@@ -355,6 +359,15 @@
         return currentBounds;
     }

+    public String getSelectedURL() {
+        for (DownloadSelection s : downloadSelections) {
+            if (s instanceof OverpassSelection)
+                return ((OverpassSelection)s).getOverpassURL();
+        }
+
+        return "";
+    }
+
     @Override
     public void setVisible(boolean visible) {
         if (visible) {
Index: src/org/openstreetmap/josm/actions/DownloadAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/DownloadAction.java	(revision 5389)
+++ src/org/openstreetmap/josm/actions/DownloadAction.java	(working copy)
@@ -38,9 +38,16 @@
         if (! dialog.isCanceled()) {
             dialog.rememberSettings();
             Bounds area = dialog.getSelectedDownloadArea();
+            String url = dialog.getSelectedURL();
+
             if (dialog.isDownloadOsmData()) {
                 DownloadOsmTask task = new DownloadOsmTask();
-                Future<?> future = task.download(dialog.isNewLayerRequired(), area, null);
+                Future<?> future;
+                if (!url.isEmpty()) {
+                    future = task.loadUrl(dialog.isNewLayerRequired(), url, null);
+                } else {
+                    future = task.download(dialog.isNewLayerRequired(), area, null);
+                }
                 Main.worker.submit(new PostDownloadHandler(task, future));
             }
             if (dialog.isDownloadGpxData()) {
Index: src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTask.java
===================================================================
--- src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTask.java	(revision 5389)
+++ src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTask.java	(working copy)
@@ -15,6 +15,7 @@
 import java.util.regex.Pattern;

 import javax.swing.JOptionPane;
+
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.coor.LatLon;
@@ -81,10 +82,14 @@
      * @param url The URL as String
      */
     public Future<?> loadUrl(boolean new_layer, String url, ProgressMonitor progressMonitor) {
-        downloadTask = new DownloadTask(new_layer,
+        return loadUrl(new_layer, null, url, progressMonitor);
+    }
+
+    public Future<?> loadUrl(boolean new_layer, Bounds downloadArea, String url, ProgressMonitor progressMonitor) {
+        this.downloadTask = new DownloadTask(new_layer,
                 new OsmServerLocationReader(url),
                 progressMonitor);
-        currentBounds = null;
+        this.currentBounds = (downloadArea != null ? new Bounds(downloadArea) : null);
         // Extract .osm filename from URL to set the new layer name
         extractOsmFilename("http://.*/(.*\\.osm)", url);
         return Main.worker.submit(downloadTask);
@@ -248,6 +253,9 @@
         }

         protected void suggestImageryLayers() {
+            if (currentBounds == null)
+                return;
+
             final LatLon center = currentBounds.getCenter();
             final Set<ImageryInfo> layers = new HashSet<ImageryInfo>();

@@ -272,9 +280,8 @@
                 }
             }

-            if (layers.isEmpty()) {
+            if (layers.isEmpty())
                 return;
-            }

             final List<String> layerNames = new ArrayList<String>();
             for (ImageryInfo i : layers) {
@@ -291,9 +298,8 @@
                     tr("Add imagery layers?"),
                     JOptionPane.YES_NO_OPTION,
                     JOptionPane.QUESTION_MESSAGE,
-                    JOptionPane.YES_OPTION)) {
+                            JOptionPane.YES_OPTION))
                 return;
-            }

             ImageryLayerInfo.addLayers(layers);
         }
