001 // Copyright May 20, 2006 The Apache Software Foundation
002 //
003 // Licensed under the Apache License, Version 2.0 (the "License");
004 // you may not use this file except in compliance with the License.
005 // You may obtain a copy of the License at
006 //
007 // http://www.apache.org/licenses/LICENSE-2.0
008 //
009 // Unless required by applicable law or agreed to in writing, software
010 // distributed under the License is distributed on an "AS IS" BASIS,
011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012 // See the License for the specific language governing permissions and
013 // limitations under the License.
014 package org.apache.tapestry.internal.event;
015
016 import org.apache.tapestry.event.BrowserEvent;
017
018 import java.util.*;
019
020
021 /**
022 * Represents a configured listener/event(s) binding for a
023 * a component and the events that may be optionally listened
024 * for on the client browser.
025 */
026 public class ComponentEventProperty implements Cloneable
027 {
028 private Map _eventMap = new HashMap();
029 private Map _formEventMap = new HashMap();
030
031 private String _componentId;
032
033 /**
034 * Creates a new component event property mapped to the specified component id.
035 *
036 * @param componentId
037 * The component which is the target of all mappings in this property.
038 */
039 public ComponentEventProperty(String componentId)
040 {
041 _componentId = componentId;
042 }
043
044 /**
045 * Used in cloning only currently.
046 *
047 * @param componentId
048 * The component this property is bound to.
049 * @param events
050 * The list of event mappings.
051 * @param formEvents
052 * The list of form event mappings.
053 */
054 public ComponentEventProperty(String componentId, Map events, Map formEvents)
055 {
056 _componentId = componentId;
057 _eventMap = events;
058 _formEventMap = formEvents;
059 }
060
061 /**
062 * Adds a listener bound to the specified client side
063 * events.
064 *
065 * @param events
066 * @param methodName
067 * @param async
068 */
069 public void addListener(String[] events, String methodName,
070 String formId, boolean validateForm, boolean async, boolean focus)
071 {
072 addListener(events, methodName, formId, validateForm, async, focus, true);
073 }
074
075 /**
076 * Adds a listener bound to the specified client side
077 * events.
078 *
079 * @param events The javascript events to bind to.
080 * @param methodName The method to invoke when triggered.
081 * @param formId Optional form to bind event to.
082 * @param validateForm Whether or not form client side validation should be performed.
083 * @param async Whether or not the request should be asynchronous.
084 * @param focus Whether or not the form should recieve focus events. (if any forms are involved)
085 * @param autoSubmit Whether or not {@link org.apache.tapestry.form.IFormComponent}s should have their forms autowired for submission.
086 */
087 public void addListener(String[] events, String methodName,
088 String formId, boolean validateForm, boolean async, boolean focus, boolean autoSubmit)
089 {
090 for (int i=0; i < events.length; i++)
091 {
092 if (formId != null && formId.length() > 0)
093 {
094 addFormEventListener(events[i], methodName, formId, validateForm, async, focus, autoSubmit);
095 } else
096 {
097 EventBoundListener listener = new EventBoundListener(methodName, formId, validateForm,
098 _componentId, async, focus, autoSubmit);
099 List listeners = getEventListeners(events[i]);
100 if (!listeners.contains(listener))
101 {
102 listeners.add(listener);
103 }
104 }
105 }
106 }
107
108 /**
109 * Adds a form listener to the specified client side event.
110 * @param event
111 * @param methodName
112 * @param formId
113 * @param validateForm
114 */
115 public void addFormEventListener(String event, String methodName,
116 String formId, boolean validateForm, boolean async, boolean focus, boolean autoSubmit)
117 {
118 EventBoundListener listener = new EventBoundListener(methodName, formId, validateForm, _componentId,
119 async, focus, autoSubmit);
120
121 List listeners = getFormEventListeners(event);
122 if (!listeners.contains(listener))
123 listeners.add(listener);
124 }
125
126 /**
127 * Adds a listener to the specified client side event.
128 * @param event
129 * @param methodName
130 */
131 public void addEventListener(String event, String methodName, boolean autoSubmit)
132 {
133 EventBoundListener listener = new EventBoundListener(methodName, _componentId);
134
135 List listeners = getEventListeners(event);
136 if (!listeners.contains(listener))
137 listeners.add(listener);
138 }
139
140 public void connectAutoSubmitEvents(String formIdPath)
141 {
142 Iterator it = getEvents().iterator();
143 List removeKeys = new ArrayList();
144
145 while (it.hasNext())
146 {
147 String key = (String)it.next();
148 List listeners = (List) _eventMap.get(key);
149
150 Iterator lit = listeners.iterator();
151 while (lit.hasNext())
152 {
153 EventBoundListener listener = (EventBoundListener) lit.next();
154
155 listener.setFormId(formIdPath);
156 lit.remove();
157
158 List formListeners = getFormEventListeners(key);
159 if (!formListeners.contains(listener))
160 formListeners.add(listener);
161 }
162
163 // remove mapping if empty
164
165 if (listeners.size() == 0)
166 {
167 removeKeys.add(key);
168 }
169 }
170
171 for (int i=0; i < removeKeys.size(); i++)
172 {
173 _eventMap.remove(removeKeys.get(i));
174 }
175
176 it = getFormEvents().iterator();
177
178 while (it.hasNext())
179 {
180 String key = (String) it.next();
181 List listeners = (List) _formEventMap.get(key);
182 Iterator lit = listeners.iterator();
183
184 while(lit.hasNext())
185 {
186 EventBoundListener listener = (EventBoundListener) lit.next();
187 listener.setFormId(formIdPath);
188 }
189 }
190 }
191
192 /**
193 * Replaces all instances of the existing component id mapped for this property with the new
194 * {@link org.apache.tapestry.IComponent#getIdPath()} version.
195 *
196 * @param extendedId The component extended id path.
197 * @param idPath The component idPath from the page.
198 */
199 public void rewireComponentId(String extendedId, String idPath)
200 {
201 _componentId = extendedId;
202
203 Iterator it = getEvents().iterator();
204 while (it.hasNext())
205 {
206 String key = (String) it.next();
207 List listeners = (List)_eventMap.get(key);
208
209 for (int i=0; i < listeners.size(); i++)
210 {
211 EventBoundListener listener = (EventBoundListener) listeners.get(i);
212
213 listener.setComponentId(extendedId);
214 listener.setComponentIdPath(idPath);
215 }
216 }
217
218 it = getFormEvents().iterator();
219 while (it.hasNext())
220 {
221 String key = (String) it.next();
222 List listeners = (List)_formEventMap.get(key);
223
224 for (int i=0; i < listeners.size(); i++)
225 {
226 EventBoundListener listener = (EventBoundListener) listeners.get(i);
227
228 listener.setComponentId(extendedId);
229 listener.setComponentIdPath(idPath);
230 }
231 }
232 }
233
234 /**
235 * @return the componentId
236 */
237 public String getComponentId()
238 {
239 return _componentId;
240 }
241
242 /**
243 * Gets the current list of listeners for a specific event,
244 * creates a new instance if one doesn't exist already.
245 *
246 * @param event
247 *
248 * @return The current set of listeners bound to the specified event.
249 */
250 public List getEventListeners(String event)
251 {
252 List listeners = (List)_eventMap.get(event);
253 if (listeners == null)
254 {
255 listeners = new ArrayList();
256 _eventMap.put(event, listeners);
257 }
258
259 return listeners;
260 }
261
262 /**
263 * Gets the current list of listeners for a specific event,
264 * creates a new instance if one doesn't exist already.
265 *
266 * @param event
267 *
268 * @return The current set of listeners that will submit a form bound to the
269 * specified event.
270 */
271 public List getFormEventListeners(String event)
272 {
273 List listeners = (List)_formEventMap.get(event);
274 if (listeners == null)
275 {
276 listeners = new ArrayList();
277 _formEventMap.put(event, listeners);
278 }
279
280 return listeners;
281 }
282
283 /**
284 * The set of all non form based events.
285 * @return The unique set of events.
286 */
287 public Set getEvents()
288 {
289 return _eventMap.keySet();
290 }
291
292 /**
293 * The set of all form based listener events.
294 *
295 * @return All mapped form event keys.
296 */
297 public Set getFormEvents()
298 {
299 return _formEventMap.keySet();
300 }
301
302 /**
303 * Creates a list of listeners bound to a particular form
304 * and client side browser event.
305 *
306 * @param formId
307 * The form to find listeners for.
308 * @param event
309 * The browser event that generated the request.
310 * @param append
311 * The optional list to add the listeners to.
312 * @return The list of listeners to invoke for the form and event passed in,
313 * will be empty if none found.
314 */
315 public List getFormEventListeners(String formId, BrowserEvent event, List append)
316 {
317 List ret = (append == null) ? new ArrayList() : append;
318
319 List listeners = (List)_formEventMap.get(event.getName());
320 if (listeners == null)
321 return ret;
322
323 for (int i=0; i < listeners.size(); i++)
324 {
325 EventBoundListener listener = (EventBoundListener)listeners.get(i);
326
327 if (listener.getFormId().equals(formId))
328 ret.add(listener);
329 }
330
331 return ret;
332 }
333
334 void cloneEvents(Map source, Map target)
335 throws CloneNotSupportedException
336 {
337 Iterator it = source.keySet().iterator();
338 while (it.hasNext())
339 {
340 String event = (String) it.next();
341 List listeners = (List)source.get(event);
342
343 List newListeners = new ArrayList();
344 for (int i=0; i < listeners.size(); i++)
345 {
346 EventBoundListener listener = (EventBoundListener) listeners.get(i);
347 newListeners.add(listener.clone());
348 }
349
350 target.put(event, newListeners);
351 }
352 }
353
354 public Object clone()
355 throws CloneNotSupportedException
356 {
357 Map events = new HashMap();
358 Map formEvents = new HashMap();
359
360 cloneEvents(_eventMap, events);
361 cloneEvents(_formEventMap, formEvents);
362
363 return new ComponentEventProperty(_componentId, events, formEvents);
364 }
365 }