Ignore:
Timestamp:
2024-03-03T10:25:25+01:00 (14 months ago)
Author:
GerdP
Message:

fix #23521: fix some memory leaks

  • dispose dialogs
  • either avoid to create clones of ways or relations or use setNodes(null) / setMembers(null)
  • replaces most ChangeCommand instances by better specialized alternatives
  • add some comments
  • fix some checkstyle / sonar issues
Location:
applications/editors/josm/plugins/reltoolbox/src/relcontext/actions
Files:
9 edited

Legend:

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

    r36102 r36217  
    1010
    1111import org.openstreetmap.josm.actions.JosmAction;
    12 import org.openstreetmap.josm.command.ChangeCommand;
     12import org.openstreetmap.josm.command.ChangeMembersCommand;
    1313import org.openstreetmap.josm.command.Command;
    1414import org.openstreetmap.josm.data.UndoRedoHandler;
     
    8282
    8383        if (!r.getMemberPrimitives().equals(rel.get().getMemberPrimitives())) {
    84             UndoRedoHandler.getInstance().add(new ChangeCommand(rel.get(), r));
     84            UndoRedoHandler.getInstance().add(new ChangeMembersCommand(rel.get(), r.getMembers()));
    8585        }
     86        r.setMembers(null); // See #19885
    8687    }
    8788
     
    9697        if (firstNode != null && !firstNode.equals(lastNode)) {
    9798            for (int i = 0; i < r.getMembersCount(); i++) {
    98                 if (r.getMember(i).getType().equals(OsmPrimitiveType.WAY)) {
     99                if (r.getMember(i).getType() == OsmPrimitiveType.WAY) {
    99100                    Way rw = (Way) r.getMember(i).getMember();
    100101                    Node firstNodeR = rw.firstNode();
     
    133134
    134135    protected void updateIcon() {
    135         // todo: change icon based on selection
    136136        final int state; // 0=unknown, 1=add, 2=remove, 3=both
    137137        DataSet ds = getLayerManager().getEditDataSet();
    138         if (ds == null || ds.getSelected() == null
    139                 || ds.getSelected().isEmpty() || rel == null || rel.get() == null) {
     138        if (ds == null || ds.getSelected().isEmpty() || rel == null || rel.get() == null) {
    140139            state = 0;
    141140        } else {
     
    156155            }
    157156        }
    158         GuiHelper.runInEDT(new Runnable() {
    159             @Override
    160             public void run() {
    161                 if (state == 0) {
    162                     putValue(LARGE_ICON_KEY, ImageProvider.get("relcontext", "addremove"));
    163                 } else {
    164                     String iconName = state == 1 ? "add" : state == 2 ? "remove" : "addremove";
    165                     putValue(NAME, null);
    166                     putValue(LARGE_ICON_KEY, ImageProvider.get("relcontext", iconName));
    167                 }
     157        GuiHelper.runInEDT(() -> {
     158            if (state == 0) {
     159                putValue(LARGE_ICON_KEY, ImageProvider.get("relcontext", "addremove"));
     160            } else {
     161                String iconName = state == 1 ? "add" : state == 2 ? "remove" : "addremove";
     162                putValue(NAME, null);
     163                putValue(LARGE_ICON_KEY, ImageProvider.get("relcontext", iconName));
    168164            }
    169165        });
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/ClearChosenRelationAction.java

    r36102 r36217  
    1616
    1717public class ClearChosenRelationAction extends AbstractAction implements ChosenRelationListener {
    18     private final ChosenRelation rel;
     18    private final transient ChosenRelation rel;
    1919
    2020    public ClearChosenRelationAction(ChosenRelation rel) {
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/CreateMultipolygonAction.java

    r36102 r36217  
    77import java.awt.GridBagLayout;
    88import java.awt.event.ActionEvent;
    9 import java.awt.event.ActionListener;
    109import java.awt.event.KeyEvent;
    1110import java.util.ArrayList;
    1211import java.util.Arrays;
    1312import java.util.Collection;
     13import java.util.Collections;
    1414import java.util.HashMap;
    1515import java.util.HashSet;
    1616import java.util.List;
    1717import java.util.Map;
     18import java.util.Map.Entry;
    1819import java.util.Set;
    1920import java.util.TreeSet;
     
    2829import org.openstreetmap.josm.actions.JosmAction;
    2930import org.openstreetmap.josm.command.AddCommand;
    30 import org.openstreetmap.josm.command.ChangeCommand;
    3131import org.openstreetmap.josm.command.ChangePropertyCommand;
    3232import org.openstreetmap.josm.command.Command;
     
    4040import org.openstreetmap.josm.data.osm.Relation;
    4141import org.openstreetmap.josm.data.osm.RelationMember;
     42import org.openstreetmap.josm.data.osm.TagMap;
    4243import org.openstreetmap.josm.data.osm.Way;
    4344import org.openstreetmap.josm.gui.MainApplication;
     
    5657public class CreateMultipolygonAction extends JosmAction {
    5758    private static final String PREF_MULTIPOLY = "reltoolbox.multipolygon.";
    58     protected ChosenRelation chRel;
     59    protected transient ChosenRelation chRel;
    5960
    6061    public CreateMultipolygonAction(ChosenRelation chRel) {
     
    7273    public static boolean getDefaultPropertyValue(String property) {
    7374        switch (property) {
    74             case "boundary":
    75             case "alltags":
    76             case "allowsplit":
    77                 return false;
    78             case "boundaryways":
    79             case "tags":
    80             case "single":
    81                 return true;
     75        case "boundary":
     76        case "alltags":
     77        case "allowsplit":
     78            return false;
     79        case "boundaryways":
     80        case "tags":
     81        case "single":
     82            return true;
    8283        }
    8384        throw new IllegalArgumentException(property);
    8485    }
    8586
    86     private boolean getPref(String property) {
     87    private static boolean getPref(String property) {
    8788        return Config.getPref().getBoolean(PREF_MULTIPOLY + property, getDefaultPropertyValue(property));
    8889    }
     
    9798            if (getPref("allowsplit") || selectedWays.size() == 1) {
    9899                if (SplittingMultipolygons.canProcess(selectedWays)) {
    99                     rels = SplittingMultipolygons.process(ds.getSelectedWays());
     100                    rels = SplittingMultipolygons.process(selectedWays);
    100101                }
    101102            } else {
     
    201202        for (OsmPrimitive p : getLayerManager().getEditDataSet().getSelected()) {
    202203            String role = null;
    203             if (p.getType().equals(OsmPrimitiveType.RELATION)) {
     204            if (p.getType() == OsmPrimitiveType.RELATION) {
    204205                role = "subarea";
    205             } else if (p.getType().equals(OsmPrimitiveType.NODE)) {
     206            } else if (p.getType() == OsmPrimitiveType.NODE) {
    206207                Node n = (Node) p;
    207208                if (!n.isIncomplete()) {
     
    319320        if (isBoundary || !getPref("alltags")) {
    320321            for (RelationMember m : relation.getMembers()) {
    321                 if (m.hasRole() && m.getRole().equals("outer") && m.isWay()) {
     322                if (m.hasRole() && "outer".equals(m.getRole()) && m.isWay()) {
    322323                    for (String key : values.keySet()) {
    323324                        if (!m.getWay().hasKey(key) && !relation.hasKey(key)) {
     
    337338        }
    338339
    339         if (values.containsKey("natural") && values.get("natural").equals("coastline")) {
     340        if ("coastline".equals(values.get("natural"))) {
    340341            values.remove("natural");
    341342        }
     
    356357        boolean moveTags = getPref("tags");
    357358
    358         for (String key : values.keySet()) {
     359        for (Entry<String, String> entry : values.entrySet()) {
     360            String key = entry.getKey();
    359361            List<OsmPrimitive> affectedWays = new ArrayList<>();
    360             String value = values.get(key);
     362            String value = entry.getValue();
    361363
    362364            for (Way way : innerWays) {
     
    375377            }
    376378
    377             if (affectedWays.size() > 0) {
     379            if (!affectedWays.isEmpty()) {
    378380                commands.add(new ChangePropertyCommand(affectedWays, key, null));
    379381            }
     
    386388            }
    387389            boolean fixed = false;
    388             Relation r2 = new Relation(relation);
    389             for (String key : values.keySet()) {
    390                 if (!r2.hasKey(key) && !key.equals("area")
    391                         && (!isBoundary || key.equals("admin_level") || key.equals("name"))) {
    392                     if (relation.isNew()) {
    393                         relation.put(key, values.get(key));
     390            TagMap tags = relation.getKeys();
     391            for (Entry<String, String> e: values.entrySet()) {
     392                final String key = e.getKey();
     393                final String val = e.getValue();
     394                if (!tags.containsKey(key) && !"area".equals(key)
     395                        && (!isBoundary || "admin_level".equals(key) || "name".equals(key))) {
     396                    if (relation.getDataSet() == null) {
     397                        relation.put(key, val);
    394398                    } else {
    395                         r2.put(key, values.get(key));
     399                        tags.put(key, val);
    396400                    }
    397401                    fixed = true;
    398402                }
    399403            }
    400             if (fixed && !relation.isNew()) {
    401                 commands.add(new ChangeCommand(relation, r2));
     404            if (fixed && relation.getDataSet() != null) {
     405                commands.add(new ChangePropertyCommand(Collections.singleton(relation), tags));
    402406            }
    403407        }
     
    444448        dlg.setModalityType(ModalityType.DOCUMENT_MODAL);
    445449
    446         name.addActionListener(new ActionListener() {
    447             @Override
    448             public void actionPerformed(ActionEvent e) {
    449                 dlg.setVisible(false);
    450                 optionPane.setValue(JOptionPane.OK_OPTION);
    451             }
     450        name.addActionListener(e -> {
     451            dlg.setVisible(false);
     452            optionPane.setValue(JOptionPane.OK_OPTION);
    452453        });
    453454
     
    455456
    456457        Object answer = optionPane.getValue();
     458        dlg.dispose();
    457459        if (answer == null || answer == JOptionPane.UNINITIALIZED_VALUE
    458460                || (answer instanceof Integer && (Integer) answer != JOptionPane.OK_OPTION))
    459461            return false;
    460462
    461         String admin_level = admin.getText().trim();
    462         String new_name = name.getText().trim();
    463         if (admin_level.equals("10") || (admin_level.length() == 1 && Character.isDigit(admin_level.charAt(0)))) {
    464             rel.put("admin_level", admin_level);
    465             Config.getPref().put(PREF_MULTIPOLY + "lastadmin", admin_level);
    466         }
    467         if (new_name.length() > 0) {
    468             rel.put("name", new_name);
     463        String adminLevel = admin.getText().trim();
     464        String newName = name.getText().trim();
     465        if ("10".equals(adminLevel) || (adminLevel.length() == 1 && Character.isDigit(adminLevel.charAt(0)))) {
     466            rel.put("admin_level", adminLevel);
     467            Config.getPref().put(PREF_MULTIPOLY + "lastadmin", adminLevel);
     468        }
     469        if (!newName.isEmpty()) {
     470            rel.put("name", newName);
    469471        }
    470472        return true;
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/CreateRelationAction.java

    r36102 r36217  
    127127
    128128        Object answer = optionPane.getValue();
     129        dlg.dispose();
    129130        if (answer == null || answer == JOptionPane.UNINITIALIZED_VALUE
    130131                || (answer instanceof Integer && (Integer) answer != JOptionPane.OK_OPTION))
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/FindRelationAction.java

    r36102 r36217  
    123123
    124124        Object answer = optionPane.getValue();
     125        dlg.dispose();
     126       
    125127        if (answer == null || answer == JOptionPane.UNINITIALIZED_VALUE
    126128                || (answer instanceof Integer && (Integer) answer != JOptionPane.OK_OPTION))
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/ReconstructPolygonAction.java

    r36142 r36217  
    88import java.util.ArrayList;
    99import java.util.Arrays;
     10import java.util.Collection;
    1011import java.util.Collections;
    1112import java.util.HashSet;
     
    1920import org.openstreetmap.josm.command.AddCommand;
    2021import org.openstreetmap.josm.command.ChangeCommand;
     22import org.openstreetmap.josm.command.ChangeMembersCommand;
    2123import org.openstreetmap.josm.command.Command;
    2224import org.openstreetmap.josm.command.DeleteCommand;
     
    4345 */
    4446public class ReconstructPolygonAction extends JosmAction implements ChosenRelationListener {
    45     private final ChosenRelation rel;
     47    private final transient ChosenRelation rel;
    4648
    4749    private static final List<String> IRRELEVANT_KEYS = Arrays.asList("source", "created_by", "note");
    4850
     51    /**
     52     * Reconstruct one or more polygons from multipolygon relation.
     53     * @param rel the multipolygon relation
     54     */
    4955    public ReconstructPolygonAction(ChosenRelation rel) {
    5056        super(tr("Reconstruct polygon"), "dialogs/filter", tr("Reconstruct polygon from multipolygon relation"),
    5157                Shortcut.registerShortcut("reltoolbox:reconstructpoly", tr("Relation Toolbox: {0}",
    5258                        tr("Reconstruct polygon from multipolygon relation")),
    53                         KeyEvent.CHAR_UNDEFINED, Shortcut.NONE), false);
     59                        KeyEvent.CHAR_UNDEFINED, Shortcut.NONE), false, false);
    5460        this.rel = rel;
    5561        rel.addChosenRelationListener(this);
     
    7278        if (wont) {
    7379            JOptionPane.showMessageDialog(MainApplication.getMainFrame(),
    74                     tr("Multipolygon must consist only of ways with one referring relation"),
     80                    tr("Multipolygon must consist only of ways"),
    7581                    tr("Reconstruct polygon"), JOptionPane.ERROR_MESSAGE);
    7682            return;
     
    8591
    8692        rel.clear();
    87         List<OsmPrimitive> newSelection = new ArrayList<>();
    8893        List<Command> commands = new ArrayList<>();
    8994        Command relationDeleteCommand = DeleteCommand.delete(Collections.singleton(r), true, true);
     
    108113                // this ring has inner rings, so we leave a multipolygon in
    109114                // place and don't reconstruct the rings.
     115                List<RelationMember> members = new ArrayList<>();
    110116                Relation n;
     117                for (Way w : p.ways) {
     118                    members.add(new RelationMember("outer", w));
     119                }
     120                for (JoinedPolygon i : myInnerWays) {
     121                    for (Way w : i.ways) {
     122                        members.add(new RelationMember("inner", w));
     123                    }
     124                }
    111125                if (relationReused) {
    112126                    n = new Relation();
    113127                    n.setKeys(r.getKeys());
    114                 } else {
    115                     n = new Relation(r);
    116                     n.setMembers(null);
    117                 }
    118                 for (Way w : p.ways) {
    119                     n.addMember(new RelationMember("outer", w));
    120                 }
    121                 for (JoinedPolygon i : myInnerWays) {
    122                     for (Way w : i.ways) {
    123                         n.addMember(new RelationMember("inner", w));
    124                     }
    125                 }
    126                 if (relationReused) {
     128                    n.setMembers(members);
    127129                    commands.add(new AddCommand(ds, n));
    128130                } else {
    129131                    relationReused = true;
    130                     commands.add(new ChangeCommand(r, n));
    131                 }
    132                 newSelection.add(n);
     132                    commands.add(new ChangeMembersCommand(r, members));
     133                }
    133134                continue;
    134135            }
     
    186187            result.addNode(result.firstNode());
    187188            result.setKeys(tags);
    188             newSelection.add(candidateWay == null ? result : candidateWay);
    189189            commands.add(candidateWay == null ? new AddCommand(ds, result) : new ChangeCommand(candidateWay, result));
    190190        }
     
    195195            commands.add(0, relationDeleteCommand);
    196196        }
    197 
    198197        UndoRedoHandler.getInstance().add(new SequenceCommand(tr("Reconstruct polygons from relation {0}",
    199198                r.getDisplayName(DefaultNameFormatter.getInstance())), commands));
     199        Collection<? extends OsmPrimitive> newSelection = UndoRedoHandler.getInstance().getLastCommand().getParticipatingPrimitives();
     200        newSelection.removeIf(p -> p.isDeleted());
    200201        ds.setSelected(newSelection);
    201202    }
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/ReconstructRouteAction.java

    r36102 r36217  
    1313import javax.swing.AbstractAction;
    1414
    15 import org.openstreetmap.josm.command.ChangeCommand;
    16 import org.openstreetmap.josm.command.Command;
     15import org.openstreetmap.josm.command.ChangeMembersCommand;
    1716import org.openstreetmap.josm.data.UndoRedoHandler;
    1817import org.openstreetmap.josm.data.coor.EastNorth;
     
    3534 */
    3635public class ReconstructRouteAction extends AbstractAction implements ChosenRelationListener {
    37     private final ChosenRelation rel;
    38 
     36    private final transient ChosenRelation rel;
     37
     38    /**
     39     * Reconstruct route relation to scheme of public_transport.
     40     * @param rel chosen relation
     41     */
    3942    public ReconstructRouteAction(ChosenRelation rel) {
    4043        super(tr("Reconstruct route"));
     
    4952    public void actionPerformed(ActionEvent e) {
    5053        Relation r = rel.get();
    51         Relation recRel = new Relation(r);
    52         recRel.removeMembersFor(recRel.getMemberPrimitives());
     54        List<RelationMember> recMembers = new ArrayList<>();
    5355
    5456        Map<OsmPrimitive, RelationMember> stopMembers = new LinkedHashMap<>();
     
    118120                    nIndex += increment) {
    119121                Node refNode = w.getNode(nIndex);
    120                 if (PublicTransportHelper.isNodeStop(refNode)) {
    121                     if (stopMembers.containsKey(refNode)) {
    122                         recRel.addMember(stopMembers.get(refNode));
    123                         stopMembers.remove(refNode);
    124                         String stopName = PublicTransportHelper.getNameViaStoparea(refNode);
    125                         if (stopName == null) {
    126                             stopName = "";
     122                if (!(PublicTransportHelper.isNodeStop(refNode) && stopMembers.containsKey(refNode)))
     123                    continue;
     124                recMembers.add(stopMembers.get(refNode));
     125                stopMembers.remove(refNode);
     126                String stopName = PublicTransportHelper.getNameViaStoparea(refNode);
     127                if (stopName == null) {
     128                    stopName = "";
     129                }
     130                boolean existsPlatform = platformMembers.containsKey(stopName);
     131                if (!existsPlatform) {
     132                    stopName = ""; // find of the nameless
     133                }
     134                if (existsPlatform || platformMembers.containsKey(stopName)) {
     135                    List<RelationMember> lMember = platformMembers.get(stopName);
     136                    if (lMember.size() == 1) {
     137                        recMembers.add(lMember.get(0));
     138                        lMember.remove(0);
     139                    } else {
     140                        // choose closest
     141                        RelationMember candidat = getClosestPlatform(lMember, refNode);
     142                        if (candidat != null) {
     143                            recMembers.add(candidat);
     144                            lMember.remove(candidat);
    127145                        }
    128                         boolean existsPlatform = platformMembers.containsKey(stopName);
    129                         if (!existsPlatform) {
    130                             stopName = ""; // find of the nameless
    131                         }
    132                         if (existsPlatform || platformMembers.containsKey(stopName)) {
    133                             List<RelationMember> lMember = platformMembers.get(stopName);
    134                             if (lMember.size() == 1) {
    135                                 recRel.addMember(lMember.get(0));
    136                                 lMember.remove(0);
    137                             } else {
    138                                 // choose closest
    139                                 RelationMember candidat = getClosestPlatform(lMember, refNode);
    140                                 if (candidat != null) {
    141                                     recRel.addMember(candidat);
    142                                     lMember.remove(candidat);
    143                                 }
    144                             }
    145                             if (lMember.isEmpty()) {
    146                                 platformMembers.remove(stopName);
    147                             }
    148                         }
     146                    }
     147                    if (lMember.isEmpty()) {
     148                        platformMembers.remove(stopName);
    149149                    }
    150150                }
     
    153153
    154154        for (RelationMember stop : stopMembers.values()) {
    155             recRel.addMember(stop);
     155            recMembers.add(stop);
    156156            String stopName = PublicTransportHelper.getNameViaStoparea(stop);
    157157            boolean existsPlatform = platformMembers.containsKey(stopName);
     
    162162                List<RelationMember> lMember = platformMembers.get(stopName);
    163163                if (lMember.size() == 1) {
    164                     recRel.addMember(lMember.get(0));
     164                    recMembers.add(lMember.get(0));
    165165                    lMember.remove(0);
    166166                } else {
     
    168168                    RelationMember candidat = getClosestPlatform(lMember, stop.getNode());
    169169                    if (candidat != null) {
    170                         recRel.addMember(candidat);
     170                        recMembers.add(candidat);
    171171                        lMember.remove(candidat);
    172172                    }
     
    180180        for (List<RelationMember> lPlatforms : platformMembers.values()) {
    181181            for (RelationMember platform : lPlatforms) {
    182                 recRel.addMember(platform);
     182                recMembers.add(platform);
    183183            }
    184184        }
    185185
    186186        for (RelationMember route : routeMembers) {
    187             recRel.addMember(route);
     187            recMembers.add(route);
    188188        }
    189189        for (RelationMember wtf : wtfMembers) {
    190             recRel.addMember(wtf);
    191         }
    192         Command command = new ChangeCommand(r, recRel);
    193         UndoRedoHandler.getInstance().add(command);
     190            recMembers.add(wtf);
     191        }
     192        UndoRedoHandler.getInstance().add(new ChangeMembersCommand(r, recMembers));
    194193    }
    195194
    196195    private static final double maxSqrDistBetweenStopAndPlatform = 2000; // ~ 26m
    197     private RelationMember getClosestPlatform(List<RelationMember> members, Node stop) {
     196   
     197    private static RelationMember getClosestPlatform(List<RelationMember> members, Node stop) {
    198198        if (stop == null || members.isEmpty()) return null;
    199199        double maxDist = maxSqrDistBetweenStopAndPlatform;
     
    229229    }
    230230
    231     private boolean isSuitableRelation(Relation newRelation) {
     231    private static boolean isSuitableRelation(Relation newRelation) {
    232232        return !(newRelation == null || !"route".equals(newRelation.get("type")) || newRelation.getMembersCount() == 0);
    233233    }
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/SplittingMultipolygons.java

    r36102 r36217  
    1212import java.util.List;
    1313import java.util.Map;
     14import java.util.Map.Entry;
    1415import java.util.Objects;
    1516
     
    351352                if (p instanceof Way && !p.equals(ring)) {
    352353                    for (OsmPrimitive r : p.getReferrers()) {
    353                         if (r instanceof Relation && r.hasKey("type") && r.get("type").equals("multipolygon")) {
     354                        if (r instanceof Relation && "multipolygon".equals(r.get("type"))) {
    354355                            if (touchingWays.containsKey(p)) {
    355356                                touchingWays.put((Way) p, Boolean.TRUE);
     
    365366
    366367        List<TheRing> otherWays = new ArrayList<>();
    367         for (Way w : touchingWays.keySet()) {
    368             if (touchingWays.get(w)) {
    369                 otherWays.add(new TheRing(w));
     368        for (Entry<Way, Boolean> e : touchingWays.entrySet()) {
     369            if (Boolean.TRUE.equals(e.getValue())) {
     370                otherWays.add(new TheRing(e.getKey()));
    370371            }
    371372        }
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/TheRing.java

    r36134 r36217  
    1515import org.openstreetmap.josm.command.AddCommand;
    1616import org.openstreetmap.josm.command.ChangeCommand;
     17import org.openstreetmap.josm.command.ChangeMembersCommand;
     18import org.openstreetmap.josm.command.ChangeNodesCommand;
     19import org.openstreetmap.josm.command.ChangePropertyCommand;
    1720import org.openstreetmap.josm.command.Command;
    1821import org.openstreetmap.josm.command.DeleteCommand;
     
    330333    public List<Command> getCommands(boolean createMultipolygon, Map<Relation, Relation> relationChangeMap) {
    331334        Way sourceCopy = new Way(source);
     335        Map<String, String> tagsToRemove = new HashMap<>();
    332336        if (createMultipolygon) {
    333337            Collection<String> linearTags = Config.getPref().getList(PREF_MULTIPOLY + "lineartags",
     
    335339            relation = new Relation();
    336340            relation.put("type", "multipolygon");
    337             for (String key : sourceCopy.keySet()) {
    338                 if (linearTags.contains(key)) {
     341            for (String key : source.keySet()) {
     342                if (linearTags.contains(key)
     343                        || ("natural".equals(key) && "coastline".equals(source.get("natural"))))
    339344                    continue;
    340                 }
    341                 if ("natural".equals(key) && "coastline".equals(sourceCopy.get("natural"))) {
    342                     continue;
    343                 }
    344                 relation.put(key, sourceCopy.get(key));
     345               
     346                relation.put(key, source.get(key));
    345347                sourceCopy.remove(key);
     348                tagsToRemove.put(key, null);
    346349            }
    347350        }
     
    354357                Relation rel;
    355358                if (relationChangeMap != null) {
    356                     if (relationChangeMap.containsKey(p)) {
    357                         rel = relationChangeMap.get(p);
    358                     } else {
     359                    rel = relationChangeMap.get(p);
     360                    if (rel == null) {
    359361                        rel = new Relation((Relation) p);
    360362                        relationChangeMap.put((Relation) p, rel);
     
    362364                } else {
    363365                    rel = new Relation((Relation) p);
    364                     relationCommands.add(new ChangeCommand(p, rel));
     366                    relationCommands.add(new ChangeCommand(p, rel)); // should not happen
    365367                }
    366368                for (int i = 0; i < rel.getMembersCount(); i++) {
     
    384386                if (createMultipolygon || !seg.getWayNodes().equals(source.getNodes())) {
    385387                    sourceCopy.setNodes(seg.getWayNodes());
    386                     commands.add(new ChangeCommand(source, sourceCopy));
     388                    if (!tagsToRemove.isEmpty()) {
     389                        commands.add(new ChangePropertyCommand(Collections.singleton(source), tagsToRemove));
     390                    }
     391                    if (!sourceCopy.getNodes().equals(source.getNodes()))
     392                        commands.add(new ChangeNodesCommand(source, sourceCopy.getNodes()));
    387393                }
    388394                foundOwnWay = true;
     
    398404            }
    399405        }
     406        sourceCopy.setNodes(null); // see #19885
    400407        if (!foundOwnWay) {
    401408            final Command deleteCommand = DeleteCommand.delete(Collections.singleton(source));
     
    413420    public static void updateCommandsWithRelations(List<Command> commands, Map<Relation, Relation> relationCache) {
    414421        for (Map.Entry<Relation, Relation> entry : relationCache.entrySet()) {
    415             commands.add(new ChangeCommand(entry.getKey(), entry.getValue()));
     422            Relation oldRel = entry.getKey();
     423            Relation newRel = entry.getValue();
     424            if (oldRel.getKeys().equals(newRel.getKeys())) {
     425                commands.add(new ChangeMembersCommand(oldRel, newRel.getMembers()));
     426                newRel.setMembers(null); // see #19885
     427            } else {
     428                commands.add(new ChangeCommand(oldRel, newRel)); // should not happen
     429            }
    416430        }
    417431    }
Note: See TracChangeset for help on using the changeset viewer.