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; 008 009import javax.swing.Icon; 010 011import org.openstreetmap.josm.data.osm.OsmPrimitive; 012import org.openstreetmap.josm.data.osm.OsmPrimitiveType; 013import org.openstreetmap.josm.data.osm.Way; 014import org.openstreetmap.josm.gui.DefaultNameFormatter; 015import org.openstreetmap.josm.gui.layer.OsmDataLayer; 016import org.openstreetmap.josm.tools.CheckParameterUtil; 017import org.openstreetmap.josm.tools.ImageProvider; 018 019/** 020 * Command that basically replaces one OSM primitive by another of the same type. 021 * 022 * @since 93 023 */ 024public class ChangeCommand extends Command { 025 026 private final OsmPrimitive osm; 027 private final OsmPrimitive newOsm; 028 029 /** 030 * Constructs a new {@code ChangeCommand} in the context of the current edit layer, if any. 031 * @param osm The existing primitive to modify 032 * @param newOsm The new primitive 033 */ 034 public ChangeCommand(OsmPrimitive osm, OsmPrimitive newOsm) { 035 this.osm = osm; 036 this.newOsm = newOsm; 037 sanityChecks(); 038 } 039 040 /** 041 * Constructs a new {@code ChangeCommand} in the context of a given data layer. 042 * @param layer The data layer 043 * @param osm The existing primitive to modify 044 * @param newOsm The new primitive 045 */ 046 public ChangeCommand(OsmDataLayer layer, OsmPrimitive osm, OsmPrimitive newOsm) { 047 super(layer); 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 } 083 return tr(msg, osm.getDisplayName(DefaultNameFormatter.getInstance())); 084 } 085 086 @Override 087 public Icon getDescriptionIcon() { 088 return ImageProvider.get(osm.getDisplayType()); 089 } 090 091 @Override 092 public int hashCode() { 093 final int prime = 31; 094 int result = super.hashCode(); 095 result = prime * result + ((newOsm == null) ? 0 : newOsm.hashCode()); 096 result = prime * result + ((osm == null) ? 0 : osm.hashCode()); 097 return result; 098 } 099 100 @Override 101 public boolean equals(Object obj) { 102 if (this == obj) 103 return true; 104 if (!super.equals(obj)) 105 return false; 106 if (getClass() != obj.getClass()) 107 return false; 108 ChangeCommand other = (ChangeCommand) obj; 109 if (newOsm == null) { 110 if (other.newOsm != null) 111 return false; 112 } else if (!newOsm.equals(other.newOsm)) 113 return false; 114 if (osm == null) { 115 if (other.osm != null) 116 return false; 117 } else if (!osm.equals(other.osm)) 118 return false; 119 return true; 120 } 121}