001 /* 002 * $Id: JavaBean.java,v 1.2 2006/05/14 15:55:55 dmouse Exp $ 003 * 004 * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, 005 * Santa Clara, California 95054, U.S.A. All rights reserved. 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this library; if not, write to the Free Software 019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 020 */ 021 022 package org.jdesktop.swingx; 023 024 import java.beans.PropertyChangeEvent; 025 import java.beans.PropertyChangeListener; 026 import java.beans.PropertyChangeSupport; 027 028 /** 029 * <p>A convenience class from which to extend all non-visual JavaBeans. It 030 * manages the PropertyChange notification system, making it relatively trivial 031 * to add support for property change events in getters/setters.</p> 032 * 033 * <p>Here is a simple example bean that contains one property, foo, and the 034 * proper pattern for implementing property change notification: 035 * <pre><code> 036 * public class ABean extends JavaBean { 037 * private String foo; 038 * 039 * public void setFoo(String newFoo) { 040 * String old = getFoo(); 041 * this.foo = newFoo; 042 * firePropertyChange("foo", old, getFoo()); 043 * } 044 * 045 * public String getFoo() { 046 * return foo; 047 * } 048 * } 049 * </code></pre></p> 050 * 051 * <p>You will notice that "getFoo()" is used in the setFoo method rather than 052 * accessing "foo" directly for the gets. This is done intentionally so that if 053 * a subclass overrides getFoo() to return, for instance, a constant value the 054 * property change notification system will continue to work properly.</p> 055 * 056 * <p>The firePropertyChange method takes into account the old value and the new 057 * value. Only if the two differ will it fire a property change event. So you can 058 * be assured from the above code fragment that a property change event will only 059 * occur if old is indeed different from getFoo()</p> 060 * 061 * @author rbair 062 */ 063 public class JavaBean { 064 /** 065 * Helper class that manages all the property change notification machinery. 066 * PropertyChangeSupport can not be extended directly because it requires 067 * a bean in the constructor, and the "this" argument is not valid until 068 * after super construction. Hence, delegation instead of extension 069 */ 070 private PropertyChangeSupport pcs; 071 072 /** Creates a new instance of JavaBean */ 073 public JavaBean() { 074 pcs = new PropertyChangeSupport(this); 075 } 076 077 /** 078 * Add a PropertyChangeListener to the listener list. 079 * The listener is registered for all properties. 080 * The same listener object may be added more than once, and will be called 081 * as many times as it is added. 082 * If <code>listener</code> is null, no exception is thrown and no action 083 * is taken. 084 * 085 * @param listener The PropertyChangeListener to be added 086 */ 087 public void addPropertyChangeListener(PropertyChangeListener listener) { 088 pcs.addPropertyChangeListener(listener); 089 } 090 091 /** 092 * Remove a PropertyChangeListener from the listener list. 093 * This removes a PropertyChangeListener that was registered 094 * for all properties. 095 * If <code>listener</code> was added more than once to the same event 096 * source, it will be notified one less time after being removed. 097 * If <code>listener</code> is null, or was never added, no exception is 098 * thrown and no action is taken. 099 * 100 * @param listener The PropertyChangeListener to be removed 101 */ 102 public void removePropertyChangeListener(PropertyChangeListener listener) { 103 pcs.removePropertyChangeListener(listener); 104 } 105 106 /** 107 * Returns an array of all the listeners that were added to the 108 * PropertyChangeSupport object with addPropertyChangeListener(). 109 * <p> 110 * If some listeners have been added with a named property, then 111 * the returned array will be a mixture of PropertyChangeListeners 112 * and <code>PropertyChangeListenerProxy</code>s. If the calling 113 * method is interested in distinguishing the listeners then it must 114 * test each element to see if it's a 115 * <code>PropertyChangeListenerProxy</code>, perform the cast, and examine 116 * the parameter. 117 * 118 * <pre> 119 * PropertyChangeListener[] listeners = bean.getPropertyChangeListeners(); 120 * for (int i = 0; i < listeners.length; i++) { 121 * if (listeners[i] instanceof PropertyChangeListenerProxy) { 122 * PropertyChangeListenerProxy proxy = 123 * (PropertyChangeListenerProxy)listeners[i]; 124 * if (proxy.getPropertyName().equals("foo")) { 125 * // proxy is a PropertyChangeListener which was associated 126 * // with the property named "foo" 127 * } 128 * } 129 * } 130 *</pre> 131 * 132 * @see java.beans.PropertyChangeListenerProxy 133 * @return all of the <code>PropertyChangeListeners</code> added or an 134 * empty array if no listeners have been added 135 */ 136 public PropertyChangeListener[] getPropertyChangeListeners() { 137 return pcs.getPropertyChangeListeners(); 138 } 139 140 /** 141 * Add a PropertyChangeListener for a specific property. The listener 142 * will be invoked only when a call on firePropertyChange names that 143 * specific property. 144 * The same listener object may be added more than once. For each 145 * property, the listener will be invoked the number of times it was added 146 * for that property. 147 * If <code>propertyName</code> or <code>listener</code> is null, no 148 * exception is thrown and no action is taken. 149 * 150 * @param propertyName The name of the property to listen on. 151 * @param listener The PropertyChangeListener to be added 152 */ 153 154 public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { 155 pcs.addPropertyChangeListener(propertyName, listener); 156 } 157 158 /** 159 * Remove a PropertyChangeListener for a specific property. 160 * If <code>listener</code> was added more than once to the same event 161 * source for the specified property, it will be notified one less time 162 * after being removed. 163 * If <code>propertyName</code> is null, no exception is thrown and no 164 * action is taken. 165 * If <code>listener</code> is null, or was never added for the specified 166 * property, no exception is thrown and no action is taken. 167 * 168 * @param propertyName The name of the property that was listened on. 169 * @param listener The PropertyChangeListener to be removed 170 */ 171 172 public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { 173 pcs.removePropertyChangeListener(propertyName, listener); 174 } 175 176 /** 177 * Returns an array of all the listeners which have been associated 178 * with the named property. 179 * 180 * @param propertyName The name of the property being listened to 181 * @return all of the <code>PropertyChangeListeners</code> associated with 182 * the named property. If no such listeners have been added, 183 * or if <code>propertyName</code> is null, an empty array is 184 * returned. 185 */ 186 public PropertyChangeListener[] getPropertyChangeListeners(String propertyName) { 187 return pcs.getPropertyChangeListeners(propertyName); 188 } 189 190 /** 191 * Report a bound property update to any registered listeners. 192 * No event is fired if old and new are equal and non-null. 193 * 194 * <p> 195 * This is merely a convenience wrapper around the more general 196 * firePropertyChange method that takes {@code 197 * PropertyChangeEvent} value. 198 * 199 * @param propertyName The programmatic name of the property 200 * that was changed. 201 * @param oldValue The old value of the property. 202 * @param newValue The new value of the property. 203 */ 204 public void firePropertyChange(String propertyName, Object oldValue, Object newValue) { 205 pcs.firePropertyChange(propertyName, oldValue, newValue); 206 } 207 208 /** 209 * Report an int bound property update to any registered listeners. 210 * No event is fired if old and new are equal. 211 * <p> 212 * This is merely a convenience wrapper around the more general 213 * firePropertyChange method that takes Object values. 214 * 215 * @param propertyName The programmatic name of the property 216 * that was changed. 217 * @param oldValue The old value of the property. 218 * @param newValue The new value of the property. 219 */ 220 public void firePropertyChange(String propertyName, int oldValue, int newValue) { 221 pcs.firePropertyChange(propertyName, oldValue, newValue); 222 } 223 224 225 /** 226 * Report a boolean bound property update to any registered listeners. 227 * No event is fired if old and new are equal. 228 * <p> 229 * This is merely a convenience wrapper around the more general 230 * firePropertyChange method that takes Object values. 231 * 232 * @param propertyName The programmatic name of the property 233 * that was changed. 234 * @param oldValue The old value of the property. 235 * @param newValue The new value of the property. 236 */ 237 public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) { 238 pcs.firePropertyChange(propertyName, oldValue, newValue); 239 } 240 241 /** 242 * Fire an existing PropertyChangeEvent to any registered listeners. 243 * No event is fired if the given event's old and new values are 244 * equal and non-null. 245 * @param evt The PropertyChangeEvent object. 246 */ 247 public void firePropertyChange(PropertyChangeEvent evt) { 248 pcs.firePropertyChange(evt); 249 } 250 251 252 /** 253 * Report a bound indexed property update to any registered 254 * listeners. 255 * <p> 256 * No event is fired if old and new values are equal 257 * and non-null. 258 * 259 * <p> 260 * This is merely a convenience wrapper around the more general 261 * firePropertyChange method that takes {@code PropertyChangeEvent} value. 262 * 263 * @param propertyName The programmatic name of the property that 264 * was changed. 265 * @param index index of the property element that was changed. 266 * @param oldValue The old value of the property. 267 * @param newValue The new value of the property. 268 */ 269 public void fireIndexedPropertyChange(String propertyName, int index, 270 Object oldValue, Object newValue) { 271 pcs.fireIndexedPropertyChange(propertyName, index, oldValue, newValue); 272 } 273 274 /** 275 * Report an <code>int</code> bound indexed property update to any registered 276 * listeners. 277 * <p> 278 * No event is fired if old and new values are equal. 279 * <p> 280 * This is merely a convenience wrapper around the more general 281 * fireIndexedPropertyChange method which takes Object values. 282 * 283 * @param propertyName The programmatic name of the property that 284 * was changed. 285 * @param index index of the property element that was changed. 286 * @param oldValue The old value of the property. 287 * @param newValue The new value of the property. 288 */ 289 public void fireIndexedPropertyChange(String propertyName, int index, 290 int oldValue, int newValue) { 291 pcs.fireIndexedPropertyChange(propertyName, index, oldValue, newValue); 292 } 293 294 /** 295 * Report a <code>boolean</code> bound indexed property update to any 296 * registered listeners. 297 * <p> 298 * No event is fired if old and new values are equal. 299 * <p> 300 * This is merely a convenience wrapper around the more general 301 * fireIndexedPropertyChange method which takes Object values. 302 * 303 * @param propertyName The programmatic name of the property that 304 * was changed. 305 * @param index index of the property element that was changed. 306 * @param oldValue The old value of the property. 307 * @param newValue The new value of the property. 308 */ 309 public void fireIndexedPropertyChange(String propertyName, int index, 310 boolean oldValue, boolean newValue) { 311 pcs.fireIndexedPropertyChange(propertyName, index, oldValue, newValue); 312 } 313 314 /** 315 * Check if there are any listeners for a specific property, including 316 * those registered on all properties. If <code>propertyName</code> 317 * is null, only check for listeners registered on all properties. 318 * 319 * @param propertyName the property name. 320 * @return true if there are one or more listeners for the given property 321 */ 322 public boolean hasListeners(String propertyName) { 323 return pcs.hasListeners(propertyName); 324 } 325 }