001: /*
002: * The contents of this file are subject to the Mozilla Public License
003: * Version 1.1 (the "License"); you may not use this file except in
004: * compliance with the License. You may obtain a copy of the License at
005: * http://www.mozilla.org/MPL/
006: *
007: * Software distributed under the License is distributed on an "AS IS"
008: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
009: * License for the specific language governing rights and limitations
010: * under the License.
011: *
012: * The Original Code is iSQL-Viewer, A Mutli-Platform Database Tool.
013: *
014: * The Initial Developer of the Original Code is iSQL-Viewer, A Mutli-Platform Database Tool.
015: * Portions created by Mark A. Kobold are Copyright (C) 2000-2007. All Rights Reserved.
016: *
017: * Contributor(s):
018: * Mark A. Kobold [mkobold <at> isqlviewer <dot> com].
019: *
020: * If you didn't download this code from the following link, you should check
021: * if you aren't using an obsolete version: http://www.isqlviewer.com
022: */
023: package org.isqlviewer.swing.action;
024:
025: import java.awt.event.ActionEvent;
026: import java.awt.event.ActionListener;
027: import java.awt.event.FocusEvent;
028: import java.awt.event.FocusListener;
029: import java.awt.event.ItemEvent;
030: import java.awt.event.ItemListener;
031: import java.awt.event.MouseEvent;
032: import java.awt.event.MouseListener;
033: import java.lang.reflect.InvocationTargetException;
034: import java.lang.reflect.Method;
035: import java.util.EventListener;
036: import java.util.LinkedList;
037:
038: import javax.swing.Action;
039: import javax.swing.ActionMap;
040: import javax.swing.event.ChangeEvent;
041: import javax.swing.event.ChangeListener;
042: import javax.swing.event.EventListenerList;
043:
044: import org.apache.log4j.Logger;
045: import org.isqlviewer.util.IsqlToolkit;
046:
047: /**
048: * Event delegate system to process events outside of the standard swing thread.
049: * <p>
050: *
051: * @author Mark A. Kobold
052: * @version 1.0
053: */
054: public final class SwingEventManager implements ActionListener,
055: MouseListener, FocusListener, ChangeListener, ItemListener {
056:
057: private EventListenerList eventDelegates = new EventListenerList();
058: private Thread eventThread = null;
059: private final LinkedList<EventTask> taskHeap = new LinkedList<EventTask>();
060: private final ThreadGroup eventGroup;
061: private final EventLoop runLoop;
062: private final Logger logger = IsqlToolkit.getApplicationLogger();
063: private final ActionMap actionMap = new ActionMap();
064:
065: public SwingEventManager() {
066:
067: this ("isql-swing-loop");
068: }
069:
070: public SwingEventManager(String eventGroupName) {
071:
072: this .eventGroup = new ThreadGroup(eventGroupName);
073: this .runLoop = new EventLoop();
074: }
075:
076: public synchronized void stop() {
077:
078: if (eventThread != null)
079: eventThread.interrupt();
080: purgeTasks();
081: eventThread = null;
082: }
083:
084: public synchronized void start() {
085:
086: if (eventThread == null) {
087: eventThread = new Thread(eventGroup, runLoop,
088: "isql-swing-events");
089: eventThread.start();
090: } else {
091: notify();
092: }
093: }
094:
095: public void registerAction(String name, Action action) {
096:
097: actionMap.put(name, action);
098: }
099:
100: public Action getAction(String key) {
101:
102: return actionMap.get(key);
103: }
104:
105: /**
106: * @param renderer
107: */
108: public void enqueueRunnable(Runnable runnable) {
109:
110: if (runnable != null) {
111: enqueueEventTask(new RunnableEventTask(runnable));
112: }
113: }
114:
115: /**
116: * Adds an actionListener delegate to recieve ActionEvents from this manager.
117: * <p>
118: *
119: * @param listener actionLister to add for processing actionEvents.
120: */
121: public void addActionListener(ActionListener listener) {
122:
123: eventDelegates.add(ActionListener.class, listener);
124: }
125:
126: /**
127: * Removes an actionListener delegate to stop recieving ActionEvents from this manager.
128: * <p>
129: *
130: * @param listener actionLister to remove from processing ActionEvents.
131: */
132: public void removeActionListener(ActionListener listener) {
133:
134: eventDelegates.remove(ActionListener.class, listener);
135: }
136:
137: /**
138: * Adds an changeListener delegate to recieve ChangeEvents from this manager.
139: * <p>
140: *
141: * @param listener changeLister to add for processing ChangeEvents.
142: */
143: public void addChangeListener(ChangeListener listener) {
144:
145: eventDelegates.add(ChangeListener.class, listener);
146: }
147:
148: /**
149: * Removes a changeListener delegate to stop recieving ChangeEvents from this manager.
150: * <p>
151: *
152: * @param listener changeLister to remove from processing ChangeEvents.
153: */
154: public void removeChangeListener(ChangeListener listener) {
155:
156: eventDelegates.remove(ChangeListener.class, listener);
157: }
158:
159: /**
160: * Adds an itemListener delegate to recieve ItemEvents from this manager.
161: * <p>
162: *
163: * @param listener itemLister to add for processing ItemEvents.
164: */
165: public void addItemListener(ItemListener listener) {
166:
167: eventDelegates.add(ItemListener.class, listener);
168: }
169:
170: /**
171: * Removes an itemListener delegate to stop recieving ItemEvents from this manager.
172: * <p>
173: *
174: * @param listener itemLister to remove from processing ItemEvents.
175: */
176: public void removeItemListener(ItemListener listener) {
177:
178: eventDelegates.remove(ItemListener.class, listener);
179: }
180:
181: /**
182: * Adds a focusListener delegate to recieve FocusEvents from this manager.
183: * <p>
184: *
185: * @param listener focusLister to add for processing FocusEvents.
186: */
187: public void addFocusListener(FocusListener listener) {
188:
189: eventDelegates.add(FocusListener.class, listener);
190: }
191:
192: /**
193: * Removes a focusListener delegate to stop recieving FocusEvents from this manager.
194: * <p>
195: *
196: * @param listener focusLister to remove from processing FocusEvents.
197: */
198: public void removeFocusListener(FocusListener listener) {
199:
200: eventDelegates.remove(FocusListener.class, listener);
201: }
202:
203: public void focusGained(FocusEvent event) {
204:
205: EventTask eventTask = new EventTask(FocusListener.class,
206: "focusGained", event);
207: enqueueEventTask(eventTask);
208: }
209:
210: public void focusLost(FocusEvent event) {
211:
212: EventTask eventTask = new EventTask(FocusListener.class,
213: "focusLost", event);
214: enqueueEventTask(eventTask);
215: }
216:
217: public void actionPerformed(ActionEvent event) {
218:
219: EventTask eventTask = new EventTask(ActionListener.class,
220: "actionPerformed", event);
221: enqueueEventTask(eventTask);
222: }
223:
224: public void itemStateChanged(ItemEvent event) {
225:
226: EventTask eventTask = new EventTask(ItemListener.class,
227: "itemStateChanged", event);
228: enqueueEventTask(eventTask);
229:
230: }
231:
232: public void stateChanged(ChangeEvent event) {
233:
234: EventTask eventTask = new EventTask(ChangeListener.class,
235: "stateChanged", event);
236: enqueueEventTask(eventTask);
237: }
238:
239: public void mouseClicked(MouseEvent e) {
240:
241: }
242:
243: public void mouseEntered(MouseEvent e) {
244:
245: }
246:
247: public void mouseExited(MouseEvent e) {
248:
249: }
250:
251: public void mousePressed(MouseEvent e) {
252:
253: }
254:
255: public void mouseReleased(MouseEvent e) {
256:
257: }
258:
259: protected synchronized void enqueueEventTask(EventTask task) {
260:
261: synchronized (taskHeap) {
262: taskHeap.addLast(task);
263: }
264: start();
265: }
266:
267: protected void purgeTasks() {
268:
269: synchronized (taskHeap) {
270: while (taskHeap.size() > 0) {
271: try {
272: taskHeap.removeFirst();
273: } catch (Exception e) {
274: }
275: }
276: }
277: }
278:
279: protected synchronized EventTask nextTask() {
280:
281: try {
282: while (!Thread.interrupted()) {
283:
284: EventTask task = null;
285: if (!taskHeap.isEmpty()) {
286: task = taskHeap.removeFirst();
287: }
288:
289: if (task == null) {
290: wait();
291: } else {
292: return task;
293: }
294: }
295: } catch (InterruptedException ex) {
296: } // fall through
297: return null; // on interrupt
298: }
299:
300: /** set thread_ to null to indicate termination * */
301: protected synchronized void clearThread() {
302:
303: eventThread = null;
304: }
305:
306: protected class EventLoop implements Runnable {
307:
308: public void run() {
309:
310: try {
311: for (;;) {
312: EventTask task = nextTask();
313: if (task == null) {
314: break;
315: }
316: if (task instanceof Runnable) {
317: Runnable runnableTask = (Runnable) task;
318: try {
319: runnableTask.run();
320: } catch (Throwable t) {
321: logger.error("Error dispatching event", t);
322: }
323: } else {
324: // normal event.
325: delegateEvent(task);
326: }
327: }
328: } finally {
329: System.runFinalization();
330: clearThread();
331: }
332: }
333:
334: private void delegateEvent(EventTask task) {
335:
336: Method method = task.getMethod();
337: if (method == null) {
338: return;
339: }
340:
341: EventListener[] delegates = eventDelegates
342: .getListeners(task.getEventClass());
343: Object[] eventParameters = new Object[] { task
344: .getEventObject() };
345: for (int i = 0; i < delegates.length; i++) {
346: EventListener listener = delegates[i];
347: try {
348: method.invoke(listener, eventParameters);
349: } catch (InvocationTargetException err) {
350: logger.error("error dispatching event", err
351: .getTargetException());
352: } catch (Throwable t) {
353: logger.error("Error dispatching event", t);
354: }
355: }
356: }
357: }
358:
359: }
|