1. /*
  2. * @(#)SwingPropertyChangeSupport.java 1.7 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing.event;
  8. import java.beans.*;
  9. import java.io.Serializable;
  10. import java.io.ObjectOutputStream;
  11. import java.io.ObjectInputStream;
  12. import java.io.IOException;
  13. /**
  14. * This subclass of java.beans.PropertyChangeSupport is identical
  15. * in functionality -- it sacrifices thread-safety (not a Swing
  16. * concern) for reduce memory consumption, which helps performance
  17. * (both big Swing concerns). Most of the overridden methods are
  18. * only necessary because all of PropertyChangeSupport's instance
  19. * data is private, without accessor methods.
  20. *
  21. * @version 1.7 11/29/01
  22. * @author unattributed
  23. */
  24. public final class SwingPropertyChangeSupport extends PropertyChangeSupport {
  25. /**
  26. * Constructs a SwingPropertyChangeSupport object.
  27. *
  28. * @param sourceBean The bean to be given as the source for any events.
  29. */
  30. public SwingPropertyChangeSupport(Object sourceBean) {
  31. super(sourceBean);
  32. source = sourceBean;
  33. }
  34. /**
  35. * Add a PropertyChangeListener to the listener list.
  36. * The listener is registered for all properties.
  37. *
  38. * @param listener The PropertyChangeListener to be added
  39. */
  40. public synchronized void addPropertyChangeListener(
  41. PropertyChangeListener listener) {
  42. if (listeners == null) {
  43. listeners = new java.util.Vector();
  44. }
  45. listeners.addElement(listener);
  46. }
  47. /**
  48. * Remove a PropertyChangeListener from the listener list.
  49. * This removes a PropertyChangeListener that was registered
  50. * for all properties.
  51. *
  52. * @param listener The PropertyChangeListener to be removed
  53. */
  54. public synchronized void removePropertyChangeListener(
  55. PropertyChangeListener listener) {
  56. if (listeners == null) {
  57. return;
  58. }
  59. listeners.removeElement(listener);
  60. }
  61. /**
  62. * Add a PropertyChangeListener for a specific property. The listener
  63. * will be invoked only when a call on firePropertyChange names that
  64. * specific property.
  65. *
  66. * @param propertyName The name of the property to listen on.
  67. * @param listener The PropertyChangeListener to be added
  68. */
  69. public synchronized void addPropertyChangeListener(
  70. String propertyName,
  71. PropertyChangeListener listener) {
  72. if (children == null) {
  73. children = new java.util.Hashtable();
  74. }
  75. SwingPropertyChangeSupport child =
  76. (SwingPropertyChangeSupport)children.get(propertyName);
  77. if (child == null) {
  78. child = new SwingPropertyChangeSupport(source);
  79. children.put(propertyName, child);
  80. }
  81. child.addPropertyChangeListener(listener);
  82. }
  83. /**
  84. * Remove a PropertyChangeListener for a specific property.
  85. *
  86. * @param propertyName The name of the property that was listened on.
  87. * @param listener The PropertyChangeListener to be removed
  88. */
  89. public synchronized void removePropertyChangeListener(
  90. String propertyName,
  91. PropertyChangeListener listener) {
  92. if (children == null) {
  93. return;
  94. }
  95. SwingPropertyChangeSupport child =
  96. (SwingPropertyChangeSupport)children.get(propertyName);
  97. if (child == null) {
  98. return;
  99. }
  100. child.removePropertyChangeListener(listener);
  101. }
  102. /**
  103. * Report a bound property update to any registered listeners.
  104. * No event is fired if old and new are equal and non-null.
  105. *
  106. * @param propertyName The programmatic name of the property
  107. * that was changed.
  108. * @param oldValue The old value of the property.
  109. * @param newValue The new value of the property.
  110. */
  111. public void firePropertyChange(String propertyName,
  112. Object oldValue, Object newValue) {
  113. if (oldValue != null && newValue != null && oldValue.equals(newValue)) {
  114. return;
  115. }
  116. SwingPropertyChangeSupport child = null;
  117. synchronized (this) {
  118. if (children != null && propertyName != null) {
  119. child = (SwingPropertyChangeSupport)children.get(propertyName);
  120. }
  121. }
  122. if (listeners != null || child != null) {
  123. // Only create an event if there's an interested receiver.
  124. PropertyChangeEvent evt = new PropertyChangeEvent(
  125. source, propertyName, oldValue, newValue);
  126. if (listeners != null) {
  127. for (int i = 0; i < listeners.size(); i++) {
  128. PropertyChangeListener target =
  129. (PropertyChangeListener)listeners.elementAt(i);
  130. target.propertyChange(evt);
  131. }
  132. }
  133. if (child != null) {
  134. child.firePropertyChange(evt);
  135. }
  136. }
  137. }
  138. /**
  139. * Fire an existing PropertyChangeEvent to any registered listeners.
  140. * No event is fired if the given event's old and new values are
  141. * equal and non-null.
  142. * @param evt The PropertyChangeEvent object.
  143. */
  144. public void firePropertyChange(PropertyChangeEvent evt) {
  145. Object oldValue = evt.getOldValue();
  146. Object newValue = evt.getNewValue();
  147. String propertyName = evt.getPropertyName();
  148. if (oldValue != null && newValue != null && oldValue.equals(newValue)) {
  149. return;
  150. }
  151. SwingPropertyChangeSupport child = null;
  152. synchronized (this) {
  153. if (children != null && propertyName != null) {
  154. child = (SwingPropertyChangeSupport)children.get(propertyName);
  155. }
  156. }
  157. if (listeners != null) {
  158. int size = listeners.size();
  159. for (int i = 0; i < size; i++) {
  160. PropertyChangeListener target =
  161. (PropertyChangeListener)listeners.elementAt(i);
  162. target.propertyChange(evt);
  163. }
  164. }
  165. if (child != null) {
  166. child.firePropertyChange(evt);
  167. }
  168. }
  169. /**
  170. * Check if there are any listeners for a specific property.
  171. *
  172. * @param propertyName the property name.
  173. * @return true if there are ore or more listeners for the given property
  174. */
  175. public synchronized boolean hasListeners(String propertyName) {
  176. if (listeners != null && !listeners.isEmpty()) {
  177. // there is a generic listener
  178. return true;
  179. }
  180. if (children != null) {
  181. SwingPropertyChangeSupport child =
  182. (SwingPropertyChangeSupport)children.get(propertyName);
  183. if (child != null) {
  184. // The child will always have a listeners Vector.
  185. return !child.listeners.isEmpty();
  186. }
  187. }
  188. return false;
  189. }
  190. private void writeObject(ObjectOutputStream s) throws IOException {
  191. s.defaultWriteObject();
  192. java.util.Vector v = null;
  193. synchronized (this) {
  194. if (listeners != null) {
  195. v = (java.util.Vector) listeners.clone();
  196. }
  197. }
  198. if (v != null) {
  199. int size = v.size();
  200. for (int i = 0; i < size; i++) {
  201. PropertyChangeListener l = (PropertyChangeListener)v.elementAt(i);
  202. if (l instanceof Serializable) {
  203. s.writeObject(l);
  204. }
  205. }
  206. }
  207. s.writeObject(null);
  208. }
  209. private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException {
  210. s.defaultReadObject();
  211. Object listenerOrNull;
  212. while (null != (listenerOrNull = s.readObject())) {
  213. addPropertyChangeListener((PropertyChangeListener)listenerOrNull);
  214. }
  215. }
  216. // "listeners" lists all the generic listeners.
  217. transient private java.util.Vector listeners;
  218. // "children" contains SwingPropertyChangeSupports for individual properties
  219. private java.util.Hashtable children;
  220. private Object source;
  221. // Serialization version ID
  222. static final long serialVersionUID = 7162625831330845068L;
  223. }