Index: /trunk/src/org/openstreetmap/josm/gui/io/AbstractUploadDialog.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/io/AbstractUploadDialog.java	(revision 9684)
+++ /trunk/src/org/openstreetmap/josm/gui/io/AbstractUploadDialog.java	(revision 9685)
@@ -13,5 +13,5 @@
  * @since 7358
  */
-public abstract class AbstractUploadDialog extends JDialog {
+public abstract class AbstractUploadDialog extends JDialog implements IUploadDialog {
 
     private boolean canceled;
@@ -181,9 +181,5 @@
     }
 
-    /**
-     * Returns true if the dialog was canceled
-     *
-     * @return true if the dialog was canceled
-     */
+    @Override
     public final boolean isCanceled() {
         return canceled;
@@ -199,7 +195,5 @@
     }
 
-    /**
-     * Remembers the user input in the preference settings
-     */
+    @Override
     public void rememberUserInput() {
         // Override if needed
Index: /trunk/src/org/openstreetmap/josm/gui/io/BasicUploadSettingsPanel.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/io/BasicUploadSettingsPanel.java	(revision 9684)
+++ /trunk/src/org/openstreetmap/josm/gui/io/BasicUploadSettingsPanel.java	(revision 9685)
@@ -95,4 +95,8 @@
     }
 
+    /**
+     * Returns the default list of sources.
+     * @return the default list of sources
+     */
     public static List<String> getDefaultSources() {
         return Arrays.asList("knowledge", "survey", "Bing");
@@ -140,8 +144,12 @@
 
                     @Override
-                    public void keyReleased(KeyEvent e) {}
+                    public void keyReleased(KeyEvent e) {
+                        // Do nothing
+                    }
 
                     @Override
-                    public void keyPressed(KeyEvent e) {}
+                    public void keyPressed(KeyEvent e) {
+                        // Do nothing
+                    }
                 }
         );
@@ -169,7 +177,18 @@
     }
 
+    /**
+     * Initializes editing of upload comment.
+     */
     public void initEditingOfUploadComment() {
         hcbUploadComment.getEditor().selectAll();
         hcbUploadComment.requestFocusInWindow();
+    }
+
+    /**
+     * Initializes editing of upload source.
+     */
+    public void initEditingOfUploadSource() {
+        hcbUploadSource.getEditor().selectAll();
+        hcbUploadSource.requestFocusInWindow();
     }
 
Index: /trunk/src/org/openstreetmap/josm/gui/io/IUploadDialog.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/io/IUploadDialog.java	(revision 9685)
+++ /trunk/src/org/openstreetmap/josm/gui/io/IUploadDialog.java	(revision 9685)
@@ -0,0 +1,66 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.io;
+
+import java.util.Map;
+
+/**
+ * Upload dialog super interface.
+ * @since 9685
+ */
+public interface IUploadDialog {
+
+    /**
+     * Returns true if the dialog was canceled
+     *
+     * @return true if the dialog was canceled
+     */
+    boolean isCanceled();
+
+    /**
+     * Remembers the user input in the preference settings
+     */
+    void rememberUserInput();
+
+    /**
+     * Returns the current value for the upload comment
+     *
+     * @return the current value for the upload comment
+     */
+    String getUploadComment();
+
+    /**
+     * Returns the current value for the changeset source
+     *
+     * @return the current value for the changeset source
+     */
+    String getUploadSource();
+
+    /**
+     * Replies the {@link UploadStrategySpecification} the user entered in the dialog.
+     *
+     * @return the {@link UploadStrategySpecification} the user entered in the dialog.
+     */
+    UploadStrategySpecification getUploadStrategySpecification();
+
+    /**
+     * Replies the map with the current tags in the tag editor model.
+     * @param keepEmpty {@code true} to keep empty tags
+     * @return the map with the current tags in the tag editor model.
+     */
+    Map<String, String> getTags(boolean keepEmpty);
+
+    /**
+     * Handles missing comment.
+     */
+    void handleMissingComment();
+
+    /**
+     * Handles missing source.
+     */
+    void handleMissingSource();
+
+    /**
+     * Handles illegal chunk size.
+     */
+    void handleIllegalChunkSize();
+}
Index: /trunk/src/org/openstreetmap/josm/gui/io/TagSettingsPanel.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/io/TagSettingsPanel.java	(revision 9684)
+++ /trunk/src/org/openstreetmap/josm/gui/io/TagSettingsPanel.java	(revision 9685)
@@ -3,5 +3,4 @@
 
 import java.awt.BorderLayout;
-import java.util.HashMap;
 import java.util.Map;
 import java.util.Observable;
@@ -14,5 +13,4 @@
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.osm.Changeset;
-import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.gui.tagging.TagEditorPanel;
 import org.openstreetmap.josm.gui.tagging.TagModel;
@@ -96,22 +94,4 @@
 
     /**
-     * @return an empty map
-     * @deprecated No longer supported, returns an empty map
-     */
-    @Deprecated
-    public Map<String, String> getDefaultTags() {
-        return new HashMap<>();
-    }
-
-    /**
-     * @param tags ignored
-     * @deprecated No longer supported, does nothing; use {@link UploadDialog#setChangesetTags(DataSet)} instead!
-     */
-    @Deprecated
-    public void setDefaultTags(Map<String, String> tags) {
-        // Deprecated
-    }
-
-    /**
      * Initializes the panel for user input
      */
Index: /trunk/src/org/openstreetmap/josm/gui/io/UploadDialog.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/io/UploadDialog.java	(revision 9684)
+++ /trunk/src/org/openstreetmap/josm/gui/io/UploadDialog.java	(revision 9685)
@@ -10,4 +10,5 @@
 import java.awt.Dimension;
 import java.awt.FlowLayout;
+import java.awt.GraphicsEnvironment;
 import java.awt.GridBagLayout;
 import java.awt.event.ActionEvent;
@@ -177,5 +178,5 @@
 
         // -- upload button
-        btnUpload = new SideButton(new UploadAction());
+        btnUpload = new SideButton(new UploadAction(this));
         pnl.add(btnUpload);
         btnUpload.setFocusable(true);
@@ -183,5 +184,5 @@
 
         // -- cancel button
-        CancelAction cancelAction = new CancelAction();
+        CancelAction cancelAction = new CancelAction(this);
         pnl.add(new SideButton(cancelAction));
         getRootPane().registerKeyboardAction(
@@ -370,27 +371,5 @@
     }
 
-    /**
-     * @deprecated No longer supported, does nothing;
-     * @return empty map
-     */
-    @Deprecated
-    public Map<String, String> getDefaultChangesetTags() {
-        return pnlTagSettings.getDefaultTags();
-    }
-
-    /**
-     * @param tags ignored
-     * @deprecated No longer supported, does nothing; use {@link #setChangesetTags(DataSet)} instead!
-     */
-    @Deprecated
-    public void setDefaultChangesetTags(Map<String, String> tags) {
-        // Deprecated
-    }
-
-    /**
-     * Replies the {@link UploadStrategySpecification} the user entered in the dialog.
-     *
-     * @return the {@link UploadStrategySpecification} the user entered in the dialog.
-     */
+    @Override
     public UploadStrategySpecification getUploadStrategySpecification() {
         UploadStrategySpecification spec = pnlUploadStrategySelectionPanel.getUploadStrategySpecification();
@@ -399,19 +378,11 @@
     }
 
-    /**
-     * Returns the current value for the upload comment
-     *
-     * @return the current value for the upload comment
-     */
-    protected String getUploadComment() {
+    @Override
+    public String getUploadComment() {
         return changesetCommentModel.getComment();
     }
 
-    /**
-     * Returns the current value for the changeset source
-     *
-     * @return the current value for the changeset source
-     */
-    protected String getUploadSource() {
+    @Override
+    public String getUploadSource() {
         return changesetSourceModel.getComment();
     }
@@ -449,9 +420,12 @@
 
     /**
-     * Handles an upload
-     *
-     */
-    class UploadAction extends AbstractAction {
-        UploadAction() {
+     * Handles an upload.
+     */
+    static class UploadAction extends AbstractAction {
+
+        private final transient IUploadDialog dialog;
+
+        UploadAction(IUploadDialog dialog) {
+            this.dialog = dialog;
             putValue(NAME, tr("Upload Changes"));
             putValue(SMALL_ICON, ImageProvider.get("upload"));
@@ -493,17 +467,23 @@
 
         protected boolean warnUploadTag(final String title, final String message, final String togglePref) {
-            ExtendedDialog dlg = new ExtendedDialog(UploadDialog.this,
-                    title,
-                    new String[] {tr("Revise"), tr("Cancel"), tr("Continue as is")});
-            dlg.setContent("<html>" + message + "</html>");
-            dlg.setButtonIcons(new Icon[] {
+            String[] buttonTexts = new String[] {tr("Revise"), tr("Cancel"), tr("Continue as is")};
+            Icon[] buttonIcons = new Icon[] {
                     new ImageProvider("ok").setMaxSize(ImageSizes.LARGEICON).get(),
                     new ImageProvider("cancel").setMaxSize(ImageSizes.LARGEICON).get(),
                     new ImageProvider("upload").setMaxSize(ImageSizes.LARGEICON).addOverlay(
-                            new ImageOverlay(new ImageProvider("warning-small"), 0.5, 0.5, 1.0, 1.0)).get()});
-            dlg.setToolTipTexts(new String[] {
+                            new ImageOverlay(new ImageProvider("warning-small"), 0.5, 0.5, 1.0, 1.0)).get()};
+            String[] tooltips = new String[] {
                     tr("Return to the previous dialog to enter a more descriptive comment"),
                     tr("Cancel and return to the previous dialog"),
-                    tr("Ignore this hint and upload anyway")});
+                    tr("Ignore this hint and upload anyway")};
+
+            if (GraphicsEnvironment.isHeadless()) {
+                return false;
+            }
+
+            ExtendedDialog dlg = new ExtendedDialog((Component) dialog, title, buttonTexts);
+            dlg.setContent("<html>" + message + "</html>");
+            dlg.setButtonIcons(buttonIcons);
+            dlg.setToolTipTexts(tooltips);
             dlg.setIcon(JOptionPane.WARNING_MESSAGE);
             dlg.toggleEnable(togglePref);
@@ -514,5 +494,5 @@
         protected void warnIllegalChunkSize() {
             HelpAwareOptionPane.showOptionDialog(
-                    UploadDialog.this,
+                    (Component) dialog,
                     tr("Please enter a valid chunk size first"),
                     tr("Illegal chunk size"),
@@ -524,9 +504,12 @@
         @Override
         public void actionPerformed(ActionEvent e) {
-            if ((getUploadComment().trim().length() < 10 && warnUploadComment()) /* abort for missing comment */
-                    || (getUploadSource().trim().isEmpty() && warnUploadSource()) /* abort for missing changeset source */
-                    ) {
-                tpConfigPanels.setSelectedIndex(0);
-                pnlBasicUploadSettings.initEditingOfUploadComment();
+            if (dialog.getUploadComment().trim().length() < 10 && warnUploadComment()) {
+                // abort for missing comment
+                dialog.handleMissingComment();
+                return;
+            }
+            if (dialog.getUploadSource().trim().isEmpty() && warnUploadSource()) {
+                // abort for missing changeset source
+                dialog.handleMissingSource();
                 return;
             }
@@ -535,5 +518,5 @@
              * though, accept if key and value are empty (cf. xor). */
             List<String> emptyChangesetTags = new ArrayList<>();
-            for (final Entry<String, String> i : pnlTagSettings.getTags(true).entrySet()) {
+            for (final Entry<String, String> i : dialog.getTags(true).entrySet()) {
                 final boolean isKeyEmpty = i.getKey() == null || i.getKey().trim().isEmpty();
                 final boolean isValueEmpty = i.getValue() == null || i.getValue().trim().isEmpty();
@@ -553,27 +536,31 @@
                     JOptionPane.WARNING_MESSAGE
             )) {
-                tpConfigPanels.setSelectedIndex(0);
-                pnlBasicUploadSettings.initEditingOfUploadComment();
+                dialog.handleMissingComment();
                 return;
             }
 
-            UploadStrategySpecification strategy = getUploadStrategySpecification();
+            UploadStrategySpecification strategy = dialog.getUploadStrategySpecification();
             if (strategy.getStrategy().equals(UploadStrategy.CHUNKED_DATASET_STRATEGY)
                     && strategy.getChunkSize() == UploadStrategySpecification.UNSPECIFIED_CHUNK_SIZE) {
                 warnIllegalChunkSize();
-                tpConfigPanels.setSelectedIndex(0);
+                dialog.handleIllegalChunkSize();
                 return;
             }
-            setCanceled(false);
-            setVisible(false);
-        }
-    }
-
-    /**
-     * Action for canceling the dialog
-     *
-     */
-    class CancelAction extends AbstractAction {
-        CancelAction() {
+            if (dialog instanceof AbstractUploadDialog) {
+                ((AbstractUploadDialog) dialog).setCanceled(false);
+                ((AbstractUploadDialog) dialog).setVisible(false);
+            }
+        }
+    }
+
+    /**
+     * Action for canceling the dialog.
+     */
+    static class CancelAction extends AbstractAction {
+
+        private final transient IUploadDialog dialog;
+
+        CancelAction(IUploadDialog dialog) {
+            this.dialog = dialog;
             putValue(NAME, tr("Cancel"));
             putValue(SMALL_ICON, ImageProvider.get("cancel"));
@@ -583,6 +570,8 @@
         @Override
         public void actionPerformed(ActionEvent e) {
-            setCanceled(true);
-            setVisible(false);
+            if (dialog instanceof AbstractUploadDialog) {
+                ((AbstractUploadDialog) dialog).setCanceled(true);
+                ((AbstractUploadDialog) dialog).setVisible(false);
+            }
         }
     }
@@ -665,3 +654,25 @@
         return getLastChangesetTagFromHistory(BasicUploadSettingsPanel.SOURCE_HISTORY_KEY, BasicUploadSettingsPanel.getDefaultSources());
     }
+
+    @Override
+    public Map<String, String> getTags(boolean keepEmpty) {
+        return pnlTagSettings.getTags(keepEmpty);
+    }
+
+    @Override
+    public void handleMissingComment() {
+        tpConfigPanels.setSelectedIndex(0);
+        pnlBasicUploadSettings.initEditingOfUploadComment();
+    }
+
+    @Override
+    public void handleMissingSource() {
+        tpConfigPanels.setSelectedIndex(0);
+        pnlBasicUploadSettings.initEditingOfUploadSource();
+    }
+
+    @Override
+    public void handleIllegalChunkSize() {
+        tpConfigPanels.setSelectedIndex(0);
+    }
 }
Index: /trunk/test/unit/org/openstreetmap/josm/gui/io/UploadDialogTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/gui/io/UploadDialogTest.java	(revision 9685)
+++ /trunk/test/unit/org/openstreetmap/josm/gui/io/UploadDialogTest.java	(revision 9685)
@@ -0,0 +1,92 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.io;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.openstreetmap.josm.JOSMFixture;
+
+/**
+ * Unit tests of {@link UploadDialog} class.
+ */
+public class UploadDialogTest {
+
+    /**
+     * Setup tests
+     */
+    @BeforeClass
+    public static void setUpBeforeClass() {
+        JOSMFixture.createUnitTestFixture().init();
+    }
+
+    private static IUploadDialog newUploadDialog(final String comment, final String source) {
+        return new IUploadDialog() {
+
+            @Override
+            public void rememberUserInput() {
+                // Do nothing
+            }
+
+            @Override
+            public boolean isCanceled() {
+                return false;
+            }
+
+            @Override
+            public void handleMissingSource() {
+                // Do nothing
+            }
+
+            @Override
+            public void handleMissingComment() {
+                // Do nothing
+            }
+
+            @Override
+            public void handleIllegalChunkSize() {
+                // Do nothing
+            }
+
+            @Override
+            public UploadStrategySpecification getUploadStrategySpecification() {
+                return new UploadStrategySpecification();
+            }
+
+            @Override
+            public String getUploadSource() {
+                return source;
+            }
+
+            @Override
+            public String getUploadComment() {
+                return comment;
+            }
+
+            @Override
+            public Map<String, String> getTags(boolean keepEmpty) {
+                return new ConcurrentHashMap<>();
+            }
+        };
+    }
+
+    /**
+     * Test of {@link UploadDialog.CancelAction} class.
+     */
+    @Test
+    public void testCancelAction() {
+        new UploadDialog.CancelAction(newUploadDialog(null, null)).actionPerformed(null);
+    }
+
+    /**
+     * Test of {@link UploadDialog.UploadAction} class.
+     */
+    @Test
+    public void testUploadAction() {
+        new UploadDialog.UploadAction(newUploadDialog("comment", "source")).actionPerformed(null);
+        new UploadDialog.UploadAction(newUploadDialog("", "source")).actionPerformed(null);
+        new UploadDialog.UploadAction(newUploadDialog("comment", "")).actionPerformed(null);
+        new UploadDialog.UploadAction(newUploadDialog("a comment long enough", "a source long enough")).actionPerformed(null);
+    }
+}
