Ticket #13467: patch-dataset-selection-listener.patch
| File patch-dataset-selection-listener.patch, 28.9 KB (added by , 10 years ago) |
|---|
-
new file src/org/openstreetmap/josm/data/osm/DataSelectionListener.java
diff --git a/src/org/openstreetmap/josm/data/osm/DataSelectionListener.java b/src/org/openstreetmap/josm/data/osm/DataSelectionListener.java new file mode 100644 index 0000000..475d9e8
- + 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.data.osm; 3 4 import java.util.Collections; 5 import java.util.HashSet; 6 import java.util.Set; 7 import java.util.stream.Collectors; 8 import java.util.stream.Stream; 9 10 import org.openstreetmap.josm.tools.CheckParameterUtil; 11 12 /** 13 * This is a listener that listens to selection change events in the data set. 14 * @author Michael Zangl 15 * @since xxx 16 */ 17 @FunctionalInterface 18 public interface DataSelectionListener { 19 20 /** 21 * Called whenever the selection is changed. 22 * @param e The selection change event. 23 */ 24 void selectionChanged(SelectionChangeEvent e); 25 26 /** 27 * The event that is fired when the selection changed. 28 * @author Michael Zangl 29 * @since xxx 30 */ 31 public static interface SelectionChangeEvent { 32 /** 33 * Gets the previous selection 34 * <p> 35 * This collection cannot be modified and will not change. 36 * @return The old selection 37 */ 38 public Set<OsmPrimitive> getOldSelection(); 39 40 /** 41 * Gets the new selection 42 * <p> 43 * This collection cannot be modified and will not change. 44 * @return The new selection 45 */ 46 public Set<OsmPrimitive> getSelection(); 47 48 /** 49 * Gets the primitives that have been removed from the selection. 50 * <p> 51 * Those are the primitives contained in {@link #getOldSelection()} but not in {@link #getSelection()} 52 * <p> 53 * This collection cannot be modified and will not change. 54 * @return The primitives 55 */ 56 public Set<OsmPrimitive> getRemoved(); 57 58 /** 59 * Gets the primitives that have been added to the selection. 60 * <p> 61 * Those are the primitives contained in {@link #getSelection()} but not in {@link #getOldSelection()} 62 * <p> 63 * This collection cannot be modified and will not change. 64 * @return The primitives 65 */ 66 public Set<OsmPrimitive> getAdded(); 67 68 /** 69 * Gets the data set that triggered this selection event. 70 * @return The data set. 71 */ 72 public DataSet getSource(); 73 74 /** 75 * Test if this event did not change anything. 76 * <p> 77 * Should return true for all events that are fired. 78 * @return <code>true</code> if this did not change the selection. 79 */ 80 default boolean isNop() { 81 return getAdded().isEmpty() && getRemoved().isEmpty(); 82 } 83 } 84 85 /** 86 * The base class for selection events 87 * @author Michael Zangl 88 * @since xxx 89 */ 90 abstract static class AbstractSelectionEvent implements SelectionChangeEvent { 91 private final DataSet source; 92 private final Set<OsmPrimitive> old; 93 94 public AbstractSelectionEvent(DataSet source, Set<OsmPrimitive> old) { 95 CheckParameterUtil.ensureParameterNotNull(source, "source"); 96 CheckParameterUtil.ensureParameterNotNull(old, "old"); 97 this.source = source; 98 this.old = Collections.unmodifiableSet(old); 99 } 100 101 @Override 102 public Set<OsmPrimitive> getOldSelection() { 103 return old; 104 } 105 106 @Override 107 public DataSet getSource() { 108 return source; 109 } 110 } 111 112 113 /** 114 * The selection is replaced by a new selection 115 * @author Michael Zangl 116 * @since xxx 117 */ 118 public static class SelectionReplaceEvent extends AbstractSelectionEvent { 119 private final Set<OsmPrimitive> current; 120 private Set<OsmPrimitive> removed; 121 private Set<OsmPrimitive> added; 122 123 /** 124 * Create a {@link SelectionReplaceEvent} 125 * @param source The source dataset 126 * @param old The old primitves that were previously selected. The caller needs to ensure that this set is not modifed. 127 * @param newSelection The primitives of the new selection. 128 */ 129 public SelectionReplaceEvent(DataSet source, Set<OsmPrimitive> old, Stream<OsmPrimitive> newSelection) { 130 super(source, old); 131 this.current = newSelection.collect(Collectors.toSet()); 132 133 } 134 135 @Override 136 public Set<OsmPrimitive> getSelection() { 137 return current; 138 } 139 140 @Override 141 public synchronized Set<OsmPrimitive> getRemoved() { 142 if (removed == null) { 143 removed = getOldSelection().stream().filter(p -> !current.contains(p)).collect(Collectors.toSet()); 144 } 145 return removed; 146 } 147 148 @Override 149 public synchronized Set<OsmPrimitive> getAdded() { 150 if (added == null) { 151 added = current.stream().filter(p -> !getOldSelection().contains(p)).collect(Collectors.toSet()); 152 } 153 return added; 154 } 155 } 156 157 /** 158 * Primitives are added to the selection 159 * @author Michael Zangl 160 * @since xxx 161 */ 162 public static class SelectionAddEvent extends AbstractSelectionEvent { 163 private final Set<OsmPrimitive> add; 164 private final Set<OsmPrimitive> current; 165 166 /** 167 * Create a {@link SelectionAddEvent} 168 * @param source The source dataset 169 * @param old The old primitves that were previously selected. The caller needs to ensure that this set is not modifed. 170 * @param toAdd The primitives to add. 171 */ 172 public SelectionAddEvent(DataSet source, Set<OsmPrimitive> old, Stream<OsmPrimitive> toAdd) { 173 super(source, old); 174 this.add = toAdd.filter(p -> !old.contains(p)).collect(Collectors.toSet()); 175 if (this.add.isEmpty()) { 176 this.current = this.getOldSelection(); 177 } else { 178 this.current = new HashSet<>(old); 179 this.current.addAll(add); 180 } 181 } 182 183 @Override 184 public Set<OsmPrimitive> getSelection() { 185 return current; 186 } 187 188 @Override 189 public Set<OsmPrimitive> getRemoved() { 190 return Collections.emptySet(); 191 } 192 193 @Override 194 public Set<OsmPrimitive> getAdded() { 195 return add; 196 } 197 } 198 199 /** 200 * Primitives are removed from the selection 201 * @author Michael Zangl 202 * @since xxx 203 */ 204 public static class SelectionRemoveEvent extends AbstractSelectionEvent { 205 private final Set<OsmPrimitive> remove; 206 private final Set<OsmPrimitive> current; 207 208 /** 209 * Create a {@link SelectionRemoveEvent} 210 * @param source The source dataset 211 * @param old The old primitves that were previously selected. The caller needs to ensure that this set is not modifed. 212 * @param toRemove The primitives to remove. 213 */ 214 public SelectionRemoveEvent(DataSet source, Set<OsmPrimitive> old, Stream<OsmPrimitive> toRemove) { 215 super(source, old); 216 this.remove = toRemove.filter(old::contains).collect(Collectors.toSet()); 217 if (this.remove.isEmpty()) { 218 this.current = this.getOldSelection(); 219 } else { 220 HashSet<OsmPrimitive> currentSet = new HashSet<>(old); 221 currentSet.removeAll(remove); 222 current = Collections.unmodifiableSet(currentSet); 223 } 224 } 225 226 @Override 227 public Set<OsmPrimitive> getSelection() { 228 return current; 229 } 230 231 @Override 232 public Set<OsmPrimitive> getRemoved() { 233 return remove; 234 } 235 236 @Override 237 public Set<OsmPrimitive> getAdded() { 238 return Collections.emptySet(); 239 } 240 } 241 242 /** 243 * Toggle the selected state of a primitive 244 * @author Michael Zangl 245 * @since xxx 246 */ 247 public static class SelectionToggleEvent extends AbstractSelectionEvent { 248 private final Set<OsmPrimitive> current; 249 private final Set<OsmPrimitive> remove; 250 private final Set<OsmPrimitive> add; 251 252 /** 253 * Create a {@link SelectionToggleEvent} 254 * @param source The source dataset 255 * @param old The old primitves that were previously selected. The caller needs to ensure that this set is not modifed. 256 * @param toToggle The primitives to toggle. 257 */ 258 public SelectionToggleEvent(DataSet source, Set<OsmPrimitive> old, Stream<OsmPrimitive> toToggle) { 259 super(source, old); 260 HashSet<OsmPrimitive> currentSet = new HashSet<>(old); 261 HashSet<OsmPrimitive> removeSet = new HashSet<>(); 262 HashSet<OsmPrimitive> addSet = new HashSet<>(); 263 toToggle.forEach(p -> { 264 if (currentSet.remove(p)) { 265 removeSet.add(p); 266 } else { 267 addSet.add(p); 268 currentSet.add(p); 269 } 270 }); 271 this.current = Collections.unmodifiableSet(currentSet); 272 this.remove = Collections.unmodifiableSet(removeSet); 273 this.add = Collections.unmodifiableSet(addSet); 274 } 275 276 @Override 277 public Set<OsmPrimitive> getSelection() { 278 return current; 279 } 280 281 @Override 282 public Set<OsmPrimitive> getRemoved() { 283 return remove; 284 } 285 286 @Override 287 public Set<OsmPrimitive> getAdded() { 288 return add; 289 } 290 } 291 } -
src/org/openstreetmap/josm/data/osm/DataSet.java
diff --git a/src/org/openstreetmap/josm/data/osm/DataSet.java b/src/org/openstreetmap/josm/data/osm/DataSet.java index ae31a3a..5b30af9 100644
a b import static org.openstreetmap.josm.tools.I18n.tr; 5 5 6 6 import java.awt.geom.Area; 7 7 import java.util.ArrayList; 8 import java.util.Arrays;9 8 import java.util.Collection; 10 9 import java.util.Collections; 11 10 import java.util.HashMap; 12 11 import java.util.HashSet; 13 12 import java.util.Iterator; 14 import java.util.LinkedHashSet;15 13 import java.util.LinkedList; 16 14 import java.util.List; 17 15 import java.util.Map; 16 import java.util.Objects; 18 17 import java.util.Set; 19 18 import java.util.concurrent.CopyOnWriteArrayList; 20 19 import java.util.concurrent.locks.Lock; 21 20 import java.util.concurrent.locks.ReadWriteLock; 22 21 import java.util.concurrent.locks.ReentrantReadWriteLock; 22 import java.util.function.Function; 23 23 import java.util.function.Predicate; 24 import java.util.stream.Stream; 24 25 25 26 import org.openstreetmap.josm.Main; 26 27 import org.openstreetmap.josm.data.Bounds; … … import org.openstreetmap.josm.data.ProjectionBounds; 30 31 import org.openstreetmap.josm.data.SelectionChangedListener; 31 32 import org.openstreetmap.josm.data.coor.EastNorth; 32 33 import org.openstreetmap.josm.data.coor.LatLon; 34 import org.openstreetmap.josm.data.osm.DataSelectionListener.SelectionAddEvent; 35 import org.openstreetmap.josm.data.osm.DataSelectionListener.SelectionChangeEvent; 36 import org.openstreetmap.josm.data.osm.DataSelectionListener.SelectionRemoveEvent; 37 import org.openstreetmap.josm.data.osm.DataSelectionListener.SelectionReplaceEvent; 38 import org.openstreetmap.josm.data.osm.DataSelectionListener.SelectionToggleEvent; 33 39 import org.openstreetmap.josm.data.osm.event.AbstractDatasetChangedEvent; 34 40 import org.openstreetmap.josm.data.osm.event.ChangesetIdChangedEvent; 35 41 import org.openstreetmap.josm.data.osm.event.DataChangedEvent; … … import org.openstreetmap.josm.data.projection.Projection; 46 52 import org.openstreetmap.josm.data.projection.ProjectionChangeListener; 47 53 import org.openstreetmap.josm.gui.progress.ProgressMonitor; 48 54 import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionManager; 55 import org.openstreetmap.josm.tools.ListenerList; 49 56 import org.openstreetmap.josm.tools.SubclassFilteredCollection; 50 57 import org.openstreetmap.josm.tools.Utils; 51 58 … … public final class DataSet implements Data, Cloneable, ProjectionChangeListener 124 131 125 132 private final ReadWriteLock lock = new ReentrantReadWriteLock(); 126 133 private final Object selectionLock = new Object(); 134 private Set<OsmPrimitive> currentSelectedPrimitives = new HashSet<>(); 135 136 private final ListenerList<DataSelectionListener> selectionListeners = ListenerList.create(); 127 137 128 138 /** 129 139 * Constructs a new {@code DataSet}. … … public final class DataSet implements Data, Cloneable, ProjectionChangeListener 132 142 // Transparently register as projection change listener. No need to explicitly remove 133 143 // the listener, projection change listeners are managed as WeakReferences. 134 144 Main.addProjectionChangeListener(this); 145 addSelectionListener((DataSelectionListener) e -> fireDreprecatedSelectionChange(e.getSelection())); 135 146 } 136 147 137 148 /** … … public final class DataSet implements Data, Cloneable, ProjectionChangeListener 552 563 } 553 564 if (!success) 554 565 throw new RuntimeException("failed to remove primitive: "+primitive); 555 synchronized (selectionLock) { 556 selectedPrimitives.remove(primitive); 557 selectionSnapshot = null; 558 } 566 clearSelection(primitiveId); 559 567 allPrimitives.remove(primitive); 560 568 primitive.setDataset(null); 561 569 firePrimitivesRemoved(Collections.singletonList(primitive), false); … … public final class DataSet implements Data, Cloneable, ProjectionChangeListener 569 577 *---------------------------------------------------*/ 570 578 571 579 /** 580 * Add a listener that listens to selection changes in this specific data set. 581 * @param listener The listener. 582 * @see #removeSelectionListener(DataSelectionListener) 583 */ 584 public void addSelectionListener(DataSelectionListener listener) { 585 selectionListeners.addListener(listener); 586 } 587 588 /** 589 * Remove a listener that listens to selection changes in this specific data set. 590 * @param listener The listener. 591 * @see #addSelectionListener(DataSelectionListener) 592 */ 593 public void removeSelectionListener(DataSelectionListener listener) { 594 selectionListeners.removeListener(listener); 595 } 596 597 /*--------------------------------------------------- 598 * OLD SELECTION HANDLING 599 *---------------------------------------------------*/ 600 601 /** 572 602 * A list of listeners to selection changed events. The list is static, as listeners register 573 603 * themselves for any dataset selection changes that occur, regardless of the current active 574 604 * dataset. (However, the selection does only change in the active layer) … … public final class DataSet implements Data, Cloneable, ProjectionChangeListener 594 624 /** 595 625 * Notifies all registered {@link SelectionChangedListener} about the current selection in 596 626 * this dataset. 597 * 627 * @deprecated You should never need to do this from the outside. 598 628 */ 629 @Deprecated 599 630 public void fireSelectionChanged() { 600 Collection<? extends OsmPrimitive> currentSelection = getAllSelected(); 631 fireDreprecatedSelectionChange(getAllSelected()); 632 } 633 634 private static void fireDreprecatedSelectionChange(Collection<? extends OsmPrimitive> currentSelection) { 601 635 for (SelectionChangedListener l : selListeners) { 602 636 l.selectionChanged(currentSelection); 603 637 } 604 638 } 605 639 606 private Set<OsmPrimitive> selectedPrimitives = new LinkedHashSet<>();607 private Collection<OsmPrimitive> selectionSnapshot;608 609 640 /** 610 641 * Returns selected nodes and ways. 611 642 * @return selected nodes and ways … … public final class DataSet implements Data, Cloneable, ProjectionChangeListener 651 682 * @return unmodifiable collection of primitives 652 683 */ 653 684 public Collection<OsmPrimitive> getAllSelected() { 654 Collection<OsmPrimitive> currentList; 655 synchronized (selectionLock) { 656 if (selectionSnapshot == null) { 657 selectionSnapshot = Collections.unmodifiableList(new ArrayList<>(selectedPrimitives)); 658 } 659 currentList = selectionSnapshot; 660 } 661 return currentList; 685 return currentSelectedPrimitives; 662 686 } 663 687 664 688 /** … … public final class DataSet implements Data, Cloneable, ProjectionChangeListener 690 714 * @return whether the selection is empty or not 691 715 */ 692 716 public boolean selectionEmpty() { 693 return selectedPrimitives.isEmpty();717 return currentSelectedPrimitives.isEmpty(); 694 718 } 695 719 696 720 /** … … public final class DataSet implements Data, Cloneable, ProjectionChangeListener 699 723 * @return whether {@code osm} is selected or not 700 724 */ 701 725 public boolean isSelected(OsmPrimitive osm) { 702 return selectedPrimitives.contains(osm); 703 } 704 705 /** 706 * Toggles the selected state of the given collection of primitives. 707 * @param osm The primitives to toggle 708 */ 709 public void toggleSelected(Collection<? extends PrimitiveId> osm) { 710 boolean changed = false; 711 synchronized (selectionLock) { 712 for (PrimitiveId o : osm) { 713 changed = changed | this.dotoggleSelected(o); 714 } 715 if (changed) { 716 selectionSnapshot = null; 717 } 718 } 719 if (changed) { 720 fireSelectionChanged(); 721 } 722 } 723 724 /** 725 * Toggles the selected state of the given collection of primitives. 726 * @param osm The primitives to toggle 727 */ 728 public void toggleSelected(PrimitiveId... osm) { 729 toggleSelected(Arrays.asList(osm)); 730 } 731 732 private boolean dotoggleSelected(PrimitiveId primitiveId) { 733 OsmPrimitive primitive = getPrimitiveByIdChecked(primitiveId); 734 if (primitive == null) 735 return false; 736 if (!selectedPrimitives.remove(primitive)) { 737 selectedPrimitives.add(primitive); 738 } 739 selectionSnapshot = null; 740 return true; 726 return currentSelectedPrimitives.contains(osm); 741 727 } 742 728 743 729 /** … … public final class DataSet implements Data, Cloneable, ProjectionChangeListener 772 758 * 773 759 * @param selection the selection 774 760 * @param fireSelectionChangeEvent true, if the selection change listeners are to be notified; false, otherwise 761 * @deprecated Use {@link #setSelected(Collection)} instead. To bee removed soon. 775 762 */ 763 @Deprecated 776 764 public void setSelected(Collection<? extends PrimitiveId> selection, boolean fireSelectionChangeEvent) { 777 boolean changed; 778 synchronized (selectionLock) { 779 Set<OsmPrimitive> oldSelection = new LinkedHashSet<>(selectedPrimitives); 780 selectedPrimitives = new LinkedHashSet<>(); 781 addSelected(selection, false); 782 changed = !oldSelection.equals(selectedPrimitives); 783 if (changed) { 784 selectionSnapshot = null; 785 } 786 } 787 788 if (changed && fireSelectionChangeEvent) { 789 // If selection is not empty then event was already fired in addSelecteds 790 fireSelectionChanged(); 791 } 765 setSelected(selection); 792 766 } 793 767 794 768 /** … … public final class DataSet implements Data, Cloneable, ProjectionChangeListener 798 772 * @param selection the selection 799 773 */ 800 774 public void setSelected(Collection<? extends PrimitiveId> selection) { 801 setSelected(selection , true /* fire selection change event */);775 setSelected(selection.stream()); 802 776 } 803 777 804 778 /** 805 779 * Sets the current selection to the primitives in <code>osm</code> 806 780 * and notifies all {@link SelectionChangedListener}. 807 781 * 808 * @param osm the primitives to set 782 * @param osm the primitives to set. <code>null</code> values are ignored for now, but this may be removed in the future. 809 783 */ 810 784 public void setSelected(PrimitiveId... osm) { 811 if (osm.length == 1 && osm[0] == null) {812 setSelected();813 return; 814 }815 List<PrimitiveId> list = Arrays.asList(osm);816 setSelected(list);785 setSelected(Stream.of(osm).filter(Objects::nonNull)); 786 } 787 788 private void setSelected(Stream<? extends PrimitiveId> stream) { 789 doSelectionChange(old -> new SelectionReplaceEvent(this, old, 790 stream.map(this::getPrimitiveByIdChecked).filter(Objects::nonNull))); 817 791 } 818 792 819 793 /** … … public final class DataSet implements Data, Cloneable, ProjectionChangeListener 823 797 * @param selection the selection 824 798 */ 825 799 public void addSelected(Collection<? extends PrimitiveId> selection) { 826 addSelected(selection , true /* fire selection change event */);800 addSelected(selection.stream()); 827 801 } 828 802 829 803 /** … … public final class DataSet implements Data, Cloneable, ProjectionChangeListener 833 807 * @param osm the primitives to add 834 808 */ 835 809 public void addSelected(PrimitiveId... osm) { 836 addSelected(Arrays.asList(osm)); 810 addSelected(Stream.of(osm)); 811 } 812 813 private void addSelected(Stream<? extends PrimitiveId> stream) { 814 doSelectionChange(old -> new SelectionAddEvent(this, old, 815 stream.map(this::getPrimitiveByIdChecked).filter(Objects::nonNull))); 837 816 } 838 817 839 818 /** 840 * Adds the primitives in <code>selection</code> to the current selection. 841 * Notifies all {@link SelectionChangedListener} if <code>fireSelectionChangeEvent</code> is true. 842 * 843 * @param selection the selection 844 * @param fireSelectionChangeEvent true, if the selection change listeners are to be notified; false, otherwise 845 * @return if the selection was changed in the process 846 */ 847 private boolean addSelected(Collection<? extends PrimitiveId> selection, boolean fireSelectionChangeEvent) { 848 boolean changed = false; 849 synchronized (selectionLock) { 850 for (PrimitiveId id: selection) { 851 OsmPrimitive primitive = getPrimitiveByIdChecked(id); 852 if (primitive != null) { 853 changed = changed | selectedPrimitives.add(primitive); 854 } 855 } 856 if (changed) { 857 selectionSnapshot = null; 858 } 859 } 860 if (fireSelectionChangeEvent && changed) { 861 fireSelectionChanged(); 862 } 863 return changed; 819 * Removes the selection from every value in the collection. 820 * @param osm The collection of ids to remove the selection from. 821 */ 822 public void clearSelection(PrimitiveId... osm) { 823 clearSelection(Stream.of(osm)); 864 824 } 865 825 866 826 /** 867 * clear all highlights of virtual nodes 827 * Removes the selection from every value in the collection. 828 * @param list The collection of ids to remove the selection from. 868 829 */ 869 public void clear HighlightedVirtualNodes() {870 setHighlightedVirtualNodes(new ArrayList<WaySegment>());830 public void clearSelection(Collection<? extends PrimitiveId> list) { 831 clearSelection(list.stream()); 871 832 } 872 833 873 834 /** 874 * clear all highlights of way segments835 * Clears the current selection. 875 836 */ 876 public void clearHighlightedWaySegments() { 877 setHighlightedWaySegments(new ArrayList<WaySegment>()); 837 public void clearSelection() { 838 setSelected(Stream.empty()); 839 } 840 841 private void clearSelection(Stream<? extends PrimitiveId> stream) { 842 doSelectionChange(old -> new SelectionRemoveEvent(this, old, 843 stream.map(this::getPrimitiveByIdChecked).filter(Objects::nonNull))); 878 844 } 879 845 880 846 /** 881 * Removes the selection from every value in the collection.882 * @param osm The collection of ids to remove the selection from.847 * Toggles the selected state of the given collection of primitives. 848 * @param osm The primitives to toggle 883 849 */ 884 public void clearSelection(PrimitiveId...osm) {885 clearSelection(Arrays.asList(osm));850 public void toggleSelected(Collection<? extends PrimitiveId> osm) { 851 toggleSelected(osm.stream()); 886 852 } 887 853 888 854 /** 889 * Removes the selection from every value in the collection.890 * @param list The collection of ids to remove the selection from.855 * Toggles the selected state of the given collection of primitives. 856 * @param osm The primitives to toggle 891 857 */ 892 public void clearSelection(Collection<? extends PrimitiveId> list) { 893 boolean changed = false; 894 synchronized (selectionLock) { 895 for (PrimitiveId id:list) { 896 OsmPrimitive primitive = getPrimitiveById(id); 897 if (primitive != null) { 898 changed = changed | selectedPrimitives.remove(primitive); 899 } 900 } 901 if (changed) { 902 selectionSnapshot = null; 903 } 904 } 905 if (changed) { 906 fireSelectionChanged(); 907 } 858 public void toggleSelected(PrimitiveId... osm) { 859 toggleSelected(Stream.of(osm)); 860 } 861 862 private void toggleSelected(Stream<? extends PrimitiveId> stream) { 863 doSelectionChange(old -> new SelectionToggleEvent(this, old, 864 stream.map(this::getPrimitiveByIdChecked).filter(Objects::nonNull))); 908 865 } 909 866 910 867 /** 911 * Clears the current selection. 868 * Do a selection change. 869 * <p> 870 * This is the only method that changes the current selection state. 871 * @param command A generator that generates the {@link SelectionChangeEvent} for the given base set of currently selected primitives. 872 * @return if the command did change the selection. 912 873 */ 913 public void clearSelection() { 914 if (!selectedPrimitives.isEmpty()) { 874 private boolean doSelectionChange(Function<Set<OsmPrimitive>, SelectionChangeEvent> command) { 875 lock.readLock().lock(); 876 try { 915 877 synchronized (selectionLock) { 916 selectedPrimitives.clear(); 917 selectionSnapshot = null; 878 SelectionChangeEvent event = command.apply(currentSelectedPrimitives); 879 if (event.isNop()) { 880 return false; 881 } 882 currentSelectedPrimitives = event.getSelection(); 883 selectionListeners.fireEvent(l -> l.selectionChanged(event)); 884 return true; 918 885 } 919 fireSelectionChanged(); 886 } finally { 887 lock.readLock().unlock(); 920 888 } 921 889 } 922 890 923 891 /** 892 * clear all highlights of virtual nodes 893 */ 894 public void clearHighlightedVirtualNodes() { 895 setHighlightedVirtualNodes(new ArrayList<WaySegment>()); 896 } 897 898 /** 899 * clear all highlights of way segments 900 */ 901 public void clearHighlightedWaySegments() { 902 setHighlightedWaySegments(new ArrayList<WaySegment>()); 903 } 904 905 /** 924 906 * Return a copy of this dataset 925 907 * @deprecated Use the copy constructor instead. Remove in July 2016 926 908 */ … … public final class DataSet implements Data, Cloneable, ProjectionChangeListener 1267 1249 public void cleanupDeletedPrimitives() { 1268 1250 beginUpdate(); 1269 1251 try { 1270 boolean changed = cleanupDeleted(nodes.iterator()); 1271 if (cleanupDeleted(ways.iterator())) { 1272 changed = true; 1273 } 1274 if (cleanupDeleted(relations.iterator())) { 1275 changed = true; 1276 } 1277 if (changed) { 1278 fireSelectionChanged(); 1279 } 1252 cleanupDeleted(Stream.concat( 1253 nodes.stream(), Stream.concat(ways.stream(), relations.stream()))); 1280 1254 } finally { 1281 1255 endUpdate(); 1282 1256 } 1283 1257 } 1284 1258 1285 private boolean cleanupDeleted(Iterator<? extends OsmPrimitive> it) { 1286 boolean changed = false; 1287 synchronized (selectionLock) { 1288 while (it.hasNext()) { 1289 OsmPrimitive primitive = it.next(); 1290 if (primitive.isDeleted() && (!primitive.isVisible() || primitive.isNew())) { 1291 selectedPrimitives.remove(primitive); 1292 selectionSnapshot = null; 1293 allPrimitives.remove(primitive); 1294 primitive.setDataset(null); 1295 changed = true; 1296 it.remove(); 1297 } 1298 } 1299 if (changed) { 1300 selectionSnapshot = null; 1301 } 1302 } 1303 return changed; 1259 private void cleanupDeleted(Stream<? extends OsmPrimitive> it) { 1260 clearSelection(it 1261 .filter(primitive -> primitive.isDeleted() && (!primitive.isVisible() || primitive.isNew())) 1262 .peek(allPrimitives::remove) 1263 .peek(primitive -> primitive.setDataset(null))); 1304 1264 } 1305 1265 1306 1266 /**
