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

Last change on this file since 11746 was 11746, checked in by Don-vip, 7 years ago

PMD - Strict Exceptions

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