Ticket #5221: merger.diff

File merger.diff, 7.2 KB (added by Upliner, 22 months 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