001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.command;
003
004import static org.openstreetmap.josm.tools.I18n.marktr;
005import static org.openstreetmap.josm.tools.I18n.tr;
006
007import java.util.Collection;
008import java.util.Collections;
009import java.util.Objects;
010
011import javax.swing.Icon;
012
013import org.openstreetmap.josm.data.osm.DataSet;
014import org.openstreetmap.josm.data.osm.OsmPrimitive;
015import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
016import org.openstreetmap.josm.data.osm.Way;
017import org.openstreetmap.josm.gui.DefaultNameFormatter;
018import org.openstreetmap.josm.gui.layer.OsmDataLayer;
019import org.openstreetmap.josm.tools.ImageProvider;
020
021/**
022 * A command that adds an osm primitive to a dataset. Keys cannot be added this way.
023 *
024 * See {@link ChangeCommand} for comments on relation back references.
025 *
026 * @author imi
027 */
028public class AddCommand extends Command {
029
030    /**
031     * The primitive to add to the dataset.
032     */
033    private final OsmPrimitive osm;
034
035    /**
036     * Creates the command and specify the element to add in the context of the current edit layer, if any.
037     * @param osm The primitive to add
038     */
039    public AddCommand(OsmPrimitive osm) {
040        this.osm = Objects.requireNonNull(osm, "osm");
041    }
042
043    /**
044     * Creates the command and specify the element to add in the context of the given data layer.
045     * @param layer The data layer. Must not be {@code null}
046     * @param osm The primitive to add
047     */
048    public AddCommand(OsmDataLayer layer, OsmPrimitive osm) {
049        super(layer);
050        this.osm = Objects.requireNonNull(osm, "osm");
051    }
052
053    /**
054     * Creates the command and specify the element to add in the context of the given data set.
055     * @param data The data set. Must not be {@code null}
056     * @param osm The primitive to add
057     * @since 11240
058     */
059    public AddCommand(DataSet data, OsmPrimitive osm) {
060        super(data);
061        this.osm = Objects.requireNonNull(osm, "osm");
062    }
063
064    protected static final void checkNodeStyles(OsmPrimitive osm) {
065        if (osm instanceof Way) {
066            // Fix #10557 - node icon not updated after undoing/redoing addition of a way
067            ((Way) osm).clearCachedNodeStyles();
068        }
069    }
070
071    @Override
072    public boolean executeCommand() {
073        getAffectedDataSet().addPrimitive(osm);
074        osm.setModified(true);
075        checkNodeStyles(osm);
076        return true;
077    }
078
079    @Override
080    public void undoCommand() {
081        getAffectedDataSet().removePrimitive(osm);
082        checkNodeStyles(osm);
083    }
084
085    @Override
086    public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
087        added.add(osm);
088    }
089
090    @Override
091    public String getDescriptionText() {
092        String msg;
093        switch(OsmPrimitiveType.from(osm)) {
094        case NODE: msg = marktr("Add node {0}"); break;
095        case WAY: msg = marktr("Add way {0}"); break;
096        case RELATION: msg = marktr("Add relation {0}"); break;
097        default: /* should not happen */msg = ""; break;
098        }
099        return tr(msg, osm.getDisplayName(DefaultNameFormatter.getInstance()));
100    }
101
102    @Override
103    public Icon getDescriptionIcon() {
104        return ImageProvider.get(osm.getDisplayType());
105    }
106
107    @Override
108    public Collection<OsmPrimitive> getParticipatingPrimitives() {
109        return Collections.singleton(osm);
110    }
111
112    @Override
113    public int hashCode() {
114        return Objects.hash(super.hashCode(), osm);
115    }
116
117    @Override
118    public boolean equals(Object obj) {
119        if (this == obj) return true;
120        if (obj == null || getClass() != obj.getClass()) return false;
121        if (!super.equals(obj)) return false;
122        AddCommand that = (AddCommand) obj;
123        return Objects.equals(osm, that.osm);
124    }
125}