001: package net.xoetrope.xui;
002:
003: import java.lang.reflect.Method;
004: import java.util.Hashtable;
005:
006: import java.awt.AWTEvent;
007: import java.awt.Component;
008: import java.awt.Container;
009: import java.awt.event.ActionEvent;
010: import java.awt.event.ActionListener;
011: import java.awt.event.FocusEvent;
012: import java.awt.event.FocusListener;
013: import java.awt.event.ItemEvent;
014: import java.awt.event.ItemListener;
015: import java.awt.event.KeyEvent;
016: import java.awt.event.KeyListener;
017: import java.awt.event.MouseEvent;
018: import java.awt.event.MouseListener;
019: import java.awt.event.MouseMotionListener;
020: import java.awt.event.TextEvent;
021: import java.awt.event.TextListener;
022:
023: import net.xoetrope.debug.DebugLogger;
024: import net.xoetrope.xui.validation.XValidationHandler;
025: import net.xoetrope.xui.validation.XValidator;
026:
027: /**
028: * <p>Implements an event handler for XUI. Most of the common events
029: * are handled. The class is intended as a mixin for a panel class such as
030: * XPage and should not be used directly</p>
031: * <p>Copyright (c) Xoetrope Ltd., 2002-2003</p>
032: * <p>License: see license.txt</p>
033: * $Revision: 1.24 $
034: */
035: public class XEventHandler implements ActionListener, FocusListener,
036: TextListener, ItemListener, KeyListener, MouseListener,
037: MouseMotionListener {
038: protected static AWTEvent currentEvt;
039: protected Container container;
040: protected Hashtable handlers;
041: protected static Component mouseDownComponent = null;
042: protected static boolean mouseEventInvoked = false;
043: protected static int suppressFocusEvents = 0;
044: protected XValidationHandler xValidationHandler;
045:
046: public XEventHandler(Container c, XValidationHandler vh) {
047: handlers = new Hashtable(5);
048:
049: container = c;
050: xValidationHandler = vh;
051:
052: xValidationHandler.setEventHandler(this );
053: }
054:
055: /**
056: * Invokes an event. Called in response to an event. If a handler has been
057: * added for the event it will be invoked.
058: * @param evt the event object
059: */
060: protected void invoke(long eventType, AWTEvent evt) {
061: // If necessary first check for presence of a validation event handler
062: // the method name will be "validationHandler" and stop event dispatch if an
063: // error has occurred.
064: try {
065: currentEvt = evt;
066: if (xValidationHandler.validationHandler() > XValidator.LEVEL_WARNING)
067: return;
068:
069: // Then call any other event handler
070: Method m = (Method) handlers.get(new Long(eventType
071: * evt.getSource().hashCode()));
072: try {
073: if ((m != null)
074: && (m.getName().compareTo("validationHandler") != 0))
075: m.invoke(container, null);
076: } catch (Exception e) {
077: DebugLogger.logWarning("error invoking '" + m.getName()
078: + "' in XEventHandler");
079: e.printStackTrace();
080: }
081: currentEvt = null;
082: } catch (Exception ex) {
083: System.out.println("Error invoking");
084: }
085: }
086:
087: /**
088: * Lookup an event for a component.
089: * @param evt the event object
090: */
091: public Method findEvent(Component src, long eventType) {
092: return (Method) handlers.get(new Long(eventType
093: * src.hashCode()));
094: }
095:
096: /**
097: * Check the focus change status
098: * @return true if the focus change events are being suppressed.
099: */
100: public boolean isFocusChangeSuppressed() {
101: return suppressFocusEvents > 0;
102: }
103:
104: /**
105: * Get the current event
106: * @return the AWTEvent that was last triggered
107: */
108: public AWTEvent getCurrentEvent() {
109: return currentEvt;
110: }
111:
112: /**
113: * Adds an event handler. A specific handler such as the addActionHandler should
114: * be used instead of calling this method
115: * @param comp the component that fires the event
116: * @param methodName the method to be invoked in response to the object
117: */
118: public void addHandler(Object comp, long eventType,
119: String methodName) throws Exception {
120: try {
121: Method m = container.getClass().getMethod(methodName, null);
122: long hashCode = comp.hashCode();
123: if (comp instanceof XHashCode)
124: hashCode = ((XHashCode) comp).getComponentHashCode();
125: handlers.put(new Long(eventType * hashCode), m);
126: } catch (NoSuchMethodException ex) {
127: throw new Exception("Could not locate method '"
128: + methodName + "'");
129: } catch (SecurityException ex) {
130: throw new Exception("Access to method '" + methodName
131: + "' not permitted");
132: }
133: }
134:
135: /**
136: * Adds a listener for an event type. This method should not normally be
137: * called by an application
138: * @param comp the component that fires events
139: * @param listenerName the name of the listener interface
140: * @param argType the listener arguments
141: */
142: public void addListener(Object comp, String listenerName,
143: String argType) {
144: try {
145: Class params[] = new Class[1];
146: params[0] = Class.forName(argType);
147: Method m = comp.getClass().getMethod(listenerName, params);
148: Object args[] = new Object[1];
149: args[0] = this ;
150: m.invoke(comp, args);
151: } catch (Exception e) {
152: e.printStackTrace();
153: }
154: }
155:
156: /**
157: * Adds a handler for action events
158: * @param menuItem the menu item that fires the events
159: * @param methodName the method to be invoked in response to the action event
160: * @see java.awt.event.ActionListener
161: * @see java.awt.event.ActionEvent
162: */
163: public void addMenuHandler(Object menuItem, String methodName) {
164: addListener(menuItem, "addActionListener",
165: "java.awt.event.ActionListener");
166: try {
167: addHandler(menuItem, AWTEvent.ACTION_EVENT_MASK, methodName);
168: } catch (Exception ex) {
169: ex.printStackTrace();
170: }
171: }
172:
173: /**
174: * Adds a handler for action events
175: * @param comp the component that fires the events
176: * @param methodName the method to be invoked in response to the action event
177: * @see java.awt.event.ActionListener
178: * @see java.awt.event.ActionEvent
179: */
180: public void addActionHandler(Component comp, String methodName) {
181: addListener(comp, "addActionListener",
182: "java.awt.event.ActionListener");
183: try {
184: addHandler(comp, AWTEvent.ACTION_EVENT_MASK, methodName);
185: } catch (Exception ex) {
186: ex.printStackTrace();
187: }
188: }
189:
190: /**
191: * Adds a handler for focus events
192: * @param comp the component that fires the events
193: * @param methodName the method to be invoked in response to the focus event
194: * @see java.awt.event.FocusListener
195: * @see java.awt.event.FocusEvent
196: */
197: public void addFocusHandler(Component comp, String methodName) {
198: addListener(comp, "addFocusListener",
199: "java.awt.event.FocusListener");
200: try {
201: addHandler(comp, AWTEvent.FOCUS_EVENT_MASK, methodName);
202: } catch (Exception ex) {
203: ex.printStackTrace();
204: }
205: }
206:
207: /**
208: * Adds a handler for text events
209: * @param comp the component that fires the events
210: * @param methodName the method to be invoked in response to the text event
211: * @see java.awt.event.TextListener
212: * @see java.awt.event.TextEvent
213: */
214: public void addTextHandler(Component comp, String methodName) {
215: addListener(comp, "addTextListener",
216: "java.awt.event.TextListener");
217: try {
218: addHandler(comp, AWTEvent.TEXT_EVENT_MASK, methodName);
219: } catch (Exception ex) {
220: ex.printStackTrace();
221: }
222: }
223:
224: /**
225: * Adds a handler for item events
226: * @param comp the component that fires the events
227: * @param methodName the method to be invoked in response to the item event
228: * @see java.awt.event.ItemListener
229: * @see java.awt.event.ItemEvent
230: */
231: public void addItemHandler(Component comp, String methodName) {
232: addListener(comp, "addItemListener",
233: "java.awt.event.ItemListener");
234: try {
235: addHandler(comp, AWTEvent.ITEM_EVENT_MASK, methodName);
236: } catch (Exception ex) {
237: ex.printStackTrace();
238: }
239: }
240:
241: /**
242: * Adds a handler for key events
243: * @param comp the component that fires the events
244: * @param methodName the method to be invoked in response to the key event
245: * @see java.awt.event.KeyListener
246: * @see java.awt.event.KeyEvent
247: */
248: public void addKeyHandler(Component comp, String methodName) {
249: addListener(comp, "addKeyListener",
250: "java.awt.event.KeyListener");
251: try {
252: addHandler(comp, AWTEvent.KEY_EVENT_MASK, methodName);
253: } catch (Exception ex) {
254: ex.printStackTrace();
255: }
256: }
257:
258: /**
259: * Adds a handler for mouse events
260: * @param comp the component that fires the events
261: * @param methodName the method to be invoked in response to the mouse event
262: * @see java.awt.event.MouseMotionListener
263: * @see java.awt.event.MouseEvent
264: */
265: public void addMouseHandler(Component comp, String methodName) {
266: addListener(comp, "addMouseListener",
267: "java.awt.event.MouseListener");
268: try {
269: addHandler(comp, AWTEvent.MOUSE_EVENT_MASK, methodName);
270: } catch (Exception ex) {
271: ex.printStackTrace();
272: }
273: }
274:
275: /**
276: * Adds a handler for mouse motion events
277: * @param comp the component that fires the events
278: * @param methodName the method to be invoked in response to the mouse event
279: * @see java.awt.event.MouseMotionListener
280: * @see java.awt.event.MouseEvent
281: */
282: public void addMouseMotionHandler(Component comp, String methodName) {
283: addListener(comp, "addMouseMotionListener",
284: "java.awt.event.MouseMotionListener");
285: try {
286: addHandler(comp, AWTEvent.MOUSE_MOTION_EVENT_MASK,
287: methodName);
288: } catch (Exception ex) {
289: ex.printStackTrace();
290: }
291: }
292:
293: /**
294: * A utility method used to determine if the last event corrseponds to a mouse
295: * click. The notion of a click is extended by assuming the a mouse press and
296: * release within a single component constitutes a click even if not at the
297: * same coordinate. A MouseEvent.MOUSE_CLICKED is only triggered when the press
298: * and release are at the same location and this is often inadequate for end-user
299: * interaction.
300: * @return true if the mouse was clicked
301: */
302: public boolean wasMouseClicked() {
303: if (currentEvt != null) {
304: if ((currentEvt.getID() == MouseEvent.MOUSE_CLICKED)
305: || ((currentEvt.getID() == MouseEvent.MOUSE_RELEASED) && (((Component) currentEvt
306: .getSource()) == mouseDownComponent))) {
307: mouseDownComponent = null;
308: return true;
309: }
310: }
311:
312: mouseEventInvoked = true;
313: return false;
314: }
315:
316: /**
317: * A utility method used to determine if the last event corrseponds to a mouse
318: * double click. The notion of a click is extended by assuming the a mouse press and
319: * release within a single component constitutes a click even if not at the
320: * same coordinate. A MouseEvent.MOUSE_CLICKED is only triggered when the press
321: * and release are at the same location and this is often inadequate for end-user
322: * interaction.
323: * @return true if the mouse was double clicked
324: */
325: public boolean wasMouseDoubleClicked() {
326: if (currentEvt != null) {
327: if ((currentEvt.getID() == MouseEvent.MOUSE_CLICKED)
328: || ((currentEvt.getID() == MouseEvent.MOUSE_RELEASED) && (((Component) currentEvt
329: .getSource()) == mouseDownComponent))
330: && (((MouseEvent) currentEvt).getModifiers() & MouseEvent.BUTTON1_MASK) != 0
331: && (((MouseEvent) currentEvt).getClickCount() == 2)) {
332: mouseDownComponent = null;
333: return true;
334: }
335: }
336: mouseEventInvoked = true;
337: return false;
338: }
339:
340: /**
341: * A utility method used to determine if the last event corrseponds to a mouse
342: * right click. The notion of a click is extended by assuming the a mouse press and
343: * release within a single component constitutes a click even if not at the
344: * same coordinate. A MouseEvent.MOUSE_CLICKED is only triggered when the press
345: * and release are at the same location and this is often inadequate for end-user
346: * interaction.
347: * @return true if the mouse was right clicked
348: */
349: public boolean wasMouseRightClicked() {
350: if (currentEvt != null) {
351: if ((currentEvt.getID() == MouseEvent.MOUSE_CLICKED)
352: || ((currentEvt.getID() == MouseEvent.MOUSE_RELEASED) && (((Component) currentEvt
353: .getSource()) == mouseDownComponent))
354: && (((MouseEvent) currentEvt).getModifiers() & MouseEvent.BUTTON3_MASK) != 0) {
355: mouseDownComponent = null;
356: return true;
357: }
358: }
359: mouseEventInvoked = true;
360: return false;
361: }
362:
363: //----------------------------------------------------------------------------
364: public void actionPerformed(ActionEvent e) {
365: invoke(AWTEvent.ACTION_EVENT_MASK, e);
366: }
367:
368: public void focusGained(FocusEvent e) {
369: // The suppressFocusEvents flag is used as poping up a message dialog causes
370: // input fields to loose focus. This in turn could cause a continuous loop
371: // of validation errors - messages - loss of focus - validations - validation errors
372: if (suppressFocusEvents < 2) {
373: invoke(AWTEvent.FOCUS_EVENT_MASK, e);
374: if (suppressFocusEvents == 1) {
375: suppressFocusEvents++;
376: }
377: }
378: }
379:
380: public void focusLost(FocusEvent e) {
381: if (suppressFocusEvents == 0) {
382: invoke(AWTEvent.FOCUS_EVENT_MASK, e);
383: }
384: }
385:
386: public void textValueChanged(TextEvent e) {
387: invoke(AWTEvent.TEXT_EVENT_MASK, e);
388: }
389:
390: public void itemStateChanged(ItemEvent e) {
391: invoke(AWTEvent.ITEM_EVENT_MASK, e);
392: }
393:
394: public void keyPressed(KeyEvent e) {
395: invoke(AWTEvent.KEY_EVENT_MASK, e);
396: }
397:
398: public void keyReleased(KeyEvent e) {
399: invoke(AWTEvent.KEY_EVENT_MASK, e);
400: }
401:
402: public void keyTyped(KeyEvent e) {
403: invoke(AWTEvent.KEY_EVENT_MASK, e);
404: }
405:
406: public void mouseClicked(MouseEvent e) {
407: if (!mouseEventInvoked)
408: invoke(AWTEvent.MOUSE_EVENT_MASK, e);
409: }
410:
411: public void mouseEntered(MouseEvent e) {
412: invoke(AWTEvent.MOUSE_EVENT_MASK, e);
413: }
414:
415: public void mouseExited(MouseEvent e) {
416: invoke(AWTEvent.MOUSE_EVENT_MASK, e);
417: }
418:
419: public void mousePressed(MouseEvent e) {
420: mouseDownComponent = e.getComponent();
421: mouseEventInvoked = false;
422: invoke(AWTEvent.MOUSE_EVENT_MASK, e);
423: }
424:
425: public void mouseReleased(MouseEvent e) {
426: invoke(AWTEvent.MOUSE_EVENT_MASK, e);
427: }
428:
429: public void mouseMoved(MouseEvent e) {
430: invoke(AWTEvent.MOUSE_MOTION_EVENT_MASK, e);
431: }
432:
433: public void mouseDragged(MouseEvent e) {
434: invoke(AWTEvent.MOUSE_MOTION_EVENT_MASK, e);
435: }
436:
437: //----------------------------------------------------------------------------
438:
439: /**
440: * Used by messageboxes and other dialogs to prevent the display of the dialog
441: * causing extra focus events from being fired.
442: * @param suppress true to suppress focus events
443: */
444: public void suppressFocusEvents(boolean suppress) {
445: if (suppress)
446: suppressFocusEvents++;
447: else
448: suppressFocusEvents = Math.max(--suppressFocusEvents, 0);
449: }
450: }
|