source: josm/trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/LoadAndZoomHandler.java@ 8221

Last change on this file since 8221 was 8221, checked in by simon04, 9 years ago

see #11000 - Remote control: allow to specify layer_name for load_and_zoom, load_object

  • Property svn:eol-style set to native
File size: 12.8 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.io.remotecontrol.handler;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.geom.Area;
7import java.awt.geom.Rectangle2D;
8import java.util.Collection;
9import java.util.Collections;
10import java.util.HashSet;
11import java.util.Set;
12import java.util.concurrent.Future;
13
14import org.openstreetmap.josm.Main;
15import org.openstreetmap.josm.actions.AutoScaleAction;
16import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask;
17import org.openstreetmap.josm.actions.downloadtasks.DownloadTask;
18import org.openstreetmap.josm.actions.downloadtasks.PostDownloadHandler;
19import org.openstreetmap.josm.actions.search.SearchCompiler;
20import org.openstreetmap.josm.data.Bounds;
21import org.openstreetmap.josm.data.coor.LatLon;
22import org.openstreetmap.josm.data.osm.BBox;
23import org.openstreetmap.josm.data.osm.DataSet;
24import org.openstreetmap.josm.data.osm.OsmPrimitive;
25import org.openstreetmap.josm.data.osm.Relation;
26import org.openstreetmap.josm.data.osm.SimplePrimitiveId;
27import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
28import org.openstreetmap.josm.gui.util.GuiHelper;
29import org.openstreetmap.josm.io.remotecontrol.AddTagsDialog;
30import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault;
31import org.openstreetmap.josm.tools.Utils;
32
33/**
34 * Handler for {@code load_and_zoom} and {@code zoom} requests.
35 * @since 3707
36 */
37public class LoadAndZoomHandler extends RequestHandler {
38
39 /**
40 * The remote control command name used to load data and zoom.
41 */
42 public static final String command = "load_and_zoom";
43
44 /**
45 * The remote control command name used to zoom.
46 */
47 public static final String command2 = "zoom";
48
49 // Mandatory arguments
50 private double minlat;
51 private double maxlat;
52 private double minlon;
53 private double maxlon;
54
55 // Optional argument 'select'
56 private final Set<SimplePrimitiveId> toSelect = new HashSet<>();
57
58 @Override
59 public String getPermissionMessage() {
60 String msg = tr("Remote Control has been asked to load data from the API.") +
61 "<br>" + tr("Bounding box: ") + new BBox(minlon, minlat, maxlon, maxlat).toStringCSV(", ");
62 if (args.containsKey("select") && toSelect.size() > 0) {
63 msg += "<br>" + tr("Selection: {0}", toSelect.size());
64 }
65 return msg;
66 }
67
68 @Override
69 public String[] getMandatoryParams() {
70 return new String[] { "bottom", "top", "left", "right" };
71 }
72
73 @Override
74 public String[] getOptionalParams() {
75 return new String[] {"new_layer", "layer_name", "addtags", "select", "zoom_mode", "changeset_comment", "changeset_source", "search"};
76 }
77
78 @Override
79 public String getUsage() {
80 return "download a bounding box from the API, zoom to the downloaded area and optionally select one or more objects";
81 }
82
83 @Override
84 public String[] getUsageExamples() {
85 return getUsageExamples(myCommand);
86 }
87
88 @Override
89 public String[] getUsageExamples(String cmd) {
90 if (command.equals(cmd)) {
91 return new String[] {
92 "/load_and_zoom?addtags=wikipedia:de=Wei%C3%9Fe_Gasse|maxspeed=5&select=way23071688,way23076176,way23076177,&left=13.740&right=13.741&top=51.05&bottom=51.049",
93 "/load_and_zoom?left=8.19&right=8.20&top=48.605&bottom=48.590&select=node413602999&new_layer=true"};
94 } else {
95 return new String[] {
96 "/zoom?left=8.19&right=8.20&top=48.605&bottom=48.590&select=node413602999",
97 "/zoom?left=8.19&right=8.20&top=48.605&bottom=48.590&search=highway+OR+railway",
98 };
99 }
100 }
101
102 @Override
103 protected void handleRequest() throws RequestHandlerErrorException {
104 DownloadTask osmTask = new DownloadOsmTask() {
105 {
106 newLayerName = args.get("layer_name");
107 }
108 };
109 try {
110 boolean newLayer = isLoadInNewLayer();
111
112 if (command.equals(myCommand)) {
113 if (!PermissionPrefWithDefault.LOAD_DATA.isAllowed()) {
114 Main.info("RemoteControl: download forbidden by preferences");
115 } else {
116 Area toDownload = null;
117 if (!newLayer) {
118 // find out whether some data has already been downloaded
119 Area present = null;
120 DataSet ds = Main.main.getCurrentDataSet();
121 if (ds != null) {
122 present = ds.getDataSourceArea();
123 }
124 if (present != null && !present.isEmpty()) {
125 toDownload = new Area(new Rectangle2D.Double(minlon,minlat,maxlon-minlon,maxlat-minlat));
126 toDownload.subtract(present);
127 if (!toDownload.isEmpty()) {
128 // the result might not be a rectangle (L shaped etc)
129 Rectangle2D downloadBounds = toDownload.getBounds2D();
130 minlat = downloadBounds.getMinY();
131 minlon = downloadBounds.getMinX();
132 maxlat = downloadBounds.getMaxY();
133 maxlon = downloadBounds.getMaxX();
134 }
135 }
136 }
137 if (toDownload != null && toDownload.isEmpty()) {
138 Main.info("RemoteControl: no download necessary");
139 } else {
140 Future<?> future = osmTask.download(newLayer, new Bounds(minlat,minlon,maxlat,maxlon), null /* let the task manage the progress monitor */);
141 Main.worker.submit(new PostDownloadHandler(osmTask, future));
142 }
143 }
144 }
145 } catch (Exception ex) {
146 Main.warn("RemoteControl: Error parsing load_and_zoom remote control request:");
147 Main.error(ex);
148 throw new RequestHandlerErrorException(ex);
149 }
150
151 /**
152 * deselect objects if parameter addtags given
153 */
154 if (args.containsKey("addtags")) {
155 GuiHelper.executeByMainWorkerInEDT(new Runnable() {
156 @Override
157 public void run() {
158 DataSet ds = Main.main.getCurrentDataSet();
159 if(ds == null) // e.g. download failed
160 return;
161 ds.clearSelection();
162 }
163 });
164 }
165
166 final Collection<OsmPrimitive> forTagAdd = new HashSet<>();
167 final Bounds bbox = new Bounds(minlat, minlon, maxlat, maxlon);
168 if (args.containsKey("select") && PermissionPrefWithDefault.CHANGE_SELECTION.isAllowed()) {
169 // select objects after downloading, zoom to selection.
170 GuiHelper.executeByMainWorkerInEDT(new Runnable() {
171 @Override
172 public void run() {
173 Set<OsmPrimitive> newSel = new HashSet<>();
174 DataSet ds = Main.main.getCurrentDataSet();
175 if (ds == null) // e.g. download failed
176 return;
177 for (SimplePrimitiveId id : toSelect) {
178 final OsmPrimitive p = ds.getPrimitiveById(id);
179 if (p != null) {
180 newSel.add(p);
181 forTagAdd.add(p);
182 }
183 }
184 toSelect.clear();
185 ds.setSelected(newSel);
186 zoom(newSel, bbox);
187 if (Main.isDisplayingMapView() && Main.map.relationListDialog != null) {
188 Main.map.relationListDialog.selectRelations(null); // unselect all relations to fix #7342
189 Main.map.relationListDialog.dataChanged(null);
190 Main.map.relationListDialog.selectRelations(Utils.filteredCollection(newSel, Relation.class));
191 }
192 }
193 });
194 } else if (args.containsKey("search") && PermissionPrefWithDefault.CHANGE_SELECTION.isAllowed()) {
195 try {
196 final SearchCompiler.Match search = SearchCompiler.compile(args.get("search"), false, false);
197 Main.worker.submit(new Runnable() {
198 @Override
199 public void run() {
200 final DataSet ds = Main.main.getCurrentDataSet();
201 final Collection<OsmPrimitive> filteredPrimitives = Utils.filter(ds.allPrimitives(), search);
202 ds.setSelected(filteredPrimitives);
203 forTagAdd.addAll(filteredPrimitives);
204 zoom(filteredPrimitives, bbox);
205 }
206 });
207 } catch (SearchCompiler.ParseError ex) {
208 Main.error(ex);
209 throw new RequestHandlerErrorException(ex);
210 }
211 } else {
212 // after downloading, zoom to downloaded area.
213 zoom(Collections.<OsmPrimitive>emptySet(), bbox);
214 }
215
216 // add changeset tags after download if necessary
217 if (args.containsKey("changeset_comment") || args.containsKey("changeset_source")) {
218 Main.worker.submit(new Runnable() {
219 @Override
220 public void run() {
221 if (Main.main.getCurrentDataSet() != null) {
222 if (args.containsKey("changeset_comment")) {
223 Main.main.getCurrentDataSet().addChangeSetTag("comment", args.get("changeset_comment"));
224 }
225 if (args.containsKey("changeset_source")) {
226 Main.main.getCurrentDataSet().addChangeSetTag("source", args.get("changeset_source"));
227 }
228 }
229 }
230 });
231 }
232
233 AddTagsDialog.addTags(args, sender, forTagAdd);
234 }
235
236 protected void zoom(Collection<OsmPrimitive> primitives, final Bounds bbox) {
237 if (!PermissionPrefWithDefault.CHANGE_VIEWPORT.isAllowed()) {
238 return;
239 }
240 // zoom_mode=(download|selection), defaults to selection
241 if (!"download".equals(args.get("zoom_mode")) && !primitives.isEmpty()) {
242 AutoScaleAction.autoScale("selection");
243 } else if (Main.isDisplayingMapView()) {
244 // make sure this isn't called unless there *is* a MapView
245 GuiHelper.executeByMainWorkerInEDT(new Runnable() {
246 @Override
247 public void run() {
248 BoundingXYVisitor bbox1 = new BoundingXYVisitor();
249 bbox1.visit(bbox);
250 Main.map.mapView.zoomTo(bbox1);
251 }
252 });
253 }
254 }
255
256 @Override
257 public PermissionPrefWithDefault getPermissionPref() {
258 return null;
259 }
260
261 @Override
262 protected void validateRequest() throws RequestHandlerBadRequestException {
263 // Process mandatory arguments
264 minlat = 0;
265 maxlat = 0;
266 minlon = 0;
267 maxlon = 0;
268 try {
269 minlat = LatLon.roundToOsmPrecision(Double.parseDouble(args.get("bottom")));
270 maxlat = LatLon.roundToOsmPrecision(Double.parseDouble(args.get("top")));
271 minlon = LatLon.roundToOsmPrecision(Double.parseDouble(args.get("left")));
272 maxlon = LatLon.roundToOsmPrecision(Double.parseDouble(args.get("right")));
273 } catch (NumberFormatException e) {
274 throw new RequestHandlerBadRequestException("NumberFormatException ("+e.getMessage()+")");
275 }
276
277 // Current API 0.6 check: "The latitudes must be between -90 and 90"
278 if (!LatLon.isValidLat(minlat) || !LatLon.isValidLat(maxlat)) {
279 throw new RequestHandlerBadRequestException(tr("The latitudes must be between {0} and {1}", -90d, 90d));
280 }
281 // Current API 0.6 check: "longitudes between -180 and 180"
282 if (!LatLon.isValidLon(minlon) || !LatLon.isValidLon(maxlon)) {
283 throw new RequestHandlerBadRequestException(tr("The longitudes must be between {0} and {1}", -180d, 180d));
284 }
285 // Current API 0.6 check: "the minima must be less than the maxima"
286 if (minlat > maxlat || minlon > maxlon) {
287 throw new RequestHandlerBadRequestException(tr("The minima must be less than the maxima"));
288 }
289
290 // Process optional argument 'select'
291 if (args.containsKey("select")) {
292 toSelect.clear();
293 for (String item : args.get("select").split(",")) {
294 try {
295 toSelect.add(SimplePrimitiveId.fromString(item));
296 } catch (IllegalArgumentException ex) {
297 Main.warn("RemoteControl: invalid selection '" + item + "' ignored");
298 }
299 }
300 }
301 }
302}
Note: See TracBrowser for help on using the repository browser.