- Timestamp:
- Apr 27, 2004, 8:39:34 PM (22 years ago)
- Location:
- branches/GNU/src/gcc
- Files:
-
- 2 edited
-
. (modified) (1 prop)
-
libjava/java/beans/PropertyChangeSupport.java (modified) (3 diffs, 1 prop)
Legend:
- Unmodified
- Added
- Removed
-
branches/GNU/src/gcc
- Property svn:ignore
-
old new 26 26 configure.vr 27 27 configure.vrs 28 28 29 Makefile 29 dir.info30 30 lost+found 31 31 update.out
-
- Property svn:ignore
-
branches/GNU/src/gcc/libjava/java/beans/PropertyChangeSupport.java
-
Property cvs2svn:cvs-rev
changed from
1.1to1.1.1.2
r1390 r1391 1 /* java.beans.PropertyChangeSupport2 Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.1 /* 2 Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. 3 3 4 4 This file is part of GNU Classpath. … … 8 8 the Free Software Foundation; either version 2, or (at your option) 9 9 any later version. 10 10 11 11 GNU Classpath is distributed in the hope that it will be useful, but 12 12 WITHOUT ANY WARRANTY; without even the implied warranty of … … 38 38 39 39 package java.beans; 40 import java.util.Hashtable; 41 import java.util.Vector; 42 import java.util.Enumeration; 40 41 import java.io.IOException; 43 42 import java.io.ObjectInputStream; 44 43 import java.io.ObjectOutputStream; 45 import java.io.IOException;46 44 import java.io.Serializable; 45 46 47 48 49 50 47 51 48 52 /** 49 ** PropertyChangeSupport makes it easy to fire property 50 ** change events and handle listeners. 51 ** 52 ** @author John Keiser 53 ** @since JDK1.1 54 ** @version 1.2.0, 15 Mar 1999 55 **/ 56 57 public class PropertyChangeSupport implements java.io.Serializable { 58 transient Hashtable propertyListeners = new Hashtable(); 59 transient Vector listeners = new Vector(); 60 Hashtable children; 61 Object source; 62 int propertyChangeSupportSerializedDataVersion = 2; 63 private static final long serialVersionUID = 6401253773779951803L; 64 65 /** 66 * Saves the state of the object to the stream. */ 67 private void writeObject(ObjectOutputStream stream) throws IOException { 68 children = propertyListeners.isEmpty() ? null : propertyListeners; 69 stream.defaultWriteObject(); 70 for (Enumeration e = listeners.elements(); e.hasMoreElements(); ) { 71 PropertyChangeListener l = (PropertyChangeListener)e.nextElement(); 72 if (l instanceof Serializable) 73 stream.writeObject(l); 74 } 75 stream.writeObject(null); 76 } 77 78 /** 79 * Reads the object back from stream (deserialization). 80 */ 81 private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { 82 stream.defaultReadObject(); 83 propertyListeners = (children == null) ? new Hashtable() : children; 84 PropertyChangeListener l; 85 while ((l = (PropertyChangeListener)stream.readObject()) != null) { 86 addPropertyChangeListener(l); 87 } 88 // FIXME: XXX: There is no spec for JDK 1.1 serialization 89 // so it is unclear what to do if the value of 90 // propertyChangeSupportSerializedDataVersion is 1. 91 } 92 93 /** Create PropertyChangeSupport to work with a specific 94 ** source bean. 95 ** @param source the source bean to use. 96 **/ 97 public PropertyChangeSupport(Object source) { 98 this.source = source; 99 } 100 101 /** Adds a PropertyChangeListener to the list of listeners. 102 ** All property change events will be sent to this listener. 103 ** <P> 104 ** 105 ** The listener add is not unique: that is, <em>n</em> adds with 106 ** the same listener will result in <em>n</em> events being sent 107 ** to that listener for every property change. 108 ** <P> 109 ** 110 ** Adding a null listener will cause undefined behavior. 111 ** 112 ** @param l the listener to add. 113 **/ 114 public void addPropertyChangeListener(PropertyChangeListener l) { 115 listeners.addElement(l); 116 } 117 118 /** Adds a PropertyChangeListener listening on the specified property. 119 ** Events will be sent to the listener for that particular property. 120 ** <P> 121 ** 122 ** The listener add is not unique; that is, <em>n</em> adds on a 123 ** particular property for a particular listener will result in 124 ** <em>n</em> events being sent to that listener when that 125 ** property is changed. 126 ** <P> 127 ** 128 ** The effect is cumulative, too; if you are registered to listen 129 ** to receive events on all property changes, and then you 130 ** register on a particular property, you will receive change 131 ** events for that property twice. 132 ** <P> 133 ** 134 ** Adding a null listener will cause undefined behavior. 135 ** 136 ** @param propertyName the name of the property to listen on. 137 ** @param l the listener to add. 138 **/ 139 public void addPropertyChangeListener(String propertyName, PropertyChangeListener l) { 140 synchronized(propertyListeners) { 141 Vector v = (Vector)propertyListeners.get(propertyName); 142 try { 143 v.addElement(l); 144 } catch(NullPointerException e) { 145 /* If v is not found, create a new vector. */ 146 v = new Vector(); 147 v.addElement(l); 148 propertyListeners.put(propertyName, v); 149 } 150 } 151 } 152 153 /** Removes a PropertyChangeListener from the list of listeners. 154 ** If any specific properties are being listened on, they must 155 ** be deregistered by themselves; this will only remove the 156 ** general listener to all properties. 157 ** <P> 158 ** 159 ** If <code>add()</code> has been called multiple times for a 160 ** particular listener, <code>remove()</code> will have to be 161 ** called the same number of times to deregister it. 162 ** 163 ** @param l the listener to remove. 164 **/ 165 public void removePropertyChangeListener(PropertyChangeListener l) { 166 listeners.removeElement(l); 167 } 168 169 /** Removes a PropertyChangeListener from listening to a specific property. 170 ** <P> 171 ** 172 ** If <code>add()</code> has been called multiple times for a 173 ** particular listener on a property, <code>remove()</code> will 174 ** have to be called the same number of times to deregister it. 175 ** 176 ** @param propertyName the property to stop listening on. 177 ** @param l the listener to remove. 178 **/ 179 public void removePropertyChangeListener(String propertyName, PropertyChangeListener l) { 180 synchronized(propertyListeners) { 181 Vector v = (Vector)propertyListeners.get(propertyName); 182 try { 183 v.removeElement(l); 184 if(v.size() == 0) { 185 propertyListeners.remove(propertyName); 186 } 187 } catch(NullPointerException e) { 188 /* if v is not found, do nothing. */ 189 } 190 } 191 } 192 193 /** Fire a PropertyChangeEvent to all the listeners. 194 ** 195 ** @param event the event to fire. 196 **/ 197 public void firePropertyChange(PropertyChangeEvent event) { 198 for(int i=0;i<listeners.size();i++) { 199 ((PropertyChangeListener)listeners.elementAt(i)).propertyChange(event); 200 } 201 Vector moreListeners = (Vector)propertyListeners.get(event.getPropertyName()); 202 if(moreListeners != null) { 203 for(int i=0;i<moreListeners.size();i++) { 204 ((PropertyChangeListener)moreListeners.elementAt(i)).propertyChange(event); 205 } 206 } 207 } 208 209 /** Fire a PropertyChangeEvent containing the old and new values of the property to all the listeners. 210 ** 211 ** @param propertyName the name of the property that changed. 212 ** @param oldVal the old value. 213 ** @param newVal the new value. 214 **/ 215 public void firePropertyChange(String propertyName, Object oldVal, Object newVal) { 216 firePropertyChange(new PropertyChangeEvent(source,propertyName,oldVal,newVal)); 217 } 218 219 /** Fire a PropertyChangeEvent containing the old and new values of the property to all the listeners. 220 ** 221 ** @param propertyName the name of the property that changed. 222 ** @param oldVal the old value. 223 ** @param newVal the new value. 224 **/ 225 public void firePropertyChange(String propertyName, boolean oldVal, boolean newVal) { 226 firePropertyChange(new PropertyChangeEvent(source, propertyName, new Boolean(oldVal), new Boolean(newVal))); 227 } 228 229 /** Fire a PropertyChangeEvent containing the old and new values of the property to all the listeners. 230 ** 231 ** @param propertyName the name of the property that changed. 232 ** @param oldVal the old value. 233 ** @param newVal the new value. 234 **/ 235 public void firePropertyChange(String propertyName, int oldVal, int newVal) { 236 firePropertyChange(new PropertyChangeEvent(source, propertyName, new Integer(oldVal), new Integer(newVal))); 237 } 238 239 /** Tell whether the specified property is being listened on or not. 240 ** This will only return <code>true</code> if there are listeners 241 ** on all properties or if there is a listener specifically on this 242 ** property. 243 ** 244 ** @param propertyName the property that may be listened on 245 ** @return whether the property is being listened on 246 **/ 247 public boolean hasListeners(String propertyName) { 248 return listeners.size() > 0 || propertyListeners.get(propertyName) != null; 249 } 250 } 53 * PropertyChangeSupport makes it easy to fire property change events and 54 * handle listeners. It allows chaining of listeners, as well as filtering 55 * by property name. In addition, it will serialize only those listeners 56 * which are serializable, ignoring the others without problem. This class 57 * is thread-safe. 58 * 59 * @author John Keiser 60 * @author Eric Blake <[email protected]> 61 * @since 1.1 62 * @status updated to 1.4 63 */ 64 public class PropertyChangeSupport implements Serializable 65 { 66 /** 67 * Compatible with JDK 1.1+. 68 */ 69 private static final long serialVersionUID = 6401253773779951803L; 70 71 /** 72 * Maps property names (String) to named listeners (PropertyChangeSupport). 73 * If this is a child instance, this field will be null. 74 * 75 * @serial the map of property names to named listener managers 76 * @since 1.2 77 */ 78 private Hashtable children; 79 80 /** 81 * The non-null source object for any generated events. 82 * 83 * @serial the event source 84 */ 85 private final Object source; 86 87 /** 88 * A field to compare serialization versions - this class uses version 2. 89 * 90 * @serial the serialization format 91 */ 92 private final int propertyChangeSupportSerializedDataVersion = 2; 93 94 /** 95 * The list of all registered property listeners. If this instance was 96 * created by user code, this only holds the global listeners (ie. not tied 97 * to a name), and may be null. If it was created by this class, as a 98 * helper for named properties, then this vector will be non-null, and this 99 * instance appears as a value in the <code>children</code> hashtable of 100 * another instance, so that the listeners are tied to the key of that 101 * hashtable entry. 102 */ 103 private transient Vector listeners; 104 105 /** 106 * Create a PropertyChangeSupport to work with a specific source bean. 107 * 108 * @param source the source bean to use 109 * @throws NullPointerException if source is null 110 */ 111 public PropertyChangeSupport(Object source) 112 { 113 this.source = source; 114 if (source == null) 115 throw new NullPointerException(); 116 } 117 118 /** 119 * Adds a PropertyChangeListener to the list of global listeners. All 120 * property change events will be sent to this listener. The listener add 121 * is not unique: that is, <em>n</em> adds with the same listener will 122 * result in <em>n</em> events being sent to that listener for every 123 * property change. Adding a null listener may cause a NullPointerException 124 * down the road. This method will unwrap a PropertyChangeListenerProxy, 125 * registering the underlying delegate to the named property list. 126 * 127 * @param l the listener to add 128 */ 129 public synchronized void addPropertyChangeListener(PropertyChangeListener l) 130 { 131 if (l instanceof PropertyChangeListenerProxy) 132 { 133 PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l; 134 addPropertyChangeListener(p.propertyName, 135 (PropertyChangeListener) p.getListener()); 136 } 137 else 138 { 139 if (listeners == null) 140 listeners = new Vector(); 141 listeners.add(l); 142 } 143 } 144 145 /** 146 * Removes a PropertyChangeListener from the list of global listeners. If 147 * any specific properties are being listened on, they must be deregistered 148 * by themselves; this will only remove the general listener to all 149 * properties. If <code>add()</code> has been called multiple times for a 150 * particular listener, <code>remove()</code> will have to be called the 151 * same number of times to deregister it. This method will unwrap a 152 * PropertyChangeListenerProxy, removing the underlying delegate from the 153 * named property list. 154 * 155 * @param l the listener to remove 156 */ 157 public synchronized void 158 removePropertyChangeListener(PropertyChangeListener l) 159 { 160 if (l instanceof PropertyChangeListenerProxy) 161 { 162 PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l; 163 removePropertyChangeListener(p.propertyName, 164 (PropertyChangeListener) p.getListener()); 165 } 166 else if (listeners != null) 167 { 168 listeners.remove(l); 169 if (listeners.isEmpty()) 170 listeners = null; 171 } 172 } 173 174 /** 175 * Returns an array of all registered property change listeners. Those that 176 * were registered under a name will be wrapped in a 177 * <code>PropertyChangeListenerProxy</code>, so you must check whether the 178 * listener is an instance of the proxy class in order to see what name the 179 * real listener is registered under. If there are no registered listeners, 180 * this returns an empty array. 181 * 182 * @return the array of registered listeners 183 * @see PropertyChangeListenerProxy 184 * @since 1.4 185 */ 186 public synchronized PropertyChangeListener[] getPropertyChangeListeners() 187 { 188 ArrayList list = new ArrayList(); 189 if (listeners != null) 190 list.addAll(listeners); 191 if (children != null) 192 { 193 int i = children.size(); 194 Iterator iter = children.entrySet().iterator(); 195 while (--i >= 0) 196 { 197 Entry e = (Entry) iter.next(); 198 String name = (String) e.getKey(); 199 Vector v = ((PropertyChangeSupport) e.getValue()).listeners; 200 int j = v.size(); 201 while (--j >= 0) 202 list.add(new PropertyChangeListenerProxy 203 (name, (PropertyChangeListener) v.get(j))); 204 } 205 } 206 return (PropertyChangeListener[]) 207 list.toArray(new PropertyChangeListener[list.size()]); 208 } 209 210 /** 211 * Adds a PropertyChangeListener listening on the specified property. Events 212 * will be sent to the listener only if the property name matches. The 213 * listener add is not unique; that is, <em>n</em> adds on a particular 214 * property for a particular listener will result in <em>n</em> events 215 * being sent to that listener when that property is changed. The effect is 216 * cumulative, too; if you are registered to listen to receive events on 217 * all property changes, and then you register on a particular property, 218 * you will receive change events for that property twice. Adding a null 219 * listener may cause a NullPointerException down the road. This method 220 * will unwrap a PropertyChangeListenerProxy, registering the underlying 221 * delegate to the named property list if the names match, and discarding 222 * it otherwise. 223 * 224 * @param propertyName the name of the property to listen on 225 * @param l the listener to add 226 * @throws NullPointerException if propertyName is null 227 */ 228 public synchronized void addPropertyChangeListener(String propertyName, 229 PropertyChangeListener l) 230 { 231 while (l instanceof PropertyChangeListenerProxy) 232 { 233 PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l; 234 if (propertyName == null ? p.propertyName != null 235 : ! propertyName.equals(p.propertyName)) 236 return; 237 l = (PropertyChangeListener) p.getListener(); 238 } 239 PropertyChangeSupport s = null; 240 if (children == null) 241 children = new Hashtable(); 242 else 243 s = (PropertyChangeSupport) children.get(propertyName); 244 if (s == null) 245 { 246 s = new PropertyChangeSupport(source); 247 s.listeners = new Vector(); 248 children.put(propertyName, s); 249 } 250 s.listeners.add(l); 251 } 252 253 /** 254 * Removes a PropertyChangeListener from listening to a specific property. 255 * If <code>add()</code> has been called multiple times for a particular 256 * listener on a property, <code>remove()</code> will have to be called the 257 * same number of times to deregister it. This method will unwrap a 258 * PropertyChangeListenerProxy, removing the underlying delegate from the 259 * named property list if the names match. 260 * 261 * @param propertyName the property to stop listening on 262 * @param l the listener to remove 263 * @throws NullPointerException if propertyName is null 264 */ 265 public synchronized void 266 removePropertyChangeListener(String propertyName, PropertyChangeListener l) 267 { 268 if (children == null) 269 return; 270 PropertyChangeSupport s 271 = (PropertyChangeSupport) children.get(propertyName); 272 if (s == null) 273 return; 274 while (l instanceof PropertyChangeListenerProxy) 275 { 276 PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l; 277 if (propertyName == null ? p.propertyName != null 278 : ! propertyName.equals(p.propertyName)) 279 return; 280 l = (PropertyChangeListener) p.getListener(); 281 } 282 s.listeners.remove(l); 283 if (s.listeners.isEmpty()) 284 { 285 children.remove(propertyName); 286 if (children.isEmpty()) 287 children = null; 288 } 289 } 290 291 /** 292 * Returns an array of all property change listeners registered under the 293 * given property name. If there are no registered listeners, this returns 294 * an empty array. 295 * 296 * @return the array of registered listeners 297 * @throws NullPointerException if propertyName is null 298 * @since 1.4 299 */ 300 public synchronized PropertyChangeListener[] 301 getPropertyChangeListeners(String propertyName) 302 { 303 if (children == null) 304 return new PropertyChangeListener[0]; 305 PropertyChangeSupport s 306 = (PropertyChangeSupport) children.get(propertyName); 307 if (s == null) 308 return new PropertyChangeListener[0]; 309 return (PropertyChangeListener[]) 310 s.listeners.toArray(new PropertyChangeListener[s.listeners.size()]); 311 } 312 313 /** 314 * Fire a PropertyChangeEvent containing the old and new values of the 315 * property to all the global listeners, and to all the listeners for the 316 * specified property name. This does nothing if old and new are non-null 317 * and equal. 318 * 319 * @param propertyName the name of the property that changed 320 * @param oldVal the old value 321 * @param newVal the new value 322 */ 323 public void firePropertyChange(String propertyName, 324 Object oldVal, Object newVal) 325 { 326 firePropertyChange(new PropertyChangeEvent(source, propertyName, 327 oldVal, newVal)); 328 } 329 330 /** 331 * Fire a PropertyChangeEvent containing the old and new values of the 332 * property to all the global listeners, and to all the listeners for the 333 * specified property name. This does nothing if old and new are equal. 334 * 335 * @param propertyName the name of the property that changed 336 * @param oldVal the old value 337 * @param newVal the new value 338 */ 339 public void firePropertyChange(String propertyName, int oldVal, int newVal) 340 { 341 if (oldVal != newVal) 342 firePropertyChange(new PropertyChangeEvent(source, propertyName, 343 new Integer(oldVal), 344 new Integer(newVal))); 345 } 346 347 /** 348 * Fire a PropertyChangeEvent containing the old and new values of the 349 * property to all the global listeners, and to all the listeners for the 350 * specified property name. This does nothing if old and new are equal. 351 * 352 * @param propertyName the name of the property that changed 353 * @param oldVal the old value 354 * @param newVal the new value 355 */ 356 public void firePropertyChange(String propertyName, 357 boolean oldVal, boolean newVal) 358 { 359 if (oldVal != newVal) 360 firePropertyChange(new PropertyChangeEvent(source, propertyName, 361 Boolean.valueOf(oldVal), 362 Boolean.valueOf(newVal))); 363 } 364 365 /** 366 * Fire a PropertyChangeEvent to all the global listeners, and to all the 367 * listeners for the specified property name. This does nothing if old and 368 * new values of the event are equal. 369 * 370 * @param event the event to fire 371 * @throws NullPointerException if event is null 372 */ 373 public void firePropertyChange(PropertyChangeEvent event) 374 { 375 if (event.oldValue != null && event.oldValue.equals(event.newValue)) 376 return; 377 Vector v = listeners; // Be thread-safe. 378 if (v != null) 379 { 380 int i = v.size(); 381 while (--i >= 0) 382 ((PropertyChangeListener) v.get(i)).propertyChange(event); 383 } 384 Hashtable h = children; // Be thread-safe. 385 if (h != null && event.propertyName != null) 386 { 387 PropertyChangeSupport s 388 = (PropertyChangeSupport) h.get(event.propertyName); 389 if (s != null) 390 { 391 v = s.listeners; // Be thread-safe. 392 int i = v == null ? 0 : v.size(); 393 while (--i >= 0) 394 ((PropertyChangeListener) v.get(i)).propertyChange(event); 395 } 396 } 397 } 398 399 /** 400 * Tell whether the specified property is being listened on or not. This 401 * will only return <code>true</code> if there are listeners on all 402 * properties or if there is a listener specifically on this property. 403 * 404 * @param propertyName the property that may be listened on 405 * @return whether the property is being listened on 406 * @throws NullPointerException if propertyName is null 407 */ 408 public synchronized boolean hasListeners(String propertyName) 409 { 410 return listeners != null || (children != null 411 && children.get(propertyName) != null); 412 } 413 414 /** 415 * Saves the state of the object to the stream. 416 * 417 * @param s the stream to write to 418 * @throws IOException if anything goes wrong 419 * @serialData this writes out a null-terminated list of serializable 420 * global property change listeners (the listeners for a named 421 * property are written out as the global listeners of the 422 * children, when the children hashtable is saved) 423 */ 424 private synchronized void writeObject(ObjectOutputStream s) 425 throws IOException 426 { 427 s.defaultWriteObject(); 428 if (listeners != null) 429 { 430 int i = listeners.size(); 431 while (--i >= 0) 432 if (listeners.get(i) instanceof Serializable) 433 s.writeObject(listeners.get(i)); 434 } 435 s.writeObject(null); 436 } 437 438 /** 439 * Reads the object back from stream (deserialization). 440 * 441 * XXX Since serialization for 1.1 streams was not documented, this may 442 * not work if propertyChangeSupportSerializedDataVersion is 1. 443 * 444 * @param s the stream to read from 445 * @throws IOException if reading the stream fails 446 * @throws ClassNotFoundException if deserialization fails 447 * @serialData this reads in a null-terminated list of serializable 448 * global property change listeners (the listeners for a named 449 * property are written out as the global listeners of the 450 * children, when the children hashtable is saved) 451 */ 452 private void readObject(ObjectInputStream s) 453 throws IOException, ClassNotFoundException 454 { 455 s.defaultReadObject(); 456 PropertyChangeListener l = (PropertyChangeListener) s.readObject(); 457 while (l != null) 458 { 459 addPropertyChangeListener(l); 460 l = (PropertyChangeListener) s.readObject(); 461 } 462 // Sun is not as careful with children as we are, and lets some proxys 463 // in that can never receive events. So, we clean up anything that got 464 // serialized, to make sure our invariants hold. 465 if (children != null) 466 { 467 int i = children.size(); 468 Iterator iter = children.entrySet().iterator(); 469 while (--i >= 0) 470 { 471 Entry e = (Entry) iter.next(); 472 String name = (String) e.getKey(); 473 PropertyChangeSupport pcs = (PropertyChangeSupport) e.getValue(); 474 if (pcs.listeners == null) 475 pcs.listeners = new Vector(); 476 if (pcs.children != null) 477 pcs.listeners.addAll 478 (Arrays.asList(pcs.getPropertyChangeListeners(name))); 479 if (pcs.listeners.size() == 0) 480 iter.remove(); 481 else 482 pcs.children = null; 483 } 484 if (children.size() == 0) 485 children = null; 486 } 487 } 488 } // class PropertyChangeSupport -
Property cvs2svn:cvs-rev
changed from
Note:
See TracChangeset
for help on using the changeset viewer.
