Ticket #14410: AddPrimitivesCommand-undo-existing.patch

File AddPrimitivesCommand-undo-existing.patch, 7.8 KB (added by Tyndare, 7 years ago)

PATCH

  • josm/core/src/org/openstreetmap/josm/command/AddPrimitivesCommand.java

     
    99import java.util.List;
    1010import java.util.Objects;
    1111import java.util.Optional;
     12import java.util.stream.Collectors;
    1213
    1314import javax.swing.Icon;
    1415
     
    2728 */
    2829public class AddPrimitivesCommand extends Command {
    2930
    30     private List<PrimitiveData> data = new ArrayList<>();
    31     private Collection<PrimitiveData> toSelect = new ArrayList<>();
     31    private List<PrimitiveData> data;
     32    private Collection<PrimitiveData> toSelect;
     33    private List<PrimitiveData> preexistinglData;
    3234
    3335    // only filled on undo
    3436    private List<OsmPrimitive> createdPrimitives;
    35     private Collection<OsmPrimitive> createdPrimitivesToSelect;
    3637
    3738    /**
    3839     * Constructs a new {@code AddPrimitivesCommand} to add data to the current edit layer.
     
    6566
    6667    private void init(List<PrimitiveData> data, List<PrimitiveData> toSelect) {
    6768        CheckParameterUtil.ensureParameterNotNull(data, "data");
    68         this.data.addAll(data);
    69         if (toSelect != null) {
    70             this.toSelect.addAll(toSelect);
     69        this.data = new ArrayList<>(data);
     70        if (toSelect == data) {
     71            this.toSelect = this.data;
     72        } else if (toSelect != null) {
     73            this.toSelect = new ArrayList<>(toSelect);
    7174        }
    7275    }
    7376
    7477    @Override
    7578    public boolean executeCommand() {
    76         Collection<OsmPrimitive> primitivesToSelect;
     79        DataSet ds = getAffectedDataSet();
    7780        if (createdPrimitives == null) { // first time execution
    7881            List<OsmPrimitive> newPrimitives = new ArrayList<>(data.size());
    79             primitivesToSelect = new ArrayList<>(toSelect.size());
     82            preexistinglData = new ArrayList<>();
    8083
    8184            for (PrimitiveData pd : data) {
    82                 OsmPrimitive primitive = getAffectedDataSet().getPrimitiveById(pd);
     85                OsmPrimitive primitive = ds.getPrimitiveById(pd);
    8386                boolean created = primitive == null;
    84                 if (created) {
     87                if (primitive == null) {
    8588                    primitive = pd.getType().newInstance(pd.getUniqueId(), true);
     89                } else {
     90                    preexistinglData.add(primitive.save());
    8691                }
    8792                if (pd instanceof NodeData) { // Load nodes immediately because they can't be added to dataset without coordinates
    8893                    primitive.load(pd);
    8994                }
    9095                if (created) {
    91                     getAffectedDataSet().addPrimitive(primitive);
     96                    ds.addPrimitive(primitive);
    9297                }
    9398                newPrimitives.add(primitive);
    94                 if (toSelect.contains(pd)) {
    95                     primitivesToSelect.add(primitive);
    96                 }
    9799            }
    98100
    99101            // Then load ways and relations
     
    107109            // When redoing this command, we have to add the same objects, otherwise
    108110            // a subsequent command (e.g. MoveCommand) cannot be redone.
    109111            for (OsmPrimitive osm : createdPrimitives) {
    110                 getAffectedDataSet().addPrimitive(osm);
     112                if (preexistinglData.stream().anyMatch(pd -> pd.getUniqueId() == osm.getUniqueId())) {
     113                    osm.load(data.stream().filter(pd -> pd.getUniqueId() == osm.getUniqueId()).findAny().get());
     114                } else {
     115                    ds.addPrimitive(osm);
     116                }
    111117            }
    112             primitivesToSelect = createdPrimitivesToSelect;
    113118        }
    114 
    115         getAffectedDataSet().setSelected(primitivesToSelect);
     119        if (toSelect != null) {
     120            ds.setSelected(toSelect.stream()
     121                    .map(pd -> ds.getPrimitiveById(pd))
     122                    .collect(Collectors.toList()));
     123        }
    116124        return true;
    117125    }
    118126
    119127    @Override public void undoCommand() {
    120128        DataSet ds = getAffectedDataSet();
    121 
    122129        if (createdPrimitives == null) {
    123130            createdPrimitives = new ArrayList<>(data.size());
    124             createdPrimitivesToSelect = new ArrayList<>(toSelect.size());
    125 
    126131            for (PrimitiveData pd : data) {
    127132                OsmPrimitive p = ds.getPrimitiveById(pd);
    128133                createdPrimitives.add(p);
    129                 if (toSelect.contains(pd)) {
    130                     createdPrimitivesToSelect.add(p);
    131                 }
    132134            }
    133135            createdPrimitives = PurgeCommand.topoSort(createdPrimitives);
    134 
    135             for (PrimitiveData p : data) {
    136                 ds.removePrimitive(p);
    137             }
    138             data = null;
    139             toSelect = null;
    140 
    141         } else {
    142             for (OsmPrimitive osm : createdPrimitives) {
     136        }
     137        for (OsmPrimitive osm : createdPrimitives) {
     138            Optional<PrimitiveData> previous = preexistinglData.stream().filter(pd -> pd.getUniqueId() == osm.getUniqueId()).findAny();
     139            if (previous.isPresent()) {
     140                osm.load(previous.get());
     141            } else {
    143142                ds.removePrimitive(osm);
    144143            }
    145144        }
     
    177176
    178177    @Override
    179178    public int hashCode() {
    180         return Objects.hash(super.hashCode(), data, toSelect, createdPrimitives, createdPrimitivesToSelect);
     179        return Objects.hash(super.hashCode(), data, toSelect, preexistinglData, createdPrimitives);
    181180    }
    182181
    183182    @Override
     
    188187        AddPrimitivesCommand that = (AddPrimitivesCommand) obj;
    189188        return Objects.equals(data, that.data) &&
    190189               Objects.equals(toSelect, that.toSelect) &&
    191                Objects.equals(createdPrimitives, that.createdPrimitives) &&
    192                Objects.equals(createdPrimitivesToSelect, that.createdPrimitivesToSelect);
     190               Objects.equals(preexistinglData, that.preexistinglData) &&
     191               Objects.equals(createdPrimitives, that.createdPrimitives);
    193192    }
    194193}
  • josm/core/test/unit/org/openstreetmap/josm/command/AddPrimitivesCommandTest.java

     
    175175    }
    176176
    177177    /**
     178     * Tests if the undo command does not remove
     179     * data ignored by by the add command because they where already existing.
     180     */
     181    @Test
     182    public void testUndoIgnoresExisting() {
     183        OsmDataLayer layer1 = new OsmDataLayer(new DataSet(), "l1", null);
     184        Main.getLayerManager().addLayer(layer1);
     185
     186        List<PrimitiveData> testData = createTestData();
     187
     188        assertTrue(new AddPrimitivesCommand(testData).executeCommand());
     189        assertEquals(2, layer1.data.getNodes().size());
     190        assertEquals(1, layer1.data.getWays().size());
     191
     192        testData.set(2, createTestNode(7));
     193
     194        AddPrimitivesCommand command = new AddPrimitivesCommand(testData);
     195
     196        assertTrue(command.executeCommand());
     197
     198        assertEquals(3, layer1.data.getNodes().size());
     199        assertEquals(1, layer1.data.getWays().size());
     200
     201        for (int i = 0; i < 2; i++) {
     202            // Needs to work multiple times.
     203            command.undoCommand();
     204
     205            assertEquals(2, layer1.data.getNodes().size());
     206            assertEquals(1, layer1.data.getWays().size());
     207
     208            // redo
     209            assertTrue(command.executeCommand());
     210
     211            assertEquals(3, layer1.data.getNodes().size());
     212            assertEquals(1, layer1.data.getWays().size());
     213        }
     214
     215
     216    }
     217
     218    /**
    178219     * Test {@link AddCommand#getParticipatingPrimitives()}
    179220     */
    180221    @Test