Index: /applications/editors/josm/plugins/mirrored_download/build.xml
===================================================================
--- /applications/editors/josm/plugins/mirrored_download/build.xml	(revision 28107)
+++ /applications/editors/josm/plugins/mirrored_download/build.xml	(revision 28108)
@@ -86,5 +86,5 @@
                 <attribute name="Plugin-Description" value="Simplifies download from different read-only APIs."/>
                 <attribute name="Plugin-Link" value="http://wiki.openstreetmap.org/wiki/JOSM/Plugins/mirrored_download"/>
-                <attribute name="Plugin-Mainversion" value="5089"/>
+                <attribute name="Plugin-Mainversion" value="5097"/>
                 <attribute name="Plugin-Version" value="${version.entry.commit.revision}"/>
             </manifest>
Index: plications/editors/josm/plugins/mirrored_download/src/mirrored_download/BoundingBoxDownloader2.java
===================================================================
--- /applications/editors/josm/plugins/mirrored_download/src/mirrored_download/BoundingBoxDownloader2.java	(revision 28107)
+++ 	(revision )
@@ -1,81 +1,0 @@
-// License: GPL. Copyright 2007 by Immanuel Scholz and others
-package mirrored_download;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.openstreetmap.josm.io.BoundingBoxDownloader;
-import org.openstreetmap.josm.io.OsmApi;
-import org.openstreetmap.josm.io.OsmTransferException;
-
-import org.openstreetmap.josm.data.Bounds;
-import org.openstreetmap.josm.data.gpx.GpxData;
-import org.openstreetmap.josm.data.osm.DataSet;
-import org.openstreetmap.josm.data.osm.DataSource;
-import org.openstreetmap.josm.gui.progress.ProgressMonitor;
-import org.xml.sax.SAXException;
-
-public class BoundingBoxDownloader2 extends BoundingBoxDownloader {
-
-    /**
-     * The boundings of the desired map data.
-     */
-    private final double lat1;
-    private final double lon1;
-    private final double lat2;
-    private final double lon2;
-    private final boolean crosses180th;
-
-    public BoundingBoxDownloader2(Bounds downloadArea) {
-        super(downloadArea);
-
-        this.lat1 = downloadArea.getMin().lat();
-        this.lon1 = downloadArea.getMin().lon();
-        this.lat2 = downloadArea.getMax().lat();
-        this.lon2 = downloadArea.getMax().lon();
-        this.crosses180th = downloadArea.crosses180thMeridian();
-    }
-
-    protected InputStream getInputStream(String urlStr, ProgressMonitor progressMonitor)
-        throws OsmTransferException  {
-
-        try {
-            OsmApi.getOsmApi().initialize(progressMonitor);
-            urlStr = MirroredDownloadPlugin.getDownloadUrl() + urlStr;
-            return getInputStreamRaw(urlStr, progressMonitor);
-        } finally {
-            progressMonitor.invalidate();
-        }
-    }
-
-    public DataSet parseOsm(ProgressMonitor progressMonitor) throws OsmTransferException {
-
-        DataSet ds = super.parseOsm(progressMonitor);
-
-        System.out.println(ds.dataSources.toString());
-        if (ds != null && ds.dataSources.size() == 0)
-        {
-            if (crosses180th)
-            {
-                Bounds bounds = new Bounds(lat1, lon1, lat2, 180.0);
-                DataSource src = new DataSource(bounds, MirroredDownloadPlugin.getDownloadUrl());
-                ds.dataSources.add(src);
-
-                bounds = new Bounds(lat1, -180.0, lat2, lon2);
-                src = new DataSource(bounds, MirroredDownloadPlugin.getDownloadUrl());
-                ds.dataSources.add(src);
-            }
-            else
-            {
-                Bounds bounds = new Bounds(lat1, lon1, lat2, lon2);
-                DataSource src = new DataSource(bounds, MirroredDownloadPlugin.getDownloadUrl());
-                ds.dataSources.add(src);
-            }
-        }
-        System.out.println(ds.dataSources.toString());
-
-        return ds;
-    }
-}
Index: plications/editors/josm/plugins/mirrored_download/src/mirrored_download/DownloadAction2.java
===================================================================
--- /applications/editors/josm/plugins/mirrored_download/src/mirrored_download/DownloadAction2.java	(revision 28107)
+++ 	(revision )
@@ -1,55 +1,0 @@
-// License: GPL. Copyright 2007 by Immanuel Scholz and others
-package mirrored_download;
-
-import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.event.ActionEvent;
-import java.awt.event.KeyEvent;
-import java.util.concurrent.Future;
-
-import org.openstreetmap.josm.actions.JosmAction;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.actions.downloadtasks.DownloadGpsTask;
-import org.openstreetmap.josm.actions.downloadtasks.PostDownloadHandler;
-import org.openstreetmap.josm.data.Bounds;
-import org.openstreetmap.josm.gui.download.DownloadDialog;
-import org.openstreetmap.josm.tools.Shortcut;
-
-/**
- * Action that opens a connection to the osm server and downloads map data.
- *
- * An dialog is displayed asking the user to specify a rectangle to grab.
- * The url and account settings from the preferences are used.
- *
- * @author imi
- */
-public class DownloadAction2 extends JosmAction {
-    public DownloadAction2() {
-        super(tr("Download from OSM mirror..."), null, tr("Download map data from the OSM server."),
-            Shortcut.registerShortcut("mirror:download", tr("File: {0}", tr("Download from OSM mirror...")), KeyEvent.VK_DOWN, Shortcut.ALT_SHIFT),
-            true, "mirroreddownload/download", true);
-        putValue("help", ht("/Action/MirroredDownload"));
-    }
-
-    public void actionPerformed(ActionEvent e) {
-        DownloadDialog dialog = DownloadDialog.getInstance();
-        dialog.restoreSettings();
-        dialog.setVisible(true);
-        if (! dialog.isCanceled()) {
-            dialog.rememberSettings();
-            Bounds area = dialog.getSelectedDownloadArea();
-            if (dialog.isDownloadOsmData()) {
-                DownloadOsmTask2 task = new DownloadOsmTask2();
-                Future<?> future = task.download(dialog.isNewLayerRequired(), area, null);
-                Main.worker.submit(new PostDownloadHandler(task, future));
-            }
-            if (dialog.isDownloadGpxData()) {
-                DownloadGpsTask task = new DownloadGpsTask();
-                Future<?> future = task.download(dialog.isNewLayerRequired(),area, null);
-                Main.worker.submit(new PostDownloadHandler(task, future));
-            }
-        }
-    }
-}
Index: plications/editors/josm/plugins/mirrored_download/src/mirrored_download/DownloadOsmTask2.java
===================================================================
--- /applications/editors/josm/plugins/mirrored_download/src/mirrored_download/DownloadOsmTask2.java	(revision 28107)
+++ 	(revision )
@@ -1,39 +1,0 @@
-package mirrored_download;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.io.IOException;
-import java.util.Collection;
-import java.util.concurrent.Future;
-
-import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.Bounds;
-import org.openstreetmap.josm.data.coor.LatLon;
-import org.openstreetmap.josm.data.osm.DataSet;
-import org.openstreetmap.josm.data.osm.DataSource;
-import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
-import org.openstreetmap.josm.gui.PleaseWaitRunnable;
-import org.openstreetmap.josm.gui.layer.Layer;
-import org.openstreetmap.josm.gui.layer.OsmDataLayer;
-import org.openstreetmap.josm.gui.progress.ProgressMonitor;
-import org.openstreetmap.josm.io.OsmServerLocationReader;
-import org.openstreetmap.josm.io.OsmServerReader;
-import org.openstreetmap.josm.io.OsmTransferCanceledException;
-import org.openstreetmap.josm.io.OsmTransferException;
-import org.xml.sax.SAXException;
-
-public class DownloadOsmTask2 extends DownloadOsmTask {
-
-    public Future<?> download(boolean newLayer, Bounds downloadArea, ProgressMonitor progressMonitor) {
-
-        downloadTask = new DownloadTask(newLayer,
-                new BoundingBoxDownloader2(downloadArea), progressMonitor);
-        currentBounds = new Bounds(downloadArea);
-        // We need submit instead of execute so we can wait for it to finish and get the error
-        // message if necessary. If no one calls getErrorMessage() it just behaves like execute.
-        return Main.worker.submit(downloadTask);
-    }
-
-}
Index: /applications/editors/josm/plugins/mirrored_download/src/mirrored_download/MirroredDownloadAction.java
===================================================================
--- /applications/editors/josm/plugins/mirrored_download/src/mirrored_download/MirroredDownloadAction.java	(revision 28108)
+++ /applications/editors/josm/plugins/mirrored_download/src/mirrored_download/MirroredDownloadAction.java	(revision 28108)
@@ -0,0 +1,192 @@
+// License: GPL. For details, see LICENSE file.
+package mirrored_download;
+
+import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Component;
+import java.awt.GridBagConstraints;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.util.LinkedList;
+import java.util.concurrent.Future;
+import java.util.regex.Pattern;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.text.JTextComponent;
+
+import org.openstreetmap.josm.actions.JosmAction;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask;
+import org.openstreetmap.josm.actions.downloadtasks.PostDownloadHandler;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.DataSource;
+import org.openstreetmap.josm.gui.download.DownloadDialog;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.gui.widgets.AbstractTextComponentValidator;
+import org.openstreetmap.josm.gui.widgets.HistoryComboBox;
+import org.openstreetmap.josm.io.BoundingBoxDownloader;
+import org.openstreetmap.josm.io.OsmTransferException;
+import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.Shortcut;
+
+public class MirroredDownloadAction extends JosmAction {
+
+    static final String XAPI_QUERY_HISTORY_KEY = "plugin.mirrored_download.query-history";
+    static final String XAPI_QUERY_TOOLTIP = tr("XAPI query, e.g., '''' (to download all data), ''[highway=*]'', or ''[[network=VRR][ref=603|613]''");
+
+    public MirroredDownloadAction() {
+        super(tr("Download from OSM mirror..."), null, tr("Download map data from the OSM server."),
+                Shortcut.registerShortcut("mirror:download", tr("File: {0}", tr("Download from OSM mirror...")), KeyEvent.VK_DOWN, Shortcut.ALT_SHIFT),
+                true, "mirroreddownload/download", true);
+        putValue("help", ht("/Action/MirroredDownload"));
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        MirroredDownloadDialog dialog = MirroredDownloadDialog.getInstance();
+        dialog.restoreSettings();
+        dialog.setVisible(true);
+        if (!dialog.isCanceled()) {
+            dialog.rememberSettings();
+            Bounds area = dialog.getSelectedDownloadArea();
+            DownloadOsmTask task = new DownloadOsmTask();
+            Future<?> future = task.download(
+                    new MirroredDownloadReader(area, dialog.getOverpassType(), dialog.getOverpassQuery()),
+                    dialog.isNewLayerRequired(), area, null);
+            Main.worker.submit(new PostDownloadHandler(task, future));
+        }
+    }
+
+    static class XAPIQueryValidator extends AbstractTextComponentValidator {
+
+        static final Pattern pattern = Pattern.compile("^(\\[([^=]+=[^=]*)\\])*$");
+
+        public XAPIQueryValidator(JTextComponent tc) throws IllegalArgumentException {
+            super(tc);
+        }
+
+        @Override
+        public void validate() {
+            if (pattern.matcher(getComponent().getText().trim()).matches()) {
+                feedbackValid(XAPI_QUERY_TOOLTIP);
+            } else {
+                feedbackInvalid(tr("This XAPI query seems to be invalid, please doublecheck"));
+            }
+        }
+
+        @Override
+        public boolean isValid() {
+            return pattern.matcher(getComponent().getText().trim()).matches();
+        }
+    }
+
+    static class MirroredDownloadDialog extends DownloadDialog {
+
+        protected JComboBox<String> overpassType;
+        protected HistoryComboBox overpassQuery;
+        private static MirroredDownloadDialog instance;
+
+        private MirroredDownloadDialog(Component parent) {
+            super(parent);
+            cbDownloadOsmData.setEnabled(false);
+            cbDownloadGpxData.setEnabled(false);
+            cbStartup.setEnabled(false);
+        }
+
+        static public MirroredDownloadDialog getInstance() {
+            if (instance == null) {
+                instance = new MirroredDownloadDialog(Main.parent);
+            }
+            return instance;
+        }
+
+        @Override
+        protected void buildMainPanelAboveDownloadSelections(JPanel pnl) {
+            overpassType = new JComboBox<String>(new String[]{"*", "node", "way", "relation"});
+            pnl.add(new JLabel(tr("Object type: ")), GBC.std().insets(5, 5, 5, 5));
+            pnl.add(overpassType, GBC.eol().fill(GridBagConstraints.HORIZONTAL));
+            overpassType.setToolTipText(tr("OSM object type to download (''*'' stands for any)"));
+            overpassQuery = new HistoryComboBox();
+            pnl.add(new JLabel(tr("XAPI query: ")), GBC.std().insets(5, 5, 5, 5));
+            new XAPIQueryValidator((JTextComponent) overpassQuery.getEditor().getEditorComponent());
+            pnl.add(overpassQuery, GBC.eol().fill(GridBagConstraints.HORIZONTAL));
+            overpassQuery.setToolTipText(XAPI_QUERY_TOOLTIP);
+        }
+
+        public String getOverpassQuery() {
+            return overpassQuery.getText();
+        }
+
+        public String getOverpassType() {
+            return overpassType.getItemAt(overpassType.getSelectedIndex());
+        }
+
+        @Override
+        public void restoreSettings() {
+            super.restoreSettings();
+            overpassQuery.setPossibleItems(
+                    Main.pref.getCollection(XAPI_QUERY_HISTORY_KEY, new LinkedList<String>()));
+        }
+
+        @Override
+        public void rememberSettings() {
+            super.rememberSettings();
+            overpassQuery.addCurrentItemToHistory();
+            Main.pref.putCollection(XAPI_QUERY_HISTORY_KEY, overpassQuery.getHistory());
+        }
+    }
+
+    static class MirroredDownloadReader extends BoundingBoxDownloader {
+
+        final String overpassType;
+        final String overpassQuery;
+
+        public MirroredDownloadReader(Bounds downloadArea, String overpassType, String overpassQuery) {
+            super(downloadArea);
+            this.overpassType = overpassType;
+            this.overpassQuery = overpassQuery.trim();
+        }
+
+        @Override
+        protected String getBaseUrl() {
+            return MirroredDownloadPlugin.getDownloadUrl();
+        }
+
+        @Override
+        protected String getRequestForBbox(double lon1, double lat1, double lon2, double lat2) {
+            return overpassQuery.isEmpty() && "*".equals(overpassType)
+                    ? super.getRequestForBbox(lon1, lat1, lon2, lat2)
+                    : overpassType + "[bbox=" + lon1 + "," + lat1 + "," + lon2 + "," + lat2 + "][@meta]" + overpassQuery;
+        }
+
+        @Override
+        public DataSet parseOsm(ProgressMonitor progressMonitor) throws OsmTransferException {
+
+            DataSet ds = super.parseOsm(progressMonitor);
+
+            // add bounds if necessary (note that Overpass API does not return bounds in the response XML)
+            if (ds != null && ds.dataSources.isEmpty()) {
+                if (crosses180th) {
+                    Bounds bounds = new Bounds(lat1, lon1, lat2, 180.0);
+                    DataSource src = new DataSource(bounds, MirroredDownloadPlugin.getDownloadUrl());
+                    ds.dataSources.add(src);
+
+                    bounds = new Bounds(lat1, -180.0, lat2, lon2);
+                    src = new DataSource(bounds, MirroredDownloadPlugin.getDownloadUrl());
+                    ds.dataSources.add(src);
+                } else {
+                    Bounds bounds = new Bounds(lat1, lon1, lat2, lon2);
+                    DataSource src = new DataSource(bounds, MirroredDownloadPlugin.getDownloadUrl());
+                    ds.dataSources.add(src);
+                }
+            }
+
+            return ds;
+        }
+    }
+}
Index: /applications/editors/josm/plugins/mirrored_download/src/mirrored_download/MirroredDownloadPlugin.java
===================================================================
--- /applications/editors/josm/plugins/mirrored_download/src/mirrored_download/MirroredDownloadPlugin.java	(revision 28107)
+++ /applications/editors/josm/plugins/mirrored_download/src/mirrored_download/MirroredDownloadPlugin.java	(revision 28108)
@@ -1,5 +1,4 @@
+// License: GPL. For details, see LICENSE file.
 package mirrored_download;
-
-import javax.swing.JMenu;
 
 import org.openstreetmap.josm.Main;
@@ -10,9 +9,7 @@
 public class MirroredDownloadPlugin extends Plugin {
 
-    static JMenu jMenu;
-
     public MirroredDownloadPlugin(PluginInformation info) {
         super(info);
-        MainMenu.addAfter(Main.main.menu.fileMenu, new DownloadAction2(), false, Main.main.menu.download);
+        MainMenu.addAfter(Main.main.menu.fileMenu, new MirroredDownloadAction(), false, Main.main.menu.download);
         MainMenu.add(Main.main.menu.editMenu, new UrlSelectionAction());
     }
Index: /applications/editors/josm/plugins/mirrored_download/src/mirrored_download/UrlSelectionAction.java
===================================================================
--- /applications/editors/josm/plugins/mirrored_download/src/mirrored_download/UrlSelectionAction.java	(revision 28107)
+++ /applications/editors/josm/plugins/mirrored_download/src/mirrored_download/UrlSelectionAction.java	(revision 28108)
@@ -1,3 +1,3 @@
-// License: GPL. Copyright 2007 by Immanuel Scholz and others
+// License: GPL. For details, see LICENSE file.
 package mirrored_download;
 
Index: /applications/editors/josm/plugins/mirrored_download/src/mirrored_download/UrlSelectionDialog.java
===================================================================
--- /applications/editors/josm/plugins/mirrored_download/src/mirrored_download/UrlSelectionDialog.java	(revision 28107)
+++ /applications/editors/josm/plugins/mirrored_download/src/mirrored_download/UrlSelectionDialog.java	(revision 28108)
@@ -1,2 +1,3 @@
+// License: GPL. For details, see LICENSE file.
 package mirrored_download;
 
