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

Last change on this file since 18823 was 18801, checked in by taylor.smock, 11 months ago

Fix #22832: Code cleanup and some simplification, documentation fixes (patch by gaben)

There should not be any functional changes in this patch; it is intended to do
the following:

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