|
|||||||||||||||||||
Source file | Conditionals | Statements | Methods | TOTAL | |||||||||||||||
WindowMonitor.java | 75% | 86% | 75% | 82.2% |
|
1 |
package junit.extensions.jfcunit;
|
|
2 |
|
|
3 |
import java.awt.AWTEvent;
|
|
4 |
import java.awt.Frame;
|
|
5 |
import java.awt.Toolkit;
|
|
6 |
import java.awt.Window;
|
|
7 |
import java.awt.event.AWTEventListener;
|
|
8 |
import java.awt.event.WindowEvent;
|
|
9 |
|
|
10 |
import java.util.ArrayList;
|
|
11 |
import java.lang.ref.WeakReference;
|
|
12 |
|
|
13 |
|
|
14 |
/**
|
|
15 |
* The WindowMonitor class is used to monitor for windows
|
|
16 |
* that might not show up in Frame.getFrames(). So we must watch for these
|
|
17 |
* windows to be opened.
|
|
18 |
*
|
|
19 |
* @author Kevin Wilson
|
|
20 |
* @author <a href="mailto:vraravam@thoughtworks.com">Vijay Aravamudhan : ThoughtWorks Inc.</a>
|
|
21 |
*/
|
|
22 |
public final class WindowMonitor implements AWTEventListener { |
|
23 |
/**
|
|
24 |
* A handle to this class instance.
|
|
25 |
*/
|
|
26 |
private static WindowMonitor s_singleton = null; |
|
27 |
|
|
28 |
/**
|
|
29 |
* The dispatch thread used to process the event queue.
|
|
30 |
*/
|
|
31 |
private static DispatchThread s_dt = null; |
|
32 |
|
|
33 |
/**
|
|
34 |
* Flag used to shutdown the window monitor.
|
|
35 |
*/
|
|
36 |
private static volatile boolean s_running = true; |
|
37 |
|
|
38 |
/**
|
|
39 |
* Event queue item or null if no pending items.
|
|
40 |
* The event queue is a linked list.
|
|
41 |
*/
|
|
42 |
private static WindowEventItem s_windowEventQueue = null; |
|
43 |
|
|
44 |
/**
|
|
45 |
* Lock for the event queue and dispatch thread.
|
|
46 |
*/
|
|
47 |
private static final Object QLOCK = new Object(); |
|
48 |
|
|
49 |
/**
|
|
50 |
* All Non-Popup Windows which have been found.
|
|
51 |
*/
|
|
52 |
private static final ArrayList WINDOWS = new ArrayList(); |
|
53 |
|
|
54 |
/**
|
|
55 |
* Constructor.
|
|
56 |
*
|
|
57 |
* Private use the static start() method.
|
|
58 |
*/
|
|
59 | 79 |
private WindowMonitor() {
|
60 | 79 |
super();
|
61 |
|
|
62 | 79 |
if (s_dt == null) { |
63 |
// Survey the current windows open.
|
|
64 | 79 |
Frame[] frames = Frame.getFrames(); |
65 |
|
|
66 | 79 |
for (int i = 0; i < frames.length; i++) { |
67 | 0 |
populateWindows(frames[i]); |
68 |
} |
|
69 |
|
|
70 | 79 |
s_dt = new DispatchThread("WindowMonitor-DispatchThread"); |
71 | 79 |
s_dt.setDaemon(true);
|
72 | 79 |
s_dt.start(); |
73 | 79 |
Toolkit.getDefaultToolkit().addAWTEventListener(this,
|
74 |
AWTEvent.WINDOW_EVENT_MASK); |
|
75 |
} |
|
76 |
} |
|
77 |
|
|
78 |
/**
|
|
79 |
* Get all of the windows which are open.
|
|
80 |
*
|
|
81 |
* @return Window[] containing all of the windows
|
|
82 |
* which have been instantiated.
|
|
83 |
*/
|
|
84 | 276 |
public static Window[] getWindows() { |
85 | 276 |
ArrayList v = new ArrayList();
|
86 | 276 |
ArrayList toRemove = new ArrayList();
|
87 | 276 |
for (int i = 0; i < WINDOWS.size(); i++) { |
88 | 516 |
WeakReference r = (WeakReference) WINDOWS.get(i); |
89 | 516 |
Window w = (Window) r.get(); |
90 | 516 |
if (w == null) { |
91 | 0 |
toRemove.add(r); |
92 |
} else {
|
|
93 | 516 |
v.add(w); |
94 |
} |
|
95 |
} |
|
96 | 276 |
WINDOWS.removeAll(toRemove); |
97 |
|
|
98 | 276 |
return (Window[]) v.toArray(new Window[0]); |
99 |
} |
|
100 |
|
|
101 |
/**
|
|
102 |
* Start the monitor.
|
|
103 |
*/
|
|
104 | 81 |
public static void start() { |
105 | 81 |
getSingleton(); |
106 |
} |
|
107 |
|
|
108 |
/**
|
|
109 |
* Stop the monitor.
|
|
110 |
*/
|
|
111 | 0 |
public static void stop() { |
112 | 0 |
getSingleton().stopInternal(); |
113 |
} |
|
114 |
|
|
115 |
/**
|
|
116 |
* Event dispatch implementation.
|
|
117 |
*
|
|
118 |
* @param theEvent AWTEvent which is to be processed.
|
|
119 |
*/
|
|
120 | 1775 |
public void eventDispatched(final AWTEvent theEvent) { |
121 | 1775 |
processEvent(theEvent); |
122 |
} |
|
123 |
|
|
124 |
/**
|
|
125 |
* return the singleton instance.
|
|
126 |
* If the singleton has not been created,
|
|
127 |
* then create one.
|
|
128 |
*
|
|
129 |
* @return WindowMonitor singleton instance.
|
|
130 |
*/
|
|
131 | 81 |
private static WindowMonitor getSingleton() { |
132 | 81 |
if (s_singleton == null) { |
133 | 79 |
s_singleton = new WindowMonitor();
|
134 |
} |
|
135 |
|
|
136 | 81 |
return s_singleton;
|
137 |
} |
|
138 |
|
|
139 |
/**
|
|
140 |
* Flush the AWT Event Queue.
|
|
141 |
*/
|
|
142 | 0 |
private static void flushAWT() { |
143 |
// Invoke the below to insure that we have flushed the queue
|
|
144 |
// of all current pending events.
|
|
145 | 0 |
if (Toolkit.getDefaultToolkit().getSystemEventQueue().isDispatchThread()) {
|
146 | 0 |
return;
|
147 |
} |
|
148 |
|
|
149 | 0 |
try {
|
150 | 0 |
Toolkit.getDefaultToolkit().getSystemEventQueue().invokeAndWait( |
151 |
new Runnable() {
|
|
152 | 0 |
public void run() { |
153 |
} |
|
154 |
}); |
|
155 |
} catch (Exception e) {
|
|
156 |
// don't do anything here
|
|
157 |
} |
|
158 |
} |
|
159 |
|
|
160 |
/**
|
|
161 |
* Populate frames.
|
|
162 |
* @param w Frame to be traversed.
|
|
163 |
*/
|
|
164 | 0 |
private static void populateWindows(final Window w) { |
165 | 0 |
WINDOWS.add(new WeakReference(w));
|
166 |
|
|
167 | 0 |
Window[] windows = w.getOwnedWindows(); |
168 |
|
|
169 | 0 |
for (int i = 0; i < windows.length; i++) { |
170 | 0 |
populateWindows(windows[i]); |
171 |
} |
|
172 |
} |
|
173 |
|
|
174 |
/**
|
|
175 |
* Processes the events by adding the event onto the
|
|
176 |
* event queue to be processed by the dispatch thread.
|
|
177 |
*
|
|
178 |
* @param theEvent The event to be processed.
|
|
179 |
*/
|
|
180 | 1775 |
private static void processEvent(final AWTEvent theEvent) { |
181 | 1775 |
switch (theEvent.getID()) {
|
182 | 309 |
case WindowEvent.WINDOW_OPENED:
|
183 | 297 |
case WindowEvent.WINDOW_ACTIVATED:
|
184 | 290 |
case WindowEvent.WINDOW_DEACTIVATED:
|
185 | 259 |
case WindowEvent.WINDOW_CLOSING:
|
186 | 1155 |
queueWindowEvent((WindowEvent) theEvent); |
187 |
|
|
188 | 1155 |
break;
|
189 |
|
|
190 | 620 |
default:
|
191 | 620 |
break;
|
192 |
} |
|
193 |
} |
|
194 |
|
|
195 |
/**
|
|
196 |
* Queue the event.
|
|
197 |
*
|
|
198 |
* @param we WindowEvent to be queued.
|
|
199 |
*/
|
|
200 | 1155 |
private static void queueWindowEvent(final WindowEvent we) { |
201 | 1155 |
synchronized (QLOCK) {
|
202 | 1155 |
WindowEventItem qi = new WindowEventItem(we);
|
203 |
|
|
204 | 1155 |
if (s_windowEventQueue == null) { |
205 | 1096 |
s_windowEventQueue = qi; |
206 |
} else {
|
|
207 | 59 |
WindowEventItem q = s_windowEventQueue; |
208 |
|
|
209 | 59 |
while (true) { |
210 | 96 |
if (q.getNext() != null) { |
211 | 37 |
q = q.getNext(); |
212 |
} else {
|
|
213 | 59 |
break;
|
214 |
} |
|
215 |
} |
|
216 |
|
|
217 | 59 |
q.setNext(qi); |
218 |
} |
|
219 |
|
|
220 | 1155 |
QLOCK.notifyAll(); |
221 |
} |
|
222 |
} |
|
223 |
|
|
224 |
/**
|
|
225 |
* Stop the window monitor.
|
|
226 |
*/
|
|
227 | 0 |
private void stopInternal() { |
228 | 0 |
s_running = false;
|
229 |
|
|
230 |
//dt.interrupt();
|
|
231 |
} |
|
232 |
|
|
233 |
/**
|
|
234 |
* Handle all Component events in a separate thread. The reason for
|
|
235 |
* this is that WindowEvents tend to be used to do lots of processing
|
|
236 |
* on the Window hierarchy. As a result, it can frequently result
|
|
237 |
* in deadlock situations.
|
|
238 |
*/
|
|
239 |
private class DispatchThread extends Thread { |
|
240 |
/**
|
|
241 |
* Constructor.
|
|
242 |
*
|
|
243 |
* @param name Name of the thread.
|
|
244 |
*/
|
|
245 | 79 |
public DispatchThread(final String name) {
|
246 | 79 |
super(name);
|
247 | 79 |
setDaemon(true);
|
248 |
} |
|
249 |
|
|
250 |
/**
|
|
251 |
* Run the Dispatch thread.
|
|
252 |
* Process the events recieved and track the windows.
|
|
253 |
*/
|
|
254 | 79 |
public void run() { |
255 | 79 |
WindowEvent we = null;
|
256 |
|
|
257 | 1234 |
while (s_running) {
|
258 | 1234 |
while (WindowMonitor.s_windowEventQueue == null) { |
259 | 3410 |
synchronized (WindowMonitor.QLOCK) {
|
260 | 3410 |
try {
|
261 | 3410 |
WindowMonitor.QLOCK.wait(500); |
262 |
} catch (ExitException exe) {
|
|
263 |
// don't do anything, but still catch it
|
|
264 |
} catch (InterruptedException e) {
|
|
265 |
// don't do anything, but still catch it
|
|
266 |
} |
|
267 |
} |
|
268 |
} |
|
269 |
|
|
270 | 1155 |
synchronized (WindowMonitor.QLOCK) {
|
271 | 1155 |
we = WindowMonitor.s_windowEventQueue |
272 |
.getEvent(); |
|
273 | 1155 |
WindowMonitor.s_windowEventQueue = WindowMonitor.s_windowEventQueue |
274 |
.getNext(); |
|
275 |
|
|
276 | 1155 |
switch (we.getID()) {
|
277 | 309 |
case WindowEvent.WINDOW_OPENED:
|
278 | 297 |
case WindowEvent.WINDOW_ACTIVATED:
|
279 | 290 |
case WindowEvent.WINDOW_DEACTIVATED:
|
280 |
|
|
281 | 896 |
if (!containsKey(we.getWindow())) {
|
282 | 309 |
WINDOWS.add( |
283 |
new WeakReference(we.getWindow()));
|
|
284 |
} |
|
285 |
|
|
286 | 896 |
break;
|
287 |
|
|
288 | 259 |
case WindowEvent.WINDOW_CLOSING:
|
289 | 259 |
remove(we.getWindow()); |
290 | 259 |
break;
|
291 |
|
|
292 | 0 |
default:
|
293 | 0 |
break;
|
294 |
} |
|
295 |
|
|
296 | 1155 |
try {
|
297 | 1155 |
WindowMonitor.QLOCK.notifyAll(); |
298 |
} catch (ExitException exe) {
|
|
299 |
// don't do anything, but still catch it
|
|
300 |
} |
|
301 |
} |
|
302 |
} |
|
303 |
} |
|
304 |
} |
|
305 |
|
|
306 |
/**
|
|
307 |
* WindowEventItem is the basic type that handles the
|
|
308 |
* queue for queueWindowEvent and the DispatchThread.
|
|
309 |
*/
|
|
310 |
private static class WindowEventItem { |
|
311 |
/**
|
|
312 |
* Event to be processed by the dispatch thread.
|
|
313 |
*/
|
|
314 |
private WindowEvent m_event;
|
|
315 |
|
|
316 |
/**
|
|
317 |
* Next event item to be processed. Null if no more.
|
|
318 |
*/
|
|
319 |
private WindowEventItem m_next;
|
|
320 |
|
|
321 |
/**
|
|
322 |
* Constructor.
|
|
323 |
*
|
|
324 |
* @param evt Event to construct the queue item for.
|
|
325 |
*/
|
|
326 | 1155 |
WindowEventItem(final WindowEvent evt) { |
327 | 1155 |
m_event = evt; |
328 | 1155 |
m_next = null;
|
329 |
} |
|
330 |
|
|
331 |
/**
|
|
332 |
* Get the event.
|
|
333 |
*
|
|
334 |
* @return the event.
|
|
335 |
*/
|
|
336 | 1155 |
public WindowEvent getEvent() {
|
337 | 1155 |
return m_event;
|
338 |
} |
|
339 |
|
|
340 |
/**
|
|
341 |
* Set the next entry.
|
|
342 |
*
|
|
343 |
* @param n next item.
|
|
344 |
*/
|
|
345 | 59 |
public void setNext(final WindowEventItem n) { |
346 | 59 |
m_next = n; |
347 |
} |
|
348 |
|
|
349 |
/**
|
|
350 |
* Get the next entry.
|
|
351 |
*
|
|
352 |
* @return WindowEventItem next item.
|
|
353 |
*/
|
|
354 | 1288 |
public WindowEventItem getNext() {
|
355 | 1288 |
return m_next;
|
356 |
} |
|
357 |
} |
|
358 |
|
|
359 |
/**
|
|
360 |
* Check to see if the key is in the current
|
|
361 |
* list.
|
|
362 |
*
|
|
363 |
* @param key Window to search for.
|
|
364 |
* @return boolean true if the window is in the list.
|
|
365 |
*/
|
|
366 | 896 |
private boolean containsKey(final Window key) { |
367 | 896 |
ArrayList toRemove = new ArrayList();
|
368 | 896 |
boolean result = false; |
369 | 896 |
for (int i = 0; i < WINDOWS.size() && !result; i++) { |
370 | 2188 |
WeakReference r = (WeakReference) WINDOWS.get(i); |
371 | 2188 |
Window w = (Window) r.get(); |
372 | 2188 |
if (w == null) { |
373 | 3 |
toRemove.add(r); |
374 | 2185 |
} else if (w == key) { |
375 | 587 |
result = true;
|
376 |
} |
|
377 |
} |
|
378 | 896 |
WINDOWS.removeAll(toRemove); |
379 | 896 |
return result;
|
380 |
} |
|
381 |
|
|
382 |
/**
|
|
383 |
* Remove the window from the list.
|
|
384 |
* @param key Window to be removed.
|
|
385 |
* @return Object Window which was removed.
|
|
386 |
*/
|
|
387 | 259 |
private Object remove(final Window key) {
|
388 | 259 |
ArrayList toRemove = new ArrayList();
|
389 | 259 |
Object result = null;
|
390 | 259 |
for (int i = 0; i < WINDOWS.size() && result == null; i++) { |
391 | 546 |
WeakReference r = (WeakReference) WINDOWS.get(i); |
392 | 546 |
Window w = (Window) r.get(); |
393 | 546 |
if (w == null) { |
394 | 0 |
toRemove.add(r); |
395 | 546 |
} else if (w == key) { |
396 | 258 |
toRemove.add(r); |
397 | 258 |
result = w; |
398 |
} |
|
399 |
} |
|
400 | 259 |
WINDOWS.removeAll(toRemove); |
401 | 259 |
return result;
|
402 |
} |
|
403 |
} |
|
404 |
|
|