source: josm/trunk/src/org/openstreetmap/josm/command/AddPrimitivesCommand.java@ 12718

Last change on this file since 12718 was 12718, checked in by Don-vip, 7 years ago

see #13036 - see #15229 - see #15182 - make Commands depends only on a DataSet, not a Layer. This removes a lot of GUI dependencies

  • Property svn:eol-style set to native
File size: 7.8 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.command;
3
4import static org.openstreetmap.josm.tools.I18n.trn;
5
6import java.util.ArrayList;
7import java.util.Collection;
8import java.util.HashSet;
9import java.util.List;
10import java.util.Objects;
11import java.util.Optional;
12import java.util.stream.Collectors;
13
14import javax.swing.Icon;
15
16import org.openstreetmap.josm.data.osm.DataSet;
17import org.openstreetmap.josm.data.osm.Node;
18import org.openstreetmap.josm.data.osm.NodeData;
19import org.openstreetmap.josm.data.osm.OsmPrimitive;
20import org.openstreetmap.josm.data.osm.PrimitiveData;
21import org.openstreetmap.josm.gui.layer.OsmDataLayer;
22import org.openstreetmap.josm.tools.CheckParameterUtil;
23import org.openstreetmap.josm.tools.JosmRuntimeException;
24
25/**
26 * Add primitives to a data layer.
27 * @since 2305
28 */
29public class AddPrimitivesCommand extends Command {
30
31 private List<PrimitiveData> data;
32 private Collection<PrimitiveData> toSelect;
33 private List<PrimitiveData> preExistingData;
34
35 // only filled on undo
36 private List<OsmPrimitive> createdPrimitives;
37
38 /**
39 * Constructs a new {@code AddPrimitivesCommand} to add data to the current edit layer.
40 * @param data The OSM primitives data to add. Must not be {@code null}
41 */
42 public AddPrimitivesCommand(List<PrimitiveData> data) {
43 this(data, data);
44 }
45
46 /**
47 * Constructs a new {@code AddPrimitivesCommand} to add data to the current edit layer.
48 * @param data The OSM primitives to add. Must not be {@code null}
49 * @param toSelect The OSM primitives to select at the end. Can be {@code null}
50 * @since 5953
51 */
52 public AddPrimitivesCommand(List<PrimitiveData> data, List<PrimitiveData> toSelect) {
53 init(data, toSelect);
54 }
55
56 /**
57 * Constructs a new {@code AddPrimitivesCommand} to add data to the given layer.
58 * @param data The OSM primitives data to add. Must not be {@code null}
59 * @param toSelect The OSM primitives to select at the end. Can be {@code null}
60 * @param layer The target data layer. Must not be {@code null}
61 * @deprecated to be removed end of 2017. Use {@link #AddPrimitivesCommand(List, List, DataSet)} instead
62 */
63 @Deprecated
64 public AddPrimitivesCommand(List<PrimitiveData> data, List<PrimitiveData> toSelect, OsmDataLayer layer) {
65 super(layer);
66 init(data, toSelect);
67 }
68
69 /**
70 * Constructs a new {@code AddPrimitivesCommand} to add data to the given data set.
71 * @param data The OSM primitives data to add. Must not be {@code null}
72 * @param toSelect The OSM primitives to select at the end. Can be {@code null}
73 * @param ds The target data set. Must not be {@code null}
74 * @since 12718
75 */
76 public AddPrimitivesCommand(List<PrimitiveData> data, List<PrimitiveData> toSelect, DataSet ds) {
77 super(ds);
78 init(data, toSelect);
79 }
80
81 private void init(List<PrimitiveData> data, List<PrimitiveData> toSelect) {
82 CheckParameterUtil.ensureParameterNotNull(data, "data");
83 this.data = new ArrayList<>(data);
84 if (toSelect == data) {
85 this.toSelect = this.data;
86 } else if (toSelect != null) {
87 this.toSelect = new ArrayList<>(toSelect);
88 }
89 }
90
91 @Override
92 public boolean executeCommand() {
93 DataSet ds = getAffectedDataSet();
94 if (createdPrimitives == null) { // first time execution
95 List<OsmPrimitive> newPrimitives = new ArrayList<>(data.size());
96 preExistingData = new ArrayList<>();
97
98 for (PrimitiveData pd : data) {
99 OsmPrimitive primitive = ds.getPrimitiveById(pd);
100 boolean created = primitive == null;
101 if (primitive == null) {
102 primitive = pd.getType().newInstance(pd.getUniqueId(), true);
103 } else {
104 preExistingData.add(primitive.save());
105 }
106 if (pd instanceof NodeData) { // Load nodes immediately because they can't be added to dataset without coordinates
107 primitive.load(pd);
108 }
109 if (created) {
110 ds.addPrimitive(primitive);
111 }
112 newPrimitives.add(primitive);
113 }
114
115 // Then load ways and relations
116 for (int i = 0; i < newPrimitives.size(); i++) {
117 if (!(newPrimitives.get(i) instanceof Node)) {
118 newPrimitives.get(i).load(data.get(i));
119 }
120 }
121 newPrimitives.stream().forEach(p -> p.setModified(true));
122 } else { // redo
123 // When redoing this command, we have to add the same objects, otherwise
124 // a subsequent command (e.g. MoveCommand) cannot be redone.
125 for (OsmPrimitive osm : createdPrimitives) {
126 if (preExistingData.stream().anyMatch(pd -> pd.getUniqueId() == osm.getUniqueId())) {
127 Optional<PrimitiveData> o = data.stream().filter(pd -> pd.getUniqueId() == osm.getUniqueId()).findAny();
128 if (o.isPresent()) {
129 osm.load(o.get());
130 }
131 } else {
132 ds.addPrimitive(osm);
133 }
134 }
135 }
136 if (toSelect != null) {
137 ds.setSelected(toSelect.stream().map(ds::getPrimitiveById).collect(Collectors.toList()));
138 }
139 return true;
140 }
141
142 @Override public void undoCommand() {
143 DataSet ds = getAffectedDataSet();
144 if (createdPrimitives == null) {
145 createdPrimitives = new ArrayList<>(data.size());
146 for (PrimitiveData pd : data) {
147 OsmPrimitive p = ds.getPrimitiveById(pd);
148 createdPrimitives.add(p);
149 }
150 createdPrimitives = PurgeCommand.topoSort(createdPrimitives);
151 }
152 for (OsmPrimitive osm : createdPrimitives) {
153 Optional<PrimitiveData> previous = preExistingData.stream().filter(pd -> pd.getUniqueId() == osm.getUniqueId()).findAny();
154 if (previous.isPresent()) {
155 osm.load(previous.get());
156 } else {
157 ds.removePrimitive(osm);
158 }
159 }
160 }
161
162 @Override
163 public String getDescriptionText() {
164 int size = data != null ? data.size() : createdPrimitives.size();
165 return trn("Added {0} object", "Added {0} objects", size, size);
166 }
167
168 @Override
169 public Icon getDescriptionIcon() {
170 return null;
171 }
172
173 @Override
174 public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted,
175 Collection<OsmPrimitive> added) {
176 // Does nothing because we don't want to create OsmPrimitives.
177 }
178
179 @Override
180 public Collection<? extends OsmPrimitive> getParticipatingPrimitives() {
181 if (createdPrimitives != null)
182 return createdPrimitives;
183
184 Collection<OsmPrimitive> prims = new HashSet<>();
185 for (PrimitiveData d : data) {
186 prims.add(Optional.ofNullable(getAffectedDataSet().getPrimitiveById(d)).orElseThrow(
187 () -> new JosmRuntimeException("No primitive found for " + d)));
188 }
189 return prims;
190 }
191
192 @Override
193 public int hashCode() {
194 return Objects.hash(super.hashCode(), data, toSelect, preExistingData, createdPrimitives);
195 }
196
197 @Override
198 public boolean equals(Object obj) {
199 if (this == obj) return true;
200 if (obj == null || getClass() != obj.getClass()) return false;
201 if (!super.equals(obj)) return false;
202 AddPrimitivesCommand that = (AddPrimitivesCommand) obj;
203 return Objects.equals(data, that.data) &&
204 Objects.equals(toSelect, that.toSelect) &&
205 Objects.equals(preExistingData, that.preExistingData) &&
206 Objects.equals(createdPrimitives, that.createdPrimitives);
207 }
208}
Note: See TracBrowser for help on using the repository browser.