001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.io.remotecontrol.handler; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.util.Arrays; 007import java.util.LinkedHashSet; 008import java.util.Map; 009import java.util.Objects; 010import java.util.Set; 011 012import org.openstreetmap.josm.data.StructUtils; 013import org.openstreetmap.josm.data.imagery.ImageryInfo; 014import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryPreferenceEntry; 015import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType; 016import org.openstreetmap.josm.data.imagery.ImageryLayerInfo; 017import org.openstreetmap.josm.gui.MainApplication; 018import org.openstreetmap.josm.gui.layer.ImageryLayer; 019import org.openstreetmap.josm.gui.util.GuiHelper; 020import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault; 021import org.openstreetmap.josm.tools.CheckParameterUtil; 022import org.openstreetmap.josm.tools.Logging; 023import org.openstreetmap.josm.tools.Utils; 024 025/** 026 * Adds an imagery (WMS/TMS) layer. For instance, {@code /imagery?title=...&type=...&url=...}. 027 * @since 3715 028 */ 029public class ImageryHandler extends RequestHandler.RawURLParseRequestHandler { 030 031 /** 032 * The remote control command name used to add an imagery layer. 033 */ 034 public static final String command = "imagery"; 035 036 @Override 037 public String getPermissionMessage() { 038 return tr("Remote Control has been asked to load an imagery layer from the following URL:") 039 + "<br>" + args.getOrDefault("url", args.get("id")); 040 } 041 042 @Override 043 public String[] getMandatoryParams() { 044 return new String[0]; 045 } 046 047 @Override 048 public String[] getOptionalParams() { 049 Set<String> params = new LinkedHashSet<>(); 050 params.add("url"); 051 params.add("id"); 052 Map<String, String> struct = StructUtils.serializeStruct(new ImageryPreferenceEntry(), ImageryPreferenceEntry.class, 053 StructUtils.SerializeOptions.INCLUDE_NULL, StructUtils.SerializeOptions.INCLUDE_DEFAULT); 054 params.addAll(struct.keySet()); 055 return params.toArray(new String[0]); 056 } 057 058 @Override 059 public PermissionPrefWithDefault getPermissionPref() { 060 return PermissionPrefWithDefault.LOAD_IMAGERY; 061 } 062 063 protected ImageryInfo buildImageryInfo() { 064 String id = args.get("id"); 065 if (id != null) { 066 return ImageryLayerInfo.instance.getAllDefaultLayers().stream() 067 .filter(l -> Objects.equals(l.getId(), id)) 068 .findFirst() 069 .orElseThrow(() -> new IllegalArgumentException("Cannot find layer for id " + id)); 070 } 071 args.computeIfAbsent("type", ignore -> ImageryType.WMS.getDefault().getTypeString()); 072 args.computeIfAbsent("name", ignore -> args.getOrDefault("title", tr("Remote imagery"))); 073 ImageryPreferenceEntry imageryPreferenceEntry = StructUtils.deserializeStruct(args, ImageryPreferenceEntry.class); 074 return new ImageryInfo(imageryPreferenceEntry); 075 } 076 077 @Override 078 protected void handleRequest() throws RequestHandlerErrorException { 079 final ImageryInfo imgInfo = buildImageryInfo(); 080 if (MainApplication.isDisplayingMapView()) { 081 for (ImageryLayer layer : MainApplication.getLayerManager().getLayersOfType(ImageryLayer.class)) { 082 if (layer.getInfo().equals(imgInfo)) { 083 Logging.info("Imagery layer already exists: "+imgInfo); 084 return; 085 } 086 } 087 } 088 GuiHelper.runInEDT(() -> { 089 try { 090 MainApplication.getLayerManager().addLayer(ImageryLayer.create(imgInfo)); 091 } catch (IllegalArgumentException e) { 092 Logging.log(Logging.LEVEL_ERROR, e); 093 } 094 }); 095 } 096 097 @Override 098 protected void validateRequest() throws RequestHandlerBadRequestException { 099 try { 100 CheckParameterUtil.ensureParameterNotNull(args); 101 CheckParameterUtil.ensureThat(args.containsKey("url") || args.containsKey("id"), 102 tr("The following keys are mandatory, but have not been provided: {0}", "url/id")); 103 ImageryLayer.create(buildImageryInfo()); 104 } catch (IllegalArgumentException e) { 105 throw new RequestHandlerBadRequestException(e.getMessage(), e); 106 } 107 } 108 109 @Override 110 public String getUsage() { 111 return "adds an imagery layer (e.g. WMS, TMS)"; 112 } 113 114 @Override 115 public String[] getUsageExamples() { 116 final String types = String.join("|", Utils.transform(Arrays.asList(ImageryInfo.ImageryType.values()), 117 ImageryType::getTypeString)); 118 return new String[] { 119 "/imagery?id=Bing", 120 "/imagery?title=osm&type=tms&url=https://a.tile.openstreetmap.org/%7Bzoom%7D/%7Bx%7D/%7By%7D.png", 121 "/imagery?title=landsat&type=wms&url=http://irs.gis-lab.info/?" + 122 "layers=landsat&SRS=%7Bproj%7D&WIDTH=%7Bwidth%7D&HEIGHT=%7Bheight%7D&BBOX=%7Bbbox%7D", 123 "/imagery?title=...&type={"+types+"}&url=....[&cookies=...][&min_zoom=...][&max_zoom=...]" 124 }; 125 } 126}