001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.command;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.util.Collection;
007import java.util.List;
008import java.util.Objects;
009
010import javax.swing.Icon;
011
012import org.openstreetmap.josm.data.osm.DataSet;
013import org.openstreetmap.josm.data.osm.DefaultNameFormatter;
014import org.openstreetmap.josm.data.osm.Node;
015import org.openstreetmap.josm.data.osm.OsmPrimitive;
016import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
017import org.openstreetmap.josm.data.osm.Way;
018import org.openstreetmap.josm.tools.ImageProvider;
019
020/**
021 * Command that changes the nodes list of a way.
022 * The same can be done with ChangeCommand, but this is more
023 * efficient. (Needed for the duplicate node fixing
024 * tool of the validator plugin, when processing large data sets.)
025 *
026 * @author Imi
027 */
028public class ChangeNodesCommand extends Command {
029
030    private final Way way;
031    private final List<Node> newNodes;
032
033    /**
034     * Constructs a new {@code ChangeNodesCommand}.
035     * @param way The way to modify
036     * @param newNodes The new list of nodes for the given way
037     */
038    public ChangeNodesCommand(Way way, List<Node> newNodes) {
039        this(way.getDataSet(), way, newNodes);
040    }
041
042    /**
043     * Constructs a new {@code ChangeNodesCommand}.
044     * @param ds The target data set. Must not be {@code null}
045     * @param way The way to modify
046     * @param newNodes The new list of nodes for the given way
047     * @since 12726
048     */
049    public ChangeNodesCommand(DataSet ds, Way way, List<Node> newNodes) {
050        super(ds);
051        this.way = way;
052        this.newNodes = newNodes;
053        if (newNodes.isEmpty()) {
054            throw new IllegalArgumentException("Cannot set nodes to be an empty list.");
055        }
056    }
057
058    @Override
059    public boolean executeCommand() {
060        super.executeCommand();
061        way.setNodes(newNodes);
062        way.setModified(true);
063        return true;
064    }
065
066    @Override
067    public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
068        modified.add(way);
069    }
070
071    @Override
072    public String getDescriptionText() {
073        return tr("Change nodes of {0}", way.getDisplayName(DefaultNameFormatter.getInstance()));
074    }
075
076    @Override
077    public Icon getDescriptionIcon() {
078        return ImageProvider.get(OsmPrimitiveType.WAY);
079    }
080
081    @Override
082    public int hashCode() {
083        return Objects.hash(super.hashCode(), way, newNodes);
084    }
085
086    @Override
087    public boolean equals(Object obj) {
088        if (this == obj) return true;
089        if (obj == null || getClass() != obj.getClass()) return false;
090        if (!super.equals(obj)) return false;
091        ChangeNodesCommand that = (ChangeNodesCommand) obj;
092        return Objects.equals(way, that.way) &&
093                Objects.equals(newNodes, that.newNodes);
094    }
095}