001: /* Events.java
002:
003: {{IS_NOTE
004: Purpose:
005:
006: Description:
007:
008: History:
009: Fri Jul 22 15:49:51 2005, Created by tomyeh
010: }}IS_NOTE
011:
012: Copyright (C) 2005 Potix Corporation. All Rights Reserved.
013:
014: {{IS_RIGHT
015: This program is distributed under GPL Version 2.0 in the hope that
016: it will be useful, but WITHOUT ANY WARRANTY.
017: }}IS_RIGHT
018: */
019: package org.zkoss.zk.ui.event;
020:
021: import java.util.Set;
022:
023: import org.zkoss.lang.D;
024:
025: import org.zkoss.zk.ui.Desktop;
026: import org.zkoss.zk.ui.Page;
027: import org.zkoss.zk.ui.Component;
028: import org.zkoss.zk.ui.Execution;
029: import org.zkoss.zk.ui.Executions;
030: import org.zkoss.zk.ui.UiException;
031: import org.zkoss.zk.ui.sys.ExecutionCtrl;
032: import org.zkoss.zk.ui.sys.DesktopCtrl;
033: import org.zkoss.zk.ui.sys.ComponentCtrl;
034: import org.zkoss.zk.ui.sys.ComponentsCtrl;
035: import org.zkoss.zk.ui.sys.EventProcessingThread;
036: import org.zkoss.zk.ui.impl.EventProcessor;
037: import org.zkoss.zk.au.AuRequest;
038: import org.zkoss.zk.au.out.AuEcho;
039: import org.zkoss.zk.ui.util.Clients;
040:
041: /**
042: * Utilities to handle events.
043: *
044: * @author tomyeh
045: */
046: public class Events {
047: private Events() {
048: } //prevent from creation
049:
050: /** The onClick event (used with {@link MouseEvent}).
051: */
052: public static final String ON_CLICK = "onClick";
053: /** The onRightClick event (used with {@link MouseEvent}).
054: */
055: public static final String ON_RIGHT_CLICK = "onRightClick";
056: /** The onDoubleClick event (used with {@link MouseEvent}).
057: */
058: public static final String ON_DOUBLE_CLICK = "onDoubleClick";
059: /** The onOK event (used with {@link KeyEvent}).
060: */
061: public static final String ON_OK = "onOK";
062: /** The onCancel event (used with {@link KeyEvent}).
063: */
064: public static final String ON_CANCEL = "onCancel";
065: /** The onCtrlKey event (used with {@link KeyEvent}).
066: */
067: public static final String ON_CTRL_KEY = "onCtrlKey";
068: /** The onChange event (used with {@link InputEvent}).
069: */
070: public static final String ON_CHANGE = "onChange";
071: /** The onChanging event (used with {@link InputEvent}).
072: */
073: public static final String ON_CHANGING = "onChanging";
074: /** The onError event (used with {@link ErrorEvent}).
075: */
076: public static final String ON_ERROR = "onError";
077: /** The onScroll event (used with {@link ScrollEvent}).
078: */
079: public static final String ON_SCROLL = "onScroll";
080: /** The onScrolling event (used with {@link ScrollEvent}).
081: */
082: public static final String ON_SCROLLING = "onScrolling";
083: /** The onSelect event (used with {@link SelectEvent}).
084: */
085: public static final String ON_SELECT = "onSelect";
086: /** The onSelection event (used with {@link SelectionEvent}).
087: */
088: public static final String ON_SELECTION = "onSelection";
089: /** The onCheck event (used with {@link CheckEvent}).
090: */
091: public static final String ON_CHECK = "onCheck";
092: /** The onMove event (used with {@link MoveEvent}).
093: */
094: public static final String ON_MOVE = "onMove";
095: /** The onSize event (used with {@link SizeEvent}).
096: */
097: public static final String ON_SIZE = "onSize";
098: /** The onZIndex event (used with {@link ZIndexEvent}).
099: */
100: public static final String ON_Z_INDEX = "onZIndex";
101: /** The onOpen event (used with {@link OpenEvent}).
102: */
103: public static final String ON_OPEN = "onOpen";
104: /** The onClose event (used with {@link Event})
105: * used to denote the close button is pressed.
106: */
107: public static final String ON_CLOSE = "onClose";
108: /** The onRender event (used with {@link org.zkoss.zk.ui.ext.client.RenderOnDemand}).
109: */
110: public static final String ON_RENDER = "onRender";
111: /** The onTimer event (used with {@link Event}).
112: * Sent when a timer is up.
113: */
114: public static final String ON_TIMER = "onTimer";
115: /** The onFocus event (used with {@link Event}).
116: * Sent when a component gets a focus.
117: */
118: public static final String ON_FOCUS = "onFocus";
119: /** The onBlur event (used with {@link Event}).
120: * Sent when a component loses a focus.
121: */
122: public static final String ON_BLUR = "onBlur";
123: /** The onDrop event (used with {@link DropEvent}).
124: * Sent when a component is dragged and drop to another.
125: */
126: public static final String ON_DROP = "onDrop";
127: /** The onNotify event (used with {@link Event}).
128: * It is not used by any component, but it is, rather, designed to
129: * let users add customized events.
130: */
131: public static final String ON_NOTIFY = "onNotify";
132: /** The onSort event (used with {@link Event})
133: * to notify a request for sorting.
134: */
135: public static final String ON_SORT = "onSort";
136: /** The onUpload event (used with {@link UploadEvent}.
137: */
138: public static final String ON_UPLOAD = "onUpload";
139: /** The onBookmarkChanged event (used with {@link BookmarkEvent})
140: * to notify that user pressed BACK, FORWARD or specified URL directly
141: * that causes the bookmark is changed (but still in the same desktop).
142: * <p>All root components of all pages of the desktop will
143: * recieve this event.
144: */
145: public static final String ON_BOOKMARK_CHANGED = "onBookmarkChanged";
146: /** The onClientInfo event (used with {@link ClientInfoEvent}).
147: */
148: public static final String ON_CLIENT_INFO = "onClientInfo";
149:
150: /** The onCreate event (used with {@link CreateEvent}) to notify a compoent
151: * that it (and its children) has been created by ZK's evaluating a ZUML page.
152: */
153: public static final String ON_CREATE = "onCreate";
154: /** The onModal event (used with {@link Event}) to notify a component
155: * shall become modal. Currently, only ZUL's window components support it.
156: */
157: public static final String ON_MODAL = "onModal";
158: /** The onPiggyback event (used with {@link Event}) used to notify
159: * a root component that the client has sent a request to the server.
160: * It is meaningful only if it is registered to the root component.
161: * Once registered, it is called
162: * each time the client sends a request to the server.
163: * The onPiggyback's event listener is processed after all other
164: * events are processed.
165: *
166: * <p>The onPiggyback event is designed to let developers piggyback
167: * the least-emergent UI updates to the client.
168: *
169: * @since 2.4.0
170: */
171: public static final String ON_PIGGYBACK = "onPiggyback";
172:
173: /** The onUser event. It is a generic event that an application developer
174: * might send from the client. ZK doesn't use this event.
175: */
176: public static final String ON_USER = "onUser";
177:
178: /** Returns whether an event name is valid.
179: *
180: * <p>The event name must start with on and the third character
181: * must be upper case.
182: */
183: public static final boolean isValid(String name) {
184: return name != null && name.length() > 2
185: && name.charAt(0) == 'o' && name.charAt(1) == 'n'
186: && Character.isUpperCase(name.charAt(2));
187: }
188:
189: /** Returns whether the current thread is an event listener.
190: */
191: public static final boolean inEventListener() {
192: return EventProcessor.inEventListener();
193: }
194:
195: /** Returns whether an event handler or listener is available for
196: * the specified component and event.
197: *
198: * <p>A event handler is either a public method named onXxx or
199: * a ZUL attribute named onXxx, where onXxx is the event name.
200: * A event listener is {@link EventListener} being added
201: * by {@link Component#addEventListener} and {@link Page#addEventListener}.
202: *
203: * <p>Unlike {@link Component#isListenerAvailable}, which checks
204: * only the event listener, this method
205: * check both event handlers and listeners, i.e.,
206: * the onXxx members defined in ZUML, the onXxx method defined
207: * in the implementation class, and the event listener registered.
208: *
209: * @param asap whether to check only non-deferrable listener,
210: * i.e., not implementing {@link org.zkoss.zk.ui.event.Deferrable},
211: * or {@link org.zkoss.zk.ui.event.Deferrable#isDeferrable} is false.
212: * @see org.zkoss.zk.ui.event.Deferrable
213: * @see Component#isListenerAvailable
214: */
215: public static boolean isListened(Component comp, String evtnm,
216: boolean asap) {
217: if (((ComponentCtrl) comp).getEventHandler(evtnm) != null)
218: return true;
219:
220: if (ComponentsCtrl.getEventMethod(comp.getClass(), evtnm) != null
221: || comp.isListenerAvailable(evtnm, asap))
222: return true;
223:
224: if (!asap) {
225: final Page page = comp.getPage();
226: return page != null && page.isListenerAvailable(evtnm);
227: }
228: return false;
229: }
230:
231: /** Returns whether an event handler or listener is available for
232: * the specified component and event.
233: *
234: * @deprecated As of release 2.4.0, replaced by {@link #isListened}
235: */
236: public static boolean isListenerAvailable(Component comp,
237: String evtnm, boolean asap) {
238: return isListened(comp, evtnm, asap);
239: }
240:
241: /** Sends the event to the specified component and process it
242: * immediately. This method can only be called when processing an event.
243: * It is OK to send event to component from another page as long as
244: * they are in the same desktop.
245: */
246: public static void sendEvent(Component comp, Event event) {
247: final Execution exec = Executions.getCurrent();
248: final Desktop desktop = exec.getDesktop();
249: //note: we don't use comp.getDesktop because 1) it may be null
250: //2) it may be different from the current desktop
251:
252: event = ((DesktopCtrl) desktop).beforeSendEvent(event);
253: if (event == null)
254: return; //done
255:
256: final Thread thd = (Thread) Thread.currentThread();
257: if (!(thd instanceof EventProcessingThread)) {
258: if (!desktop.getWebApp().getConfiguration()
259: .isEventThreadEnabled()) {
260: final ExecutionCtrl execCtrl = (ExecutionCtrl) exec;
261: final Page page = execCtrl.getCurrentPage();
262: final EventProcessor proc = new EventProcessor(desktop,
263: comp, event);
264: proc.setup();
265: try {
266: proc.process();
267: } catch (Exception ex) {
268: throw UiException.Aide.wrap(ex);
269: } finally {
270: execCtrl.setCurrentPage(page);
271: }
272: return; //done
273: }
274:
275: throw new UiException("Callable only in the event listener");
276: }
277:
278: try {
279: ((EventProcessingThread) thd).sendEvent(comp, event);
280: } catch (Exception ex) {
281: throw UiException.Aide.wrap(ex);
282: }
283: }
284:
285: /** Sends the event the target specified in the event.
286: *
287: * <p>Note: {@link Event#getTarget} cannot be null.
288: */
289: public static void sendEvent(Event event) {
290: sendEvent(event.getTarget(), event);
291: }
292:
293: /** Posts an event.
294: * The event is placed at the end of the event queue.
295: * It will be processed after all other events are processed.
296: *
297: * <p>On the other hand, the event sent by {@link #sendEvent} is processed
298: * immediately without posting it to the queue.
299: *
300: * <p>Note: if the target of an event is not attached to
301: * the page yet, the event is ignored silently.
302: * @see #sendEvent
303: * @see #echoEvent
304: */
305: public static final void postEvent(Event event) {
306: Executions.getCurrent().postEvent(event);
307: }
308:
309: /** Posts a generic event (aka, an instance of {@link Event}).
310: */
311: public static final void postEvent(String name, Component target,
312: Object data) {
313: if (name == null || name.length() == 0 || target == null)
314: throw new IllegalArgumentException("null");
315: postEvent(new Event(name, target, data));
316: }
317:
318: /** Echos an event.
319: * By echo we mean the event is fired after the client receives the AU
320: * responses and then echoes back.
321: * In others, the event won't be execute in the current execution.
322: * Rather, it executes after the client receives the AU responses
323: * and then echoes back the event back.
324: *
325: * <p>It is usually if you want to prompt the user before doing a long
326: * operartion. A typical case is to open a hightlighted window to
327: * prevent the user from clicking any button before the operation gets done.
328: *
329: * @since 3.0.2
330: * @see #sendEvent
331: * @see #echoEvent
332: * @param name the event name, such as onSomething
333: * @param target the component to receive the event (never null).
334: * @param data the extra information, or null if not available.
335: * It will become {@link Event#getData}.
336: */
337: public static final void echoEvent(String name, Component target,
338: String data) {
339: if (name == null || name.length() == 0 || target == null)
340: throw new IllegalArgumentException();
341:
342: Clients.response(new AuEcho(target, name, data));
343: }
344: }
|