Ticket #18295: split_multipolygon_utilsplugin2_fix_2021-08-02.patch

File split_multipolygon_utilsplugin2_fix_2021-08-02.patch, 6.1 KB (added by Woazboat, 5 years ago)

Fix: prevent mp split with multiple split ways selected + combine into one undo/redo action

  • plugins/utilsplugin2/src/org/openstreetmap/josm/plugins/utilsplugin2/actions/SplitObjectAction.java

     
    276276     * @param allowInvalidSplit allow multipolygon splits that result in invalid multipolygons.
    277277     * @return the new multipolygon relations after splitting + the executed commands
    278278     * (already executed and added to the {@link UndoRedoHandler}).
    279      * Relation and command lists are empty if split did not succeed.
     279     * Returns null if split did not succeed.
    280280     */
    281     public static Pair<List<Relation>, List<Command>> splitMultipolygonAtWayChecked(
     281    public static Pair<List<Relation>, SplitMultipolygonCommand> splitMultipolygonAtWayChecked(
    282282            Relation mpRelation, Way splitWay, boolean allowInvalidSplit) {
    283283
    284284        CheckParameterUtil.ensureParameterNotNull(mpRelation, "mpRelation");
     
    286286        CheckParameterUtil.ensureThat(mpRelation.isMultipolygon(), "mpRelation.isMultipolygon");
    287287
    288288        try {
    289             Pair<List<Relation>, List<Command>> splitResult = splitMultipolygonAtWay(mpRelation, splitWay, allowInvalidSplit);
     289            Pair<List<Relation>, SplitMultipolygonCommand> splitResult = splitMultipolygonAtWay(mpRelation, splitWay, allowInvalidSplit);
    290290            List<Relation> mpRelations = splitResult.a;
    291             List<Command> commands = splitResult.b;
     291            SplitMultipolygonCommand splitCmd = splitResult.b;
    292292
    293293            List<TestError> mpErrorsPostSplit = new ArrayList<>();
    294294            for (Relation mp : mpRelations) {
     
    310310                    for (TestError testError : mpErrorsPostSplit) {
    311311                        showWarningNotification(testError.getMessage());
    312312                    }
    313                     for (int i = commands.size()-1; i >= 0; --i) {
    314                         commands.get(i).undoCommand();
    315                     }
    316313
    317                     return new Pair<>(new ArrayList<>(), new ArrayList<>());
     314                    splitCmd.undoCommand();
     315
     316                    return null;
    318317                } else {
    319318                    showWarningNotification(tr("Multipolygon split created invalid multipolygons! Please review and fix these errors."));
    320319                    for (TestError testError : mpErrorsPostSplit) {
     
    323322                }
    324323            }
    325324
    326             for (Command mpSplitCommand : commands) {
    327                 UndoRedoHandler.getInstance().add(mpSplitCommand, false);
    328             }
     325            UndoRedoHandler.getInstance().add(splitCmd, false);
     326            mpRelation.getDataSet().setSelected(mpRelations);
    329327
    330             mpRelation.getDataSet().setSelected(mpRelations);
    331328            return splitResult;
    332329
    333330        } catch (IllegalArgumentException e) {
    334331            // Changes were already undone in splitMultipolygonAtWay
    335332            showWarningNotification(e.getMessage());
    336             return new Pair<>(new ArrayList<>(), new ArrayList<>());
     333            return null;
    337334        }
    338335    }
    339336
     
    349346     * @throws IllegalArgumentException if the multipolygon has errors and/or the splitWay is unsuitable for
    350347     * splitting the multipolygon (e.g. because it crosses inners and {@code allowInvalidSplit == false}).
    351348     */
    352     public static Pair<List<Relation>, List<Command>> splitMultipolygonAtWay(Relation mpRelation,
     349    public static Pair<List<Relation>, SplitMultipolygonCommand> splitMultipolygonAtWay(Relation mpRelation,
    353350                                                                             Way splitWay,
    354351                                                                             boolean allowInvalidSplit) throws IllegalArgumentException {
    355352        CheckParameterUtil.ensureParameterNotNull(mpRelation, "mpRelation");
     
    498495                mpCreationCommands.add(new ChangeMembersCommand(mpRelation, mpMembers));
    499496                mpCreationCommands.add(new AddCommand(mpRelation.getDataSet(), newMpRelation));
    500497
    501                 SequenceCommand sequenceCommand = new SequenceCommand(mpRelation.getDataSet(), "Split Multipolygon", mpCreationCommands, false);
     498                SequenceCommand sequenceCommand = new SequenceCommand(mpRelation.getDataSet(),
     499                    "Create new multipolygon and assign members", mpCreationCommands, false);
     500                   
    502501                sequenceCommand.executeCommand();
    503502                commands.add(sequenceCommand);
    504503
     
    506505            }
    507506        }
    508507
    509         return new Pair<>(mpRelations, commands);
     508        return new Pair<>(mpRelations, new SplitMultipolygonCommand(commands));
    510509    }
    511510
    512511    /**
     
    568567            } else
    569568                return false;
    570569        }
    571         return (node == 2 || ways == 1 || ways == 2) || //only 2 nodes selected. one split-way selected. split-way + way to split.
    572                (multipolygons == 1 && ways == 1);
     570
     571        // When splitting closed ways: only 2 nodes selected. one split-way selected. split-way + way to split.
     572        // When splitting multipolygons: 1 multipolygon + 1 split way
     573        return ((multipolygons == 0) && (node == 2 || ways == 1 || ways == 2)) ||
     574               ((multipolygons == 1) && (ways == 1));
    573575    }
    574576
    575577    @Override
     
    590592        new Notification(msg)
    591593        .setIcon(JOptionPane.WARNING_MESSAGE).show();
    592594    }
     595
     596    private static class SplitMultipolygonCommand extends SequenceCommand {
     597        SplitMultipolygonCommand(Collection<Command> sequence) {
     598            super(tr("Split multipolygon"), sequence, true);
     599            setSequenceComplete(true); // commands were already executed
     600        }
     601
     602        @Override
     603        public void undoCommand() {
     604            getAffectedDataSet().update(super::undoCommand);
     605        }
     606
     607        @Override
     608        public boolean executeCommand() {
     609            return getAffectedDataSet().update(super::executeCommand);
     610        }
     611    }
    593612}