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.
...@@ -7,7 +7,7 @@ GNU Classpath is free software; you can redistribute it and/or modify ...@@ -7,7 +7,7 @@ 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option) the Free Software Foundation; either version 2, or (at your option)
any later version. any later version.
GNU Classpath is distributed in the hope that it will be useful, but GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
...@@ -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 * PropertyChangeEvents are fired in the PropertyChange and VetoableChange
** and VetoableChange event classes. They represent the * event classes. They represent the old and new values as well as the
** old and new values as well as the source Bean.<P> * 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.,
** If the old or new value is a primitive type, it must * etc.).
** be wrapped in the appropriate wrapper type *
** (java.lang.Integer for int, etc., etc.).<P> * <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
** If the old or new values are unknown (although why * changed, the name should be null, and the old and new values may also be
** that would be I do not know), they may be null.<P> * null. Right now Sun put in a propagationId, reserved for future use. Read
** * the comments on the constructor and on setPropagationId for more
** Right now Sun put in a propagationId, reserved for * information.
** future use. Read the comments on the constructor *
** and on setPropagationId for more information. * @author John Keiser
** * @author Eric Blake <ebb9@email.byu.edu>
** @author John Keiser * @since 1.1
** @since JDK1.1 * @status udpated to 1.4
** @version 1.1.0, 29 Jul 1998 */
**/ public class PropertyChangeEvent extends EventObject
{
public class PropertyChangeEvent extends java.util.EventObject { /**
String propertyName; * Compatible with JDK 1.1+.
Object oldValue; */
Object newValue; private static final long serialVersionUID = 7042693688939648123L;
Object propagationId;
/**
private static final long serialVersionUID = 7042693688939648123L; * The name of the property that changed, may be null. Package visible for
* use by PropertyChangeSupport.
/** Create a new PropertyChangeEvent. Remember that if *
** you received a PropertyChangeEvent and are sending * @serial the changed property name
** a new one, you should also set the propagation ID */
** from the old PropertyChangeEvent. final String propertyName;
** @param source the Bean containing the property.
** @param propertyName the property's name. /**
** @param oldValue the old value of the property. * The new value of the property, may be null. Package visible for use by
** @param newValue the new value of the property. * PropertyChangeSupport.
**/ *
public PropertyChangeEvent(Object source, String propertyName, Object oldVal, Object newVal) { * @serial the new property value
super(source); */
this.propertyName = propertyName; final Object newValue;
oldValue = oldVal;
newValue = newVal; /**
} * The old value of the property, may be null. Package visible for use by
* PropertyChangeSupport.
/** Get the property name. *
** @return the property name. * @serial the old property value
**/ */
public String getPropertyName() { final Object oldValue;
return propertyName;
} /**
* The propagation ID, reserved for future use. May be null.
/** Get the property's old value. *
** @return the property's old value. * @see #getPropagationId()
**/ * @serial the Propagation ID
public Object getOldValue() { */
return oldValue; private Object propagationId;
}
/**
/** Get the property's new value. * Create a new PropertyChangeEvent. Remember that if you received a
** @return the property's new value. * PropertyChangeEvent and are sending a new one, you should also set the
**/ * propagation ID from the old PropertyChangeEvent.
public Object getNewValue() { *
return newValue; * @param source the Bean containing the property
} * @param propertyName the property's name
* @param oldValue the old value of the property
/** Set the propagation ID. This is a way for the event * @param newValue the new value of the property
** to be passed from hand to hand and retain a little * @throws IllegalArgumentException if source is null
** extra state. Right now it is unused, but it should */
** be propagated anyway so that future versions of public PropertyChangeEvent(Object source, String propertyName,
** JavaBeans can use it, for God knows what. Object oldVal, Object newVal)
** @param propagationId the propagation ID. {
**/ super(source);
public void setPropagationId(Object propagationId) { this.propertyName = propertyName;
this.propagationId = propagationId; oldValue = oldVal;
} newValue = newVal;
}
/** Get the propagation ID.
** @return the propagation ID. /**
**/ * Get the property name. May be null if multiple properties changed.
public Object getPropagationId() { *
return propagationId; * @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
/* 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.
...@@ -7,7 +7,7 @@ GNU Classpath is free software; you can redistribute it and/or modify ...@@ -7,7 +7,7 @@ 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option) the Free Software Foundation; either version 2, or (at your option)
any later version. any later version.
GNU Classpath is distributed in the hope that it will be useful, but GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
...@@ -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.
...@@ -7,7 +7,7 @@ GNU Classpath is free software; you can redistribute it and/or modify ...@@ -7,7 +7,7 @@ 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option) the Free Software Foundation; either version 2, or (at your option)
any later version. any later version.
GNU Classpath is distributed in the hope that it will be useful, but GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
...@@ -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; /**
private static final long serialVersionUID = 6401253773779951803L; * Compatible with JDK 1.1+.
*/
/** 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; * Maps property names (String) to named listeners (PropertyChangeSupport).
stream.defaultWriteObject(); * If this is a child instance, this field will be null.
for (Enumeration e = listeners.elements(); e.hasMoreElements(); ) { *
PropertyChangeListener l = (PropertyChangeListener)e.nextElement(); * @serial the map of property names to named listener managers
if (l instanceof Serializable) * @since 1.2
stream.writeObject(l); */
} private Hashtable children;
stream.writeObject(null);
} /**
* The non-null source object for any generated events.
/** *
* Reads the object back from stream (deserialization). * @serial the event source
*/ */
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { private final Object source;
stream.defaultReadObject();
propertyListeners = (children == null) ? new Hashtable() : children; /**
PropertyChangeListener l; * A field to compare serialization versions - this class uses version 2.
while ((l = (PropertyChangeListener)stream.readObject()) != null) { *
addPropertyChangeListener(l); * @serial the serialization format
} */
// FIXME: XXX: There is no spec for JDK 1.1 serialization private final int propertyChangeSupportSerializedDataVersion = 2;
// so it is unclear what to do if the value of
// propertyChangeSupportSerializedDataVersion is 1. /**
} * The list of all registered property listeners. If this instance was
* created by user code, this only holds the global listeners (ie. not tied
/** Create PropertyChangeSupport to work with a specific * to a name), and may be null. If it was created by this class, as a
** source bean. * helper for named properties, then this vector will be non-null, and this
** @param source the source bean to use. * 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
public PropertyChangeSupport(Object source) { * hashtable entry.
this.source = source; */
} private transient Vector listeners;
/** Adds a PropertyChangeListener to the list of listeners. /**
** All property change events will be sent to this listener. * Create a PropertyChangeSupport to work with a specific source bean.
** <P> *
** * @param source the source bean to use
** The listener add is not unique: that is, <em>n</em> adds with * @throws NullPointerException if source is null
** the same listener will result in <em>n</em> events being sent */
** to that listener for every property change. public PropertyChangeSupport(Object source)
** <P> {
** this.source = source;
** Adding a null listener will cause undefined behavior. if (source == null)
** throw new NullPointerException();
** @param l the listener to add. }
**/
public void addPropertyChangeListener(PropertyChangeListener l) { /**
listeners.addElement(l); * 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
/** Adds a PropertyChangeListener listening on the specified property. * result in <em>n</em> events being sent to that listener for every
** Events will be sent to the listener for that particular property. * property change. Adding a null listener may cause a NullPointerException
** <P> * down the road. This method will unwrap a PropertyChangeListenerProxy,
** * registering the underlying delegate to the named property list.
** The listener add is not unique; that is, <em>n</em> adds on a *
** particular property for a particular listener will result in * @param l the listener to add
** <em>n</em> events being sent to that listener when that */
** property is changed. public synchronized void addPropertyChangeListener(PropertyChangeListener l)
** <P> {
** if (l instanceof PropertyChangeListenerProxy)
** The effect is cumulative, too; if you are registered to listen {
** to receive events on all property changes, and then you PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l;
** register on a particular property, you will receive change addPropertyChangeListener(p.propertyName,
** events for that property twice. (PropertyChangeListener) p.getListener());
** <P> }
** else
** Adding a null listener will cause undefined behavior. {
** if (listeners == null)
** @param propertyName the name of the property to listen on. listeners = new Vector();
** @param l the listener to add. listeners.add(l);
**/ }
public void addPropertyChangeListener(String propertyName, PropertyChangeListener l) { }
synchronized(propertyListeners) {
Vector v = (Vector)propertyListeners.get(propertyName); /**
try { * Removes a PropertyChangeListener from the list of global listeners. If
v.addElement(l); * any specific properties are being listened on, they must be deregistered
} catch(NullPointerException e) { * by themselves; this will only remove the general listener to all
/* If v is not found, create a new vector. */ * properties. If <code>add()</code> has been called multiple times for a
v = new Vector(); * particular listener, <code>remove()</code> will have to be called the
v.addElement(l); * same number of times to deregister it. This method will unwrap a
propertyListeners.put(propertyName, v); * PropertyChangeListenerProxy, removing the underlying delegate from the
} * named property list.
} *
} * @param l the listener to remove
*/
/** Removes a PropertyChangeListener from the list of listeners. public synchronized void
** If any specific properties are being listened on, they must removePropertyChangeListener(PropertyChangeListener l)
** be deregistered by themselves; this will only remove the {
** general listener to all properties. if (l instanceof PropertyChangeListenerProxy)
** <P> {
** PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l;
** If <code>add()</code> has been called multiple times for a removePropertyChangeListener(p.propertyName,
** particular listener, <code>remove()</code> will have to be (PropertyChangeListener) p.getListener());
** called the same number of times to deregister it. }
** else if (listeners != null)
** @param l the listener to remove. {
**/ listeners.remove(l);
public void removePropertyChangeListener(PropertyChangeListener l) { if (listeners.isEmpty())
listeners.removeElement(l); listeners = null;
} }
}
/** Removes a PropertyChangeListener from listening to a specific property.
** <P> /**
** * Returns an array of all registered property change listeners. Those that
** If <code>add()</code> has been called multiple times for a * were registered under a name will be wrapped in a
** particular listener on a property, <code>remove()</code> will * <code>PropertyChangeListenerProxy</code>, so you must check whether the
** have to be called the same number of times to deregister it. * 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,
** @param propertyName the property to stop listening on. * this returns an empty array.
** @param l the listener to remove. *
**/ * @return the array of registered listeners
public void removePropertyChangeListener(String propertyName, PropertyChangeListener l) { * @see PropertyChangeListenerProxy
synchronized(propertyListeners) { * @since 1.4
Vector v = (Vector)propertyListeners.get(propertyName); */
try { public synchronized PropertyChangeListener[] getPropertyChangeListeners()
v.removeElement(l); {
if(v.size() == 0) { ArrayList list = new ArrayList();
propertyListeners.remove(propertyName); if (listeners != null)
} list.addAll(listeners);
} catch(NullPointerException e) { if (children != null)
/* if v is not found, do nothing. */ {
} int i = children.size();
} Iterator iter = children.entrySet().iterator();
} while (--i >= 0)
{
/** Fire a PropertyChangeEvent to all the listeners. Entry e = (Entry) iter.next();
** String name = (String) e.getKey();
** @param event the event to fire. Vector v = ((PropertyChangeSupport) e.getValue()).listeners;
**/ int j = v.size();
public void firePropertyChange(PropertyChangeEvent event) { while (--j >= 0)
for(int i=0;i<listeners.size();i++) { list.add(new PropertyChangeListenerProxy
((PropertyChangeListener)listeners.elementAt(i)).propertyChange(event); (name, (PropertyChangeListener) v.get(j)));
} }
Vector moreListeners = (Vector)propertyListeners.get(event.getPropertyName()); }
if(moreListeners != null) { return (PropertyChangeListener[])
for(int i=0;i<moreListeners.size();i++) { list.toArray(new PropertyChangeListener[list.size()]);
((PropertyChangeListener)moreListeners.elementAt(i)).propertyChange(event); }
}
} /**
} * Adds a PropertyChangeListener listening on the specified property. Events
* will be sent to the listener only if the property name matches. The
/** Fire a PropertyChangeEvent containing the old and new values of the property to all the listeners. * 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
** @param propertyName the name of the property that changed. * being sent to that listener when that property is changed. The effect is
** @param oldVal the old value. * cumulative, too; if you are registered to listen to receive events on
** @param newVal the new value. * all property changes, and then you register on a particular property,
**/ * you will receive change events for that property twice. Adding a null
public void firePropertyChange(String propertyName, Object oldVal, Object newVal) { * listener may cause a NullPointerException down the road. This method
firePropertyChange(new PropertyChangeEvent(source,propertyName,oldVal,newVal)); * will unwrap a PropertyChangeListenerProxy, registering the underlying
} * delegate to the named property list if the names match, and discarding
* it otherwise.
/** Fire a PropertyChangeEvent containing the old and new values of the property to all the listeners. *
** * @param propertyName the name of the property to listen on
** @param propertyName the name of the property that changed. * @param l the listener to add
** @param oldVal the old value. * @throws NullPointerException if propertyName is null
** @param newVal the new value. */
**/ public synchronized void addPropertyChangeListener(String propertyName,
public void firePropertyChange(String propertyName, boolean oldVal, boolean newVal) { PropertyChangeListener l)
firePropertyChange(new PropertyChangeEvent(source, propertyName, new Boolean(oldVal), new Boolean(newVal))); {
} while (l instanceof PropertyChangeListenerProxy)
{
/** Fire a PropertyChangeEvent containing the old and new values of the property to all the listeners. PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l;
** if (propertyName == null ? p.propertyName != null
** @param propertyName the name of the property that changed. : ! propertyName.equals(p.propertyName))
** @param oldVal the old value. return;
** @param newVal the new value. l = (PropertyChangeListener) p.getListener();
**/ }
public void firePropertyChange(String propertyName, int oldVal, int newVal) { PropertyChangeSupport s = null;
firePropertyChange(new PropertyChangeEvent(source, propertyName, new Integer(oldVal), new Integer(newVal))); if (children == null)
} children = new Hashtable();
else
/** Tell whether the specified property is being listened on or not. s = (PropertyChangeSupport) children.get(propertyName);
** This will only return <code>true</code> if there are listeners if (s == null)
** on all properties or if there is a listener specifically on this {
** property. s = new PropertyChangeSupport(source);
** s.listeners = new Vector();
** @param propertyName the property that may be listened on children.put(propertyName, s);
** @return whether the property is being listened on }
**/ s.listeners.add(l);
public boolean hasListeners(String propertyName) { }
return listeners.size() > 0 || propertyListeners.get(propertyName) != null;
} /**
} * 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
/* 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.
...@@ -7,7 +7,7 @@ GNU Classpath is free software; you can redistribute it and/or modify ...@@ -7,7 +7,7 @@ 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option) the Free Software Foundation; either version 2, or (at your option)
any later version. any later version.
GNU Classpath is distributed in the hope that it will be useful, but GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
...@@ -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.
...@@ -7,7 +7,7 @@ GNU Classpath is free software; you can redistribute it and/or modify ...@@ -7,7 +7,7 @@ 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option) the Free Software Foundation; either version 2, or (at your option)
any later version. any later version.
GNU Classpath is distributed in the hope that it will be useful, but GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
...@@ -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
* @status updated to 1.4
*/
public class VetoableChangeSupport implements Serializable
{
/**
* Compatible with JDK 1.1+.
*/
private static final long serialVersionUID = -5090210921595982017L;
public class VetoableChangeSupport implements java.io.Serializable { /**
transient Hashtable propertyListeners = new Hashtable(); * Maps property names (String) to named listeners (VetoableChangeSupport).
transient Vector listeners = new Vector(); * If this is a child instance, this field will be null.
Hashtable children; *
Object source; * @serial the map of property names to named listener managers
int vetoableChangeSupportSerializedDataVersion = 2; * @since 1.2
private static final long serialVersionUID = -5090210921595982017L; */
private Hashtable children;
/** /**
* Saves the state of the object to the stream. */ * The non-null source object for any generated events.
private void writeObject(ObjectOutputStream stream) throws IOException { *
children = propertyListeners.isEmpty() ? null : propertyListeners; * @serial the event source
stream.defaultWriteObject(); */
for (Enumeration e = listeners.elements(); e.hasMoreElements(); ) { private final Object source;
VetoableChangeListener l = (VetoableChangeListener)e.nextElement();
if (l instanceof Serializable)
stream.writeObject(l);
}
stream.writeObject(null);
}
/** /**
* Reads the object back from stream (deserialization). * A field to compare serialization versions - this class uses version 2.
*/ *
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { * @serial the serialization format
stream.defaultReadObject(); */
propertyListeners = (children == null) ? new Hashtable() : children; private final int vetoableChangeSupportSerializedDataVersion = 2;
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.
}
/**
* 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
this.source = source; */
} public VetoableChangeSupport(Object 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) { else if (listeners != null)
synchronized(propertyListeners) { {
Vector v = (Vector)propertyListeners.get(propertyName); listeners.remove(l);
try { if (listeners.isEmpty())
v.addElement(l); listeners = null;
} 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 * 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);
}
/**
* 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;
}
}
/** Fire a VetoableChangeEvent to all the listeners. /**
** If any listener objects, a reversion event will be sent to * Returns an array of all vetoable change listeners registered under the
** those listeners who received the initial event. * given property name. If there are no registered listeners, this returns
** * an empty array.
** @param proposedChange the event to send. *
** @exception PropertyVetoException if the change is vetoed. * @return the array of registered listeners
**/ * @throws NullPointerException if propertyName is null
public void fireVetoableChange(PropertyChangeEvent proposedChange) throws PropertyVetoException { * @since 1.4
int currentListener=0; */
try { public synchronized VetoableChangeListener[]
for(;currentListener<listeners.size();currentListener++) { getVetoableChangeListeners(String propertyName)
((VetoableChangeListener)listeners.elementAt(currentListener)).vetoableChange(proposedChange); {
} if (children == null)
} catch(PropertyVetoException e) { return new VetoableChangeListener[0];
PropertyChangeEvent reversion = new PropertyChangeEvent(proposedChange.getSource(),proposedChange.getPropertyName(),proposedChange.getNewValue(),proposedChange.getOldValue()); VetoableChangeSupport s
for(int sendAgain=0;sendAgain<currentListener;sendAgain++) { = (VetoableChangeSupport) children.get(propertyName);
try { if (s == null)
((VetoableChangeListener)listeners.elementAt(sendAgain)).vetoableChange(reversion); return new VetoableChangeListener[0];
} catch(PropertyVetoException e2) { return (VetoableChangeListener[])
} s.listeners.toArray(new VetoableChangeListener[s.listeners.size()]);
} }
throw e;
}
Vector moreListeners = (Vector)propertyListeners.get(proposedChange.getPropertyName()); /**
if(moreListeners != null) { * 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
for(currentListener = 0; currentListener < moreListeners.size(); currentListener++) { * specified property name. This does nothing if old and new are non-null
((VetoableChangeListener)moreListeners.elementAt(currentListener)).vetoableChange(proposedChange); * and equal. If the change is vetoed, a new event is fired to notify
} * listeners about the rollback before the exception is thrown.
} catch(PropertyVetoException e) { *
PropertyChangeEvent reversion = new PropertyChangeEvent(proposedChange.getSource(),proposedChange.getPropertyName(),proposedChange.getNewValue(),proposedChange.getOldValue()); * @param propertyName the name of the property that changed
for(int sendAgain=0;sendAgain<listeners.size();sendAgain++) { * @param oldVal the old value
try { * @param newVal the new value
((VetoableChangeListener)listeners.elementAt(currentListener)).vetoableChange(proposedChange); * @throws PropertyVetoException if the change is vetoed by a listener
} catch(PropertyVetoException e2) { */
} public void fireVetoableChange(String propertyName,
} Object oldVal, Object newVal)
throws PropertyVetoException
{
fireVetoableChange(new PropertyChangeEvent(source, propertyName,
oldVal, 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.
throw e; *
} * @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 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 * Fire a PropertyChangeEvent containing the old and new values of the
** those listeners who received the initial event. * 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 * If the change is vetoed, a new event is fired to notify listeners about
** changed. * the rollback before the exception is thrown.
** @param oldVal the old value. *
** @param newVal the new value. * @param propertyName the name of the property that changed
** @exception PropertyVetoException if the change is vetoed. * @param oldVal the old value
**/ * @param newVal the new value
public void fireVetoableChange(String propertyName, Object oldVal, Object newVal) throws PropertyVetoException { * @throws PropertyVetoException if the change is vetoed by a listener
fireVetoableChange(new PropertyChangeEvent(source,propertyName,oldVal,newVal)); */
} 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 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 * Fire a PropertyChangeEvent to all the global listeners, and to all the
** those listeners who received the initial event. * 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
** @param propertyName the name of the property that * is fired to notify listeners about the rollback before the exception is
** changed. * thrown.
** @param oldVal the old value. *
** @param newVal the new value. * @param event the event to fire
** @exception PropertyVetoException if the change is vetoed. * @throws NullPointerException if event is null
**/ * @throws PropertyVetoException if the change is vetoed by a listener
public void fireVetoableChange(String propertyName, boolean oldVal, boolean newVal) throws PropertyVetoException { */
fireVetoableChange(new PropertyChangeEvent(source,propertyName,new Boolean(oldVal),new Boolean(newVal))); 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;
}
}
}
}
/** 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