Ticket #4142: 4142.4.patch
| File 4142.4.patch, 25.7 KB (added by , 2 years ago) |
|---|
-
src/org/openstreetmap/josm/actions/AlignInCircleAction.java
1 1 // License: GPL. For details, see LICENSE file. 2 2 package org.openstreetmap.josm.actions; 3 3 4 import static java.util.function.Predicate.not; 4 5 import static org.openstreetmap.josm.gui.help.HelpUtil.ht; 5 6 import static org.openstreetmap.josm.tools.I18n.tr; 6 7 … … 271 272 } 272 273 fixNodes.addAll(collectNodesWithExternReferrers(ways)); 273 274 274 // Check if one or more nodes are outside of download area275 if (nodes.stream().anyMatch( Node::isOutsideDownloadArea))276 throw new InvalidSelection(tr("One or more nodes involved in this action is outside of the downloaded area."));275 // Check if one or more nodes does not have all parents available 276 if (nodes.stream().anyMatch(not(Node::isReferrersDownloaded))) 277 throw new InvalidSelection(tr("One or more nodes involved in this action may have additional referrers.")); 277 278 278 279 279 280 if (center == null) { -
src/org/openstreetmap/josm/actions/CombineWayAction.java
284 284 for (Way w : selectedWays) { 285 285 final Node[] endnodes = {w.firstNode(), w.lastNode()}; 286 286 for (Node n : endnodes) { 287 if (!n.isNew() && n.isOutsideDownloadArea() && !endNodesOutside.add(n)) {288 new Notification(tr("Combine ways refused<br>" + "(A shared node is outside of the download area)"))287 if (!n.isNew() && !n.isReferrersDownloaded() && !endNodesOutside.add(n)) { 288 new Notification(tr("Combine ways refused<br>" + "(A shared node may have additional referrers)")) 289 289 .setIcon(JOptionPane.INFORMATION_MESSAGE).show(); 290 290 return; 291 291 -
src/org/openstreetmap/josm/actions/DeleteAction.java
16 16 17 17 import org.openstreetmap.josm.command.DeleteCommand.DeletionCallback; 18 18 import org.openstreetmap.josm.data.osm.DefaultNameFormatter; 19 import org.openstreetmap.josm.data.osm.INode; 20 import org.openstreetmap.josm.data.osm.IRelation; 21 import org.openstreetmap.josm.data.osm.IWay; 19 22 import org.openstreetmap.josm.data.osm.OsmPrimitive; 20 23 import org.openstreetmap.josm.data.osm.Relation; 21 24 import org.openstreetmap.josm.data.osm.RelationToChildReference; … … 103 106 */ 104 107 public static boolean checkAndConfirmOutlyingDelete(Collection<? extends OsmPrimitive> primitives, 105 108 Collection<? extends OsmPrimitive> ignore) { 109 final boolean nodes = primitives.stream().anyMatch(INode.class::isInstance); 110 final boolean ways = primitives.stream().anyMatch(IWay.class::isInstance); 111 final boolean relations = primitives.stream().anyMatch(IRelation.class::isInstance); 112 final String type; 113 if (nodes && !ways && !relations) { 114 type = tr("You are about to delete nodes which can have other referrers not yet downloaded."); 115 } else if (!nodes && ways && !relations) { 116 type = tr("You are about to delete ways which can have other referrers not yet downloaded."); 117 } else if (!nodes && !ways && relations) { 118 type = tr("You are about to delete relations which can have other referrers not yet downloaded."); 119 } else { 120 // OK. We have multiple types being deleted. 121 type = tr("You are about to delete primitives which can have other referrers not yet downloaded."); 122 } 106 123 return Boolean.TRUE.equals(GuiHelper.runInEDTAndWaitAndReturn(() -> checkAndConfirmOutlyingOperation("delete", 107 124 tr("Delete confirmation"), 108 tr(" You are about to delete nodes which can have other referrers not yet downloaded."125 tr("{0}" 109 126 + "<br>" 110 127 + "This can cause problems because other objects (that you do not see) might use them." 111 128 + "<br>" 112 + "Do you really want to delete?" ),129 + "Do you really want to delete?", type), 113 130 tr("You are about to delete incomplete objects." 114 131 + "<br>" 115 132 + "This will cause problems because you don''t see the real object." -
src/org/openstreetmap/josm/actions/JoinAreasAction.java
672 672 commitCommands(marktr("Removed duplicate nodes")); 673 673 // remove now unconnected nodes without tags 674 674 List<Node> toRemove = oldNodes.stream().filter( 675 n -> (n.isNew() || !n.isOutsideDownloadArea()) && !n.hasKeys() && n.getReferrers().isEmpty())675 n -> n.isReferrersDownloaded() && !n.hasKeys() && n.getReferrers().isEmpty()) 676 676 .collect(Collectors.toList()); 677 677 if (!toRemove.isEmpty()) { 678 678 cmds.add(new DeleteCommand(toRemove)); -
src/org/openstreetmap/josm/actions/SplitWayAction.java
143 143 .setIcon(JOptionPane.WARNING_MESSAGE) 144 144 .show(); 145 145 return; 146 } else if (!checkAndConfirmOutlyingOperation("splitway", tr("Split way confirmation"), 147 tr("You are about to split a way that may have referrers that are not yet downloaded.") 148 + "<br/>" 149 + tr("This can lead to broken relations.") + "<br/>" 150 + tr("Do you really want to split?"), 151 tr("The selected area is incomplete. Continue?"), 152 applicableWays, null)) { 153 return; 146 154 } 147 155 148 156 // Finally, applicableWays contains only one perfect way -
src/org/openstreetmap/josm/actions/downloadtasks/DownloadReferrersTask.java
123 123 124 124 DataSetMerger visitor = new DataSetMerger(targetLayer.getDataSet(), parents); 125 125 visitor.merge(); 126 this.children.stream().map(p -> targetLayer.getDataSet().getPrimitiveById(p)) 127 .forEach(p -> p.setReferrersDownloaded(true)); 128 126 129 SwingUtilities.invokeLater(targetLayer::onPostDownloadFromServer); 127 130 if (visitor.getConflicts().isEmpty()) 128 131 return; -
src/org/openstreetmap/josm/command/Command.java
227 227 for (OsmPrimitive osm : primitives) { 228 228 if (osm.isIncomplete()) { 229 229 res |= IS_INCOMPLETE; 230 } else if ((res & IS_OUTSIDE) == 0 && (osm.isOutsideDownloadArea() 231 || (osm instanceof Node && !osm.isNew() && osm.getDataSet() != null && osm.getDataSet().getDataSourceBounds().isEmpty())) 232 && (ignore == null || !ignore.contains(osm))) { 230 } else if ((res & IS_OUTSIDE) == 0 && !osm.isReferrersDownloaded() && (ignore == null || !ignore.contains(osm))) { 233 231 res |= IS_OUTSIDE; 234 232 } 235 233 } -
src/org/openstreetmap/josm/command/DeleteCommand.java
433 433 primitivesToDelete.addAll(nodesToDelete); 434 434 } 435 435 436 if (!silent && !callback.checkAndConfirmOutlyingDelete( 437 primitivesToDelete, Utils.filteredCollection(primitivesToDelete, Way.class))) 436 if (!silent && !callback.checkAndConfirmOutlyingDelete(primitivesToDelete, null)) 438 437 return null; 439 438 440 439 Collection<Way> waysToBeChanged = primitivesToDelete.stream() -
src/org/openstreetmap/josm/data/osm/AbstractPrimitive.java
3 3 4 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 5 6 import java.io.IOException; 7 import java.io.ObjectInputStream; 8 import java.io.ObjectOutputStream; 6 9 import java.text.MessageFormat; 7 10 import java.time.Instant; 8 11 import java.util.ArrayList; … … 131 134 protected static final short FLAG_PRESERVED = 1 << 13; 132 135 133 136 /** 137 * Determines if the primitive has all of its referrers 138 */ 139 protected static final short FLAG_ALL_REFERRERS_DOWNLOADED = 1 << 14; 140 141 /** 134 142 * Put several boolean flags to one short int field to save memory. 135 143 * Other bits of this field are used in subclasses. 136 144 */ 137 pr otectedvolatile short flags = FLAG_VISIBLE; // visible per default145 private volatile short flags = FLAG_VISIBLE; // visible per default 138 146 139 147 /** 140 148 * The mappaint cache index for this primitive. … … 365 373 return oldFlags != flags; 366 374 } 367 375 376 protected void writeObjectCommon(ObjectOutputStream oos) throws IOException { 377 oos.writeLong(id); 378 oos.writeLong(user == null ? -1 : user.getId()); 379 oos.writeInt(version); 380 oos.writeInt(changesetId); 381 oos.writeInt(timestamp); 382 oos.writeObject(keys); 383 oos.writeShort(flags); 384 } 385 386 protected void readObjectCommon(ObjectInputStream ois) throws ClassNotFoundException, IOException { 387 id = ois.readLong(); 388 final long userId = ois.readLong(); 389 user = userId == -1 ? null : User.getById(userId); 390 version = ois.readInt(); 391 changesetId = ois.readInt(); 392 timestamp = ois.readInt(); 393 keys = (String[]) ois.readObject(); 394 flags = ois.readShort(); 395 } 396 368 397 @Override 369 398 public void setModified(boolean modified) { 370 399 updateFlags(FLAG_MODIFIED, modified); … … 381 410 } 382 411 383 412 @Override 413 public void setReferrersDownloaded(boolean referrersDownloaded) { 414 this.updateFlags(FLAG_ALL_REFERRERS_DOWNLOADED, referrersDownloaded); 415 } 416 417 @Override 384 418 public boolean isUndeleted() { 385 419 return (flags & (FLAG_VISIBLE + FLAG_DELETED)) == 0; 386 420 } … … 408 442 setModified(deleted ^ !isVisible()); 409 443 } 410 444 445 @Override 446 public boolean hasDirectionKeys() { 447 return (flags & FLAG_HAS_DIRECTIONS) != 0; 448 } 449 450 @Override 451 public boolean reversedDirection() { 452 return (flags & FLAG_DIRECTION_REVERSED) != 0; 453 } 454 455 @Override 456 public boolean isTagged() { 457 return (flags & FLAG_TAGGED) != 0; 458 } 459 460 @Override 461 public boolean isAnnotated() { 462 return (flags & FLAG_ANNOTATED) != 0; 463 } 464 465 @Override 466 public boolean isHighlighted() { 467 return (flags & FLAG_HIGHLIGHTED) != 0; 468 } 469 470 @Override 471 public boolean isDisabled() { 472 return (flags & FLAG_DISABLED) != 0; 473 } 474 475 @Override 476 public boolean isDisabledAndHidden() { 477 return ((flags & FLAG_DISABLED) != 0) && ((flags & FLAG_HIDE_IF_DISABLED) != 0); 478 } 479 480 @Override 481 public boolean isPreserved() { 482 return (flags & FLAG_PRESERVED) != 0; 483 } 484 485 @Override 486 public boolean isReferrersDownloaded() { 487 return isNew() || (flags & FLAG_ALL_REFERRERS_DOWNLOADED) != 0; 488 } 489 411 490 /** 412 491 * If set to true, this object is incomplete, which means only the id 413 492 * and type is known (type is the objects instance class) -
src/org/openstreetmap/josm/data/osm/DataSetMerger.java
369 369 mergeFromSource = true; 370 370 } 371 371 if (mergeFromSource) { 372 boolean backupReferrersDownloadedStatus = target.isReferrersDownloaded() && haveSameVersion; 372 373 target.mergeFrom(source); 374 if (backupReferrersDownloadedStatus && !target.isReferrersDownloaded()) { 375 target.setReferrersDownloaded(true); 376 } 373 377 objectsWithChildrenToMerge.add(source.getPrimitiveId()); 374 378 } 375 379 return true; -
src/org/openstreetmap/josm/data/osm/IPrimitive.java
37 37 void setModified(boolean modified); 38 38 39 39 /** 40 * Set the status of the referrers 41 * @param referrersDownloaded {@code true} if all referrers for this object have been downloaded 42 * @since xxx 43 */ 44 default void setReferrersDownloaded(boolean referrersDownloaded) { 45 throw new UnsupportedOperationException(this.getClass().getName() + " does not support referrers status"); 46 } 47 48 /** 40 49 * Checks if object is known to the server. 41 50 * Replies true if this primitive is either unknown to the server (i.e. its id 42 51 * is 0) or it is known to the server and it hasn't be deleted on the server. … … 76 85 void setDeleted(boolean deleted); 77 86 78 87 /** 88 * Determines if this primitive is fully downloaded 89 * @return {@code true} if the primitive is fully downloaded and all parents and children should be available. 90 * {@code false} otherwise. 91 * @since xxx 92 */ 93 default boolean isReferrersDownloaded() { 94 return false; 95 } 96 97 /** 79 98 * Determines if this primitive is incomplete. 80 99 * @return {@code true} if this primitive is incomplete, {@code false} otherwise 81 100 */ -
src/org/openstreetmap/josm/data/osm/OsmPrimitive.java
364 364 } 365 365 366 366 @Override 367 public boolean isDisabled() {368 return (flags & FLAG_DISABLED) != 0;369 }370 371 @Override372 public boolean isDisabledAndHidden() {373 return ((flags & FLAG_DISABLED) != 0) && ((flags & FLAG_HIDE_IF_DISABLED) != 0);374 }375 376 @Override377 public boolean isPreserved() {378 return (flags & FLAG_PRESERVED) != 0;379 }380 381 @Override382 367 public boolean isSelectable() { 383 368 // not synchronized -> check disabled twice just to be sure we did not have a race condition. 384 369 return !isDisabled() && isDrawable() && !isDisabled(); … … 492 477 } 493 478 } 494 479 495 @Override496 public boolean isHighlighted() {497 return (flags & FLAG_HIGHLIGHTED) != 0;498 }499 500 480 /*--------------- 501 481 * DIRECTION KEYS 502 482 *---------------*/ … … 526 506 updateFlagsNoLock(FLAG_ANNOTATED, hasKeys() && getWorkInProgressKeys().stream().anyMatch(this::hasKey)); 527 507 } 528 508 529 @Override530 public boolean isTagged() {531 return (flags & FLAG_TAGGED) != 0;532 }533 534 @Override535 public boolean isAnnotated() {536 return (flags & FLAG_ANNOTATED) != 0;537 }538 539 509 protected void updateDirectionFlags() { 540 510 boolean hasDirections = false; 541 511 boolean directionReversed = false; … … 551 521 updateFlagsNoLock(FLAG_HAS_DIRECTIONS, hasDirections); 552 522 } 553 523 554 @Override555 public boolean hasDirectionKeys() {556 return (flags & FLAG_HAS_DIRECTIONS) != 0;557 }558 559 @Override560 public boolean reversedDirection() {561 return (flags & FLAG_DIRECTION_REVERSED) != 0;562 }563 564 524 /*------------ 565 525 * Keys handling 566 526 ------------*/ … … 851 811 throw new DataIntegrityProblemException( 852 812 tr("Cannot merge primitives with different ids. This id is {0}, the other is {1}", id, other.getId())); 853 813 814 setIncomplete(other.isIncomplete()); 815 super.cloneFrom(other); 854 816 setKeys(other.hasKeys() ? other.getKeys() : null); 855 timestamp = other.timestamp;856 817 version = other.version; 857 setIncomplete(other.isIncomplete());858 flags = other.flags;859 user = other.user;860 818 changesetId = other.changesetId; 861 819 } finally { 862 820 writeUnlock(locked); -
src/org/openstreetmap/josm/data/osm/PrimitiveData.java
84 84 85 85 private void writeObject(ObjectOutputStream oos) throws IOException { 86 86 // since super class is not Serializable 87 oos.writeLong(id); 88 oos.writeLong(user == null ? -1 : user.getId()); 89 oos.writeInt(version); 90 oos.writeInt(changesetId); 91 oos.writeInt(timestamp); 92 oos.writeObject(keys); 93 oos.writeShort(flags); 87 super.writeObjectCommon(oos); 94 88 oos.defaultWriteObject(); 95 89 } 96 90 97 91 private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { 98 92 // since super class is not Serializable 99 id = ois.readLong(); 100 final long userId = ois.readLong(); 101 user = userId == -1 ? null : User.getById(userId); 102 version = ois.readInt(); 103 changesetId = ois.readInt(); 104 timestamp = ois.readInt(); 105 keys = (String[]) ois.readObject(); 106 flags = ois.readShort(); 93 super.readObjectCommon(ois); 107 94 ois.defaultReadObject(); 108 95 } 109 96 -
src/org/openstreetmap/josm/data/validation/tests/BarriersEntrances.java
26 26 27 27 @Override 28 28 public void visit(Node n) { 29 if (n.hasTag("barrier", "entrance") && !n.isOutsideDownloadArea()) {29 if (n.hasTag("barrier", "entrance") && n.isReferrersDownloaded()) { 30 30 for (OsmPrimitive p : n.getReferrers()) { 31 31 if (p.hasKey("barrier")) { 32 32 return; -
src/org/openstreetmap/josm/data/vector/VectorPrimitive.java
59 59 } 60 60 61 61 @Override 62 public boolean isTagged() {63 return (flags & FLAG_TAGGED) != 0;64 }65 66 @Override67 62 public boolean isAnnotated() { 68 63 return this.getInterestingTags().size() - this.getKeys().size() > 0; 69 64 } -
src/org/openstreetmap/josm/gui/dialogs/InspectPrimitiveDataText.java
129 129 if (!o.isVisible()) { 130 130 sb.append(tr("deleted-on-server")).append(INDENT); 131 131 } 132 if (o.isReferrersDownloaded()) { 133 sb.append(tr("all-referrers-downloaded")).append(INDENT); 134 } else { 135 sb.append(tr("referrers-not-all-downloaded")).append(INDENT); 136 } 132 137 if (o.isModified()) { 133 138 sb.append(tr("modified")).append(INDENT); 134 139 } -
src/org/openstreetmap/josm/io/BoundingBoxDownloader.java
6 6 import java.io.IOException; 7 7 import java.io.InputStream; 8 8 import java.net.SocketException; 9 import java.util.Collection; 10 import java.util.Collections; 9 11 import java.util.List; 10 12 11 13 import org.openstreetmap.josm.data.Bounds; … … 215 217 ds = parseDataSet(in, progressMonitor.createSubTaskMonitor(1, false)); 216 218 } 217 219 } 220 // From https://wiki.openstreetmap.org/wiki/API_v0.6#Retrieving_map_data_by_bounding_box:_GET_/api/0.6/map, 221 // relations are not recursed up, so they *may* have parent relations. 222 // Nodes inside the download area should have all relations and ways that refer to them. 223 // Ways should have all relations that refer to them and all child nodes, but those child nodes may not 224 // have their parent referrers. 225 // Relations will have the *first* parent relations downloaded, but those are not split out in the returns. 226 // So we always assume that a relation has referrers that need to be downloaded unless it has no child relations. 227 // Our "full" overpass query doesn't return the same data as a standard download, so we cannot 228 // mark relations with no child relations as fully downloaded *yet*. 229 if (this.considerAsFullDownload()) { 230 final Collection<Bounds> bounds = this.getBounds(); 231 // We cannot use OsmPrimitive#isOutsideDownloadArea yet since some download methods haven't added 232 // the download bounds to the dataset yet. This is specifically the case for overpass downloads. 233 ds.getNodes().stream().filter(n -> bounds.stream().anyMatch(b -> b.contains(n))) 234 .forEach(i -> i.setReferrersDownloaded(true)); 235 ds.getWays().forEach(i -> i.setReferrersDownloaded(true)); 236 } 218 237 return ds; 219 238 } catch (OsmTransferException e) { 220 239 throw e; … … 279 298 return true; 280 299 } 281 300 301 /** 302 * Get the bounds for this downloader 303 * @return The bounds for this downloader 304 * @since xxx 305 */ 306 protected Collection<Bounds> getBounds() { 307 return Collections.singleton(new Bounds(this.lat1, this.lon1, this.lat2, this.lon2)); 308 } 282 309 } -
src/org/openstreetmap/josm/io/OverpassDownloadReader.java
13 13 import java.time.ZoneOffset; 14 14 import java.time.format.DateTimeParseException; 15 15 import java.util.Arrays; 16 import java.util.Collection; 17 import java.util.Collections; 16 18 import java.util.EnumMap; 17 19 import java.util.List; 18 20 import java.util.Locale; … … 19 21 import java.util.Map; 20 22 import java.util.NoSuchElementException; 21 23 import java.util.Objects; 24 import java.util.Set; 22 25 import java.util.concurrent.ConcurrentHashMap; 23 26 import java.util.concurrent.TimeUnit; 24 27 import java.util.regex.Matcher; … … 406 409 } else { 407 410 // add bounds if necessary (note that Overpass API does not return bounds in the response XML) 408 411 if (ds != null && ds.getDataSources().isEmpty() && overpassQuery.contains("{{bbox}}")) { 409 if (crosses180th) { 410 Bounds bounds = new Bounds(lat1, lon1, lat2, 180.0); 411 DataSource src = new DataSource(bounds, getBaseUrl()); 412 ds.addDataSource(src); 413 414 bounds = new Bounds(lat1, -180.0, lat2, lon2); 415 src = new DataSource(bounds, getBaseUrl()); 416 ds.addDataSource(src); 417 } else { 418 Bounds bounds = new Bounds(lat1, lon1, lat2, lon2); 419 DataSource src = new DataSource(bounds, getBaseUrl()); 420 ds.addDataSource(src); 421 } 412 getBounds().forEach(bounds -> ds.addDataSource(new DataSource(bounds, getBaseUrl()))); 422 413 } 423 414 return ds; 424 415 } … … 440 431 public boolean considerAsFullDownload() { 441 432 return overpassQuery.equals(OverpassDownloadSource.FULL_DOWNLOAD_QUERY); 442 433 } 434 435 @Override 436 protected Collection<Bounds> getBounds() { 437 if (this.overpassQuery.contains("{{bbox}}")) { 438 if (crosses180th) { 439 return Set.of(new Bounds(lat1, lon1, lat2, 180.0), 440 new Bounds(lat1, -180.0, lat2, lon2)); 441 } else { 442 return Collections.singleton(new Bounds(lat1, lon1, lat2, lon2)); 443 } 444 } 445 return Collections.emptySet(); 446 } 443 447 }
