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.HashMap; 008 009import org.openstreetmap.josm.Main; 010import org.openstreetmap.josm.data.imagery.ImageryInfo; 011import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType; 012import org.openstreetmap.josm.data.imagery.ImageryLayerInfo; 013import org.openstreetmap.josm.gui.layer.ImageryLayer; 014import org.openstreetmap.josm.gui.util.GuiHelper; 015import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault; 016import org.openstreetmap.josm.tools.Utils; 017 018/** 019 * Adds an imagery (WMS/TMS) layer. For instance, {@code /imagery?title=...&type=...&url=...}. 020 * @since 3715 021 */ 022public class ImageryHandler extends RequestHandler { 023 024 /** 025 * The remote control command name used to add an imagery layer. 026 */ 027 public static final String command = "imagery"; 028 029 @Override 030 public String getPermissionMessage() { 031 return tr("Remote Control has been asked to load an imagery layer from the following URL:") 032 + "<br>" + args.get("url"); 033 } 034 035 @Override 036 public String[] getMandatoryParams() { 037 return new String[]{"url"}; 038 } 039 040 @Override 041 public String[] getOptionalParams() { 042 return new String[] { "title", "type", "cookies", "min_zoom", "max_zoom"}; 043 } 044 045 @Override 046 public PermissionPrefWithDefault getPermissionPref() { 047 return PermissionPrefWithDefault.LOAD_IMAGERY; 048 } 049 050 protected static ImageryInfo findBingEntry() { 051 for (ImageryInfo i : ImageryLayerInfo.instance.getDefaultLayers()) { 052 if (ImageryType.BING.equals(i.getImageryType())) { 053 return i; 054 } 055 } 056 return null; 057 } 058 059 protected ImageryInfo buildImageryInfo() { 060 String url = args.get("url"); 061 String title = args.get("title"); 062 String type = args.get("type"); 063 final ImageryInfo bing = ImageryType.BING.getTypeString().equals(type) ? findBingEntry() : null; 064 if ((title == null || title.isEmpty()) && bing != null) { 065 title = bing.getName(); 066 } 067 if (title == null || title.isEmpty()) { 068 title = tr("Remote imagery"); 069 } 070 String cookies = args.get("cookies"); 071 final ImageryInfo imgInfo = new ImageryInfo(title, url, type, null, cookies); 072 if (bing != null) { 073 imgInfo.setIcon(bing.getIcon()); 074 } 075 String minZoom = args.get("min_zoom"); 076 if (minZoom != null && !minZoom.isEmpty()) { 077 try { 078 imgInfo.setDefaultMinZoom(Integer.parseInt(minZoom)); 079 } catch (NumberFormatException e) { 080 Main.error(e); 081 } 082 } 083 String maxZoom = args.get("max_zoom"); 084 if (maxZoom != null && !maxZoom.isEmpty()) { 085 try { 086 imgInfo.setDefaultMaxZoom(Integer.parseInt(maxZoom)); 087 } catch (NumberFormatException e) { 088 Main.error(e); 089 } 090 } 091 return imgInfo; 092 } 093 094 @Override 095 protected void handleRequest() throws RequestHandlerErrorException { 096 final ImageryInfo imgInfo = buildImageryInfo(); 097 if (Main.isDisplayingMapView()) { 098 for (ImageryLayer layer : Main.map.mapView.getLayersOfType(ImageryLayer.class)) { 099 if (layer.getInfo().equals(imgInfo)) { 100 Main.info("Imagery layer already exists: "+imgInfo); 101 return; 102 } 103 } 104 } 105 GuiHelper.runInEDT(new Runnable() { 106 @Override 107 public void run() { 108 try { 109 Main.main.addLayer(ImageryLayer.create(imgInfo)); 110 } catch (IllegalArgumentException e) { 111 Main.error(e, false); 112 } 113 } 114 }); 115 } 116 117 @Override 118 protected void parseArgs() { 119 HashMap<String, String> args = new HashMap<>(); 120 if (request.indexOf('?') != -1) { 121 String query = request.substring(request.indexOf('?') + 1); 122 if (query.indexOf("url=") == 0) { 123 args.put("url", decodeParam(query.substring(4))); 124 } else { 125 int urlIdx = query.indexOf("&url="); 126 if (urlIdx != -1) { 127 args.put("url", decodeParam(query.substring(urlIdx + 5))); 128 query = query.substring(0, urlIdx); 129 } else if (query.indexOf('#') != -1) { 130 query = query.substring(0, query.indexOf('#')); 131 } 132 String[] params = query.split("&", -1); 133 for (String param : params) { 134 int eq = param.indexOf('='); 135 if (eq != -1) { 136 args.put(param.substring(0, eq), decodeParam(param.substring(eq + 1))); 137 } 138 } 139 } 140 } 141 this.args = args; 142 } 143 144 @Override 145 protected void validateRequest() throws RequestHandlerBadRequestException { 146 String url = args.get("url"); 147 String type = args.get("type"); 148 String cookies = args.get("cookies"); 149 try { 150 ImageryLayer.create(new ImageryInfo(null, url, type, null, cookies)); 151 } catch (IllegalArgumentException e) { 152 throw new RequestHandlerBadRequestException(e.getMessage(), e); 153 } 154 } 155 156 @Override 157 public String getUsage() { 158 return "adds an imagery layer (e.g. WMS, TMS)"; 159 } 160 161 @Override 162 public String[] getUsageExamples() { 163 final String types = Utils.join("|", Utils.transform(Arrays.asList(ImageryInfo.ImageryType.values()), new Utils.Function<ImageryInfo.ImageryType, String>() { 164 @Override 165 public String apply(ImageryInfo.ImageryType x) { 166 return x.getTypeString(); 167 } 168 })); 169 return new String[] { "/imagery?title=osm&type=tms&url=https://a.tile.openstreetmap.org/%7Bzoom%7D/%7Bx%7D/%7By%7D.png", 170 "/imagery?title=landsat&type=wms&url=http://irs.gis-lab.info/?layers=landsat&SRS=%7Bproj%7D&WIDTH=%7Bwidth%7D&HEIGHT=%7Bheight%7D&BBOX=%7Bbbox%7D", 171 "/imagery?title=...&type={"+types+"}&url=....[&cookies=...][&min_zoom=...][&max_zoom=...]"}; 172 } 173}