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 }