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 }