001: /*
002: #IFNDEF ALT_LICENSE
003: ThinWire(R) RIA Ajax Framework
004: Copyright (C) 2003-2007 Custom Credit Systems
005:
006: This library is free software; you can redistribute it and/or modify it under
007: the terms of the GNU Lesser General Public License as published by the Free
008: Software Foundation; either version 2.1 of the License, or (at your option) any
009: later version.
010:
011: This library is distributed in the hope that it will be useful, but WITHOUT ANY
012: WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
013: PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
014:
015: You should have received a copy of the GNU Lesser General Public License along
016: with this library; if not, write to the Free Software Foundation, Inc., 59
017: Temple Place, Suite 330, Boston, MA 02111-1307 USA
018:
019: Users who would rather have a commercial license, warranty or support should
020: contact the following company who invented, built and supports the technology:
021:
022: Custom Credit Systems, Richardson, TX 75081, USA.
023: email: info@thinwire.com ph: +1 (888) 644-6405
024: http://www.thinwire.com
025: #ENDIF
026: [ v1.2_RC2 ]
027: */
028: package thinwire.ui;
029:
030: import java.util.ArrayList;
031: import java.util.Date;
032: import java.util.EventListener;
033: import java.util.EventObject;
034: import java.util.HashMap;
035: import java.util.HashSet;
036: import java.util.List;
037: import java.util.Map;
038: import java.util.Set;
039:
040: import thinwire.render.Renderer;
041: import thinwire.ui.event.*;
042:
043: /**
044: * @author Joshua J. Gertzen
045: */
046: class EventListenerImpl<E extends EventListener> {
047: private Map<E, Set<Object>> specificListeners;
048: private Class<E> type;
049: private Renderer renderer;
050: private Component comp;
051: private SubTypeValidator subTypeValidator;
052:
053: interface SubTypeValidator {
054: public Object validate(Object subType);
055: }
056:
057: static SubTypeValidator DEFAULT_VALIDATOR = new SubTypeValidator() {
058: public Object validate(Object subType) {
059: return subType != null && !subType.equals("") ? subType
060: : null;
061: }
062: };
063:
064: static final EventListenerImpl.SubTypeValidator ACTION_VALIDATOR = new EventListenerImpl.SubTypeValidator() {
065: public Object validate(Object subType) {
066: return subType != null
067: && (subType.equals(Component.ACTION_CLICK) || subType
068: .equals(Component.ACTION_DOUBLE_CLICK)) ? subType
069: : null;
070: }
071: };
072:
073: static final EventListenerImpl.SubTypeValidator KEY_PRESS_VALIDATOR = new EventListenerImpl.SubTypeValidator() {
074: public Object validate(Object subType) {
075: return KeyPressEvent
076: .normalizeKeyPressCombo((String) subType);
077: }
078: };
079:
080: static Class getSourceType(Component comp) {
081: Class clazz;
082:
083: if (comp instanceof GridBox) {
084: clazz = GridBox.Range.class;
085: } else if (comp instanceof DateBox) {
086: clazz = Date.class;
087: } else if (comp instanceof Tree) {
088: clazz = Tree.Item.class;
089: } else if (comp instanceof Menu) {
090: clazz = Menu.Item.class;
091: } else {
092: clazz = comp.getClass();
093: }
094:
095: return clazz;
096: }
097:
098: EventListenerImpl(Component comp, Class<E> type) {
099: this (comp, type, null, null);
100: }
101:
102: EventListenerImpl(Component comp, Class<E> type,
103: SubTypeValidator subTypeValidator) {
104: this (comp, type, subTypeValidator, null);
105: }
106:
107: EventListenerImpl(Component comp, Class<E> type,
108: SubTypeValidator subTypeValidator, EventListenerImpl<E> copy) {
109: this .subTypeValidator = subTypeValidator == null ? DEFAULT_VALIDATOR
110: : subTypeValidator;
111: this .type = type;
112:
113: if (copy != null && copy.hasListeners()) {
114: for (Map.Entry<E, Set<Object>> e : copy.specificListeners
115: .entrySet()) {
116: Set<Object> subTypes = e.getValue();
117:
118: if (subTypes == null) {
119: this .addListener(e.getKey());
120: } else {
121: E listener = e.getKey();
122:
123: for (Object subType : subTypes) {
124: this .addListener(subType, listener);
125: }
126: }
127: }
128: }
129:
130: this .comp = comp;
131: }
132:
133: private boolean hasListeners() {
134: return specificListeners != null
135: && specificListeners.size() > 0;
136: }
137:
138: void setRenderer(Renderer r) {
139: this .renderer = r;
140:
141: if (specificListeners != null && renderer != null) {
142: Set<Object> allSubTypes = new HashSet<Object>();
143:
144: for (Map.Entry<E, Set<Object>> e : specificListeners
145: .entrySet()) {
146: EventListener listener = e.getKey();
147:
148: //Do not process the renderer's listener
149: if (listener != r) {
150: Set<Object> subTypes = e.getValue();
151:
152: if (subTypes == null) {
153: allSubTypes.clear();
154: break;
155: } else {
156: allSubTypes.addAll(subTypes);
157: }
158: }
159: }
160:
161: if (allSubTypes.size() > 0)
162: renderer.eventSubTypeListenerInit(type, allSubTypes);
163: }
164: }
165:
166: void addListener(E listener) {
167: if (listener == null)
168: throw new IllegalArgumentException("listener == null");
169: addEventListener(null, listener);
170: }
171:
172: void addListener(Object eventSubType, E listener) {
173: if (listener == null)
174: throw new IllegalArgumentException("listener == null");
175: if ((eventSubType = subTypeValidator.validate(eventSubType)) == null)
176: throw new IllegalArgumentException(
177: "eventSubType is not valid:" + eventSubType);
178: addEventListener(eventSubType, listener);
179: }
180:
181: void addListener(Object[] eventSubTypes, E listener) {
182: if (listener == null)
183: throw new IllegalArgumentException("listener == null");
184: if (eventSubTypes == null || eventSubTypes.length == 0)
185: throw new IllegalArgumentException(
186: "eventSubTypes == null || eventSubTypes.length == 0");
187:
188: for (int i = eventSubTypes.length; --i >= 0;) {
189: if ((eventSubTypes[i] = subTypeValidator
190: .validate(eventSubTypes[i])) == null)
191: throw new IllegalArgumentException("eventSubType[" + i
192: + "] is not valid:" + eventSubTypes[i]);
193: }
194:
195: addEventListener(eventSubTypes, listener);
196: }
197:
198: private void addEventListener(Object eventSubType, E listener) {
199: if (listener == null)
200: throw new IllegalArgumentException("listener == null");
201: if (specificListeners == null)
202: specificListeners = new HashMap<E, Set<Object>>(3);
203:
204: //If no sub type specified, then add non-specific listener
205: if (eventSubType == null) {
206: if (specificListeners.containsKey(listener)) {
207: Set<Object> subTypes = specificListeners.get(listener);
208: if (subTypes != null)
209: throw new IllegalArgumentException(
210: "the specified listener has already been added for specific event types:"
211: + subTypes);
212: } else {
213: specificListeners.put(listener, null);
214: }
215: } else {
216: Set<Object> subTypes = specificListeners.get(listener);
217:
218: if (subTypes == null) {
219: if (specificListeners.containsKey(listener))
220: throw new IllegalArgumentException(
221: "the specified listener has already been added without specific event sub types");
222: subTypes = new HashSet<Object>(2);
223: specificListeners.put(listener, subTypes);
224: }
225:
226: if (eventSubType instanceof Object[]) {
227: for (Object subType : (Object[]) eventSubType) {
228: subTypes.add(subType);
229: if (renderer != null)
230: renderer.eventSubTypeListenerAdded(type,
231: subType);
232: }
233: } else {
234: subTypes.add(eventSubType);
235: if (renderer != null)
236: renderer.eventSubTypeListenerAdded(type,
237: eventSubType);
238: }
239: }
240: }
241:
242: void removeListener(E listener) {
243: if (listener == null)
244: throw new IllegalArgumentException("listener == null");
245: if (specificListeners == null)
246: return;
247: if (renderer == null) {
248: specificListeners.remove(listener);
249: } else {
250: outer: for (Object subType : specificListeners
251: .remove(listener)) {
252: //If there is another listener listening to the same sub type then we don't
253: //want to tell the renderer that the subtype is no longer being listened to.
254: for (Set<Object> subTypes : specificListeners.values()) {
255: if (subTypes.contains(subType))
256: continue outer;
257: }
258:
259: renderer.eventSubTypeListenerRemoved(type, subType);
260: }
261: }
262: }
263:
264: void firePropertyChange(Object source, String propertyName,
265: Object oldValue, Object newValue) {
266: if (!hasListeners() && renderer == null)
267: return;
268: PropertyChangeEvent pce = new PropertyChangeEvent(propertyName,
269: oldValue, newValue, comp, source);
270: if (renderer != null)
271: renderer.propertyChange(pce);
272: if (hasListeners())
273: fireEvent(pce, propertyName);
274: }
275:
276: void fireAction(ActionEvent ev) {
277: if (ev == null)
278: throw new IllegalArgumentException("ev == null");
279: if (comp != ev.getSourceComponent())
280: throw new IllegalArgumentException(
281: "this != ev.getSourceComponent()");
282: Class sourceType = getSourceType(ev.getSourceComponent());
283:
284: if (sourceType == null) {
285: if (ev.getSource() != ev.getSourceComponent())
286: throw new IllegalArgumentException(
287: "ev.getSource() != ev.getSourceComponent()");
288: } else {
289: if (!(sourceType.isInstance(ev.getSource())))
290: throw new IllegalArgumentException(
291: "!(ev.getSource() instanceof "
292: + sourceType.getName() + ")");
293: }
294:
295: if (!hasListeners())
296: return;
297: fireEvent(ev, ev.getAction());
298: }
299:
300: void fireDrop(DropEvent ev) {
301: if (ev == null)
302: throw new IllegalArgumentException("ev == null");
303: if (comp != ev.getSourceComponent())
304: throw new IllegalArgumentException(
305: "this != ev.getSourceComponent()");
306: Class sourceType = getSourceType(ev.getSourceComponent());
307:
308: if (sourceType == null) {
309: if (ev.getSource() != ev.getSourceComponent())
310: throw new IllegalArgumentException(
311: "ev.getSource() != ev.getSourceComponent()");
312: } else {
313: if (!(sourceType.isInstance(ev.getSource()))
314: && ev.getSource() != ev.getSourceComponent())
315: throw new IllegalArgumentException(
316: "!(ev.getSource() instanceof "
317: + sourceType.getName()
318: + ") && ev.getSource() != ev.getSourceComponent()");
319: }
320:
321: Class dragType = getSourceType(ev.getDragComponent());
322:
323: if (dragType == null) {
324: if (ev.getDragObject() != ev.getDragComponent())
325: throw new IllegalArgumentException(
326: "ev.getDragObject() != ev.getDragComponent()");
327: } else {
328: if (!(dragType.isInstance(ev.getDragObject()))
329: && ev.getSource() != ev.getSourceComponent())
330: throw new IllegalArgumentException(
331: "!(ev.getDragObject() instanceof "
332: + dragType.getName()
333: + ") && ev.getSource() != ev.getSourceComponent()");
334: }
335:
336: if (!hasListeners())
337: return;
338: fireEvent(ev, ev.getDragComponent());
339: }
340:
341: void fireKeyPress(KeyPressEvent kpe) {
342: if (!hasListeners())
343: return;
344: fireEvent(kpe, kpe.getKeyPressCombo());
345: }
346:
347: void fireItemChange(ItemChangeEvent.Type type, int columnIndex,
348: int rowIndex, Object oldValue, Object newValue) {
349: if (!hasListeners())
350: return;
351: ItemChangeEvent ice = new ItemChangeEvent(
352: (GridBox) comp,
353: type,
354: new GridBox.Range((GridBox) comp, columnIndex, rowIndex),
355: oldValue, newValue);
356: fireEvent(ice, null);
357: }
358:
359: void fireItemChange(HierarchyComponent.Item source,
360: ItemChangeEvent.Type type, int index, Object oldValue,
361: Object newValue) {
362: if (!hasListeners())
363: return;
364: ItemChangeEvent ice = new ItemChangeEvent(
365: (ItemChangeEventComponent) comp, source, type, index,
366: oldValue, newValue);
367: fireEvent(ice, null);
368: }
369:
370: private void fireEvent(EventObject eo, Object eventSubType) {
371: List<EventListener> listeners = new ArrayList<EventListener>(
372: specificListeners.size());
373:
374: for (Map.Entry<E, Set<Object>> e : specificListeners.entrySet()) {
375: Set<Object> subTypes = e.getValue();
376:
377: if (subTypes == null) {
378: listeners.add(e.getKey());
379: } else {
380: for (Object subType : subTypes) {
381: if (subType.equals(eventSubType)) {
382: listeners.add(e.getKey());
383: break;
384: }
385: }
386: }
387: }
388:
389: for (EventListener el : listeners) {
390: try {
391: if (eo instanceof PropertyChangeEvent)
392: ((PropertyChangeListener) el)
393: .propertyChange((PropertyChangeEvent) eo);
394: else if (eo instanceof ItemChangeEvent)
395: ((ItemChangeListener) el)
396: .itemChange((ItemChangeEvent) eo);
397: else if (eo instanceof ActionEvent)
398: ((ActionListener) el)
399: .actionPerformed((ActionEvent) eo);
400: else if (eo instanceof DropEvent)
401: ((DropListener) el).dropPerformed((DropEvent) eo);
402: else if (eo instanceof KeyPressEvent)
403: ((KeyPressListener) el)
404: .keyPress((KeyPressEvent) eo);
405: else {
406: if (el == null)
407: throw new IllegalStateException(
408: "EventListener is null"
409: + (eo == null ? ""
410: : ", event object type is: "
411: + eo
412: .getClass()
413: .getName()));
414: else if (eo == null)
415: throw new IllegalStateException(
416: "EventObject is null for event listener "
417: + el.getClass().getName());
418: else
419: throw new IllegalStateException(
420: "EventListener "
421: + el.getClass().getName()
422: + " is unsupported");
423: }
424: } catch (Throwable e) {
425: Application app = Application.current();
426: boolean gracefulShutdown = e
427: .getClass()
428: .getName()
429: .equals(
430: "thinwire.render.web.EventProcessor$GracefulShutdown");
431:
432: if (app == null || gracefulShutdown) {
433: if (e instanceof RuntimeException) {
434: throw (RuntimeException) e;
435: } else if (e instanceof Error) {
436: throw (Error) e;
437: } else {
438: throw new RuntimeException(e);
439: }
440: } else {
441: app.reportException(app, e);
442: }
443: }
444: }
445: }
446: }
|