This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
Patch: FYI: Merge java.beans
- From: Tom Tromey <tromey at redhat dot com>
- To: Java Patch List <java-patches at gcc dot gnu dot org>
- Date: 15 Jul 2002 10:09:49 -0600
- Subject: Patch: FYI: Merge java.beans
- Reply-to: tromey at redhat dot com
I'm checking this in. This patch re-syncs java.beans with Classpath.
Tom
Index: ChangeLog
from Tom Tromey <tromey@redhat.com>
* Makefile.in: Rebuilt.
* Makefile.am (awt_java_source_files): Added new files.
* java/beans/ExceptionListener.java: Merged with Classpath.
* java/beans/PropertyChangeEvent.java: Merged with Classpath.
* java/beans/PropertyChangeListener.java: Merged with Classpath.
* java/beans/PropertyChangeListenerProxy.java: Merged with Classpath.
* java/beans/PropertyChangeSupport.java: Merged with Classpath.
* java/beans/VetoableChangeListener.java: Merged with Classpath.
* java/beans/VetoableChangeListenerProxy.java: Merged with Classpath.
* java/beans/VetoableChangeSupport.java: Merged with Classpath.
Index: Makefile.am
===================================================================
RCS file: /cvs/gcc/gcc/libjava/Makefile.am,v
retrieving revision 1.231
diff -u -r1.231 Makefile.am
--- Makefile.am 14 Jul 2002 22:18:34 -0000 1.231
+++ Makefile.am 15 Jul 2002 16:03:13 -0000
@@ -799,6 +799,7 @@
java/beans/Customizer.java \
java/beans/DesignMode.java \
java/beans/EventSetDescriptor.java \
+java/beans/ExceptionListener.java \
java/beans/FeatureDescriptor.java \
java/beans/IndexedPropertyDescriptor.java \
java/beans/IntrospectionException.java \
@@ -807,6 +808,7 @@
java/beans/ParameterDescriptor.java \
java/beans/PropertyChangeEvent.java \
java/beans/PropertyChangeListener.java \
+java/beans/PropertyChangeListenerProxy.java \
java/beans/PropertyChangeSupport.java \
java/beans/PropertyDescriptor.java \
java/beans/PropertyEditor.java \
@@ -815,6 +817,7 @@
java/beans/PropertyVetoException.java \
java/beans/SimpleBeanInfo.java \
java/beans/VetoableChangeListener.java \
+java/beans/VetoableChangeListenerProxy.java \
java/beans/VetoableChangeSupport.java \
java/beans/Visibility.java
Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/libjava/Makefile.in,v
retrieving revision 1.251
diff -u -r1.251 Makefile.in
--- Makefile.in 14 Jul 2002 22:18:34 -0000 1.251
+++ Makefile.in 15 Jul 2002 16:03:17 -0000
@@ -568,6 +568,7 @@
java/beans/Customizer.java \
java/beans/DesignMode.java \
java/beans/EventSetDescriptor.java \
+java/beans/ExceptionListener.java \
java/beans/FeatureDescriptor.java \
java/beans/IndexedPropertyDescriptor.java \
java/beans/IntrospectionException.java \
@@ -576,6 +577,7 @@
java/beans/ParameterDescriptor.java \
java/beans/PropertyChangeEvent.java \
java/beans/PropertyChangeListener.java \
+java/beans/PropertyChangeListenerProxy.java \
java/beans/PropertyChangeSupport.java \
java/beans/PropertyDescriptor.java \
java/beans/PropertyEditor.java \
@@ -584,6 +586,7 @@
java/beans/PropertyVetoException.java \
java/beans/SimpleBeanInfo.java \
java/beans/VetoableChangeListener.java \
+java/beans/VetoableChangeListenerProxy.java \
java/beans/VetoableChangeSupport.java \
java/beans/Visibility.java
@@ -1776,7 +1779,7 @@
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
-TAR = tar
+TAR = gtar
GZIP_ENV = --best
DIST_SUBDIRS = @DIRLTDL@ testsuite gcj include @DIRLTDL@ gcj include
DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \
@@ -2197,6 +2200,7 @@
.deps/java/beans/BeanInfo.P .deps/java/beans/Beans.P \
.deps/java/beans/Customizer.P .deps/java/beans/DesignMode.P \
.deps/java/beans/EventSetDescriptor.P \
+.deps/java/beans/ExceptionListener.P \
.deps/java/beans/FeatureDescriptor.P \
.deps/java/beans/IndexedPropertyDescriptor.P \
.deps/java/beans/IntrospectionException.P \
@@ -2204,6 +2208,7 @@
.deps/java/beans/ParameterDescriptor.P \
.deps/java/beans/PropertyChangeEvent.P \
.deps/java/beans/PropertyChangeListener.P \
+.deps/java/beans/PropertyChangeListenerProxy.P \
.deps/java/beans/PropertyChangeSupport.P \
.deps/java/beans/PropertyDescriptor.P .deps/java/beans/PropertyEditor.P \
.deps/java/beans/PropertyEditorManager.P \
@@ -2211,6 +2216,7 @@
.deps/java/beans/PropertyVetoException.P \
.deps/java/beans/SimpleBeanInfo.P \
.deps/java/beans/VetoableChangeListener.P \
+.deps/java/beans/VetoableChangeListenerProxy.P \
.deps/java/beans/VetoableChangeSupport.P .deps/java/beans/Visibility.P \
.deps/java/beans/beancontext/BeanContext.P \
.deps/java/beans/beancontext/BeanContextChild.P \
Index: java/beans/ExceptionListener.java
===================================================================
RCS file: java/beans/ExceptionListener.java
diff -N java/beans/ExceptionListener.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ java/beans/ExceptionListener.java 15 Jul 2002 16:03:17 -0000
@@ -0,0 +1,57 @@
+/* ExceptionListener.java -- listen for recoverable internal exceptions
+ Copyright (C) 2002 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans;
+
+/**
+ * This interface allows a class to monitor internal exceptions, to try to
+ * recover from them.
+ *
+ * @author Eric Blake <ebb9@email.byu.edu>
+ * @since 1.4
+ * @status updated to 1.4
+ */
+public interface ExceptionListener
+{
+ /**
+ * Fired after an exception occurs.
+ *
+ * @param e the trapped exception
+ */
+ void exceptionThrown(Exception e);
+} // interface ExceptionListener
Index: java/beans/PropertyChangeEvent.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/beans/PropertyChangeEvent.java,v
retrieving revision 1.4
diff -u -r1.4 PropertyChangeEvent.java
--- java/beans/PropertyChangeEvent.java 22 Jan 2002 22:40:11 -0000 1.4
+++ java/beans/PropertyChangeEvent.java 15 Jul 2002 16:03:17 -0000
@@ -1,5 +1,5 @@
-/* java.beans.PropertyChangeEvent
- Copyright (C) 1998, 2000 Free Software Foundation, Inc.
+/* PropertyChangeEvent.java -- describes a change in a property
+ Copyright (C) 1998, 2000, 2002 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -7,7 +7,7 @@
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-
+
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@@ -38,87 +38,152 @@
package java.beans;
+import java.util.EventObject;
+
/**
- ** PropertyChangeEvents are fired in the PropertyChange
- ** and VetoableChange event classes. They represent the
- ** old and new values as well as the source Bean.<P>
- **
- ** If the old or new value is a primitive type, it must
- ** be wrapped in the appropriate wrapper type
- ** (java.lang.Integer for int, etc., etc.).<P>
- **
- ** If the old or new values are unknown (although why
- ** that would be I do not know), they may be null.<P>
- **
- ** Right now Sun put in a propagationId, reserved for
- ** future use. Read the comments on the constructor
- ** and on setPropagationId for more information.
- **
- ** @author John Keiser
- ** @since JDK1.1
- ** @version 1.1.0, 29 Jul 1998
- **/
-
-public class PropertyChangeEvent extends java.util.EventObject {
- String propertyName;
- Object oldValue;
- Object newValue;
- Object propagationId;
-
- private static final long serialVersionUID = 7042693688939648123L;
-
- /** Create a new PropertyChangeEvent. Remember that if
- ** you received a PropertyChangeEvent and are sending
- ** a new one, you should also set the propagation ID
- ** from the old PropertyChangeEvent.
- ** @param source the Bean containing the property.
- ** @param propertyName the property's name.
- ** @param oldValue the old value of the property.
- ** @param newValue the new value of the property.
- **/
- public PropertyChangeEvent(Object source, String propertyName, Object oldVal, Object newVal) {
- super(source);
- this.propertyName = propertyName;
- oldValue = oldVal;
- newValue = newVal;
- }
-
- /** Get the property name.
- ** @return the property name.
- **/
- public String getPropertyName() {
- return propertyName;
- }
-
- /** Get the property's old value.
- ** @return the property's old value.
- **/
- public Object getOldValue() {
- return oldValue;
- }
-
- /** Get the property's new value.
- ** @return the property's new value.
- **/
- public Object getNewValue() {
- return newValue;
- }
-
- /** Set the propagation ID. This is a way for the event
- ** to be passed from hand to hand and retain a little
- ** extra state. Right now it is unused, but it should
- ** be propagated anyway so that future versions of
- ** JavaBeans can use it, for God knows what.
- ** @param propagationId the propagation ID.
- **/
- public void setPropagationId(Object propagationId) {
- this.propagationId = propagationId;
- }
-
- /** Get the propagation ID.
- ** @return the propagation ID.
- **/
- public Object getPropagationId() {
- return propagationId;
- }
-}
+ * PropertyChangeEvents are fired in the PropertyChange and VetoableChange
+ * event classes. They represent the old and new values as well as the
+ * source Bean. If the old or new value is a primitive type, it must be
+ * wrapped in the appropriate wrapper type (java.lang.Integer for int, etc.,
+ * etc.).
+ *
+ * <p>If the old or new values are unknown (although why that would be I do
+ * not know), they may be null. Also, if the set of properties itself has
+ * changed, the name should be null, and the old and new values may also be
+ * null. Right now Sun put in a propagationId, reserved for future use. Read
+ * the comments on the constructor and on setPropagationId for more
+ * information.
+ *
+ * @author John Keiser
+ * @author Eric Blake <ebb9@email.byu.edu>
+ * @since 1.1
+ * @status udpated to 1.4
+ */
+public class PropertyChangeEvent extends EventObject
+{
+ /**
+ * Compatible with JDK 1.1+.
+ */
+ private static final long serialVersionUID = 7042693688939648123L;
+
+ /**
+ * The name of the property that changed, may be null. Package visible for
+ * use by PropertyChangeSupport.
+ *
+ * @serial the changed property name
+ */
+ final String propertyName;
+
+ /**
+ * The new value of the property, may be null. Package visible for use by
+ * PropertyChangeSupport.
+ *
+ * @serial the new property value
+ */
+ final Object newValue;
+
+ /**
+ * The old value of the property, may be null. Package visible for use by
+ * PropertyChangeSupport.
+ *
+ * @serial the old property value
+ */
+ final Object oldValue;
+
+ /**
+ * The propagation ID, reserved for future use. May be null.
+ *
+ * @see #getPropagationId()
+ * @serial the Propagation ID
+ */
+ private Object propagationId;
+
+ /**
+ * Create a new PropertyChangeEvent. Remember that if you received a
+ * PropertyChangeEvent and are sending a new one, you should also set the
+ * propagation ID from the old PropertyChangeEvent.
+ *
+ * @param source the Bean containing the property
+ * @param propertyName the property's name
+ * @param oldValue the old value of the property
+ * @param newValue the new value of the property
+ * @throws IllegalArgumentException if source is null
+ */
+ public PropertyChangeEvent(Object source, String propertyName,
+ Object oldVal, Object newVal)
+ {
+ super(source);
+ this.propertyName = propertyName;
+ oldValue = oldVal;
+ newValue = newVal;
+ }
+
+ /**
+ * Get the property name. May be null if multiple properties changed.
+ *
+ * @return the property name
+ */
+ public String getPropertyName()
+ {
+ return propertyName;
+ }
+
+ /**
+ * Get the property's new value. May be null if multiple properties changed.
+ *
+ * @return the property's new value
+ */
+ public Object getNewValue()
+ {
+ return newValue;
+ }
+
+ /**
+ * Get the property's old value. May be null if multiple properties changed.
+ *
+ * @return the property's old value
+ */
+ public Object getOldValue()
+ {
+ return oldValue;
+ }
+
+ /**
+ * Set the propagation ID. This is a way for the event to be passed from
+ * hand to hand and retain a little extra state. Right now it is unused,
+ * but it should be propagated anyway so that future versions of JavaBeans
+ * can use it, for God knows what.
+ *
+ * @param propagationId the propagation ID
+ * @see #getPropagationId()
+ */
+ public void setPropagationId(Object propagationId)
+ {
+ this.propagationId = propagationId;
+ }
+
+ /**
+ * Get the propagation ID. Right now, it is not used for anything.
+ *
+ * @return the propagation ID
+ * @see #setPropagationId(Object)
+ */
+ public Object getPropagationId()
+ {
+ return propagationId;
+ }
+
+ /**
+ * Utility method to rollback a change.
+ *
+ * @param event the event to rollback
+ * @return a new event with old and new swapped
+ */
+ PropertyChangeEvent rollback()
+ {
+ PropertyChangeEvent result
+ = new PropertyChangeEvent(source, propertyName, newValue, oldValue);
+ result.propagationId = propagationId;
+ return result;
+ }
+} // class PropertyChangeEvent
Index: java/beans/PropertyChangeListener.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/beans/PropertyChangeListener.java,v
retrieving revision 1.3
diff -u -r1.3 PropertyChangeListener.java
--- java/beans/PropertyChangeListener.java 22 Jan 2002 22:40:11 -0000 1.3
+++ java/beans/PropertyChangeListener.java 15 Jul 2002 16:03:17 -0000
@@ -1,5 +1,5 @@
-/* java.beans.PropertyChangeListener
- Copyright (C) 1998, 2000 Free Software Foundation, Inc.
+/* PropertyChangeListener.java -- listen for changes in a bound property
+ Copyright (C) 1998, 2000, 2002 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -7,7 +7,7 @@
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-
+
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@@ -41,22 +41,21 @@
import java.util.EventListener;
/**
- ** PropertyChangeListener allows a class to monitor
- ** properties of a Bean for changes.<P>
- **
- ** A propertyChange() event will only be fired
- ** <EM>after</EM> the property has changed.
- **
- ** @author John Keiser
- ** @since JDK1.1
- ** @version 1.1.0, 29 Jul 1998
- ** @see java.beans.PropertyChangeSupport
- **/
-
+ * PropertyChangeListener allows a class to monitor properties of a Bean for
+ * changes. A propertyChange() event will only be fired <em>after</em> the
+ * property has changed.
+ *
+ * @author John Keiser
+ * @see PropertyChangeSupport
+ * @since 1.1
+ * @status updated to 1.4
+ */
public interface PropertyChangeListener extends EventListener
{
- /** Fired after a Bean's property has changed.
- ** @param e the change (containing the old and new values)
- **/
- public abstract void propertyChange(PropertyChangeEvent e);
-}
+ /**
+ * Fired after a Bean's property has changed.
+ *
+ * @param e the change (containing the old and new values)
+ */
+ void propertyChange(PropertyChangeEvent e);
+} // interface PropertyChangeListener
Index: java/beans/PropertyChangeListenerProxy.java
===================================================================
RCS file: java/beans/PropertyChangeListenerProxy.java
diff -N java/beans/PropertyChangeListenerProxy.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ java/beans/PropertyChangeListenerProxy.java 15 Jul 2002 16:03:17 -0000
@@ -0,0 +1,102 @@
+/* PropertyChangeListenerProxy.java -- adds a name to a property listener
+ Copyright (C) 2002 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans;
+
+import java.util.EventListenerProxy;
+
+/**
+ * This class provides an extension to <code>PropertyChangeListener</code> -
+ * associating a name with the listener. This can be used to filter the
+ * changes that one is interested in.
+ *
+ * @author Eric Blake <ebb9@email.byu.edu>
+ * @since 1.4
+ * @status udpated to 1.4
+ */
+public class PropertyChangeListenerProxy extends EventListenerProxy
+ implements PropertyChangeListener
+{
+ /**
+ * The name of the property to listen for. Package visible for use by
+ * PropertyChangeSupport.
+ */
+ final String propertyName;
+
+ /**
+ * Create a new proxy which filters property change events and only passes
+ * changes to the named property on to the delegate. A null propertyName
+ * or listener does not fail now, but may cause a NullPointerException down
+ * the road.
+ *
+ * @param propertyName the property's name to filter on
+ * @param listener the delegate listener
+ */
+ public PropertyChangeListenerProxy(String propertyName,
+ PropertyChangeListener listener)
+ {
+ super(listener);
+ this.propertyName = propertyName;
+ }
+
+ /**
+ * Forwards the event on to the delegate if the property name matches.
+ *
+ * @param event the event to pass on, if it meets the filter
+ * @throws NullPointerException if the delegate this was created with is null
+ */
+ public void propertyChange(PropertyChangeEvent event)
+ {
+ // Note: Sun does not filter, under the assumption that since
+ // PropertyChangeSupport unwraps proxys, this method should never be
+ // called by normal use of listeners.
+ String name = event == null ? null : event.getPropertyName();
+ if (name == null ? propertyName == null : name.equals(propertyName))
+ ((PropertyChangeListener) getListener()).propertyChange(event);
+ }
+
+ /**
+ * Gets the name of the property this proxy is filtering on.
+ *
+ * @return the property name
+ */
+ public String getPropertyName()
+ {
+ return propertyName;
+ }
+} // class PropertyChangeListenerProxy
Index: java/beans/PropertyChangeSupport.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/beans/PropertyChangeSupport.java,v
retrieving revision 1.3
diff -u -r1.3 PropertyChangeSupport.java
--- java/beans/PropertyChangeSupport.java 22 Jan 2002 22:40:11 -0000 1.3
+++ java/beans/PropertyChangeSupport.java 15 Jul 2002 16:03:18 -0000
@@ -1,5 +1,5 @@
-/* java.beans.PropertyChangeSupport
- Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+/* PropertyChangeSupport.java -- support to manage property change listeners
+ Copyright (C) 1998, 1999, 2000, 2002 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -7,7 +7,7 @@
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-
+
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@@ -37,214 +37,452 @@
package java.beans;
-import java.util.Hashtable;
-import java.util.Vector;
-import java.util.Enumeration;
+
+import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
-import java.io.IOException;
import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map.Entry;
+import java.util.Vector;
/**
- ** PropertyChangeSupport makes it easy to fire property
- ** change events and handle listeners.
- **
- ** @author John Keiser
- ** @since JDK1.1
- ** @version 1.2.0, 15 Mar 1999
- **/
-
-public class PropertyChangeSupport implements java.io.Serializable {
- transient Hashtable propertyListeners = new Hashtable();
- transient Vector listeners = new Vector();
- Hashtable children;
- Object source;
- int propertyChangeSupportSerializedDataVersion = 2;
- private static final long serialVersionUID = 6401253773779951803L;
-
- /**
- * Saves the state of the object to the stream. */
- private void writeObject(ObjectOutputStream stream) throws IOException {
- children = propertyListeners.isEmpty() ? null : propertyListeners;
- stream.defaultWriteObject();
- for (Enumeration e = listeners.elements(); e.hasMoreElements(); ) {
- PropertyChangeListener l = (PropertyChangeListener)e.nextElement();
- if (l instanceof Serializable)
- stream.writeObject(l);
- }
- stream.writeObject(null);
- }
-
- /**
- * Reads the object back from stream (deserialization).
- */
- private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
- stream.defaultReadObject();
- propertyListeners = (children == null) ? new Hashtable() : children;
- PropertyChangeListener l;
- while ((l = (PropertyChangeListener)stream.readObject()) != null) {
- addPropertyChangeListener(l);
- }
- // FIXME: XXX: There is no spec for JDK 1.1 serialization
- // so it is unclear what to do if the value of
- // propertyChangeSupportSerializedDataVersion is 1.
- }
-
- /** Create PropertyChangeSupport to work with a specific
- ** source bean.
- ** @param source the source bean to use.
- **/
- public PropertyChangeSupport(Object source) {
- this.source = source;
- }
-
- /** Adds a PropertyChangeListener to the list of listeners.
- ** All property change events will be sent to this listener.
- ** <P>
- **
- ** The listener add is not unique: that is, <em>n</em> adds with
- ** the same listener will result in <em>n</em> events being sent
- ** to that listener for every property change.
- ** <P>
- **
- ** Adding a null listener will cause undefined behavior.
- **
- ** @param l the listener to add.
- **/
- public void addPropertyChangeListener(PropertyChangeListener l) {
- listeners.addElement(l);
- }
-
- /** Adds a PropertyChangeListener listening on the specified property.
- ** Events will be sent to the listener for that particular property.
- ** <P>
- **
- ** The listener add is not unique; that is, <em>n</em> adds on a
- ** particular property for a particular listener will result in
- ** <em>n</em> events being sent to that listener when that
- ** property is changed.
- ** <P>
- **
- ** The effect is cumulative, too; if you are registered to listen
- ** to receive events on all property changes, and then you
- ** register on a particular property, you will receive change
- ** events for that property twice.
- ** <P>
- **
- ** Adding a null listener will cause undefined behavior.
- **
- ** @param propertyName the name of the property to listen on.
- ** @param l the listener to add.
- **/
- public void addPropertyChangeListener(String propertyName, PropertyChangeListener l) {
- synchronized(propertyListeners) {
- Vector v = (Vector)propertyListeners.get(propertyName);
- try {
- v.addElement(l);
- } catch(NullPointerException e) {
- /* If v is not found, create a new vector. */
- v = new Vector();
- v.addElement(l);
- propertyListeners.put(propertyName, v);
- }
- }
- }
-
- /** Removes a PropertyChangeListener from the list of listeners.
- ** If any specific properties are being listened on, they must
- ** be deregistered by themselves; this will only remove the
- ** general listener to all properties.
- ** <P>
- **
- ** If <code>add()</code> has been called multiple times for a
- ** particular listener, <code>remove()</code> will have to be
- ** called the same number of times to deregister it.
- **
- ** @param l the listener to remove.
- **/
- public void removePropertyChangeListener(PropertyChangeListener l) {
- listeners.removeElement(l);
- }
-
- /** Removes a PropertyChangeListener from listening to a specific property.
- ** <P>
- **
- ** If <code>add()</code> has been called multiple times for a
- ** particular listener on a property, <code>remove()</code> will
- ** have to be called the same number of times to deregister it.
- **
- ** @param propertyName the property to stop listening on.
- ** @param l the listener to remove.
- **/
- public void removePropertyChangeListener(String propertyName, PropertyChangeListener l) {
- synchronized(propertyListeners) {
- Vector v = (Vector)propertyListeners.get(propertyName);
- try {
- v.removeElement(l);
- if(v.size() == 0) {
- propertyListeners.remove(propertyName);
- }
- } catch(NullPointerException e) {
- /* if v is not found, do nothing. */
- }
- }
- }
-
- /** Fire a PropertyChangeEvent to all the listeners.
- **
- ** @param event the event to fire.
- **/
- public void firePropertyChange(PropertyChangeEvent event) {
- for(int i=0;i<listeners.size();i++) {
- ((PropertyChangeListener)listeners.elementAt(i)).propertyChange(event);
- }
- Vector moreListeners = (Vector)propertyListeners.get(event.getPropertyName());
- if(moreListeners != null) {
- for(int i=0;i<moreListeners.size();i++) {
- ((PropertyChangeListener)moreListeners.elementAt(i)).propertyChange(event);
- }
- }
- }
-
- /** Fire a PropertyChangeEvent containing the old and new values of the property to all the listeners.
- **
- ** @param propertyName the name of the property that changed.
- ** @param oldVal the old value.
- ** @param newVal the new value.
- **/
- public void firePropertyChange(String propertyName, Object oldVal, Object newVal) {
- firePropertyChange(new PropertyChangeEvent(source,propertyName,oldVal,newVal));
- }
-
- /** Fire a PropertyChangeEvent containing the old and new values of the property to all the listeners.
- **
- ** @param propertyName the name of the property that changed.
- ** @param oldVal the old value.
- ** @param newVal the new value.
- **/
- public void firePropertyChange(String propertyName, boolean oldVal, boolean newVal) {
- firePropertyChange(new PropertyChangeEvent(source, propertyName, new Boolean(oldVal), new Boolean(newVal)));
- }
-
- /** Fire a PropertyChangeEvent containing the old and new values of the property to all the listeners.
- **
- ** @param propertyName the name of the property that changed.
- ** @param oldVal the old value.
- ** @param newVal the new value.
- **/
- public void firePropertyChange(String propertyName, int oldVal, int newVal) {
- firePropertyChange(new PropertyChangeEvent(source, propertyName, new Integer(oldVal), new Integer(newVal)));
- }
-
- /** Tell whether the specified property is being listened on or not.
- ** This will only return <code>true</code> if there are listeners
- ** on all properties or if there is a listener specifically on this
- ** property.
- **
- ** @param propertyName the property that may be listened on
- ** @return whether the property is being listened on
- **/
- public boolean hasListeners(String propertyName) {
- return listeners.size() > 0 || propertyListeners.get(propertyName) != null;
- }
-}
+ * PropertyChangeSupport makes it easy to fire property change events and
+ * handle listeners. It allows chaining of listeners, as well as filtering
+ * by property name. In addition, it will serialize only those listeners
+ * which are serializable, ignoring the others without problem. This class
+ * is thread-safe.
+ *
+ * @author John Keiser
+ * @author Eric Blake <ebb9@email.byu.edu>
+ * @since 1.1
+ * @status updated to 1.4
+ */
+public class PropertyChangeSupport implements Serializable
+{
+ /**
+ * Compatible with JDK 1.1+.
+ */
+ private static final long serialVersionUID = 6401253773779951803L;
+
+ /**
+ * Maps property names (String) to named listeners (PropertyChangeSupport).
+ * If this is a child instance, this field will be null.
+ *
+ * @serial the map of property names to named listener managers
+ * @since 1.2
+ */
+ private Hashtable children;
+
+ /**
+ * The non-null source object for any generated events.
+ *
+ * @serial the event source
+ */
+ private final Object source;
+
+ /**
+ * A field to compare serialization versions - this class uses version 2.
+ *
+ * @serial the serialization format
+ */
+ private final int propertyChangeSupportSerializedDataVersion = 2;
+
+ /**
+ * The list of all registered property listeners. If this instance was
+ * created by user code, this only holds the global listeners (ie. not tied
+ * to a name), and may be null. If it was created by this class, as a
+ * helper for named properties, then this vector will be non-null, and this
+ * instance appears as a value in the <code>children</code> hashtable of
+ * another instance, so that the listeners are tied to the key of that
+ * hashtable entry.
+ */
+ private transient Vector listeners;
+
+ /**
+ * Create a PropertyChangeSupport to work with a specific source bean.
+ *
+ * @param source the source bean to use
+ * @throws NullPointerException if source is null
+ */
+ public PropertyChangeSupport(Object source)
+ {
+ this.source = source;
+ if (source == null)
+ throw new NullPointerException();
+ }
+
+ /**
+ * Adds a PropertyChangeListener to the list of global listeners. All
+ * property change events will be sent to this listener. The listener add
+ * is not unique: that is, <em>n</em> adds with the same listener will
+ * result in <em>n</em> events being sent to that listener for every
+ * property change. Adding a null listener may cause a NullPointerException
+ * down the road. This method will unwrap a PropertyChangeListenerProxy,
+ * registering the underlying delegate to the named property list.
+ *
+ * @param l the listener to add
+ */
+ public synchronized void addPropertyChangeListener(PropertyChangeListener l)
+ {
+ if (l instanceof PropertyChangeListenerProxy)
+ {
+ PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l;
+ addPropertyChangeListener(p.propertyName,
+ (PropertyChangeListener) p.getListener());
+ }
+ else
+ {
+ if (listeners == null)
+ listeners = new Vector();
+ listeners.add(l);
+ }
+ }
+
+ /**
+ * Removes a PropertyChangeListener from the list of global listeners. If
+ * any specific properties are being listened on, they must be deregistered
+ * by themselves; this will only remove the general listener to all
+ * properties. If <code>add()</code> has been called multiple times for a
+ * particular listener, <code>remove()</code> will have to be called the
+ * same number of times to deregister it. This method will unwrap a
+ * PropertyChangeListenerProxy, removing the underlying delegate from the
+ * named property list.
+ *
+ * @param l the listener to remove
+ */
+ public synchronized void
+ removePropertyChangeListener(PropertyChangeListener l)
+ {
+ if (l instanceof PropertyChangeListenerProxy)
+ {
+ PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l;
+ removePropertyChangeListener(p.propertyName,
+ (PropertyChangeListener) p.getListener());
+ }
+ else if (listeners != null)
+ {
+ listeners.remove(l);
+ if (listeners.isEmpty())
+ listeners = null;
+ }
+ }
+
+ /**
+ * Returns an array of all registered property change listeners. Those that
+ * were registered under a name will be wrapped in a
+ * <code>PropertyChangeListenerProxy</code>, so you must check whether the
+ * listener is an instance of the proxy class in order to see what name the
+ * real listener is registered under. If there are no registered listeners,
+ * this returns an empty array.
+ *
+ * @return the array of registered listeners
+ * @see PropertyChangeListenerProxy
+ * @since 1.4
+ */
+ public synchronized PropertyChangeListener[] getPropertyChangeListeners()
+ {
+ ArrayList list = new ArrayList();
+ if (listeners != null)
+ list.addAll(listeners);
+ if (children != null)
+ {
+ int i = children.size();
+ Iterator iter = children.entrySet().iterator();
+ while (--i >= 0)
+ {
+ Entry e = (Entry) iter.next();
+ String name = (String) e.getKey();
+ Vector v = ((PropertyChangeSupport) e.getValue()).listeners;
+ int j = v.size();
+ while (--j >= 0)
+ list.add(new PropertyChangeListenerProxy
+ (name, (PropertyChangeListener) v.get(j)));
+ }
+ }
+ return (PropertyChangeListener[])
+ list.toArray(new PropertyChangeListener[list.size()]);
+ }
+
+ /**
+ * Adds a PropertyChangeListener listening on the specified property. Events
+ * will be sent to the listener only if the property name matches. The
+ * listener add is not unique; that is, <em>n</em> adds on a particular
+ * property for a particular listener will result in <em>n</em> events
+ * being sent to that listener when that property is changed. The effect is
+ * cumulative, too; if you are registered to listen to receive events on
+ * all property changes, and then you register on a particular property,
+ * you will receive change events for that property twice. Adding a null
+ * listener may cause a NullPointerException down the road. This method
+ * will unwrap a PropertyChangeListenerProxy, registering the underlying
+ * delegate to the named property list if the names match, and discarding
+ * it otherwise.
+ *
+ * @param propertyName the name of the property to listen on
+ * @param l the listener to add
+ * @throws NullPointerException if propertyName is null
+ */
+ public synchronized void addPropertyChangeListener(String propertyName,
+ PropertyChangeListener l)
+ {
+ while (l instanceof PropertyChangeListenerProxy)
+ {
+ PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l;
+ if (propertyName == null ? p.propertyName != null
+ : ! propertyName.equals(p.propertyName))
+ return;
+ l = (PropertyChangeListener) p.getListener();
+ }
+ PropertyChangeSupport s = null;
+ if (children == null)
+ children = new Hashtable();
+ else
+ s = (PropertyChangeSupport) children.get(propertyName);
+ if (s == null)
+ {
+ s = new PropertyChangeSupport(source);
+ s.listeners = new Vector();
+ children.put(propertyName, s);
+ }
+ s.listeners.add(l);
+ }
+
+ /**
+ * Removes a PropertyChangeListener from listening to a specific property.
+ * If <code>add()</code> has been called multiple times for a particular
+ * listener on a property, <code>remove()</code> will have to be called the
+ * same number of times to deregister it. This method will unwrap a
+ * PropertyChangeListenerProxy, removing the underlying delegate from the
+ * named property list if the names match.
+ *
+ * @param propertyName the property to stop listening on
+ * @param l the listener to remove
+ * @throws NullPointerException if propertyName is null
+ */
+ public synchronized void
+ removePropertyChangeListener(String propertyName, PropertyChangeListener l)
+ {
+ if (children == null)
+ return;
+ PropertyChangeSupport s
+ = (PropertyChangeSupport) children.get(propertyName);
+ if (s == null)
+ return;
+ while (l instanceof PropertyChangeListenerProxy)
+ {
+ PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l;
+ if (propertyName == null ? p.propertyName != null
+ : ! propertyName.equals(p.propertyName))
+ return;
+ l = (PropertyChangeListener) p.getListener();
+ }
+ s.listeners.remove(l);
+ if (s.listeners.isEmpty())
+ {
+ children.remove(propertyName);
+ if (children.isEmpty())
+ children = null;
+ }
+ }
+
+ /**
+ * Returns an array of all property change listeners registered under the
+ * given property name. If there are no registered listeners, this returns
+ * an empty array.
+ *
+ * @return the array of registered listeners
+ * @throws NullPointerException if propertyName is null
+ * @since 1.4
+ */
+ public synchronized PropertyChangeListener[]
+ getPropertyChangeListeners(String propertyName)
+ {
+ if (children == null)
+ return new PropertyChangeListener[0];
+ PropertyChangeSupport s
+ = (PropertyChangeSupport) children.get(propertyName);
+ if (s == null)
+ return new PropertyChangeListener[0];
+ return (PropertyChangeListener[])
+ s.listeners.toArray(new PropertyChangeListener[s.listeners.size()]);
+ }
+
+ /**
+ * Fire a PropertyChangeEvent containing the old and new values of the
+ * property to all the global listeners, and to all the listeners for the
+ * specified property name. This does nothing if old and new are non-null
+ * and equal.
+ *
+ * @param propertyName the name of the property that changed
+ * @param oldVal the old value
+ * @param newVal the new value
+ */
+ public void firePropertyChange(String propertyName,
+ Object oldVal, Object newVal)
+ {
+ firePropertyChange(new PropertyChangeEvent(source, propertyName,
+ oldVal, newVal));
+ }
+
+ /**
+ * Fire a PropertyChangeEvent containing the old and new values of the
+ * property to all the global listeners, and to all the listeners for the
+ * specified property name. This does nothing if old and new are equal.
+ *
+ * @param propertyName the name of the property that changed
+ * @param oldVal the old value
+ * @param newVal the new value
+ */
+ public void firePropertyChange(String propertyName, int oldVal, int newVal)
+ {
+ if (oldVal != newVal)
+ firePropertyChange(new PropertyChangeEvent(source, propertyName,
+ new Integer(oldVal),
+ new Integer(newVal)));
+ }
+
+ /**
+ * Fire a PropertyChangeEvent containing the old and new values of the
+ * property to all the global listeners, and to all the listeners for the
+ * specified property name. This does nothing if old and new are equal.
+ *
+ * @param propertyName the name of the property that changed
+ * @param oldVal the old value
+ * @param newVal the new value
+ */
+ public void firePropertyChange(String propertyName,
+ boolean oldVal, boolean newVal)
+ {
+ if (oldVal != newVal)
+ firePropertyChange(new PropertyChangeEvent(source, propertyName,
+ Boolean.valueOf(oldVal),
+ Boolean.valueOf(newVal)));
+ }
+
+ /**
+ * Fire a PropertyChangeEvent to all the global listeners, and to all the
+ * listeners for the specified property name. This does nothing if old and
+ * new values of the event are equal.
+ *
+ * @param event the event to fire
+ * @throws NullPointerException if event is null
+ */
+ public void firePropertyChange(PropertyChangeEvent event)
+ {
+ if (event.oldValue != null && event.oldValue.equals(event.newValue))
+ return;
+ Vector v = listeners; // Be thread-safe.
+ if (v != null)
+ {
+ int i = v.size();
+ while (--i >= 0)
+ ((PropertyChangeListener) v.get(i)).propertyChange(event);
+ }
+ Hashtable h = children; // Be thread-safe.
+ if (h != null && event.propertyName != null)
+ {
+ PropertyChangeSupport s
+ = (PropertyChangeSupport) h.get(event.propertyName);
+ if (s != null)
+ {
+ v = s.listeners; // Be thread-safe.
+ int i = v == null ? 0 : v.size();
+ while (--i >= 0)
+ ((PropertyChangeListener) v.get(i)).propertyChange(event);
+ }
+ }
+ }
+
+ /**
+ * Tell whether the specified property is being listened on or not. This
+ * will only return <code>true</code> if there are listeners on all
+ * properties or if there is a listener specifically on this property.
+ *
+ * @param propertyName the property that may be listened on
+ * @return whether the property is being listened on
+ * @throws NullPointerException if propertyName is null
+ */
+ public synchronized boolean hasListeners(String propertyName)
+ {
+ return listeners != null || (children != null
+ && children.get(propertyName) != null);
+ }
+
+ /**
+ * Saves the state of the object to the stream.
+ *
+ * @param s the stream to write to
+ * @throws IOException if anything goes wrong
+ * @serialData this writes out a null-terminated list of serializable
+ * global property change listeners (the listeners for a named
+ * property are written out as the global listeners of the
+ * children, when the children hashtable is saved)
+ */
+ private synchronized void writeObject(ObjectOutputStream s)
+ throws IOException
+ {
+ s.defaultWriteObject();
+ if (listeners != null)
+ {
+ int i = listeners.size();
+ while (--i >= 0)
+ if (listeners.get(i) instanceof Serializable)
+ s.writeObject(listeners.get(i));
+ }
+ s.writeObject(null);
+ }
+
+ /**
+ * Reads the object back from stream (deserialization).
+ *
+ * XXX Since serialization for 1.1 streams was not documented, this may
+ * not work if propertyChangeSupportSerializedDataVersion is 1.
+ *
+ * @param s the stream to read from
+ * @throws IOException if reading the stream fails
+ * @throws ClassNotFoundException if deserialization fails
+ * @serialData this reads in a null-terminated list of serializable
+ * global property change listeners (the listeners for a named
+ * property are written out as the global listeners of the
+ * children, when the children hashtable is saved)
+ */
+ private void readObject(ObjectInputStream s)
+ throws IOException, ClassNotFoundException
+ {
+ s.defaultReadObject();
+ PropertyChangeListener l = (PropertyChangeListener) s.readObject();
+ while (l != null)
+ {
+ addPropertyChangeListener(l);
+ l = (PropertyChangeListener) s.readObject();
+ }
+ // Sun is not as careful with children as we are, and lets some proxys
+ // in that can never receive events. So, we clean up anything that got
+ // serialized, to make sure our invariants hold.
+ if (children != null)
+ {
+ int i = children.size();
+ Iterator iter = children.entrySet().iterator();
+ while (--i >= 0)
+ {
+ Entry e = (Entry) iter.next();
+ String name = (String) e.getKey();
+ PropertyChangeSupport pcs = (PropertyChangeSupport) e.getValue();
+ if (pcs.listeners == null)
+ pcs.listeners = new Vector();
+ if (pcs.children != null)
+ pcs.listeners.addAll
+ (Arrays.asList(pcs.getPropertyChangeListeners(name)));
+ if (pcs.listeners.size() == 0)
+ iter.remove();
+ else
+ pcs.children = null;
+ }
+ if (children.size() == 0)
+ children = null;
+ }
+ }
+} // class PropertyChangeSupport
Index: java/beans/VetoableChangeListener.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/beans/VetoableChangeListener.java,v
retrieving revision 1.3
diff -u -r1.3 VetoableChangeListener.java
--- java/beans/VetoableChangeListener.java 22 Jan 2002 22:40:11 -0000 1.3
+++ java/beans/VetoableChangeListener.java 15 Jul 2002 16:03:18 -0000
@@ -1,5 +1,5 @@
-/* java.beans.VetoableChangeListener
- Copyright (C) 1998, 2000 Free Software Foundation, Inc.
+/* VetoableChangeListener.java -- listen for a change which can be vetoed
+ Copyright (C) 1998, 2000, 2002 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -7,7 +7,7 @@
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-
+
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@@ -41,37 +41,33 @@
import java.util.EventListener;
/**
- ** VetoableChangeListener allows a class to monitor
- ** proposed changes to properties of a Bean and, if
- ** desired, prevent them from occurring.<P>
- **
- ** A vetoableChange() event will be fired <EM>before</EM>
- ** the property has changed. If any listener rejects the
- ** change by throwing the PropertyChangeException, a new
- ** vetoableChange() event will be fired to all listeners
- ** who received a vetoableChange() event in the first
- ** place informing them of a reversion to the old value.
- ** The value, of course, never actually changed.<P>
- **
- ** <STRONG>Note:</STRONG> This class may not be reliably
- ** used to determine whether a property has actually
- ** changed. Use the PropertyChangeListener interface
- ** for that instead.
- **
- ** @author John Keiser
- ** @version 1.1.0, 29 Jul 1998
- ** @since JDK1.1
- ** @see java.beans.PropertyChangeListener
- ** @see java.beans.VetoableChangeSupport
- **/
-
+ * VetoableChangeListener allows a class to monitor proposed changes to
+ * properties of a Bean and, if desired, prevent them from occurring. A
+ * vetoableChange() event will be fired <em>after</em> the property change has
+ * been requested, but before it is permanent. If any listener rejects the
+ * change by throwing the PropertyChangeException, a new vetoableChange()
+ * event will be fired to all listeners who received a vetoableChange() event
+ * in the first place, informing them to revert back to the old value. Thus,
+ * the listener that threw the exception the first time should be prepared
+ * to rethrow it the second time. The value, of course, never actually changed.
+ *
+ * <p><strong>Note:</strong> This class may not be reliably used to determine
+ * whether a property has actually changed. Use the PropertyChangeListener
+ * interface for that instead.
+ *
+ * @author John Keiser
+ * @see java.beans.PropertyChangeListener
+ * @see java.beans.VetoableChangeSupport
+ * @since 1.1
+ * @status updated to 1.4
+ */
public interface VetoableChangeListener extends EventListener
{
- /** Fired before a Bean's property changes.
- ** @param e the change (containing the old and new values)
- ** @exception PropertyChangeException if the listener
- ** does not desire the change to be made.
- **/
- public abstract void vetoableChange(PropertyChangeEvent e)
- throws PropertyVetoException;
-}
+ /**
+ * Fired before a Bean's property changes.
+ *
+ * @param e the change (containing the old and new values)
+ * @throws PropertyVetoException if the change is vetoed by the listener
+ */
+ void vetoableChange(PropertyChangeEvent e) throws PropertyVetoException;
+} // interface VetoableChangeListener
Index: java/beans/VetoableChangeListenerProxy.java
===================================================================
RCS file: java/beans/VetoableChangeListenerProxy.java
diff -N java/beans/VetoableChangeListenerProxy.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ java/beans/VetoableChangeListenerProxy.java 15 Jul 2002 16:03:18 -0000
@@ -0,0 +1,102 @@
+/* VetoableChangeListenerProxy.java -- adds a name to a vetoable listener
+ Copyright (C) 2002 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.beans;
+
+import java.util.EventListenerProxy;
+
+/**
+ * This class provides an extension to <code>VetoableChangeListener</code> -
+ * associating a name with the listener. This can be used to filter the
+ * changes that one is interested in.
+ *
+ * @author Eric Blake <ebb9@email.byu.edu>
+ * @since 1.4
+ * @status udpated to 1.4
+ */
+public class VetoableChangeListenerProxy extends EventListenerProxy
+ implements VetoableChangeListener
+{
+ /**
+ * The name of the property to listen for. Package visible for use by
+ * VetoableChangeSupport.
+ */
+ final String propertyName;
+
+ /**
+ * Create a new proxy which filters property change events and only passes
+ * changes to the named property on to the delegate.
+ *
+ * @param propertyName the property's name to filter on
+ * @param listener the delegate listener
+ */
+ public VetoableChangeListenerProxy(String propertyName,
+ VetoableChangeListener listener)
+ {
+ super(listener);
+ this.propertyName = propertyName;
+ }
+
+ /**
+ * Forwards the event on to the delegate if the property name matches.
+ *
+ * @param event the event to pass on, if it meets the filter
+ * @throws NullPointerException if the delegate this was created with is null
+ * @throws PropertyVetoException if the change is vetoed by the listener
+ */
+ public void vetoableChange(PropertyChangeEvent event)
+ throws PropertyVetoException
+ {
+ // Note: Sun does not filter, under the assumption that since
+ // VetoableChangeSupport unwraps proxys, this method should never be
+ // called by normal use of listeners.
+ String name = event == null ? null : event.getPropertyName();
+ if (name == null ? propertyName == null : name.equals(propertyName))
+ ((VetoableChangeListener) getListener()).vetoableChange(event);
+ }
+
+ /**
+ * Gets the name of the property this proxy is filtering on.
+ *
+ * @return the property name
+ */
+ public String getPropertyName()
+ {
+ return propertyName;
+ }
+} // class VetoableChangeListenerProxy
Index: java/beans/VetoableChangeSupport.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/beans/VetoableChangeSupport.java,v
retrieving revision 1.4
diff -u -r1.4 VetoableChangeSupport.java
--- java/beans/VetoableChangeSupport.java 22 Jan 2002 22:40:11 -0000 1.4
+++ java/beans/VetoableChangeSupport.java 15 Jul 2002 16:03:18 -0000
@@ -1,5 +1,5 @@
-/* java.beans.VetoableChangeSupport
- Copyright (C) 1998 Free Software Foundation, Inc.
+/* VetoableChangeSupport.java -- support to manage vetoable change listeners
+ Copyright (C) 1998, 1999, 2000, 2002 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -7,7 +7,7 @@
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-
+
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@@ -35,265 +35,496 @@
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
+
package java.beans;
-import java.util.Hashtable;
-import java.util.Vector;
-import java.util.Enumeration;
+
+import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
-import java.io.IOException;
import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map.Entry;
+import java.util.Vector;
/**
- ** VetoableChangeSupport makes it easy to fire vetoable
- ** change events and handle listeners as well as reversion
- ** of old values when things go wrong.
- **
- ** @author John Keiser
- ** @since JDK1.1
- ** @version 1.2.0, 15 Mar 1998
- **/
-
-public class VetoableChangeSupport implements java.io.Serializable {
- transient Hashtable propertyListeners = new Hashtable();
- transient Vector listeners = new Vector();
- Hashtable children;
- Object source;
- int vetoableChangeSupportSerializedDataVersion = 2;
- private static final long serialVersionUID = -5090210921595982017L;
-
- /**
- * Saves the state of the object to the stream. */
- private void writeObject(ObjectOutputStream stream) throws IOException {
- children = propertyListeners.isEmpty() ? null : propertyListeners;
- stream.defaultWriteObject();
- for (Enumeration e = listeners.elements(); e.hasMoreElements(); ) {
- VetoableChangeListener l = (VetoableChangeListener)e.nextElement();
- if (l instanceof Serializable)
- stream.writeObject(l);
- }
- stream.writeObject(null);
- }
-
- /**
- * Reads the object back from stream (deserialization).
- */
- private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
- stream.defaultReadObject();
- propertyListeners = (children == null) ? new Hashtable() : children;
- VetoableChangeListener l;
- while ((l = (VetoableChangeListener)stream.readObject()) != null) {
- addVetoableChangeListener(l);
- }
- // FIXME: XXX: There is no spec for JDK 1.1 serialization
- // so it is unclear what to do if the value of
- // vetoableChangeSupportSerializedDataVersion is 1.
- }
-
-
- /** Create VetoableChangeSupport to work with a specific
- ** source bean.
- ** @param source the source bean to use.
- **/
- public VetoableChangeSupport(Object source) {
- this.source = source;
- }
-
- /** Adds a VetoableChangeListener to the list of listeners.
- ** All property change events will be sent to this listener.
- ** <P>
- **
- ** The listener add is not unique: that is, <em>n</em> adds with
- ** the same listener will result in <em>n</em> events being sent
- ** to that listener for every property change.
- ** <P>
- **
- ** Adding a null listener will cause undefined behavior.
- **
- ** @param l the listener to add.
- **/
- public void addVetoableChangeListener(VetoableChangeListener l) {
- listeners.addElement(l);
- }
-
- /** Adds a VetoableChangeListener listening on the specified property.
- ** Events will be sent to the listener for that particular property.
- ** <P>
- **
- ** The listener add is not unique; that is, <em>n</em> adds on a
- ** particular property for a particular listener will result in
- ** <em>n</em> events being sent to that listener when that
- ** property is changed.
- ** <P>
- **
- ** The effect is cumulative, too; if you are registered to listen
- ** to receive events on all property changes, and then you
- ** register on a particular property, you will receive change
- ** events for that property twice.
- ** <P>
- **
- ** Adding a null listener will cause undefined behavior.
- **
- ** @param propertyName the name of the property to listen on.
- ** @param l the listener to add.
- **/
- public void addVetoableChangeListener(String propertyName, VetoableChangeListener l) {
- synchronized(propertyListeners) {
- Vector v = (Vector)propertyListeners.get(propertyName);
- try {
- v.addElement(l);
- } catch(NullPointerException e) {
- /* If v is not found, create a new vector. */
- v = new Vector();
- v.addElement(l);
- propertyListeners.put(propertyName, v);
- }
- }
- }
-
- /** Removes a VetoableChangeListener from the list of listeners.
- ** If any specific properties are being listened on, they must
- ** be deregistered by themselves; this will only remove the
- ** general listener to all properties.
- ** <P>
- **
- ** If <code>add()</code> has been called multiple times for a
- ** particular listener, <code>remove()</code> will have to be
- ** called the same number of times to deregister it.
- **
- ** @param l the listener to remove.
- **/
- public void removeVetoableChangeListener(VetoableChangeListener l) {
- listeners.removeElement(l);
- }
-
- /** Removes a VetoableChangeListener from listening to a specific property.
- ** <P>
- **
- ** If <code>add()</code> has been called multiple times for a
- ** particular listener on a property, <code>remove()</code> will
- ** have to be called the same number of times to deregister it.
- **
- ** @param propertyName the property to stop listening on.
- ** @param l the listener to remove.
- **/
- public void removeVetoableChangeListener(String propertyName, VetoableChangeListener l) {
- synchronized(propertyListeners) {
- Vector v = (Vector)propertyListeners.get(propertyName);
- try {
- v.removeElement(l);
- if(v.size() == 0) {
- propertyListeners.remove(propertyName);
- }
- } catch(NullPointerException e) {
- /* if v is not found, do nothing. */
- }
- }
- }
-
-
- /** Fire a VetoableChangeEvent to all the listeners.
- ** If any listener objects, a reversion event will be sent to
- ** those listeners who received the initial event.
- **
- ** @param proposedChange the event to send.
- ** @exception PropertyVetoException if the change is vetoed.
- **/
- public void fireVetoableChange(PropertyChangeEvent proposedChange) throws PropertyVetoException {
- int currentListener=0;
- try {
- for(;currentListener<listeners.size();currentListener++) {
- ((VetoableChangeListener)listeners.elementAt(currentListener)).vetoableChange(proposedChange);
- }
- } catch(PropertyVetoException e) {
- PropertyChangeEvent reversion = new PropertyChangeEvent(proposedChange.getSource(),proposedChange.getPropertyName(),proposedChange.getNewValue(),proposedChange.getOldValue());
- for(int sendAgain=0;sendAgain<currentListener;sendAgain++) {
- try {
- ((VetoableChangeListener)listeners.elementAt(sendAgain)).vetoableChange(reversion);
- } catch(PropertyVetoException e2) {
- }
- }
- throw e;
- }
-
- Vector moreListeners = (Vector)propertyListeners.get(proposedChange.getPropertyName());
- if(moreListeners != null) {
- try {
- for(currentListener = 0; currentListener < moreListeners.size(); currentListener++) {
- ((VetoableChangeListener)moreListeners.elementAt(currentListener)).vetoableChange(proposedChange);
- }
- } catch(PropertyVetoException e) {
- PropertyChangeEvent reversion = new PropertyChangeEvent(proposedChange.getSource(),proposedChange.getPropertyName(),proposedChange.getNewValue(),proposedChange.getOldValue());
- for(int sendAgain=0;sendAgain<listeners.size();sendAgain++) {
- try {
- ((VetoableChangeListener)listeners.elementAt(currentListener)).vetoableChange(proposedChange);
- } catch(PropertyVetoException e2) {
- }
- }
-
- for(int sendAgain=0;sendAgain<currentListener;sendAgain++) {
- try {
- ((VetoableChangeListener)moreListeners.elementAt(sendAgain)).vetoableChange(reversion);
- } catch(PropertyVetoException e2) {
- }
- }
- throw e;
- }
- }
- }
-
- /** Fire a VetoableChangeEvent containing the old and new values of the property to all the listeners.
- ** If any listener objects, a reversion event will be sent to
- ** those listeners who received the initial event.
- **
- ** @param propertyName the name of the property that
- ** changed.
- ** @param oldVal the old value.
- ** @param newVal the new value.
- ** @exception PropertyVetoException if the change is vetoed.
- **/
- public void fireVetoableChange(String propertyName, Object oldVal, Object newVal) throws PropertyVetoException {
- fireVetoableChange(new PropertyChangeEvent(source,propertyName,oldVal,newVal));
- }
-
- /** Fire a VetoableChangeEvent containing the old and new values of the property to all the listeners.
- ** If any listener objects, a reversion event will be sent to
- ** those listeners who received the initial event.
- **
- ** @param propertyName the name of the property that
- ** changed.
- ** @param oldVal the old value.
- ** @param newVal the new value.
- ** @exception PropertyVetoException if the change is vetoed.
- **/
- public void fireVetoableChange(String propertyName, boolean oldVal, boolean newVal) throws PropertyVetoException {
- fireVetoableChange(new PropertyChangeEvent(source,propertyName,new Boolean(oldVal),new Boolean(newVal)));
- }
-
- /** Fire a VetoableChangeEvent containing the old and new values of the property to all the listeners.
- ** If any listener objects, a reversion event will be sent to
- ** those listeners who received the initial event.
- **
- ** @param propertyName the name of the property that
- ** changed.
- ** @param oldVal the old value.
- ** @param newVal the new value.
- ** @exception PropertyVetoException if the change is vetoed.
- **/
- public void fireVetoableChange(String propertyName, int oldVal, int newVal) throws PropertyVetoException {
- fireVetoableChange(new PropertyChangeEvent(source,propertyName,new Integer(oldVal),new Integer(newVal)));
- }
-
-
- /** Tell whether the specified property is being listened on or not.
- ** This will only return <code>true</code> if there are listeners
- ** on all properties or if there is a listener specifically on this
- ** property.
- **
- ** @param propertyName the property that may be listened on
- ** @return whether the property is being listened on
- **/
- public boolean hasListeners(String propertyName) {
- return listeners.size() > 0 || propertyListeners.get(propertyName) != null;
- }
-}
+ * VetoableChangeSupport makes it easy to fire vetoable change events and
+ * handle listeners. It allows chaining of listeners, as well as filtering
+ * by property name. In addition, it will serialize only those listeners
+ * which are serializable, ignoring the others without problem. This class
+ * is thread-safe.
+ *
+ * @author John Keiser
+ * @author Eric Blake <ebb9@email.byu.edu>
+ * @since 1.1
+ * @status updated to 1.4
+ */
+public class VetoableChangeSupport implements Serializable
+{
+ /**
+ * Compatible with JDK 1.1+.
+ */
+ private static final long serialVersionUID = -5090210921595982017L;
+
+ /**
+ * Maps property names (String) to named listeners (VetoableChangeSupport).
+ * If this is a child instance, this field will be null.
+ *
+ * @serial the map of property names to named listener managers
+ * @since 1.2
+ */
+ private Hashtable children;
+
+ /**
+ * The non-null source object for any generated events.
+ *
+ * @serial the event source
+ */
+ private final Object source;
+
+ /**
+ * A field to compare serialization versions - this class uses version 2.
+ *
+ * @serial the serialization format
+ */
+ private final int vetoableChangeSupportSerializedDataVersion = 2;
+
+ /**
+ * The list of all registered vetoable listeners. If this instance was
+ * created by user code, this only holds the global listeners (ie. not tied
+ * to a name), and may be null. If it was created by this class, as a
+ * helper for named properties, then this vector will be non-null, and this
+ * instance appears as a value in the <code>children</code> hashtable of
+ * another instance, so that the listeners are tied to the key of that
+ * hashtable entry.
+ */
+ private transient Vector listeners;
+
+ /**
+ * Create a VetoableChangeSupport to work with a specific source bean.
+ *
+ * @param source the source bean to use
+ * @throws NullPointerException if source is null
+ */
+ public VetoableChangeSupport(Object source)
+ {
+ this.source = source;
+ if (source == null)
+ throw new NullPointerException();
+ }
+
+ /**
+ * Adds a VetoableChangeListener to the list of global listeners. All
+ * vetoable change events will be sent to this listener. The listener add
+ * is not unique: that is, <em>n</em> adds with the same listener will
+ * result in <em>n</em> events being sent to that listener for every
+ * vetoable change. Adding a null listener may cause a NullPointerException
+ * down the road. This method will unwrap a VetoableChangeListenerProxy,
+ * registering the underlying delegate to the named property list.
+ *
+ * @param l the listener to add
+ */
+ public synchronized void addVetoableChangeListener(VetoableChangeListener l)
+ {
+ if (l instanceof VetoableChangeListenerProxy)
+ {
+ VetoableChangeListenerProxy p = (VetoableChangeListenerProxy) l;
+ addVetoableChangeListener(p.propertyName,
+ (VetoableChangeListener) p.getListener());
+ }
+ else
+ {
+ if (listeners == null)
+ listeners = new Vector();
+ listeners.add(l);
+ }
+ }
+
+ /**
+ * Removes a VetoableChangeListener from the list of global listeners. If
+ * any specific properties are being listened on, they must be deregistered
+ * by themselves; this will only remove the general listener to all
+ * properties. If <code>add()</code> has been called multiple times for a
+ * particular listener, <code>remove()</code> will have to be called the
+ * same number of times to deregister it. This method will unwrap a
+ * VetoableChangeListenerProxy, removing the underlying delegate from the
+ * named property list.
+ *
+ * @param l the listener to remove
+ */
+ public synchronized void
+ removeVetoableChangeListener(VetoableChangeListener l)
+ {
+ if (l instanceof VetoableChangeListenerProxy)
+ {
+ VetoableChangeListenerProxy p = (VetoableChangeListenerProxy) l;
+ removeVetoableChangeListener(p.propertyName,
+ (VetoableChangeListener) p.getListener());
+ }
+ else if (listeners != null)
+ {
+ listeners.remove(l);
+ if (listeners.isEmpty())
+ listeners = null;
+ }
+ }
+
+ /**
+ * Returns an array of all registered vetoable change listeners. Those that
+ * were registered under a name will be wrapped in a
+ * <code>VetoableChangeListenerProxy</code>, so you must check whether the
+ * listener is an instance of the proxy class in order to see what name the
+ * real listener is registered under. If there are no registered listeners,
+ * this returns an empty array.
+ *
+ * @return the array of registered listeners
+ * @see VetoableChangeListenerProxy
+ * @since 1.4
+ */
+ public synchronized VetoableChangeListener[] getVetoableChangeListeners()
+ {
+ ArrayList list = new ArrayList();
+ if (listeners != null)
+ list.addAll(listeners);
+ if (children != null)
+ {
+ int i = children.size();
+ Iterator iter = children.entrySet().iterator();
+ while (--i >= 0)
+ {
+ Entry e = (Entry) iter.next();
+ String name = (String) e.getKey();
+ Vector v = ((VetoableChangeSupport) e.getValue()).listeners;
+ int j = v.size();
+ while (--j >= 0)
+ list.add(new VetoableChangeListenerProxy
+ (name, (VetoableChangeListener) v.get(j)));
+ }
+ }
+ return (VetoableChangeListener[])
+ list.toArray(new VetoableChangeListener[list.size()]);
+ }
+
+ /**
+ * Adds a VetoableChangeListener listening on the specified property. Events
+ * will be sent to the listener only if the property name matches. The
+ * listener add is not unique; that is, <em>n</em> adds on a particular
+ * property for a particular listener will result in <em>n</em> events
+ * being sent to that listener when that property is changed. The effect is
+ * cumulative, too; if you are registered to listen to receive events on
+ * all vetoable changes, and then you register on a particular property,
+ * you will receive change events for that property twice. Adding a null
+ * listener may cause a NullPointerException down the road. This method
+ * will unwrap a VetoableChangeListenerProxy, registering the underlying
+ * delegate to the named property list if the names match, and discarding
+ * it otherwise.
+ *
+ * @param propertyName the name of the property to listen on
+ * @param l the listener to add
+ * @throws NullPointerException if propertyName is null
+ */
+ public synchronized void addVetoableChangeListener(String propertyName,
+ VetoableChangeListener l)
+ {
+ while (l instanceof VetoableChangeListenerProxy)
+ {
+ VetoableChangeListenerProxy p = (VetoableChangeListenerProxy) l;
+ if (propertyName == null ? p.propertyName != null
+ : ! propertyName.equals(p.propertyName))
+ return;
+ l = (VetoableChangeListener) p.getListener();
+ }
+ VetoableChangeSupport s = null;
+ if (children == null)
+ children = new Hashtable();
+ else
+ s = (VetoableChangeSupport) children.get(propertyName);
+ if (s == null)
+ {
+ s = new VetoableChangeSupport(source);
+ s.listeners = new Vector();
+ children.put(propertyName, s);
+ }
+ s.listeners.add(l);
+ }
+
+ /**
+ * Removes a VetoableChangeListener from listening to a specific property.
+ * If <code>add()</code> has been called multiple times for a particular
+ * listener on a property, <code>remove()</code> will have to be called the
+ * same number of times to deregister it. This method will unwrap a
+ * VetoableChangeListenerProxy, removing the underlying delegate from the
+ * named property list if the names match.
+ *
+ * @param propertyName the property to stop listening on
+ * @param l the listener to remove
+ * @throws NullPointerException if propertyName is null
+ */
+ public synchronized void
+ removeVetoableChangeListener(String propertyName, VetoableChangeListener l)
+ {
+ if (children == null)
+ return;
+ VetoableChangeSupport s
+ = (VetoableChangeSupport) children.get(propertyName);
+ if (s == null)
+ return;
+ while (l instanceof VetoableChangeListenerProxy)
+ {
+ VetoableChangeListenerProxy p = (VetoableChangeListenerProxy) l;
+ if (propertyName == null ? p.propertyName != null
+ : ! propertyName.equals(p.propertyName))
+ return;
+ l = (VetoableChangeListener) p.getListener();
+ }
+ s.listeners.remove(l);
+ if (s.listeners.isEmpty())
+ {
+ children.remove(propertyName);
+ if (children.isEmpty())
+ children = null;
+ }
+ }
+
+ /**
+ * Returns an array of all vetoable change listeners registered under the
+ * given property name. If there are no registered listeners, this returns
+ * an empty array.
+ *
+ * @return the array of registered listeners
+ * @throws NullPointerException if propertyName is null
+ * @since 1.4
+ */
+ public synchronized VetoableChangeListener[]
+ getVetoableChangeListeners(String propertyName)
+ {
+ if (children == null)
+ return new VetoableChangeListener[0];
+ VetoableChangeSupport s
+ = (VetoableChangeSupport) children.get(propertyName);
+ if (s == null)
+ return new VetoableChangeListener[0];
+ return (VetoableChangeListener[])
+ s.listeners.toArray(new VetoableChangeListener[s.listeners.size()]);
+ }
+
+ /**
+ * Fire a PropertyChangeEvent containing the old and new values of the
+ * property to all the global listeners, and to all the listeners for the
+ * specified property name. This does nothing if old and new are non-null
+ * and equal. If the change is vetoed, a new event is fired to notify
+ * listeners about the rollback before the exception is thrown.
+ *
+ * @param propertyName the name of the property that changed
+ * @param oldVal the old value
+ * @param newVal the new value
+ * @throws PropertyVetoException if the change is vetoed by a listener
+ */
+ public void fireVetoableChange(String propertyName,
+ Object oldVal, Object newVal)
+ throws PropertyVetoException
+ {
+ fireVetoableChange(new PropertyChangeEvent(source, propertyName,
+ oldVal, newVal));
+ }
+
+ /**
+ * Fire a PropertyChangeEvent containing the old and new values of the
+ * property to all the global listeners, and to all the listeners for the
+ * specified property name. This does nothing if old and new are equal.
+ * If the change is vetoed, a new event is fired to notify listeners about
+ * the rollback before the exception is thrown.
+ *
+ * @param propertyName the name of the property that changed
+ * @param oldVal the old value
+ * @param newVal the new value
+ * @throws PropertyVetoException if the change is vetoed by a listener
+ */
+ public void fireVetoableChange(String propertyName, int oldVal, int newVal)
+ throws PropertyVetoException
+ {
+ if (oldVal != newVal)
+ fireVetoableChange(new PropertyChangeEvent(source, propertyName,
+ new Integer(oldVal),
+ new Integer(newVal)));
+ }
+
+ /**
+ * Fire a PropertyChangeEvent containing the old and new values of the
+ * property to all the global listeners, and to all the listeners for the
+ * specified property name. This does nothing if old and new are equal.
+ * If the change is vetoed, a new event is fired to notify listeners about
+ * the rollback before the exception is thrown.
+ *
+ * @param propertyName the name of the property that changed
+ * @param oldVal the old value
+ * @param newVal the new value
+ * @throws PropertyVetoException if the change is vetoed by a listener
+ */
+ public void fireVetoableChange(String propertyName,
+ boolean oldVal, boolean newVal)
+ throws PropertyVetoException
+ {
+ if (oldVal != newVal)
+ fireVetoableChange(new PropertyChangeEvent(source, propertyName,
+ Boolean.valueOf(oldVal),
+ Boolean.valueOf(newVal)));
+ }
+
+ /**
+ * Fire a PropertyChangeEvent to all the global listeners, and to all the
+ * listeners for the specified property name. This does nothing if old and
+ * new values of the event are equal. If the change is vetoed, a new event
+ * is fired to notify listeners about the rollback before the exception is
+ * thrown.
+ *
+ * @param event the event to fire
+ * @throws NullPointerException if event is null
+ * @throws PropertyVetoException if the change is vetoed by a listener
+ */
+ public void fireVetoableChange(PropertyChangeEvent event)
+ throws PropertyVetoException
+ {
+ if (event.oldValue != null && event.oldValue.equals(event.newValue))
+ return;
+ Vector v = listeners; // Be thread-safe.
+ if (v != null)
+ {
+ int i = v.size();
+ try
+ {
+ while (--i >= 0)
+ ((VetoableChangeListener) v.get(i)).vetoableChange(event);
+ }
+ catch (PropertyVetoException e)
+ {
+ event = event.rollback();
+ int limit = i;
+ i = v.size();
+ while (--i >= limit)
+ ((VetoableChangeListener) v.get(i)).vetoableChange(event);
+ throw e;
+ }
+ }
+ Hashtable h = children; // Be thread-safe.
+ if (h != null && event.propertyName != null)
+ {
+ VetoableChangeSupport s
+ = (VetoableChangeSupport) h.get(event.propertyName);
+ if (s != null)
+ {
+ Vector v1 = s.listeners; // Be thread-safe.
+ int i = v1 == null ? 0 : v1.size();
+ try
+ {
+ while (--i >= 0)
+ ((VetoableChangeListener) v1.get(i)).vetoableChange(event);
+ }
+ catch (PropertyVetoException e)
+ {
+ event = event.rollback();
+ int limit = i;
+ i = v.size();
+ while (--i >= 0)
+ ((VetoableChangeListener) v.get(i)).vetoableChange(event);
+ i = v1.size();
+ while (--i >= limit)
+ ((VetoableChangeListener) v1.get(i)).vetoableChange(event);
+ throw e;
+ }
+ }
+ }
+ }
+
+ /**
+ * Tell whether the specified property is being listened on or not. This
+ * will only return <code>true</code> if there are listeners on all
+ * properties or if there is a listener specifically on this property.
+ *
+ * @param propertyName the property that may be listened on
+ * @return whether the property is being listened on
+ * @throws NullPointerException if propertyName is null
+ */
+ public synchronized boolean hasListeners(String propertyName)
+ {
+ return listeners != null || (children != null
+ && children.get(propertyName) != null);
+ }
+
+ /**
+ * Saves the state of the object to the stream.
+ *
+ * @param s the stream to write to
+ * @throws IOException if anything goes wrong
+ * @serialData this writes out a null-terminated list of serializable
+ * global vetoable change listeners (the listeners for a named
+ * property are written out as the global listeners of the
+ * children, when the children hashtable is saved)
+ */
+ private synchronized void writeObject(ObjectOutputStream s)
+ throws IOException
+ {
+ s.defaultWriteObject();
+ if (listeners != null)
+ {
+ int i = listeners.size();
+ while (--i >= 0)
+ if (listeners.get(i) instanceof Serializable)
+ s.writeObject(listeners.get(i));
+ }
+ s.writeObject(null);
+ }
+
+ /**
+ * Reads the object back from stream (deserialization).
+ *
+ * XXX Since serialization for 1.1 streams was not documented, this may
+ * not work if vetoableChangeSupportSerializedDataVersion is 1.
+ *
+ * @param s the stream to read from
+ * @throws IOException if reading the stream fails
+ * @throws ClassNotFoundException if deserialization fails
+ * @serialData this reads in a null-terminated list of serializable
+ * global vetoable change listeners (the listeners for a named
+ * property are written out as the global listeners of the
+ * children, when the children hashtable is saved)
+ */
+ private void readObject(ObjectInputStream s)
+ throws IOException, ClassNotFoundException
+ {
+ s.defaultReadObject();
+ VetoableChangeListener l = (VetoableChangeListener) s.readObject();
+ while (l != null)
+ {
+ addVetoableChangeListener(l);
+ l = (VetoableChangeListener) s.readObject();
+ }
+ // Sun is not as careful with children as we are, and lets some proxys
+ // in that can never receive events. So, we clean up anything that got
+ // serialized, to make sure our invariants hold.
+ if (children != null)
+ {
+ int i = children.size();
+ Iterator iter = children.entrySet().iterator();
+ while (--i >= 0)
+ {
+ Entry e = (Entry) iter.next();
+ String name = (String) e.getKey();
+ VetoableChangeSupport vcs = (VetoableChangeSupport) e.getValue();
+ if (vcs.listeners == null)
+ vcs.listeners = new Vector();
+ if (vcs.children != null)
+ vcs.listeners.addAll
+ (Arrays.asList(vcs.getVetoableChangeListeners(name)));
+ if (vcs.listeners.size() == 0)
+ iter.remove();
+ else
+ vcs.children = null;
+ }
+ if (children.size() == 0)
+ children = null;
+ }
+ }
+} // class VetoableChangeSupport