Index: trunk/src/org/openstreetmap/josm/gui/ExtendedDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/ExtendedDialog.java	(revision 3401)
+++ trunk/src/org/openstreetmap/josm/gui/ExtendedDialog.java	(revision 3403)
@@ -5,15 +5,22 @@
 import java.awt.Component;
 import java.awt.Dimension;
+import java.awt.GridBagConstraints;
 import java.awt.GridBagLayout;
+import java.awt.Insets;
 import java.awt.Toolkit;
 import java.awt.event.ActionEvent;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 
 import javax.swing.AbstractAction;
 import javax.swing.Action;
+import javax.swing.Icon;
 import javax.swing.JButton;
 import javax.swing.JCheckBox;
 import javax.swing.JComponent;
 import javax.swing.JDialog;
+import javax.swing.JLabel;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
@@ -21,4 +28,6 @@
 import javax.swing.JScrollPane;
 import javax.swing.KeyStroke;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
 
 import org.openstreetmap.josm.Main;
@@ -29,4 +38,19 @@
 import org.openstreetmap.josm.tools.WindowGeometry;
 
+/**
+ * General configurable dialog window.
+ *
+ * If dialog is modal, you can use getValue() to retrieve the
+ * button index. Note that the user can close the dialog
+ * by other means. This is usually equivalent to cancel action.
+ *
+ * For non-modal dialogs, buttonAction(int) can be overridden.
+ *
+ * There are various options, see below.
+ *
+ * Note: The button indices are counted from 1 and upwards.
+ * So for getValue(), setDefaultButton(int) and setCancelButton(int) the
+ * first button has index 1.
+ */
 public class ExtendedDialog extends JDialog {
     private final boolean disposeOnClose;
@@ -44,8 +68,10 @@
     private final String[] bTexts;
     private String[] bToolTipTexts;
-    private String[] bIcons;
-    private int cancelButtonIdx = -1;
-    private int defaultButtonIdx = -1;
+    private Icon[] bIcons;
+    private List<Integer> cancelButtonIdx = Collections.emptyList();
+    private int defaultButtonIdx = 1;
     private JButton defaultButton = null;
+    private Icon icon;
+    private boolean modal;
 
     /** true, if the dialog should include a help button */
@@ -61,5 +87,5 @@
 
     // For easy access when inherited
-    protected Object contentConstraints = GBC.eol().anchor(GBC.CENTER).fill(GBC.BOTH).insets(5,10,5,0);
+    protected Insets contentInsets = new Insets(10,5,0,5);
     protected ArrayList<JButton> buttons = new ArrayList<JButton>();
 
@@ -101,4 +127,5 @@
         super(JOptionPane.getFrameForComponent(parent), title, modal);
         this.parent = parent;
+        this.modal = modal;
         bTexts = buttonTexts;
         if (disposeOnClose) {
@@ -109,10 +136,20 @@
 
     /**
-     * Allows decorating the buttons with icons. Expects an String[] with paths
-     * to images relative to JOSM/images.
+     * Allows decorating the buttons with icons.
      * @param buttonIcons
      */
+    public ExtendedDialog setButtonIcons(Icon[] buttonIcons) {
+        this.bIcons = buttonIcons;
+        return this;
+    }
+
+    /**
+     * Convenience method to provide image names instead of images.
+     */
     public ExtendedDialog setButtonIcons(String[] buttonIcons) {
-        this.bIcons = buttonIcons;
+        bIcons = new Icon[buttonIcons.length];
+        for (int i=0; i<buttonIcons.length; ++i) {
+            bIcons[i] = ImageProvider.get(buttonIcons[i]);
+        }
         return this;
     }
@@ -171,4 +208,33 @@
 
     /**
+     * Decorate the dialog with an icon that is shown on the left part of
+     * the window area. (Similar to how it is done in JOptionPane)
+     */
+    public ExtendedDialog setIcon(Icon icon) {
+        this.icon = icon;
+        return this;
+    }
+
+    /**
+     * Convenience method to allow values that would be accepted by JOptionPane as messageType.
+     */
+    public ExtendedDialog setIcon(int messageType) {
+        switch (messageType) {
+            case JOptionPane.ERROR_MESSAGE:
+                return setIcon(UIManager.getIcon("OptionPane.errorIcon"));
+            case JOptionPane.INFORMATION_MESSAGE:
+                return setIcon(UIManager.getIcon("OptionPane.informationIcon"));
+            case JOptionPane.WARNING_MESSAGE:
+                return setIcon(UIManager.getIcon("OptionPane.warningIcon"));
+            case JOptionPane.QUESTION_MESSAGE:
+                return setIcon(UIManager.getIcon("OptionPane.questionIcon"));
+            case JOptionPane.PLAIN_MESSAGE:
+                return setIcon(null);
+            default:
+                throw new IllegalArgumentException("Unknown message type!");
+        }
+    }
+
+    /**
      * Show the dialog to the user. Call this after you have set all options
      * for the dialog. You can retrieve the result using <code>getValue</code>
@@ -176,5 +242,5 @@
     public ExtendedDialog showDialog() {
         // Check if the user has set the dialog to not be shown again
-        if(toggleCheckState(togglePref)) {
+        if (toggleCheckState(togglePref)) {
             result = toggleValue;
             return this;
@@ -185,4 +251,5 @@
             getRootPane().setDefaultButton(defaultButton);
         }
+        fixFocus();
         setVisible(true);
         toggleSaveState();
@@ -227,5 +294,5 @@
             }
             if(bIcons != null && bIcons[i] != null) {
-                button.setIcon(ImageProvider.get(bIcons[i]));
+                button.setIcon(bIcons[i]);
             }
             if (bToolTipTexts != null && i < bToolTipTexts.length && bToolTipTexts[i] != null) {
@@ -233,7 +300,4 @@
             }
 
-            if(i == 0) {
-                rootPane.setDefaultButton(button);
-            }
             buttonsPanel.add(button, GBC.std().insets(2,2,2,2));
             buttons.add(button);
@@ -245,14 +309,43 @@
 
         JPanel cp = new JPanel(new GridBagLayout());
-        cp.add(content, contentConstraints);
-
-        if(toggleable) {
+
+        GridBagConstraints gc = new GridBagConstraints();
+        gc.gridx = 0;
+        int y = 0;
+        gc.gridy = y++;
+        gc.weightx = 0.0;
+        gc.weighty = 0.0;
+
+        if (icon != null) {
+            JLabel iconLbl = new JLabel(icon);
+            gc.insets = new Insets(10,10,10,10);
+            gc.anchor = GridBagConstraints.NORTH;
+            cp.add(iconLbl, gc);
+            gc.anchor = GridBagConstraints.CENTER;
+            gc.gridx = 1;
+        }
+
+        gc.fill = GridBagConstraints.BOTH;
+        gc.insets = contentInsets;
+        cp.add(content, gc);
+
+        gc.fill = GridBagConstraints.NONE;
+        gc.gridwidth = GridBagConstraints.REMAINDER;
+
+        if (toggleable) {
             toggleCheckbox = new JCheckBox(toggleCheckboxText);
             boolean showDialog = Main.pref.getBoolean("message."+ togglePref, true);
             toggleCheckbox.setSelected(!showDialog);
-            cp.add(toggleCheckbox, GBC.eol().anchor(GBC.LINE_START).insets(5,5,5,5));
-        }
-
-        cp.add(buttonsPanel, GBC.eol().anchor(GBC.CENTER).insets(5,5,5,5));
+            gc.gridx = icon != null ? 1 : 0;
+            gc.gridy = y++;
+            gc.anchor = GridBagConstraints.LINE_START;
+            gc.insets = new Insets(5,contentInsets.left,5,contentInsets.right);
+            cp.add(toggleCheckbox, gc);
+        }
+
+        gc.gridy = y++;
+        gc.anchor = GridBagConstraints.CENTER;
+            gc.insets = new Insets(5,5,5,5);
+        cp.add(buttonsPanel, gc);
         if (placeContentInScrollPane) {
             JScrollPane pane = new JScrollPane(cp);
@@ -326,5 +419,5 @@
 
         getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
-        .put(KeyStroke.getKeyStroke("ESCAPE"), "ESCAPE");
+            .put(KeyStroke.getKeyStroke("ESCAPE"), "ESCAPE");
         getRootPane().getActionMap().put("ESCAPE", actionListener);
     }
@@ -379,7 +472,11 @@
      * dialog. Default is to not offer the choice; the dialog will be shown
      * every time.
+     * Currently, this is not supported for non-modal dialogs.
      * @param togglePref  The preference to save the checkbox state to
      */
     public ExtendedDialog toggleEnable(String togglePref) {
+        if (!modal) {
+            throw new IllegalArgumentException();
+        }
         this.toggleable = true;
         this.togglePref = togglePref;
@@ -418,9 +515,23 @@
      * Used in combination with toggle:
      * If the user presses 'cancel' the toggle settings are ignored and not saved to the pref
-     * @param cancelButton index of the button that stands for cancel
-     */
-    public ExtendedDialog setCancelButton(int cancelButtonIdx) {
-        this.cancelButtonIdx = cancelButtonIdx;
-        return this;
+     * @param cancelButton index of the button that stands for cancel, accepts
+     *                     multiple values
+     */
+    public ExtendedDialog setCancelButton(Integer... cancelButtonIdx) {
+        this.cancelButtonIdx = Arrays.<Integer>asList(cancelButtonIdx);
+        return this;
+    }
+
+    /**
+     * Don't focus the "do not show this again" check box, but the default button.
+     */
+    protected void fixFocus() {
+        if (toggleable && defaultButton != null) {
+            SwingUtilities.invokeLater(new Runnable() {
+                public void run() {
+                    defaultButton.requestFocusInWindow();
+                }
+            });
+        }
     }
 
@@ -446,5 +557,8 @@
      */
     private void toggleSaveState() {
-        if(!toggleable || toggleCheckbox == null || result == cancelButtonIdx || result == ExtendedDialog.DialogClosedOtherwise)
+        if (!toggleable ||
+                toggleCheckbox == null ||
+                cancelButtonIdx.contains(result) ||
+                result == ExtendedDialog.DialogClosedOtherwise)
             return;
         Main.pref.put("message."+ togglePref, !toggleCheckbox.isSelected());
Index: trunk/src/org/openstreetmap/josm/gui/io/UploadDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/io/UploadDialog.java	(revision 3401)
+++ trunk/src/org/openstreetmap/josm/gui/io/UploadDialog.java	(revision 3403)
@@ -7,4 +7,5 @@
 import java.awt.Dimension;
 import java.awt.FlowLayout;
+import java.awt.Image;
 import java.awt.event.ActionEvent;
 import java.awt.event.KeyEvent;
@@ -19,4 +20,6 @@
 import javax.swing.AbstractAction;
 import javax.swing.BorderFactory;
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
 import javax.swing.InputMap;
 import javax.swing.JButton;
@@ -34,9 +37,9 @@
 import org.openstreetmap.josm.data.osm.Changeset;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.gui.ExtendedDialog;
 import org.openstreetmap.josm.gui.HelpAwareOptionPane;
 import org.openstreetmap.josm.gui.SideButton;
 import org.openstreetmap.josm.gui.help.ContextSensitiveHelpAction;
 import org.openstreetmap.josm.gui.help.HelpUtil;
-import org.openstreetmap.josm.gui.HelpAwareOptionPane.ButtonSpec;
 import org.openstreetmap.josm.io.OsmApi;
 import org.openstreetmap.josm.tools.ImageProvider;
@@ -364,24 +367,9 @@
          */
         protected boolean warnUploadComment() {
-
-            ButtonSpec[] options = new ButtonSpec[] {
-                    new ButtonSpec(
-                            tr("Yes, revise"),
-                            ImageProvider.get("ok"),
-                            tr("Go back to the changeset comment and enter a better description"),
-                            null
-                    ),
-                    new ButtonSpec(
-                            tr("No, continue as is"),
-                            ImageProvider.get("cancel"),
-                            tr("Continue without improving the changeset comment"),
-                            null
-                    )
-            };
-
-            return 0 == HelpAwareOptionPane.showOptionDialog(
-                    UploadDialog.this,
-                    "<html>" + 
-                    tr("Your upload comment is empty, or very short.<br /><br />" + 
+            ExtendedDialog dlg = new ExtendedDialog(UploadDialog.this,
+                tr("Please revise upload comment"),
+                new String[] {tr("Revise"), tr("Cancel"), tr("Continue as is")});
+            dlg.setContent("<html>" + 
+                    tr("Your upload comment is <i>empty</i>, or <i>very short</i>.<br /><br />" + 
                        "This is technically allowed, but please consider that many users who are<br />" +
                        "watching changes in their area depend on meaningful changeset comments<br />" +
@@ -389,12 +377,21 @@
                        "If you spend a minute now to explain your change, you will make life<br />" +
                        "easier for many other mappers.") + 
-                    "</html>",
-                    tr("Please revise upload comment"),
-                    JOptionPane.WARNING_MESSAGE,
-                    null,
-                    options,
-                    options[0],
-                    ht("/Dialog/UploadDialog#ReviseUploadComment")
-            );
+                    "</html>");
+            dlg.setButtonIcons(new Icon[] {
+                ImageProvider.get("ok"),
+                ImageProvider.get("cancel"),
+                ImageProvider.overlay(
+                    ImageProvider.get("upload"), 
+                    new ImageIcon(ImageProvider.get("warning-small").getImage().getScaledInstance(10 , 10, Image.SCALE_SMOOTH)),
+                    ImageProvider.OverlayPosition.SOUTHEAST)});
+            dlg.setToolTipTexts(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")});
+            dlg.setIcon(JOptionPane.WARNING_MESSAGE);
+            dlg.toggleEnable("upload_comment_is_empty_or_very_short");
+            dlg.setToggleCheckboxText(tr("Do not show this message again"));
+            dlg.setCancelButton(1, 2);
+            return dlg.showDialog().getValue() != 3;
         }
 
Index: trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPreset.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPreset.java	(revision 3401)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPreset.java	(revision 3403)
@@ -10,4 +10,5 @@
 import java.awt.GridBagLayout;
 import java.awt.Image;
+import java.awt.Insets;
 import java.awt.event.ActionEvent;
 import java.io.BufferedReader;
@@ -934,5 +935,5 @@
                             new String[] { tr("Apply Preset"), tr("Cancel") },
                             true);
-                    contentConstraints = GBC.eol().fill().insets(5,10,5,0);
+                    contentInsets = new Insets(10,5,0,5);
                     setButtonIcons(new String[] {"ok.png", "cancel.png" });
                     setContent(content);
Index: trunk/src/org/openstreetmap/josm/tools/ImageProvider.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/ImageProvider.java	(revision 3401)
+++ trunk/src/org/openstreetmap/josm/tools/ImageProvider.java	(revision 3403)
@@ -273,9 +273,12 @@
      */
     public static ImageIcon overlay(Icon ground, String overlayImage, OverlayPosition pos) {
+        return overlay(ground, ImageProvider.get(overlayImage), pos);
+    }
+
+    public static ImageIcon overlay(Icon ground, Icon overlay, OverlayPosition pos) {
         GraphicsConfiguration conf = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice()
         .getDefaultConfiguration();
         int w = ground.getIconWidth();
         int h = ground.getIconHeight();
-        ImageIcon overlay = ImageProvider.get(overlayImage);
         int wo = overlay.getIconWidth();
         int ho = overlay.getIconHeight();
