source: josm/trunk/src/org/openstreetmap/josm/data/conflict/ConflictCollection.java@ 15832

Last change on this file since 15832 was 15832, checked in by simon04, 4 years ago

ConflictCollection: use Java 8 features

  • Property svn:eol-style set to native
File size: 11.0 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.conflict;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.util.ArrayList;
7import java.util.Collection;
8import java.util.Iterator;
9import java.util.List;
10import java.util.Objects;
11import java.util.Set;
12import java.util.concurrent.CopyOnWriteArrayList;
13import java.util.stream.Collectors;
14
15import org.openstreetmap.josm.data.osm.Node;
16import org.openstreetmap.josm.data.osm.OsmPrimitive;
17import org.openstreetmap.josm.data.osm.Relation;
18import org.openstreetmap.josm.data.osm.Way;
19import org.openstreetmap.josm.tools.CheckParameterUtil;
20import org.openstreetmap.josm.tools.SubclassFilteredCollection;
21
22/**
23 * This is a collection of {@link Conflict}s. This collection is {@link Iterable}, i.e.
24 * it can be used in <code>for</code>-loops as follows:
25 * <pre>
26 * ConflictCollection conflictCollection = ....
27 *
28 * for (Conflict c : conflictCollection) {
29 * // do something
30 * }
31 * </pre>
32 *
33 * This collection emits an event when the content of the collection changes. You can register
34 * and unregister for these events using:
35 * <ul>
36 * <li>{@link #addConflictListener(IConflictListener)}</li>
37 * <li>{@link #removeConflictListener(IConflictListener)}</li>
38 * </ul>
39 */
40public class ConflictCollection implements Iterable<Conflict<? extends OsmPrimitive>> {
41 private final List<Conflict<? extends OsmPrimitive>> conflicts;
42 private final CopyOnWriteArrayList<IConflictListener> listeners;
43
44 /**
45 * Constructs a new {@code ConflictCollection}.
46 */
47 public ConflictCollection() {
48 conflicts = new ArrayList<>();
49 listeners = new CopyOnWriteArrayList<>();
50 }
51
52 /**
53 * Adds the specified conflict listener, if not already present.
54 * @param listener The conflict listener to add
55 */
56 public void addConflictListener(IConflictListener listener) {
57 if (listener != null) {
58 listeners.addIfAbsent(listener);
59 }
60 }
61
62 /**
63 * Removes the specified conflict listener.
64 * @param listener The conflict listener to remove
65 */
66 public void removeConflictListener(IConflictListener listener) {
67 listeners.remove(listener);
68 }
69
70 protected void fireConflictAdded() {
71 listeners.forEach(listener -> listener.onConflictsAdded(this));
72 }
73
74 protected void fireConflictRemoved() {
75 listeners.forEach(listener -> listener.onConflictsRemoved(this));
76 }
77
78 /**
79 * Adds a conflict to the collection
80 *
81 * @param conflict the conflict
82 * @throws IllegalStateException if this collection already includes a conflict for conflict.getMy()
83 */
84 protected void addConflict(Conflict<?> conflict) {
85 if (hasConflictForMy(conflict.getMy()))
86 throw new IllegalStateException(tr("Already registered a conflict for primitive ''{0}''.", conflict.getMy().toString()));
87 if (!conflicts.contains(conflict)) {
88 conflicts.add(conflict);
89 }
90 }
91
92 /**
93 * Adds a conflict to the collection of conflicts.
94 *
95 * @param conflict the conflict to add. Must not be null.
96 * @throws IllegalArgumentException if conflict is null
97 * @throws IllegalStateException if this collection already includes a conflict for conflict.getMy()
98 */
99 public void add(Conflict<?> conflict) {
100 CheckParameterUtil.ensureParameterNotNull(conflict, "conflict");
101 addConflict(conflict);
102 fireConflictAdded();
103 }
104
105 /**
106 * Add the conflicts in <code>otherConflicts</code> to this collection of conflicts
107 *
108 * @param otherConflicts the collection of conflicts. Does nothing is conflicts is null.
109 */
110 public void add(Collection<Conflict<?>> otherConflicts) {
111 if (otherConflicts == null) return;
112 otherConflicts.forEach(this::addConflict);
113 fireConflictAdded();
114 }
115
116 /**
117 * Adds a conflict for the pair of {@link OsmPrimitive}s given by <code>my</code> and
118 * <code>their</code>.
119 *
120 * @param my my primitive
121 * @param their their primitive
122 */
123 public void add(OsmPrimitive my, OsmPrimitive their) {
124 addConflict(new Conflict<>(my, their));
125 fireConflictAdded();
126 }
127
128 /**
129 * removes a conflict from this collection
130 *
131 * @param conflict the conflict
132 */
133 public void remove(Conflict<?> conflict) {
134 conflicts.remove(conflict);
135 fireConflictRemoved();
136 }
137
138 /**
139 * removes the conflict registered for {@link OsmPrimitive} <code>my</code> if any
140 *
141 * @param my the primitive
142 * @deprecated use {@link #removeForMy(OsmPrimitive)}
143 */
144 @Deprecated
145 public void remove(OsmPrimitive my) {
146 removeForMy(my);
147 }
148
149 /**
150 * Replies the conflict for the {@link OsmPrimitive} <code>my</code>, null
151 * if no such conflict exists.
152 *
153 * @param my my primitive
154 * @return the conflict for the {@link OsmPrimitive} <code>my</code>, null
155 * if no such conflict exists.
156 */
157 public Conflict<?> getConflictForMy(OsmPrimitive my) {
158 return conflicts.stream()
159 .filter(c -> c.isMatchingMy(my))
160 .findFirst()
161 .orElse(null);
162 }
163
164 /**
165 * Replies the conflict for the {@link OsmPrimitive} <code>their</code>, null
166 * if no such conflict exists.
167 *
168 * @param their their primitive
169 * @return the conflict for the {@link OsmPrimitive} <code>their</code>, null
170 * if no such conflict exists.
171 */
172 public Conflict<?> getConflictForTheir(OsmPrimitive their) {
173 return conflicts.stream()
174 .filter(c -> c.isMatchingTheir(their))
175 .findFirst()
176 .orElse(null);
177 }
178
179 /**
180 * Replies true, if this collection includes a conflict for <code>my</code>.
181 *
182 * @param my my primitive
183 * @return true, if this collection includes a conflict for <code>my</code>; false, otherwise
184 */
185 public boolean hasConflictForMy(OsmPrimitive my) {
186 return getConflictForMy(my) != null;
187 }
188
189 /**
190 * Replies true, if this collection includes a given conflict
191 *
192 * @param c the conflict
193 * @return true, if this collection includes the conflict; false, otherwise
194 */
195 public boolean hasConflict(Conflict<?> c) {
196 return hasConflictForMy(c.getMy());
197 }
198
199 /**
200 * Replies true, if this collection includes a conflict for <code>their</code>.
201 *
202 * @param their their primitive
203 * @return true, if this collection includes a conflict for <code>their</code>; false, otherwise
204 */
205 public boolean hasConflictForTheir(OsmPrimitive their) {
206 return getConflictForTheir(their) != null;
207 }
208
209 /**
210 * Removes any conflicts for the {@link OsmPrimitive} <code>my</code>.
211 *
212 * @param my the primitive
213 */
214 public void removeForMy(OsmPrimitive my) {
215 if (conflicts.removeIf(c -> c.isMatchingMy(my))) {
216 fireConflictRemoved();
217 }
218 }
219
220 /**
221 * Removes any conflicts for the {@link OsmPrimitive} <code>their</code>.
222 *
223 * @param their the primitive
224 */
225 public void removeForTheir(OsmPrimitive their) {
226 if (conflicts.removeIf(c -> c.isMatchingTheir(their))) {
227 fireConflictRemoved();
228 }
229 }
230
231 /**
232 * Replies the conflicts as list.
233 *
234 * @return the list of conflicts
235 */
236 public List<Conflict<?>> get() {
237 return conflicts;
238 }
239
240 /**
241 * Replies the size of the collection
242 *
243 * @return the size of the collection
244 */
245 public int size() {
246 return conflicts.size();
247 }
248
249 /**
250 * Replies the conflict at position <code>idx</code>
251 *
252 * @param idx the index
253 * @return the conflict at position <code>idx</code>
254 */
255 public Conflict<?> get(int idx) {
256 return conflicts.get(idx);
257 }
258
259 /**
260 * Replies the iterator for this collection.
261 *
262 * @return the iterator
263 */
264 @Override
265 public Iterator<Conflict<?>> iterator() {
266 return conflicts.iterator();
267 }
268
269 /**
270 * Adds all conflicts from another collection.
271 * @param other The other collection of conflicts to add
272 */
273 public void add(ConflictCollection other) {
274 other.conflicts.stream()
275 .filter(c -> !hasConflict(c))
276 .forEach(this::add);
277 }
278
279 /**
280 * Replies the set of {@link OsmPrimitive} which participate in the role
281 * of "my" in the conflicts managed by this collection.
282 *
283 * @return the set of {@link OsmPrimitive} which participate in the role
284 * of "my" in the conflicts managed by this collection.
285 */
286 public Set<OsmPrimitive> getMyConflictParties() {
287 return conflicts.stream()
288 .map(Conflict::getMy)
289 .collect(Collectors.toSet());
290 }
291
292 /**
293 * Replies the set of {@link OsmPrimitive} which participate in the role
294 * of "their" in the conflicts managed by this collection.
295 *
296 * @return the set of {@link OsmPrimitive} which participate in the role
297 * of "their" in the conflicts managed by this collection.
298 */
299 public Set<OsmPrimitive> getTheirConflictParties() {
300 return conflicts.stream()
301 .map(Conflict::getTheir)
302 .collect(Collectors.toSet());
303 }
304
305 /**
306 * Replies true if this collection is empty
307 *
308 * @return true, if this collection is empty; false, otherwise
309 */
310 public boolean isEmpty() {
311 return size() == 0;
312 }
313
314 @Override
315 public String toString() {
316 return conflicts.toString();
317 }
318
319 /**
320 * Returns the list of conflicts involving nodes.
321 * @return The list of conflicts involving nodes.
322 * @since 6555
323 */
324 public final Collection<Conflict<? extends OsmPrimitive>> getNodeConflicts() {
325 return SubclassFilteredCollection.filter(conflicts, c -> c != null && c.getMy() instanceof Node);
326 }
327
328 /**
329 * Returns the list of conflicts involving nodes.
330 * @return The list of conflicts involving nodes.
331 * @since 6555
332 */
333 public final Collection<Conflict<? extends OsmPrimitive>> getWayConflicts() {
334 return SubclassFilteredCollection.filter(conflicts, c -> c != null && c.getMy() instanceof Way);
335 }
336
337 /**
338 * Returns the list of conflicts involving nodes.
339 * @return The list of conflicts involving nodes.
340 * @since 6555
341 */
342 public final Collection<Conflict<? extends OsmPrimitive>> getRelationConflicts() {
343 return SubclassFilteredCollection.filter(conflicts, c -> c != null && c.getMy() instanceof Relation);
344 }
345
346 @Override
347 public int hashCode() {
348 return Objects.hash(conflicts, listeners);
349 }
350
351 @Override
352 public boolean equals(Object obj) {
353 if (this == obj) return true;
354 if (obj == null || getClass() != obj.getClass()) return false;
355 ConflictCollection conflicts1 = (ConflictCollection) obj;
356 return Objects.equals(conflicts, conflicts1.conflicts) &&
357 Objects.equals(listeners, conflicts1.listeners);
358 }
359}
Note: See TracBrowser for help on using the repository browser.