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

Last change on this file since 12846 was 12846, checked in by bastiK, 7 years ago

see #15229 - use Config.getPref() wherever possible

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