001 // License: GPL. For details, see LICENSE file. 002 package org.openstreetmap.josm.io.remotecontrol.handler; 003 004 import static org.openstreetmap.josm.tools.I18n.tr; 005 006 import java.awt.geom.Area; 007 import java.awt.geom.Rectangle2D; 008 import java.io.UnsupportedEncodingException; 009 import java.net.URLDecoder; 010 import java.util.HashSet; 011 import java.util.Map; 012 import java.util.concurrent.Future; 013 014 import org.openstreetmap.josm.Main; 015 import org.openstreetmap.josm.actions.AutoScaleAction; 016 import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask; 017 import org.openstreetmap.josm.actions.downloadtasks.DownloadTask; 018 import org.openstreetmap.josm.actions.downloadtasks.PostDownloadHandler; 019 import org.openstreetmap.josm.data.Bounds; 020 import org.openstreetmap.josm.data.coor.LatLon; 021 import org.openstreetmap.josm.data.osm.DataSet; 022 import org.openstreetmap.josm.data.osm.Node; 023 import org.openstreetmap.josm.data.osm.OsmPrimitive; 024 import org.openstreetmap.josm.data.osm.Relation; 025 import org.openstreetmap.josm.data.osm.Way; 026 import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor; 027 import org.openstreetmap.josm.io.remotecontrol.AddTagsDialog; 028 import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault; 029 import org.openstreetmap.josm.tools.Utils; 030 031 /** 032 * Handler for load_and_zoom request. 033 */ 034 public class LoadAndZoomHandler extends RequestHandler 035 { 036 public static final String command = "load_and_zoom"; 037 public static final String command2 = "zoom"; 038 039 @Override 040 public String getPermissionMessage() 041 { 042 return tr("Remote Control has been asked to load data from the API.") + 043 "<br>" + tr("Request details: {0}", request); 044 } 045 046 @Override 047 public String[] getMandatoryParams() 048 { 049 return new String[] { "bottom", "top", "left", "right" }; 050 } 051 052 @Override 053 protected void handleRequest() throws RequestHandlerErrorException 054 { 055 DownloadTask osmTask = new DownloadOsmTask(); 056 double minlat = 0; 057 double maxlat = 0; 058 double minlon = 0; 059 double maxlon = 0; 060 try { 061 minlat = LatLon.roundToOsmPrecision(Double.parseDouble(args.get("bottom"))); 062 maxlat = LatLon.roundToOsmPrecision(Double.parseDouble(args.get("top"))); 063 minlon = LatLon.roundToOsmPrecision(Double.parseDouble(args.get("left"))); 064 maxlon = LatLon.roundToOsmPrecision(Double.parseDouble(args.get("right"))); 065 boolean newLayer = isLoadInNewLayer(); 066 067 if(command.equals(myCommand)) 068 { 069 if (!PermissionPrefWithDefault.LOAD_DATA.isAllowed()) 070 { 071 System.out.println("RemoteControl: download forbidden by preferences"); 072 } 073 else 074 { 075 Area toDownload = null; 076 if (!newLayer) { 077 // find out whether some data has already been downloaded 078 Area present = null; 079 DataSet ds = Main.main.getCurrentDataSet(); 080 if (ds != null) { 081 present = ds.getDataSourceArea(); 082 } 083 if (present != null && !present.isEmpty()) { 084 toDownload = new Area(new Rectangle2D.Double(minlon,minlat,maxlon-minlon,maxlat-minlat)); 085 toDownload.subtract(present); 086 if (!toDownload.isEmpty()) 087 { 088 // the result might not be a rectangle (L shaped etc) 089 Rectangle2D downloadBounds = toDownload.getBounds2D(); 090 minlat = downloadBounds.getMinY(); 091 minlon = downloadBounds.getMinX(); 092 maxlat = downloadBounds.getMaxY(); 093 maxlon = downloadBounds.getMaxX(); 094 } 095 } 096 } 097 if (toDownload != null && toDownload.isEmpty()) 098 { 099 System.out.println("RemoteControl: no download necessary"); 100 } 101 else 102 { 103 Future<?> future = osmTask.download(newLayer, new Bounds(minlat,minlon,maxlat,maxlon), null /* let the task manage the progress monitor */); 104 Main.worker.submit(new PostDownloadHandler(osmTask, future)); 105 } 106 } 107 } 108 } catch (Exception ex) { 109 System.out.println("RemoteControl: Error parsing load_and_zoom remote control request:"); 110 ex.printStackTrace(); 111 throw new RequestHandlerErrorException(); 112 } 113 114 /** 115 * deselect objects if parameter addtags given 116 */ 117 if (args.containsKey("addtags")) { 118 Main.worker.execute(new Runnable() { 119 public void run() { 120 DataSet ds = Main.main.getCurrentDataSet(); 121 if(ds == null) // e.g. download failed 122 return; 123 ds.clearSelection(); 124 } 125 }); 126 } 127 128 if (args.containsKey("select") && PermissionPrefWithDefault.CHANGE_SELECTION.isAllowed()) { 129 // select objects after downloading, zoom to selection. 130 final String selection = args.get("select"); 131 Main.worker.execute(new Runnable() { 132 public void run() { 133 HashSet<Long> ways = new HashSet<Long>(); 134 HashSet<Long> nodes = new HashSet<Long>(); 135 HashSet<Long> relations = new HashSet<Long>(); 136 HashSet<OsmPrimitive> newSel = new HashSet<OsmPrimitive>(); 137 for (String item : selection.split(",")) { 138 if (item.startsWith("way")) { 139 ways.add(Long.parseLong(item.substring(3))); 140 } else if (item.startsWith("node")) { 141 nodes.add(Long.parseLong(item.substring(4))); 142 } else if (item.startsWith("relation")) { 143 relations.add(Long.parseLong(item.substring(8))); 144 } else if (item.startsWith("rel")) { 145 relations.add(Long.parseLong(item.substring(3))); 146 } else { 147 System.out.println("RemoteControl: invalid selection '"+item+"' ignored"); 148 } 149 } 150 DataSet ds = Main.main.getCurrentDataSet(); 151 if(ds == null) // e.g. download failed 152 return; 153 for (Way w : ds.getWays()) { 154 if (ways.contains(w.getId())) { 155 newSel.add(w); 156 } 157 } 158 for (Node n : ds.getNodes()) { 159 if (nodes.contains(n.getId())) { 160 newSel.add(n); 161 } 162 } 163 for (Relation r : ds.getRelations()) { 164 if (relations.contains(r.getId())) { 165 newSel.add(r); 166 } 167 } 168 ds.setSelected(newSel); 169 if (PermissionPrefWithDefault.CHANGE_VIEWPORT.isAllowed()) { 170 AutoScaleAction.autoScale("selection"); 171 } 172 if (Main.isDisplayingMapView() && Main.map.relationListDialog != null) { 173 Main.map.relationListDialog.selectRelations(null); // unselect all relations to fix #7342 174 Main.map.relationListDialog.dataChanged(null); 175 Main.map.relationListDialog.selectRelations(Utils.filteredCollection(newSel, Relation.class)); 176 } 177 } 178 }); 179 } else if (PermissionPrefWithDefault.CHANGE_VIEWPORT.isAllowed()) { 180 // after downloading, zoom to downloaded area. 181 zoom(minlat, maxlat, minlon, maxlon); 182 } 183 184 addTags(args); 185 186 } 187 188 /* 189 * parse addtags parameters Example URL (part): 190 * addtags=wikipedia:de%3DResidenzschloss Dresden|name:en%3DDresden Castle 191 */ 192 static void addTags(final Map<String, String> args) { 193 if (args.containsKey("addtags")) { 194 Main.worker.execute(new Runnable() { 195 196 public void run() { 197 String[] tags = null; 198 try { 199 tags = URLDecoder.decode(args.get("addtags"), "UTF-8").split("\\|"); 200 } catch (UnsupportedEncodingException e) { 201 throw new RuntimeException(); 202 } 203 String[][] keyValue = new String[tags.length][2]; 204 for (int i = 0; i < tags.length; i++) { 205 keyValue[i] = tags[i].split("="); 206 207 keyValue[i][0] = keyValue[i][0]; 208 keyValue[i][1] = keyValue[i][1]; 209 } 210 211 new AddTagsDialog(keyValue); 212 } 213 }); 214 } 215 } 216 217 protected void zoom(double minlat, double maxlat, double minlon, double maxlon) { 218 final Bounds bounds = new Bounds(new LatLon(minlat, minlon), 219 new LatLon(maxlat, maxlon)); 220 221 // make sure this isn't called unless there *is* a MapView 222 // 223 if (Main.isDisplayingMapView()) { 224 Main.worker.execute(new Runnable() { 225 public void run() { 226 BoundingXYVisitor bbox = new BoundingXYVisitor(); 227 bbox.visit(bounds); 228 Main.map.mapView.recalculateCenterScale(bbox); 229 } 230 }); 231 } 232 } 233 234 @Override 235 public PermissionPrefWithDefault getPermissionPref() { 236 return null; 237 } 238 }