source: josm/trunk/src/org/openstreetmap/josm/data/osm/DataSelectionListener.java@ 13223

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

see #15008, see #15421 - add toString() methods to allow to report potentially incorrect selection events

File size: 10.6 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.osm;
3
4import java.util.Collections;
5import java.util.HashSet;
6import java.util.LinkedHashSet;
7import java.util.Set;
8import java.util.stream.Collectors;
9import java.util.stream.Stream;
10
11import org.openstreetmap.josm.tools.CheckParameterUtil;
12
13/**
14 * This is a listener that listens to selection change events in the data set.
15 * @author Michael Zangl
16 * @since 12048
17 */
18@FunctionalInterface
19public interface DataSelectionListener {
20
21 /**
22 * Called whenever the selection is changed.
23 *
24 * You get notified about the new selection, the elements that were added and removed and the layer that triggered the event.
25 * @param event The selection change event.
26 * @see SelectionChangeEvent
27 */
28 void selectionChanged(SelectionChangeEvent event);
29
30 /**
31 * The event that is fired when the selection changed.
32 * @author Michael Zangl
33 * @since 12048
34 */
35 interface SelectionChangeEvent {
36 /**
37 * Gets the previous selection
38 * <p>
39 * This collection cannot be modified and will not change.
40 * @return The old selection
41 */
42 Set<OsmPrimitive> getOldSelection();
43
44 /**
45 * Gets the new selection. New elements are added to the end of the collection.
46 * <p>
47 * This collection cannot be modified and will not change.
48 * @return The new selection
49 */
50 Set<OsmPrimitive> getSelection();
51
52 /**
53 * Gets the primitives that have been removed from the selection.
54 * <p>
55 * Those are the primitives contained in {@link #getOldSelection()} but not in {@link #getSelection()}
56 * <p>
57 * This collection cannot be modified and will not change.
58 * @return The primitives that were removed
59 */
60 Set<OsmPrimitive> getRemoved();
61
62 /**
63 * Gets the primitives that have been added to the selection.
64 * <p>
65 * Those are the primitives contained in {@link #getSelection()} but not in {@link #getOldSelection()}
66 * <p>
67 * This collection cannot be modified and will not change.
68 * @return The primitives that were added
69 */
70 Set<OsmPrimitive> getAdded();
71
72 /**
73 * Gets the data set that triggered this selection event.
74 * @return The data set.
75 */
76 DataSet getSource();
77
78 /**
79 * Test if this event did not change anything.
80 * <p>
81 * This will return <code>false</code> for all events that are sent to listeners, so you don't need to test it.
82 * @return <code>true</code> if this did not change the selection.
83 */
84 default boolean isNop() {
85 return getAdded().isEmpty() && getRemoved().isEmpty();
86 }
87 }
88
89 /**
90 * The base class for selection events
91 * @author Michael Zangl
92 * @since 12048
93 */
94 abstract class AbstractSelectionEvent implements SelectionChangeEvent {
95 private final DataSet source;
96 private final Set<OsmPrimitive> old;
97
98 public AbstractSelectionEvent(DataSet source, Set<OsmPrimitive> old) {
99 CheckParameterUtil.ensureParameterNotNull(source, "source");
100 CheckParameterUtil.ensureParameterNotNull(old, "old");
101 this.source = source;
102 this.old = Collections.unmodifiableSet(old);
103 }
104
105 @Override
106 public Set<OsmPrimitive> getOldSelection() {
107 return old;
108 }
109
110 @Override
111 public DataSet getSource() {
112 return source;
113 }
114 }
115
116
117 /**
118 * The selection is replaced by a new selection
119 * @author Michael Zangl
120 * @since 12048
121 */
122 class SelectionReplaceEvent extends AbstractSelectionEvent {
123 private final Set<OsmPrimitive> current;
124 private Set<OsmPrimitive> removed;
125 private Set<OsmPrimitive> added;
126
127 /**
128 * Create a {@link SelectionReplaceEvent}
129 * @param source The source dataset
130 * @param old The old primitves that were previously selected. The caller needs to ensure that this set is not modifed.
131 * @param newSelection The primitives of the new selection.
132 */
133 public SelectionReplaceEvent(DataSet source, Set<OsmPrimitive> old, Stream<OsmPrimitive> newSelection) {
134 super(source, old);
135 this.current = newSelection.collect(Collectors.toCollection(LinkedHashSet::new));
136 }
137
138 @Override
139 public Set<OsmPrimitive> getSelection() {
140 return current;
141 }
142
143 @Override
144 public synchronized Set<OsmPrimitive> getRemoved() {
145 if (removed == null) {
146 removed = getOldSelection().stream()
147 .filter(p -> !current.contains(p))
148 .collect(Collectors.toCollection(LinkedHashSet::new));
149 }
150 return removed;
151 }
152
153 @Override
154 public synchronized Set<OsmPrimitive> getAdded() {
155 if (added == null) {
156 added = current.stream()
157 .filter(p -> !getOldSelection().contains(p)).collect(Collectors.toCollection(LinkedHashSet::new));
158 }
159 return added;
160 }
161
162 @Override
163 public String toString() {
164 return "SelectionReplaceEvent [current=" + current + ", removed=" + removed + ", added=" + added + ']';
165 }
166 }
167
168 /**
169 * Primitives are added to the selection
170 * @author Michael Zangl
171 * @since 12048
172 */
173 class SelectionAddEvent extends AbstractSelectionEvent {
174 private final Set<OsmPrimitive> add;
175 private final Set<OsmPrimitive> current;
176
177 /**
178 * Create a {@link SelectionAddEvent}
179 * @param source The source dataset
180 * @param old The old primitves that were previously selected. The caller needs to ensure that this set is not modifed.
181 * @param toAdd The primitives to add.
182 */
183 public SelectionAddEvent(DataSet source, Set<OsmPrimitive> old, Stream<OsmPrimitive> toAdd) {
184 super(source, old);
185 this.add = toAdd
186 .filter(p -> !old.contains(p))
187 .collect(Collectors.toCollection(LinkedHashSet::new));
188 if (this.add.isEmpty()) {
189 this.current = this.getOldSelection();
190 } else {
191 this.current = new LinkedHashSet<>(old);
192 this.current.addAll(add);
193 }
194 }
195
196 @Override
197 public Set<OsmPrimitive> getSelection() {
198 return Collections.unmodifiableSet(current);
199 }
200
201 @Override
202 public Set<OsmPrimitive> getRemoved() {
203 return Collections.emptySet();
204 }
205
206 @Override
207 public Set<OsmPrimitive> getAdded() {
208 return Collections.unmodifiableSet(add);
209 }
210
211 @Override
212 public String toString() {
213 return "SelectionAddEvent [add=" + add + ", current=" + current + ']';
214 }
215 }
216
217 /**
218 * Primitives are removed from the selection
219 * @author Michael Zangl
220 * @since 12048
221 */
222 class SelectionRemoveEvent extends AbstractSelectionEvent {
223 private final Set<OsmPrimitive> remove;
224 private final Set<OsmPrimitive> current;
225
226 /**
227 * Create a {@link SelectionRemoveEvent}
228 * @param source The source dataset
229 * @param old The old primitves that were previously selected. The caller needs to ensure that this set is not modifed.
230 * @param toRemove The primitives to remove.
231 */
232 public SelectionRemoveEvent(DataSet source, Set<OsmPrimitive> old, Stream<OsmPrimitive> toRemove) {
233 super(source, old);
234 this.remove = toRemove
235 .filter(old::contains)
236 .collect(Collectors.toCollection(LinkedHashSet::new));
237 if (this.remove.isEmpty()) {
238 this.current = this.getOldSelection();
239 } else {
240 HashSet<OsmPrimitive> currentSet = new LinkedHashSet<>(old);
241 currentSet.removeAll(remove);
242 current = currentSet;
243 }
244 }
245
246 @Override
247 public Set<OsmPrimitive> getSelection() {
248 return Collections.unmodifiableSet(current);
249 }
250
251 @Override
252 public Set<OsmPrimitive> getRemoved() {
253 return Collections.unmodifiableSet(remove);
254 }
255
256 @Override
257 public Set<OsmPrimitive> getAdded() {
258 return Collections.emptySet();
259 }
260
261 @Override
262 public String toString() {
263 return "SelectionRemoveEvent [remove=" + remove + ", current=" + current + ']';
264 }
265 }
266
267 /**
268 * Toggle the selected state of a primitive
269 * @author Michael Zangl
270 * @since 12048
271 */
272 class SelectionToggleEvent extends AbstractSelectionEvent {
273 private final Set<OsmPrimitive> current;
274 private final Set<OsmPrimitive> remove;
275 private final Set<OsmPrimitive> add;
276
277 /**
278 * Create a {@link SelectionToggleEvent}
279 * @param source The source dataset
280 * @param old The old primitves that were previously selected. The caller needs to ensure that this set is not modifed.
281 * @param toToggle The primitives to toggle.
282 */
283 public SelectionToggleEvent(DataSet source, Set<OsmPrimitive> old, Stream<OsmPrimitive> toToggle) {
284 super(source, old);
285 HashSet<OsmPrimitive> currentSet = new LinkedHashSet<>(old);
286 HashSet<OsmPrimitive> removeSet = new LinkedHashSet<>();
287 HashSet<OsmPrimitive> addSet = new LinkedHashSet<>();
288 toToggle.forEach(p -> {
289 if (currentSet.remove(p)) {
290 removeSet.add(p);
291 } else {
292 addSet.add(p);
293 currentSet.add(p);
294 }
295 });
296 this.current = Collections.unmodifiableSet(currentSet);
297 this.remove = Collections.unmodifiableSet(removeSet);
298 this.add = Collections.unmodifiableSet(addSet);
299 }
300
301 @Override
302 public Set<OsmPrimitive> getSelection() {
303 return Collections.unmodifiableSet(current);
304 }
305
306 @Override
307 public Set<OsmPrimitive> getRemoved() {
308 return Collections.unmodifiableSet(remove);
309 }
310
311 @Override
312 public Set<OsmPrimitive> getAdded() {
313 return Collections.unmodifiableSet(add);
314 }
315
316 @Override
317 public String toString() {
318 return "SelectionToggleEvent [current=" + current + ", remove=" + remove + ", add=" + add + ']';
319 }
320 }
321}
Note: See TracBrowser for help on using the repository browser.