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 * @param events 065 * @param methodName 066 * @param async 067 */ 068 public void addListener(String[] events, String methodName, 069 String formId, boolean validateForm, boolean async, boolean focus) 070 { 071 addListener(events, methodName, formId, validateForm, async, focus, false); 072 } 073 074 /** 075 * Adds a listener bound to the specified client side 076 * events. 077 * 078 * @param events The javascript events to bind to. 079 * @param methodName The method to invoke when triggered. 080 * @param formId Optional form to bind event to. 081 * @param validateForm Whether or not form client side validation should be performed. 082 * @param async Whether or not the request should be asynchronous. 083 * @param focus Whether or not the form should recieve focus events. (if any forms are involved) 084 * @param autoSubmit Whether or not {@link org.apache.tapestry.form.IFormComponent}s should have their forms autowired for submission. 085 */ 086 public void addListener(String[] events, String methodName, 087 String formId, boolean validateForm, boolean async, boolean focus, boolean autoSubmit) 088 { 089 for (int i=0; i < events.length; i++) { 090 if (formId != null && formId.length() > 0) 091 addFormEventListener(events[i], methodName, formId, validateForm, async, focus); 092 else 093 addEventListener(events[i], methodName, autoSubmit); 094 } 095 } 096 097 /** 098 * Adds a form listener to the specified client side event. 099 * @param event 100 * @param methodName 101 * @param formId 102 * @param validateForm 103 */ 104 public void addFormEventListener(String event, String methodName, 105 String formId, boolean validateForm, boolean async, boolean focus) 106 { 107 EventBoundListener listener = new EventBoundListener(methodName, formId, validateForm, _componentId, async, focus); 108 109 List listeners = getFormEventListeners(event); 110 if (!listeners.contains(listener)) 111 listeners.add(listener); 112 } 113 114 /** 115 * Adds a listener to the specified client side event. 116 * @param event 117 * @param methodName 118 */ 119 public void addEventListener(String event, String methodName, boolean autoSubmit) 120 { 121 EventBoundListener listener = new EventBoundListener(methodName, _componentId); 122 123 List listeners = getEventListeners(event); 124 if (!listeners.contains(listener)) 125 listeners.add(listener); 126 } 127 128 public void connectAutoSubmitEvents(String formIdPath) 129 { 130 Iterator it = getEvents().iterator(); 131 List removeKeys = new ArrayList(); 132 133 while (it.hasNext()) { 134 String key = (String)it.next(); 135 136 List listeners = (List) _eventMap.get(key); 137 Iterator lit = listeners.iterator(); 138 while (lit.hasNext()) { 139 140 EventBoundListener listener = (EventBoundListener) lit.next(); 141 142 listener.setFormId(formIdPath); 143 lit.remove(); 144 145 List formListeners = getFormEventListeners(key); 146 if (!formListeners.contains(listener)) 147 formListeners.add(listener); 148 } 149 150 // remove mapping if empty 151 152 if (listeners.size() == 0) { 153 removeKeys.add(key); 154 } 155 } 156 157 for (int i=0; i < removeKeys.size(); i++) { 158 159 _eventMap.remove(removeKeys.get(i)); 160 } 161 162 it = getFormEvents().iterator(); 163 164 while (it.hasNext()) 165 { 166 String key = (String) it.next(); 167 List listeners = (List) _formEventMap.get(key); 168 Iterator lit = listeners.iterator(); 169 170 while(lit.hasNext()) 171 { 172 EventBoundListener listener = (EventBoundListener) lit.next(); 173 listener.setFormId(formIdPath); 174 } 175 } 176 } 177 178 /** 179 * Replaces all instances of the existing component id mapped for this property with the new 180 * {@link org.apache.tapestry.IComponent#getIdPath()} version. 181 * 182 * @param idPath The component id path. 183 */ 184 public void rewireComponentId(String idPath) 185 { 186 _componentId = idPath; 187 188 Iterator it = getEvents().iterator(); 189 while (it.hasNext()) 190 { 191 String key = (String) it.next(); 192 193 List listeners = (List)_eventMap.get(key); 194 195 for (int i=0; i < listeners.size(); i++) { 196 197 EventBoundListener listener = (EventBoundListener) listeners.get(i); 198 listener.setComponentId(idPath); 199 } 200 } 201 202 it = getFormEvents().iterator(); 203 while (it.hasNext()) 204 { 205 String key = (String) it.next(); 206 207 List listeners = (List)_formEventMap.get(key); 208 209 for (int i=0; i < listeners.size(); i++) { 210 211 EventBoundListener listener = (EventBoundListener) listeners.get(i); 212 listener.setComponentId(idPath); 213 } 214 } 215 } 216 217 /** 218 * @return the componentId 219 */ 220 public String getComponentId() 221 { 222 return _componentId; 223 } 224 225 /** 226 * Gets the current list of listeners for a specific event, 227 * creates a new instance if one doesn't exist already. 228 * 229 * @param event 230 * 231 * @return The current set of listeners bound to the specified event. 232 */ 233 public List getEventListeners(String event) 234 { 235 List listeners = (List)_eventMap.get(event); 236 if (listeners == null) { 237 listeners = new ArrayList(); 238 _eventMap.put(event, listeners); 239 } 240 241 return listeners; 242 } 243 244 /** 245 * Gets the current list of listeners for a specific event, 246 * creates a new instance if one doesn't exist already. 247 * 248 * @param event 249 * 250 * @return The current set of listeners that will submit a form bound to the 251 * specified event. 252 */ 253 public List getFormEventListeners(String event) 254 { 255 List listeners = (List)_formEventMap.get(event); 256 if (listeners == null) { 257 listeners = new ArrayList(); 258 _formEventMap.put(event, listeners); 259 } 260 261 return listeners; 262 } 263 264 /** 265 * The set of all non form based events. 266 * @return The unique set of events. 267 */ 268 public Set getEvents() 269 { 270 return _eventMap.keySet(); 271 } 272 273 /** 274 * The set of all form based listener events. 275 * 276 * @return All mapped form event keys. 277 */ 278 public Set getFormEvents() 279 { 280 return _formEventMap.keySet(); 281 } 282 283 /** 284 * Creates a list of listeners bound to a particular form 285 * and client side browser event. 286 * 287 * @param formId 288 * The form to find listeners for. 289 * @param event 290 * The browser event that generated the request. 291 * @param append 292 * The optional list to add the listeners to. 293 * @return The list of listeners to invoke for the form and event passed in, 294 * will be empty if none found. 295 */ 296 public List getFormEventListeners(String formId, BrowserEvent event, List append) 297 { 298 List ret = (append == null) ? new ArrayList() : append; 299 300 List listeners = (List)_formEventMap.get(event.getName()); 301 if (listeners == null) 302 return ret; 303 304 for (int i=0; i < listeners.size(); i++) { 305 EventBoundListener listener = (EventBoundListener)listeners.get(i); 306 if (listener.getFormId().equals(formId)) 307 ret.add(listener); 308 } 309 310 return ret; 311 } 312 313 void cloneEvents(Map source, Map target) 314 throws CloneNotSupportedException 315 { 316 Iterator it = source.keySet().iterator(); 317 while (it.hasNext()) 318 { 319 String event = (String) it.next(); 320 List listeners = (List)source.get(event); 321 322 List newListeners = new ArrayList(); 323 for (int i=0; i < listeners.size(); i++) { 324 EventBoundListener listener = (EventBoundListener) listeners.get(i); 325 newListeners.add(listener.clone()); 326 } 327 328 target.put(event, newListeners); 329 } 330 } 331 332 public Object clone() 333 throws CloneNotSupportedException 334 { 335 Map events = new HashMap(); 336 Map formEvents = new HashMap(); 337 338 cloneEvents(_eventMap, events); 339 cloneEvents(_formEventMap, formEvents); 340 341 return new ComponentEventProperty(_componentId, events, formEvents); 342 } 343 }