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

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

see #15182 - deprecate Main.worker, replace it by gui.MainApplication.worker + code refactoring to make sure only editor packages use it

  • Property svn:eol-style set to native
File size: 12.9 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.MainApplication;
29import org.openstreetmap.josm.gui.MapFrame;
30import org.openstreetmap.josm.gui.util.GuiHelper;
31import org.openstreetmap.josm.io.remotecontrol.AddTagsDialog;
32import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault;
33import org.openstreetmap.josm.tools.Logging;
34import org.openstreetmap.josm.tools.SubclassFilteredCollection;
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(", ");
66 if (args.containsKey("select") && !toSelect.isEmpty()) {
67 msg += "<br>" + tr("Selection: {0}", toSelect.size());
68 }
69 return msg;
70 }
71
72 @Override
73 public String[] getMandatoryParams() {
74 return new String[] {"bottom", "top", "left", "right"};
75 }
76
77 @Override
78 public String[] getOptionalParams() {
79 return new String[] {"new_layer", "layer_name", "addtags", "select", "zoom_mode", "changeset_comment", "changeset_source", "search"};
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[] {
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",
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 {
109 DownloadTask osmTask = new DownloadOsmTask() {
110 {
111 newLayerName = args.get("layer_name");
112 }
113 };
114 try {
115 boolean newLayer = isLoadInNewLayer();
116
117 if (command.equals(myCommand)) {
118 if (!PermissionPrefWithDefault.LOAD_DATA.isAllowed()) {
119 Logging.info("RemoteControl: download forbidden by preferences");
120 } else {
121 Area toDownload = null;
122 if (!newLayer) {
123 // find out whether some data has already been downloaded
124 Area present = null;
125 DataSet ds = Main.getLayerManager().getEditDataSet();
126 if (ds != null) {
127 present = ds.getDataSourceArea();
128 }
129 if (present != null && !present.isEmpty()) {
130 toDownload = new Area(new Rectangle2D.Double(minlon, minlat, maxlon-minlon, maxlat-minlat));
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()) {
143 Logging.info("RemoteControl: no download necessary");
144 } else {
145 Future<?> future = osmTask.download(newLayer, new Bounds(minlat, minlon, maxlat, maxlon),
146 null /* let the task manage the progress monitor */);
147 MainApplication.worker.submit(new PostDownloadHandler(osmTask, future));
148 }
149 }
150 }
151 } catch (RuntimeException ex) { // NOPMD
152 Logging.warn("RemoteControl: Error parsing load_and_zoom remote control request:");
153 Logging.error(ex);
154 throw new RequestHandlerErrorException(ex);
155 }
156
157 /**
158 * deselect objects if parameter addtags given
159 */
160 if (args.containsKey("addtags")) {
161 GuiHelper.executeByMainWorkerInEDT(() -> {
162 DataSet ds = Main.getLayerManager().getEditDataSet();
163 if (ds == null) // e.g. download failed
164 return;
165 ds.clearSelection();
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.
173 GuiHelper.executeByMainWorkerInEDT(() -> {
174 Set<OsmPrimitive> newSel = new HashSet<>();
175 DataSet ds = Main.getLayerManager().getEditDataSet();
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);
183 }
184 }
185 toSelect.clear();
186 ds.setSelected(newSel);
187 zoom(newSel, bbox);
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));
193 }
194 });
195 } else if (args.containsKey("search") && PermissionPrefWithDefault.CHANGE_SELECTION.isAllowed()) {
196 try {
197 final SearchCompiler.Match search = SearchCompiler.compile(args.get("search"));
198 MainApplication.worker.submit(() -> {
199 final DataSet ds = Main.getLayerManager().getEditDataSet();
200 final Collection<OsmPrimitive> filteredPrimitives = SubclassFilteredCollection.filter(ds.allPrimitives(), search);
201 ds.setSelected(filteredPrimitives);
202 forTagAdd.addAll(filteredPrimitives);
203 zoom(filteredPrimitives, bbox);
204 });
205 } catch (SearchCompiler.ParseError ex) {
206 Logging.error(ex);
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")) {
216 MainApplication.worker.submit(() -> {
217 if (Main.getLayerManager().getEditDataSet() != null) {
218 if (args.containsKey("changeset_comment")) {
219 Main.getLayerManager().getEditDataSet().addChangeSetTag("comment", args.get("changeset_comment"));
220 }
221 if (args.containsKey("changeset_source")) {
222 Main.getLayerManager().getEditDataSet().addChangeSetTag("source", args.get("changeset_source"));
223 }
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");
238 } else if (MainApplication.isDisplayingMapView()) {
239 // make sure this isn't called unless there *is* a MapView
240 GuiHelper.executeByMainWorkerInEDT(() -> {
241 BoundingXYVisitor bbox1 = new BoundingXYVisitor();
242 bbox1.visit(bbox);
243 MainApplication.getMap().mapView.zoomTo(bbox1);
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 {
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") : ""));
265 } catch (NumberFormatException e) {
266 throw new RequestHandlerBadRequestException("NumberFormatException ("+e.getMessage()+')', e);
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'
283 if (args != null && args.containsKey("select")) {
284 toSelect.clear();
285 for (String item : args.get("select").split(",")) {
286 if (!item.isEmpty()) {
287 try {
288 toSelect.add(SimplePrimitiveId.fromString(item));
289 } catch (IllegalArgumentException ex) {
290 Logging.log(Logging.LEVEL_WARN, "RemoteControl: invalid selection '" + item + "' ignored", ex);
291 }
292 }
293 }
294 }
295 }
296}
Note: See TracBrowser for help on using the repository browser.