001: /*
002: * @(#)PropertyChangeSupport.java 1.47 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package java.beans;
029:
030: import java.io.Serializable;
031: import java.io.ObjectOutputStream;
032: import java.io.ObjectInputStream;
033: import java.io.IOException;
034: import java.util.ArrayList;
035: import java.util.Arrays;
036: import java.util.List;
037:
038: /**
039: * This is a utility class that can be used by beans that support bound
040: * properties. You can use an instance of this class as a member field
041: * of your bean and delegate various work to it.
042: *
043: * This class is serializable. When it is serialized it will save
044: * (and restore) any listeners that are themselves serializable. Any
045: * non-serializable listeners will be skipped during serialization.
046: *
047: */
048:
049: public class PropertyChangeSupport implements java.io.Serializable {
050: /**
051: * Constructs a <code>PropertyChangeSupport</code> object.
052: *
053: * @param sourceBean The bean to be given as the source for any events.
054: */
055:
056: public PropertyChangeSupport(Object sourceBean) {
057: if (sourceBean == null) {
058: throw new NullPointerException();
059: }
060: source = sourceBean;
061: }
062:
063: /**
064: * Add a PropertyChangeListener to the listener list.
065: * The listener is registered for all properties.
066: *
067: * @param listener The PropertyChangeListener to be added
068: */
069:
070: public synchronized void addPropertyChangeListener(
071: PropertyChangeListener listener) {
072: if (listeners == null) {
073: listeners = new java.util.Vector();
074: }
075: listeners.addElement(listener);
076: }
077:
078: /**
079: * Remove a PropertyChangeListener from the listener list.
080: * This removes a PropertyChangeListener that was registered
081: * for all properties.
082: *
083: * @param listener The PropertyChangeListener to be removed
084: */
085:
086: public synchronized void removePropertyChangeListener(
087: PropertyChangeListener listener) {
088: if (listeners == null) {
089: return;
090: }
091: listeners.removeElement(listener);
092: }
093:
094: /**
095: * Add a PropertyChangeListener for a specific property. The listener
096: * will be invoked only when a call on firePropertyChange names that
097: * specific property.
098: *
099: * @param propertyName The name of the property to listen on.
100: * @param listener The PropertyChangeListener to be added
101: */
102:
103: /* public synchronized void addPropertyChangeListener(
104: String propertyName,
105: PropertyChangeListener listener) {
106: if (children == null) {
107: children = new java.util.Hashtable();
108: }
109: PropertyChangeSupport child = (PropertyChangeSupport)children.get(propertyName);
110: if (child == null) {
111: child = new PropertyChangeSupport(source);
112: children.put(propertyName, child);
113: }
114: child.addPropertyChangeListener(listener);
115: }
116: */
117:
118: /**
119: * Remove a PropertyChangeListener for a specific property.
120: *
121: * @param propertyName The name of the property that was listened on.
122: * @param listener The PropertyChangeListener to be removed
123: */
124:
125: /* public synchronized void removePropertyChangeListener(
126: String propertyName,
127: PropertyChangeListener listener) {
128: if (children == null) {
129: return;
130: }
131: PropertyChangeSupport child = (PropertyChangeSupport)children.get(propertyName);
132: if (child == null) {
133: return;
134: }
135: child.removePropertyChangeListener(listener);
136: }
137: */
138:
139: /**
140: * Report a bound property update to any registered listeners.
141: * No event is fired if old and new are equal and non-null.
142: *
143: * @param propertyName The programmatic name of the property
144: * that was changed.
145: * @param oldValue The old value of the property.
146: * @param newValue The new value of the property.
147: */
148: public void firePropertyChange(String propertyName,
149: Object oldValue, Object newValue) {
150: if (oldValue != null && newValue != null
151: && oldValue.equals(newValue)) {
152: return;
153: }
154: java.util.Vector targets = null;
155: PropertyChangeSupport child = null;
156: synchronized (this ) {
157: if (listeners != null) {
158: targets = (java.util.Vector) listeners.clone();
159: }
160: if (children != null && propertyName != null) {
161: child = (PropertyChangeSupport) children
162: .get(propertyName);
163: }
164: }
165: PropertyChangeEvent evt = new PropertyChangeEvent(source,
166: propertyName, oldValue, newValue);
167: if (targets != null) {
168: for (int i = 0; i < targets.size(); i++) {
169: PropertyChangeListener target = (PropertyChangeListener) targets
170: .elementAt(i);
171: target.propertyChange(evt);
172: }
173: }
174: if (child != null) {
175: child.firePropertyChange(evt);
176: }
177: }
178:
179: /**
180: * Report an int bound property update to any registered listeners.
181: * No event is fired if old and new are equal and non-null.
182: * <p>
183: * This is merely a convenience wrapper around the more general
184: * firePropertyChange method that takes Object values.
185: *
186: * @param propertyName The programmatic name of the property
187: * that was changed.
188: * @param oldValue The old value of the property.
189: * @param newValue The new value of the property.
190: */
191:
192: /* public void firePropertyChange(String propertyName,
193: int oldValue, int newValue) {
194: if (oldValue == newValue) {
195: return;
196: }
197: firePropertyChange(propertyName, new Integer(oldValue), new Integer(newValue));
198: }
199: */
200:
201: /**
202: * Report a boolean bound property update to any registered listeners.
203: * No event is fired if old and new are equal and non-null.
204: * <p>
205: * This is merely a convenience wrapper around the more general
206: * firePropertyChange method that takes Object values.
207: *
208: * @param propertyName The programmatic name of the property
209: * that was changed.
210: * @param oldValue The old value of the property.
211: * @param newValue The new value of the property.
212: */
213:
214: /* public void firePropertyChange(String propertyName,
215: boolean oldValue, boolean newValue) {
216: if (oldValue == newValue) {
217: return;
218: }
219: firePropertyChange(propertyName, new Boolean(oldValue), new Boolean(newValue));
220: }
221: */
222:
223: /**
224: * Fire an existing PropertyChangeEvent to any registered listeners.
225: * No event is fired if the given event's old and new values are
226: * equal and non-null.
227: * @param evt The PropertyChangeEvent object.
228: */
229: private void firePropertyChange(PropertyChangeEvent evt) {
230: Object oldValue = evt.getOldValue();
231: Object newValue = evt.getNewValue();
232: String propertyName = evt.getPropertyName();
233: if (oldValue != null && newValue != null
234: && oldValue.equals(newValue)) {
235: return;
236: }
237: java.util.Vector targets = null;
238: PropertyChangeSupport child = null;
239: synchronized (this ) {
240: if (listeners != null) {
241: targets = (java.util.Vector) listeners.clone();
242: }
243: if (children != null && propertyName != null) {
244: child = (PropertyChangeSupport) children
245: .get(propertyName);
246: }
247: }
248: if (targets != null) {
249: for (int i = 0; i < targets.size(); i++) {
250: PropertyChangeListener target = (PropertyChangeListener) targets
251: .elementAt(i);
252: target.propertyChange(evt);
253: }
254: }
255: if (child != null) {
256: child.firePropertyChange(evt);
257: }
258: }
259:
260: /**
261: * Check if there are any listeners for a specific property.
262: *
263: * @param propertyName the property name.
264: * @return true if there are ore or more listeners for the given property
265: */
266:
267: /* public synchronized boolean hasListeners(String propertyName) {
268: if (listeners != null && !listeners.isEmpty()) {
269: // there is a generic listener
270: return true;
271: }
272: if (children != null) {
273: PropertyChangeSupport child = (PropertyChangeSupport)children.get(propertyName);
274: if (child != null && child.listeners != null) {
275: return !child.listeners.isEmpty();
276: }
277: }
278: return false;
279: }
280: */
281:
282: /**
283: * @serialData Null terminated list of <code>PropertyChangeListeners</code>.
284: * <p>
285: * At serialization time we skip non-serializable listeners and
286: * only serialize the serializable listeners.
287: *
288: */
289: private void writeObject(ObjectOutputStream s) throws IOException {
290: s.defaultWriteObject();
291: java.util.Vector v = null;
292: synchronized (this ) {
293: if (listeners != null) {
294: v = (java.util.Vector) listeners.clone();
295: }
296: }
297: if (v != null) {
298: for (int i = 0; i < v.size(); i++) {
299: PropertyChangeListener l = (PropertyChangeListener) v
300: .elementAt(i);
301: if (l instanceof Serializable) {
302: s.writeObject(l);
303: }
304: }
305: }
306: s.writeObject(null);
307: }
308:
309: private void readObject(ObjectInputStream s)
310: throws ClassNotFoundException, IOException {
311: s.defaultReadObject();
312: Object listenerOrNull;
313: while (null != (listenerOrNull = s.readObject())) {
314: addPropertyChangeListener((PropertyChangeListener) listenerOrNull);
315: }
316: }
317:
318: /**
319: * "listeners" lists all the generic listeners.
320: *
321: * This is transient - its state is written in the writeObject method.
322: */
323: transient private java.util.Vector listeners;
324: /**
325: * Hashtable for managing listeners for specific properties.
326: * Maps property names to PropertyChangeSupport objects.
327: * @serial
328: * @since 1.2
329: */
330: private java.util.Hashtable children;
331: /**
332: * The object to be provided as the "source" for any generated events.
333: * @serial
334: */
335: private Object source;
336: /**
337: * Internal version number
338: * @serial
339: * @since
340: */
341: private int propertyChangeSupportSerializedDataVersion = 2;
342: /**
343: * Serialization version ID, so we're compatible with JDK 1.1
344: */
345: static final long serialVersionUID = 6401253773779951803L;
346:
347: // Focus-related functionality added
348: //-------------------------------------------------------------------------
349: public synchronized PropertyChangeListener[] getPropertyChangeListeners() {
350: List returnList = new ArrayList();
351: // Add all the PropertyChangeListeners
352: if (listeners != null) {
353: returnList.addAll(listeners);
354: }
355: return (PropertyChangeListener[]) (returnList
356: .toArray(new PropertyChangeListener[0]));
357: }
358:
359: /*
360: public synchronized PropertyChangeListener[] getPropertyChangeListeners(
361: String propertyName) {
362: ArrayList returnList = new ArrayList();
363: if (children != null) {
364: PropertyChangeSupport support =
365: (PropertyChangeSupport)children.get(propertyName);
366: if (support != null) {
367: returnList.addAll(
368: Arrays.asList(support.getPropertyChangeListeners()));
369: }
370: }
371: return (PropertyChangeListener[])(returnList.toArray
372: (new PropertyChangeListener[0]));
373: }
374:
375: public void firePropertyChange(String propertyName,
376: int oldValue, int newValue) {
377: if (oldValue == newValue) {
378: return;
379: }
380: firePropertyChange(propertyName, new Integer(oldValue), new Integer(newValue));
381: }
382:
383: public void firePropertyChange(String propertyName,
384: boolean oldValue, boolean newValue) {
385: if (oldValue == newValue) {
386: return;
387: }
388: firePropertyChange(propertyName, new Boolean(oldValue), new Boolean(newValue));
389: }
390:
391: public synchronized void addPropertyChangeListener(
392: String propertyName,
393: PropertyChangeListener listener) {
394: if (children == null) {
395: children = new java.util.Hashtable();
396: }
397: PropertyChangeSupport child = (PropertyChangeSupport)children.get(propertyName);
398: if (child == null) {
399: child = new PropertyChangeSupport(source);
400: children.put(propertyName, child);
401: }
402: child.addPropertyChangeListener(listener);
403: }
404:
405: public synchronized void removePropertyChangeListener(
406: String propertyName,
407: PropertyChangeListener listener) {
408: if (children == null) {
409: return;
410: }
411: PropertyChangeSupport child = (PropertyChangeSupport)children.get(propertyName);
412: if (child == null) {
413: return;
414: }
415: child.removePropertyChangeListener(listener);
416: }
417: */
418: }
|