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 /** 141 * Moves all of the non-form-submitting events with autoSubmit=true in {@link #_eventMap} over 142 * to the list of form-submitting events {@link #_formEventMap}. 143 * This is called when the targeted component is an {@link org.apache.tapestry.form.IFormComponent} 144 * by the {@link org.apache.tapestry.pageload.EventConnectionVisitor}. 145 * */ 146 public void connectAutoSubmitEvents(String formIdPath) 147 { 148 Iterator it = getEvents().iterator(); 149 List removeKeys = new ArrayList(); 150 151 while (it.hasNext()) 152 { 153 String key = (String)it.next(); 154 List listeners = (List) _eventMap.get(key); 155 156 Iterator lit = listeners.iterator(); 157 while (lit.hasNext()) 158 { 159 EventBoundListener listener = (EventBoundListener) lit.next(); 160 if ( !listener.isAutoSubmit() ) 161 continue; 162 163 listener.setFormId(formIdPath); 164 lit.remove(); 165 166 List formListeners = getFormEventListeners(key); 167 if (!formListeners.contains(listener)) 168 formListeners.add(listener); 169 } 170 171 // remove mapping if empty 172 173 if (listeners.size() == 0) 174 { 175 removeKeys.add(key); 176 } 177 } 178 179 for (int i=0; i < removeKeys.size(); i++) 180 { 181 _eventMap.remove(removeKeys.get(i)); 182 } 183 184 it = getFormEvents().iterator(); 185 186 while (it.hasNext()) 187 { 188 String key = (String) it.next(); 189 List listeners = (List) _formEventMap.get(key); 190 Iterator lit = listeners.iterator(); 191 192 while(lit.hasNext()) 193 { 194 EventBoundListener listener = (EventBoundListener) lit.next(); 195 listener.setFormId(formIdPath); 196 } 197 } 198 } 199 200 /** 201 * Replaces all instances of the existing component id mapped for this property with the new 202 * {@link org.apache.tapestry.IComponent#getIdPath()} version. 203 * 204 * @param extendedId The component extended id path. 205 * @param idPath The component idPath from the page. 206 */ 207 public void rewireComponentId(String extendedId, String idPath) 208 { 209 _componentId = extendedId; 210 211 Iterator it = getEvents().iterator(); 212 while (it.hasNext()) 213 { 214 String key = (String) it.next(); 215 List listeners = (List)_eventMap.get(key); 216 217 for (int i=0; i < listeners.size(); i++) 218 { 219 EventBoundListener listener = (EventBoundListener) listeners.get(i); 220 221 listener.setComponentId(extendedId); 222 listener.setComponentIdPath(idPath); 223 } 224 } 225 226 it = getFormEvents().iterator(); 227 while (it.hasNext()) 228 { 229 String key = (String) it.next(); 230 List listeners = (List)_formEventMap.get(key); 231 232 for (int i=0; i < listeners.size(); i++) 233 { 234 EventBoundListener listener = (EventBoundListener) listeners.get(i); 235 236 listener.setComponentId(extendedId); 237 listener.setComponentIdPath(idPath); 238 } 239 } 240 } 241 242 /** 243 * @return the componentId 244 */ 245 public String getComponentId() 246 { 247 return _componentId; 248 } 249 250 /** 251 * Gets the current list of listeners for a specific event, 252 * creates a new instance if one doesn't exist already. 253 * 254 * @param event 255 * 256 * @return The current set of listeners bound to the specified event. 257 */ 258 public List getEventListeners(String event) 259 { 260 List listeners = (List)_eventMap.get(event); 261 if (listeners == null) 262 { 263 listeners = new ArrayList(); 264 _eventMap.put(event, listeners); 265 } 266 267 return listeners; 268 } 269 270 /** 271 * Gets the current list of listeners for a specific event, 272 * creates a new instance if one doesn't exist already. 273 * 274 * @param event 275 * 276 * @return The current set of listeners that will submit a form bound to the 277 * specified event. 278 */ 279 public List getFormEventListeners(String event) 280 { 281 List listeners = (List)_formEventMap.get(event); 282 if (listeners == null) 283 { 284 listeners = new ArrayList(); 285 _formEventMap.put(event, listeners); 286 } 287 288 return listeners; 289 } 290 291 /** 292 * The set of all non form based events. 293 * @return The unique set of events. 294 */ 295 public Set getEvents() 296 { 297 return _eventMap.keySet(); 298 } 299 300 /** 301 * The set of all form based listener events. 302 * 303 * @return All mapped form event keys. 304 */ 305 public Set getFormEvents() 306 { 307 return _formEventMap.keySet(); 308 } 309 310 /** 311 * Creates a list of listeners bound to a particular form 312 * and client side browser event. 313 * 314 * @param formId 315 * The form to find listeners for. 316 * @param event 317 * The browser event that generated the request. 318 * @param append 319 * The optional list to add the listeners to. 320 * @return The list of listeners to invoke for the form and event passed in, 321 * will be empty if none found. 322 */ 323 public List getFormEventListeners(String formId, BrowserEvent event, List append) 324 { 325 List ret = (append == null) ? new ArrayList() : append; 326 327 List listeners = (List)_formEventMap.get(event.getName()); 328 if (listeners == null) 329 return ret; 330 331 for (int i=0; i < listeners.size(); i++) 332 { 333 EventBoundListener listener = (EventBoundListener)listeners.get(i); 334 335 if (listener.getFormId().equals(formId)) 336 ret.add(listener); 337 } 338 339 return ret; 340 } 341 342 void cloneEvents(Map source, Map target) 343 throws CloneNotSupportedException 344 { 345 Iterator it = source.keySet().iterator(); 346 while (it.hasNext()) 347 { 348 String event = (String) it.next(); 349 List listeners = (List)source.get(event); 350 351 List newListeners = new ArrayList(); 352 for (int i=0; i < listeners.size(); i++) 353 { 354 EventBoundListener listener = (EventBoundListener) listeners.get(i); 355 newListeners.add(listener.clone()); 356 } 357 358 target.put(event, newListeners); 359 } 360 } 361 362 public Object clone() 363 throws CloneNotSupportedException 364 { 365 Map events = new HashMap(); 366 Map formEvents = new HashMap(); 367 368 cloneEvents(_eventMap, events); 369 cloneEvents(_formEventMap, formEvents); 370 371 return new ComponentEventProperty(_componentId, events, formEvents); 372 } 373 }