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