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 * @throws IllegalArgumentException if sanity checks fail 035 */ 036 public ChangeCommand(OsmPrimitive osm, OsmPrimitive newOsm) { 037 this(osm.getDataSet(), osm, newOsm); 038 } 039 040 /** 041 * Constructs a new {@code ChangeCommand} in the context of a given data set. 042 * @param data The data set 043 * @param osm The existing primitive to modify 044 * @param newOsm The new primitive 045 * @throws IllegalArgumentException if sanity checks fail 046 * @since 11240 047 */ 048 public ChangeCommand(DataSet data, OsmPrimitive osm, OsmPrimitive newOsm) { 049 super(data); 050 this.osm = osm; 051 this.newOsm = newOsm; 052 sanityChecks(); 053 } 054 055 private void sanityChecks() { 056 CheckParameterUtil.ensureParameterNotNull(osm, "osm"); 057 CheckParameterUtil.ensureParameterNotNull(newOsm, "newOsm"); 058 if (newOsm instanceof Way && ((Way) newOsm).isEmpty()) { 059 // Do not allow to create empty ways (see #7465) 060 throw new IllegalArgumentException(tr("New way {0} has 0 nodes", newOsm)); 061 } 062 } 063 064 @Override 065 public boolean executeCommand() { 066 super.executeCommand(); 067 osm.cloneFrom(newOsm); 068 osm.setModified(true); 069 return true; 070 } 071 072 @Override 073 public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) { 074 modified.add(osm); 075 } 076 077 @Override 078 public String getDescriptionText() { 079 String msg; 080 switch(OsmPrimitiveType.from(osm)) { 081 case NODE: msg = marktr("Change node {0}"); break; 082 case WAY: msg = marktr("Change way {0}"); break; 083 case RELATION: msg = marktr("Change relation {0}"); break; 084 default: throw new AssertionError(); 085 } 086 return tr(msg, osm.getDisplayName(DefaultNameFormatter.getInstance())); 087 } 088 089 @Override 090 public Icon getDescriptionIcon() { 091 return ImageProvider.get(osm.getDisplayType()); 092 } 093 094 /** 095 * Returns the original OSM primitive to modify. It belongs to a dataset. 096 * @return the original OSM primitive to modify 097 * @since 14283 098 */ 099 public final OsmPrimitive getOsmPrimitive() { 100 return osm; 101 } 102 103 /** 104 * Returns the new OSM primitive. 105 * @return the new OSM primitive 106 * @since 14283 107 */ 108 public final OsmPrimitive getNewOsmPrimitive() { 109 return newOsm; 110 } 111 112 @Override 113 public int hashCode() { 114 return Objects.hash(super.hashCode(), osm, newOsm); 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 ChangeCommand that = (ChangeCommand) obj; 123 return Objects.equals(osm, that.osm) && 124 Objects.equals(newOsm, that.newOsm); 125 } 126}