Changeset 36318 in osm
- Timestamp:
- 2024-08-21T22:32:24+02:00 (5 months ago)
- Location:
- applications/editors/josm/plugins/reverter/src/reverter
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
applications/editors/josm/plugins/reverter/src/reverter/ChangesetReverter.java
r36237 r36318 14 14 import java.util.List; 15 15 import java.util.Map; 16 import java.util.Objects; 16 17 import java.util.Optional; 17 18 import java.util.stream.Collectors; … … 56 57 public class ChangesetReverter { 57 58 59 /** The type of reversion */ 58 60 public enum RevertType { 59 61 FULL, … … 67 69 )); 68 70 71 /** The id of the changeset */ 69 72 public final int changesetId; 73 /** The changeset to be reverted */ 70 74 public final Changeset changeset; 75 /** The reversion type */ 71 76 public final RevertType revertType; 72 77 73 private final OsmDataLayer layer; // data layer associated with reverter 74 private final DataSet ds; // DataSet associated with reverter 75 private final ChangesetDataSet cds; // Current changeset data 78 /** data layer associated with reverter */ 79 private final OsmDataLayer layer; 80 /** DataSet associated with reverter */ 81 private final DataSet ds; 82 /** Current changeset data */ 83 private final ChangesetDataSet cds; 76 84 /** original DataSet, used if a new layer is requested */ 77 85 private final DataSet ods; 78 private DataSet nds; // Dataset that contains new objects downloaded by reverter 86 /** Dataset that contains new objects downloaded by reverter */ 87 private DataSet nds; 79 88 80 89 private final HashSet<PrimitiveId> missing = new HashSet<>(); … … 87 96 //// Handling missing objects 88 97 //////////////////////////////////////// 98 99 /** 100 * Add a primitive that is not in {@link #ds} to {@link #missing} 101 * @param id The primitive to add if missing 102 */ 89 103 private void addIfMissing(PrimitiveId id) { 90 104 OsmPrimitive p = ds.getPrimitiveById(id); … … 94 108 } 95 109 110 /** 111 * Add missing primitives to {@link #missing} 112 * @param primitives The primitives to iterate through 113 */ 96 114 private void addMissingHistoryIds(Iterable<HistoryOsmPrimitive> primitives) { 97 115 for (HistoryOsmPrimitive p : primitives) { … … 100 118 } 101 119 120 /** 121 * Add missing necessary primitives to {@link #missing} 122 * @param p The primitive to look at 123 */ 102 124 private void addMissingId(OsmPrimitive p) { 103 125 addIfMissing(p); … … 171 193 } 172 194 173 // Build our own lists of created/updated/modified objects for better performance 195 buildCreatedUpdatedModifiedObjectLists(); 196 } 197 198 /** 199 * Build our own lists of created/updated/modified objects for better performance 200 */ 201 private void buildCreatedUpdatedModifiedObjectLists() { 174 202 for (PrimitiveId id : cds.getIds()) { 175 203 ChangesetDataSetEntry first = cds.getFirstEntry(id); … … 189 217 } 190 218 219 /** 220 * Add missing primitives that have been created 221 */ 191 222 public void checkMissingCreated() { 192 223 addMissingHistoryIds(created); 193 224 } 194 225 226 /** 227 * Add missing primitives that have been updated 228 */ 195 229 public void checkMissingUpdated() { 196 230 addMissingHistoryIds(updated); 197 231 } 198 232 233 /** 234 * Add missing primitives that have been deleted 235 */ 199 236 public void checkMissingDeleted() { 200 237 addMissingHistoryIds(deleted); … … 237 274 if (progressMonitor.isCanceled()) return; 238 275 nds = rdr.parseOsm(progressMonitor.createSubTaskMonitor(1, true)); 239 ds.update(() -> { 240 for (OsmPrimitive p : nds.allPrimitives()) { 241 if (!p.isIncomplete()) { 242 addMissingId(p); 243 } else { 244 if (ds.getPrimitiveById(p.getPrimitiveId()) == null) { 245 switch (p.getType()) { 246 case NODE: ds.addPrimitive(new Node(p.getUniqueId())); break; 247 case CLOSEDWAY: 248 case WAY: ds.addPrimitive(new Way(p.getUniqueId())); break; 249 case MULTIPOLYGON: 250 case RELATION: ds.addPrimitive(new Relation(p.getUniqueId())); break; 251 default: throw new AssertionError(); 252 } 253 } 254 } 255 } 256 }); 276 ds.update(this::addPartialPrimitives); 257 277 } finally { 258 278 progressMonitor.finishTask(); … … 260 280 } 261 281 282 /** 283 * Add partial primitives if they are incomplete in {@link #nds} 284 */ 285 private void addPartialPrimitives() { 286 for (OsmPrimitive p : nds.allPrimitives()) { 287 if (!p.isIncomplete()) { 288 addMissingId(p); 289 } else { 290 if (ds.getPrimitiveById(p.getPrimitiveId()) == null) { 291 switch (p.getType()) { 292 case NODE: ds.addPrimitive(new Node(p.getUniqueId())); break; 293 case CLOSEDWAY: 294 case WAY: ds.addPrimitive(new Way(p.getUniqueId())); break; 295 case MULTIPOLYGON: 296 case RELATION: ds.addPrimitive(new Relation(p.getUniqueId())); break; 297 default: throw new AssertionError(); 298 } 299 } 300 } 301 } 302 } 303 304 /** 305 * Download any missing primitives we have 306 * @param monitor The monitor to update with our progress 307 * @throws OsmTransferException If there is an issue transferring data from OSM 308 */ 262 309 public void downloadMissingPrimitives(ProgressMonitor monitor) throws OsmTransferException { 263 310 if (!hasMissingObjects()) return; … … 308 355 switch (current.getType()) { 309 356 case NODE: 310 LatLon currentCoor = ((Node) current).getCoor(); 311 LatLon historyCoor = ((HistoryNode) history).getCoords(); 312 if (currentCoor == historyCoor || (currentCoor != null && historyCoor != null && currentCoor.equals(historyCoor))) 313 return true; 314 // Handle case where a deleted note has been restored to avoid false conflicts (fix #josm8660) 315 if (currentCoor != null && historyCoor == null) { 316 LatLon previousCoor = ((Node) nds.getPrimitiveById(history.getPrimitiveId())).getCoor(); 317 return previousCoor != null && previousCoor.equals(currentCoor); 318 } 319 return false; 357 return hasEqualSemanticAttributesNode(nds, (HistoryNode) history, (Node) current); 320 358 case CLOSEDWAY: 321 359 case WAY: 322 List<Node> currentNodes = ((Way) current).getNodes(); 323 List<Long> historyNodes = ((HistoryWay) history).getNodes(); 324 if (currentNodes.size() != historyNodes.size()) return false; 325 for (int i = 0; i < currentNodes.size(); i++) { 326 if (currentNodes.get(i).getId() != historyNodes.get(i)) return false; 327 } 328 return true; 360 return hasEqualSemanticAttributesWay((HistoryWay) history, (Way) current); 329 361 case MULTIPOLYGON: 330 362 case RELATION: 331 List<org.openstreetmap.josm.data.osm.RelationMember> currentMembers = 332 ((Relation) current).getMembers(); 333 List<RelationMemberData> historyMembers = ((HistoryRelation) history).getMembers(); 334 if (currentMembers.size() != historyMembers.size()) return false; 335 for (int i = 0; i < currentMembers.size(); i++) { 336 org.openstreetmap.josm.data.osm.RelationMember currentMember = 363 return hasEqualSemanticAttributesRelation((HistoryRelation) history, (Relation) current); 364 default: throw new AssertionError(); 365 } 366 } 367 368 /** 369 * Check if two nodes with the same tags are otherwise semantically similar 370 * @param nds The dataset with downloaded data from OSM (see {@link #nds}) 371 * @param history The node history 372 * @param current The current node 373 * @return {@code true} if they are semantically similar 374 */ 375 private static boolean hasEqualSemanticAttributesNode(DataSet nds, HistoryNode history, Node current) { 376 LatLon currentCoor = current.getCoor(); 377 LatLon historyCoor = history.getCoords(); 378 if (Objects.equals(currentCoor, historyCoor)) 379 return true; 380 // Handle case where a deleted note has been restored to avoid false conflicts (fix #josm8660) 381 if (currentCoor != null && historyCoor == null) { 382 LatLon previousCoor = ((Node) nds.getPrimitiveById(history.getPrimitiveId())).getCoor(); 383 return previousCoor != null && previousCoor.equals(currentCoor); 384 } 385 return false; 386 } 387 388 /** 389 * Check if two ways with the same tags are otherwise semantically similar 390 * @param history The way history 391 * @param current The current way 392 * @return {@code true} if they are semantically similar 393 */ 394 private static boolean hasEqualSemanticAttributesWay(HistoryWay history, Way current) { 395 List<Node> currentNodes = current.getNodes(); 396 List<Long> historyNodes = history.getNodes(); 397 if (currentNodes.size() != historyNodes.size()) return false; 398 for (int i = 0; i < currentNodes.size(); i++) { 399 if (currentNodes.get(i).getId() != historyNodes.get(i)) return false; 400 } 401 return true; 402 } 403 404 /** 405 * Check if two relations with the same tags are otherwise semantically similar 406 * @param history The relation history 407 * @param current The current relation 408 * @return {@code true} if they are semantically similar 409 */ 410 private static boolean hasEqualSemanticAttributesRelation(HistoryRelation history, Relation current) { 411 List<org.openstreetmap.josm.data.osm.RelationMember> currentMembers = current.getMembers(); 412 List<RelationMemberData> historyMembers = history.getMembers(); 413 if (currentMembers.size() != historyMembers.size()) return false; 414 for (int i = 0; i < currentMembers.size(); i++) { 415 org.openstreetmap.josm.data.osm.RelationMember currentMember = 337 416 currentMembers.get(i); 338 RelationMemberData historyMember = historyMembers.get(i); 339 if (!currentMember.getRole().equals(historyMember.getRole())) return false; 340 if (!currentMember.getMember().getPrimitiveId().equals(new SimplePrimitiveId( 341 historyMember.getMemberId(), historyMember.getMemberType()))) return false; 342 } 343 return true; 344 default: throw new AssertionError(); 345 } 417 RelationMemberData historyMember = historyMembers.get(i); 418 if (!currentMember.getRole().equals(historyMember.getRole())) return false; 419 if (!currentMember.getMember().getPrimitiveId().equals(new SimplePrimitiveId( 420 historyMember.getMemberId(), historyMember.getMemberType()))) return false; 421 } 422 return true; 346 423 } 347 424 … … 386 463 } 387 464 388 // Check objects versions 465 checkObjectVersions(cmds, conflicted, toDelete); 466 checkForDeletedReferrers(cmds, conflicted, toDelete); 467 return cmds; 468 } 469 470 /** 471 * Check objects versions 472 * @param cmds The command list to add to 473 * @param conflicted The primitives with conflicts 474 * @param toDelete The primitives that will be deleted 475 */ 476 private void checkObjectVersions(List<Command> cmds, HashSet<OsmPrimitive> conflicted, HashSet<OsmPrimitive> toDelete) { 389 477 for (Iterator<ChangesetDataSetEntry> it = cds.iterator(); it.hasNext();) { 390 478 ChangesetDataSetEntry entry = it.next(); 391 if (!checkOsmChangeEntry(entry)) continue; 392 if (entry.getModificationType() == ChangesetModificationType.DELETED 393 && revertType == RevertType.SELECTION_WITH_UNDELETE) { 394 // see #22520: missing merge target when object is first created and then 395 // deleted in the same changeset 396 ChangesetDataSetEntry first = cds.getFirstEntry(entry.getPrimitive().getPrimitiveId()); 397 if (first.getModificationType() == ChangesetModificationType.CREATED) 398 continue; 399 } 400 HistoryOsmPrimitive hp = entry.getPrimitive(); 401 OsmPrimitive dp = ds.getPrimitiveById(hp.getPrimitiveId()); 402 if (dp == null || dp.isIncomplete()) { 403 throw new IllegalStateException(addChangesetIdPrefix(tr("Missing merge target for {0}", hp.getPrimitiveId()))); 404 } 405 406 if (hp.getVersion() != dp.getVersion() 407 && (hp.isVisible() || dp.isVisible()) && 408 /* Don't create conflict if changeset object and dataset object 409 * has same semantic attributes (but different versions) */ 410 !hasEqualSemanticAttributes(dp, hp) 411 /* Don't create conflict if the object has to be deleted but has already been deleted */ 412 && !(toDelete.contains(dp) && dp.isDeleted())) { 413 cmds.add(new ConflictAddCommand(layer.data, createConflict(dp, 414 entry.getModificationType() == ChangesetModificationType.CREATED))); 415 conflicted.add(dp); 416 } 417 } 418 419 /* Check referrers for deleted objects: if object is referred by another object that 420 * isn't going to be deleted or modified, create a conflict. 421 */ 479 if (checkOsmChangeEntry(entry) && checkModificationType(cds, entry, revertType)) { 480 HistoryOsmPrimitive hp = entry.getPrimitive(); 481 OsmPrimitive dp = ds.getPrimitiveById(hp.getPrimitiveId()); 482 if (dp == null || dp.isIncomplete()) { 483 throw new IllegalStateException(addChangesetIdPrefix(tr("Missing merge target for {0}", hp.getPrimitiveId()))); 484 } 485 486 if (checkObjectVersionsNotSemanticallySame(toDelete, hp, dp)) { 487 cmds.add(new ConflictAddCommand(layer.data, createConflict(dp, 488 entry.getModificationType() == ChangesetModificationType.CREATED))); 489 conflicted.add(dp); 490 } 491 } 492 } 493 } 494 495 /** 496 * Check that the modification type is something that we are looking at 497 * @param cds {@link #cds} (current changeset data) 498 * @param entry The entry in the changeset data 499 * @param revertType The type of revert we are doing 500 * @return {@code true} if the entry is something we are interested in for this revert 501 */ 502 private static boolean checkModificationType(ChangesetDataSet cds, ChangesetDataSetEntry entry, RevertType revertType) { 503 if (entry.getModificationType() == ChangesetModificationType.DELETED 504 && revertType == RevertType.SELECTION_WITH_UNDELETE) { 505 // see #22520: missing merge target when object is first created and then 506 // deleted in the same changeset 507 ChangesetDataSetEntry first = cds.getFirstEntry(entry.getPrimitive().getPrimitiveId()); 508 return first.getModificationType() != ChangesetModificationType.CREATED; 509 } 510 return true; 511 } 512 513 /** 514 * Check that versions are not the same prior to creating a conflict 515 * @param toDelete The deleted objects 516 * @param hp The history primitive 517 * @param dp The current primitive 518 * @return {@code true} if the objects are not semantically the same 519 */ 520 private boolean checkObjectVersionsNotSemanticallySame(HashSet<OsmPrimitive> toDelete, HistoryOsmPrimitive hp, OsmPrimitive dp) { 521 return hp.getVersion() != dp.getVersion() 522 && (hp.isVisible() || dp.isVisible()) && 523 /* Don't create conflict if changeset object and dataset object 524 * has same semantic attributes (but different versions) */ 525 !hasEqualSemanticAttributes(dp, hp) 526 /* Don't create conflict if the object has to be deleted but has already been deleted */ 527 && !(toDelete.contains(dp) && dp.isDeleted()); 528 } 529 530 /** 531 * Check referrers for deleted objects: if object is referred by another object that 532 * isn't going to be deleted or modified, create a conflict. 533 * @param cmds The command list to add to 534 * @param conflicted The primitives with conflicts 535 * @param toDelete The primitives that will be deleted 536 */ 537 private void checkForDeletedReferrers(List<Command> cmds, HashSet<OsmPrimitive> conflicted, HashSet<OsmPrimitive> toDelete) { 422 538 List<OsmPrimitive> delSorted = toDelete.stream() 423 539 .filter(p -> !p.isDeleted()) … … 429 545 for (int i = 0; i < delSorted.size() && !restartNeeded; i++) { 430 546 OsmPrimitive p = delSorted.get(i); 431 for (OsmPrimitive referrer : p.getReferrers()) { 432 if (toDelete.contains(referrer)) continue; // object is going to be deleted 433 if (nds.getPrimitiveById(referrer) != null) 434 continue; /* object is going to be modified so it cannot refer to 435 * objects created in changeset to be reverted 436 */ 437 if (conflicted.add(p)) { 438 cmds.add(new ConflictAddCommand(layer.data, createConflict(p, true))); 439 if (p instanceof Relation) { 440 // handle possible special case with nested relations 441 for (int j = 0; j < i; j++) { 442 if (delSorted.get(j).getReferrers().contains(p)) { 443 // we have to create a conflict for a previously processed relation 444 restartNeeded = true; 445 break; 446 } 447 } 448 } 449 } 450 toDelete.remove(p); 451 break; 452 } 547 restartNeeded = checkForDeletedReferrersPrimitive(cmds, conflicted, toDelete, delSorted, p, i); 453 548 } 454 549 } while (restartNeeded); … … 458 553 cmds.add(new DeleteCommand(delSorted)); 459 554 } 460 return cmds; 461 } 462 555 } 556 557 /** 558 * 559 * @param cmds The command list to add to 560 * @param conflicted The primitives with conflicts 561 * @param toDelete The primitives that will be deleted 562 * @param delSorted The list of sorted deleted objects we need to check against 563 * @param p The primitive to check 564 * @param i The current index in {@code delSorted} 565 * @return {@code true} if we need to restart processing 566 */ 567 private boolean checkForDeletedReferrersPrimitive(List<Command> cmds, HashSet<OsmPrimitive> conflicted, 568 HashSet<OsmPrimitive> toDelete, List<OsmPrimitive> delSorted, 569 OsmPrimitive p, int i) { 570 for (OsmPrimitive referrer : p.getReferrers()) { 571 if (toDelete.contains(referrer) || // object is going to be deleted 572 nds.getPrimitiveById(referrer) != null) 573 continue; /* object is going to be modified so it cannot refer to 574 * objects created in changeset to be reverted 575 */ 576 if (conflicted.add(p)) { 577 cmds.add(new ConflictAddCommand(layer.data, createConflict(p, true))); 578 if (p instanceof Relation) { 579 // handle possible special case with nested relations 580 for (int j = 0; j < i; j++) { 581 if (delSorted.get(j).getReferrers().contains(p)) { 582 // we have to create a conflict for a previously processed relation 583 return true; 584 } 585 } 586 } 587 } 588 toDelete.remove(p); 589 return false; 590 } 591 return false; 592 } 593 594 /** 595 * Check if there are missing objects 596 * @return {@code true} if we need to handle missing objects 597 */ 463 598 public boolean hasMissingObjects() { 464 599 return !missing.isEmpty(); 465 600 } 466 601 602 /** 603 * Get coordinates for nodes that have no coordinates 604 * @param progressMonitor The monitor to update our progress with 605 * @throws OsmTransferException If we have an issue getting data from the API 606 */ 467 607 public void fixNodesWithoutCoordinates(ProgressMonitor progressMonitor) throws OsmTransferException { 468 608 Collection<Node> nodes = new ArrayList<>(nds.getNodes()); -
applications/editors/josm/plugins/reverter/src/reverter/RevertChangesetAction.java
r35579 r36318 2 2 package reverter; 3 3 4 import static org.openstreetmap.josm.tools.I18n.marktr; 4 5 import static org.openstreetmap.josm.tools.I18n.tr; 5 6 … … 14 15 import reverter.ChangesetReverter.RevertType; 15 16 17 /** 18 * An action for reverting changesets 19 */ 16 20 public class RevertChangesetAction extends JosmAction { 21 private static final String REVERT_CHANGESET = marktr("Revert changeset"); 17 22 23 /** 24 * Create a new action for reverting changesets 25 */ 18 26 public RevertChangesetAction() { 19 super(tr( "Revert changeset"), "revert-changeset", tr("Revert changeset"),20 Shortcut.registerShortcut("tool:revert", tr("Data: {0}", tr( "Revert changeset")), KeyEvent.VK_T, Shortcut.CTRL_SHIFT),27 super(tr(REVERT_CHANGESET), "revert-changeset", tr(REVERT_CHANGESET), 28 Shortcut.registerShortcut("tool:revert", tr("Data: {0}", tr(REVERT_CHANGESET)), KeyEvent.VK_T, Shortcut.CTRL_SHIFT), 21 29 true, false); 22 30 } -
applications/editors/josm/plugins/reverter/src/reverter/RevertChangesetTask.java
r36230 r36318 9 9 import java.util.Collections; 10 10 import java.util.List; 11 import java.util.concurrent.Callable;12 11 import java.util.stream.Collectors; 13 12 … … 30 29 import reverter.ChangesetReverter.RevertType; 31 30 31 /** 32 * The task for reverting changesets 33 */ 32 34 public class RevertChangesetTask extends PleaseWaitRunnable { 33 35 private final Collection<Integer> changesetIds; … … 40 42 private int numberOfConflicts; 41 43 44 /** 45 * Create a new task for reverting a changeset with a default progress monitor and no new layer with user confirmation of the download 46 * @param changesetId The changeset id to revert 47 * @param revertType The type of revert to do 48 */ 42 49 public RevertChangesetTask(int changesetId, RevertType revertType) { 43 50 this(changesetId, revertType, false); 44 51 } 45 52 53 /** 54 * Create a new task for reverting a changeset with a default progress monitor and no new layer 55 * @param changesetId The changeset id to revert 56 * @param revertType The type of revert to do 57 * @param autoConfirmDownload {@code true} if the user has already indicated that they want to download missing data 58 */ 46 59 public RevertChangesetTask(int changesetId, RevertType revertType, boolean autoConfirmDownload) { 47 60 this(changesetId, revertType, autoConfirmDownload, false); 48 61 } 49 62 63 /** 64 * Create a new task for reverting a changeset with a default progress monitor 65 * @param changesetId The changeset id to revert 66 * @param revertType The type of revert to do 67 * @param autoConfirmDownload {@code true} if the user has already indicated that they want to download missing data 68 * @param newLayer {@code true} if the user wants the reversion to be on a new layer 69 */ 50 70 public RevertChangesetTask(int changesetId, RevertType revertType, boolean autoConfirmDownload, boolean newLayer) { 51 71 this(Collections.singleton(changesetId), revertType, autoConfirmDownload, newLayer); 52 72 } 53 73 74 /** 75 * Create a new task for reverting a changeset with a default progress monitor 76 * @param changesetIds The changeset ids to revert 77 * @param revertType The type of revert to do 78 * @param autoConfirmDownload {@code true} if the user has already indicated that they want to download missing data 79 * @param newLayer {@code true} if the user wants the reversion to be on a new layer 80 */ 54 81 public RevertChangesetTask(Collection<Integer> changesetIds, RevertType revertType, boolean autoConfirmDownload, boolean newLayer) { 55 82 this(null, changesetIds, revertType, autoConfirmDownload, newLayer); … … 64 91 * @param newLayer {@code true} if the user wants the reversion to be on a new layer 65 92 */ 66 public RevertChangesetTask(ProgressMonitor progressMonitor, Collection<Integer> changesetIds, RevertType revertType, boolean autoConfirmDownload, boolean newLayer) { 93 public RevertChangesetTask(ProgressMonitor progressMonitor, Collection<Integer> changesetIds, RevertType revertType, 94 boolean autoConfirmDownload, boolean newLayer) { 67 95 super(tr("Reverting..."), progressMonitor, false); 68 96 this.changesetIds = new ArrayList<>(changesetIds); … … 77 105 if (!rev.hasMissingObjects()) return true; 78 106 if (!downloadConfirmed) { 79 final Integer selectedOption = GuiHelper.runInEDTAndWaitAndReturn(new Callable<Integer>() { 80 @Override 81 public Integer call() throws Exception { 82 return JOptionPane.showConfirmDialog(MainApplication.getMainFrame(), 83 tr("This changeset has objects that are not present in current dataset.\n" + 84 "It is needed to download them before reverting. Do you want to continue?"), 85 tr("Confirm"), JOptionPane.YES_NO_OPTION); 86 } 87 }); 107 final Integer selectedOption = GuiHelper.runInEDTAndWaitAndReturn(() -> JOptionPane.showConfirmDialog(MainApplication.getMainFrame(), 108 tr("This changeset has objects that are not present in current dataset.\n" + 109 "It is needed to download them before reverting. Do you want to continue?"), 110 tr("Confirm"), JOptionPane.YES_NO_OPTION)); 88 111 downloadConfirmed = selectedOption != null && selectedOption == JOptionPane.YES_OPTION; 89 112 if (!downloadConfirmed) return false; … … 142 165 rev = new ChangesetReverter(changesetId, revertType, newLayer, oldDataSet, progressMonitor.createSubTaskMonitor(0, true)); 143 166 } catch (final RevertRedactedChangesetException e) { 167 Logging.debug(e); 144 168 GuiHelper.runInEDT(() -> new Notification( 145 169 e.getMessage()+"<br>"+ … … 191 215 return null; 192 216 } 193 GuiHelper.runInEDT(() -> cmds.get(0).getAffectedDataSet().update(() -> { 217 GuiHelper.runInEDT(() -> executeCommands(cmds)); 218 final String desc = getRevertDescription(revertType, changesetId); 219 return new RevertChangesetCommand(desc, cmds); 220 } 221 222 /** 223 * Execute a list of commands 224 * @param cmds The commands to execute 225 */ 226 private void executeCommands(List<Command> cmds) { 227 cmds.get(0).getAffectedDataSet().update(() -> { 194 228 for (Command c : cmds) { 195 229 if (c instanceof ConflictAddCommand) { … … 198 232 c.executeCommand(); 199 233 } 200 })); 201 final String desc; 234 }); 235 } 236 237 /** 238 * Get the description to show the user for this reversion 239 * @param revertType The type of revert 240 * @param changesetId The changeset id 241 * @return The string to show the user 242 */ 243 private static String getRevertDescription(RevertType revertType, int changesetId) { 202 244 if (revertType == RevertType.FULL) { 203 desc =tr("Revert changeset {0}", String.valueOf(changesetId));245 return tr("Revert changeset {0}", String.valueOf(changesetId)); 204 246 } else { 205 desc = tr("Partially revert changeset {0}", String.valueOf(changesetId)); 206 } 207 return new RevertChangesetCommand(desc, cmds); 247 return tr("Partially revert changeset {0}", String.valueOf(changesetId)); 248 } 208 249 } 209 250
Note:
See TracChangeset
for help on using the changeset viewer.