Ticket #7489: add_merge_command2.patch

File add_merge_command2.patch, 25.9 KB (added by joshdoe, 14 years ago)

slight changes, and add undo for download actions

  • src/org/openstreetmap/josm/gui/dialogs/relation/DownloadRelationMemberTask.java

     
    1313import javax.swing.SwingUtilities;
    1414
    1515import org.openstreetmap.josm.Main;
     16import org.openstreetmap.josm.command.DownloadOsmCommand;
    1617import org.openstreetmap.josm.data.osm.DataSet;
    1718import org.openstreetmap.josm.data.osm.OsmPrimitive;
    1819import org.openstreetmap.josm.data.osm.Relation;
     
    135136            SwingUtilities.invokeLater(
    136137                    new Runnable() {
    137138                        public void run() {
    138                             curLayer.mergeFrom(dataSet);
    139                             curLayer.onPostDownloadFromServer();
     139                            Main.main.undoRedo.add(new DownloadOsmCommand(tr("Download relation members"), curLayer, dataSet));
    140140                        }
    141141                    }
    142142            );
  • src/org/openstreetmap/josm/gui/dialogs/relation/DownloadRelationTask.java

     
    99import javax.swing.SwingUtilities;
    1010
    1111import org.openstreetmap.josm.Main;
     12import org.openstreetmap.josm.command.DownloadOsmCommand;
    1213import org.openstreetmap.josm.data.osm.DataSet;
    1314import org.openstreetmap.josm.data.osm.DataSetMerger;
    1415import org.openstreetmap.josm.data.osm.Relation;
     
    9899            SwingUtilities.invokeAndWait(
    99100                    new Runnable() {
    100101                        public void run() {
    101                             layer.mergeFrom(allDownloads);
    102                             layer.onPostDownloadFromServer();
     102                            Main.main.undoRedo.add(new DownloadOsmCommand(tr("Download relation(s)"), layer, allDownloads));
    103103                            Main.map.repaint();
    104104                        }
    105105                    }
  • src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java

     
    9999
    100100    public List<TestError> validationErrors = new ArrayList<TestError>();
    101101
    102     protected void setRequiresSaveToFile(boolean newValue) {
     102    public void setRequiresSaveToFile(boolean newValue) {
    103103        boolean oldValue = requiresSaveToFile;
    104104        requiresSaveToFile = newValue;
    105105        if (oldValue != newValue) {
     
    107107        }
    108108    }
    109109
    110     protected void setRequiresUploadToServer(boolean newValue) {
     110    public void setRequiresUploadToServer(boolean newValue) {
    111111        boolean oldValue = requiresUploadToServer;
    112112        requiresUploadToServer = newValue;
    113113        if (oldValue != newValue) {
     
    299299    }
    300300
    301301    @Override public void mergeFrom(final Layer from) {
     302        // TODO: make undo-able
    302303        final PleaseWaitProgressMonitor monitor = new PleaseWaitProgressMonitor(tr("Merging layers"));
    303304        monitor.setCancelable(false);
    304305        mergeFrom(((OsmDataLayer)from).data, monitor);
     
    311312     *
    312313     * @param from  the source data set
    313314     */
     315    @Deprecated
    314316    public void mergeFrom(final DataSet from) {
    315317        mergeFrom(from, null);
    316318    }
     
    321323     *
    322324     * @param from  the source data set
    323325     */
     326    @Deprecated
    324327    public void mergeFrom(final DataSet from, ProgressMonitor progressMonitor) {
    325328        final DataSetMerger visitor = new DataSetMerger(data,from);
    326329        try {
     
    372375     *
    373376     * @param numNewConflicts the number of detected conflicts
    374377     */
    375     protected void warnNumNewConflicts(int numNewConflicts) {
     378    public void warnNumNewConflicts(int numNewConflicts) {
    376379        if (numNewConflicts == 0) return;
    377380
    378381        String msg1 = trn(
  • src/org/openstreetmap/josm/gui/io/DownloadPrimitivesTask.java

     
    1010import java.util.Set;
    1111
    1212import javax.swing.SwingUtilities;
     13import org.openstreetmap.josm.Main;
    1314
    1415import org.openstreetmap.josm.actions.AutoScaleAction;
     16import org.openstreetmap.josm.command.DownloadOsmCommand;
    1517import org.openstreetmap.josm.data.osm.DataSet;
    1618import org.openstreetmap.josm.data.osm.DataSetMerger;
    1719import org.openstreetmap.josm.data.osm.Node;
     
    8385        }
    8486        Runnable r = new Runnable() {
    8587            public void run() {
    86                 layer.mergeFrom(ds);
     88                Main.main.undoRedo.add(new DownloadOsmCommand(tr("Download primitives"), layer, ds));
    8789                AutoScaleAction.zoomTo(ds.allPrimitives());
    88                 layer.onPostDownloadFromServer();
    8990            }
    9091        };
    9192
  • src/org/openstreetmap/josm/gui/io/UpdatePrimitivesTask.java

     
    1010import java.util.Collections;
    1111
    1212import javax.swing.SwingUtilities;
     13import org.openstreetmap.josm.Main;
     14import org.openstreetmap.josm.command.DownloadOsmCommand;
    1315
    1416import org.openstreetmap.josm.data.osm.DataSet;
    1517import org.openstreetmap.josm.data.osm.DataSetMerger;
     
    8183        }
    8284        Runnable r = new Runnable() {
    8385            public void run() {
    84                 layer.mergeFrom(ds);
    85                 layer.onPostDownloadFromServer();
     86                Main.main.undoRedo.add(new DownloadOsmCommand(tr("Update primitives"), layer, ds));
    8687            }
    8788        };
    8889
  • src/org/openstreetmap/josm/actions/UpdateSelectionAction.java

     
    1313import javax.swing.JOptionPane;
    1414
    1515import org.openstreetmap.josm.Main;
     16import org.openstreetmap.josm.command.DownloadOsmCommand;
    1617import org.openstreetmap.josm.data.osm.DataSet;
    1718import org.openstreetmap.josm.data.osm.OsmPrimitive;
    1819import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
     
    3940        reader.append(getCurrentDataSet(),id, type);
    4041        try {
    4142            DataSet ds = reader.parseOsm(NullProgressMonitor.INSTANCE);
    42             Main.map.mapView.getEditLayer().mergeFrom(ds);
     43            Main.main.undoRedo.add(new DownloadOsmCommand(tr("Update selected primitives"), Main.map.mapView.getEditLayer(), ds));
    4344        } catch(Exception e) {
    4445            ExceptionDialogUtil.explainException(e);
    4546        }
  • src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTask.java

     
    1010import java.util.regex.Pattern;
    1111
    1212import org.openstreetmap.josm.Main;
     13import org.openstreetmap.josm.actions.AutoScaleAction;
     14import org.openstreetmap.josm.command.DownloadOsmCommand;
    1315import org.openstreetmap.josm.data.Bounds;
    1416import org.openstreetmap.josm.data.coor.LatLon;
    1517import org.openstreetmap.josm.data.osm.DataSet;
     
    207209                if (targetLayer == null) {
    208210                    targetLayer = getFirstDataLayer();
    209211                }
    210                 targetLayer.mergeFrom(dataSet);
    211                 computeBboxAndCenterScale();
    212                 targetLayer.onPostDownloadFromServer();
     212                Main.main.undoRedo.add(new DownloadOsmCommand(tr("Download primitives from bounding box"), targetLayer, dataSet));
     213                AutoScaleAction.zoomTo(dataSet.allPrimitives());
    213214            }
    214215        }
    215216       
  • src/org/openstreetmap/josm/actions/MergeSelectionAction.java

     
    88import java.awt.event.KeyEvent;
    99import java.util.Collection;
    1010import java.util.List;
     11import org.openstreetmap.josm.Main;
     12import org.openstreetmap.josm.command.MergeCommand;
    1113
    1214import org.openstreetmap.josm.data.osm.DataSet;
    1315import org.openstreetmap.josm.data.osm.OsmPrimitive;
    14 import org.openstreetmap.josm.data.osm.visitor.MergeSourceBuildingVisitor;
    1516import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
    1617import org.openstreetmap.josm.gui.layer.Layer;
    1718import org.openstreetmap.josm.gui.layer.OsmDataLayer;
     
    3637        Layer targetLayer = askTargetLayer(targetLayers);
    3738        if (targetLayer == null)
    3839            return;
    39         MergeSourceBuildingVisitor builder = new MergeSourceBuildingVisitor(getEditLayer().data);
    40         ((OsmDataLayer)targetLayer).mergeFrom(builder.build());
     40       
     41        MergeCommand cmd = new MergeCommand((OsmDataLayer)targetLayer, getEditLayer().data, true);
     42        Main.main.undoRedo.add(cmd);
    4143    }
    4244
     45    @Override
    4346    public void actionPerformed(ActionEvent e) {
    4447        if (getEditLayer() == null || getEditLayer().data.getSelected().isEmpty())
    4548            return;
  • src/org/openstreetmap/josm/data/osm/DataSetMerger.java

     
    4343     */
    4444    private final Set<PrimitiveId> objectsWithChildrenToMerge;
    4545    private final Set<OsmPrimitive> objectsToDelete;
     46   
     47    private final Map<OsmPrimitive, PrimitiveData> changedObjectsMap;
     48    private final Set<OsmPrimitive> addedObjects;
     49   
     50    private enum UndoState {
     51        INIT, MERGED, UNDONE, REDONE
     52    }
     53    private UndoState undoState;
    4654
    4755    /**
    4856     * constructor
     
    6169        mergedMap = new HashMap<PrimitiveId, PrimitiveId>();
    6270        objectsWithChildrenToMerge = new HashSet<PrimitiveId>();
    6371        objectsToDelete = new HashSet<OsmPrimitive>();
     72        changedObjectsMap = new HashMap<OsmPrimitive, PrimitiveData>();
     73        addedObjects = new HashSet<OsmPrimitive>();
     74        undoState = UndoState.INIT;
    6475    }
    6576
    6677    /**
     
    7788     * @param <P>  the type of the other primitive
    7889     * @param source  the other primitive
    7990     */
    80     protected void mergePrimitive(OsmPrimitive source, Collection<? extends OsmPrimitive> candidates) {
     91        protected void mergePrimitive(OsmPrimitive source, Collection<? extends OsmPrimitive> candidates) {
    8192        if (!source.isNew() ) {
    8293            // try to merge onto a matching primitive with the same
    8394            // defined id
     
    107118                    target.setTimestamp(source.getTimestamp());
    108119                    target.setModified(source.isModified());
    109120                    objectsWithChildrenToMerge.add(source.getPrimitiveId());
     121                    changedObjectsMap.put(target, source.save());
    110122                    return;
    111123                }
    112124            }
     
    126138        targetDataSet.addPrimitive(target);
    127139        mergedMap.put(source.getPrimitiveId(), target.getPrimitiveId());
    128140        objectsWithChildrenToMerge.add(source.getPrimitiveId());
     141        addedObjects.add(target);
    129142    }
    130143
    131144    protected OsmPrimitive getMergeTarget(OsmPrimitive mergeSource) throws IllegalStateException {
     
    180193                if (referrers.isEmpty()) {
    181194                    target.setDeleted(true);
    182195                    target.mergeFrom(source);
     196                    changedObjectsMap.put(target, source.save());
    183197                    it.remove();
    184198                    flag = true;
    185199                } else {
     
    208222                    ((Relation) osm).setMembers(null);
    209223                }
    210224            }
    211             for (OsmPrimitive osm: objectsToDelete) {
    212                 osm.setDeleted(true);
    213                 osm.mergeFrom(sourceDataSet.getPrimitiveById(osm.getPrimitiveId()));
     225            for (OsmPrimitive target: objectsToDelete) {
     226                OsmPrimitive source = sourceDataSet.getPrimitiveById(target.getPrimitiveId());
     227                target.setDeleted(true);
     228                target.mergeFrom(source);
     229                changedObjectsMap.put(target, source.save());
    214230            }
    215231        }
    216232    }
     
    293309            // => merge source into target
    294310            //
    295311            target.mergeFrom(source);
     312            changedObjectsMap.put(target, source.save());
    296313            objectsWithChildrenToMerge.add(source.getPrimitiveId());
    297314        } else if (!target.isIncomplete() && source.isIncomplete()) {
    298315            // target is complete and source is incomplete
     
    318335                if (targetDataSet.getPrimitiveById(referrer.getPrimitiveId()) == null) {
    319336                    conflicts.add(new Conflict<OsmPrimitive>(target, source, true));
    320337                    target.setDeleted(false);
     338                    changedObjectsMap.put(target, source.save());
    321339                    break;
    322340                }
    323341            }
     
    330348            // target not modified. We can assume that source is the most recent version.
    331349            // clone it into target.
    332350            target.mergeFrom(source);
     351            changedObjectsMap.put(target, source.save());
    333352            objectsWithChildrenToMerge.add(source.getPrimitiveId());
    334353        } else if (! target.isModified() && !source.isModified() && target.getVersion() == source.getVersion()) {
    335354            // both not modified. Merge nevertheless.
    336355            // This helps when updating "empty" relations, see #4295
    337356            target.mergeFrom(source);
     357            changedObjectsMap.put(target, source.save());
    338358            objectsWithChildrenToMerge.add(source.getPrimitiveId());
    339359        } else if (! target.isModified() && !source.isModified() && target.getVersion() < source.getVersion()) {
    340360            // my not modified but other is newer. clone other onto mine.
    341361            //
    342362            target.mergeFrom(source);
     363            changedObjectsMap.put(target, source.save());
    343364            objectsWithChildrenToMerge.add(source.getPrimitiveId());
    344365        } else if (target.isModified() && ! source.isModified() && target.getVersion() == source.getVersion()) {
    345366            // target is same as source but target is modified
    346367            // => keep target and reset modified flag if target and source are semantically equal
    347368            if (target.hasEqualSemanticAttributes(source)) {
    348369                target.setModified(false);
     370                changedObjectsMap.put(target, source.save());
    349371            }
    350372        } else if (source.isDeleted() != target.isDeleted()) {
    351373            // target is modified and deleted state differs.
     
    363385            // attributes should already be equal if we get here.
    364386            //
    365387            target.mergeFrom(source);
     388            changedObjectsMap.put(target, source.save());
    366389            objectsWithChildrenToMerge.add(source.getPrimitiveId());
    367390        }
    368391        return true;
     
    423446        if (progressMonitor != null) {
    424447            progressMonitor.finishTask();
    425448        }
     449       
     450        undoState = UndoState.MERGED;
    426451    }
    427452
    428453    /**
     
    442467    public ConflictCollection getConflicts() {
    443468        return conflicts;
    444469    }
     470   
     471    /**
     472     * Undos the merge operation.
     473     */
     474    public void unmerge() {
     475        if (undoState != UndoState.MERGED && undoState != UndoState.REDONE) {
     476            throw new AssertionError();
     477        }
     478       
     479        targetDataSet.beginUpdate();
     480       
     481        for (PrimitiveId osm : addedObjects) {
     482            targetDataSet.removePrimitive(osm);
     483        }
     484       
     485        for (Map.Entry<OsmPrimitive, PrimitiveData> e : changedObjectsMap.entrySet()) {
     486            // restore previous state and save current state for opposite undo action
     487            PrimitiveData old = e.getKey().save();
     488            e.getKey().load(e.getValue());
     489            e.setValue(old);
     490        }
     491       
     492        targetDataSet.endUpdate();
     493        undoState = UndoState.UNDONE;
     494    }
     495   
     496    /**
     497     * Re-merge objects with dataset. Identical results as {@see #merge()}, but performed
     498     * after {@see #unmerge()} has been called.
     499     */
     500    public void remerge() {
     501        if (undoState != UndoState.UNDONE) {
     502            throw new AssertionError();
     503        }
     504       
     505        targetDataSet.beginUpdate();
     506       
     507        // add back objects in order that they can be referenced by other objects
     508        for (OsmPrimitive osm : OsmPrimitive.getFilteredList(addedObjects, Node.class)) {
     509            targetDataSet.addPrimitive(osm);
     510        }
     511        for (OsmPrimitive osm : OsmPrimitive.getFilteredList(addedObjects, Way.class)) {
     512            targetDataSet.addPrimitive(osm);
     513        }
     514        for (OsmPrimitive osm : OsmPrimitive.getFilteredList(addedObjects, Relation.class)) {
     515            targetDataSet.addPrimitive(osm);
     516        }
     517       
     518        for (Map.Entry<OsmPrimitive, PrimitiveData> e : changedObjectsMap.entrySet()) {
     519            // restore previous state and save current state for opposite undo action
     520            PrimitiveData old = e.getKey().save();
     521            e.getKey().load(e.getValue());
     522            e.setValue(old);
     523        }
     524       
     525        targetDataSet.endUpdate();
     526        undoState = UndoState.REDONE;
     527    }
     528   
     529    public Map<OsmPrimitive, PrimitiveData> getChangedObjectsMap() {
     530        return changedObjectsMap;
     531    }
     532   
     533    public Set<OsmPrimitive> getAddedObjects() {
     534        return addedObjects;
     535    }
    445536}
  • src/org/openstreetmap/josm/command/MergeCommand.java

     
     1// License: GPL. Copyright 2012 by Josh Doe and others
     2package org.openstreetmap.josm.command;
     3
     4import java.awt.geom.Area;
     5import java.util.Collection;
     6import java.util.HashSet;
     7import javax.swing.Icon;
     8import javax.swing.JOptionPane;
     9import org.openstreetmap.josm.Main;
     10import org.openstreetmap.josm.data.conflict.Conflict;
     11import org.openstreetmap.josm.data.osm.*;
     12import org.openstreetmap.josm.data.osm.visitor.MergeSourceBuildingVisitor;
     13import org.openstreetmap.josm.gui.layer.OsmDataLayer;
     14import org.openstreetmap.josm.gui.progress.PleaseWaitProgressMonitor;
     15import org.openstreetmap.josm.tools.CheckParameterUtil;
     16import static org.openstreetmap.josm.tools.I18n.marktr;
     17import static org.openstreetmap.josm.tools.I18n.tr;
     18import org.openstreetmap.josm.tools.ImageProvider;
     19
     20/**
     21 * A command that merges objects from one layer to another.
     22 *
     23 * @author joshdoe
     24 */
     25public class MergeCommand extends Command {
     26
     27    private DataSetMerger merger;
     28    private DataSet sourceDataSet;
     29    private DataSet targetDataSet;
     30    private OsmDataLayer targetLayer;
     31    private Collection<DataSource> addedDataSources;
     32    private String otherVersion;
     33    private Collection<Conflict> addedConflicts;
     34
     35    /**
     36     * Create command to merge all or only currently selected objects from
     37     * sourceDataSet to targetLayer.
     38     *
     39     * @param targetLayer
     40     * @param sourceDataSet
     41     * @param onlySelected true to only merge objects selected in the
     42     * sourceDataSet
     43     */
     44    public MergeCommand(OsmDataLayer targetLayer, DataSet sourceDataSet, boolean onlySelected) {
     45        this(targetLayer, sourceDataSet, onlySelected ? sourceDataSet.getSelected() : null);
     46    }
     47
     48    /**
     49     * Create command to merge the selection from the sourceDataSet to the
     50     * targetLayer.
     51     *
     52     * @param targetLayer
     53     * @param sourceDataSet
     54     * @param selection
     55     */
     56    public MergeCommand(OsmDataLayer targetLayer, DataSet sourceDataSet, Collection<OsmPrimitive> selection) {
     57        super(targetLayer);
     58        CheckParameterUtil.ensureParameterNotNull(targetLayer, "targetLayer");
     59        CheckParameterUtil.ensureParameterNotNull(sourceDataSet, "sourceDataSet");
     60        this.targetLayer = targetLayer;
     61        this.targetDataSet = targetLayer.data;
     62
     63        // if selection present, create new dataset with just selected objects
     64        // and their "hull" (otherwise use entire dataset)
     65        if (selection != null && !selection.isEmpty()) {
     66            Collection<OsmPrimitive> origSelection = sourceDataSet.getSelected();
     67            sourceDataSet.setSelected(selection);
     68            MergeSourceBuildingVisitor builder = new MergeSourceBuildingVisitor(sourceDataSet);
     69            this.sourceDataSet = builder.build();
     70            sourceDataSet.setSelected(origSelection);
     71        } else {
     72            this.sourceDataSet = sourceDataSet;
     73        }
     74       
     75
     76        addedConflicts = new HashSet<Conflict>();
     77        addedDataSources = new HashSet<DataSource>();
     78    }
     79
     80    @Override
     81    public boolean executeCommand() {
     82        PleaseWaitProgressMonitor monitor = new PleaseWaitProgressMonitor(tr("Merging data"));
     83        monitor.setCancelable(false);
     84        if (merger == null) {
     85            //first time command is executed
     86            merger = new DataSetMerger(targetDataSet, sourceDataSet);
     87            try {
     88                merger.merge(monitor);
     89            } catch (DataIntegrityProblemException e) {
     90                JOptionPane.showMessageDialog(
     91                        Main.parent,
     92                        e.getHtmlMessage() != null ? e.getHtmlMessage() : e.getMessage(),
     93                        tr("Error"),
     94                        JOptionPane.ERROR_MESSAGE);
     95                return false;
     96
     97            }
     98
     99            Area a = targetDataSet.getDataSourceArea();
     100
     101            // copy the merged layer's data source info;
     102            // only add source rectangles if they are not contained in the
     103            // layer already.
     104            for (DataSource src : sourceDataSet.dataSources) {
     105                if (a == null || !a.contains(src.bounds.asRect())) {
     106                    targetDataSet.dataSources.add(src);
     107                    addedDataSources.add(src);
     108                }
     109            }
     110
     111            otherVersion = targetDataSet.getVersion();
     112            // copy the merged layer's API version, downgrade if required
     113            if (targetDataSet.getVersion() == null) {
     114                targetDataSet.setVersion(sourceDataSet.getVersion());
     115            } else if ("0.5".equals(targetDataSet.getVersion()) ^ "0.5".equals(sourceDataSet.getVersion())) {
     116                System.err.println(tr("Warning: mixing 0.6 and 0.5 data results in version 0.5"));
     117                targetDataSet.setVersion("0.5");
     118            }
     119
     120
     121            // FIXME: allow conflicts to be retrieved rather than added to layer?
     122            if (targetLayer != null) {
     123                for (Conflict<?> c : merger.getConflicts()) {
     124                    if (!targetLayer.getConflicts().hasConflict(c)) {
     125                        targetLayer.getConflicts().add(c);
     126                        addedConflicts.add(c);
     127                    }
     128                }
     129            }
     130        } else {
     131            // command is being "redone"
     132           
     133            merger.remerge();
     134            targetDataSet.dataSources.addAll(addedDataSources);
     135
     136            String version = otherVersion;
     137            otherVersion = targetDataSet.getVersion();
     138            targetDataSet.setVersion(version);
     139
     140            for (Conflict c : addedConflicts) {
     141                targetLayer.getConflicts().add(c);
     142            }
     143        }
     144       
     145        if (addedConflicts.size() > 0) {
     146            targetLayer.warnNumNewConflicts(addedConflicts.size());
     147        }
     148       
     149        // repaint to make sure new data is displayed properly.
     150        Main.map.mapView.repaint();
     151       
     152        monitor.close();
     153       
     154        return true;
     155    }
     156
     157    @Override
     158    public void undoCommand() {
     159        merger.unmerge();
     160
     161        // restore data source area
     162        targetDataSet.dataSources.removeAll(addedDataSources);
     163
     164        String version = otherVersion;
     165        otherVersion = targetDataSet.getVersion();
     166        targetDataSet.setVersion(version);
     167
     168        for (Conflict c : addedConflicts) {
     169            targetLayer.getConflicts().remove(c);
     170        }
     171
     172        Main.map.mapView.repaint();
     173    }
     174
     175    @Override
     176    public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
     177        throw new UnsupportedOperationException("Not supported yet.");
     178    }
     179
     180    @Override
     181    public String getDescriptionText() {
     182        return tr(marktr("Merged objects: {0} added, {1} modified"),
     183                merger.getAddedObjects().size(),
     184                merger.getChangedObjectsMap().size());
     185    }
     186
     187    @Override
     188    public Icon getDescriptionIcon() {
     189        return ImageProvider.get("dialogs", "mergedown");
     190    }
     191   
     192    @Override
     193    public Collection<? extends OsmPrimitive> getParticipatingPrimitives() {
     194        HashSet<OsmPrimitive> prims = new HashSet<OsmPrimitive>();
     195        prims.addAll(merger.getAddedObjects());
     196        prims.addAll(merger.getChangedObjectsMap().keySet());
     197        return prims;
     198    }
     199}
     200 No newline at end of file