001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.command; 003 004import static org.openstreetmap.josm.tools.I18n.trn; 005 006import java.util.ArrayList; 007import java.util.Collection; 008import java.util.HashSet; 009import java.util.List; 010 011import javax.swing.Icon; 012 013import org.openstreetmap.josm.data.osm.DataSet; 014import org.openstreetmap.josm.data.osm.Node; 015import org.openstreetmap.josm.data.osm.NodeData; 016import org.openstreetmap.josm.data.osm.OsmPrimitive; 017import org.openstreetmap.josm.data.osm.PrimitiveData; 018import org.openstreetmap.josm.gui.layer.OsmDataLayer; 019import org.openstreetmap.josm.tools.CheckParameterUtil; 020 021/** 022 * Add primitives to a data layer. 023 * @since 2305 024 */ 025public class AddPrimitivesCommand extends Command { 026 027 private List<PrimitiveData> data = new ArrayList<>(); 028 private Collection<PrimitiveData> toSelect = new ArrayList<>(); 029 030 // only filled on undo 031 private List<OsmPrimitive> createdPrimitives; 032 private Collection<OsmPrimitive> createdPrimitivesToSelect; 033 034 /** 035 * Constructs a new {@code AddPrimitivesCommand} to add data to the current edit layer. 036 * @param data The OSM primitives data to add. Must not be {@code null} 037 */ 038 public AddPrimitivesCommand(List<PrimitiveData> data) { 039 this(data, data); 040 } 041 042 /** 043 * Constructs a new {@code AddPrimitivesCommand} to add data to the current edit layer. 044 * @param data The OSM primitives to add. Must not be {@code null} 045 * @param toSelect The OSM primitives to select at the end. Can be {@code null} 046 * @since 5953 047 */ 048 public AddPrimitivesCommand(List<PrimitiveData> data, List<PrimitiveData> toSelect) { 049 init(data, toSelect); 050 } 051 052 /** 053 * Constructs a new {@code AddPrimitivesCommand} to add data to the given layer. 054 * @param data The OSM primitives data to add. Must not be {@code null} 055 * @param toSelect The OSM primitives to select at the end. Can be {@code null} 056 * @param layer The target data layer. Must not be {@code null} 057 */ 058 public AddPrimitivesCommand(List<PrimitiveData> data, List<PrimitiveData> toSelect, OsmDataLayer layer) { 059 super(layer); 060 init(data, toSelect); 061 } 062 063 private void init(List<PrimitiveData> data, List<PrimitiveData> toSelect) { 064 CheckParameterUtil.ensureParameterNotNull(data, "data"); 065 this.data.addAll(data); 066 if (toSelect != null) { 067 this.toSelect.addAll(toSelect); 068 } 069 } 070 071 @Override 072 public boolean executeCommand() { 073 Collection<OsmPrimitive> primitivesToSelect; 074 if (createdPrimitives == null) { // first time execution 075 List<OsmPrimitive> newPrimitives = new ArrayList<>(data.size()); 076 primitivesToSelect = new ArrayList<>(toSelect.size()); 077 078 for (PrimitiveData pd : data) { 079 OsmPrimitive primitive = getLayer().data.getPrimitiveById(pd); 080 boolean created = primitive == null; 081 if (created) { 082 primitive = pd.getType().newInstance(pd.getUniqueId(), true); 083 } 084 if (pd instanceof NodeData) { // Load nodes immediately because they can't be added to dataset without coordinates 085 primitive.load(pd); 086 } 087 if (created) { 088 getLayer().data.addPrimitive(primitive); 089 } 090 newPrimitives.add(primitive); 091 if (toSelect.contains(pd)) { 092 primitivesToSelect.add(primitive); 093 } 094 } 095 096 // Then load ways and relations 097 for (int i = 0; i < newPrimitives.size(); i++) { 098 if (!(newPrimitives.get(i) instanceof Node)) { 099 newPrimitives.get(i).load(data.get(i)); 100 } 101 } 102 } else { // redo 103 // When redoing this command, we have to add the same objects, otherwise 104 // a subsequent command (e.g. MoveCommand) cannot be redone. 105 for (OsmPrimitive osm : createdPrimitives) { 106 getLayer().data.addPrimitive(osm); 107 } 108 primitivesToSelect = createdPrimitivesToSelect; 109 } 110 111 getLayer().data.setSelected(primitivesToSelect); 112 return true; 113 } 114 115 @Override public void undoCommand() { 116 DataSet ds = getLayer().data; 117 118 if (createdPrimitives == null) { 119 createdPrimitives = new ArrayList<>(data.size()); 120 createdPrimitivesToSelect = new ArrayList<>(toSelect.size()); 121 122 for (PrimitiveData pd : data) { 123 OsmPrimitive p = ds.getPrimitiveById(pd); 124 createdPrimitives.add(p); 125 if (toSelect.contains(pd)) { 126 createdPrimitivesToSelect.add(p); 127 } 128 } 129 createdPrimitives = PurgeCommand.topoSort(createdPrimitives); 130 131 for (PrimitiveData p : data) { 132 ds.removePrimitive(p); 133 } 134 data = null; 135 toSelect = null; 136 137 } else { 138 for (OsmPrimitive osm : createdPrimitives) { 139 ds.removePrimitive(osm); 140 } 141 } 142 } 143 144 @Override 145 public String getDescriptionText() { 146 int size = data != null ? data.size() : createdPrimitives.size(); 147 return trn("Added {0} object", "Added {0} objects", size, size); 148 } 149 150 @Override 151 public Icon getDescriptionIcon() { 152 return null; 153 } 154 155 @Override 156 public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, 157 Collection<OsmPrimitive> added) { 158 // Does nothing because we don't want to create OsmPrimitives. 159 } 160 161 @Override 162 public Collection<? extends OsmPrimitive> getParticipatingPrimitives() { 163 if (createdPrimitives != null) 164 return createdPrimitives; 165 166 Collection<OsmPrimitive> prims = new HashSet<>(); 167 for (PrimitiveData d : data) { 168 OsmPrimitive osm = getLayer().data.getPrimitiveById(d); 169 if (osm == null) 170 throw new RuntimeException(); 171 prims.add(osm); 172 } 173 return prims; 174 } 175 176 @Override 177 public int hashCode() { 178 final int prime = 31; 179 int result = super.hashCode(); 180 result = prime * result + ((createdPrimitives == null) ? 0 : createdPrimitives.hashCode()); 181 result = prime * result + ((createdPrimitivesToSelect == null) ? 0 : createdPrimitivesToSelect.hashCode()); 182 result = prime * result + ((data == null) ? 0 : data.hashCode()); 183 result = prime * result + ((toSelect == null) ? 0 : toSelect.hashCode()); 184 return result; 185 } 186 187 @Override 188 public boolean equals(Object obj) { 189 if (this == obj) 190 return true; 191 if (!super.equals(obj)) 192 return false; 193 if (getClass() != obj.getClass()) 194 return false; 195 AddPrimitivesCommand other = (AddPrimitivesCommand) obj; 196 if (createdPrimitives == null) { 197 if (other.createdPrimitives != null) 198 return false; 199 } else if (!createdPrimitives.equals(other.createdPrimitives)) 200 return false; 201 if (createdPrimitivesToSelect == null) { 202 if (other.createdPrimitivesToSelect != null) 203 return false; 204 } else if (!createdPrimitivesToSelect.equals(other.createdPrimitivesToSelect)) 205 return false; 206 if (data == null) { 207 if (other.data != null) 208 return false; 209 } else if (!data.equals(other.data)) 210 return false; 211 if (toSelect == null) { 212 if (other.toSelect != null) 213 return false; 214 } else if (!toSelect.equals(other.toSelect)) 215 return false; 216 return true; 217 } 218}