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.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.OsmPrimitive; 015import org.openstreetmap.josm.data.osm.OsmPrimitiveType; 016import org.openstreetmap.josm.data.osm.Way; 017import org.openstreetmap.josm.tools.CheckParameterUtil; 018import org.openstreetmap.josm.tools.ImageProvider; 019 020/** 021 * Command that basically replaces one OSM primitive by another of the same type. 022 * 023 * @since 93 024 */ 025public class ChangeCommand extends Command { 026 027 private final OsmPrimitive osm; 028 private final OsmPrimitive newOsm; 029 030 /** 031 * Constructs a new {@code ChangeCommand} in the context of {@code osm} data set. 032 * @param osm The existing primitive to modify. It must belong to a data set 033 * @param newOsm The new primitive 034 */ 035 public ChangeCommand(OsmPrimitive osm, OsmPrimitive newOsm) { 036 this(osm.getDataSet(), osm, newOsm); 037 } 038 039 /** 040 * Constructs a new {@code ChangeCommand} in the context of a given data set. 041 * @param data The data set 042 * @param osm The existing primitive to modify 043 * @param newOsm The new primitive 044 * @since 11240 045 */ 046 public ChangeCommand(DataSet data, OsmPrimitive osm, OsmPrimitive newOsm) { 047 super(data); 048 this.osm = osm; 049 this.newOsm = newOsm; 050 sanityChecks(); 051 } 052 053 private void sanityChecks() { 054 CheckParameterUtil.ensureParameterNotNull(osm, "osm"); 055 CheckParameterUtil.ensureParameterNotNull(newOsm, "newOsm"); 056 if (newOsm instanceof Way && ((Way) newOsm).getNodesCount() == 0) { 057 // Do not allow to create empty ways (see #7465) 058 throw new IllegalArgumentException(tr("New way {0} has 0 nodes", newOsm)); 059 } 060 } 061 062 @Override 063 public boolean executeCommand() { 064 super.executeCommand(); 065 osm.cloneFrom(newOsm); 066 osm.setModified(true); 067 return true; 068 } 069 070 @Override 071 public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) { 072 modified.add(osm); 073 } 074 075 @Override 076 public String getDescriptionText() { 077 String msg; 078 switch(OsmPrimitiveType.from(osm)) { 079 case NODE: msg = marktr("Change node {0}"); break; 080 case WAY: msg = marktr("Change way {0}"); break; 081 case RELATION: msg = marktr("Change relation {0}"); break; 082 default: throw new AssertionError(); 083 } 084 return tr(msg, osm.getDisplayName(DefaultNameFormatter.getInstance())); 085 } 086 087 @Override 088 public Icon getDescriptionIcon() { 089 return ImageProvider.get(osm.getDisplayType()); 090 } 091 092 @Override 093 public int hashCode() { 094 return Objects.hash(super.hashCode(), osm, newOsm); 095 } 096 097 @Override 098 public boolean equals(Object obj) { 099 if (this == obj) return true; 100 if (obj == null || getClass() != obj.getClass()) return false; 101 if (!super.equals(obj)) return false; 102 ChangeCommand that = (ChangeCommand) obj; 103 return Objects.equals(osm, that.osm) && 104 Objects.equals(newOsm, that.newOsm); 105 } 106}