1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package net.wotonomy.control;
20
21 import java.util.Iterator;
22 import java.util.LinkedList;
23 import java.util.List;
24
25 import net.wotonomy.foundation.NSRunLoop;
26 import net.wotonomy.foundation.NSSelector;
27
28 /***
29 * EODelayedObserverQueue allows EODelayedObservers
30 * to receive only one subjectChanged() message
31 * after numerous willChange() messages have
32 * been sent. Observers are then notified in order
33 * of their priority property,
34 * so that certain observers can be notified before
35 * others for whatever application-specific purpose.
36 * This class is not thread-safe and should be used
37 * only for single-threaded GUI clients (AWT and Swing).
38 * <br><br>
39 *
40 * Important note: because AWT's event queue does
41 * not allow for priority-based scheduling, this
42 * class installs a custom event queue, replacing
43 * the existing queue on the AWT dispatch thread.
44 * We know of no way around this problem.
45 * <br><br>
46 *
47 * Implementation note: this queue relies on the
48 * result of equals() for maintaining a set of
49 * objects on the queue. If two EODelayedObservers
50 * evaluate to the same value using equals(), only
51 * one of them will exist on the queue. If this,
52 * starts to suck, we can change it.
53 *
54 * @author michael@mpowers.net
55 * @author $Author: cgruber $
56 * @version $Revision: 894 $
57 */
58
59 public class EODelayedObserverQueue
60 {
61 /***
62 * The default run loop ordering flushes the delayed observers
63 * up to ObserverPrioritySixth before dispatching the AWT event
64 * queue. ObserverPriorityLater is run last.
65 */
66 public static int FlushDelayedObserversRunLoopOrdering = 400000;
67
68 private static EODelayedObserverQueue
69 defaultObserverQueue = null;
70
71 private static NSSelector runLaterSelector =
72 new NSSelector( "flushObserverQueue",
73 new Class[] { Object.class } );
74
75 private boolean willRunLater;
76 private LinkedList priorityQueue;
77
78 /***
79 * Default constructor.
80 */
81 public EODelayedObserverQueue ()
82 {
83 willRunLater = false;
84 priorityQueue = new LinkedList();
85 }
86
87 /***
88 * Returns the system default observer queue.
89 */
90 public static EODelayedObserverQueue defaultObserverQueue ()
91 {
92 if ( defaultObserverQueue == null )
93 {
94 defaultObserverQueue = new EODelayedObserverQueue();
95 }
96 return defaultObserverQueue;
97 }
98
99 /***
100 * Removes the specified observer from the queue.
101 */
102 public void dequeueObserver (
103 EODelayedObserver anObserver )
104 {
105
106
107
108 priorityQueue.remove( anObserver );
109
110 }
111
112 /***
113 * Adds the specified observer to the queue.
114 * An already enqueued observer will not be
115 * added again.
116 * If the observer's priority is
117 * ObserverPriorityImmediate, it will be
118 * notified immediately and not added to the
119 * queue.
120 * Otherwise, the queue sets itself up to
121 * call notifyObserversUpToPriority during the
122 * run loop as specified by
123 * FlushDelayedObserversRunLoopOrdering.
124 */
125 public void enqueueObserver (
126 EODelayedObserver anObserver )
127 {
128
129 final EODelayedObserver observer = anObserver;
130
131 if ( observer.priority() ==
132 EODelayedObserver.ObserverPriorityImmediate )
133 {
134
135 observer.subjectChanged();
136 }
137 else
138 {
139
140
141
142
143 int i = 0;
144 int priority = observer.priority();
145 Object o;
146
147 Iterator iterator = priorityQueue.iterator();
148
149
150 while ( iterator.hasNext() )
151 {
152 o = iterator.next();
153 if ( o == observer )
154 {
155
156 return;
157 }
158 if ( ((EODelayedObserver)o).priority() > priority )
159 {
160
161 break;
162 }
163 i++;
164 }
165
166
167
168 while ( iterator.hasNext() )
169 {
170 if ( iterator.next() == observer )
171 {
172
173 return;
174 }
175 }
176
177
178
179 priorityQueue.add( i, observer );
180
181
182 runLater();
183 }
184
185 }
186
187 /***
188 * Notifies all observers with priority equal to
189 * or greater than the specified priority.
190 */
191 public void notifyObserversUpToPriority ( int priority )
192 {
193
194 EODelayedObserver o;
195 while ( ! priorityQueue.isEmpty() )
196 {
197 o = (EODelayedObserver) priorityQueue.getFirst();
198 if ( o.priority() > priority ) break;
199 priorityQueue.removeFirst();
200
201 try
202 {
203 o.subjectChanged();
204 }
205 catch ( Exception exc )
206 {
207 System.out.println( "Error notifying observer: " + o );
208 exc.printStackTrace();
209 }
210 }
211 }
212
213 /***
214 * Called to ensure that notifyObserversUpToPriority
215 * will be called on the next event loop.
216 */
217 private void runLater()
218 {
219 if ( ! willRunLater )
220 {
221 willRunLater = true;
222 NSRunLoop.currentRunLoop().performSelectorWithOrder(
223 runLaterSelector, this, null, FlushDelayedObserversRunLoopOrdering, null );
224 }
225 }
226
227 /***
228 * This method is called by the event queue run loop
229 * and calls notifyObserversUpToPriority with
230 * ObserverPriorityLater.
231 * NOTE: This method is not part of the specification.
232 */
233 public void flushObserverQueue( Object anObject )
234 {
235
236 notifyObserversUpToPriority( EODelayedObserver.ObserverPrioritySixth );
237 if ( ! priorityQueue.isEmpty() )
238 {
239
240 NSRunLoop.invokeLater(
241 new PriorityLaterRunnable( new LinkedList( priorityQueue ) ) );
242 priorityQueue.clear();
243 }
244 willRunLater = false;
245 }
246
247 /***
248 * A runnable for dispatching remaining observers running at ObserverPriorityLater.
249 */
250 class PriorityLaterRunnable implements Runnable
251 {
252 List observers;
253
254 public PriorityLaterRunnable( List anObserverList )
255 {
256 observers = anObserverList;
257 }
258
259 public void run()
260 {
261 EODelayedObserver o = null;
262 Iterator i = observers.iterator();
263 while ( i.hasNext() )
264 {
265 try
266 {
267 o = (EODelayedObserver) i.next();
268 o.subjectChanged();
269 }
270 catch ( Exception exc )
271 {
272 System.out.println( "Error notifying observer: " + o );
273 exc.printStackTrace();
274 }
275 }
276 }
277 }
278
279 }
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323