source: josm/trunk/src/org/openstreetmap/josm/data/osm/event/DatasetEventManager.java@ 5909

Last change on this file since 5909 was 5909, checked in by stoecker, 11 years ago

fix all remaining javadoc warnings

  • Property svn:eol-style set to native
File size: 8.0 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.osm.event;
3
4import java.util.ArrayList;
5import java.util.Arrays;
6import java.util.List;
7import java.util.Queue;
8import java.util.concurrent.CopyOnWriteArrayList;
9import java.util.concurrent.LinkedBlockingQueue;
10
11import javax.swing.SwingUtilities;
12
13import org.openstreetmap.josm.data.osm.DataSet;
14import org.openstreetmap.josm.data.osm.event.DataSetListenerAdapter.Listener;
15import org.openstreetmap.josm.gui.MapView;
16import org.openstreetmap.josm.gui.layer.OsmDataLayer;
17
18/**
19 * This class allows to add DatasetListener to currently active dataset. If active
20 * layer is changed, listeners are automatically registered at new active dataset
21 * (it's no longer necessary to register for layer events and reregister every time
22 * new layer is selected)
23 *
24 * Events in EDT are supported, see {@link #addDatasetListener(DataSetListener, FireMode)}
25 *
26 */
27public class DatasetEventManager implements MapView.EditLayerChangeListener, Listener {
28
29 private static final DatasetEventManager instance = new DatasetEventManager();
30
31 public enum FireMode {
32 /**
33 * Fire in calling thread immediately.
34 */
35 IMMEDIATELY,
36 /**
37 * Fire in event dispatch thread.
38 */
39 IN_EDT,
40 /**
41 * Fire in event dispatch thread. If more than one event arrived when event queue is checked, merged them to
42 * one event
43 */
44 IN_EDT_CONSOLIDATED}
45
46 private static class ListenerInfo {
47 final DataSetListener listener;
48 final boolean consolidate;
49
50 public ListenerInfo(DataSetListener listener, boolean consolidate) {
51 this.listener = listener;
52 this.consolidate = consolidate;
53 }
54
55 @Override
56 public int hashCode() {
57 return listener.hashCode();
58 }
59
60 @Override
61 public boolean equals(Object o) {
62 return o instanceof ListenerInfo && ((ListenerInfo)o).listener == listener;
63 }
64 }
65
66 public static DatasetEventManager getInstance() {
67 return instance;
68 }
69
70 private final Queue<AbstractDatasetChangedEvent> eventsInEDT = new LinkedBlockingQueue<AbstractDatasetChangedEvent>();
71 private final CopyOnWriteArrayList<ListenerInfo> inEDTListeners = new CopyOnWriteArrayList<ListenerInfo>();
72 private final CopyOnWriteArrayList<ListenerInfo> normalListeners = new CopyOnWriteArrayList<ListenerInfo>();
73 private final DataSetListener myListener = new DataSetListenerAdapter(this);
74
75 public DatasetEventManager() {
76 MapView.addEditLayerChangeListener(this);
77 }
78
79 /**
80 * Register listener, that will receive events from currently active dataset
81 * @param listener the listener to be registered
82 * @param fireMode If {@link FireMode#IN_EDT} or {@link FireMode#IN_EDT_CONSOLIDATED},
83 * listener will be notified in event dispatch thread instead of thread that caused
84 * the dataset change
85 */
86 public void addDatasetListener(DataSetListener listener, FireMode fireMode) {
87 if (fireMode == FireMode.IN_EDT || fireMode == FireMode.IN_EDT_CONSOLIDATED) {
88 inEDTListeners.addIfAbsent(new ListenerInfo(listener, fireMode == FireMode.IN_EDT_CONSOLIDATED));
89 } else {
90 normalListeners.addIfAbsent(new ListenerInfo(listener, false));
91 }
92 }
93
94 public void removeDatasetListener(DataSetListener listener) {
95 ListenerInfo searchListener = new ListenerInfo(listener, false);
96 inEDTListeners.remove(searchListener);
97 normalListeners.remove(searchListener);
98 }
99
100 public void editLayerChanged(OsmDataLayer oldLayer, OsmDataLayer newLayer) {
101 if (oldLayer != null) {
102 oldLayer.data.removeDataSetListener(myListener);
103 }
104
105 if (newLayer != null) {
106 newLayer.data.addDataSetListener(myListener);
107 processDatasetEvent(new DataChangedEvent(newLayer.data));
108 } else {
109 processDatasetEvent(new DataChangedEvent(null));
110 }
111 }
112
113 private void fireEvents(List<ListenerInfo> listeners, AbstractDatasetChangedEvent event) {
114 for (ListenerInfo listener: listeners) {
115 if (!listener.consolidate) {
116 event.fire(listener.listener);
117 }
118 }
119 }
120
121 private void fireConsolidatedEvents(List<ListenerInfo> listeners, AbstractDatasetChangedEvent event) {
122 for (ListenerInfo listener: listeners) {
123 if (listener.consolidate) {
124 event.fire(listener.listener);
125 }
126 }
127 }
128
129 public void processDatasetEvent(AbstractDatasetChangedEvent event) {
130 fireEvents(normalListeners, event);
131 eventsInEDT.add(event);
132 SwingUtilities.invokeLater(edtRunnable);
133 }
134
135 private final Runnable edtRunnable = new Runnable() {
136 public void run() {
137 while (!eventsInEDT.isEmpty()) {
138 List<AbstractDatasetChangedEvent> events = new ArrayList<AbstractDatasetChangedEvent>();
139 events.addAll(eventsInEDT);
140
141 DataSet dataSet = null;
142 AbstractDatasetChangedEvent consolidatedEvent = null;
143 AbstractDatasetChangedEvent event = null;
144
145 while ((event = eventsInEDT.poll()) != null) {
146 fireEvents(inEDTListeners, event);
147
148 // DataSet changed - fire consolidated event early
149 if (consolidatedEvent != null && dataSet != event.getDataset()) {
150 fireConsolidatedEvents(inEDTListeners, consolidatedEvent);
151 consolidatedEvent = null;
152 }
153
154 dataSet = event.getDataset();
155
156 // Build consolidated event
157 if (event instanceof DataChangedEvent) {
158 // DataChangeEvent can contains other events, so it gets special handling
159 DataChangedEvent dataEvent = (DataChangedEvent) event;
160 if (dataEvent.getEvents() == null) {
161 consolidatedEvent = dataEvent; // Dataset was completely changed, we can ignore older events
162 } else {
163 if (consolidatedEvent == null) {
164 consolidatedEvent = new DataChangedEvent(dataSet, dataEvent.getEvents());
165 } else if (consolidatedEvent instanceof DataChangedEvent) {
166 List<AbstractDatasetChangedEvent> evts = ((DataChangedEvent) consolidatedEvent).getEvents();
167 if (evts != null) {
168 evts.addAll(dataEvent.getEvents());
169 }
170 } else {
171 AbstractDatasetChangedEvent oldConsolidateEvent = consolidatedEvent;
172 consolidatedEvent = new DataChangedEvent(dataSet, dataEvent.getEvents());
173 ((DataChangedEvent) consolidatedEvent).getEvents().add(oldConsolidateEvent);
174 }
175 }
176 } else {
177 // Normal events
178 if (consolidatedEvent == null) {
179 consolidatedEvent = event;
180 } else if (consolidatedEvent instanceof DataChangedEvent) {
181 List<AbstractDatasetChangedEvent> evs = ((DataChangedEvent) consolidatedEvent).getEvents();
182 if (evs != null) {
183 evs.add(event);
184 }
185 } else {
186 consolidatedEvent = new DataChangedEvent(dataSet,
187 new ArrayList<AbstractDatasetChangedEvent>(Arrays.asList(consolidatedEvent)));
188 }
189
190 }
191 }
192
193 // Fire consolidated event
194 fireConsolidatedEvents(inEDTListeners, consolidatedEvent);
195 }
196 }
197 };
198}
Note: See TracBrowser for help on using the repository browser.