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.DefaultNameFormatter;
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 * A command that adds an osm primitive to a dataset. Keys cannot be added this way.
022 *
023 * See {@link ChangeCommand} for comments on relation back references.
024 *
025 * @author imi
026 */
027public class AddCommand extends Command {
028
029    /**
030     * The primitive to add to the dataset.
031     */
032    private final OsmPrimitive osm;
033
034    /**
035     * Creates the command and specify the element to add in the context of the given data set.
036     * @param data The data set. Must not be {@code null}
037     * @param osm The primitive to add
038     * @since 11240
039     */
040    public AddCommand(DataSet data, OsmPrimitive osm) {
041        super(data);
042        this.osm = Objects.requireNonNull(osm, "osm");
043    }
044
045    protected static final void checkNodeStyles(OsmPrimitive osm) {
046        if (osm instanceof Way) {
047            // Fix #10557 - node icon not updated after undoing/redoing addition of a way
048            ((Way) osm).clearCachedNodeStyles();
049        }
050    }
051
052    @Override
053    public boolean executeCommand() {
054        getAffectedDataSet().addPrimitive(osm);
055        osm.setModified(true);
056        checkNodeStyles(osm);
057        return true;
058    }
059
060    @Override
061    public void undoCommand() {
062        getAffectedDataSet().removePrimitive(osm);
063        checkNodeStyles(osm);
064    }
065
066    @Override
067    public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
068        added.add(osm);
069    }
070
071    @Override
072    public String getDescriptionText() {
073        String msg;
074        switch(OsmPrimitiveType.from(osm)) {
075        case NODE: msg = marktr("Add node {0}"); break;
076        case WAY: msg = marktr("Add way {0}"); break;
077        case RELATION: msg = marktr("Add relation {0}"); break;
078        default: /* should not happen */msg = ""; break;
079        }
080        return tr(msg, osm.getDisplayName(DefaultNameFormatter.getInstance()));
081    }
082
083    @Override
084    public Icon getDescriptionIcon() {
085        return ImageProvider.get(osm.getDisplayType());
086    }
087
088    @Override
089    public Collection<OsmPrimitive> getParticipatingPrimitives() {
090        return Collections.singleton(osm);
091    }
092
093    @Override
094    public int hashCode() {
095        return Objects.hash(super.hashCode(), osm);
096    }
097
098    @Override
099    public boolean equals(Object obj) {
100        if (this == obj) return true;
101        if (obj == null || getClass() != obj.getClass()) return false;
102        if (!super.equals(obj)) return false;
103        AddCommand that = (AddCommand) obj;
104        return Objects.equals(osm, that.osm);
105    }
106}