60 * return this.value;
61 * }
62 *
63 * public void setValue(String newValue) {
64 * String oldValue = this.value;
65 * this.value = newValue;
66 * this.pcs.firePropertyChange("value", oldValue, newValue);
67 * }
68 *
69 * [...]
70 * }
71 * </pre>
72 * <p>
73 * A {@code PropertyChangeSupport} instance is thread-safe.
74 * <p>
75 * This class is serializable. When it is serialized it will save
76 * (and restore) any listeners that are themselves serializable. Any
77 * non-serializable listeners will be skipped during serialization.
78 *
79 * @see VetoableChangeSupport
80 */
81 public class PropertyChangeSupport implements Serializable {
82 private PropertyChangeListenerMap map = new PropertyChangeListenerMap();
83
84 /**
85 * Constructs a <code>PropertyChangeSupport</code> object.
86 *
87 * @param sourceBean The bean to be given as the source for any events.
88 */
89 public PropertyChangeSupport(Object sourceBean) {
90 if (sourceBean == null) {
91 throw new NullPointerException();
92 }
93 source = sourceBean;
94 }
95
96 /**
97 * Add a PropertyChangeListener to the listener list.
98 * The listener is registered for all properties.
99 * The same listener object may be added more than once, and will be called
174 * @return all of the <code>PropertyChangeListeners</code> added or an
175 * empty array if no listeners have been added
176 * @since 1.4
177 */
178 public PropertyChangeListener[] getPropertyChangeListeners() {
179 return this.map.getListeners();
180 }
181
182 /**
183 * Add a PropertyChangeListener for a specific property. The listener
184 * will be invoked only when a call on firePropertyChange names that
185 * specific property.
186 * The same listener object may be added more than once. For each
187 * property, the listener will be invoked the number of times it was added
188 * for that property.
189 * If <code>propertyName</code> or <code>listener</code> is null, no
190 * exception is thrown and no action is taken.
191 *
192 * @param propertyName The name of the property to listen on.
193 * @param listener The PropertyChangeListener to be added
194 */
195 public void addPropertyChangeListener(
196 String propertyName,
197 PropertyChangeListener listener) {
198 if (listener == null || propertyName == null) {
199 return;
200 }
201 listener = this.map.extract(listener);
202 if (listener != null) {
203 this.map.add(propertyName, listener);
204 }
205 }
206
207 /**
208 * Remove a PropertyChangeListener for a specific property.
209 * If <code>listener</code> was added more than once to the same event
210 * source for the specified property, it will be notified one less time
211 * after being removed.
212 * If <code>propertyName</code> is null, no exception is thrown and no
213 * action is taken.
214 * If <code>listener</code> is null, or was never added for the specified
215 * property, no exception is thrown and no action is taken.
216 *
217 * @param propertyName The name of the property that was listened on.
218 * @param listener The PropertyChangeListener to be removed
219 */
220 public void removePropertyChangeListener(
221 String propertyName,
222 PropertyChangeListener listener) {
223 if (listener == null || propertyName == null) {
224 return;
225 }
226 listener = this.map.extract(listener);
227 if (listener != null) {
228 this.map.remove(propertyName, listener);
229 }
230 }
231
232 /**
233 * Returns an array of all the listeners which have been associated
234 * with the named property.
235 *
236 * @param propertyName The name of the property being listened to
237 * @return all of the <code>PropertyChangeListeners</code> associated with
238 * the named property. If no such listeners have been added,
260 */
261 public void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
262 if (oldValue == null || newValue == null || !oldValue.equals(newValue)) {
263 firePropertyChange(new PropertyChangeEvent(this.source, propertyName, oldValue, newValue));
264 }
265 }
266
267 /**
268 * Reports an integer bound property update to listeners
269 * that have been registered to track updates of
270 * all properties or a property with the specified name.
271 * <p>
272 * No event is fired if old and new values are equal.
273 * <p>
274 * This is merely a convenience wrapper around the more general
275 * {@link #firePropertyChange(String, Object, Object)} method.
276 *
277 * @param propertyName the programmatic name of the property that was changed
278 * @param oldValue the old value of the property
279 * @param newValue the new value of the property
280 */
281 public void firePropertyChange(String propertyName, int oldValue, int newValue) {
282 if (oldValue != newValue) {
283 firePropertyChange(propertyName, Integer.valueOf(oldValue), Integer.valueOf(newValue));
284 }
285 }
286
287 /**
288 * Reports a boolean bound property update to listeners
289 * that have been registered to track updates of
290 * all properties or a property with the specified name.
291 * <p>
292 * No event is fired if old and new values are equal.
293 * <p>
294 * This is merely a convenience wrapper around the more general
295 * {@link #firePropertyChange(String, Object, Object)} method.
296 *
297 * @param propertyName the programmatic name of the property that was changed
298 * @param oldValue the old value of the property
299 * @param newValue the new value of the property
300 */
301 public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {
302 if (oldValue != newValue) {
303 firePropertyChange(propertyName, Boolean.valueOf(oldValue), Boolean.valueOf(newValue));
304 }
305 }
306
307 /**
308 * Fires a property change event to listeners
309 * that have been registered to track updates of
310 * all properties or a property with the specified name.
311 * <p>
312 * No event is fired if the given event's old and new values are equal and non-null.
313 *
314 * @param event the {@code PropertyChangeEvent} to be fired
315 */
316 public void firePropertyChange(PropertyChangeEvent event) {
317 Object oldValue = event.getOldValue();
318 Object newValue = event.getNewValue();
319 if (oldValue == null || newValue == null || !oldValue.equals(newValue)) {
320 String name = event.getPropertyName();
321
322 PropertyChangeListener[] common = this.map.get(null);
323 PropertyChangeListener[] named = (name != null)
324 ? this.map.get(name)
325 : null;
326
327 fire(common, event);
328 fire(named, event);
329 }
330 }
331
332 private static void fire(PropertyChangeListener[] listeners, PropertyChangeEvent event) {
333 if (listeners != null) {
334 for (PropertyChangeListener listener : listeners) {
393 *
394 * @param propertyName the programmatic name of the property that was changed
395 * @param index the index of the property element that was changed
396 * @param oldValue the old value of the property
397 * @param newValue the new value of the property
398 * @since 1.5
399 */
400 public void fireIndexedPropertyChange(String propertyName, int index, boolean oldValue, boolean newValue) {
401 if (oldValue != newValue) {
402 fireIndexedPropertyChange(propertyName, index, Boolean.valueOf(oldValue), Boolean.valueOf(newValue));
403 }
404 }
405
406 /**
407 * Check if there are any listeners for a specific property, including
408 * those registered on all properties. If <code>propertyName</code>
409 * is null, only check for listeners registered on all properties.
410 *
411 * @param propertyName the property name.
412 * @return true if there are one or more listeners for the given property
413 */
414 public boolean hasListeners(String propertyName) {
415 return this.map.hasListeners(propertyName);
416 }
417
418 /**
419 * @serialData Null terminated list of <code>PropertyChangeListeners</code>.
420 * <p>
421 * At serialization time we skip non-serializable listeners and
422 * only serialize the serializable listeners.
423 */
424 private void writeObject(ObjectOutputStream s) throws IOException {
425 Hashtable<String, PropertyChangeSupport> children = null;
426 PropertyChangeListener[] listeners = null;
427 synchronized (this.map) {
428 for (Entry<String, PropertyChangeListener[]> entry : this.map.getEntries()) {
429 String property = entry.getKey();
430 if (property == null) {
431 listeners = entry.getValue();
432 } else {
|
60 * return this.value;
61 * }
62 *
63 * public void setValue(String newValue) {
64 * String oldValue = this.value;
65 * this.value = newValue;
66 * this.pcs.firePropertyChange("value", oldValue, newValue);
67 * }
68 *
69 * [...]
70 * }
71 * </pre>
72 * <p>
73 * A {@code PropertyChangeSupport} instance is thread-safe.
74 * <p>
75 * This class is serializable. When it is serialized it will save
76 * (and restore) any listeners that are themselves serializable. Any
77 * non-serializable listeners will be skipped during serialization.
78 *
79 * @see VetoableChangeSupport
80 * @since 1.1
81 */
82 public class PropertyChangeSupport implements Serializable {
83 private PropertyChangeListenerMap map = new PropertyChangeListenerMap();
84
85 /**
86 * Constructs a <code>PropertyChangeSupport</code> object.
87 *
88 * @param sourceBean The bean to be given as the source for any events.
89 */
90 public PropertyChangeSupport(Object sourceBean) {
91 if (sourceBean == null) {
92 throw new NullPointerException();
93 }
94 source = sourceBean;
95 }
96
97 /**
98 * Add a PropertyChangeListener to the listener list.
99 * The listener is registered for all properties.
100 * The same listener object may be added more than once, and will be called
175 * @return all of the <code>PropertyChangeListeners</code> added or an
176 * empty array if no listeners have been added
177 * @since 1.4
178 */
179 public PropertyChangeListener[] getPropertyChangeListeners() {
180 return this.map.getListeners();
181 }
182
183 /**
184 * Add a PropertyChangeListener for a specific property. The listener
185 * will be invoked only when a call on firePropertyChange names that
186 * specific property.
187 * The same listener object may be added more than once. For each
188 * property, the listener will be invoked the number of times it was added
189 * for that property.
190 * If <code>propertyName</code> or <code>listener</code> is null, no
191 * exception is thrown and no action is taken.
192 *
193 * @param propertyName The name of the property to listen on.
194 * @param listener The PropertyChangeListener to be added
195 * @since 1.2
196 */
197 public void addPropertyChangeListener(
198 String propertyName,
199 PropertyChangeListener listener) {
200 if (listener == null || propertyName == null) {
201 return;
202 }
203 listener = this.map.extract(listener);
204 if (listener != null) {
205 this.map.add(propertyName, listener);
206 }
207 }
208
209 /**
210 * Remove a PropertyChangeListener for a specific property.
211 * If <code>listener</code> was added more than once to the same event
212 * source for the specified property, it will be notified one less time
213 * after being removed.
214 * If <code>propertyName</code> is null, no exception is thrown and no
215 * action is taken.
216 * If <code>listener</code> is null, or was never added for the specified
217 * property, no exception is thrown and no action is taken.
218 *
219 * @param propertyName The name of the property that was listened on.
220 * @param listener The PropertyChangeListener to be removed
221 * @since 1.2
222 */
223 public void removePropertyChangeListener(
224 String propertyName,
225 PropertyChangeListener listener) {
226 if (listener == null || propertyName == null) {
227 return;
228 }
229 listener = this.map.extract(listener);
230 if (listener != null) {
231 this.map.remove(propertyName, listener);
232 }
233 }
234
235 /**
236 * Returns an array of all the listeners which have been associated
237 * with the named property.
238 *
239 * @param propertyName The name of the property being listened to
240 * @return all of the <code>PropertyChangeListeners</code> associated with
241 * the named property. If no such listeners have been added,
263 */
264 public void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
265 if (oldValue == null || newValue == null || !oldValue.equals(newValue)) {
266 firePropertyChange(new PropertyChangeEvent(this.source, propertyName, oldValue, newValue));
267 }
268 }
269
270 /**
271 * Reports an integer bound property update to listeners
272 * that have been registered to track updates of
273 * all properties or a property with the specified name.
274 * <p>
275 * No event is fired if old and new values are equal.
276 * <p>
277 * This is merely a convenience wrapper around the more general
278 * {@link #firePropertyChange(String, Object, Object)} method.
279 *
280 * @param propertyName the programmatic name of the property that was changed
281 * @param oldValue the old value of the property
282 * @param newValue the new value of the property
283 * @since 1.2
284 */
285 public void firePropertyChange(String propertyName, int oldValue, int newValue) {
286 if (oldValue != newValue) {
287 firePropertyChange(propertyName, Integer.valueOf(oldValue), Integer.valueOf(newValue));
288 }
289 }
290
291 /**
292 * Reports a boolean bound property update to listeners
293 * that have been registered to track updates of
294 * all properties or a property with the specified name.
295 * <p>
296 * No event is fired if old and new values are equal.
297 * <p>
298 * This is merely a convenience wrapper around the more general
299 * {@link #firePropertyChange(String, Object, Object)} method.
300 *
301 * @param propertyName the programmatic name of the property that was changed
302 * @param oldValue the old value of the property
303 * @param newValue the new value of the property
304 * @since 1.2
305 */
306 public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {
307 if (oldValue != newValue) {
308 firePropertyChange(propertyName, Boolean.valueOf(oldValue), Boolean.valueOf(newValue));
309 }
310 }
311
312 /**
313 * Fires a property change event to listeners
314 * that have been registered to track updates of
315 * all properties or a property with the specified name.
316 * <p>
317 * No event is fired if the given event's old and new values are equal and non-null.
318 *
319 * @param event the {@code PropertyChangeEvent} to be fired
320 * @since 1.2
321 */
322 public void firePropertyChange(PropertyChangeEvent event) {
323 Object oldValue = event.getOldValue();
324 Object newValue = event.getNewValue();
325 if (oldValue == null || newValue == null || !oldValue.equals(newValue)) {
326 String name = event.getPropertyName();
327
328 PropertyChangeListener[] common = this.map.get(null);
329 PropertyChangeListener[] named = (name != null)
330 ? this.map.get(name)
331 : null;
332
333 fire(common, event);
334 fire(named, event);
335 }
336 }
337
338 private static void fire(PropertyChangeListener[] listeners, PropertyChangeEvent event) {
339 if (listeners != null) {
340 for (PropertyChangeListener listener : listeners) {
399 *
400 * @param propertyName the programmatic name of the property that was changed
401 * @param index the index of the property element that was changed
402 * @param oldValue the old value of the property
403 * @param newValue the new value of the property
404 * @since 1.5
405 */
406 public void fireIndexedPropertyChange(String propertyName, int index, boolean oldValue, boolean newValue) {
407 if (oldValue != newValue) {
408 fireIndexedPropertyChange(propertyName, index, Boolean.valueOf(oldValue), Boolean.valueOf(newValue));
409 }
410 }
411
412 /**
413 * Check if there are any listeners for a specific property, including
414 * those registered on all properties. If <code>propertyName</code>
415 * is null, only check for listeners registered on all properties.
416 *
417 * @param propertyName the property name.
418 * @return true if there are one or more listeners for the given property
419 * @since 1.2
420 */
421 public boolean hasListeners(String propertyName) {
422 return this.map.hasListeners(propertyName);
423 }
424
425 /**
426 * @serialData Null terminated list of <code>PropertyChangeListeners</code>.
427 * <p>
428 * At serialization time we skip non-serializable listeners and
429 * only serialize the serializable listeners.
430 */
431 private void writeObject(ObjectOutputStream s) throws IOException {
432 Hashtable<String, PropertyChangeSupport> children = null;
433 PropertyChangeListener[] listeners = null;
434 synchronized (this.map) {
435 for (Entry<String, PropertyChangeListener[]> entry : this.map.getEntries()) {
436 String property = entry.getKey();
437 if (property == null) {
438 listeners = entry.getValue();
439 } else {
|