Ignore:
Timestamp:
2023-09-18T19:27:57+02:00 (14 months ago)
Author:
taylor.smock
Message:

See #23170: Better behavior around undo/redo, only delete ways with one referrer

Location:
applications/editors/josm/plugins/reltoolbox
Files:
4 added
2 edited

Legend:

Unmodified
Added
Removed
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/ReconstructPolygonAction.java

    r36136 r36142  
    6464        boolean wont = false;
    6565        for (RelationMember m : r.getMembers()) {
    66             if (m.isWay() && m.getWay().getReferrers().size() == 1) {
     66            if (m.isWay()) {
    6767                ways.add(m.getWay());
    6868            } else {
     
    157157            tags.remove("type");
    158158
    159             // then delete ways that are not relevant (do not take part in other relations of have strange tags)
     159            // then delete ways that are not relevant (do not take part in other relations or have strange tags)
    160160            Way candidateWay = null;
    161161            for (Way w : p.ways) {
    162                 if (w.getReferrers().equals(relations)) {
     162                if (w.getReferrers().size() == 1) {
    163163                    // check tags that remain
    164164                    Set<String> keys = new HashSet<>(w.keySet());
     
    192192        // only delete the relation if it hasn't been re-used
    193193        if (!relationReused) {
    194             commands.add(relationDeleteCommand);
     194            // The relation needs to be deleted first, so that undo/redo continue to work properly
     195            commands.add(0, relationDeleteCommand);
    195196        }
    196197
  • applications/editors/josm/plugins/reltoolbox/test/unit/relcontext/actions/ReconstructPolygonActionTest.java

    r36136 r36142  
    55import static org.junit.jupiter.api.Assertions.assertEquals;
    66import static org.junit.jupiter.api.Assertions.assertTrue;
    7 import static org.openstreetmap.josm.tools.I18n.tr;
    87
    9 import java.awt.Component;
    10 import java.util.Arrays;
     8import java.io.IOException;
    119import java.util.Collection;
    12 import java.util.concurrent.atomic.AtomicBoolean;
    13 import java.util.concurrent.atomic.AtomicReference;
    14 import java.util.function.Predicate;
    1510import java.util.stream.Stream;
    16 
    17 import javax.swing.JOptionPane;
    1811
    1912import org.junit.jupiter.api.AfterEach;
     
    2316import org.openstreetmap.josm.actions.DeleteAction;
    2417import org.openstreetmap.josm.command.DeleteCommand;
     18import org.openstreetmap.josm.data.UndoRedoHandler;
    2519import org.openstreetmap.josm.data.osm.DataSet;
    2620import org.openstreetmap.josm.data.osm.DatasetConsistencyTest;
    2721import org.openstreetmap.josm.data.osm.OsmPrimitive;
     22import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
    2823import org.openstreetmap.josm.data.osm.Relation;
    2924import org.openstreetmap.josm.data.osm.RelationMember;
    3025import org.openstreetmap.josm.data.osm.RelationToChildReference;
     26import org.openstreetmap.josm.data.osm.SimplePrimitiveId;
    3127import org.openstreetmap.josm.data.osm.Way;
    3228import org.openstreetmap.josm.gui.MainApplication;
    3329import org.openstreetmap.josm.gui.layer.OsmDataLayer;
     30import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
    3431import org.openstreetmap.josm.gui.util.GuiHelper;
     32import org.openstreetmap.josm.io.IllegalDataException;
     33import org.openstreetmap.josm.io.OsmReader;
    3534import org.openstreetmap.josm.testutils.annotations.Main;
    3635import org.openstreetmap.josm.testutils.annotations.Projection;
    3736
    3837import junit.framework.AssertionFailedError;
    39 import mockit.Mock;
    40 import mockit.MockUp;
    4138import relcontext.ChosenRelation;
    4239
     
    108105        assertEquals(1, keptWay.getNodes().stream().distinct().filter(n -> "3".equals(n.get("name"))).count());
    109106        assertEmpty(DatasetConsistencyTest.runTests(ds));
     107        assertDoesNotThrow(() -> UndoRedoHandler.getInstance().undo());
     108        assertEmpty(DatasetConsistencyTest.runTests(ds));
    110109    }
    111110
     
    115114    @Test
    116115    void testPolygonReconstructComplex() {
    117         final AtomicReference<String> shownMessage = new AtomicReference<>();
    118         new MockUp<JOptionPane>() {
    119             @Mock
    120             void showMessageDialog(Component parentComponent,
    121                                    Object message, String title, int messageType) {
    122                 shownMessage.set((String) message);
    123             }
    124         };
    125116        final Relation otherRelation = TestUtils.newRelation("type=multipolygon landuse=retail",
    126117                new RelationMember("outer", way1),
     
    131122        assertDoesNotThrow(() -> GuiHelper.runInEDTAndWait(() -> action.actionPerformed(null)));
    132123        assertEmpty(DatasetConsistencyTest.runTests(ds));
    133         assertEquals(tr("Multipolygon must consist only of ways with one referring relation"), shownMessage.get());
     124        assertDoesNotThrow(() -> UndoRedoHandler.getInstance().undo());
     125        assertEmpty(DatasetConsistencyTest.runTests(ds));
     126    }
     127
     128    /**
     129     * Ensure that we bail if a way in the relation to be simplified will be deleted from another relation.
     130     */
     131    @Test
     132    void testPolygonReconstructDuplicate() {
     133        final Relation otherRelation = TestUtils.newRelation("type=multipolygon landuse=retail",
     134                new RelationMember("outer", way1),
     135                new RelationMember("outer", way2),
     136                new RelationMember("outer", way3));
     137        ds.addPrimitiveRecursive(otherRelation);
     138        assertDoesNotThrow(() -> GuiHelper.runInEDTAndWait(() -> action.actionPerformed(null)));
     139        assertEmpty(DatasetConsistencyTest.runTests(ds));
     140        assertDoesNotThrow(() -> UndoRedoHandler.getInstance().undo());
     141        assertEmpty(DatasetConsistencyTest.runTests(ds));
     142    }
     143
     144    @Test
     145    void testPolygonReconstructR1585888() throws IOException, IllegalDataException {
     146        ds.clear();
     147        ds.mergeFrom(OsmReader.parseDataSet(TestUtils.getRegressionDataStream(23170, "r1585888.osm"), NullProgressMonitor.INSTANCE));
     148        assertEmpty(DatasetConsistencyTest.runTests(ds));
     149
     150        ds.setSelected(new SimplePrimitiveId(1585888, OsmPrimitiveType.RELATION));
     151        chosenRelation.set((Relation) ds.getPrimitiveById(1585888, OsmPrimitiveType.RELATION));
     152        assertDoesNotThrow(() -> GuiHelper.runInEDTAndWait(() -> action.actionPerformed(null)));
     153        assertEmpty(DatasetConsistencyTest.runTests(ds));
     154
     155        final Collection<Way> selectedWays = ds.getSelectedWays();
     156        assertEquals(selectedWays.size(), ds.getSelected().size());
     157        assertTrue(selectedWays.stream().allMatch(Way::isClosed));
     158        assertTrue(selectedWays.stream().mapToInt(Way::getNodesCount).anyMatch(i -> i == 15));
     159        assertTrue(selectedWays.stream().mapToInt(Way::getNodesCount).anyMatch(i -> i == 23));
     160        assertTrue(selectedWays.stream().mapToInt(Way::getNodesCount).anyMatch(i -> i == 37));
     161        assertTrue(selectedWays.stream().allMatch(way -> "residential".equals(way.get("landuse"))));
     162        assertDoesNotThrow(() -> UndoRedoHandler.getInstance().undo());
     163        assertEmpty(DatasetConsistencyTest.runTests(ds));
    134164    }
    135165
Note: See TracChangeset for help on using the changeset viewer.