001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.layer;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import org.apache.commons.jcs.access.CacheAccess;
007import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader;
008import org.openstreetmap.gui.jmapviewer.tilesources.AbstractTMSTileSource;
009import org.openstreetmap.gui.jmapviewer.tilesources.ScanexTileSource;
010import org.openstreetmap.gui.jmapviewer.tilesources.TMSTileSource;
011import org.openstreetmap.gui.jmapviewer.tilesources.TemplatedTMSTileSource;
012import org.openstreetmap.josm.Main;
013import org.openstreetmap.josm.data.cache.BufferedImageCacheEntry;
014import org.openstreetmap.josm.data.imagery.CachedAttributionBingAerialTileSource;
015import org.openstreetmap.josm.data.imagery.ImageryInfo;
016import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
017import org.openstreetmap.josm.data.imagery.TMSCachedTileLoader;
018import org.openstreetmap.josm.data.preferences.BooleanProperty;
019import org.openstreetmap.josm.data.preferences.IntegerProperty;
020import org.openstreetmap.josm.data.projection.Projection;
021
022/**
023 * Class that displays a slippy map layer.
024 *
025 * @author Frederik Ramm
026 * @author LuVar <lubomir.varga@freemap.sk>
027 * @author Dave Hansen <dave@sr71.net>
028 * @author Upliner <upliner@gmail.com>
029 *
030 */
031public class TMSLayer extends AbstractCachedTileSourceLayer {
032    private static final String CACHE_REGION_NAME = "TMS";
033
034    private static final String PREFERENCE_PREFIX = "imagery.tms";
035
036    /** minimum zoom level for TMS layer */
037    public static final IntegerProperty PROP_MIN_ZOOM_LVL = new IntegerProperty(PREFERENCE_PREFIX + ".min_zoom_lvl",
038            AbstractTileSourceLayer.PROP_MIN_ZOOM_LVL.get());
039    /** maximum zoom level for TMS layer */
040    public static final IntegerProperty PROP_MAX_ZOOM_LVL = new IntegerProperty(PREFERENCE_PREFIX + ".max_zoom_lvl",
041            AbstractTileSourceLayer.PROP_MAX_ZOOM_LVL.get());
042    /** shall TMS layers be added to download dialog */
043    public static final BooleanProperty PROP_ADD_TO_SLIPPYMAP_CHOOSER = new BooleanProperty(PREFERENCE_PREFIX + ".add_to_slippymap_chooser",
044            true);
045
046    /**
047     * Create a layer based on ImageryInfo
048     * @param info description of the layer
049     */
050    public TMSLayer(ImageryInfo info) {
051        super(info);
052    }
053
054
055    /**
056     * Creates and returns a new TileSource instance depending on the {@link ImageryType}
057     * of the passed ImageryInfo object.
058     *
059     * If no appropriate TileSource is found, null is returned.
060     * Currently supported ImageryType are {@link ImageryType#TMS},
061     * {@link ImageryType#BING}, {@link ImageryType#SCANEX}.
062     *
063     *
064     * @param info imagery info
065     * @return a new TileSource instance or null if no TileSource for the ImageryInfo/ImageryType could be found.
066     * @throws IllegalArgumentException if url from imagery info is null or invalid
067     */
068    @Override
069    protected AbstractTMSTileSource getTileSource(ImageryInfo info) throws IllegalArgumentException {
070        return getTileSourceStatic(info, new Runnable() {
071            @Override
072            public void run() {
073                Main.debug("Attribution loaded, running loadAllErrorTiles");
074                TMSLayer.this.loadAllErrorTiles(true);
075            }
076        });
077    }
078
079    /**
080     * Adds a context menu to the mapView.
081     */
082
083    @Override
084    public final boolean isProjectionSupported(Projection proj) {
085        return "EPSG:3857".equals(proj.toCode()) || "EPSG:4326".equals(proj.toCode());
086    }
087
088    @Override
089    public final String nameSupportedProjections() {
090        return tr("EPSG:4326 and Mercator projection are supported");
091    }
092
093    /**
094     * Creates and returns a new TileSource instance depending on the {@link ImageryType}
095     * of the passed ImageryInfo object.
096     *
097     * If no appropriate TileSource is found, null is returned.
098     * Currently supported ImageryType are {@link ImageryType#TMS},
099     * {@link ImageryType#BING}, {@link ImageryType#SCANEX}.
100     *
101     * @param info imagery info
102     * @return a new TileSource instance or null if no TileSource for the ImageryInfo/ImageryType could be found.
103     * @throws IllegalArgumentException if url from imagery info is null or invalid
104     */
105    public static AbstractTMSTileSource getTileSourceStatic(ImageryInfo info) throws IllegalArgumentException {
106        return getTileSourceStatic(info, null);
107    }
108
109    /**
110     * Creates and returns a new TileSource instance depending on the {@link ImageryType}
111     * of the passed ImageryInfo object.
112     *
113     * If no appropriate TileSource is found, null is returned.
114     * Currently supported ImageryType are {@link ImageryType#TMS},
115     * {@link ImageryType#BING}, {@link ImageryType#SCANEX}.
116     *
117     * @param info imagery info
118     * @param attributionLoadedTask task to be run once attribution is loaded, might be null, if nothing special shall happen
119     * @return a new TileSource instance or null if no TileSource for the ImageryInfo/ImageryType could be found.
120     * @throws IllegalArgumentException if url from imagery info is null or invalid
121     */
122    public static AbstractTMSTileSource getTileSourceStatic(ImageryInfo info, Runnable attributionLoadedTask) throws IllegalArgumentException {
123        if (info.getImageryType() == ImageryType.TMS) {
124            TemplatedTMSTileSource.checkUrl(info.getUrl());
125            TMSTileSource t = new TemplatedTMSTileSource(info);
126            info.setAttribution(t);
127            return t;
128        } else if (info.getImageryType() == ImageryType.BING)
129            return new CachedAttributionBingAerialTileSource(info, attributionLoadedTask);
130        else if (info.getImageryType() == ImageryType.SCANEX) {
131            return new ScanexTileSource(info);
132        }
133        return null;
134    }
135
136    @Override
137    protected Class<? extends TileLoader> getTileLoaderClass() {
138        return TMSCachedTileLoader.class;
139    }
140
141    @Override
142    protected String getCacheName() {
143        return CACHE_REGION_NAME;
144    }
145
146    /**
147     * @return cache for TMS region
148     */
149    public static CacheAccess<String, BufferedImageCacheEntry> getCache() {
150        return AbstractCachedTileSourceLayer.getCache(CACHE_REGION_NAME);
151    }
152
153}