Index: trunk/src/org/openstreetmap/josm/gui/bbox/JosmMapViewer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/bbox/JosmMapViewer.java	(revision 15145)
+++ trunk/src/org/openstreetmap/josm/gui/bbox/JosmMapViewer.java	(revision 15145)
@@ -0,0 +1,181 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.bbox;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.gui.jmapviewer.JMapViewer;
+import org.openstreetmap.gui.jmapviewer.MemoryTileCache;
+import org.openstreetmap.gui.jmapviewer.OsmTileLoader;
+import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader;
+import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
+import org.openstreetmap.gui.jmapviewer.tilesources.OsmTileSource;
+import org.openstreetmap.josm.data.Version;
+import org.openstreetmap.josm.data.imagery.ImageryInfo;
+import org.openstreetmap.josm.data.imagery.ImageryLayerInfo;
+import org.openstreetmap.josm.data.imagery.TMSCachedTileLoader;
+import org.openstreetmap.josm.data.imagery.TileLoaderFactory;
+import org.openstreetmap.josm.data.preferences.StringProperty;
+import org.openstreetmap.josm.gui.MainApplication;
+import org.openstreetmap.josm.gui.layer.AbstractCachedTileSourceLayer;
+import org.openstreetmap.josm.gui.layer.ImageryLayer;
+import org.openstreetmap.josm.gui.layer.TMSLayer;
+import org.openstreetmap.josm.tools.Logging;
+
+/**
+ * An extension of {@link JMapViewer} that implements JOSM-specific tile loading mechanisms.
+ * @since 15145
+ */
+public class JosmMapViewer extends JMapViewer {
+
+    /**
+     * A list of tile sources that can be used for displaying the map.
+     */
+    @FunctionalInterface
+    public interface TileSourceProvider {
+        /**
+         * Gets the tile sources that can be displayed
+         * @return The tile sources
+         */
+        List<TileSource> getTileSources();
+    }
+
+    /**
+     * TileSource provider.
+     */
+    public abstract static class AbstractImageryInfoBasedTileSourceProvider implements TileSourceProvider {
+        /**
+         * Returns the list of imagery infos backing tile sources.
+         * @return the list of imagery infos backing tile sources
+         */
+        public abstract List<ImageryInfo> getImageryInfos();
+
+        @Override
+        public List<TileSource> getTileSources() {
+            if (!TMSLayer.PROP_ADD_TO_SLIPPYMAP_CHOOSER.get()) return Collections.<TileSource>emptyList();
+            return imageryInfosToTileSources(getImageryInfos());
+        }
+    }
+
+    static List<TileSource> imageryInfosToTileSources(List<ImageryInfo> imageryInfos) {
+        List<TileSource> sources = new ArrayList<>();
+        for (ImageryInfo info : imageryInfos) {
+            try {
+                TileSource source = TMSLayer.getTileSourceStatic(info);
+                if (source != null) {
+                    sources.add(source);
+                }
+            } catch (IllegalArgumentException ex) {
+                Logging.warn(ex);
+                if (ex.getMessage() != null && !ex.getMessage().isEmpty()) {
+                    JOptionPane.showMessageDialog(MainApplication.getMainFrame(),
+                            ex.getMessage(), tr("Warning"),
+                            JOptionPane.WARNING_MESSAGE);
+                }
+            }
+        }
+        return sources;
+    }
+
+    /**
+     * TileSource provider - providing default OSM tile source
+     */
+    public static class DefaultOsmTileSourceProvider implements TileSourceProvider {
+
+        protected static final StringProperty DEFAULT_OSM_TILE_URL = new StringProperty(
+                "default.osm.tile.source.url", "https://{switch:a,b,c}.tile.openstreetmap.org/{zoom}/{x}/{y}.png");
+
+        @Override
+        public List<TileSource> getTileSources() {
+            List<TileSource> result = imageryInfosToTileSources(ImageryLayerInfo.instance.getLayers().stream()
+                   .filter(l -> l.getUrl().equals(DEFAULT_OSM_TILE_URL.get())).collect(Collectors.toList()));
+            if (result.isEmpty()) {
+                result.add(new OsmTileSource.Mapnik());
+            }
+            return result;
+        }
+
+        /**
+         * Returns the default OSM tile source.
+         * @return the default OSM tile source
+         */
+        public static TileSource get() {
+            return new DefaultOsmTileSourceProvider().getTileSources().get(0);
+        }
+    }
+
+    /**
+     * TileSource provider - providing sources from imagery sources menu
+     */
+    public static class TMSTileSourceProvider extends AbstractImageryInfoBasedTileSourceProvider {
+        @Override
+        public List<ImageryInfo> getImageryInfos() {
+            return ImageryLayerInfo.instance.getLayers();
+        }
+    }
+
+    /**
+     * TileSource provider - providing sources from current layers
+     */
+    public static class CurrentLayersTileSourceProvider extends AbstractImageryInfoBasedTileSourceProvider {
+        @Override
+        public List<ImageryInfo> getImageryInfos() {
+            return MainApplication.getLayerManager().getLayers().stream().filter(
+                layer -> layer instanceof ImageryLayer
+            ).map(
+                layer -> ((ImageryLayer) layer).getInfo()
+            ).collect(Collectors.toList());
+        }
+    }
+
+    protected final transient TileLoader cachedLoader;
+    protected final transient OsmTileLoader uncachedLoader;
+
+    /**
+     * Constructs a new {@code JosmMapViewer}.
+     */
+    public JosmMapViewer() {
+        Map<String, String> headers = new HashMap<>();
+        headers.put("User-Agent", Version.getInstance().getFullAgentString());
+
+        TileLoaderFactory cachedLoaderFactory = AbstractCachedTileSourceLayer.getTileLoaderFactory("TMS", TMSCachedTileLoader.class);
+        if (cachedLoaderFactory != null) {
+            cachedLoader = cachedLoaderFactory.makeTileLoader(this, headers, TimeUnit.HOURS.toSeconds(1));
+        } else {
+            cachedLoader = null;
+        }
+
+        uncachedLoader = new OsmTileLoader(this);
+        uncachedLoader.headers.putAll(headers);
+        setFileCacheEnabled(true);
+    }
+
+    /**
+     * Enables the disk tile cache.
+     * @param enabled true to enable, false to disable
+     */
+    public final void setFileCacheEnabled(boolean enabled) {
+        if (enabled && cachedLoader != null) {
+            setTileLoader(cachedLoader);
+        } else {
+            setTileLoader(uncachedLoader);
+        }
+    }
+
+    /**
+     * Sets the maximum number of tiles that may be held in memory
+     * @param tiles The maximum number of tiles.
+     */
+    public final void setMaxTilesInMemory(int tiles) {
+        ((MemoryTileCache) getTileCache()).setCacheSize(tiles);
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/bbox/SlippyMapBBoxChooser.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/bbox/SlippyMapBBoxChooser.java	(revision 15143)
+++ trunk/src/org/openstreetmap/josm/gui/bbox/SlippyMapBBoxChooser.java	(revision 15145)
@@ -1,6 +1,4 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.gui.bbox;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
 
 import java.awt.Color;
@@ -13,15 +11,10 @@
 import java.awt.geom.Path2D;
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 import javax.swing.ButtonModel;
-import javax.swing.JOptionPane;
 import javax.swing.JToggleButton;
 import javax.swing.SpringLayout;
@@ -30,20 +23,11 @@
 
 import org.openstreetmap.gui.jmapviewer.Coordinate;
-import org.openstreetmap.gui.jmapviewer.JMapViewer;
 import org.openstreetmap.gui.jmapviewer.MapMarkerDot;
 import org.openstreetmap.gui.jmapviewer.MemoryTileCache;
-import org.openstreetmap.gui.jmapviewer.OsmTileLoader;
 import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
 import org.openstreetmap.gui.jmapviewer.interfaces.MapMarker;
-import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader;
 import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
-import org.openstreetmap.gui.jmapviewer.tilesources.OsmTileSource;
 import org.openstreetmap.josm.data.Bounds;
-import org.openstreetmap.josm.data.Version;
 import org.openstreetmap.josm.data.coor.LatLon;
-import org.openstreetmap.josm.data.imagery.ImageryInfo;
-import org.openstreetmap.josm.data.imagery.ImageryLayerInfo;
-import org.openstreetmap.josm.data.imagery.TMSCachedTileLoader;
-import org.openstreetmap.josm.data.imagery.TileLoaderFactory;
 import org.openstreetmap.josm.data.osm.BBox;
 import org.openstreetmap.josm.data.osm.DataSet;
@@ -51,8 +35,6 @@
 import org.openstreetmap.josm.data.preferences.StringProperty;
 import org.openstreetmap.josm.gui.MainApplication;
-import org.openstreetmap.josm.gui.layer.AbstractCachedTileSourceLayer;
 import org.openstreetmap.josm.gui.layer.ImageryLayer;
 import org.openstreetmap.josm.gui.layer.MainLayerManager;
-import org.openstreetmap.josm.gui.layer.TMSLayer;
 import org.openstreetmap.josm.spi.preferences.Config;
 import org.openstreetmap.josm.tools.Logging;
@@ -61,109 +43,6 @@
  * This panel displays a map and lets the user chose a {@link BBox}.
  */
-public class SlippyMapBBoxChooser extends JMapViewer implements BBoxChooser, ChangeListener,
+public class SlippyMapBBoxChooser extends JosmMapViewer implements BBoxChooser, ChangeListener,
     MainLayerManager.ActiveLayerChangeListener, MainLayerManager.LayerChangeListener {
-    /**
-     * A list of tile sources that can be used for displaying the map.
-     */
-    @FunctionalInterface
-    public interface TileSourceProvider {
-        /**
-         * Gets the tile sources that can be displayed
-         * @return The tile sources
-         */
-        List<TileSource> getTileSources();
-    }
-
-    /**
-     * TileSource provider for the slippymap chooser.
-     * @since 14300
-     */
-    public abstract static class AbstractImageryInfoBasedTileSourceProvider implements TileSourceProvider {
-        /**
-         * Returns the list of imagery infos backing tile sources.
-         * @return the list of imagery infos backing tile sources
-         */
-        public abstract List<ImageryInfo> getImageryInfos();
-
-        @Override
-        public List<TileSource> getTileSources() {
-            if (!TMSLayer.PROP_ADD_TO_SLIPPYMAP_CHOOSER.get()) return Collections.<TileSource>emptyList();
-            return imageryInfosToTileSources(getImageryInfos());
-        }
-    }
-
-    /**
-     * TileSource provider for the slippymap chooser - providing default OSM tile source
-     * @since 14495
-     */
-    public static class DefaultOsmTileSourceProvider implements TileSourceProvider {
-
-        protected static final StringProperty DEFAULT_OSM_TILE_URL = new StringProperty(
-                "default.osm.tile.source.url", "https://{switch:a,b,c}.tile.openstreetmap.org/{zoom}/{x}/{y}.png");
-
-        @Override
-        public List<TileSource> getTileSources() {
-            List<TileSource> result = imageryInfosToTileSources(ImageryLayerInfo.instance.getLayers().stream()
-                   .filter(l -> l.getUrl().equals(DEFAULT_OSM_TILE_URL.get())).collect(Collectors.toList()));
-            if (result.isEmpty()) {
-                result.add(new OsmTileSource.Mapnik());
-            }
-            return result;
-        }
-
-        /**
-         * Returns the default OSM tile source.
-         * @return the default OSM tile source
-         */
-        public static TileSource get() {
-            return new DefaultOsmTileSourceProvider().getTileSources().get(0);
-        }
-    }
-
-    /**
-     * TileSource provider for the slippymap chooser - providing sources from imagery sources menu
-     * @since 14300
-     */
-    public static class TMSTileSourceProvider extends AbstractImageryInfoBasedTileSourceProvider {
-        @Override
-        public List<ImageryInfo> getImageryInfos() {
-            return ImageryLayerInfo.instance.getLayers();
-        }
-    }
-
-    /**
-     * TileSource provider for the slippymap chooser - providing sources from current layers
-     * @since 14300
-     */
-    public static class CurrentLayersTileSourceProvider extends AbstractImageryInfoBasedTileSourceProvider {
-        @Override
-        public List<ImageryInfo> getImageryInfos() {
-            return MainApplication.getLayerManager().getLayers().stream().filter(
-                layer -> layer instanceof ImageryLayer
-            ).map(
-                layer -> ((ImageryLayer) layer).getInfo()
-            ).collect(Collectors.toList());
-        }
-    }
-
-    static List<TileSource> imageryInfosToTileSources(List<ImageryInfo> imageryInfos) {
-        List<TileSource> sources = new ArrayList<>();
-        for (ImageryInfo info : imageryInfos) {
-            try {
-                TileSource source = TMSLayer.getTileSourceStatic(info);
-                if (source != null) {
-                    sources.add(source);
-                }
-            } catch (IllegalArgumentException ex) {
-                Logging.warn(ex);
-                if (ex.getMessage() != null && !ex.getMessage().isEmpty()) {
-                    JOptionPane.showMessageDialog(MainApplication.getMainFrame(),
-                            ex.getMessage(), tr("Warning"),
-                            JOptionPane.WARNING_MESSAGE);
-                }
-            }
-        }
-        return sources;
-    }
 
     /**
@@ -190,7 +69,4 @@
     public static final String RESIZE_PROP = SlippyMapBBoxChooser.class.getName() + ".resize";
 
-    private final transient TileLoader cachedLoader;
-    private final transient OsmTileLoader uncachedLoader;
-
     private final SizeButton iSizeButton;
     private final ButtonModel showDownloadAreaButtonModel;
@@ -210,16 +86,4 @@
         setLayout(springLayout);
 
-        Map<String, String> headers = new HashMap<>();
-        headers.put("User-Agent", Version.getInstance().getFullAgentString());
-
-        TileLoaderFactory cachedLoaderFactory = AbstractCachedTileSourceLayer.getTileLoaderFactory("TMS", TMSCachedTileLoader.class);
-        if (cachedLoaderFactory != null) {
-            cachedLoader = cachedLoaderFactory.makeTileLoader(this, headers, TimeUnit.HOURS.toSeconds(1));
-        } else {
-            cachedLoader = null;
-        }
-
-        uncachedLoader = new OsmTileLoader(this);
-        uncachedLoader.headers.putAll(headers);
         setZoomControlsVisible(Config.getPref().getBoolean("slippy_map_chooser.zoomcontrols", false));
         setMapMarkerVisible(false);
@@ -350,24 +214,4 @@
         PROP_SHOWDLAREA.put(this.showDownloadAreaButtonModel.isSelected());
         this.repaint();
-    }
-
-    /**
-     * Enables the disk tile cache.
-     * @param enabled true to enable, false to disable
-     */
-    public final void setFileCacheEnabled(boolean enabled) {
-        if (enabled && cachedLoader != null) {
-            setTileLoader(cachedLoader);
-        } else {
-            setTileLoader(uncachedLoader);
-        }
-    }
-
-    /**
-     * Sets the maximum number of tiles that may be held in memory
-     * @param tiles The maximum number of tiles.
-     */
-    public final void setMaxTilesInMemory(int tiles) {
-        ((MemoryTileCache) getTileCache()).setCacheSize(tiles);
     }
 
Index: trunk/src/org/openstreetmap/josm/gui/bbox/TileSelectionBBoxChooser.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/bbox/TileSelectionBBoxChooser.java	(revision 15143)
+++ trunk/src/org/openstreetmap/josm/gui/bbox/TileSelectionBBoxChooser.java	(revision 15145)
@@ -40,11 +40,7 @@
 import javax.swing.text.JTextComponent;
 
-import org.openstreetmap.gui.jmapviewer.JMapViewer;
 import org.openstreetmap.gui.jmapviewer.MapMarkerDot;
-import org.openstreetmap.gui.jmapviewer.OsmTileLoader;
 import org.openstreetmap.gui.jmapviewer.interfaces.MapMarker;
-import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader;
 import org.openstreetmap.josm.data.Bounds;
-import org.openstreetmap.josm.data.Version;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.gui.widgets.AbstractTextComponentValidator;
@@ -657,5 +653,5 @@
      * The map view used in this bounding box chooser
      */
-    private static final class TileBoundsMapView extends JMapViewer {
+    private static final class TileBoundsMapView extends JosmMapViewer {
         private Point min;
         private Point max;
@@ -663,8 +659,4 @@
         private TileBoundsMapView() {
             setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY));
-            TileLoader loader = tileController.getTileLoader();
-            if (loader instanceof OsmTileLoader) {
-                ((OsmTileLoader) loader).headers.put("User-Agent", Version.getInstance().getFullAgentString());
-            }
         }
 
Index: trunk/src/org/openstreetmap/josm/gui/history/CoordinateInfoViewer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/history/CoordinateInfoViewer.java	(revision 15143)
+++ trunk/src/org/openstreetmap/josm/gui/history/CoordinateInfoViewer.java	(revision 15145)
@@ -24,4 +24,5 @@
 import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive;
 import org.openstreetmap.josm.gui.NavigatableComponent;
+import org.openstreetmap.josm.gui.bbox.JosmMapViewer;
 import org.openstreetmap.josm.gui.bbox.SlippyMapBBoxChooser;
 import org.openstreetmap.josm.gui.util.GuiHelper;
@@ -317,5 +318,5 @@
     }
 
-    private static class MapViewer extends JMapViewer implements ChangeListener {
+    private static class MapViewer extends JosmMapViewer implements ChangeListener {
 
         private final transient Updater updater;
Index: trunk/src/org/openstreetmap/josm/gui/preferences/imagery/ImageryProvidersPanel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/imagery/ImageryProvidersPanel.java	(revision 15143)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/imagery/ImageryProvidersPanel.java	(revision 15145)
@@ -44,5 +44,4 @@
 
 import org.openstreetmap.gui.jmapviewer.Coordinate;
-import org.openstreetmap.gui.jmapviewer.JMapViewer;
 import org.openstreetmap.gui.jmapviewer.MapPolygonImpl;
 import org.openstreetmap.gui.jmapviewer.MapRectangleImpl;
@@ -56,4 +55,5 @@
 import org.openstreetmap.josm.data.preferences.NamedColorProperty;
 import org.openstreetmap.josm.gui.MainApplication;
+import org.openstreetmap.josm.gui.bbox.JosmMapViewer;
 import org.openstreetmap.josm.gui.bbox.SlippyMapBBoxChooser;
 import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
@@ -74,5 +74,5 @@
  */
 public class ImageryProvidersPanel extends JPanel {
-    // Public JTables and JMapViewer
+    // Public JTables and JosmMapViewer
     /** The table of active providers **/
     public final JTable activeTable;
@@ -84,5 +84,5 @@
     private final transient DefListSelectionListener defaultTableListener;
     /** The map displaying imagery bounds of selected default providers **/
-    public final JMapViewer defaultMap;
+    public final JosmMapViewer defaultMap;
 
     // Public models
@@ -265,5 +265,5 @@
 
         // Add default item map
-        defaultMap = new JMapViewer();
+        defaultMap = new JosmMapViewer();
         defaultMap.setTileSource(SlippyMapBBoxChooser.DefaultOsmTileSourceProvider.get()); // for attribution
         defaultMap.addMouseListener(new MouseAdapter() {
