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 java.awt.event.ActionEvent; 007import java.util.ArrayList; 008import java.util.Arrays; 009import java.util.List; 010import java.util.Map; 011import java.util.Set; 012import java.util.TreeSet; 013 014import javax.swing.AbstractAction; 015import javax.swing.Action; 016 017import org.apache.commons.jcs.access.CacheAccess; 018import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader; 019import org.openstreetmap.gui.jmapviewer.interfaces.TileSource; 020import org.openstreetmap.gui.jmapviewer.tilesources.AbstractTMSTileSource; 021import org.openstreetmap.josm.Main; 022import org.openstreetmap.josm.data.cache.BufferedImageCacheEntry; 023import org.openstreetmap.josm.data.imagery.ImageryInfo; 024import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType; 025import org.openstreetmap.josm.data.imagery.ImageryLayerInfo; 026import org.openstreetmap.josm.data.imagery.TemplatedWMSTileSource; 027import org.openstreetmap.josm.data.imagery.WMSCachedTileLoader; 028import org.openstreetmap.josm.data.preferences.BooleanProperty; 029import org.openstreetmap.josm.data.preferences.IntegerProperty; 030import org.openstreetmap.josm.data.projection.Projection; 031 032/** 033 * This is a layer that grabs the current screen from an WMS server. The data 034 * fetched this way is tiled and managed to the disc to reduce server load. 035 * 036 */ 037public class WMSLayer extends AbstractCachedTileSourceLayer { 038 private static final String PREFERENCE_PREFIX = "imagery.wms."; 039 040 /** default tile size for WMS Layer */ 041 public static final IntegerProperty PROP_IMAGE_SIZE = new IntegerProperty(PREFERENCE_PREFIX + "imageSize", 512); 042 043 /** should WMS layer autozoom in default mode */ 044 public static final BooleanProperty PROP_DEFAULT_AUTOZOOM = new BooleanProperty(PREFERENCE_PREFIX + "default_autozoom", true); 045 046 /** limit of concurrent connections to WMS tile source (per source) */ 047 public static final IntegerProperty THREAD_LIMIT = new IntegerProperty(PREFERENCE_PREFIX + "simultaneousConnections", 3); 048 049 private static final String CACHE_REGION_NAME = "WMS"; 050 051 private Set<String> supportedProjections; 052 053 /** 054 * Constructs a new {@code WMSLayer}. 055 * @param info ImageryInfo description of the layer 056 */ 057 public WMSLayer(ImageryInfo info) { 058 super(info); 059 this.supportedProjections = new TreeSet<>(info.getServerProjections()); 060 this.autoZoom = PROP_DEFAULT_AUTOZOOM.get(); 061 062 } 063 064 @Override 065 public Action[] getMenuEntries() { 066 List<Action> ret = new ArrayList<>(); 067 ret.addAll(Arrays.asList(super.getMenuEntries())); 068 ret.add(SeparatorLayerAction.INSTANCE); 069 ret.add(new LayerSaveAction(this)); 070 ret.add(new LayerSaveAsAction(this)); 071 ret.add(new BookmarkWmsAction()); 072 return ret.toArray(new Action[]{}); 073 } 074 075 @Override 076 protected AbstractTMSTileSource getTileSource(ImageryInfo info) { 077 if (info.getImageryType() == ImageryType.WMS && info.getUrl() != null) { 078 TemplatedWMSTileSource.checkUrl(info.getUrl()); 079 TemplatedWMSTileSource tileSource = new TemplatedWMSTileSource(info); 080 info.setAttribution(tileSource); 081 return tileSource; 082 } 083 return null; 084 } 085 086 /** 087 * This action will add a WMS layer menu entry with the current WMS layer 088 * URL and name extended by the current resolution. 089 * When using the menu entry again, the WMS cache will be used properly. 090 */ 091 public class BookmarkWmsAction extends AbstractAction { 092 /** 093 * Constructs a new {@code BookmarkWmsAction}. 094 */ 095 public BookmarkWmsAction() { 096 super(tr("Set WMS Bookmark")); 097 } 098 099 @Override 100 public void actionPerformed(ActionEvent ev) { 101 ImageryLayerInfo.addLayer(new ImageryInfo(info)); 102 } 103 } 104 105 @Override 106 protected Map<String, String> getHeaders(TileSource tileSource) { 107 if (tileSource instanceof TemplatedWMSTileSource) { 108 return ((TemplatedWMSTileSource) tileSource).getHeaders(); 109 } 110 return null; 111 } 112 113 @Override 114 public boolean isProjectionSupported(Projection proj) { 115 return supportedProjections == null || supportedProjections.isEmpty() || supportedProjections.contains(proj.toCode()); 116 } 117 118 @Override 119 public String nameSupportedProjections() { 120 StringBuilder ret = new StringBuilder(); 121 for (String e: supportedProjections) { 122 ret.append(e).append(", "); 123 } 124 String appendix = ""; 125 126 if (supportedProjections.contains("EPSG:4326") && "EPSG:3857".equals(Main.getProjection().toCode())) { 127 appendix = ". " + tr("JOSM will use EPSG:4326 to query the server, but results may vary " 128 + "depending on the WMS server"); 129 } 130 return ret.substring(0, ret.length()-2) + appendix; 131 } 132 133 @Override 134 public void projectionChanged(Projection oldValue, Projection newValue) { 135 super.projectionChanged(oldValue, newValue); 136 137 if (!newValue.equals(oldValue) && tileSource instanceof TemplatedWMSTileSource) { 138 ((TemplatedWMSTileSource) tileSource).initProjection(newValue); 139 } 140 } 141 142 @Override 143 protected Class<? extends TileLoader> getTileLoaderClass() { 144 return WMSCachedTileLoader.class; 145 } 146 147 @Override 148 protected String getCacheName() { 149 return CACHE_REGION_NAME; 150 } 151 152 /** 153 * @return cache region for WMS layer 154 */ 155 public static CacheAccess<String, BufferedImageCacheEntry> getCache() { 156 return AbstractCachedTileSourceLayer.getCache(CACHE_REGION_NAME); 157 } 158}