Changeset 12048 in josm
- Timestamp:
- 2017-05-03T16:09:46+02:00 (8 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/actions/SelectNonBranchingWaySequences.java
r9999 r12048 160 160 161 161 if (selectionChanged) 162 data.setSelected(selection , true);162 data.setSelected(selection); 163 163 } 164 164 } -
trunk/src/org/openstreetmap/josm/actions/mapmode/SelectAction.java
r11978 r12048 850 850 if (ctrl) mergePrims(e.getPoint()); 851 851 } 852 getLayerManager().getEditDataSet().fireSelectionChanged();853 852 } 854 853 -
trunk/src/org/openstreetmap/josm/data/osm/DataSet.java
r12014 r12048 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; … … 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; … … 22 20 import java.util.concurrent.locks.ReadWriteLock; 23 21 import java.util.concurrent.locks.ReentrantReadWriteLock; 22 import java.util.function.Function; 24 23 import java.util.function.Predicate; 25 24 import java.util.stream.Collectors; 25 import java.util.stream.Stream; 26 26 27 27 import org.openstreetmap.josm.Main; … … 33 33 import org.openstreetmap.josm.data.coor.EastNorth; 34 34 import org.openstreetmap.josm.data.coor.LatLon; 35 import org.openstreetmap.josm.data.osm.DataSelectionListener.SelectionAddEvent; 36 import org.openstreetmap.josm.data.osm.DataSelectionListener.SelectionChangeEvent; 37 import org.openstreetmap.josm.data.osm.DataSelectionListener.SelectionRemoveEvent; 38 import org.openstreetmap.josm.data.osm.DataSelectionListener.SelectionReplaceEvent; 39 import org.openstreetmap.josm.data.osm.DataSelectionListener.SelectionToggleEvent; 35 40 import org.openstreetmap.josm.data.osm.event.AbstractDatasetChangedEvent; 36 41 import org.openstreetmap.josm.data.osm.event.ChangesetIdChangedEvent; … … 42 47 import org.openstreetmap.josm.data.osm.event.PrimitivesRemovedEvent; 43 48 import org.openstreetmap.josm.data.osm.event.RelationMembersChangedEvent; 49 import org.openstreetmap.josm.data.osm.event.SelectionEventManager; 44 50 import org.openstreetmap.josm.data.osm.event.TagsChangedEvent; 45 51 import org.openstreetmap.josm.data.osm.event.WayNodesChangedEvent; … … 167 173 168 174 private final ReadWriteLock lock = new ReentrantReadWriteLock(); 175 176 /** 177 * The mutex lock that is used to synchronize selection changes. 178 */ 169 179 private final Object selectionLock = new Object(); 180 /** 181 * The current selected primitives. This is always a unmodifiable set. 182 */ 183 private Set<OsmPrimitive> currentSelectedPrimitives = Collections.emptySet(); 184 185 /** 186 * A list of listeners that listen to selection changes on this layer. 187 */ 188 private final ListenerList<DataSelectionListener> selectionListeners = ListenerList.create(); 170 189 171 190 private Area cachedDataSourceArea; … … 184 203 // the listener, projection change listeners are managed as WeakReferences. 185 204 Main.addProjectionChangeListener(this); 205 addSelectionListener((DataSelectionListener) e -> fireDreprecatedSelectionChange(e.getSelection())); 186 206 } 187 207 … … 637 657 if (!success) 638 658 throw new JosmRuntimeException("failed to remove primitive: "+primitive); 639 synchronized (selectionLock) { 640 selectedPrimitives.remove(primitive); 641 selectionSnapshot = null; 642 } 659 clearSelection(primitiveId); 643 660 allPrimitives.remove(primitive); 644 661 primitive.setDataset(null); … … 654 671 655 672 /** 673 * Add a listener that listens to selection changes in this specific data set. 674 * @param listener The listener. 675 * @see #removeSelectionListener(DataSelectionListener) 676 * @see SelectionEventManager#addSelectionListener(SelectionChangedListener, 677 * org.openstreetmap.josm.data.osm.event.DatasetEventManager.FireMode) 678 * To add a global listener. 679 */ 680 public void addSelectionListener(DataSelectionListener listener) { 681 selectionListeners.addListener(listener); 682 } 683 684 /** 685 * Remove a listener that listens to selection changes in this specific data set. 686 * @param listener The listener. 687 * @see #addSelectionListener(DataSelectionListener) 688 */ 689 public void removeSelectionListener(DataSelectionListener listener) { 690 selectionListeners.removeListener(listener); 691 } 692 693 /*--------------------------------------------------- 694 * OLD SELECTION HANDLING 695 *---------------------------------------------------*/ 696 697 /** 656 698 * A list of listeners to selection changed events. The list is static, as listeners register 657 699 * themselves for any dataset selection changes that occur, regardless of the current active … … 663 705 * Adds a new selection listener. 664 706 * @param listener The selection listener to add 707 * @see #addSelectionListener(DataSelectionListener) 708 * @see SelectionEventManager#removeSelectionListener(SelectionChangedListener) 665 709 */ 666 710 public static void addSelectionListener(SelectionChangedListener listener) { … … 671 715 * Removes a selection listener. 672 716 * @param listener The selection listener to remove 717 * @see #removeSelectionListener(DataSelectionListener) 718 * @see SelectionEventManager#removeSelectionListener(SelectionChangedListener) 673 719 */ 674 720 public static void removeSelectionListener(SelectionChangedListener listener) { … … 679 725 * Notifies all registered {@link SelectionChangedListener} about the current selection in 680 726 * this dataset. 681 * 682 */ 727 * @deprecated You should never need to do this from the outside. 728 */ 729 @Deprecated 683 730 public void fireSelectionChanged() { 684 Collection<? extends OsmPrimitive> currentSelection = getAllSelected(); 731 fireDreprecatedSelectionChange(getAllSelected()); 732 } 733 734 private static void fireDreprecatedSelectionChange(Collection<? extends OsmPrimitive> currentSelection) { 685 735 for (SelectionChangedListener l : selListeners) { 686 736 l.selectionChanged(currentSelection); 687 737 } 688 738 } 689 690 private Set<OsmPrimitive> selectedPrimitives = new LinkedHashSet<>();691 private Collection<OsmPrimitive> selectionSnapshot;692 739 693 740 /** … … 754 801 */ 755 802 public Collection<OsmPrimitive> getAllSelected() { 756 Collection<OsmPrimitive> currentList; 757 synchronized (selectionLock) { 758 if (selectionSnapshot == null) { 759 selectionSnapshot = Collections.unmodifiableList(new ArrayList<>(selectedPrimitives)); 760 } 761 currentList = selectionSnapshot; 762 } 763 return currentList; 803 return currentSelectedPrimitives; 764 804 } 765 805 … … 793 833 */ 794 834 public boolean selectionEmpty() { 795 return selectedPrimitives.isEmpty();835 return currentSelectedPrimitives.isEmpty(); 796 836 } 797 837 … … 802 842 */ 803 843 public boolean isSelected(OsmPrimitive osm) { 804 return selectedPrimitives.contains(osm); 805 } 806 807 /** 808 * Toggles the selected state of the given collection of primitives. 809 * @param osm The primitives to toggle 810 */ 811 public void toggleSelected(Collection<? extends PrimitiveId> osm) { 812 boolean changed = false; 813 synchronized (selectionLock) { 814 for (PrimitiveId o : osm) { 815 changed = changed | this.dotoggleSelected(o); 816 } 817 if (changed) { 818 selectionSnapshot = null; 819 } 820 } 821 if (changed) { 822 fireSelectionChanged(); 823 } 824 } 825 826 /** 827 * Toggles the selected state of the given collection of primitives. 828 * @param osm The primitives to toggle 829 */ 830 public void toggleSelected(PrimitiveId... osm) { 831 toggleSelected(Arrays.asList(osm)); 832 } 833 834 private boolean dotoggleSelected(PrimitiveId primitiveId) { 835 OsmPrimitive primitive = getPrimitiveByIdChecked(primitiveId); 836 if (primitive == null) 837 return false; 838 if (!selectedPrimitives.remove(primitive)) { 839 selectedPrimitives.add(primitive); 840 } 841 selectionSnapshot = null; 842 return true; 844 return currentSelectedPrimitives.contains(osm); 843 845 } 844 846 … … 875 877 * @param selection the selection 876 878 * @param fireSelectionChangeEvent true, if the selection change listeners are to be notified; false, otherwise 877 */ 879 * @deprecated Use {@link #setSelected(Collection)} instead. To bee removed end of 2017. Does not seem to be used by plugins. 880 */ 881 @Deprecated 878 882 public void setSelected(Collection<? extends PrimitiveId> selection, boolean fireSelectionChangeEvent) { 879 boolean changed; 880 synchronized (selectionLock) { 881 Set<OsmPrimitive> oldSelection = new LinkedHashSet<>(selectedPrimitives); 882 selectedPrimitives = new LinkedHashSet<>(); 883 addSelected(selection, false); 884 changed = !oldSelection.equals(selectedPrimitives); 885 if (changed) { 886 selectionSnapshot = null; 887 } 888 } 889 890 if (changed && fireSelectionChangeEvent) { 891 // If selection is not empty then event was already fired in addSelecteds 892 fireSelectionChanged(); 893 } 883 setSelected(selection); 894 884 } 895 885 … … 901 891 */ 902 892 public void setSelected(Collection<? extends PrimitiveId> selection) { 903 setSelected(selection , true /* fire selection change event */);893 setSelected(selection.stream()); 904 894 } 905 895 … … 908 898 * and notifies all {@link SelectionChangedListener}. 909 899 * 910 * @param osm the primitives to set 900 * @param osm the primitives to set. <code>null</code> values are ignored for now, but this may be removed in the future. 911 901 */ 912 902 public void setSelected(PrimitiveId... osm) { 913 if (osm.length == 1 && osm[0] == null) {914 setSelected();915 return; 916 }917 List<PrimitiveId> list = Arrays.asList(osm);918 setSelected(list);903 setSelected(Stream.of(osm).filter(Objects::nonNull)); 904 } 905 906 private void setSelected(Stream<? extends PrimitiveId> stream) { 907 doSelectionChange(old -> new SelectionReplaceEvent(this, old, 908 stream.map(this::getPrimitiveByIdChecked).filter(Objects::nonNull))); 919 909 } 920 910 … … 926 916 */ 927 917 public void addSelected(Collection<? extends PrimitiveId> selection) { 928 addSelected(selection , true /* fire selection change event */);918 addSelected(selection.stream()); 929 919 } 930 920 … … 936 926 */ 937 927 public void addSelected(PrimitiveId... osm) { 938 addSelected(Arrays.asList(osm)); 939 } 940 941 /** 942 * Adds the primitives in <code>selection</code> to the current selection. 943 * Notifies all {@link SelectionChangedListener} if <code>fireSelectionChangeEvent</code> is true. 944 * 945 * @param selection the selection 946 * @param fireSelectionChangeEvent true, if the selection change listeners are to be notified; false, otherwise 947 * @return if the selection was changed in the process 948 */ 949 private boolean addSelected(Collection<? extends PrimitiveId> selection, boolean fireSelectionChangeEvent) { 950 boolean changed = false; 951 synchronized (selectionLock) { 952 for (PrimitiveId id: selection) { 953 OsmPrimitive primitive = getPrimitiveByIdChecked(id); 954 if (primitive != null) { 955 changed = changed | selectedPrimitives.add(primitive); 928 addSelected(Stream.of(osm)); 929 } 930 931 private void addSelected(Stream<? extends PrimitiveId> stream) { 932 doSelectionChange(old -> new SelectionAddEvent(this, old, 933 stream.map(this::getPrimitiveByIdChecked).filter(Objects::nonNull))); 934 } 935 936 /** 937 * Removes the selection from every value in the collection. 938 * @param osm The collection of ids to remove the selection from. 939 */ 940 public void clearSelection(PrimitiveId... osm) { 941 clearSelection(Stream.of(osm)); 942 } 943 944 /** 945 * Removes the selection from every value in the collection. 946 * @param list The collection of ids to remove the selection from. 947 */ 948 public void clearSelection(Collection<? extends PrimitiveId> list) { 949 clearSelection(list.stream()); 950 } 951 952 /** 953 * Clears the current selection. 954 */ 955 public void clearSelection() { 956 setSelected(Stream.empty()); 957 } 958 959 private void clearSelection(Stream<? extends PrimitiveId> stream) { 960 doSelectionChange(old -> new SelectionRemoveEvent(this, old, 961 stream.map(this::getPrimitiveByIdChecked).filter(Objects::nonNull))); 962 } 963 964 /** 965 * Toggles the selected state of the given collection of primitives. 966 * @param osm The primitives to toggle 967 */ 968 public void toggleSelected(Collection<? extends PrimitiveId> osm) { 969 toggleSelected(osm.stream()); 970 } 971 972 /** 973 * Toggles the selected state of the given collection of primitives. 974 * @param osm The primitives to toggle 975 */ 976 public void toggleSelected(PrimitiveId... osm) { 977 toggleSelected(Stream.of(osm)); 978 } 979 980 private void toggleSelected(Stream<? extends PrimitiveId> stream) { 981 doSelectionChange(old -> new SelectionToggleEvent(this, old, 982 stream.map(this::getPrimitiveByIdChecked).filter(Objects::nonNull))); 983 } 984 985 /** 986 * Do a selection change. 987 * <p> 988 * This is the only method that changes the current selection state. 989 * @param command A generator that generates the {@link SelectionChangeEvent} for the given base set of currently selected primitives. 990 * @return true iff the command did change the selection. 991 * @since 12048 992 */ 993 private boolean doSelectionChange(Function<Set<OsmPrimitive>, SelectionChangeEvent> command) { 994 lock.readLock().lock(); 995 try { 996 synchronized (selectionLock) { 997 SelectionChangeEvent event = command.apply(currentSelectedPrimitives); 998 if (event.isNop()) { 999 return false; 956 1000 } 957 } 958 if (changed) { 959 selectionSnapshot = null; 960 } 961 } 962 if (fireSelectionChangeEvent && changed) { 963 fireSelectionChanged(); 964 } 965 return changed; 1001 currentSelectedPrimitives = event.getSelection(); 1002 selectionListeners.fireEvent(l -> l.selectionChanged(event)); 1003 return true; 1004 } 1005 } finally { 1006 lock.readLock().unlock(); 1007 } 966 1008 } 967 1009 … … 978 1020 public void clearHighlightedWaySegments() { 979 1021 setHighlightedWaySegments(new ArrayList<WaySegment>()); 980 }981 982 /**983 * Removes the selection from every value in the collection.984 * @param osm The collection of ids to remove the selection from.985 */986 public void clearSelection(PrimitiveId... osm) {987 clearSelection(Arrays.asList(osm));988 }989 990 /**991 * Removes the selection from every value in the collection.992 * @param list The collection of ids to remove the selection from.993 */994 public void clearSelection(Collection<? extends PrimitiveId> list) {995 boolean changed = false;996 synchronized (selectionLock) {997 for (PrimitiveId id:list) {998 OsmPrimitive primitive = getPrimitiveById(id);999 if (primitive != null) {1000 changed = changed | selectedPrimitives.remove(primitive);1001 }1002 }1003 if (changed) {1004 selectionSnapshot = null;1005 }1006 }1007 if (changed) {1008 fireSelectionChanged();1009 }1010 }1011 1012 /**1013 * Clears the current selection.1014 */1015 public void clearSelection() {1016 if (!selectedPrimitives.isEmpty()) {1017 synchronized (selectionLock) {1018 selectedPrimitives.clear();1019 selectionSnapshot = null;1020 }1021 fireSelectionChanged();1022 }1023 1022 } 1024 1023 … … 1372 1371 beginUpdate(); 1373 1372 try { 1374 boolean changed = cleanupDeleted(nodes.iterator()); 1375 if (cleanupDeleted(ways.iterator())) { 1376 changed = true; 1377 } 1378 if (cleanupDeleted(relations.iterator())) { 1379 changed = true; 1380 } 1381 if (changed) { 1382 fireSelectionChanged(); 1383 } 1373 cleanupDeleted(Stream.concat( 1374 nodes.stream(), Stream.concat(ways.stream(), relations.stream()))); 1384 1375 } finally { 1385 1376 endUpdate(); … … 1387 1378 } 1388 1379 1389 private boolean cleanupDeleted(Iterator<? extends OsmPrimitive> it) { 1390 boolean changed = false; 1391 synchronized (selectionLock) { 1392 while (it.hasNext()) { 1393 OsmPrimitive primitive = it.next(); 1394 if (primitive.isDeleted() && (!primitive.isVisible() || primitive.isNew())) { 1395 selectedPrimitives.remove(primitive); 1396 selectionSnapshot = null; 1397 allPrimitives.remove(primitive); 1398 primitive.setDataset(null); 1399 changed = true; 1400 it.remove(); 1401 } 1402 } 1403 if (changed) { 1404 selectionSnapshot = null; 1405 } 1406 } 1407 return changed; 1380 private void cleanupDeleted(Stream<? extends OsmPrimitive> it) { 1381 clearSelection(it 1382 .filter(primitive -> primitive.isDeleted() && (!primitive.isVisible() || primitive.isNew())) 1383 .peek(allPrimitives::remove) 1384 .peek(primitive -> primitive.setDataset(null))); 1408 1385 } 1409 1386 -
trunk/src/org/openstreetmap/josm/data/osm/event/SelectionEventManager.java
r11928 r12048 3 3 4 4 import java.util.Collection; 5 import java.util.Collections; 6 import java.util.HashSet; 5 7 import java.util.List; 6 8 import java.util.Objects; 9 import java.util.Set; 7 10 import java.util.concurrent.CopyOnWriteArrayList; 11 import java.util.stream.Stream; 8 12 9 13 import javax.swing.SwingUtilities; 10 14 15 import org.openstreetmap.josm.Main; 11 16 import org.openstreetmap.josm.data.SelectionChangedListener; 17 import org.openstreetmap.josm.data.osm.DataSelectionListener; 12 18 import org.openstreetmap.josm.data.osm.DataSet; 13 19 import org.openstreetmap.josm.data.osm.OsmPrimitive; 14 20 import org.openstreetmap.josm.data.osm.event.DatasetEventManager.FireMode; 21 import org.openstreetmap.josm.gui.layer.MainLayerManager; 22 import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeEvent; 23 import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeListener; 15 24 16 25 /** 17 * Similar like {@link DatasetEventManager}, just for selection events. Because currently selection changed 18 * event are global, only FIRE_IN_EDT and FIRE_EDT_CONSOLIDATED modes are really useful 26 * Similar like {@link DatasetEventManager}, just for selection events. 27 * 28 * It allows to register listeners to global selection events for the selection in the current edit layer. 29 * 30 * If you want to listen to selections to a specific data layer, 31 * you can register a listener to that layer by using {@link DataSet#addSelectionListener(DataSelectionListener)} 32 * 19 33 * @since 2912 20 34 */ 21 public class SelectionEventManager implements SelectionChangedListener {35 public class SelectionEventManager implements DataSelectionListener, ActiveLayerChangeListener { 22 36 23 37 private static final SelectionEventManager instance = new SelectionEventManager(); … … 59 73 * Constructs a new {@code SelectionEventManager}. 60 74 */ 61 public SelectionEventManager() { 62 DataSet.addSelectionListener(this); 75 protected SelectionEventManager() { 76 MainLayerManager layerManager = Main.getLayerManager(); 77 // We do not allow for destructing this object. 78 // Currently, this is a singleton class, so this is not required. 79 layerManager.addAndFireActiveLayerChangeListener(this); 63 80 } 64 81 … … 89 106 90 107 @Override 91 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) { 108 public void activeOrEditLayerChanged(ActiveLayerChangeEvent e) { 109 DataSet oldDataSet = e.getPreviousEditDataSet(); 110 if (oldDataSet != null) { 111 // Fake a selection removal 112 // Relying on this allows components to not have to monitor layer changes. 113 // If we would not do this, e.g. the move command would have a hard time tracking which layer 114 // the last moved selection was in. 115 SelectionReplaceEvent event = new SelectionReplaceEvent(oldDataSet, 116 new HashSet<>(oldDataSet.getAllSelected()), Stream.empty()); 117 selectionChanged(event); 118 oldDataSet.removeSelectionListener(this); 119 } 120 DataSet newDataSet = e.getSource().getEditDataSet(); 121 if (newDataSet != null) { 122 newDataSet.addSelectionListener(this); 123 // Fake a selection add 124 SelectionReplaceEvent event = new SelectionReplaceEvent(newDataSet, 125 Collections.emptySet(), newDataSet.getAllSelected().stream()); 126 selectionChanged(event); 127 } 128 } 129 130 @Override 131 public void selectionChanged(SelectionChangeEvent e) { 132 Set<OsmPrimitive> newSelection = e.getSelection(); 92 133 fireEvents(normalListeners, newSelection); 93 134 selection = newSelection; -
trunk/src/org/openstreetmap/josm/gui/dialogs/relation/actions/SavingAction.java
r11848 r12048 76 76 // make sure everybody is notified about the changes 77 77 // 78 layer.data.fireSelectionChanged();79 78 editor.setRelation(newRelation); 80 79 if (editor instanceof RelationEditor) { … … 108 107 if (!editedRelation.hasEqualSemanticAttributes(editor.getRelation(), false)) { 109 108 Main.main.undoRedo.add(new ChangeCommand(editor.getRelation(), editedRelation)); 110 layer.data.fireSelectionChanged();111 109 } 112 110 }
Note:
See TracChangeset
for help on using the changeset viewer.