Index: trunk/src/org/openstreetmap/josm/gui/preferences/imagery/AddImageryDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/imagery/AddImageryDialog.java	(revision 5731)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/imagery/AddImageryDialog.java	(revision 5731)
@@ -0,0 +1,43 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.preferences.imagery;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Component;
+import java.awt.Dimension;
+
+import org.openstreetmap.josm.gui.ExtendedDialog;
+import org.openstreetmap.josm.gui.preferences.imagery.AddImageryPanel.ContentValidationListener;
+
+/**
+ * Dialog shown to add a new imagery (WMS/TMS) source from imagery preferences.
+ * @since 5731
+ */
+public class AddImageryDialog extends ExtendedDialog implements ContentValidationListener {
+    
+    /**
+     * Constructs a new AddImageryDialog.
+     * @param parent The parent element that will be used for position and maximum size
+     * @param panel  The content that will be displayed in the message dialog
+     */
+    public AddImageryDialog(Component parent, AddImageryPanel panel) {
+        super(parent, tr("Add Imagery URL"), new String[] {tr("OK"), tr("Cancel")});
+        setButtonIcons(new String[] {"ok", "cancel"});
+        setCancelButton(2);
+        configureContextsensitiveHelp("/Dialog/AddImagery", true /* show help button */);
+        setContent(panel, false);
+        setMinimumSize(new Dimension(300, 400));
+        panel.addContentValidationListener(this);
+    }
+
+    @Override
+    public void setupDialog() {
+        super.setupDialog();
+        contentChanged(false);
+    }
+
+    @Override
+    public void contentChanged(boolean isValid) {
+        buttons.get(0).setEnabled(isValid);
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/preferences/imagery/AddImageryPanel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/imagery/AddImageryPanel.java	(revision 5730)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/imagery/AddImageryPanel.java	(revision 5731)
@@ -1,24 +1,99 @@
+// License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.gui.preferences.imagery;
 
+import java.awt.GridBagLayout;
 import java.awt.LayoutManager;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import javax.swing.AbstractButton;
 import javax.swing.JPanel;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.text.JTextComponent;
+
 import org.openstreetmap.josm.data.imagery.ImageryInfo;
 
+/**
+ * An abstract imagery panel used to add WMS/TMS imagery sources. See implementations.
+ * @see AddTMSLayerPanel
+ * @see AddWMSLayerPanel
+ * @since 5617
+ */
 public abstract class AddImageryPanel extends JPanel {
-    protected AddImageryPanel() {
+
+    protected final JTextArea rawUrl = new JTextArea(3, 40);
+    protected final JTextField name = new JTextField();
+    
+    protected final Collection<ContentValidationListener> listeners = new ArrayList<ContentValidationListener>();
+    
+    /**
+     * A listener notified when the validation status of this panel change.
+     */
+    public interface ContentValidationListener {
+        /**
+         * Called when the validation status of this panel changed
+         * @param isValid true if the conditions required to close this panel are met   
+         */
+        public void contentChanged(boolean isValid);
     }
 
-    protected AddImageryPanel(boolean isDoubleBuffered) {
-        super(isDoubleBuffered);
+    protected AddImageryPanel() {
+        this(new GridBagLayout());
     }
 
     protected AddImageryPanel(LayoutManager layout) {
         super(layout);
+        registerValidableComponent(name);
     }
 
-    protected AddImageryPanel(LayoutManager layout, boolean isDoubleBuffered) {
-        super(layout, isDoubleBuffered);
+    protected final void registerValidableComponent(AbstractButton component) {
+        component.addChangeListener(new ChangeListener() {
+            @Override public void stateChanged(ChangeEvent e) { notifyListeners(); }
+        });
     }
 
-    abstract ImageryInfo getImageryInfo();
+    protected final void registerValidableComponent(JTextComponent component) {
+        component.getDocument().addDocumentListener(new DocumentListener() {
+            @Override public void removeUpdate(DocumentEvent e) { notifyListeners(); }
+            @Override public void insertUpdate(DocumentEvent e) { notifyListeners(); }
+            @Override public void changedUpdate(DocumentEvent e) { notifyListeners(); }
+        });
+    }
+
+    protected abstract ImageryInfo getImageryInfo();
+
+    protected static String sanitize(String s) {
+        return s.replaceAll("[\r\n]+", "").trim();
+    }
+    
+    protected final String getImageryName() {
+        return sanitize(name.getText());
+    }
+
+    protected final String getImageryRawUrl() {
+        return sanitize(rawUrl.getText());
+    }
+    
+    protected abstract boolean isImageryValid();
+
+    /**
+     * Registers a new ContentValidationListener
+     * @param l The new ContentValidationListener that will be notified of validation status changes
+     */
+    public final void addContentValidationListener(ContentValidationListener l) {
+        if (l != null) {
+            listeners.add(l);
+        }
+    }
+
+    private final void notifyListeners() {
+        for (ContentValidationListener l : listeners) {
+            l.contentChanged(isImageryValid());
+        }
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/preferences/imagery/AddTMSLayerPanel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/imagery/AddTMSLayerPanel.java	(revision 5730)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/imagery/AddTMSLayerPanel.java	(revision 5731)
@@ -5,12 +5,13 @@
 
 import java.awt.Dimension;
-import java.awt.GridBagLayout;
 import java.awt.event.KeyAdapter;
 import java.awt.event.KeyEvent;
 import java.util.Arrays;
+
 import javax.swing.JLabel;
 import javax.swing.JTextArea;
 import javax.swing.JTextField;
 import javax.swing.text.View;
+
 import org.openstreetmap.josm.data.imagery.ImageryInfo;
 import org.openstreetmap.josm.tools.GBC;
@@ -19,8 +20,6 @@
 public class AddTMSLayerPanel extends AddImageryPanel {
 
-    private final JTextArea rawUrl = new JTextArea(3, 40);
     private final JTextField tmsZoom = new JTextField();
     private final JTextArea tmsUrl = new JTextArea(3, 40);
-    private final JTextField name = new JTextField();
     private final KeyAdapter keyAdapter = new KeyAdapter() {
         @Override
@@ -31,5 +30,4 @@
 
     public AddTMSLayerPanel() {
-        super(new GridBagLayout());
 
         add(new JLabel(tr("1. Enter URL")), GBC.eol());
@@ -60,8 +58,5 @@
         add(name, GBC.eop().fill());
 
-    }
-
-    private String sanitize(String s) {
-        return s.replaceAll("[\r\n]+", "").trim();
+        registerValidableComponent(tmsUrl);
     }
 
@@ -73,5 +68,5 @@
         }
         a.append(":");
-        a.append(sanitize(rawUrl.getText()));
+        a.append(getImageryRawUrl());
         return a.toString();
     }
@@ -79,5 +74,5 @@
     @Override
     public ImageryInfo getImageryInfo() {
-        return new ImageryInfo(name.getText(), tmsUrl.getText());
+        return new ImageryInfo(getImageryName(), getTmsUrl());
     }
 
@@ -91,3 +86,11 @@
                 (int) Math.ceil(view.getPreferredSpan(View.Y_AXIS)));
     }
+    
+    protected final String getTmsUrl() {
+        return sanitize(tmsUrl.getText());
+    }
+
+    protected boolean isImageryValid() {
+        return !getImageryName().isEmpty() && !getTmsUrl().isEmpty();
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/preferences/imagery/AddWMSLayerPanel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/imagery/AddWMSLayerPanel.java	(revision 5730)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/imagery/AddWMSLayerPanel.java	(revision 5731)
@@ -4,6 +4,4 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
-import java.awt.Dimension;
-import java.awt.GridBagLayout;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
@@ -14,4 +12,5 @@
 import java.io.IOException;
 import java.net.MalformedURLException;
+
 import javax.swing.JButton;
 import javax.swing.JCheckBox;
@@ -20,5 +19,5 @@
 import javax.swing.JScrollPane;
 import javax.swing.JTextArea;
-import javax.swing.JTextField;
+
 import org.openstreetmap.josm.data.imagery.ImageryInfo;
 import org.openstreetmap.josm.gui.bbox.SlippyMapBBoxChooser;
@@ -30,12 +29,11 @@
 
     private final WMSImagery wms = new WMSImagery();
-    private final JTextArea rawUrl = new JTextArea(3, 40);
     private final JCheckBox endpoint = new JCheckBox(tr("Store WMS endpoint only, select layers at usage"));
     private final WMSLayerTree tree = new WMSLayerTree();
+    private final JLabel wmsInstruction;
     private final JTextArea wmsUrl = new JTextArea(3, 40);
-    private final JTextField name = new JTextField();
+    private final JButton showBounds = new JButton(tr("Show bounds"));
 
     public AddWMSLayerPanel() {
-        super(new GridBagLayout());
 
         add(new JLabel(tr("1. Enter service URL")), GBC.eol());
@@ -48,9 +46,9 @@
         add(endpoint, GBC.eol().fill());
         add(new JScrollPane(tree.getLayerTree()), GBC.eol().fill().weight(1, 100));
-        final JButton showBounds = new JButton(tr("Show bounds"));
+
         showBounds.setEnabled(false);
         add(new JScrollPane(showBounds), GBC.eop().fill());
 
-        add(new JLabel(tr("3. Verify generated WMS URL")), GBC.eol());
+        add(wmsInstruction = new JLabel(tr("3. Verify generated WMS URL")), GBC.eol());
         add(wmsUrl, GBC.eop().fill());
         wmsUrl.setLineWrap(true);
@@ -85,5 +83,11 @@
                 tree.getLayerTree().setEnabled(!endpoint.isSelected());
                 showBounds.setEnabled(!endpoint.isSelected());
+                wmsInstruction.setEnabled(!endpoint.isSelected());
                 wmsUrl.setEnabled(!endpoint.isSelected());
+                if (endpoint.isSelected()) {
+                    name.setText(wms.getServiceUrl().getHost());
+                } else {
+                    onLayerSelectionChanged();
+                }
             }
         });
@@ -91,10 +95,6 @@
         tree.getLayerTree().addPropertyChangeListener("selectedLayers", new PropertyChangeListener() {
             @Override
-            public void propertyChange(PropertyChangeEvent evt) {
-                if (wms.getServiceUrl() != null) {
-                    wmsUrl.setText(wms.buildGetMapUrl(tree.getSelectedLayers()));
-                    name.setText(wms.getServiceUrl().getHost() + ": " + Utils.join(", ", tree.getSelectedLayers()));
-                }
-                showBounds.setEnabled(tree.getSelectedLayers().size() == 1);
+            public void propertyChange(PropertyChangeEvent evt) { 
+                onLayerSelectionChanged();
             }
         });
@@ -113,5 +113,16 @@
             }
         });
-
+        
+        registerValidableComponent(endpoint);
+        registerValidableComponent(rawUrl);
+        registerValidableComponent(wmsUrl);
+    }
+    
+    protected final void onLayerSelectionChanged() {
+        if (wms.getServiceUrl() != null) {
+            wmsUrl.setText(wms.buildGetMapUrl(tree.getSelectedLayers()));
+            name.setText(wms.getServiceUrl().getHost() + ": " + Utils.join(", ", tree.getSelectedLayers()));
+        }
+        showBounds.setEnabled(tree.getSelectedLayers().size() == 1);
     }
 
@@ -120,11 +131,26 @@
         final ImageryInfo info;
         if (endpoint.isSelected()) {
-            info = new ImageryInfo(name.getText(), rawUrl.getText());
+            info = new ImageryInfo(getImageryName(), getImageryRawUrl());
             info.setImageryType(ImageryInfo.ImageryType.WMS_ENDPOINT);
         } else {
-            info = wms.toImageryInfo(name.getText(), tree.getSelectedLayers());
-            info.setUrl(wmsUrl.getText());
+            info = wms.toImageryInfo(getImageryName(), tree.getSelectedLayers());
+            info.setUrl(getWmsUrl());
         }
         return info;
     }
+    
+    protected final String getWmsUrl() {
+        return sanitize(wmsUrl.getText());
+    }
+    
+    protected boolean isImageryValid() {
+        if (getImageryName().isEmpty()) {
+            return false;
+        }
+        if (endpoint.isSelected()) {
+            return !getImageryRawUrl().isEmpty();
+        } else {
+            return !getWmsUrl().isEmpty();
+        }
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/preferences/imagery/ImageryPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/imagery/ImageryPreference.java	(revision 5730)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/imagery/ImageryPreference.java	(revision 5731)
@@ -62,5 +62,4 @@
 import org.openstreetmap.josm.gui.preferences.PreferenceSettingFactory;
 import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
-import org.openstreetmap.josm.gui.util.GuiHelper;
 import org.openstreetmap.josm.tools.GBC;
 import org.openstreetmap.josm.tools.ImageProvider;
@@ -437,9 +436,9 @@
                     throw new IllegalStateException("Type " + type + " not supported");
                 }
-                GuiHelper.prepareResizeableOptionPane(p, new Dimension(250, 350));
-                int answer = JOptionPane.showConfirmDialog(
-                        gui, p, tr("Add Imagery URL"),
-                        JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
-                if (answer == JOptionPane.OK_OPTION) {
+                
+                final AddImageryDialog addDialog = new AddImageryDialog(gui, p);
+                addDialog.showDialog();
+                
+                if (addDialog.getValue() == 1) {
                     try {
                         activeModel.addRow(p.getImageryInfo());
@@ -456,5 +455,5 @@
             }
         }
-
+        
         private class RemoveEntryAction extends AbstractAction implements ListSelectionListener {
 
Index: trunk/src/org/openstreetmap/josm/io/imagery/WMSImagery.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/imagery/WMSImagery.java	(revision 5730)
+++ trunk/src/org/openstreetmap/josm/io/imagery/WMSImagery.java	(revision 5731)
@@ -16,7 +16,8 @@
 import java.util.Set;
 import java.util.regex.Pattern;
+
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
+
 import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.imagery.ImageryInfo;
@@ -60,4 +61,7 @@
 
     String buildRootUrl() {
+        if (serviceUrl == null) {
+            return null; 
+        }
         StringBuilder a = new StringBuilder(serviceUrl.getProtocol());
         a.append("://");
