Index: trunk/src/org/openstreetmap/josm/actions/OverpassDownloadAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/OverpassDownloadAction.java	(revision 12575)
+++ trunk/src/org/openstreetmap/josm/actions/OverpassDownloadAction.java	(revision 12576)
@@ -8,13 +8,9 @@
 import java.awt.Component;
 import java.awt.Dimension;
-import java.awt.GridBagLayout;
 import java.awt.event.ActionEvent;
 import java.awt.event.FocusEvent;
 import java.awt.event.FocusListener;
 import java.awt.event.KeyEvent;
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.Optional;
 import java.util.concurrent.Future;
@@ -25,12 +21,9 @@
 import javax.swing.ActionMap;
 import javax.swing.JButton;
-import javax.swing.JEditorPane;
 import javax.swing.JLabel;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
-import javax.swing.event.HyperlinkEvent;
 import javax.swing.plaf.basic.BasicArrowButton;
-import javax.swing.text.JTextComponent;
 
 import org.openstreetmap.josm.Main;
@@ -39,19 +32,13 @@
 import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.preferences.BooleanProperty;
-import org.openstreetmap.josm.data.preferences.CollectionProperty;
-import org.openstreetmap.josm.gui.ExtendedDialog;
 import org.openstreetmap.josm.gui.download.DownloadDialog;
 import org.openstreetmap.josm.gui.download.OverpassQueryList;
+import org.openstreetmap.josm.gui.download.OverpassQueryWizardDialog;
 import org.openstreetmap.josm.gui.preferences.server.OverpassServerPreference;
 import org.openstreetmap.josm.gui.util.GuiHelper;
-import org.openstreetmap.josm.gui.widgets.HistoryComboBox;
 import org.openstreetmap.josm.gui.widgets.JosmTextArea;
 import org.openstreetmap.josm.io.OverpassDownloadReader;
 import org.openstreetmap.josm.tools.GBC;
-import org.openstreetmap.josm.tools.OpenBrowser;
-import org.openstreetmap.josm.tools.OverpassTurboQueryWizard;
 import org.openstreetmap.josm.tools.Shortcut;
-import org.openstreetmap.josm.tools.UncheckedParseException;
-import org.openstreetmap.josm.tools.Utils;
 
 /**
@@ -160,5 +147,9 @@
     }
 
-    private static final class OverpassDownloadDialog extends DownloadDialog {
+    /**
+     * The download dialog that overpass uses.
+     * @since 12576 public
+     */
+    public static final class OverpassDownloadDialog extends DownloadDialog {
 
         private JosmTextArea overpassQuery;
@@ -196,5 +187,5 @@
                 @Override
                 public void actionPerformed(ActionEvent e) {
-                    QueryWizardDialog.getInstance().showDialog();
+                    new OverpassQueryWizardDialog(instance).showDialog();
                 }
             };
@@ -262,5 +253,10 @@
         }
 
-        void setOverpassQuery(String text) {
+        /**
+         * Sets the query that is displayed
+         * @param text The multiline query text.
+         * @since 12576 public
+         */
+        public void setOverpassQuery(String text) {
             overpassQuery.setText(text);
         }
@@ -280,221 +276,9 @@
         /**
          * Triggers the download action to fire.
-         */
-        private void triggerDownload() {
+         * @since 12576 public
+         */
+        public void triggerDownload() {
             super.btnDownload.doClick();
         }
     }
-
-    private static final class QueryWizardDialog extends ExtendedDialog {
-
-        private static final String HEADLINE_START = "<h3>";
-        private static final String HEADLINE_END = "</h3>";
-        private static final String TR_START = "<tr>";
-        private static final String TR_END = "</tr>";
-        private static final String TD_START = "<td>";
-        private static final String TD_END = "</td>";
-        private static QueryWizardDialog dialog;
-        private final HistoryComboBox queryWizard;
-        private final OverpassTurboQueryWizard overpassQueryBuilder;
-        private static final CollectionProperty OVERPASS_WIZARD_HISTORY =
-                new CollectionProperty("download.overpass.wizard", new ArrayList<String>());
-
-        // dialog buttons
-        private static final int BUILD_QUERY = 0;
-        private static final int BUILD_AN_EXECUTE_QUERY = 1;
-        private static final int CANCEL = 2;
-
-        /**
-         * Get an instance of {@link QueryWizardDialog}.
-         * @return The instance
-         */
-        public static QueryWizardDialog getInstance() {
-            if (dialog == null) {
-                dialog = new QueryWizardDialog();
-            }
-
-            return dialog;
-        }
-
-        private static final String DESCRIPTION_STYLE =
-                "<style type=\"text/css\">\n"
-                + "table { border-spacing: 0pt;}\n"
-                + "h3 {text-align: center; padding: 8px;}\n"
-                + "td {border: 1px solid #dddddd; text-align: left; padding: 8px;}\n"
-                + "#desc {width: 350px;}"
-                + "</style>\n";
-
-        private QueryWizardDialog() {
-            super(OverpassDownloadDialog.getInstance(), tr("Overpass Turbo Query Wizard"),
-                    tr("Build query"), tr("Build query and execute"), tr("Cancel"));
-
-            this.queryWizard = new HistoryComboBox();
-            this.overpassQueryBuilder = OverpassTurboQueryWizard.getInstance();
-
-            JPanel panel = new JPanel(new GridBagLayout());
-
-            JLabel searchLabel = new JLabel(tr("Search :"));
-            JTextComponent descPane = buildDescriptionSection();
-            JScrollPane scroll = GuiHelper.embedInVerticalScrollPane(descPane);
-            scroll.getVerticalScrollBar().setUnitIncrement(10); // make scrolling smooth
-
-            panel.add(searchLabel, GBC.std().insets(0, 0, 0, 20).anchor(GBC.SOUTHEAST));
-            panel.add(queryWizard, GBC.eol().insets(0, 0, 0, 15).fill(GBC.HORIZONTAL).anchor(GBC.SOUTH));
-            panel.add(scroll, GBC.eol().fill(GBC.BOTH).anchor(GBC.CENTER));
-
-            queryWizard.setPossibleItems(OVERPASS_WIZARD_HISTORY.get());
-
-            setCancelButton(CANCEL);
-            setDefaultButton(BUILD_AN_EXECUTE_QUERY + 1); // Build and execute button
-            setContent(panel, false);
-        }
-
-        @Override
-        public void buttonAction(int buttonIndex, ActionEvent evt) {
-            switch (buttonIndex) {
-                case BUILD_QUERY:
-                    if (this.buildQueryAction()) {
-                        this.saveHistory();
-                        super.buttonAction(BUILD_QUERY, evt);
-                    }
-                    break;
-                case BUILD_AN_EXECUTE_QUERY:
-                    if (this.buildQueryAction()) {
-                        this.saveHistory();
-                        super.buttonAction(BUILD_AN_EXECUTE_QUERY, evt);
-
-                        OverpassDownloadDialog.getInstance().triggerDownload();
-                    }
-                    break;
-                default:
-                    super.buttonAction(buttonIndex, evt);
-
-            }
-        }
-
-        /**
-         * Saves the latest, successfully parsed search term.
-         */
-        private void saveHistory() {
-            queryWizard.addCurrentItemToHistory();
-            OVERPASS_WIZARD_HISTORY.put(queryWizard.getHistory());
-        }
-
-        /**
-         * Tries to process a search term using {@link OverpassTurboQueryWizard}. If the term cannot
-         * be parsed, the the corresponding dialog is shown.
-         * @param searchTerm The search term to parse.
-         * @return {@link Optional#empty()} if an exception was thrown when parsing, meaning
-         * that the term cannot be processed, or non-empty {@link Optional} containing the result
-         * of parsing.
-         */
-        private Optional<String> tryParseSearchTerm(String searchTerm) {
-            try {
-                String query = this.overpassQueryBuilder.constructQuery(searchTerm);
-
-                return Optional.of(query);
-            } catch (UncheckedParseException ex) {
-                Main.error(ex);
-                JOptionPane.showMessageDialog(
-                        OverpassDownloadDialog.getInstance(),
-                        "<html>" +
-                         tr("The Overpass wizard could not parse the following query:") +
-                         Utils.joinAsHtmlUnorderedList(Collections.singleton(searchTerm)) +
-                         "</html>",
-                        tr("Parse error"),
-                        JOptionPane.ERROR_MESSAGE
-                );
-
-                return Optional.empty();
-            }
-        }
-
-        /**
-         * Builds an Overpass query out from {@link QueryWizardDialog#queryWizard} contents.
-         * @return {@code true} if the query successfully built, {@code false} otherwise.
-         */
-        private boolean buildQueryAction() {
-            final String wizardSearchTerm = this.queryWizard.getText();
-
-            Optional<String> q = this.tryParseSearchTerm(wizardSearchTerm);
-            if (q.isPresent()) {
-                String query = q.get();
-                OverpassDownloadDialog.getInstance().setOverpassQuery(query);
-
-                return true;
-            }
-
-            return false;
-        }
-
-        private static JTextComponent buildDescriptionSection() {
-            JEditorPane descriptionSection = new JEditorPane("text/html", getDescriptionContent());
-            descriptionSection.setEditable(false);
-            descriptionSection.addHyperlinkListener(e -> {
-                if (HyperlinkEvent.EventType.ACTIVATED.equals(e.getEventType())) {
-                    OpenBrowser.displayUrl(e.getURL().toString());
-                }
-            });
-
-            return descriptionSection;
-        }
-
-        private static String getDescriptionContent() {
-            return new StringBuilder("<html>")
-                    .append(DESCRIPTION_STYLE)
-                    .append("<body>")
-                    .append(HEADLINE_START)
-                    .append(tr("Query Wizard"))
-                    .append(HEADLINE_END)
-                    .append("<p>")
-                    .append(tr("Allows you to interact with <i>Overpass API</i> by writing declarative, human-readable terms."))
-                    .append(tr("The <i>Query Wizard</i> tool will transform those to a valid overpass query."))
-                    .append(tr("For more detailed description see "))
-                    .append(tr("<a href=\"{0}\">OSM Wiki</a>.", Main.getOSMWebsite() + "/wiki/Overpass_turbo/Wizard"))
-                    .append("</p>")
-                    .append(HEADLINE_START).append(tr("Hints")).append(HEADLINE_END)
-                    .append("<table>").append(TR_START).append(TD_START)
-                    .append(Utils.joinAsHtmlUnorderedList(Arrays.asList("<i>type:node</i>", "<i>type:relation</i>", "<i>type:way</i>")))
-                    .append(TD_END).append(TD_START)
-                    .append("<span>").append(tr("Download objects of a certain type.")).append("</span>")
-                    .append(TD_END).append(TR_END)
-                    .append(TR_START).append(TD_START)
-                    .append(Utils.joinAsHtmlUnorderedList(
-                            Arrays.asList("<i>key=value in <u>location</u></i>",
-                                    "<i>key=value around <u>location</u></i>",
-                                    "<i>key=value in bbox</i>")))
-                    .append(TD_END).append(TD_START)
-                    .append(tr("Download object by specifying a specific location. For example,"))
-                    .append(Utils.joinAsHtmlUnorderedList(Arrays.asList(
-                            tr("{0} all objects having {1} as attribute are downloaded.", "<i>tourism=hotel in Berlin</i> -", "'tourism=hotel'"),
-                            tr("{0} all object with the corresponding key/value pair located around Berlin. Note, the default value for radius "+
-                                    "is set to 1000m, but it can be changed in the generated query.", "<i>tourism=hotel around Berlin</i> -"),
-                            tr("{0} all objects within the current selection that have {1} as attribute.", "<i>tourism=hotel in bbox</i> -",
-                                    "'tourism=hotel'"))))
-                    .append("<span>")
-                    .append(tr("Instead of <i>location</i> any valid place name can be used like address, city, etc."))
-                    .append("</span>")
-                    .append(TD_END).append(TR_END)
-                    .append(TR_START).append(TD_START)
-                    .append(Utils.joinAsHtmlUnorderedList(Arrays.asList("<i>key=value</i>", "<i>key=*</i>", "<i>key~regex</i>",
-                            "<i>key!=value</i>", "<i>key!~regex</i>", "<i>key=\"combined value\"</i>")))
-                    .append(TD_END).append(TD_START)
-                    .append(tr("<span>Download objects that have some concrete key/value pair, only the key with any contents for the value, " +
-                            "the value matching some regular expression. 'Not equal' operators are supported as well.</span>"))
-                    .append(TD_END).append(TR_END)
-                    .append(TR_START).append(TD_START)
-                    .append(Utils.joinAsHtmlUnorderedList(Arrays.asList(
-                            tr("<i>expression1 {0} expression2</i>", "or"),
-                            tr("<i>expression1 {0} expression2</i>", "and"))))
-                    .append(TD_END).append(TD_START)
-                    .append("<span>")
-                    .append(tr("Basic logical operators can be used to create more sophisticated queries. Instead of 'or' - '|', '||' " +
-                            "can be used, and instead of 'and' - '&', '&&'."))
-                    .append("</span>")
-                    .append(TD_END).append(TR_END).append("</table>")
-                    .append("</body>")
-                    .append("</html>")
-                    .toString();
-        }
-    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/download/OverpassQueryWizardDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/download/OverpassQueryWizardDialog.java	(revision 12576)
+++ trunk/src/org/openstreetmap/josm/gui/download/OverpassQueryWizardDialog.java	(revision 12576)
@@ -0,0 +1,242 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.download;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Optional;
+
+import javax.swing.JEditorPane;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.event.HyperlinkEvent;
+import javax.swing.text.JTextComponent;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.OverpassDownloadAction.OverpassDownloadDialog;
+import org.openstreetmap.josm.data.preferences.CollectionProperty;
+import org.openstreetmap.josm.gui.ExtendedDialog;
+import org.openstreetmap.josm.gui.util.GuiHelper;
+import org.openstreetmap.josm.gui.widgets.HistoryComboBox;
+import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.OpenBrowser;
+import org.openstreetmap.josm.tools.OverpassTurboQueryWizard;
+import org.openstreetmap.josm.tools.UncheckedParseException;
+import org.openstreetmap.josm.tools.Utils;
+
+/**
+ * This dialog provides an easy and fast way to create an overpass query.
+ * @since 12576
+ */
+public final class OverpassQueryWizardDialog extends ExtendedDialog {
+
+    private static final String HEADLINE_START = "<h3>";
+    private static final String HEADLINE_END = "</h3>";
+    private static final String TR_START = "<tr>";
+    private static final String TR_END = "</tr>";
+    private static final String TD_START = "<td>";
+    private static final String TD_END = "</td>";
+    private final HistoryComboBox queryWizard;
+    private final OverpassTurboQueryWizard overpassQueryBuilder;
+    private static final CollectionProperty OVERPASS_WIZARD_HISTORY =
+            new CollectionProperty("download.overpass.wizard", new ArrayList<String>());
+
+    // dialog buttons
+    private static final int BUILD_QUERY = 0;
+    private static final int BUILD_AN_EXECUTE_QUERY = 1;
+    private static final int CANCEL = 2;
+
+    private static final String DESCRIPTION_STYLE =
+            "<style type=\"text/css\">\n"
+            + "table { border-spacing: 0pt;}\n"
+            + "h3 {text-align: center; padding: 8px;}\n"
+            + "td {border: 1px solid #dddddd; text-align: left; padding: 8px;}\n"
+            + "#desc {width: 350px;}"
+            + "</style>\n";
+
+    private final OverpassDownloadDialog parentDialog;
+
+    /**
+     * Create a new {@link OverpassQueryWizardDialog}
+     * @param parentDialog The parent this dialog should be displayed for
+     */
+    public OverpassQueryWizardDialog(OverpassDownloadDialog parentDialog) {
+        super(parentDialog, tr("Overpass Turbo Query Wizard"),
+                tr("Build query"), tr("Build query and execute"), tr("Cancel"));
+        this.parentDialog = parentDialog;
+
+        this.queryWizard = new HistoryComboBox();
+        this.overpassQueryBuilder = OverpassTurboQueryWizard.getInstance();
+
+        JPanel panel = new JPanel(new GridBagLayout());
+
+        JLabel searchLabel = new JLabel(tr("Search :"));
+        JTextComponent descPane = buildDescriptionSection();
+        JScrollPane scroll = GuiHelper.embedInVerticalScrollPane(descPane);
+        scroll.getVerticalScrollBar().setUnitIncrement(10); // make scrolling smooth
+
+        panel.add(searchLabel, GBC.std().insets(0, 0, 0, 20).anchor(GBC.SOUTHEAST));
+        panel.add(queryWizard, GBC.eol().insets(0, 0, 0, 15).fill(GBC.HORIZONTAL).anchor(GBC.SOUTH));
+        panel.add(scroll, GBC.eol().fill(GBC.BOTH).anchor(GBC.CENTER));
+
+        queryWizard.setPossibleItems(OVERPASS_WIZARD_HISTORY.get());
+
+        setCancelButton(CANCEL);
+        setDefaultButton(BUILD_AN_EXECUTE_QUERY + 1); // Build and execute button
+        setContent(panel, false);
+    }
+
+    @Override
+    public void buttonAction(int buttonIndex, ActionEvent evt) {
+        switch (buttonIndex) {
+            case BUILD_QUERY:
+                if (this.buildQueryAction()) {
+                    this.saveHistory();
+                    super.buttonAction(BUILD_QUERY, evt);
+                }
+                break;
+            case BUILD_AN_EXECUTE_QUERY:
+                if (this.buildQueryAction()) {
+                    this.saveHistory();
+                    super.buttonAction(BUILD_AN_EXECUTE_QUERY, evt);
+
+                    parentDialog.triggerDownload();
+                }
+                break;
+            default:
+                super.buttonAction(buttonIndex, evt);
+
+        }
+    }
+
+    /**
+     * Saves the latest, successfully parsed search term.
+     */
+    private void saveHistory() {
+        queryWizard.addCurrentItemToHistory();
+        OVERPASS_WIZARD_HISTORY.put(queryWizard.getHistory());
+    }
+
+    /**
+     * Tries to process a search term using {@link OverpassTurboQueryWizard}. If the term cannot
+     * be parsed, the the corresponding dialog is shown.
+     * @param searchTerm The search term to parse.
+     * @return {@link Optional#empty()} if an exception was thrown when parsing, meaning
+     * that the term cannot be processed, or non-empty {@link Optional} containing the result
+     * of parsing.
+     */
+    private Optional<String> tryParseSearchTerm(String searchTerm) {
+        try {
+            String query = this.overpassQueryBuilder.constructQuery(searchTerm);
+
+            return Optional.of(query);
+        } catch (UncheckedParseException ex) {
+            Main.error(ex);
+            JOptionPane.showMessageDialog(
+                    parentDialog,
+                    "<html>" +
+                     tr("The Overpass wizard could not parse the following query:") +
+                     Utils.joinAsHtmlUnorderedList(Collections.singleton(searchTerm)) +
+                     "</html>",
+                    tr("Parse error"),
+                    JOptionPane.ERROR_MESSAGE
+            );
+
+            return Optional.empty();
+        }
+    }
+
+    /**
+     * Builds an Overpass query out from {@link OverpassQueryWizardDialog#queryWizard} contents.
+     * @return {@code true} if the query successfully built, {@code false} otherwise.
+     */
+    private boolean buildQueryAction() {
+        final String wizardSearchTerm = this.queryWizard.getText();
+
+        Optional<String> q = this.tryParseSearchTerm(wizardSearchTerm);
+        if (q.isPresent()) {
+            String query = q.get();
+            parentDialog.setOverpassQuery(query);
+
+            return true;
+        }
+
+        return false;
+    }
+
+    private static JTextComponent buildDescriptionSection() {
+        JEditorPane descriptionSection = new JEditorPane("text/html", getDescriptionContent());
+        descriptionSection.setEditable(false);
+        descriptionSection.addHyperlinkListener(e -> {
+            if (HyperlinkEvent.EventType.ACTIVATED.equals(e.getEventType())) {
+                OpenBrowser.displayUrl(e.getURL().toString());
+            }
+        });
+
+        return descriptionSection;
+    }
+
+    private static String getDescriptionContent() {
+        return new StringBuilder("<html>")
+                .append(DESCRIPTION_STYLE)
+                .append("<body>")
+                .append(HEADLINE_START)
+                .append(tr("Query Wizard"))
+                .append(HEADLINE_END)
+                .append("<p>")
+                .append(tr("Allows you to interact with <i>Overpass API</i> by writing declarative, human-readable terms."))
+                .append(tr("The <i>Query Wizard</i> tool will transform those to a valid overpass query."))
+                .append(tr("For more detailed description see "))
+                .append(tr("<a href=\"{0}\">OSM Wiki</a>.", Main.getOSMWebsite() + "/wiki/Overpass_turbo/Wizard"))
+                .append("</p>")
+                .append(HEADLINE_START).append(tr("Hints")).append(HEADLINE_END)
+                .append("<table>").append(TR_START).append(TD_START)
+                .append(Utils.joinAsHtmlUnorderedList(Arrays.asList("<i>type:node</i>", "<i>type:relation</i>", "<i>type:way</i>")))
+                .append(TD_END).append(TD_START)
+                .append("<span>").append(tr("Download objects of a certain type.")).append("</span>")
+                .append(TD_END).append(TR_END)
+                .append(TR_START).append(TD_START)
+                .append(Utils.joinAsHtmlUnorderedList(
+                        Arrays.asList("<i>key=value in <u>location</u></i>",
+                                "<i>key=value around <u>location</u></i>",
+                                "<i>key=value in bbox</i>")))
+                .append(TD_END).append(TD_START)
+                .append(tr("Download object by specifying a specific location. For example,"))
+                .append(Utils.joinAsHtmlUnorderedList(Arrays.asList(
+                        tr("{0} all objects having {1} as attribute are downloaded.", "<i>tourism=hotel in Berlin</i> -", "'tourism=hotel'"),
+                        tr("{0} all object with the corresponding key/value pair located around Berlin. Note, the default value for radius "+
+                                "is set to 1000m, but it can be changed in the generated query.", "<i>tourism=hotel around Berlin</i> -"),
+                        tr("{0} all objects within the current selection that have {1} as attribute.", "<i>tourism=hotel in bbox</i> -",
+                                "'tourism=hotel'"))))
+                .append("<span>")
+                .append(tr("Instead of <i>location</i> any valid place name can be used like address, city, etc."))
+                .append("</span>")
+                .append(TD_END).append(TR_END)
+                .append(TR_START).append(TD_START)
+                .append(Utils.joinAsHtmlUnorderedList(Arrays.asList("<i>key=value</i>", "<i>key=*</i>", "<i>key~regex</i>",
+                        "<i>key!=value</i>", "<i>key!~regex</i>", "<i>key=\"combined value\"</i>")))
+                .append(TD_END).append(TD_START)
+                .append(tr("<span>Download objects that have some concrete key/value pair, only the key with any contents for the value, " +
+                        "the value matching some regular expression. 'Not equal' operators are supported as well.</span>"))
+                .append(TD_END).append(TR_END)
+                .append(TR_START).append(TD_START)
+                .append(Utils.joinAsHtmlUnorderedList(Arrays.asList(
+                        tr("<i>expression1 {0} expression2</i>", "or"),
+                        tr("<i>expression1 {0} expression2</i>", "and"))))
+                .append(TD_END).append(TD_START)
+                .append("<span>")
+                .append(tr("Basic logical operators can be used to create more sophisticated queries. Instead of 'or' - '|', '||' " +
+                        "can be used, and instead of 'and' - '&', '&&'."))
+                .append("</span>")
+                .append(TD_END).append(TR_END).append("</table>")
+                .append("</body>")
+                .append("</html>")
+                .toString();
+    }
+}
