Ticket #5221: merger.diff

File merger.diff, 7.2 KB (added by Upliner, 15 years ago)

patch for DataSetMerger

  • src/org/openstreetmap/josm/data/osm/DataSetMerger.java

     
    66import java.util.Collection;
    77import java.util.HashMap;
    88import java.util.HashSet;
     9import java.util.Iterator;
    910import java.util.LinkedList;
    1011import java.util.List;
    1112import java.util.Map;
     
    3940     * to relation members) after the first phase of merging
    4041     */
    4142    private final Set<PrimitiveId> objectsWithChildrenToMerge;
    42     private final Set<OsmPrimitive> deletedObjectsToUnlink;
     43    private final Set<OsmPrimitive> objectsToDelete;
    4344
    4445    /**
    4546     * constructor
     
    5758        conflicts = new ConflictCollection();
    5859        mergedMap = new HashMap<PrimitiveId, PrimitiveId>();
    5960        objectsWithChildrenToMerge = new HashSet<PrimitiveId>();
    60         deletedObjectsToUnlink = new HashSet<OsmPrimitive>();
     61        objectsToDelete = new HashSet<OsmPrimitive>();
    6162    }
    6263
    6364    /**
     
    161162                mergeRelationMembers(r);
    162163            }
    163164        }
    164         for (OsmPrimitive source: deletedObjectsToUnlink) {
    165             OsmPrimitive target = getMergeTarget(source);
    166             if (target == null)
    167                 throw new RuntimeException(tr("Missing merge target for object with id {0}", source.getUniqueId()));
    168             targetDataSet.unlinkReferencesToPrimitive(target);
     165
     166        deleteMarkedObjects();
     167    }
     168
     169    /**
     170     * Deleted objects in objectsToDelete set and create conflicts for objects that cannot
     171     * be deleted because they're referenced in the target dataset.
     172     */
     173    protected void deleteMarkedObjects() {
     174        boolean flag;
     175        do {
     176            flag = false;
     177            for (Iterator<OsmPrimitive> it = objectsToDelete.iterator();it.hasNext();) {
     178                OsmPrimitive target = it.next();
     179                OsmPrimitive source = sourceDataSet.getPrimitiveById(target.getPrimitiveId());
     180                if (source == null)
     181                    throw new RuntimeException(tr("Object of type {0} with id {1} was marked to be deleted, but it's missing in the source dataset",
     182                            target.getType(), target.getUniqueId()));
     183
     184                List<OsmPrimitive> referrers = target.getReferrers();
     185                if (referrers.isEmpty()) {
     186                    target.setDeleted(true);
     187                    target.mergeFrom(source);
     188                    it.remove();
     189                    flag = true;
     190                } else {
     191                    for (OsmPrimitive referrer : referrers) {
     192                        // If one of object referrers isn't going to be deleted,
     193                        // add a conflict and don't delete the object
     194                        if (!objectsToDelete.contains(referrer)) {
     195                            conflicts.add(target, source);
     196                            it.remove();
     197                            flag = true;
     198                            break;
     199                        }
     200                    }
     201                }
     202
     203            }
     204        } while (flag);
     205
     206        if (!objectsToDelete.isEmpty()) {
     207            // There are some more objects rest in the objectsToDelete set
     208            // This can be because of cross-referenced relations.
     209            for (OsmPrimitive osm: objectsToDelete) {
     210                if (osm instanceof Way) {
     211                    ((Way) osm).setNodes(null);
     212                } else if (osm instanceof Relation) {
     213                    ((Relation) osm).setMembers(null);
     214                }
     215            }
     216            for (OsmPrimitive osm: objectsToDelete) {
     217                osm.setDeleted(true);
     218                osm.mergeFrom(sourceDataSet.getPrimitiveById(osm.getPrimitiveId()));
     219            }
    169220        }
    170221    }
    171222
     
    256307            // target and source are incomplete. Doesn't matter which one to
    257308            // take. We take target.
    258309            //
    259         } else if (target.isDeleted() && ! source.isDeleted() && target.getVersion() == source.getVersion()) {
     310        } else if (target.isVisible() != source.isVisible() && target.getVersion() == source.getVersion())
     311            // Same version, but different "visible" attribute. It indicates a serious problem in datasets.
     312            // For example, datasets can be fetched from different OSM servers or badly hand-modified.
     313            // We shouldn't merge that datasets.
     314            throw new DataIntegrityProblemException(tr("Conflict in 'visible' attribute for object of type {0} with id {1}",
     315                    target.getType(), target.getId()));
     316        else if (target.isDeleted() && ! source.isDeleted() && target.getVersion() == source.getVersion()) {
    260317            // same version, but target is deleted. Assume target takes precedence
    261318            // otherwise too many conflicts when refreshing from the server
    262319            // but, if source has a referrer that is not in the target dataset there is a conflict
     
    268325                    break;
    269326                }
    270327            }
    271         } else if (target.isDeleted() != source.isDeleted()) {
    272             // differences in deleted state have to be resolved manually. This can
    273             // happen if one layer is merged onto another layer
     328        } else if (! target.isModified() && source.isDeleted()) {
     329            // target not modified. We can assume that source is the most recent version,
     330            // so mark it to be deleted.
    274331            //
    275             conflicts.add(target,source);
     332            objectsToDelete.add(target);
    276333        } else if (! target.isModified() && source.isModified()) {
    277334            // target not modified. We can assume that source is the most recent version.
    278             // clone it into target. But check first, whether source is deleted. if so,
    279             // make sure that target is not referenced any more in myDataSet. If it is there
    280             // is a conflict
    281             if (source.isDeleted()) {
    282                 if (!target.getReferrers().isEmpty()) {
    283                     conflicts.add(target, source);
    284                 }
    285             } else {
    286                 target.mergeFrom(source);
    287                 objectsWithChildrenToMerge.add(source.getPrimitiveId());
    288             }
     335            // clone it into target.
     336            target.mergeFrom(source);
     337            objectsWithChildrenToMerge.add(source.getPrimitiveId());
    289338        } else if (! target.isModified() && !source.isModified() && target.getVersion() == source.getVersion()) {
    290339            // both not modified. Merge nevertheless.
    291340            // This helps when updating "empty" relations, see #4295
     
    302351            if (target.hasEqualSemanticAttributes(source)) {
    303352                target.setModified(false);
    304353            }
     354        } else if (source.isDeleted() != target.isDeleted()) {
     355            // target is modified and deleted state differs.
     356            // this have to be resolved manually.
     357            //
     358            conflicts.add(target,source);
    305359        } else if (! target.hasEqualSemanticAttributes(source)) {
    306360            // target is modified and is not semantically equal with source. Can't automatically
    307361            // resolve the differences