Commit 9698ee33 by Tom Tromey Committed by Tom Tromey

Makefile.in: Rebuilt.

	* 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.

From-SVN: r55459
parent ed8d2920
2002-07-15 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.
2002-07-14 Mark Wielaard <mark@klomp.org> 2002-07-14 Mark Wielaard <mark@klomp.org>
* gnu/java/security/der/DEREncodingException.java, * gnu/java/security/der/DEREncodingException.java,
......
...@@ -799,6 +799,7 @@ java/beans/Beans.java \ ...@@ -799,6 +799,7 @@ java/beans/Beans.java \
java/beans/Customizer.java \ java/beans/Customizer.java \
java/beans/DesignMode.java \ java/beans/DesignMode.java \
java/beans/EventSetDescriptor.java \ java/beans/EventSetDescriptor.java \
java/beans/ExceptionListener.java \
java/beans/FeatureDescriptor.java \ java/beans/FeatureDescriptor.java \
java/beans/IndexedPropertyDescriptor.java \ java/beans/IndexedPropertyDescriptor.java \
java/beans/IntrospectionException.java \ java/beans/IntrospectionException.java \
...@@ -807,6 +808,7 @@ java/beans/MethodDescriptor.java \ ...@@ -807,6 +808,7 @@ java/beans/MethodDescriptor.java \
java/beans/ParameterDescriptor.java \ java/beans/ParameterDescriptor.java \
java/beans/PropertyChangeEvent.java \ java/beans/PropertyChangeEvent.java \
java/beans/PropertyChangeListener.java \ java/beans/PropertyChangeListener.java \
java/beans/PropertyChangeListenerProxy.java \
java/beans/PropertyChangeSupport.java \ java/beans/PropertyChangeSupport.java \
java/beans/PropertyDescriptor.java \ java/beans/PropertyDescriptor.java \
java/beans/PropertyEditor.java \ java/beans/PropertyEditor.java \
...@@ -815,6 +817,7 @@ java/beans/PropertyEditorSupport.java \ ...@@ -815,6 +817,7 @@ java/beans/PropertyEditorSupport.java \
java/beans/PropertyVetoException.java \ java/beans/PropertyVetoException.java \
java/beans/SimpleBeanInfo.java \ java/beans/SimpleBeanInfo.java \
java/beans/VetoableChangeListener.java \ java/beans/VetoableChangeListener.java \
java/beans/VetoableChangeListenerProxy.java \
java/beans/VetoableChangeSupport.java \ java/beans/VetoableChangeSupport.java \
java/beans/Visibility.java java/beans/Visibility.java
......
...@@ -568,6 +568,7 @@ java/beans/Beans.java \ ...@@ -568,6 +568,7 @@ java/beans/Beans.java \
java/beans/Customizer.java \ java/beans/Customizer.java \
java/beans/DesignMode.java \ java/beans/DesignMode.java \
java/beans/EventSetDescriptor.java \ java/beans/EventSetDescriptor.java \
java/beans/ExceptionListener.java \
java/beans/FeatureDescriptor.java \ java/beans/FeatureDescriptor.java \
java/beans/IndexedPropertyDescriptor.java \ java/beans/IndexedPropertyDescriptor.java \
java/beans/IntrospectionException.java \ java/beans/IntrospectionException.java \
...@@ -576,6 +577,7 @@ java/beans/MethodDescriptor.java \ ...@@ -576,6 +577,7 @@ java/beans/MethodDescriptor.java \
java/beans/ParameterDescriptor.java \ java/beans/ParameterDescriptor.java \
java/beans/PropertyChangeEvent.java \ java/beans/PropertyChangeEvent.java \
java/beans/PropertyChangeListener.java \ java/beans/PropertyChangeListener.java \
java/beans/PropertyChangeListenerProxy.java \
java/beans/PropertyChangeSupport.java \ java/beans/PropertyChangeSupport.java \
java/beans/PropertyDescriptor.java \ java/beans/PropertyDescriptor.java \
java/beans/PropertyEditor.java \ java/beans/PropertyEditor.java \
...@@ -584,6 +586,7 @@ java/beans/PropertyEditorSupport.java \ ...@@ -584,6 +586,7 @@ java/beans/PropertyEditorSupport.java \
java/beans/PropertyVetoException.java \ java/beans/PropertyVetoException.java \
java/beans/SimpleBeanInfo.java \ java/beans/SimpleBeanInfo.java \
java/beans/VetoableChangeListener.java \ java/beans/VetoableChangeListener.java \
java/beans/VetoableChangeListenerProxy.java \
java/beans/VetoableChangeSupport.java \ java/beans/VetoableChangeSupport.java \
java/beans/Visibility.java java/beans/Visibility.java
...@@ -1776,7 +1779,7 @@ libgcj-test.spec.in libgcj.spec.in ...@@ -1776,7 +1779,7 @@ libgcj-test.spec.in libgcj.spec.in
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
TAR = tar TAR = gtar
GZIP_ENV = --best GZIP_ENV = --best
DIST_SUBDIRS = @DIRLTDL@ testsuite gcj include @DIRLTDL@ gcj include DIST_SUBDIRS = @DIRLTDL@ testsuite gcj include @DIRLTDL@ gcj include
DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \ DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \
...@@ -2197,6 +2200,7 @@ DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \ ...@@ -2197,6 +2200,7 @@ DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \
.deps/java/beans/BeanInfo.P .deps/java/beans/Beans.P \ .deps/java/beans/BeanInfo.P .deps/java/beans/Beans.P \
.deps/java/beans/Customizer.P .deps/java/beans/DesignMode.P \ .deps/java/beans/Customizer.P .deps/java/beans/DesignMode.P \
.deps/java/beans/EventSetDescriptor.P \ .deps/java/beans/EventSetDescriptor.P \
.deps/java/beans/ExceptionListener.P \
.deps/java/beans/FeatureDescriptor.P \ .deps/java/beans/FeatureDescriptor.P \
.deps/java/beans/IndexedPropertyDescriptor.P \ .deps/java/beans/IndexedPropertyDescriptor.P \
.deps/java/beans/IntrospectionException.P \ .deps/java/beans/IntrospectionException.P \
...@@ -2204,6 +2208,7 @@ DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \ ...@@ -2204,6 +2208,7 @@ DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \
.deps/java/beans/ParameterDescriptor.P \ .deps/java/beans/ParameterDescriptor.P \
.deps/java/beans/PropertyChangeEvent.P \ .deps/java/beans/PropertyChangeEvent.P \
.deps/java/beans/PropertyChangeListener.P \ .deps/java/beans/PropertyChangeListener.P \
.deps/java/beans/PropertyChangeListenerProxy.P \
.deps/java/beans/PropertyChangeSupport.P \ .deps/java/beans/PropertyChangeSupport.P \
.deps/java/beans/PropertyDescriptor.P .deps/java/beans/PropertyEditor.P \ .deps/java/beans/PropertyDescriptor.P .deps/java/beans/PropertyEditor.P \
.deps/java/beans/PropertyEditorManager.P \ .deps/java/beans/PropertyEditorManager.P \
...@@ -2211,6 +2216,7 @@ DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \ ...@@ -2211,6 +2216,7 @@ DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \
.deps/java/beans/PropertyVetoException.P \ .deps/java/beans/PropertyVetoException.P \
.deps/java/beans/SimpleBeanInfo.P \ .deps/java/beans/SimpleBeanInfo.P \
.deps/java/beans/VetoableChangeListener.P \ .deps/java/beans/VetoableChangeListener.P \
.deps/java/beans/VetoableChangeListenerProxy.P \
.deps/java/beans/VetoableChangeSupport.P .deps/java/beans/Visibility.P \ .deps/java/beans/VetoableChangeSupport.P .deps/java/beans/Visibility.P \
.deps/java/beans/beancontext/BeanContext.P \ .deps/java/beans/beancontext/BeanContext.P \
.deps/java/beans/beancontext/BeanContextChild.P \ .deps/java/beans/beancontext/BeanContextChild.P \
......
/* 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
/* java.beans.PropertyChangeEvent /* PropertyChangeEvent.java -- describes a change in a property
Copyright (C) 1998, 2000 Free Software Foundation, Inc. Copyright (C) 1998, 2000, 2002 Free Software Foundation, Inc.
This file is part of GNU Classpath. This file is part of GNU Classpath.
...@@ -38,87 +38,152 @@ exception statement from your version. */ ...@@ -38,87 +38,152 @@ exception statement from your version. */
package java.beans; 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;
/**
* 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; private static final long serialVersionUID = 7042693688939648123L;
/** Create a new PropertyChangeEvent. Remember that if /**
** you received a PropertyChangeEvent and are sending * The name of the property that changed, may be null. Package visible for
** a new one, you should also set the propagation ID * use by PropertyChangeSupport.
** from the old PropertyChangeEvent. *
** @param source the Bean containing the property. * @serial the changed property name
** @param propertyName the property's name. */
** @param oldValue the old value of the property. final String propertyName;
** @param newValue the new value of the property.
**/ /**
public PropertyChangeEvent(Object source, String propertyName, Object oldVal, Object newVal) { * 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); super(source);
this.propertyName = propertyName; this.propertyName = propertyName;
oldValue = oldVal; oldValue = oldVal;
newValue = newVal; newValue = newVal;
} }
/** Get the property name. /**
** @return the property name. * Get the property name. May be null if multiple properties changed.
**/ *
public String getPropertyName() { * @return the property name
*/
public String getPropertyName()
{
return propertyName; return propertyName;
} }
/** Get the property's old value. /**
** @return the property's old value. * Get the property's new value. May be null if multiple properties changed.
**/ *
public Object getOldValue() { * @return the property's new value
return oldValue; */
public Object getNewValue()
{
return newValue;
} }
/** Get the property's new value. /**
** @return the property's new value. * Get the property's old value. May be null if multiple properties changed.
**/ *
public Object getNewValue() { * @return the property's old value
return newValue; */
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 * Set the propagation ID. This is a way for the event to be passed from
** extra state. Right now it is unused, but it should * hand to hand and retain a little extra state. Right now it is unused,
** be propagated anyway so that future versions of * but it should be propagated anyway so that future versions of JavaBeans
** JavaBeans can use it, for God knows what. * can use it, for God knows what.
** @param propagationId the propagation ID. *
**/ * @param propagationId the propagation ID
public void setPropagationId(Object propagationId) { * @see #getPropagationId()
*/
public void setPropagationId(Object propagationId)
{
this.propagationId = propagationId; this.propagationId = propagationId;
} }
/** Get the propagation ID. /**
** @return the propagation ID. * Get the propagation ID. Right now, it is not used for anything.
**/ *
public Object getPropagationId() { * @return the propagation ID
* @see #setPropagationId(Object)
*/
public Object getPropagationId()
{
return propagationId; 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
/* java.beans.PropertyChangeListener /* PropertyChangeListener.java -- listen for changes in a bound property
Copyright (C) 1998, 2000 Free Software Foundation, Inc. Copyright (C) 1998, 2000, 2002 Free Software Foundation, Inc.
This file is part of GNU Classpath. This file is part of GNU Classpath.
...@@ -41,22 +41,21 @@ package java.beans; ...@@ -41,22 +41,21 @@ package java.beans;
import java.util.EventListener; import java.util.EventListener;
/** /**
** PropertyChangeListener allows a class to monitor * PropertyChangeListener allows a class to monitor properties of a Bean for
** properties of a Bean for changes.<P> * changes. A propertyChange() event will only be fired <em>after</em> the
** * property has changed.
** A propertyChange() event will only be fired *
** <EM>after</EM> the property has changed. * @author John Keiser
** * @see PropertyChangeSupport
** @author John Keiser * @since 1.1
** @since JDK1.1 * @status updated to 1.4
** @version 1.1.0, 29 Jul 1998 */
** @see java.beans.PropertyChangeSupport
**/
public interface PropertyChangeListener extends EventListener public interface PropertyChangeListener extends EventListener
{ {
/** Fired after a Bean's property has changed. /**
** @param e the change (containing the old and new values) * Fired after a Bean's property has changed.
**/ *
public abstract void propertyChange(PropertyChangeEvent e); * @param e the change (containing the old and new values)
} */
void propertyChange(PropertyChangeEvent e);
} // interface PropertyChangeListener
/* 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
/* java.beans.PropertyChangeSupport /* PropertyChangeSupport.java -- support to manage property change listeners
Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. Copyright (C) 1998, 1999, 2000, 2002 Free Software Foundation, Inc.
This file is part of GNU Classpath. This file is part of GNU Classpath.
...@@ -37,214 +37,452 @@ exception statement from your version. */ ...@@ -37,214 +37,452 @@ exception statement from your version. */
package java.beans; package java.beans;
import java.util.Hashtable;
import java.util.Vector; import java.io.IOException;
import java.util.Enumeration;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
import java.io.IOException;
import java.io.Serializable; 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 * PropertyChangeSupport makes it easy to fire property change events and
** change events and handle listeners. * handle listeners. It allows chaining of listeners, as well as filtering
** * by property name. In addition, it will serialize only those listeners
** @author John Keiser * which are serializable, ignoring the others without problem. This class
** @since JDK1.1 * is thread-safe.
** @version 1.2.0, 15 Mar 1999 *
**/ * @author John Keiser
* @author Eric Blake <ebb9@email.byu.edu>
public class PropertyChangeSupport implements java.io.Serializable { * @since 1.1
transient Hashtable propertyListeners = new Hashtable(); * @status updated to 1.4
transient Vector listeners = new Vector(); */
Hashtable children; public class PropertyChangeSupport implements Serializable
Object source; {
int propertyChangeSupportSerializedDataVersion = 2; /**
* Compatible with JDK 1.1+.
*/
private static final long serialVersionUID = 6401253773779951803L; private static final long serialVersionUID = 6401253773779951803L;
/** /**
* Saves the state of the object to the stream. */ * Maps property names (String) to named listeners (PropertyChangeSupport).
private void writeObject(ObjectOutputStream stream) throws IOException { * If this is a child instance, this field will be null.
children = propertyListeners.isEmpty() ? null : propertyListeners; *
stream.defaultWriteObject(); * @serial the map of property names to named listener managers
for (Enumeration e = listeners.elements(); e.hasMoreElements(); ) { * @since 1.2
PropertyChangeListener l = (PropertyChangeListener)e.nextElement(); */
if (l instanceof Serializable) private Hashtable children;
stream.writeObject(l);
/**
* 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);
} }
stream.writeObject(null);
} }
/** /**
* Reads the object back from stream (deserialization). * 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
*/ */
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { public synchronized void
stream.defaultReadObject(); removePropertyChangeListener(PropertyChangeListener l)
propertyListeners = (children == null) ? new Hashtable() : children; {
PropertyChangeListener l; if (l instanceof PropertyChangeListenerProxy)
while ((l = (PropertyChangeListener)stream.readObject()) != null) { {
addPropertyChangeListener(l); PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l;
removePropertyChangeListener(p.propertyName,
(PropertyChangeListener) p.getListener());
}
else if (listeners != null)
{
listeners.remove(l);
if (listeners.isEmpty())
listeners = null;
} }
// 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. * Returns an array of all registered property change listeners. Those that
** @param source the source bean to use. * were registered under a name will be wrapped in a
**/ * <code>PropertyChangeListenerProxy</code>, so you must check whether the
public PropertyChangeSupport(Object source) { * listener is an instance of the proxy class in order to see what name the
this.source = source; * 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 to the list of listeners. /**
** All property change events will be sent to this listener. * Adds a PropertyChangeListener listening on the specified property. Events
** <P> * 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
** The listener add is not unique: that is, <em>n</em> adds with * property for a particular listener will result in <em>n</em> events
** the same listener will result in <em>n</em> events being sent * being sent to that listener when that property is changed. The effect is
** to that listener for every property change. * cumulative, too; if you are registered to listen to receive events on
** <P> * all property changes, and then you register on a particular property,
** * you will receive change events for that property twice. Adding a null
** Adding a null listener will cause undefined behavior. * listener may cause a NullPointerException down the road. This method
** * will unwrap a PropertyChangeListenerProxy, registering the underlying
** @param l the listener to add. * delegate to the named property list if the names match, and discarding
**/ * it otherwise.
public void addPropertyChangeListener(PropertyChangeListener l) { *
listeners.addElement(l); * @param propertyName the name of the property to listen on
} * @param l the listener to add
* @throws NullPointerException if propertyName is null
/** Adds a PropertyChangeListener listening on the specified property. */
** Events will be sent to the listener for that particular property. public synchronized void addPropertyChangeListener(String propertyName,
** <P> PropertyChangeListener l)
** {
** The listener add is not unique; that is, <em>n</em> adds on a while (l instanceof PropertyChangeListenerProxy)
** particular property for a particular listener will result in {
** <em>n</em> events being sent to that listener when that PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l;
** property is changed. if (propertyName == null ? p.propertyName != null
** <P> : ! propertyName.equals(p.propertyName))
** return;
** The effect is cumulative, too; if you are registered to listen l = (PropertyChangeListener) p.getListener();
** to receive events on all property changes, and then you }
** register on a particular property, you will receive change PropertyChangeSupport s = null;
** events for that property twice. if (children == null)
** <P> children = new Hashtable();
** else
** Adding a null listener will cause undefined behavior. s = (PropertyChangeSupport) children.get(propertyName);
** if (s == null)
** @param propertyName the name of the property to listen on. {
** @param l the listener to add. s = new PropertyChangeSupport(source);
**/ s.listeners = new Vector();
public void addPropertyChangeListener(String propertyName, PropertyChangeListener l) { children.put(propertyName, s);
synchronized(propertyListeners) { }
Vector v = (Vector)propertyListeners.get(propertyName); s.listeners.add(l);
try { }
v.addElement(l);
} catch(NullPointerException e) { /**
/* If v is not found, create a new vector. */ * Removes a PropertyChangeListener from listening to a specific property.
v = new Vector(); * If <code>add()</code> has been called multiple times for a particular
v.addElement(l); * listener on a property, <code>remove()</code> will have to be called the
propertyListeners.put(propertyName, v); * 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
/** Removes a PropertyChangeListener from the list of listeners. * @param l the listener to remove
** If any specific properties are being listened on, they must * @throws NullPointerException if propertyName is null
** be deregistered by themselves; this will only remove the */
** general listener to all properties. public synchronized void
** <P> removePropertyChangeListener(String propertyName, PropertyChangeListener l)
** {
** If <code>add()</code> has been called multiple times for a if (children == null)
** particular listener, <code>remove()</code> will have to be return;
** called the same number of times to deregister it. PropertyChangeSupport s
** = (PropertyChangeSupport) children.get(propertyName);
** @param l the listener to remove. if (s == null)
**/ return;
public void removePropertyChangeListener(PropertyChangeListener l) { while (l instanceof PropertyChangeListenerProxy)
listeners.removeElement(l); {
} PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l;
if (propertyName == null ? p.propertyName != null
/** Removes a PropertyChangeListener from listening to a specific property. : ! propertyName.equals(p.propertyName))
** <P> return;
** l = (PropertyChangeListener) p.getListener();
** If <code>add()</code> has been called multiple times for a }
** particular listener on a property, <code>remove()</code> will s.listeners.remove(l);
** have to be called the same number of times to deregister it. if (s.listeners.isEmpty())
** {
** @param propertyName the property to stop listening on. children.remove(propertyName);
** @param l the listener to remove. if (children.isEmpty())
**/ children = null;
public void removePropertyChangeListener(String propertyName, PropertyChangeListener l) { }
synchronized(propertyListeners) { }
Vector v = (Vector)propertyListeners.get(propertyName);
try { /**
v.removeElement(l); * Returns an array of all property change listeners registered under the
if(v.size() == 0) { * given property name. If there are no registered listeners, this returns
propertyListeners.remove(propertyName); * an empty array.
} *
} catch(NullPointerException e) { * @return the array of registered listeners
/* if v is not found, do nothing. */ * @throws NullPointerException if propertyName is null
} * @since 1.4
} */
} public synchronized PropertyChangeListener[]
getPropertyChangeListeners(String propertyName)
/** Fire a PropertyChangeEvent to all the listeners. {
** if (children == null)
** @param event the event to fire. return new PropertyChangeListener[0];
**/ PropertyChangeSupport s
public void firePropertyChange(PropertyChangeEvent event) { = (PropertyChangeSupport) children.get(propertyName);
for(int i=0;i<listeners.size();i++) { if (s == null)
((PropertyChangeListener)listeners.elementAt(i)).propertyChange(event); return new PropertyChangeListener[0];
} return (PropertyChangeListener[])
Vector moreListeners = (Vector)propertyListeners.get(event.getPropertyName()); s.listeners.toArray(new PropertyChangeListener[s.listeners.size()]);
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 global listeners, and to all the listeners for the
} * specified property name. This does nothing if old and new are non-null
* and equal.
/** 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 propertyName the name of the property that changed. * @param oldVal the old value
** @param oldVal the old value. * @param newVal the new value
** @param newVal the new value. */
**/ public void firePropertyChange(String propertyName,
public void firePropertyChange(String propertyName, Object oldVal, Object newVal) { Object oldVal, Object newVal)
firePropertyChange(new PropertyChangeEvent(source,propertyName,oldVal,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. * Fire a PropertyChangeEvent containing the old and new values of the
** @param newVal the new value. * 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.
public void firePropertyChange(String propertyName, boolean oldVal, boolean newVal) { *
firePropertyChange(new PropertyChangeEvent(source, propertyName, new Boolean(oldVal), new Boolean(newVal))); * @param propertyName the name of the property that changed
} * @param oldVal the old value
* @param newVal the new value
/** Fire a PropertyChangeEvent containing the old and new values of the property to all the listeners. */
** public void firePropertyChange(String propertyName, int oldVal, int newVal)
** @param propertyName the name of the property that changed. {
** @param oldVal the old value. if (oldVal != newVal)
** @param newVal the new value. firePropertyChange(new PropertyChangeEvent(source, propertyName,
**/ new Integer(oldVal),
public void firePropertyChange(String propertyName, int oldVal, int newVal) { new Integer(newVal)));
firePropertyChange(new PropertyChangeEvent(source, propertyName, new Integer(oldVal), new Integer(newVal))); }
}
/**
/** Tell whether the specified property is being listened on or not. * Fire a PropertyChangeEvent containing the old and new values of the
** This will only return <code>true</code> if there are listeners * property to all the global listeners, and to all the listeners for the
** on all properties or if there is a listener specifically on this * specified property name. This does nothing if old and new are equal.
** property. *
** * @param propertyName the name of the property that changed
** @param propertyName the property that may be listened on * @param oldVal the old value
** @return whether the property is being listened on * @param newVal the new value
**/ */
public boolean hasListeners(String propertyName) { public void firePropertyChange(String propertyName,
return listeners.size() > 0 || propertyListeners.get(propertyName) != null; 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
/* java.beans.VetoableChangeListener /* VetoableChangeListener.java -- listen for a change which can be vetoed
Copyright (C) 1998, 2000 Free Software Foundation, Inc. Copyright (C) 1998, 2000, 2002 Free Software Foundation, Inc.
This file is part of GNU Classpath. This file is part of GNU Classpath.
...@@ -41,37 +41,33 @@ package java.beans; ...@@ -41,37 +41,33 @@ package java.beans;
import java.util.EventListener; import java.util.EventListener;
/** /**
** VetoableChangeListener allows a class to monitor * VetoableChangeListener allows a class to monitor proposed changes to
** proposed changes to properties of a Bean and, if * properties of a Bean and, if desired, prevent them from occurring. A
** desired, prevent them from occurring.<P> * vetoableChange() event will be fired <em>after</em> the property change has
** * been requested, but before it is permanent. If any listener rejects the
** A vetoableChange() event will be fired <EM>before</EM> * change by throwing the PropertyChangeException, a new vetoableChange()
** the property has changed. If any listener rejects the * event will be fired to all listeners who received a vetoableChange() event
** change by throwing the PropertyChangeException, a new * in the first place, informing them to revert back to the old value. Thus,
** vetoableChange() event will be fired to all listeners * the listener that threw the exception the first time should be prepared
** who received a vetoableChange() event in the first * to rethrow it the second time. The value, of course, never actually changed.
** place informing them of a reversion to the old value. *
** The value, of course, never actually changed.<P> * <p><strong>Note:</strong> This class may not be reliably used to determine
** * whether a property has actually changed. Use the PropertyChangeListener
** <STRONG>Note:</STRONG> This class may not be reliably * interface for that instead.
** used to determine whether a property has actually *
** changed. Use the PropertyChangeListener interface * @author John Keiser
** for that instead. * @see java.beans.PropertyChangeListener
** * @see java.beans.VetoableChangeSupport
** @author John Keiser * @since 1.1
** @version 1.1.0, 29 Jul 1998 * @status updated to 1.4
** @since JDK1.1 */
** @see java.beans.PropertyChangeListener
** @see java.beans.VetoableChangeSupport
**/
public interface VetoableChangeListener extends EventListener public interface VetoableChangeListener extends EventListener
{ {
/** Fired before a Bean's property changes. /**
** @param e the change (containing the old and new values) * Fired before a Bean's property changes.
** @exception PropertyChangeException if the listener *
** does not desire the change to be made. * @param e the change (containing the old and new values)
**/ * @throws PropertyVetoException if the change is vetoed by the listener
public abstract void vetoableChange(PropertyChangeEvent e) */
throws PropertyVetoException; void vetoableChange(PropertyChangeEvent e) throws PropertyVetoException;
} } // interface VetoableChangeListener
/* 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
/* java.beans.VetoableChangeSupport /* VetoableChangeSupport.java -- support to manage vetoable change listeners
Copyright (C) 1998 Free Software Foundation, Inc. Copyright (C) 1998, 1999, 2000, 2002 Free Software Foundation, Inc.
This file is part of GNU Classpath. This file is part of GNU Classpath.
...@@ -35,265 +35,496 @@ this exception to your version of the library, but you are not ...@@ -35,265 +35,496 @@ 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 obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */ exception statement from your version. */
package java.beans; package java.beans;
import java.util.Hashtable;
import java.util.Vector; import java.io.IOException;
import java.util.Enumeration;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
import java.io.IOException;
import java.io.Serializable; 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 * VetoableChangeSupport makes it easy to fire vetoable change events and
** change events and handle listeners as well as reversion * handle listeners. It allows chaining of listeners, as well as filtering
** of old values when things go wrong. * by property name. In addition, it will serialize only those listeners
** * which are serializable, ignoring the others without problem. This class
** @author John Keiser * is thread-safe.
** @since JDK1.1 *
** @version 1.2.0, 15 Mar 1998 * @author John Keiser
**/ * @author Eric Blake <ebb9@email.byu.edu>
* @since 1.1
public class VetoableChangeSupport implements java.io.Serializable { * @status updated to 1.4
transient Hashtable propertyListeners = new Hashtable(); */
transient Vector listeners = new Vector(); public class VetoableChangeSupport implements Serializable
Hashtable children; {
Object source; /**
int vetoableChangeSupportSerializedDataVersion = 2; * Compatible with JDK 1.1+.
*/
private static final long serialVersionUID = -5090210921595982017L; private static final long serialVersionUID = -5090210921595982017L;
/** /**
* Saves the state of the object to the stream. */ * Maps property names (String) to named listeners (VetoableChangeSupport).
private void writeObject(ObjectOutputStream stream) throws IOException { * If this is a child instance, this field will be null.
children = propertyListeners.isEmpty() ? null : propertyListeners; *
stream.defaultWriteObject(); * @serial the map of property names to named listener managers
for (Enumeration e = listeners.elements(); e.hasMoreElements(); ) { * @since 1.2
VetoableChangeListener l = (VetoableChangeListener)e.nextElement(); */
if (l instanceof Serializable) private Hashtable children;
stream.writeObject(l);
}
stream.writeObject(null);
}
/** /**
* Reads the object back from stream (deserialization). * The non-null source object for any generated events.
*
* @serial the event source
*/ */
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { private final Object source;
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.
}
/**
* 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 VetoableChangeSupport to work with a specific /**
** source bean. * Create a VetoableChangeSupport to work with a specific source bean.
** @param source the source bean to use. *
**/ * @param source the source bean to use
public VetoableChangeSupport(Object source) { * @throws NullPointerException if source is null
*/
public VetoableChangeSupport(Object source)
{
this.source = source; this.source = source;
if (source == null)
throw new NullPointerException();
} }
/** Adds a VetoableChangeListener to the list of listeners. /**
** All property change events will be sent to this listener. * Adds a VetoableChangeListener to the list of global listeners. All
** <P> * 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
** The listener add is not unique: that is, <em>n</em> adds with * result in <em>n</em> events being sent to that listener for every
** the same listener will result in <em>n</em> events being sent * vetoable change. Adding a null listener may cause a NullPointerException
** to that listener for every property change. * down the road. This method will unwrap a VetoableChangeListenerProxy,
** <P> * registering the underlying delegate to the named property list.
** *
** Adding a null listener will cause undefined behavior. * @param l the listener to add
** */
** @param l the listener to add. public synchronized void addVetoableChangeListener(VetoableChangeListener l)
**/ {
public void addVetoableChangeListener(VetoableChangeListener l) { if (l instanceof VetoableChangeListenerProxy)
listeners.addElement(l); {
VetoableChangeListenerProxy p = (VetoableChangeListenerProxy) l;
addVetoableChangeListener(p.propertyName,
(VetoableChangeListener) p.getListener());
}
else
{
if (listeners == null)
listeners = new Vector();
listeners.add(l);
}
} }
/** Adds a VetoableChangeListener listening on the specified property. /**
** Events will be sent to the listener for that particular property. * Removes a VetoableChangeListener from the list of global listeners. If
** <P> * any specific properties are being listened on, they must be deregistered
** * by themselves; this will only remove the general listener to all
** The listener add is not unique; that is, <em>n</em> adds on a * properties. If <code>add()</code> has been called multiple times for a
** particular property for a particular listener will result in * particular listener, <code>remove()</code> will have to be called the
** <em>n</em> events being sent to that listener when that * same number of times to deregister it. This method will unwrap a
** property is changed. * VetoableChangeListenerProxy, removing the underlying delegate from the
** <P> * named property list.
** *
** The effect is cumulative, too; if you are registered to listen * @param l the listener to remove
** to receive events on all property changes, and then you */
** register on a particular property, you will receive change public synchronized void
** events for that property twice. removeVetoableChangeListener(VetoableChangeListener l)
** <P> {
** if (l instanceof VetoableChangeListenerProxy)
** Adding a null listener will cause undefined behavior. {
** VetoableChangeListenerProxy p = (VetoableChangeListenerProxy) l;
** @param propertyName the name of the property to listen on. removeVetoableChangeListener(p.propertyName,
** @param l the listener to add. (VetoableChangeListener) p.getListener());
**/
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);
} }
else if (listeners != null)
{
listeners.remove(l);
if (listeners.isEmpty())
listeners = null;
} }
} }
/** Removes a VetoableChangeListener from the list of listeners. /**
** If any specific properties are being listened on, they must * Returns an array of all registered vetoable change listeners. Those that
** be deregistered by themselves; this will only remove the * were registered under a name will be wrapped in a
** general listener to all properties. * <code>VetoableChangeListenerProxy</code>, so you must check whether the
** <P> * 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,
** If <code>add()</code> has been called multiple times for a * this returns an empty array.
** particular listener, <code>remove()</code> will have to be *
** called the same number of times to deregister it. * @return the array of registered listeners
** * @see VetoableChangeListenerProxy
** @param l the listener to remove. * @since 1.4
**/ */
public void removeVetoableChangeListener(VetoableChangeListener l) { public synchronized VetoableChangeListener[] getVetoableChangeListeners()
listeners.removeElement(l); {
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()]);
} }
/** Removes a VetoableChangeListener from listening to a specific property. /**
** <P> * Adds a VetoableChangeListener listening on the specified property. Events
** * will be sent to the listener only if the property name matches. The
** If <code>add()</code> has been called multiple times for a * listener add is not unique; that is, <em>n</em> adds on a particular
** particular listener on a property, <code>remove()</code> will * property for a particular listener will result in <em>n</em> events
** have to be called the same number of times to deregister it. * 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
** @param propertyName the property to stop listening on. * all vetoable changes, and then you register on a particular property,
** @param l the listener to remove. * you will receive change events for that property twice. Adding a null
**/ * listener may cause a NullPointerException down the road. This method
public void removeVetoableChangeListener(String propertyName, VetoableChangeListener l) { * will unwrap a VetoableChangeListenerProxy, registering the underlying
synchronized(propertyListeners) { * delegate to the named property list if the names match, and discarding
Vector v = (Vector)propertyListeners.get(propertyName); * it otherwise.
try { *
v.removeElement(l); * @param propertyName the name of the property to listen on
if(v.size() == 0) { * @param l the listener to add
propertyListeners.remove(propertyName); * @throws NullPointerException if propertyName is null
} */
} catch(NullPointerException e) { public synchronized void addVetoableChangeListener(String propertyName,
/* if v is not found, do nothing. */ 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);
} }
/**
/** Fire a VetoableChangeEvent to all the listeners. * Removes a VetoableChangeListener from listening to a specific property.
** If any listener objects, a reversion event will be sent to * If <code>add()</code> has been called multiple times for a particular
** those listeners who received the initial event. * 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
** @param proposedChange the event to send. * VetoableChangeListenerProxy, removing the underlying delegate from the
** @exception PropertyVetoException if the change is vetoed. * named property list if the names match.
**/ *
public void fireVetoableChange(PropertyChangeEvent proposedChange) throws PropertyVetoException { * @param propertyName the property to stop listening on
int currentListener=0; * @param l the listener to remove
try { * @throws NullPointerException if propertyName is null
for(;currentListener<listeners.size();currentListener++) { */
((VetoableChangeListener)listeners.elementAt(currentListener)).vetoableChange(proposedChange); public synchronized void
} removeVetoableChangeListener(String propertyName, VetoableChangeListener l)
} catch(PropertyVetoException e) { {
PropertyChangeEvent reversion = new PropertyChangeEvent(proposedChange.getSource(),proposedChange.getPropertyName(),proposedChange.getNewValue(),proposedChange.getOldValue()); if (children == null)
for(int sendAgain=0;sendAgain<currentListener;sendAgain++) { return;
try { VetoableChangeSupport s
((VetoableChangeListener)listeners.elementAt(sendAgain)).vetoableChange(reversion); = (VetoableChangeSupport) children.get(propertyName);
} catch(PropertyVetoException e2) { 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;
} }
throw e;
} }
Vector moreListeners = (Vector)propertyListeners.get(proposedChange.getPropertyName()); /**
if(moreListeners != null) { * Returns an array of all vetoable change listeners registered under the
try { * given property name. If there are no registered listeners, this returns
for(currentListener = 0; currentListener < moreListeners.size(); currentListener++) { * an empty array.
((VetoableChangeListener)moreListeners.elementAt(currentListener)).vetoableChange(proposedChange); *
* @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()]);
} }
} catch(PropertyVetoException e) {
PropertyChangeEvent reversion = new PropertyChangeEvent(proposedChange.getSource(),proposedChange.getPropertyName(),proposedChange.getNewValue(),proposedChange.getOldValue()); /**
for(int sendAgain=0;sendAgain<listeners.size();sendAgain++) { * Fire a PropertyChangeEvent containing the old and new values of the
try { * property to all the global listeners, and to all the listeners for the
((VetoableChangeListener)listeners.elementAt(currentListener)).vetoableChange(proposedChange); * specified property name. This does nothing if old and new are non-null
} catch(PropertyVetoException e2) { * 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)));
} }
for(int sendAgain=0;sendAgain<currentListener;sendAgain++) { /**
try { * Fire a PropertyChangeEvent containing the old and new values of the
((VetoableChangeListener)moreListeners.elementAt(sendAgain)).vetoableChange(reversion); * property to all the global listeners, and to all the listeners for the
} catch(PropertyVetoException e2) { * 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; 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;
}
} }
/** 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 * Tell whether the specified property is being listened on or not. This
** those listeners who received the initial event. * 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 name of the property that *
** changed. * @param propertyName the property that may be listened on
** @param oldVal the old value. * @return whether the property is being listened on
** @param newVal the new value. * @throws NullPointerException if propertyName is null
** @exception PropertyVetoException if the change is vetoed. */
**/ public synchronized boolean hasListeners(String propertyName)
public void fireVetoableChange(String propertyName, int oldVal, int newVal) throws PropertyVetoException { {
fireVetoableChange(new PropertyChangeEvent(source,propertyName,new Integer(oldVal),new Integer(newVal))); 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);
}
/** Tell whether the specified property is being listened on or not. /**
** This will only return <code>true</code> if there are listeners * Reads the object back from stream (deserialization).
** on all properties or if there is a listener specifically on this *
** property. * XXX Since serialization for 1.1 streams was not documented, this may
** * not work if vetoableChangeSupportSerializedDataVersion is 1.
** @param propertyName the property that may be listened on *
** @return whether the property is being listened on * @param s the stream to read from
**/ * @throws IOException if reading the stream fails
public boolean hasListeners(String propertyName) { * @throws ClassNotFoundException if deserialization fails
return listeners.size() > 0 || propertyListeners.get(propertyName) != null; * @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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment