Ignore:
Timestamp:
2009-11-09T08:06:56+01:00 (15 years ago)
Author:
Gubaer
Message:

Another update of MergeVisitor. Improves merging of node lists and relation members.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/MergeVisitor.java

    r2417 r2418  
    55import java.util.Collection;
    66import java.util.HashMap;
     7import java.util.HashSet;
    78import java.util.LinkedList;
    89import java.util.List;
    910import java.util.Map;
     11import java.util.Set;
    1012import java.util.logging.Logger;
    1113
     
    3840     * Key is the primitive id in their dataset, the value is the id in my dataset
    3941     */
    40     private Map<Long, Long> merged;
     42    private Map<Long, Long> mergedMap;
     43    /** a set of primitive ids for which we have to fix references (to nodes and
     44     * to relation members) after the first phase of merging
     45     */
     46    private Set<Long> fixReferences;
    4147
    4248    /**
     
    5258        this.theirDataSet = theirDataSet;
    5359        conflicts = new ConflictCollection();
    54         merged = new HashMap<Long, Long>();
     60        mergedMap = new HashMap<Long, Long>();
     61        fixReferences = new HashSet<Long>();
    5562    }
    5663
     
    9198                }
    9299                if (my.hasEqualSemanticAttributes(other)) {
     100                    mergedMap.put(other.getUniqueId(), my.getUniqueId());
    93101                    if (my.isDeleted() != other.isDeleted()) {
    94102                        // differences in deleted state have to be merged manually
    95103                        //
    96104                        conflicts.add(my, other);
    97                         merged.put(other.getUniqueId(), my.getUniqueId());
    98105                    } else {
    99106                        // copy the technical attributes from other
     
    103110                        my.setTimestamp(other.getTimestamp());
    104111                        my.setModified(other.isModified());
    105                         merged.put(other.getUniqueId(), my.getUniqueId());
     112                        fixReferences.add(other.getUniqueId());
    106113                    }
    107114                    return;
     
    120127        my.mergeFrom(other);
    121128        myDataSet.addPrimitive(my);
    122         merged.put(other.getUniqueId(), my.getUniqueId());
     129        mergedMap.put(other.getUniqueId(), my.getUniqueId());
     130        fixReferences.add(other.getUniqueId());
    123131    }
    124132
     
    136144
    137145    protected OsmPrimitive getMergeTarget(OsmPrimitive mergeSource) {
    138         Long targetId = merged.get(mergeSource.getUniqueId());
     146        Long targetId = mergedMap.get(mergeSource.getUniqueId());
    139147        if (targetId == null)
    140             throw new RuntimeException("no merge target for merge primitive " + mergeSource.getUniqueId() + " of type " + mergeSource.getType());
     148            throw new RuntimeException(tr("Missing merge target for way with id {0}", mergeSource.getUniqueId()));
    141149        return myDataSet.getPrimitiveById(targetId, mergeSource.getType());
    142150    }
     
    160168    public void fixReferences() {
    161169        for (Way w : theirDataSet.getWays()) {
    162             if (!conflicts.hasConflictForTheir(w)) {
     170            if (!conflicts.hasConflictForTheir(w) && fixReferences.contains(w.getUniqueId())) {
    163171                mergeNodeList(w);
    164172                fixIncomplete(w);
     
    166174        }
    167175        for (Relation r : theirDataSet.getRelations()) {
    168             if (!conflicts.hasConflictForTheir(r)) {
     176            if (!conflicts.hasConflictForTheir(r) && fixReferences.contains(r.getUniqueId())) {
    169177                mergeRelationMembers(r);
    170178            }
     
    262270        // merge other into an existing primitive with the same id, if possible
    263271        //
    264         if (my != null) {
    265             if (my.getVersion() <= other.getVersion()) {
    266                 if (! my.isVisible() && other.isVisible()) {
    267                     // should not happen
    268                     //
    269                     logger.warning(tr("My primitive with id {0} and version {1} is visible although "
    270                             + "their primitive with lower version {2} is not visible. "
    271                             + "Can't deal with this inconsistency. Keeping my primitive. ",
    272                             Long.toString(my.getId()),Long.toString(my.getVersion()), Long.toString(other.getVersion())
    273                     ));
    274                     merged.put(other.getUniqueId(), my.getUniqueId());
    275                 } else if (my.isVisible() && ! other.isVisible()) {
    276                     // this is always a conflict because the user has to decide whether
    277                     // he wants to create a clone of its local primitive or whether he
    278                     // wants to purge my from the local dataset. He can't keep it unchanged
    279                     // because it was deleted on the server.
    280                     //
    281                     conflicts.add(my,other);
    282                     merged.put(other.getUniqueId(), my.getUniqueId());
    283                 } else if (my.incomplete && !other.incomplete) {
    284                     // my is incomplete, other completes it
    285                     // => merge other onto my
    286                     //
    287                     my.mergeFrom(other);
    288                     merged.put(other.getUniqueId(), my.getUniqueId());
    289                 } else if (!my.incomplete && other.incomplete) {
    290                     // my is complete and the other is incomplete
    291                     // => keep mine, we have more information already
    292                     //
    293                     merged.put(other.getUniqueId(), my.getUniqueId());
    294                 } else if (my.incomplete && other.incomplete) {
    295                     // my and other are incomplete. Doesn't matter which one to
    296                     // take. We take mine.
    297                     //
    298                     merged.put(other.getUniqueId(), my.getUniqueId());
    299                 } else if (my.isDeleted() && ! other.isDeleted() && my.getVersion() == other.getVersion()) {
    300                     // same version, but my is deleted. Assume mine takes precedence
    301                     // otherwise too many conflicts when refreshing from the server
    302                     merged.put(other.getUniqueId(), my.getUniqueId());
    303                 } else if (my.isDeleted() != other.isDeleted()) {
    304                     // differences in deleted state have to be resolved manually
    305                     //
    306                     conflicts.add(my,other);
    307                     merged.put(other.getUniqueId(), my.getUniqueId());
    308                 } else if (! my.isModified() && other.isModified()) {
    309                     // my not modified. We can assume that other is the most recent version.
    310                     // clone it onto my. But check first, whether other is deleted. if so,
    311                     // make sure that my is not references anymore in myDataSet.
    312                     //
    313                     if (other.isDeleted()) {
    314                         myDataSet.unlinkReferencesToPrimitive(my);
    315                     }
    316                     my.mergeFrom(other);
    317                     merged.put(other.getUniqueId(), my.getUniqueId());
    318                 } else if (! my.isModified() && !other.isModified() && my.getVersion() == other.getVersion()) {
    319                     // both not modified. Keep mine
    320                     //
    321                     merged.put(other.getUniqueId(),my.getUniqueId());
    322                 } else if (! my.isModified() && !other.isModified() && my.getVersion() < other.getVersion()) {
    323                     // my not modified but other is newer. clone other onto mine.
    324                     //
    325                     my.mergeFrom(other);
    326                     merged.put(other.getUniqueId(),my.getUniqueId());
    327                 } else if (my.isModified() && ! other.isModified() && my.getVersion() == other.getVersion()) {
    328                     // my is same as other but mine is modified
    329                     // => keep mine
    330                     merged.put(other.getUniqueId(), my.getUniqueId());
    331                 } else if (! my.hasEqualSemanticAttributes(other)) {
    332                     // my is modified and is not semantically equal with other. Can't automatically
    333                     // resolve the differences
    334                     // =>  create a conflict
    335                     conflicts.add(my,other);
    336                     merged.put(other.getUniqueId(), my.getUniqueId());
    337                 } else {
    338                     // clone from other, but keep the modified flag. Clone will mainly copy
    339                     // technical attributes like timestamp or user information. Semantic
    340                     // attributes should already be equal if we get here.
    341                     //
    342                     my.mergeFrom(other);
    343                     my.setModified(true);
    344                     merged.put(other.getUniqueId(), my.getUniqueId());
    345                 }
    346             } else {
    347                 // my.version > other.version => keep my version
    348                 merged.put(other.getUniqueId(), my.getUniqueId());
    349             }
     272        if (my == null)
     273            return false;
     274        mergedMap.put(other.getUniqueId(), my.getUniqueId());
     275        if (my.getVersion() > other.getVersion())
     276            // my.version > other.version => keep my version
    350277            return true;
    351         }
    352         return false;
    353     }
    354 
     278        if (! my.isVisible() && other.isVisible()) {
     279            // should not happen
     280            //
     281            logger.warning(tr("My primitive with id {0} and version {1} is visible although "
     282                    + "their primitive with lower version {2} is not visible. "
     283                    + "Can't deal with this inconsistency. Keeping my primitive. ",
     284                    Long.toString(my.getId()),Long.toString(my.getVersion()), Long.toString(other.getVersion())
     285            ));
     286        } else if (my.isVisible() && ! other.isVisible()) {
     287            // this is always a conflict because the user has to decide whether
     288            // he wants to create a clone of its local primitive or whether he
     289            // wants to purge my from the local dataset. He can't keep it unchanged
     290            // because it was deleted on the server.
     291            //
     292            conflicts.add(my,other);
     293        } else if (my.incomplete && !other.incomplete) {
     294            // my is incomplete, other completes it
     295            // => merge other onto my
     296            //
     297            my.mergeFrom(other);
     298            fixReferences.add(other.getUniqueId());
     299        } else if (!my.incomplete && other.incomplete) {
     300            // my is complete and the other is incomplete
     301            // => keep mine, we have more information already
     302            //
     303        } else if (my.incomplete && other.incomplete) {
     304            // my and other are incomplete. Doesn't matter which one to
     305            // take. We take mine.
     306            //
     307        } else if (my.isDeleted() && ! other.isDeleted() && my.getVersion() == other.getVersion()) {
     308            // same version, but my is deleted. Assume mine takes precedence
     309            // otherwise too many conflicts when refreshing from the server
     310        } else if (my.isDeleted() != other.isDeleted()) {
     311            // differences in deleted state have to be resolved manually
     312            //
     313            conflicts.add(my,other);
     314        } else if (! my.isModified() && other.isModified()) {
     315            // my not modified. We can assume that other is the most recent version.
     316            // clone it onto my. But check first, whether other is deleted. if so,
     317            // make sure that my is not references anymore in myDataSet.
     318            //
     319            if (other.isDeleted()) {
     320                myDataSet.unlinkReferencesToPrimitive(my);
     321            }
     322            my.mergeFrom(other);
     323            fixReferences.add(other.getUniqueId());
     324        } else if (! my.isModified() && !other.isModified() && my.getVersion() == other.getVersion()) {
     325            // both not modified. Keep mine
     326            //
     327        } else if (! my.isModified() && !other.isModified() && my.getVersion() < other.getVersion()) {
     328            // my not modified but other is newer. clone other onto mine.
     329            //
     330            my.mergeFrom(other);
     331            fixReferences.add(other.getUniqueId());
     332        } else if (my.isModified() && ! other.isModified() && my.getVersion() == other.getVersion()) {
     333            // my is same as other but mine is modified
     334            // => keep mine
     335        } else if (! my.hasEqualSemanticAttributes(other)) {
     336            // my is modified and is not semantically equal with other. Can't automatically
     337            // resolve the differences
     338            // =>  create a conflict
     339            conflicts.add(my,other);
     340        } else {
     341            // clone from other, but keep the modified flag. mergeFrom will mainly copy
     342            // technical attributes like timestamp or user information. Semantic
     343            // attributes should already be equal if we get here.
     344            //
     345            my.mergeFrom(other);
     346            my.setModified(true);
     347            fixReferences.add(other.getUniqueId());
     348        }
     349        return true;
     350    }
    355351
    356352    /**
Note: See TracChangeset for help on using the changeset viewer.