Index: trunk/src/org/openstreetmap/josm/actions/AboutAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/AboutAction.java	(revision 2080)
+++ trunk/src/org/openstreetmap/josm/actions/AboutAction.java	(revision 2081)
@@ -61,5 +61,5 @@
                 manifest = true;
                 u = new URL("jar:" + Main.class.getProtectionDomain().getCodeSource().getLocation().toString()
-                    + "!/META-INF/MANIFEST.MF");
+                        + "!/META-INF/MANIFEST.MF");
             } catch (MalformedURLException e) {
                 e.printStackTrace();
Index: trunk/src/org/openstreetmap/josm/actions/ApiPreconditionChecker.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/ApiPreconditionChecker.java	(revision 2080)
+++ trunk/src/org/openstreetmap/josm/actions/ApiPreconditionChecker.java	(revision 2081)
@@ -4,6 +4,5 @@
 
 import java.util.Collection;
-import java.util.LinkedList;
-import java.util.List;
+import java.util.Collections;
 import java.util.Map.Entry;
 
@@ -12,4 +11,5 @@
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.actions.UploadAction.UploadHook;
+import org.openstreetmap.josm.data.APIDataSet;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Way;
@@ -21,6 +21,5 @@
 public class ApiPreconditionChecker implements UploadHook {
 
-    public boolean checkUpload(Collection<OsmPrimitive> add, Collection<OsmPrimitive> update,
-            Collection<OsmPrimitive> delete) {
+    public boolean checkUpload(APIDataSet apiData) {
         OsmApi api = OsmApi.getOsmApi();
         try {
@@ -36,9 +35,9 @@
 
             if (maxNodes > 0) {
-                if( !checkMaxNodes(add, maxNodes))
+                if( !checkMaxNodes(apiData.getPrimitivesToAdd(), maxNodes))
                     return false;
-                if( !checkMaxNodes(update, maxNodes))
+                if( !checkMaxNodes(apiData.getPrimitivesToUpdate(), maxNodes))
                     return false;
-                if( !checkMaxNodes(delete, maxNodes))
+                if( !checkMaxNodes(apiData.getPrimitivesToDelete(), maxNodes))
                     return false;
             }
@@ -46,5 +45,5 @@
             if (maxElements  > 0) {
                 int total = 0;
-                total = add.size() + update.size() + delete.size();
+                total = apiData.getPrimitivesToAdd().size() + apiData.getPrimitivesToUpdate().size() + apiData.getPrimitivesToDelete().size();
                 if(total > maxElements) {
                     JOptionPane.showMessageDialog(
@@ -67,6 +66,6 @@
     }
 
-    private boolean checkMaxNodes(Collection<OsmPrimitive> add, long maxNodes) {
-        for (OsmPrimitive osmPrimitive : add) {
+    private boolean checkMaxNodes(Collection<OsmPrimitive> primitives, long maxNodes) {
+        for (OsmPrimitive osmPrimitive : primitives) {
             for (Entry<String,String> e : osmPrimitive.entrySet()) {
                 if(e.getValue().length() > 255) {
@@ -90,7 +89,5 @@
                             JOptionPane.ERROR_MESSAGE
                     );
-                    List<OsmPrimitive> newNodes = new LinkedList<OsmPrimitive>();
-                    newNodes.add(osmPrimitive);
-                    Main.main.getCurrentDataSet().setSelected(newNodes);
+                    Main.main.getCurrentDataSet().setSelected(Collections.singleton(osmPrimitive));
                     return false;
                 }
@@ -109,8 +106,5 @@
                         JOptionPane.ERROR_MESSAGE
                 );
-                List<OsmPrimitive> newNodes = new LinkedList<OsmPrimitive>();
-                newNodes.add(osmPrimitive);
-
-                Main.main.getCurrentDataSet().setSelected(newNodes);
+                Main.main.getCurrentDataSet().setSelected(Collections.singleton(osmPrimitive));
                 return false;
             }
Index: trunk/src/org/openstreetmap/josm/actions/UploadAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/UploadAction.java	(revision 2080)
+++ trunk/src/org/openstreetmap/josm/actions/UploadAction.java	(revision 2081)
@@ -3,35 +3,16 @@
 
 import static org.openstreetmap.josm.tools.I18n.tr;
-import static org.openstreetmap.josm.tools.I18n.trn;
-
-import java.awt.BorderLayout;
-import java.awt.Dimension;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
+
 import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
 import java.awt.event.KeyEvent;
 import java.io.IOException;
 import java.net.HttpURLConnection;
 import java.util.Collection;
-import java.util.HashMap;
 import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
 import java.util.logging.Logger;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import javax.swing.BoxLayout;
-import javax.swing.ButtonGroup;
-import javax.swing.JCheckBox;
-import javax.swing.JLabel;
-import javax.swing.JList;
 import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JRadioButton;
-import javax.swing.JScrollPane;
-import javax.swing.JTabbedPane;
 
 import org.openstreetmap.josm.Main;
@@ -43,11 +24,8 @@
 import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
 import org.openstreetmap.josm.gui.ExceptionDialogUtil;
-import org.openstreetmap.josm.gui.ExtendedDialog;
-import org.openstreetmap.josm.gui.OsmPrimitivRenderer;
 import org.openstreetmap.josm.gui.PleaseWaitRunnable;
-import org.openstreetmap.josm.gui.historycombobox.SuggestingJHistoryComboBox;
+import org.openstreetmap.josm.gui.io.UploadDialog;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
-import org.openstreetmap.josm.gui.tagging.TagEditorPanel;
 import org.openstreetmap.josm.io.ChangesetProcessingType;
 import org.openstreetmap.josm.io.OsmApi;
@@ -56,7 +34,5 @@
 import org.openstreetmap.josm.io.OsmChangesetCloseException;
 import org.openstreetmap.josm.io.OsmServerWriter;
-import org.openstreetmap.josm.tools.GBC;
 import org.openstreetmap.josm.tools.Shortcut;
-import org.openstreetmap.josm.tools.WindowGeometry;
 import org.xml.sax.SAXException;
 
@@ -74,19 +50,4 @@
 public class UploadAction extends JosmAction{
     static private Logger logger = Logger.getLogger(UploadAction.class.getName());
-
-    public static final String HISTORY_KEY = "upload.comment.history";
-
-    /** Upload Hook */
-    public interface UploadHook {
-        /**
-         * Checks the upload.
-         * @param add The added primitives
-         * @param update The updated primitives
-         * @param delete The deleted primitives
-         * @return true, if the upload can continue
-         */
-        public boolean checkUpload(Collection<OsmPrimitive> add, Collection<OsmPrimitive> update, Collection<OsmPrimitive> delete);
-    }
-
     /**
      * The list of upload hooks. These hooks will be called one after the other
@@ -99,10 +60,6 @@
      * however, a plugin might also want to insert something after that.
      */
-    public final LinkedList<UploadHook> uploadHooks = new LinkedList<UploadHook>();
-
-    public UploadAction() {
-        super(tr("Upload to OSM..."), "upload", tr("Upload all changes to the OSM server."),
-                Shortcut.registerShortcut("file:upload", tr("File: {0}", tr("Upload to OSM...")), KeyEvent.VK_U, Shortcut.GROUPS_ALT1+Shortcut.GROUP_HOTKEY), true);
-
+    public static final LinkedList<UploadHook> uploadHooks = new LinkedList<UploadHook>();
+    static {
         /**
          * Checks server capabilities before upload.
@@ -115,4 +72,43 @@
          */
         uploadHooks.add(new UploadConfirmationHook());
+    }
+
+    /**
+     * Registers an upload hook. Adds the hook to the end of the list of upload hooks.
+     * 
+     * @param hook the upload hook. Ignored if null.
+     */
+    public static void registerUploadHook(UploadHook hook) {
+        if(hook == null) return;
+        if (!uploadHooks.contains(hook)) {
+            uploadHooks.add(hook);
+        }
+    }
+
+    /**
+     * Unregisters an upload hook. Removes the hook from the list of upload hooks.
+     * 
+     * @param hook the upload hook. Ignored if null.
+     */
+    public static void unregisterUploadHook(UploadHook hook) {
+        if(hook == null) return;
+        if (uploadHooks.contains(hook)) {
+            uploadHooks.remove(hook);
+        }
+    }
+
+    /** Upload Hook */
+    public interface UploadHook {
+        /**
+         * Checks the upload.
+         * @param apiDataSet the data to upload
+         */
+        public boolean checkUpload(APIDataSet apiDataSet);
+    }
+
+
+    public UploadAction() {
+        super(tr("Upload to OSM..."), "upload", tr("Upload all changes to the OSM server."),
+                Shortcut.registerShortcut("file:upload", tr("File: {0}", tr("Upload to OSM...")), KeyEvent.VK_U, Shortcut.GROUPS_ALT1+Shortcut.GROUP_HOTKEY), true);
     }
 
@@ -145,5 +141,5 @@
         // is one of these.
         for(UploadHook hook : uploadHooks)
-            if(!hook.checkUpload(apiData.getPrimitivesToAdd(), apiData.getPrimitivesToUpdate(), apiData.getPrimitivesToDelete()))
+            if(!hook.checkUpload(apiData))
                 return false;
 
@@ -180,6 +176,6 @@
                         Main.map.mapView.getEditLayer(),
                         apiData.getPrimitives(),
-                        UploadConfirmationHook.getUploadDialogPanel().getChangeset(),
-                        UploadConfirmationHook.getUploadDialogPanel().getChangesetProcessingType()
+                        UploadConfirmationHook.getUploadDialog().getChangeset(),
+                        UploadConfirmationHook.getUploadDialog().getChangesetProcessingType()
                 )
         );
@@ -461,54 +457,20 @@
 
     static public class UploadConfirmationHook implements UploadHook {
-        static private UploadDialogPanel uploadDialogPanel;
-
-        static public UploadDialogPanel getUploadDialogPanel() {
-            if (uploadDialogPanel == null) {
-                uploadDialogPanel = new UploadDialogPanel();
-            }
-            return uploadDialogPanel;
-        }
-
-        public boolean checkUpload(Collection<OsmPrimitive> add, Collection<OsmPrimitive> update, Collection<OsmPrimitive> delete) {
-            final UploadDialogPanel panel = getUploadDialogPanel();
-            panel.setUploadedPrimitives(add, update, delete);
-
-            ExtendedDialog dialog = new ExtendedDialog(
-                    Main.parent,
-                    tr("Upload these changes?"),
-                    new String[] {tr("Upload Changes"), tr("Cancel")}
-            ) {
-                @Override
-                public void setVisible(boolean visible) {
-                    if (visible) {
-                        new WindowGeometry(
-                                panel.getClass().getName(),
-                                WindowGeometry.centerInWindow(
-                                        JOptionPane.getFrameForComponent(Main.parent),
-                                        new Dimension(400,600)
-                                )
-                        ).apply(this);
-                        panel.startUserInput();
-                    } else {
-                        new WindowGeometry(this).remember(panel.getClass().getName());
-                    }
-                    super.setVisible(visible);
-                }
-            };
-
-            dialog.setButtonIcons(new String[] {"upload.png", "cancel.png"});
-            dialog.setContent(panel, false /* no scroll pane */);
-            while(true) {
-                dialog.showDialog();
-                int result = dialog.getValue();
-                // cancel pressed
-                if (result != 1) return false;
-                // don't allow empty commit message
-                if (! panel.hasChangesetComment()) {
-                    continue;
-                }
-                panel.rememberUserInput();
-                break;
-            }
+        static private UploadDialog uploadDialog;
+
+        static public UploadDialog getUploadDialog() {
+            if (uploadDialog == null) {
+                uploadDialog = new UploadDialog();
+            }
+            return uploadDialog;
+        }
+
+        public boolean checkUpload(APIDataSet apiData) {
+            final UploadDialog dialog = getUploadDialog();
+            dialog.setUploadedPrimitives(apiData.getPrimitivesToAdd(),apiData.getPrimitivesToUpdate(), apiData.getPrimitivesToDelete());
+            dialog.setVisible(true);
+            if (dialog.isCanceled())
+                return false;
+            dialog.rememberUserInput();
             return true;
         }
@@ -586,381 +548,3 @@
         }
     }
-
-    /**
-     * The panel displaying information about primitives to upload and providing
-     * UI widgets for entering the changeset comment and other configuration
-     * settings.
-     * 
-     */
-    static public class UploadDialogPanel extends JPanel {
-
-        /** the list with the added primitives */
-        private JList lstAdd;
-        private JLabel lblAdd;
-        private JScrollPane spAdd;
-        /** the list with the updated primitives */
-        private JList lstUpdate;
-        private JLabel lblUpdate;
-        private JScrollPane spUpdate;
-        /** the list with the deleted primitives */
-        private JList lstDelete;
-        private JLabel lblDelete;
-        private JScrollPane spDelete;
-        /** the panel containing the widgets for the lists of primitives */
-        private JPanel pnlLists;
-        /** checkbox for selecting whether an atomic upload is to be used  */
-        private JCheckBox cbUseAtomicUpload;
-        /** input field for changeset comment */
-        private SuggestingJHistoryComboBox cmt;
-        /** ui component for editing changeset tags */
-        private TagEditorPanel tagEditorPanel;
-        /** the tabbed pane used below of the list of primitives  */
-        private JTabbedPane southTabbedPane;
-        /** the button group with the changeset processing types */
-        private ButtonGroup bgChangesetHandlingOptions;
-        /** radio buttons for selecting a changeset processing type */
-        private Map<ChangesetProcessingType, JRadioButton> rbChangesetHandlingOptions;
-
-        /**
-         * builds the panel with the lists of primitives
-         * 
-         * @return the panel with the lists of primitives
-         */
-        protected JPanel buildListsPanel() {
-            pnlLists = new JPanel();
-            pnlLists.setLayout(new GridBagLayout());
-            // we don't add the lists yet, see setUploadPrimivies()
-            //
-            return pnlLists;
-        }
-
-        /**
-         * builds the panel with the ui components for controlling how the changeset
-         * should be processed (opening/closing a changeset)
-         * 
-         * @return the panel with the ui components for controlling how the changeset
-         * should be processed
-         */
-        protected JPanel buildChangesetHandlingControlPanel() {
-            JPanel pnl = new JPanel();
-            pnl.setLayout(new BoxLayout(pnl, BoxLayout.Y_AXIS));
-            bgChangesetHandlingOptions = new ButtonGroup();
-            rbChangesetHandlingOptions = new HashMap<ChangesetProcessingType, JRadioButton>();
-            ChangesetProcessingTypeChangedAction a = new ChangesetProcessingTypeChangedAction();
-            for(ChangesetProcessingType type: ChangesetProcessingType.values()) {
-                rbChangesetHandlingOptions.put(type, new JRadioButton());
-                rbChangesetHandlingOptions.get(type).addActionListener(a);
-            }
-            JRadioButton rb = rbChangesetHandlingOptions.get(ChangesetProcessingType.USE_NEW_AND_CLOSE);
-            rb.setText(tr("Use a new changeset and close it"));
-            rb.setToolTipText(tr("Select to upload the data using a new changeset and to close the changeset after the upload"));
-
-            rb = rbChangesetHandlingOptions.get(ChangesetProcessingType.USE_NEW_AND_LEAVE_OPEN);
-            rb.setText(tr("Use a new changeset and leave it open"));
-            rb.setToolTipText(tr("Select to upload the data using a new changeset and to leave the changeset open after the upload"));
-
-            pnl.add(new JLabel(tr("Upload to a new or to an existing changeset?")));
-            pnl.add(rbChangesetHandlingOptions.get(ChangesetProcessingType.USE_NEW_AND_CLOSE));
-            pnl.add(rbChangesetHandlingOptions.get(ChangesetProcessingType.USE_NEW_AND_LEAVE_OPEN));
-            pnl.add(rbChangesetHandlingOptions.get(ChangesetProcessingType.USE_EXISTING_AND_CLOSE));
-            pnl.add(rbChangesetHandlingOptions.get(ChangesetProcessingType.USE_EXISTING_AND_LEAVE_OPEN));
-
-            for(ChangesetProcessingType type: ChangesetProcessingType.values()) {
-                rbChangesetHandlingOptions.get(type).setVisible(false);
-                bgChangesetHandlingOptions.add(rbChangesetHandlingOptions.get(type));
-            }
-            return pnl;
-        }
-
-        /**
-         * build the panel with the widgets for controlling how the changeset should be processed
-         * (atomic upload or not, comment, opening/closing changeset)
-         * 
-         * @return
-         */
-        protected JPanel buildChangesetControlPanel() {
-            JPanel pnl = new JPanel();
-            pnl.setLayout(new BoxLayout(pnl, BoxLayout.Y_AXIS));
-            pnl.add(cbUseAtomicUpload = new JCheckBox(tr("upload all changes in one request")));
-            cbUseAtomicUpload.setToolTipText(tr("Enable to upload all changes in one request, disable to use one request per changed primitive"));
-            boolean useAtomicUpload = Main.pref.getBoolean("osm-server.atomic-upload", true);
-            cbUseAtomicUpload.setSelected(useAtomicUpload);
-            cbUseAtomicUpload.setEnabled(OsmApi.getOsmApi().hasSupportForDiffUploads());
-
-            pnl.add(buildChangesetHandlingControlPanel());
-            return pnl;
-        }
-
-        /**
-         * builds the upload control panel
-         * 
-         * @return
-         */
-        protected JPanel buildUploadControlPanel() {
-            JPanel pnl = new JPanel();
-            pnl.setLayout(new GridBagLayout());
-            pnl.add(new JLabel(tr("Provide a brief comment for the changes you are uploading:")), GBC.eol().insets(0, 5, 10, 3));
-            cmt = new SuggestingJHistoryComboBox();
-            List<String> cmtHistory = new LinkedList<String>(Main.pref.getCollection(HISTORY_KEY, new LinkedList<String>()));
-            cmt.setHistory(cmtHistory);
-            pnl.add(cmt, GBC.eol().fill(GBC.HORIZONTAL));
-
-            // configuration options for atomic upload
-            //
-            pnl.add(buildChangesetControlPanel(), GBC.eol().fill(GridBagConstraints.HORIZONTAL));
-            return pnl;
-        }
-
-        /**
-         * builds the gui
-         */
-        protected void build() {
-            setLayout(new GridBagLayout());
-            GridBagConstraints gc = new GridBagConstraints();
-
-            // first the panel with the list in the upper half
-            //
-            gc.fill = GridBagConstraints.BOTH;
-            gc.weightx = 1.0;
-            gc.weighty = 1.0;
-            add(buildListsPanel(), gc);
-
-            // a tabbed pane with two configuration panels in the
-            // lower half
-            //
-            southTabbedPane = new JTabbedPane();
-            southTabbedPane.add(buildUploadControlPanel());
-            tagEditorPanel = new TagEditorPanel();
-            southTabbedPane.add(tagEditorPanel);
-            southTabbedPane.setTitleAt(0, tr("Settings"));
-            southTabbedPane.setTitleAt(1, tr("Tags of new changeset"));
-            JPanel pnl = new JPanel();
-            pnl.setLayout(new BorderLayout());
-            pnl.add(southTabbedPane,BorderLayout.CENTER);
-            gc.fill = GridBagConstraints.HORIZONTAL;
-            gc.gridy = 1;
-            gc.weightx = 1.0;
-            gc.weighty = 0.0;
-            add(pnl, gc);
-        }
-
-        /**
-         * constructor
-         */
-        protected UploadDialogPanel() {
-            OsmPrimitivRenderer renderer = new OsmPrimitivRenderer();
-
-            // initialize the three lists for primitives
-            //
-            lstAdd = new JList();
-            lstAdd.setCellRenderer(renderer);
-            lstAdd.setVisibleRowCount(Math.min(lstAdd.getModel().getSize(), 10));
-            spAdd = new JScrollPane(lstAdd);
-            lblAdd = new JLabel(tr("Objects to add:"));
-
-            lstUpdate = new JList();
-            lstUpdate.setCellRenderer(renderer);
-            lstUpdate.setVisibleRowCount(Math.min(lstUpdate.getModel().getSize(), 10));
-            spUpdate = new JScrollPane(lstUpdate);
-            lblUpdate = new JLabel(tr("Objects to modify:"));
-
-            lstDelete = new JList();
-            lstDelete.setCellRenderer(renderer);
-            lstDelete.setVisibleRowCount(Math.min(lstDelete.getModel().getSize(), 10));
-            spDelete = new JScrollPane(lstDelete);
-            lblDelete = new JLabel(tr("Objects to delete:"));
-
-            // build the GUI
-            //
-            build();
-        }
-
-        /**
-         * sets the collection of primitives which will be uploaded
-         * 
-         * @param add  the collection of primitives to add
-         * @param update the collection of primitives to update
-         * @param delete the collection of primitives to delete
-         */
-        public void setUploadedPrimitives(Collection<OsmPrimitive> add, Collection<OsmPrimitive> update, Collection<OsmPrimitive> delete) {
-            lstAdd.setListData(add.toArray());
-            lstUpdate.setListData(update.toArray());
-            lstDelete.setListData(delete.toArray());
-
-
-            GridBagConstraints gcLabel = new GridBagConstraints();
-            gcLabel.fill = GridBagConstraints.HORIZONTAL;
-            gcLabel.weightx = 1.0;
-            gcLabel.weighty = 0.0;
-            gcLabel.anchor = GridBagConstraints.FIRST_LINE_START;
-
-            GridBagConstraints gcList = new GridBagConstraints();
-            gcList.fill = GridBagConstraints.BOTH;
-            gcList.weightx = 1.0;
-            gcList.weighty = 1.0;
-            gcList.anchor = GridBagConstraints.CENTER;
-            pnlLists.removeAll();
-            int y = -1;
-            if (!add.isEmpty()) {
-                y++;
-                gcLabel.gridy = y;
-                lblAdd.setText(trn("{0} object to add:", "{0} objects to add:", add.size(),add.size()));
-                pnlLists.add(lblAdd, gcLabel);
-                y++;
-                gcList.gridy = y;
-                pnlLists.add(spAdd, gcList);
-            }
-            if (!update.isEmpty()) {
-                y++;
-                gcLabel.gridy = y;
-                lblUpdate.setText(trn("{0} object to modifiy:", "{0} objects to modify:", update.size(),update.size()));
-                pnlLists.add(lblUpdate, gcLabel);
-                y++;
-                gcList.gridy = y;
-                pnlLists.add(spUpdate, gcList);
-            }
-            if (!delete.isEmpty()) {
-                y++;
-                gcLabel.gridy = y;
-                lblDelete.setText(trn("{0} object to delete:", "{0} objects to delete:", delete.size(),delete.size()));
-                pnlLists.add(lblDelete, gcLabel);
-                y++;
-                gcList.gridy = y;
-                pnlLists.add(spDelete, gcList);
-            }
-        }
-
-        /**
-         * Replies true if a valid changeset comment has been entered in this dialog
-         * 
-         * @return true if a valid changeset comment has been entered in this dialog
-         */
-        public boolean hasChangesetComment() {
-            if (!getChangesetProcessingType().isUseNew())
-                return true;
-            return cmt.getText().trim().length() >= 3;
-        }
-
-        /**
-         * Remembers the user input in the preference settings
-         */
-        public void rememberUserInput() {
-            // store the history of comments
-            cmt.addCurrentItemToHistory();
-            Main.pref.putCollection(HISTORY_KEY, cmt.getHistory());
-            Main.pref.put("osm-server.atomic-upload", cbUseAtomicUpload.isSelected());
-        }
-
-        /**
-         * Initializes the panel for user input
-         */
-        public void startUserInput() {
-            tagEditorPanel.initAutoCompletion(Main.main.getEditLayer());
-            initChangesetProcessingType();
-            cmt.getEditor().selectAll();
-            cmt.requestFocus();
-        }
-
-        /**
-         * Replies the current changeset processing type
-         * 
-         * @return the current changeset processing type
-         */
-        public ChangesetProcessingType getChangesetProcessingType() {
-            ChangesetProcessingType changesetProcessingType = null;
-            for (ChangesetProcessingType type: ChangesetProcessingType.values()) {
-                if (rbChangesetHandlingOptions.get(type).isSelected()) {
-                    changesetProcessingType = type;
-                    break;
-                }
-            }
-            return changesetProcessingType == null ?
-                    ChangesetProcessingType.USE_NEW_AND_CLOSE :
-                        changesetProcessingType;
-        }
-
-        /**
-         * Replies the current changeset
-         * 
-         * @return the current changeset
-         */
-        public Changeset getChangeset() {
-            Changeset changeset = new Changeset();
-            tagEditorPanel.getModel().applyToPrimitive(changeset);
-            changeset.put("comment", cmt.getText());
-            return changeset;
-        }
-
-        /**
-         * initializes the panel depending on the possible changeset processing
-         * types
-         */
-        protected void initChangesetProcessingType() {
-            for (ChangesetProcessingType type: ChangesetProcessingType.values()) {
-                // show options for new changeset, disable others
-                //
-                rbChangesetHandlingOptions.get(type).setVisible(type.isUseNew());
-            }
-            if (OsmApi.getOsmApi().getCurrentChangeset() != null) {
-                Changeset cs = OsmApi.getOsmApi().getCurrentChangeset();
-                for (ChangesetProcessingType type: ChangesetProcessingType.values()) {
-                    // show options for using existing changeset
-                    //
-                    if (!type.isUseNew()) {
-                        rbChangesetHandlingOptions.get(type).setVisible(true);
-                    }
-                }
-                JRadioButton rb = rbChangesetHandlingOptions.get(ChangesetProcessingType.USE_EXISTING_AND_CLOSE);
-                rb.setText(tr("Use the existing changeset {0} and close it after upload",cs.getId()));
-                rb.setToolTipText(tr("Select to upload to the existing changeset {0} and to close the changeset after this upload",cs.getId()));
-
-                rb = rbChangesetHandlingOptions.get(ChangesetProcessingType.USE_EXISTING_AND_LEAVE_OPEN);
-                rb.setText(tr("Use the existing changeset {0} and leave it open",cs.getId()));
-                rb.setToolTipText(tr("Select to upload to the existing changeset {0} and to leave the changeset open for further uploads",cs.getId()));
-
-                rbChangesetHandlingOptions.get(getChangesetProcessingType()).setSelected(true);
-
-            } else {
-                ChangesetProcessingType type = getChangesetProcessingType();
-                if (!type.isUseNew()) {
-                    type = ChangesetProcessingType.USE_NEW_AND_CLOSE;
-                }
-                rbChangesetHandlingOptions.get(type).setSelected(true);
-            }
-            refreshChangesetProcessingType(getChangesetProcessingType());
-        }
-
-        /**
-         * refreshes  the panel depending on a changeset processing type
-         * 
-         * @param type the changeset processing type
-         */
-        protected void refreshChangesetProcessingType(ChangesetProcessingType type) {
-            if (type.isUseNew()) {
-                southTabbedPane.setTitleAt(1, tr("Tags of new changeset"));
-                Changeset cs = new Changeset();
-                Properties sysProp = System.getProperties();
-                Object ua = sysProp.get("http.agent");
-                cs.put("created_by", (ua == null) ? "JOSM" : ua.toString());
-                tagEditorPanel.getModel().initFromPrimitive(cs);
-            } else {
-                Changeset cs = OsmApi.getOsmApi().getCurrentChangeset();
-                if (cs != null) {
-                    southTabbedPane.setTitleAt(1, tr("Tags of changeset {0}", cs.getId()));
-                    if (cs.get("comment") != null) {
-                        cmt.setText(cs.get("comment"));
-                        cs.remove("comment");
-                    }
-                    tagEditorPanel.getModel().initFromPrimitive(cs);
-                }
-            }
-        }
-
-        class ChangesetProcessingTypeChangedAction implements ActionListener {
-            public void actionPerformed(ActionEvent e) {
-                ChangesetProcessingType type = getChangesetProcessingType();
-                refreshChangesetProcessingType(type);
-            }
-        }
-    }
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/Changeset.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/Changeset.java	(revision 2080)
+++ trunk/src/org/openstreetmap/josm/data/osm/Changeset.java	(revision 2081)
@@ -3,4 +3,6 @@
 
 import static org.openstreetmap.josm.tools.I18n.tr;
+
+import javax.print.attribute.standard.MediaSize.Other;
 
 import org.openstreetmap.josm.data.osm.visitor.Visitor;
@@ -23,4 +25,17 @@
      */
     public String start_timestamp = null;
+
+    public Changeset() {
+        super(0);
+    }
+
+    public Changeset(long id) {
+        super(id);
+    }
+
+    public Changeset(Changeset clone){
+        super(clone.getId());
+        cloneFrom(clone);
+    }
 
     @Override
@@ -49,3 +64,8 @@
         return formatter.format(this);
     }
+
+
+    @Override public void cloneFrom(OsmPrimitive osm) {
+        super.cloneFrom(osm);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/MainApplication.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MainApplication.java	(revision 2080)
+++ trunk/src/org/openstreetmap/josm/gui/MainApplication.java	(revision 2081)
@@ -87,6 +87,4 @@
         }
 
-        Main.pref.init(args.containsKey("reset-preferences"));
-
         // Check if passed as parameter
         if (args.containsKey("language")) {
@@ -95,4 +93,7 @@
             I18n.set(Main.pref.get("language", null));
         }
+
+        Main.pref.init(args.containsKey("reset-preferences"));
+
 
         if (argList.contains("--help") || argList.contains("-?") || argList.contains("-h")) {
@@ -115,5 +116,5 @@
                     "\t-Djosm.home="+tr("/PATH/TO/JOSM/FOLDER/         ")+tr("Change the folder for all user settings")+"\n\n"+
                     tr("note: For some tasks, JOSM needs a lot of memory. It can be necessary to add the following\n" +
-                       "      Java option to increase the maximum size of allocated memory")+":\n"+
+                    "      Java option to increase the maximum size of allocated memory")+":\n"+
                     "\t-Xmx...m\n\n"+
                     tr("examples")+":\n"+
Index: trunk/src/org/openstreetmap/josm/gui/io/SaveLayersDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/io/SaveLayersDialog.java	(revision 2080)
+++ trunk/src/org/openstreetmap/josm/gui/io/SaveLayersDialog.java	(revision 2081)
@@ -299,6 +299,6 @@
         public void cancel() {
             switch(model.getMode()) {
-                case EDITING_DATA: cancelWhenInEditingModel(); break;
-                case UPLOADING_AND_SAVING: cancelSafeAndUploadTask(); break;
+            case EDITING_DATA: cancelWhenInEditingModel(); break;
+            case UPLOADING_AND_SAVING: cancelSafeAndUploadTask(); break;
             }
         }
@@ -334,6 +334,6 @@
                 Mode mode = (Mode)evt.getNewValue();
                 switch(mode) {
-                    case EDITING_DATA: setEnabled(true); break;
-                    case UPLOADING_AND_SAVING: setEnabled(false); break;
+                case EDITING_DATA: setEnabled(true); break;
+                case UPLOADING_AND_SAVING: setEnabled(false); break;
                 }
             }
@@ -368,6 +368,6 @@
                 SaveLayersModel.Mode mode = (SaveLayersModel.Mode)evt.getNewValue();
                 switch(mode) {
-                    case EDITING_DATA: setEnabled(true); break;
-                    case UPLOADING_AND_SAVING: setEnabled(false); break;
+                case EDITING_DATA: setEnabled(true); break;
+                case UPLOADING_AND_SAVING: setEnabled(false); break;
                 }
             }
@@ -411,6 +411,6 @@
                         layerInfo.getLayer(),
                         monitor,
-                        UploadAction.UploadConfirmationHook.getUploadDialogPanel().getChangeset(),
-                        UploadAction.UploadConfirmationHook.getUploadDialogPanel().getChangesetProcessingType()
+                        UploadAction.UploadConfirmationHook.getUploadDialog().getChangeset(),
+                        UploadAction.UploadConfirmationHook.getUploadDialog().getChangesetProcessingType()
                 );
                 currentFuture = worker.submit(currentTask);
Index: trunk/src/org/openstreetmap/josm/gui/io/UploadDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/io/UploadDialog.java	(revision 2081)
+++ trunk/src/org/openstreetmap/josm/gui/io/UploadDialog.java	(revision 2081)
@@ -0,0 +1,672 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.io;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+import static org.openstreetmap.josm.tools.I18n.trn;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import javax.swing.AbstractAction;
+import javax.swing.AbstractListModel;
+import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
+import javax.swing.ButtonGroup;
+import javax.swing.JCheckBox;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JScrollPane;
+import javax.swing.JTabbedPane;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.osm.Changeset;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.gui.OsmPrimitivRenderer;
+import org.openstreetmap.josm.gui.SideButton;
+import org.openstreetmap.josm.gui.historycombobox.SuggestingJHistoryComboBox;
+import org.openstreetmap.josm.gui.tagging.TagEditorModel;
+import org.openstreetmap.josm.gui.tagging.TagEditorPanel;
+import org.openstreetmap.josm.gui.tagging.TagModel;
+import org.openstreetmap.josm.io.ChangesetProcessingType;
+import org.openstreetmap.josm.io.OsmApi;
+import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.WindowGeometry;
+
+/**
+ * This is a dialog for entering upload options like the parameters for
+ * the upload changeset and the strategy for opening/closing a changeset.
+ * 
+ * 
+ */
+public class UploadDialog extends JDialog {
+
+    public static final String HISTORY_KEY = "upload.comment.history";
+
+    /** the list with the added primitives */
+    private PrimitiveList lstAdd;
+    private JLabel lblAdd;
+    private JScrollPane spAdd;
+    /** the list with the updated primitives */
+    private PrimitiveList lstUpdate;
+    private JLabel lblUpdate;
+    private JScrollPane spUpdate;
+    /** the list with the deleted primitives */
+    private PrimitiveList lstDelete;
+    private JLabel lblDelete;
+    private JScrollPane spDelete;
+    /** the panel containing the widgets for the lists of primitives */
+    private JPanel pnlLists;
+    /** checkbox for selecting whether an atomic upload is to be used  */
+    private JCheckBox cbUseAtomicUpload;
+    /** input field for changeset comment */
+    private SuggestingJHistoryComboBox cmt;
+    /** ui component for editing changeset tags */
+    private TagEditorPanel tagEditorPanel;
+    /** the tabbed pane used below of the list of primitives  */
+    private JTabbedPane southTabbedPane;
+    /** the button group with the changeset processing types */
+    private ButtonGroup bgChangesetHandlingOptions;
+    /** radio buttons for selecting a changeset processing type */
+    private Map<ChangesetProcessingType, JRadioButton> rbChangesetHandlingOptions;
+
+    private boolean canceled = false;
+
+    /**
+     * builds the panel with the lists of primitives
+     * 
+     * @return the panel with the lists of primitives
+     */
+    protected JPanel buildListsPanel() {
+        pnlLists = new JPanel();
+        pnlLists.setLayout(new GridBagLayout());
+        // we don't add the lists yet, see setUploadPrimivies()
+        //
+        return pnlLists;
+    }
+
+    /**
+     * builds the panel with the ui components for controlling how the changeset
+     * should be processed (opening/closing a changeset)
+     * 
+     * @return the panel with the ui components for controlling how the changeset
+     * should be processed
+     */
+    protected JPanel buildChangesetHandlingControlPanel() {
+        JPanel pnl = new JPanel();
+        pnl.setLayout(new BoxLayout(pnl, BoxLayout.Y_AXIS));
+        bgChangesetHandlingOptions = new ButtonGroup();
+        rbChangesetHandlingOptions = new HashMap<ChangesetProcessingType, JRadioButton>();
+        ChangesetProcessingTypeChangedAction a = new ChangesetProcessingTypeChangedAction();
+        for(ChangesetProcessingType type: ChangesetProcessingType.values()) {
+            rbChangesetHandlingOptions.put(type, new JRadioButton());
+            rbChangesetHandlingOptions.get(type).addActionListener(a);
+        }
+        JRadioButton rb = rbChangesetHandlingOptions.get(ChangesetProcessingType.USE_NEW_AND_CLOSE);
+        rb.setText(tr("Use a new changeset and close it"));
+        rb.setToolTipText(tr("Select to upload the data using a new changeset and to close the changeset after the upload"));
+
+        rb = rbChangesetHandlingOptions.get(ChangesetProcessingType.USE_NEW_AND_LEAVE_OPEN);
+        rb.setText(tr("Use a new changeset and leave it open"));
+        rb.setToolTipText(tr("Select to upload the data using a new changeset and to leave the changeset open after the upload"));
+
+        pnl.add(new JLabel(tr("Upload to a new or to an existing changeset?")));
+        pnl.add(rbChangesetHandlingOptions.get(ChangesetProcessingType.USE_NEW_AND_CLOSE));
+        pnl.add(rbChangesetHandlingOptions.get(ChangesetProcessingType.USE_NEW_AND_LEAVE_OPEN));
+        pnl.add(rbChangesetHandlingOptions.get(ChangesetProcessingType.USE_EXISTING_AND_CLOSE));
+        pnl.add(rbChangesetHandlingOptions.get(ChangesetProcessingType.USE_EXISTING_AND_LEAVE_OPEN));
+
+        for(ChangesetProcessingType type: ChangesetProcessingType.values()) {
+            rbChangesetHandlingOptions.get(type).setVisible(false);
+            bgChangesetHandlingOptions.add(rbChangesetHandlingOptions.get(type));
+        }
+        return pnl;
+    }
+
+    /**
+     * build the panel with the widgets for controlling how the changeset should be processed
+     * (atomic upload or not, comment, opening/closing changeset)
+     * 
+     * @return
+     */
+    protected JPanel buildChangesetControlPanel() {
+        JPanel pnl = new JPanel();
+        pnl.setLayout(new BoxLayout(pnl, BoxLayout.Y_AXIS));
+        pnl.add(cbUseAtomicUpload = new JCheckBox(tr("upload all changes in one request")));
+        cbUseAtomicUpload.setToolTipText(tr("Enable to upload all changes in one request, disable to use one request per changed primitive"));
+        boolean useAtomicUpload = Main.pref.getBoolean("osm-server.atomic-upload", true);
+        cbUseAtomicUpload.setSelected(useAtomicUpload);
+        cbUseAtomicUpload.setEnabled(OsmApi.getOsmApi().hasSupportForDiffUploads());
+
+        pnl.add(buildChangesetHandlingControlPanel());
+        return pnl;
+    }
+
+    /**
+     * builds the upload control panel
+     * 
+     * @return
+     */
+    protected JPanel buildUploadControlPanel() {
+        JPanel pnl = new JPanel();
+        pnl.setLayout(new GridBagLayout());
+        pnl.add(new JLabel(tr("Provide a brief comment for the changes you are uploading:")), GBC.eol().insets(0, 5, 10, 3));
+        cmt = new SuggestingJHistoryComboBox();
+        List<String> cmtHistory = new LinkedList<String>(Main.pref.getCollection(HISTORY_KEY, new LinkedList<String>()));
+        cmt.setHistory(cmtHistory);
+        cmt.getEditor().addActionListener(
+                new ActionListener() {
+                    public void actionPerformed(ActionEvent e) {
+                        TagModel tm = tagEditorPanel.getModel().get("comment");
+                        if (tm == null) {
+                            tagEditorPanel.getModel().add(new TagModel("comment", cmt.getText()));
+                        } else {
+                            tm.setValue(cmt.getText());
+                        }
+                        tagEditorPanel.getModel().fireTableDataChanged();
+                    }
+                }
+        );
+        pnl.add(cmt, GBC.eol().fill(GBC.HORIZONTAL));
+
+        // configuration options for atomic upload
+        //
+        pnl.add(buildChangesetControlPanel(), GBC.eol().fill(GridBagConstraints.HORIZONTAL));
+        return pnl;
+    }
+
+    protected JPanel buildContentPanel() {
+        JPanel pnl = new JPanel();
+        pnl.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+        pnl.setLayout(new GridBagLayout());
+        GridBagConstraints gc = new GridBagConstraints();
+
+        // first the panel with the list in the upper half
+        //
+        gc.fill = GridBagConstraints.BOTH;
+        gc.weightx = 1.0;
+        gc.weighty = 1.0;
+        pnl.add(buildListsPanel(), gc);
+
+        // a tabbed pane with two configuration panels in the
+        // lower half
+        //
+        southTabbedPane = new JTabbedPane();
+        southTabbedPane.add(buildUploadControlPanel());
+        tagEditorPanel = new TagEditorPanel();
+        southTabbedPane.add(tagEditorPanel);
+        southTabbedPane.setTitleAt(0, tr("Settings"));
+        southTabbedPane.setTitleAt(1, tr("Tags of new changeset"));
+        southTabbedPane.addChangeListener(new TabbedPaneChangeLister());
+        JPanel pnl1 = new JPanel();
+        pnl1.setLayout(new BorderLayout());
+        pnl1.add(southTabbedPane,BorderLayout.CENTER);
+        gc.fill = GridBagConstraints.HORIZONTAL;
+        gc.gridy = 1;
+        gc.weightx = 1.0;
+        gc.weighty = 0.0;
+        pnl.add(pnl1, gc);
+        return pnl;
+    }
+
+    protected JPanel buildActionPanel() {
+        JPanel pnl = new JPanel();
+        pnl.setLayout(new FlowLayout(FlowLayout.CENTER));
+        pnl.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+
+        // -- upload button
+        pnl.add(new SideButton(new UploadAction()));
+
+        // -- cancel button
+        pnl.add(new SideButton(new CancelAction()));
+
+        return pnl;
+    }
+
+    /**
+     * builds the gui
+     */
+    protected void build() {
+        getContentPane().setLayout(new BorderLayout());
+        getContentPane().add(buildContentPanel(), BorderLayout.CENTER);
+        getContentPane().add(buildActionPanel(), BorderLayout.SOUTH);
+
+        addWindowListener(new WindowClosingAdapter());
+    }
+
+    /**
+     * constructor
+     */
+    public UploadDialog() {
+        super(JOptionPane.getFrameForComponent(Main.parent), true /* modal */);
+        OsmPrimitivRenderer renderer = new OsmPrimitivRenderer();
+
+        // initialize the three lists for primitives
+        //
+        lstAdd = new PrimitiveList();
+        lstAdd.setCellRenderer(renderer);
+        lstAdd.setVisibleRowCount(Math.min(lstAdd.getModel().getSize(), 10));
+        spAdd = new JScrollPane(lstAdd);
+        lblAdd = new JLabel(tr("Objects to add:"));
+
+        lstUpdate = new PrimitiveList();
+        lstUpdate.setCellRenderer(renderer);
+        lstUpdate.setVisibleRowCount(Math.min(lstUpdate.getModel().getSize(), 10));
+        spUpdate = new JScrollPane(lstUpdate);
+        lblUpdate = new JLabel(tr("Objects to modify:"));
+
+        lstDelete = new PrimitiveList();
+        lstDelete.setCellRenderer(renderer);
+        lstDelete.setVisibleRowCount(Math.min(lstDelete.getModel().getSize(), 10));
+        spDelete = new JScrollPane(lstDelete);
+        lblDelete = new JLabel(tr("Objects to delete:"));
+
+        // build the GUI
+        //
+        build();
+    }
+
+    /**
+     * sets the collection of primitives which will be uploaded
+     * 
+     * @param add  the collection of primitives to add
+     * @param update the collection of primitives to update
+     * @param delete the collection of primitives to delete
+     */
+    public void setUploadedPrimitives(List<OsmPrimitive> add, List<OsmPrimitive> update, List<OsmPrimitive> delete) {
+        lstAdd.getPrimitiveListModel().setPrimitives(add);
+        lstUpdate.getPrimitiveListModel().setPrimitives(update);
+        lstDelete.getPrimitiveListModel().setPrimitives(delete);
+
+        GridBagConstraints gcLabel = new GridBagConstraints();
+        gcLabel.fill = GridBagConstraints.HORIZONTAL;
+        gcLabel.weightx = 1.0;
+        gcLabel.weighty = 0.0;
+        gcLabel.anchor = GridBagConstraints.FIRST_LINE_START;
+
+        GridBagConstraints gcList = new GridBagConstraints();
+        gcList.fill = GridBagConstraints.BOTH;
+        gcList.weightx = 1.0;
+        gcList.weighty = 1.0;
+        gcList.anchor = GridBagConstraints.CENTER;
+        pnlLists.removeAll();
+        int y = -1;
+        if (!add.isEmpty()) {
+            y++;
+            gcLabel.gridy = y;
+            lblAdd.setText(trn("{0} object to add:", "{0} objects to add:", add.size(),add.size()));
+            pnlLists.add(lblAdd, gcLabel);
+            y++;
+            gcList.gridy = y;
+            pnlLists.add(spAdd, gcList);
+        }
+        if (!update.isEmpty()) {
+            y++;
+            gcLabel.gridy = y;
+            lblUpdate.setText(trn("{0} object to modifiy:", "{0} objects to modify:", update.size(),update.size()));
+            pnlLists.add(lblUpdate, gcLabel);
+            y++;
+            gcList.gridy = y;
+            pnlLists.add(spUpdate, gcList);
+        }
+        if (!delete.isEmpty()) {
+            y++;
+            gcLabel.gridy = y;
+            lblDelete.setText(trn("{0} object to delete:", "{0} objects to delete:", delete.size(),delete.size()));
+            pnlLists.add(lblDelete, gcLabel);
+            y++;
+            gcList.gridy = y;
+            pnlLists.add(spDelete, gcList);
+        }
+    }
+
+    /**
+     * Replies true if a valid changeset comment has been entered in this dialog
+     * 
+     * @return true if a valid changeset comment has been entered in this dialog
+     */
+    public boolean hasChangesetComment() {
+        if (!getChangesetProcessingType().isUseNew())
+            return true;
+        return cmt.getText().trim().length() >= 3;
+    }
+
+    /**
+     * Remembers the user input in the preference settings
+     */
+    public void rememberUserInput() {
+        // store the history of comments
+        cmt.addCurrentItemToHistory();
+        Main.pref.putCollection(HISTORY_KEY, cmt.getHistory());
+        Main.pref.put("osm-server.atomic-upload", cbUseAtomicUpload.isSelected());
+    }
+
+    /**
+     * Initializes the panel for user input
+     */
+    public void startUserInput() {
+        tagEditorPanel.initAutoCompletion(Main.main.getEditLayer());
+        initChangesetProcessingType();
+        cmt.getEditor().selectAll();
+        cmt.requestFocus();
+    }
+
+    /**
+     * Replies the current changeset processing type
+     * 
+     * @return the current changeset processing type
+     */
+    public ChangesetProcessingType getChangesetProcessingType() {
+        ChangesetProcessingType changesetProcessingType = null;
+        for (ChangesetProcessingType type: ChangesetProcessingType.values()) {
+            if (rbChangesetHandlingOptions.get(type).isSelected()) {
+                changesetProcessingType = type;
+                break;
+            }
+        }
+        return changesetProcessingType == null ?
+                ChangesetProcessingType.USE_NEW_AND_CLOSE :
+                    changesetProcessingType;
+    }
+
+    /**
+     * Replies the current changeset
+     * 
+     * @return the current changeset
+     */
+    public Changeset getChangeset() {
+        Changeset changeset = new Changeset();
+        tagEditorPanel.getModel().applyToPrimitive(changeset);
+        changeset.put("comment", cmt.getText());
+        return changeset;
+    }
+
+    /**
+     * initializes the panel depending on the possible changeset processing
+     * types
+     */
+    protected void initChangesetProcessingType() {
+        for (ChangesetProcessingType type: ChangesetProcessingType.values()) {
+            // show options for new changeset, disable others
+            //
+            rbChangesetHandlingOptions.get(type).setVisible(type.isUseNew());
+        }
+        if (OsmApi.getOsmApi().getCurrentChangeset() != null) {
+            Changeset cs = OsmApi.getOsmApi().getCurrentChangeset();
+            for (ChangesetProcessingType type: ChangesetProcessingType.values()) {
+                // show options for using existing changeset
+                //
+                if (!type.isUseNew()) {
+                    rbChangesetHandlingOptions.get(type).setVisible(true);
+                }
+            }
+            JRadioButton rb = rbChangesetHandlingOptions.get(ChangesetProcessingType.USE_EXISTING_AND_CLOSE);
+            rb.setText(tr("Use the existing changeset {0} and close it after upload",cs.getId()));
+            rb.setToolTipText(tr("Select to upload to the existing changeset {0} and to close the changeset after this upload",cs.getId()));
+
+            rb = rbChangesetHandlingOptions.get(ChangesetProcessingType.USE_EXISTING_AND_LEAVE_OPEN);
+            rb.setText(tr("Use the existing changeset {0} and leave it open",cs.getId()));
+            rb.setToolTipText(tr("Select to upload to the existing changeset {0} and to leave the changeset open for further uploads",cs.getId()));
+
+            rbChangesetHandlingOptions.get(getChangesetProcessingType()).setSelected(true);
+
+        } else {
+            ChangesetProcessingType type = getChangesetProcessingType();
+            if (!type.isUseNew()) {
+                type = ChangesetProcessingType.USE_NEW_AND_CLOSE;
+            }
+            rbChangesetHandlingOptions.get(type).setSelected(true);
+        }
+        ChangesetProcessingType type = getChangesetProcessingType();
+        if (type.isUseNew() || (! type.isUseNew() && OsmApi.getOsmApi().getCurrentChangeset() == null)) {
+            Changeset cs = new Changeset();
+            cs.put("created_by", getDefaultCreatedBy());
+            tagEditorPanel.getModel().initFromPrimitive(cs);
+        } else {
+            Changeset cs = OsmApi.getOsmApi().getCurrentChangeset();
+            tagEditorPanel.getModel().initFromPrimitive(cs);
+        }
+    }
+
+    /**
+     * Replies the default value for "created_by"
+     * 
+     * @return the default value for "created_by"
+     */
+    protected String getDefaultCreatedBy() {
+        Object ua = System.getProperties().get("http.agent");
+        return(ua == null) ? "JOSM" : ua.toString();
+    }
+
+    /**
+     * refreshes  the panel depending on a changeset processing type
+     * 
+     * @param type the changeset processing type
+     */
+    protected void switchToProcessingType(ChangesetProcessingType type) {
+        if (type.isUseNew()) {
+            southTabbedPane.setTitleAt(1, tr("Tags of new changeset"));
+            // init a new changeset from the currently edited tags
+            // and the comment field
+            //
+            Changeset cs = new Changeset(getChangeset());
+            if (cs.get("created_by") == null) {
+                cs.put("created_by", getDefaultCreatedBy());
+            }
+            cs.put("comment", this.cmt.getText());
+            tagEditorPanel.getModel().initFromPrimitive(cs);
+        } else {
+            Changeset cs = OsmApi.getOsmApi().getCurrentChangeset();
+            if (cs != null) {
+                cs.put("comment", this.cmt.getText());
+                cs.setKeys(getChangeset().getKeys());
+                southTabbedPane.setTitleAt(1, tr("Tags of changeset {0}", cs.getId()));
+                tagEditorPanel.getModel().initFromPrimitive(cs);
+            }
+        }
+    }
+
+    public String getUploadComment() {
+        switch(southTabbedPane.getSelectedIndex()) {
+        case 0: return cmt.getText();
+        case 1:
+            TagModel tm = tagEditorPanel.getModel().get("comment");
+            return tm == null? "" : tm.getValue();
+        }
+        return "";
+    }
+
+    public boolean isCanceled() {
+        return canceled;
+    }
+
+    protected void setCanceled(boolean canceled) {
+        this.canceled = canceled;
+    }
+
+    @Override
+    public void setVisible(boolean visible) {
+        if (visible) {
+            new WindowGeometry(
+                    getClass().getName() + ".geometry",
+                    WindowGeometry.centerInWindow(
+                            JOptionPane.getFrameForComponent(Main.parent),
+                            new Dimension(400,600)
+                    )
+            ).apply(this);
+            startUserInput();
+        } else {
+            new WindowGeometry(this).remember(getClass().getName() + ".geometry");
+        }
+        super.setVisible(visible);
+    }
+
+    class ChangesetProcessingTypeChangedAction implements ActionListener {
+        public void actionPerformed(ActionEvent e) {
+            ChangesetProcessingType type = getChangesetProcessingType();
+            switchToProcessingType(type);
+        }
+    }
+
+
+    class TabbedPaneChangeLister implements ChangeListener {
+
+        protected boolean hasCommentTag() {
+            TagEditorModel model = tagEditorPanel.getModel();
+            return model.get("comment") != null;
+        }
+
+        protected TagModel getEmptyTag() {
+            TagEditorModel model = tagEditorPanel.getModel();
+            TagModel tm = model.get("");
+            if (tm != null) return tm;
+            tm = new TagModel("", "");
+            model.add(tm);
+            return tm;
+        }
+        protected TagModel getOrCreateCommentTag() {
+            TagEditorModel model = tagEditorPanel.getModel();
+            if (hasCommentTag())
+                return model.get("comment");
+            TagModel tm = getEmptyTag();
+            tm.setName("comment");
+            return tm;
+        }
+
+        protected void removeCommentTag() {
+            TagEditorModel model = tagEditorPanel.getModel();
+            model.delete("comment");
+        }
+
+        protected void refreshCommentTag() {
+            TagModel tm = getOrCreateCommentTag();
+            tm.setName("comment");
+            tm.setValue(cmt.getText().trim());
+            if (cmt.getText().trim().equals("")) {
+                removeCommentTag();
+            }
+            tagEditorPanel.getModel().fireTableDataChanged();
+        }
+
+
+        public void stateChanged(ChangeEvent e) {
+            if (southTabbedPane.getSelectedIndex() ==0) {
+                TagModel tm = tagEditorPanel.getModel().get("comment");
+                cmt.setText(tm == null ? "" : tm.getValue());
+                cmt.getEditor().selectAll();
+                cmt.requestFocus();
+            } else if (southTabbedPane.getSelectedIndex() == 1) {
+                refreshCommentTag();
+            }
+        }
+    }
+
+    class UploadAction extends AbstractAction {
+        public UploadAction() {
+            putValue(NAME, tr("Upload Changes"));
+            putValue(SMALL_ICON, ImageProvider.get("upload"));
+            putValue(SHORT_DESCRIPTION, tr("Upload the changed primitives"));
+        }
+
+        protected void warnIllegalUploadComment() {
+            JOptionPane.showMessageDialog(
+                    UploadDialog.this,
+                    tr("Please enter a comment for this upload changeset (min. 3 characters)"),
+                    tr("Illegal upload comment"),
+                    JOptionPane.ERROR_MESSAGE
+
+            );
+        }
+        public void actionPerformed(ActionEvent e) {
+            if (getUploadComment().trim().length() < 3) {
+                warnIllegalUploadComment();
+                cmt.getEditor().selectAll();
+                cmt.requestFocus();
+                return;
+            }
+            setCanceled(false);
+            setVisible(false);
+
+        }
+    }
+
+    class CancelAction extends AbstractAction {
+        public CancelAction() {
+            putValue(NAME, tr("Cancel"));
+            putValue(SMALL_ICON, ImageProvider.get("cancel"));
+            putValue(SHORT_DESCRIPTION, tr("Cancel the upload and resume editing"));
+        }
+
+
+        public void actionPerformed(ActionEvent e) {
+            setCanceled(true);
+            setVisible(false);
+        }
+    }
+
+    class PrimitiveList extends JList {
+        public PrimitiveList() {
+            super(new PrimitiveListModel());
+        }
+
+        public PrimitiveListModel getPrimitiveListModel() {
+            return (PrimitiveListModel)getModel();
+        }
+    }
+
+    class PrimitiveListModel extends AbstractListModel{
+        private List<OsmPrimitive> primitives;
+
+        public PrimitiveListModel() {
+            primitives = new ArrayList<OsmPrimitive>();
+        }
+
+        public PrimitiveListModel(List<OsmPrimitive> primitives) {
+            setPrimitives(primitives);
+        }
+
+        public void setPrimitives(List<OsmPrimitive> primitives) {
+            if (primitives == null) {
+                this.primitives = new ArrayList<OsmPrimitive>();
+            } else {
+                this.primitives = primitives;
+            }
+            fireContentsChanged(this,0,getSize());
+        }
+
+        public Object getElementAt(int index) {
+            if (primitives == null) return null;
+            return primitives.get(index);
+        }
+
+        public int getSize() {
+            if (primitives == null) return 0;
+            return primitives.size();
+        }
+    }
+
+    class WindowClosingAdapter extends WindowAdapter {
+        @Override
+        public void windowClosing(WindowEvent e) {
+            setCanceled(true);
+        }
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/tagging/TagEditorModel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/TagEditorModel.java	(revision 2080)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/TagEditorModel.java	(revision 2081)
@@ -9,4 +9,5 @@
 import java.util.Collection;
 import java.util.Comparator;
+import java.util.Iterator;
 import java.util.List;
 import java.util.logging.Logger;
@@ -216,4 +217,21 @@
 
     /**
+     * Deletes all tags with name <code>name</code>
+     * 
+     * @param name the name. Ignored if null.
+     */
+    public void delete(String name) {
+        if (name == null) return;
+        Iterator<TagModel> it = tags.iterator();
+        while(it.hasNext()) {
+            TagModel tm = it.next();
+            if (tm.getName().equals(name)) {
+                it.remove();
+            }
+        }
+        fireTableDataChanged();
+        setDirty(true);
+    }
+    /**
      * deletes the tags given by tagIndices
      *
Index: trunk/src/org/openstreetmap/josm/io/OsmServerWriter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/OsmServerWriter.java	(revision 2080)
+++ trunk/src/org/openstreetmap/josm/io/OsmServerWriter.java	(revision 2081)
@@ -7,9 +7,7 @@
 import java.util.Collection;
 import java.util.LinkedList;
-import java.util.List;
 import java.util.logging.Logger;
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.actions.UploadAction;
 import org.openstreetmap.josm.data.osm.Changeset;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
@@ -61,19 +59,4 @@
         time_left_str += Integer.toString(seconds_left);
         return time_left_str;
-    }
-
-    /**
-     * retrieves the most recent changeset comment from the preferences
-     *
-     * @return the most recent changeset comment
-     */
-    protected String getChangesetComment() {
-        String cmt = "";
-        List<String> history = new LinkedList<String>(
-                Main.pref.getCollection(UploadAction.HISTORY_KEY, new LinkedList<String>()));
-        if(history.size() > 0) {
-            cmt = history.get(0);
-        }
-        return cmt;
     }
 
