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

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

see #15182 - deprecate all Main logging methods and introduce suitable replacements in Logging for most of them

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