Changeset 19152 in josm for trunk/src/org
- Timestamp:
- 2024-07-25T20:56:22+02:00 (4 months ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/LoadAndZoomHandler.java
r18871 r19152 6 6 import java.awt.geom.Area; 7 7 import java.awt.geom.Rectangle2D; 8 import java.util.Arrays;9 8 import java.util.Collection; 10 9 import java.util.Collections; … … 18 17 import java.util.concurrent.TimeoutException; 19 18 import java.util.stream.Collectors; 19 import java.util.stream.Stream; 20 20 21 21 import javax.swing.JOptionPane; … … 65 65 public static final String command2 = "zoom"; 66 66 private static final String CURRENT_SELECTION = "currentselection"; 67 private static final String SELECT = "select"; 68 private static final String ADDTAGS = "addtags"; 69 private static final String CHANGESET_COMMENT = "changeset_comment"; 70 private static final String CHANGESET_SOURCE = "changeset_source"; 71 private static final String CHANGESET_HASHTAGS = "changeset_hashtags"; 72 private static final String CHANGESET_TAGS = "changeset_tags"; 73 private static final String SEARCH = "search"; 67 74 68 75 // Mandatory arguments … … 81 88 String msg = tr("Remote Control has been asked to load data from the API.") + 82 89 "<br>" + tr("Bounding box: ") + new BBox(minlon, minlat, maxlon, maxlat).toStringCSV(", "); 83 if (args.containsKey( "select") && !toSelect.isEmpty()) {90 if (args.containsKey(SELECT) && !toSelect.isEmpty()) { 84 91 msg += "<br>" + tr("Selection: {0}", toSelect.size()); 85 92 } … … 94 101 @Override 95 102 public String[] getOptionalParams() { 96 return new String[] {"new_layer", "layer_name", "addtags", "select", "zoom_mode",97 "changeset_comment", "changeset_source", "changeset_hashtags", "changeset_tags",98 "search", "layer_locked", "download_policy", "upload_policy"};103 return new String[] {"new_layer", "layer_name", ADDTAGS, SELECT, "zoom_mode", 104 CHANGESET_COMMENT, CHANGESET_SOURCE, CHANGESET_HASHTAGS, CHANGESET_TAGS, 105 SEARCH, "layer_locked", "download_policy", "upload_policy"}; 99 106 } 100 107 … … 127 134 @Override 128 135 protected void handleRequest() throws RequestHandlerErrorException { 136 download(); 137 /* 138 * deselect objects if parameter addtags given 139 */ 140 if (args.containsKey(ADDTAGS) && !isKeepingCurrentSelection) { 141 GuiHelper.executeByMainWorkerInEDT(() -> { 142 DataSet ds = MainApplication.getLayerManager().getEditDataSet(); 143 if (ds == null) // e.g. download failed 144 return; 145 ds.clearSelection(); 146 }); 147 } 148 149 Collection<OsmPrimitive> forTagAdd = performSearchZoom(); 150 151 // This comes before the other changeset tags, so that they can be overridden 152 parseChangesetTags(args); 153 154 // add changeset tags after download if necessary 155 addChangesetTags(); 156 157 // add tags to objects 158 addTags(forTagAdd); 159 } 160 161 private void download() throws RequestHandlerErrorException { 129 162 DownloadOsmTask osmTask = new DownloadOsmTask(); 130 163 try { … … 137 170 Area toDownload = null; 138 171 if (!settings.isNewLayer()) { 139 // find out whether some data has already been downloaded 140 Area present = null; 141 DataSet ds = MainApplication.getLayerManager().getEditDataSet(); 142 if (ds != null) { 143 present = ds.getDataSourceArea(); 144 } 145 if (present != null && !present.isEmpty()) { 146 toDownload = new Area(new Rectangle2D.Double(minlon, minlat, maxlon-minlon, maxlat-minlat)); 147 toDownload.subtract(present); 148 if (!toDownload.isEmpty()) { 149 // the result might not be a rectangle (L shaped etc) 150 Rectangle2D downloadBounds = toDownload.getBounds2D(); 151 minlat = downloadBounds.getMinY(); 152 minlon = downloadBounds.getMinX(); 153 maxlat = downloadBounds.getMaxY(); 154 maxlon = downloadBounds.getMaxX(); 155 } 156 } 172 toDownload = removeAlreadyDownloadedArea(); 157 173 } 158 174 if (toDownload != null && toDownload.isEmpty()) { 159 175 Logging.info("RemoteControl: no download necessary"); 160 176 } else { 161 Future<?> future = MainApplication.worker.submit( 162 new PostDownloadHandler(osmTask, osmTask.download(settings, new Bounds(minlat, minlon, maxlat, maxlon), 163 null /* let the task manage the progress monitor */))); 164 GuiHelper.executeByMainWorkerInEDT(() -> { 165 try { 166 future.get(OSM_DOWNLOAD_TIMEOUT.get(), TimeUnit.SECONDS); 167 if (osmTask.isFailed()) { 168 Object error = osmTask.getErrorObjects().get(0); 169 if (error instanceof OsmApiException) { 170 throw (OsmApiException) error; 171 } 172 List<Throwable> exceptions = osmTask.getErrorObjects().stream() 173 .filter(Throwable.class::isInstance).map(Throwable.class::cast) 174 .collect(Collectors.toList()); 175 OsmTransferException osmTransferException = 176 new OsmTransferException(String.join(", ", osmTask.getErrorMessages())); 177 if (!exceptions.isEmpty()) { 178 osmTransferException.initCause(exceptions.get(0)); 179 exceptions.remove(0); 180 exceptions.forEach(osmTransferException::addSuppressed); 181 } 182 throw osmTransferException; 183 } 184 } catch (InterruptedException | ExecutionException | TimeoutException | 185 OsmTransferException | RuntimeException ex) { // NOPMD 186 ExceptionDialogUtil.explainException(ex); 187 } 188 }); 177 performDownload(osmTask, settings); 189 178 } 190 179 } … … 195 184 throw new RequestHandlerErrorException(ex); 196 185 } 197 198 /* 199 * deselect objects if parameter addtags given 200 */ 201 if (args.containsKey("addtags") && !isKeepingCurrentSelection) { 202 GuiHelper.executeByMainWorkerInEDT(() -> { 203 DataSet ds = MainApplication.getLayerManager().getEditDataSet(); 204 if (ds == null) // e.g. download failed 205 return; 206 ds.clearSelection(); 207 }); 208 } 209 186 } 187 188 /** 189 * Remove areas that has already been downloaded 190 * @return The area to download 191 */ 192 private Area removeAlreadyDownloadedArea() { 193 // find out whether some data has already been downloaded 194 Area toDownload = null; 195 Area present = null; 196 DataSet ds = MainApplication.getLayerManager().getEditDataSet(); 197 if (ds != null) { 198 present = ds.getDataSourceArea(); 199 } 200 if (present != null && !present.isEmpty()) { 201 toDownload = new Area(new Rectangle2D.Double(minlon, minlat, maxlon-minlon, maxlat-minlat)); 202 toDownload.subtract(present); 203 if (!toDownload.isEmpty()) { 204 // the result might not be a rectangle (L shaped etc) 205 Rectangle2D downloadBounds = toDownload.getBounds2D(); 206 minlat = downloadBounds.getMinY(); 207 minlon = downloadBounds.getMinX(); 208 maxlat = downloadBounds.getMaxY(); 209 maxlon = downloadBounds.getMaxX(); 210 } 211 } 212 return toDownload; 213 } 214 215 private void performDownload(DownloadOsmTask osmTask, DownloadParams settings) { 216 Future<?> future = MainApplication.worker.submit( 217 new PostDownloadHandler(osmTask, osmTask.download(settings, new Bounds(minlat, minlon, maxlat, maxlon), 218 null /* let the task manage the progress monitor */))); 219 GuiHelper.executeByMainWorkerInEDT(() -> { 220 try { 221 future.get(OSM_DOWNLOAD_TIMEOUT.get(), TimeUnit.SECONDS); 222 if (osmTask.isFailed()) { 223 Object error = osmTask.getErrorObjects().get(0); 224 if (error instanceof OsmApiException) { 225 throw (OsmApiException) error; 226 } 227 List<Throwable> exceptions = osmTask.getErrorObjects().stream() 228 .filter(Throwable.class::isInstance).map(Throwable.class::cast) 229 .collect(Collectors.toList()); 230 OsmTransferException osmTransferException = 231 new OsmTransferException(String.join(", ", osmTask.getErrorMessages())); 232 if (!exceptions.isEmpty()) { 233 osmTransferException.initCause(exceptions.get(0)); 234 exceptions.remove(0); 235 exceptions.forEach(osmTransferException::addSuppressed); 236 } 237 throw osmTransferException; 238 } 239 } catch (InterruptedException ex) { 240 Thread.currentThread().interrupt(); 241 ExceptionDialogUtil.explainException(ex); 242 } catch (ExecutionException | TimeoutException | 243 OsmTransferException | RuntimeException ex) { // NOPMD 244 ExceptionDialogUtil.explainException(ex); 245 } 246 }); 247 } 248 249 private Collection<OsmPrimitive> performSearchZoom() throws RequestHandlerErrorException { 210 250 final Collection<OsmPrimitive> forTagAdd = new LinkedHashSet<>(); 211 251 final Bounds bbox = new Bounds(minlat, minlon, maxlat, maxlon); 212 if (args.containsKey( "select") && PermissionPrefWithDefault.CHANGE_SELECTION.isAllowed()) {252 if (args.containsKey(SELECT) && PermissionPrefWithDefault.CHANGE_SELECTION.isAllowed()) { 213 253 // select objects after downloading, zoom to selection. 214 GuiHelper.executeByMainWorkerInEDT(() -> { 215 Set<OsmPrimitive> newSel = new LinkedHashSet<>(); 216 DataSet ds = MainApplication.getLayerManager().getEditDataSet(); 217 if (ds == null) // e.g. download failed 218 return; 219 for (SimplePrimitiveId id : toSelect) { 220 final OsmPrimitive p = ds.getPrimitiveById(id); 221 if (p != null) { 222 newSel.add(p); 223 forTagAdd.add(p); 224 } 225 } 226 if (isKeepingCurrentSelection) { 227 Collection<OsmPrimitive> sel = ds.getSelected(); 228 newSel.addAll(sel); 229 forTagAdd.addAll(sel); 230 } 231 toSelect.clear(); 232 ds.setSelected(newSel); 233 zoom(newSel, bbox); 234 MapFrame map = MainApplication.getMap(); 235 if (MainApplication.isDisplayingMapView() && map.relationListDialog != null) { 236 map.relationListDialog.selectRelations(null); // unselect all relations to fix #7342 237 map.relationListDialog.dataChanged(null); 238 map.relationListDialog.selectRelations(Utils.filteredCollection(newSel, Relation.class)); 239 } 240 }); 241 } else if (args.containsKey("search") && PermissionPrefWithDefault.CHANGE_SELECTION.isAllowed()) { 242 try { 243 final SearchCompiler.Match search = SearchCompiler.compile(args.get("search")); 244 MainApplication.worker.submit(() -> { 245 final DataSet ds = MainApplication.getLayerManager().getEditDataSet(); 246 final Collection<OsmPrimitive> filteredPrimitives = SubclassFilteredCollection.filter(ds.allPrimitives(), search); 247 ds.setSelected(filteredPrimitives); 248 forTagAdd.addAll(filteredPrimitives); 249 zoom(filteredPrimitives, bbox); 250 }); 251 } catch (SearchParseError ex) { 252 Logging.error(ex); 253 throw new RequestHandlerErrorException(ex); 254 } 254 GuiHelper.executeByMainWorkerInEDT(() -> selectAndZoom(forTagAdd, bbox)); 255 } else if (args.containsKey(SEARCH) && PermissionPrefWithDefault.CHANGE_SELECTION.isAllowed()) { 256 searchAndZoom(forTagAdd, bbox); 255 257 } else { 256 258 // after downloading, zoom to downloaded area. 257 zoom(Collections.<OsmPrimitive>emptySet(), bbox); 258 } 259 260 // This comes before the other changeset tags, so that they can be overridden 261 parseChangesetTags(args); 262 263 // add changeset tags after download if necessary 264 if (args.containsKey("changeset_comment") || args.containsKey("changeset_source") || args.containsKey("changeset_hashtags")) { 259 zoom(Collections.emptySet(), bbox); 260 } 261 return forTagAdd; 262 } 263 264 private void selectAndZoom(Collection<OsmPrimitive> forTagAdd, Bounds bbox) { 265 Set<OsmPrimitive> newSel = new LinkedHashSet<>(); 266 DataSet ds = MainApplication.getLayerManager().getEditDataSet(); 267 if (ds == null) // e.g. download failed 268 return; 269 for (SimplePrimitiveId id : toSelect) { 270 final OsmPrimitive p = ds.getPrimitiveById(id); 271 if (p != null) { 272 newSel.add(p); 273 forTagAdd.add(p); 274 } 275 } 276 if (isKeepingCurrentSelection) { 277 Collection<OsmPrimitive> sel = ds.getSelected(); 278 newSel.addAll(sel); 279 forTagAdd.addAll(sel); 280 } 281 toSelect.clear(); 282 ds.setSelected(newSel); 283 zoom(newSel, bbox); 284 MapFrame map = MainApplication.getMap(); 285 if (MainApplication.isDisplayingMapView() && map.relationListDialog != null) { 286 map.relationListDialog.selectRelations(null); // unselect all relations to fix #7342 287 map.relationListDialog.dataChanged(null); 288 map.relationListDialog.selectRelations(Utils.filteredCollection(newSel, Relation.class)); 289 } 290 } 291 292 private void searchAndZoom(Collection<OsmPrimitive> forTagAdd, Bounds bbox) throws RequestHandlerErrorException { 293 try { 294 final SearchCompiler.Match search = SearchCompiler.compile(args.get(SEARCH)); 265 295 MainApplication.worker.submit(() -> { 266 DataSet ds = MainApplication.getLayerManager().getEditDataSet(); 267 if (ds != null) { 268 for (String tag : Arrays.asList("changeset_comment", "changeset_source", "changeset_hashtags")) { 269 if (args.containsKey(tag)) { 270 final String tagKey = tag.substring("changeset_".length()); 271 final String value = args.get(tag); 272 if (!Utils.isStripEmpty(value)) { 273 ds.addChangeSetTag(tagKey, value); 274 } else { 275 ds.addChangeSetTag(tagKey, null); 276 } 277 } 278 } 279 } 296 final DataSet ds = MainApplication.getLayerManager().getEditDataSet(); 297 final Collection<OsmPrimitive> filteredPrimitives = SubclassFilteredCollection.filter(ds.allPrimitives(), search); 298 ds.setSelected(filteredPrimitives); 299 forTagAdd.addAll(filteredPrimitives); 300 zoom(filteredPrimitives, bbox); 280 301 }); 281 } 282 283 // add tags to objects 284 if (args.containsKey("addtags")) { 302 } catch (SearchParseError ex) { 303 Logging.error(ex); 304 throw new RequestHandlerErrorException(ex); 305 } 306 } 307 308 private void addChangesetTags() { 309 List<String> values = Stream.of(CHANGESET_COMMENT, CHANGESET_SOURCE, CHANGESET_HASHTAGS) 310 .filter(args::containsKey).collect(Collectors.toList()); 311 if (values.isEmpty()) { 312 return; 313 } 314 MainApplication.worker.submit(() -> { 315 DataSet ds = MainApplication.getLayerManager().getEditDataSet(); 316 if (ds != null) { 317 for (String tag : values) { 318 final String tagKey = tag.substring("changeset_".length()); 319 final String value = args.get(tag); 320 if (!Utils.isStripEmpty(value)) { 321 ds.addChangeSetTag(tagKey, value); 322 } else { 323 ds.addChangeSetTag(tagKey, null); 324 } 325 } 326 } 327 }); 328 } 329 330 private void addTags(Collection<OsmPrimitive> forTagAdd) { 331 if (args.containsKey(ADDTAGS)) { 285 332 // needs to run in EDT since forTagAdd is updated in EDT as well 286 333 GuiHelper.executeByMainWorkerInEDT(() -> { … … 290 337 new Notification(isKeepingCurrentSelection 291 338 ? tr("You clicked on a JOSM remotecontrol link that would apply tags onto selected objects.\n" 292 293 339 + "Since no objects have been selected before this click, no tags were added.\n" 340 + "Select one or more objects and click the link again.") 294 341 : tr("You clicked on a JOSM remotecontrol link that would apply tags onto objects.\n" 295 296 297 298 342 + "Unfortunately that link seems to be broken.\n" 343 + "Technical explanation: the URL query parameter ''select='' or ''search='' has an invalid value.\n" 344 + "Ask someone at the origin of the clicked link to fix this.") 345 ).setIcon(JOptionPane.WARNING_MESSAGE).setDuration(Notification.TIME_LONG).show(); 299 346 } 300 347 }); … … 303 350 304 351 static void parseChangesetTags(Map<String, String> args) { 305 if (args.containsKey( "changeset_tags")) {352 if (args.containsKey(CHANGESET_TAGS)) { 306 353 MainApplication.worker.submit(() -> { 307 354 DataSet ds = MainApplication.getLayerManager().getEditDataSet(); 308 355 if (ds != null) { 309 AddTagsDialog.parseUrlTagsToKeyValues(args.get( "changeset_tags")).forEach(ds::addChangeSetTag);356 AddTagsDialog.parseUrlTagsToKeyValues(args.get(CHANGESET_TAGS)).forEach(ds::addChangeSetTag); 310 357 } 311 358 }); … … 366 413 367 414 // Process optional argument 'select' 368 if (args != null && args.containsKey("select")) { 415 validateSelect(); 416 } 417 418 private void validateSelect() { 419 if (args != null && args.containsKey(SELECT)) { 369 420 toSelect.clear(); 370 for (String item : args.get( "select").split(",", -1)) {421 for (String item : args.get(SELECT).split(",", -1)) { 371 422 if (!item.isEmpty()) { 372 423 if (CURRENT_SELECTION.equalsIgnoreCase(item)) {
Note:
See TracChangeset
for help on using the changeset viewer.