Index: /trunk/src/org/openstreetmap/josm/gui/preferences/imagery/AddImageryPanel.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/imagery/AddImageryPanel.java	(revision 13733)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/imagery/AddImageryPanel.java	(revision 13734)
@@ -2,19 +2,35 @@
 package org.openstreetmap.josm.gui.preferences.imagery;
 
+import static org.openstreetmap.josm.tools.I18n.tr;
+
 import java.awt.GridBagLayout;
 import java.awt.LayoutManager;
+import java.awt.event.ItemEvent;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
 import javax.swing.AbstractButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
 import javax.swing.JPanel;
+import javax.swing.JSpinner;
+import javax.swing.SpinnerNumberModel;
 import javax.swing.event.DocumentEvent;
 import javax.swing.event.DocumentListener;
 import javax.swing.text.JTextComponent;
 
+import org.openstreetmap.josm.actions.ExpertToggleAction;
 import org.openstreetmap.josm.data.imagery.ImageryInfo;
 import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
+import org.openstreetmap.josm.data.imagery.TMSCachedTileLoaderJob;
 import org.openstreetmap.josm.gui.widgets.JosmTextArea;
 import org.openstreetmap.josm.gui.widgets.JosmTextField;
+import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.Logging;
 
 /**
@@ -31,4 +47,11 @@
 
     protected final transient Collection<ContentValidationListener> listeners = new ArrayList<>();
+
+    private final JCheckBox validGeoreference= new JCheckBox(tr("Is layer properly georeferenced?"));
+    private HeadersTable headersTable;
+    private JSpinner minimumCacheExpiry;
+    private JComboBox<String> minimumCacheExpiryUnit;
+    private TimeUnit currentUnit;
+
 
     /**
@@ -47,4 +70,61 @@
     protected AddImageryPanel() {
         this(new GridBagLayout());
+        headersTable = new HeadersTable();
+        minimumCacheExpiry = new JSpinner(new SpinnerNumberModel(
+                (Number)TimeUnit.MILLISECONDS.toSeconds(TMSCachedTileLoaderJob.MINIMUM_EXPIRES.get()),
+                0L,
+                Long.valueOf(Integer.MAX_VALUE),
+                1
+                ));
+        List<String> units = Arrays.asList(new String[]{tr("seconds"), tr("minutes"), tr("hours"), tr("days")});
+        minimumCacheExpiryUnit = new JComboBox<>(units.toArray(new String[]{}));
+        currentUnit = TimeUnit.SECONDS;
+        minimumCacheExpiryUnit.addItemListener(e -> {
+            if (e.getStateChange() == ItemEvent.SELECTED) {
+                long newValue = 0;
+                switch (units.indexOf(e.getItem())) {
+                case 0:
+                    newValue = currentUnit.toSeconds((long) minimumCacheExpiry.getValue());
+                    currentUnit = TimeUnit.SECONDS;
+                    break;
+                case 1:
+                    newValue = currentUnit.toMinutes((long) minimumCacheExpiry.getValue());
+                    currentUnit = TimeUnit.MINUTES;
+                    break;
+                case 2:
+                    newValue = currentUnit.toHours((long) minimumCacheExpiry.getValue());
+                    currentUnit = TimeUnit.HOURS;
+                    break;
+                case 3:
+                    newValue = currentUnit.toDays((long) minimumCacheExpiry.getValue());
+                    currentUnit = TimeUnit.DAYS;
+                    break;
+                default:
+                    Logging.warn("Dupa: " + units.indexOf(e.getItem()));
+                }
+                minimumCacheExpiry.setValue(newValue);
+            }
+        });
+
+
+    }
+
+    protected void addCommonSettings() {
+        if (ExpertToggleAction.isExpert()) {
+            add(new JLabel(tr("Minimum cache expiry: ")));
+            add(minimumCacheExpiry);
+            add(minimumCacheExpiryUnit, GBC.eol());
+            add(new JLabel(tr("Set custom HTTP headers (if needed):")), GBC.eop());
+            add(headersTable, GBC.eol().fill());
+            add(validGeoreference, GBC.eop().fill());
+        }
+    }
+
+    protected Map<String, String> getCommonHeaders() {
+        return headersTable.getHeaders();
+    }
+
+    protected boolean getCommonIsValidGeoreference() {
+        return validGeoreference.isSelected();
     }
 
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/imagery/AddWMSLayerPanel.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/imagery/AddWMSLayerPanel.java	(revision 13733)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/imagery/AddWMSLayerPanel.java	(revision 13734)
@@ -4,8 +4,10 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
+import java.awt.event.ActionListener;
 import java.io.IOException;
 import java.net.MalformedURLException;
-import java.net.URL;
+import java.util.Collection;
 import java.util.List;
+import java.util.stream.Collectors;
 
 import javax.swing.DefaultComboBoxModel;
@@ -17,4 +19,5 @@
 import javax.swing.JScrollPane;
 
+import org.openstreetmap.josm.data.imagery.DefaultLayer;
 import org.openstreetmap.josm.data.imagery.ImageryInfo;
 import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
@@ -33,6 +36,7 @@
 public class AddWMSLayerPanel extends AddImageryPanel {
 
-    private final transient WMSImagery wms = new WMSImagery();
+    private transient WMSImagery wms;
     private final JCheckBox endpoint = new JCheckBox(tr("Store WMS endpoint only, select layers at usage"));
+    private final JCheckBox setDefaultLayers = new JCheckBox(tr("Use selected layers as default"));
     private final transient WMSLayerTree tree = new WMSLayerTree();
     private final JComboBox<String> formats = new JComboBox<>();
@@ -54,5 +58,8 @@
 
         add(new JLabel(tr("{0} Select layers", "4.")), GBC.eol());
+
         add(endpoint, GBC.eol().fill());
+        setDefaultLayers.setEnabled(false);
+        add(setDefaultLayers, GBC.eol().fill());
         add(new JScrollPane(tree.getLayerTree()), GBC.eol().fill().weight(1, 100));
 
@@ -62,4 +69,6 @@
         add(new JLabel(tr("{0} Select image format", "5.")), GBC.eol());
         add(formats, GBC.eol().fill());
+
+        addCommonSettings();
 
         wmsInstruction = new JLabel(tr("{0} Edit generated {1} URL (optional)", "6.", "WMS"));
@@ -74,9 +83,9 @@
         getLayers.addActionListener(e -> {
             try {
-                wms.attemptGetCapabilities(rawUrl.getText());
+                wms = new WMSImagery(rawUrl.getText(), getCommonHeaders());
                 tree.updateTree(wms);
-                List<String> wmsFormats = wms.getFormats();
-                formats.setModel(new DefaultComboBoxModel<>(wmsFormats.toArray(new String[0])));
-                formats.setSelectedItem(wms.getPreferredFormats());
+                Collection<String> wmsFormats = wms.getFormats();
+                formats.setModel(new DefaultComboBoxModel<>(wmsFormats.toArray(new String[wmsFormats.size()])));
+                formats.setSelectedItem(wms.getPreferredFormat());
             } catch (MalformedURLException ex1) {
                 Logging.log(Logging.LEVEL_ERROR, ex1);
@@ -104,19 +113,20 @@
         });
 
-        endpoint.addItemListener(e -> {
-            tree.getLayerTree().setEnabled(!endpoint.isSelected());
-            showBounds.setEnabled(!endpoint.isSelected());
-            wmsInstruction.setEnabled(!endpoint.isSelected());
-            formats.setEnabled(!endpoint.isSelected());
-            wmsUrl.setEnabled(!endpoint.isSelected());
-            if (endpoint.isSelected()) {
-                URL url = wms.getServiceUrl();
-                if (url != null) {
-                    name.setText(url.getHost());
-                }
-            } else {
-                onLayerSelectionChanged();
-            }
-        });
+        ActionListener availabilityManagerAction = a -> {
+            setDefaultLayers.setEnabled(endpoint.isSelected());
+            boolean enabled = !endpoint.isSelected() || setDefaultLayers.isSelected();
+            tree.getLayerTree().setEnabled(enabled);
+            showBounds.setEnabled(enabled);
+            wmsInstruction.setEnabled(enabled);
+            formats.setEnabled(enabled);
+            wmsUrl.setEnabled(enabled);
+            if (endpoint.isSelected() && !setDefaultLayers.isSelected() && wms != null) {
+                name.setText(wms.buildRootUrl());
+            }
+            onLayerSelectionChanged();
+        };
+
+        endpoint.addActionListener(availabilityManagerAction);
+        setDefaultLayers.addActionListener(availabilityManagerAction);
 
         tree.getLayerTree().addPropertyChangeListener("selectedLayers", evt -> onLayerSelectionChanged());
@@ -125,7 +135,7 @@
 
         showBounds.addActionListener(e -> {
-            if (tree.getSelectedLayers().get(0).bounds != null) {
+            if (tree.getSelectedLayers().get(0).getBounds() != null) {
                 SlippyMapBBoxChooser mapPanel = new SlippyMapBBoxChooser();
-                mapPanel.setBoundingBox(tree.getSelectedLayers().get(0).bounds);
+                mapPanel.setBoundingBox(tree.getSelectedLayers().get(0).getBounds());
                 JOptionPane.showMessageDialog(null, mapPanel, tr("Show Bounds"), JOptionPane.PLAIN_MESSAGE);
             } else {
@@ -141,7 +151,13 @@
 
     protected final void onLayerSelectionChanged() {
-        if (wms.getServiceUrl() != null) {
-            wmsUrl.setText(wms.buildGetMapUrl(tree.getSelectedLayers(), (String) formats.getSelectedItem()));
-            name.setText(wms.getServiceUrl().getHost() + ": " + Utils.join(", ", tree.getSelectedLayers()));
+        if (wms != null && wms.buildRootUrl() != null) {
+            wmsUrl.setText(wms.buildGetMapUrl(
+                    tree.getSelectedLayers().stream().map(x -> x.getName()).collect(Collectors.toList()),
+                    (List<String>) null,
+                    (String) formats.getSelectedItem(),
+                    true // TODO: ask user about transparency
+                )
+            );
+            name.setText(wms.buildRootUrl() + ": " + Utils.join(", ", tree.getSelectedLayers()));
         }
         showBounds.setEnabled(tree.getSelectedLayers().size() == 1);
@@ -150,13 +166,25 @@
     @Override
     public ImageryInfo getImageryInfo() {
-        final ImageryInfo info;
+        ImageryInfo info = null;
         if (endpoint.isSelected()) {
             info = new ImageryInfo(getImageryName(), getImageryRawUrl());
             info.setImageryType(ImageryInfo.ImageryType.WMS_ENDPOINT);
+            if (setDefaultLayers.isSelected()) {
+                info.setDefaultLayers(tree.getSelectedLayers().stream()
+                        .map(x -> new DefaultLayer(
+                                ImageryInfo.ImageryType.WMS_ENDPOINT,
+                                x.getName(),
+                                "", // TODO: allow selection of styles
+                                ""))
+                        .collect(Collectors.toList()));
+                info.setServerProjections(wms.getServerProjections(tree.getSelectedLayers()));
+            }
         } else {
-            info = wms.toImageryInfo(getImageryName(), tree.getSelectedLayers());
+            info = wms.toImageryInfo(getImageryName(), tree.getSelectedLayers(), (List<String>) null, true); // TODO: ask user about transparency
             info.setUrl(getWmsUrl());
             info.setImageryType(ImageryType.WMS);
         }
+        info.setGeoreferenceValid(getCommonIsValidGeoreference());
+        info.setCustomHttpHeaders(getCommonHeaders());
         return info;
     }
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/imagery/AddWMTSLayerPanel.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/imagery/AddWMTSLayerPanel.java	(revision 13733)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/imagery/AddWMTSLayerPanel.java	(revision 13734)
@@ -4,12 +4,28 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
+import java.awt.Dimension;
+import java.awt.GridBagLayout;
 import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map.Entry;
 
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
 import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
 
+import org.openstreetmap.josm.data.imagery.DefaultLayer;
 import org.openstreetmap.josm.data.imagery.ImageryInfo;
 import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
+import org.openstreetmap.josm.data.imagery.WMTSCapabilities;
 import org.openstreetmap.josm.data.imagery.WMTSTileSource;
+import org.openstreetmap.josm.data.imagery.WMTSTileSource.Layer;
+import org.openstreetmap.josm.data.imagery.WMTSTileSource.WMTSGetCapabilitiesException;
 import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.Logging;
 
 /**
@@ -19,4 +35,8 @@
  */
 public class AddWMTSLayerPanel extends AddImageryPanel {
+    private final transient JPanel layerPanel = new JPanel(new GridBagLayout());
+    private transient JTable layerTable = null;
+    private final JCheckBox setDefaultLayer = new JCheckBox(tr("Set default layer?"));
+    private List<Entry<String, List<Layer>>> layers;
 
     /**
@@ -29,7 +49,39 @@
         rawUrl.setLineWrap(true);
         rawUrl.setAlignmentY(TOP_ALIGNMENT);
+        JButton getLayers = new JButton(tr("Get layers"));
+        getLayers.setEnabled(setDefaultLayer.isSelected());
+        setDefaultLayer.addActionListener(e -> {
+                getLayers.setEnabled(setDefaultLayer.isSelected());
+        });
+        add(setDefaultLayer, GBC.eop().fill());
+        add(getLayers, GBC.eop().fill());
+        add(new JLabel(tr("Choose default layer")), GBC.eol().fill());
+        layerPanel.setPreferredSize(new Dimension(250, 100));
+        add(layerPanel, GBC.eol().fill());
+
+        addCommonSettings();
+
         add(new JLabel(tr("{0} Enter name for this layer", "3.")), GBC.eol());
         add(name, GBC.eol().fill(GBC.HORIZONTAL));
         registerValidableComponent(rawUrl);
+
+        getLayers.addActionListener(e -> {
+            try {
+                WMTSCapabilities capabilities = WMTSTileSource.getCapabilities(rawUrl.getText(), getCommonHeaders());
+                layers = WMTSTileSource.groupLayersByNameAndTileMatrixSet(capabilities.getLayers());
+                layerTable = WMTSTileSource.getLayerSelectionPanel(layers);
+                layerPanel.removeAll();
+                JScrollPane scrollPane = new JScrollPane(layerTable);
+                scrollPane.setPreferredSize(new Dimension(100, 100));
+                layerPanel.add(scrollPane, GBC.eol().fill());
+                layerPanel.revalidate();
+            } catch (Exception ex) {
+                JOptionPane.showMessageDialog(
+                        getParent(),
+                        tr("Error getting layers: {0}", ex.getMessage()),
+                        tr("WMTS Error"),
+                        JOptionPane.ERROR_MESSAGE);
+            }
+        });
     }
 
@@ -37,8 +89,32 @@
     protected ImageryInfo getImageryInfo() {
         ImageryInfo ret = new ImageryInfo(getImageryName(), "wmts:" + sanitize(getImageryRawUrl(), ImageryType.WMTS));
+        if (setDefaultLayer.isSelected()) {
+            if (layerTable == null) {
+                // did not call get capabilities
+                throw new RuntimeException("TODO");
+            }
+            int index = layerTable.getSelectedRow();
+            if (index < 0) {
+                throw new RuntimeException("TODO");
+            }
+            Layer selectedLayer = layers.get(layerTable.convertRowIndexToModel(index)).getValue().get(0);
+            ret.setDefaultLayers(
+                    Collections.<DefaultLayer> singletonList(
+                            new DefaultLayer(
+                                    ImageryType.WMTS,
+                                    selectedLayer.getIdentifier(),
+                                    selectedLayer.getStyle(),
+                                    selectedLayer.getTileMatrixSet().getIdentifier()
+                                    )
+                            )
+                    );
+        }
+        ret.setCustomHttpHeaders(getCommonHeaders());
+        ret.setGeoreferenceValid(getCommonIsValidGeoreference());
         ret.setImageryType(ImageryType.WMTS);
         try {
             new WMTSTileSource(ret); // check if constructor throws an error
-        } catch (IOException e) {
+        } catch (IOException | WMTSGetCapabilitiesException e) {
+            Logging.warn(e);
             throw new IllegalArgumentException(e); // if so, wrap exception, so proper message will be shown to the user
         }
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/imagery/WMSLayerTree.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/imagery/WMSLayerTree.java	(revision 13733)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/imagery/WMSLayerTree.java	(revision 13734)
@@ -2,11 +2,9 @@
 package org.openstreetmap.josm.gui.preferences.imagery;
 
-import static org.openstreetmap.josm.tools.I18n.tr;
-
 import java.awt.Component;
+import java.util.Collection;
 import java.util.LinkedList;
 import java.util.List;
 
-import javax.swing.JOptionPane;
 import javax.swing.JTree;
 import javax.swing.event.TreeSelectionEvent;
@@ -18,4 +16,5 @@
 import javax.swing.tree.TreePath;
 
+import org.openstreetmap.josm.data.imagery.LayerDetails;
 import org.openstreetmap.josm.io.imagery.WMSImagery;
 
@@ -27,6 +26,5 @@
     private final DefaultTreeModel treeData = new DefaultTreeModel(treeRootNode);
     private final JTree layerTree = new JTree(treeData);
-    private final List<WMSImagery.LayerDetails> selectedLayers = new LinkedList<>();
-    private boolean previouslyShownUnsupportedCrsError;
+    private final List<LayerDetails> selectedLayers = new LinkedList<>();
 
     /**
@@ -50,5 +48,5 @@
      * @return the list of selected layers
      */
-    public List<WMSImagery.LayerDetails> getSelectedLayers() {
+    public List<LayerDetails> getSelectedLayers() {
         return selectedLayers;
     }
@@ -62,8 +60,11 @@
     }
 
-    void addLayersToTreeData(MutableTreeNode parent, List<WMSImagery.LayerDetails> layers) {
-        for (WMSImagery.LayerDetails layerDetails : layers) {
+    void addLayersToTreeData(MutableTreeNode parent, Collection<LayerDetails> layers) {
+        for (LayerDetails layerDetails : layers.stream()
+                .sorted((l1, l2) -> -1 * l1.toString().compareTo(l2.toString()))
+                .toArray(LayerDetails[]::new)
+                ) {
             DefaultMutableTreeNode treeNode = new DefaultMutableTreeNode(layerDetails);
-            addLayersToTreeData(treeNode, layerDetails.children);
+            addLayersToTreeData(treeNode, layerDetails.getChildren());
             treeData.insertNodeInto(treeNode, parent, 0);
         }
@@ -71,9 +72,13 @@
 
     /**
-     * Updates the whole tree with the given WMS imagery info.
+     * Updates the whole tree with the given WMS imagery info. All previous content is removed
      * @param wms The imagery info for a given WMS server
      */
     public void updateTree(WMSImagery wms) {
-        treeRootNode.setUserObject(wms.getServiceUrl().getHost());
+        // treeRootNode = new DefaultMutableTreeNode();
+        while (treeRootNode.getChildCount() > 0) {
+            treeRootNode.remove(0);
+        }
+        treeRootNode.setUserObject(wms.buildRootUrl());
         updateTreeList(wms.getLayers());
     }
@@ -83,5 +88,5 @@
      * @param layers The list of layers to add to the root node
      */
-    public void updateTreeList(List<WMSImagery.LayerDetails> layers) {
+    public void updateTreeList(Collection<LayerDetails> layers) {
         addLayersToTreeData(getTreeRootNode(), layers);
         getLayerTree().expandRow(0);
@@ -98,7 +103,7 @@
             DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) value;
             Object userObject = treeNode.getUserObject();
-            if (userObject instanceof WMSImagery.LayerDetails) {
-                WMSImagery.LayerDetails layer = (WMSImagery.LayerDetails) userObject;
-                setEnabled(layer.isSupported());
+            if (userObject instanceof LayerDetails) {
+                LayerDetails ld = (LayerDetails) userObject;
+                setEnabled(ld.isSelectable());
             }
             return this;
@@ -118,15 +123,7 @@
             for (TreePath i : selectionRows) {
                 Object userObject = ((DefaultMutableTreeNode) i.getLastPathComponent()).getUserObject();
-                if (userObject instanceof WMSImagery.LayerDetails) {
-                    WMSImagery.LayerDetails detail = (WMSImagery.LayerDetails) userObject;
-                    if (!detail.isSupported()) {
-                        layerTree.removeSelectionPath(i);
-                        if (!previouslyShownUnsupportedCrsError) {
-                            JOptionPane.showMessageDialog(null, tr("That layer does not support any of JOSM''s projections,\n" +
-                                    "so you can not use it. This message will not show again."),
-                                    tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
-                            previouslyShownUnsupportedCrsError = true;
-                        }
-                    } else if (detail.ident != null) {
+                if (userObject instanceof LayerDetails) {
+                    LayerDetails detail = (LayerDetails) userObject;
+                    if (detail.isSelectable()) {
                         selectedLayers.add(detail);
                     }
Index: /trunk/test/unit/org/openstreetmap/josm/gui/preferences/imagery/AddWMSLayerPanelTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/gui/preferences/imagery/AddWMSLayerPanelTest.java	(revision 13733)
+++ /trunk/test/unit/org/openstreetmap/josm/gui/preferences/imagery/AddWMSLayerPanelTest.java	(revision 13734)
@@ -2,5 +2,4 @@
 package org.openstreetmap.josm.gui.preferences.imagery;
 
-import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 
@@ -21,5 +20,5 @@
     @Rule
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences();
+    public JOSMTestRules test = new JOSMTestRules().platform().preferences();
 
     /**
@@ -29,5 +28,4 @@
     public void testAddWMSLayerPanel() {
         AddWMSLayerPanel panel = new AddWMSLayerPanel();
-        assertEquals("", panel.getImageryInfo().getUrl());
         assertFalse(panel.isImageryValid());
     }
