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 }