// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.gui.layer; import static org.openstreetmap.josm.tools.I18n.tr; import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Objects; import javax.swing.AbstractAction; import javax.swing.Action; import org.apache.commons.jcs.access.CacheAccess; import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.data.cache.BufferedImageCacheEntry; import org.openstreetmap.josm.data.imagery.AbstractWMSTileSource; import org.openstreetmap.josm.data.imagery.ImageryInfo; import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType; import org.openstreetmap.josm.data.imagery.ImageryLayerInfo; import org.openstreetmap.josm.data.imagery.TemplatedWMSTileSource; import org.openstreetmap.josm.data.imagery.WMSCachedTileLoader; import org.openstreetmap.josm.data.preferences.BooleanProperty; import org.openstreetmap.josm.data.preferences.IntegerProperty; import org.openstreetmap.josm.data.projection.Projection; import org.openstreetmap.josm.data.projection.Projections; import org.openstreetmap.josm.gui.layer.imagery.TileSourceDisplaySettings; import org.openstreetmap.josm.tools.CheckParameterUtil; import org.openstreetmap.josm.tools.Utils; /** * This is a layer that grabs the current screen from an WMS server. The data * fetched this way is tiled and managed to the disc to reduce server load. * */ public class WMSLayer extends AbstractCachedTileSourceLayer<AbstractWMSTileSource> { private static final String PREFERENCE_PREFIX = "imagery.wms"; /** * Registers all setting properties */ static { new TileSourceDisplaySettings(PREFERENCE_PREFIX); } /** default tile size for WMS Layer */ public static final IntegerProperty PROP_IMAGE_SIZE = new IntegerProperty(PREFERENCE_PREFIX + ".imageSize", 512); /** should WMS layer autozoom in default mode */ public static final BooleanProperty PROP_DEFAULT_AUTOZOOM = new BooleanProperty(PREFERENCE_PREFIX + ".default_autozoom", true); private static final String CACHE_REGION_NAME = "WMS"; private final List<String> serverProjections; /** * Constructs a new {@code WMSLayer}. * @param info ImageryInfo description of the layer */ public WMSLayer(ImageryInfo info) { super(info); CheckParameterUtil.ensureThat(info.getImageryType() == ImageryType.WMS, "ImageryType is WMS"); CheckParameterUtil.ensureParameterNotNull(info.getUrl(), "info.url"); TemplatedWMSTileSource.checkUrl(info.getUrl()); this.serverProjections = new ArrayList<>(info.getServerProjections()); } @Override protected TileSourceDisplaySettings createDisplaySettings() { return new TileSourceDisplaySettings(PREFERENCE_PREFIX); } @Override public Action[] getMenuEntries() { List<Action> ret = new ArrayList<>(); ret.addAll(Arrays.asList(super.getMenuEntries())); ret.add(SeparatorLayerAction.INSTANCE); ret.add(new LayerSaveAction(this)); ret.add(new LayerSaveAsAction(this)); ret.add(new BookmarkWmsAction()); return ret.toArray(new Action[ret.size()]); } @Override protected AbstractWMSTileSource getTileSource() { AbstractWMSTileSource tileSource = new TemplatedWMSTileSource( info, chooseProjection(Main.getProjection())); info.setAttribution(tileSource); return tileSource; } /** * This action will add a WMS layer menu entry with the current WMS layer * URL and name extended by the current resolution. * When using the menu entry again, the WMS cache will be used properly. */ public class BookmarkWmsAction extends AbstractAction { /** * Constructs a new {@code BookmarkWmsAction}. */ public BookmarkWmsAction() { super(tr("Set WMS Bookmark")); } @Override public void actionPerformed(ActionEvent ev) { ImageryLayerInfo.addLayer(new ImageryInfo(info)); } } @Override public Collection<String> getNativeProjections() { return serverProjections; } @Override public void projectionChanged(Projection oldValue, Projection newValue) { Projection tileProjection = chooseProjection(newValue); if (!Objects.equals(tileSource.getTileProjection(), tileProjection)) { tileSource.setTileProjection(tileProjection); } } private Projection chooseProjection(Projection requested) { if (serverProjections.contains(requested.toCode())) { return requested; } else { for (String code : serverProjections) { Projection proj = Projections.getProjectionByCode(code); if (proj != null) { Main.info(tr("Reprojecting layer {0} from {1} to {2}. For best image quality and performance," + " switch to one of the supported projections: {3}", getName(), proj.toCode(), Main.getProjection().toCode(), Utils.join(", ", getNativeProjections()))); return proj; } } Main.warn(tr("Unable to find supported projection for layer {0}. Using {1}.", getName(), requested.toCode())); return requested; } } @Override protected Class<? extends TileLoader> getTileLoaderClass() { return WMSCachedTileLoader.class; } @Override protected String getCacheName() { return CACHE_REGION_NAME; } /** * @return cache region for WMS layer */ public static CacheAccess<String, BufferedImageCacheEntry> getCache() { return AbstractCachedTileSourceLayer.getCache(CACHE_REGION_NAME); } }