blob: d56e63a784bd57adaf0e5fa5d68edcdf52586b6d [file] [log] [blame]
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package java.beans;
19
20import java.io.IOException;
21import java.io.ObjectInputStream;
22import java.io.ObjectOutputStream;
23import java.io.Serializable;
24import java.util.ArrayList;
25import java.util.HashMap;
26import java.util.Hashtable;
27import java.util.Iterator;
28import java.util.List;
29import java.util.Map;
30
31public class PropertyChangeSupport implements Serializable {
32
33 private static final long serialVersionUID = 6401253773779951803l;
34
35 private transient Object sourceBean;
36
37 private transient List<PropertyChangeListener> allPropertiesChangeListeners =
38 new ArrayList<PropertyChangeListener>();
39
40 private transient Map<String, List<PropertyChangeListener>>
41 selectedPropertiesChangeListeners =
42 new HashMap<String, List<PropertyChangeListener>>();
43
44 // fields for serialization compatibility
45 private Hashtable<String, List<PropertyChangeListener>> children;
46
47 private Object source;
48
49 private int propertyChangeSupportSerializedDataVersion = 1;
50
51 public PropertyChangeSupport(Object sourceBean) {
52 if (sourceBean == null) {
53 throw new NullPointerException();
54 }
55 this.sourceBean = sourceBean;
56 }
57
58 public void firePropertyChange(String propertyName, Object oldValue,
59 Object newValue) {
60 PropertyChangeEvent event = createPropertyChangeEvent(propertyName,
61 oldValue, newValue);
62 doFirePropertyChange(event);
63 }
64
65 public void fireIndexedPropertyChange(String propertyName, int index,
66 Object oldValue, Object newValue) {
67
68 // nulls and equals check done in doFire...
69 doFirePropertyChange(new IndexedPropertyChangeEvent(sourceBean,
70 propertyName, oldValue, newValue, index));
71 }
72
73 public synchronized void removePropertyChangeListener(String propertyName,
74 PropertyChangeListener listener) {
75 if ((propertyName != null) && (listener != null)) {
76 List<PropertyChangeListener> listeners =
77 selectedPropertiesChangeListeners.get(propertyName);
78
79 if (listeners != null) {
80 listeners.remove(listener);
81 }
82 }
83 }
84
85 public synchronized void addPropertyChangeListener(String propertyName,
86 PropertyChangeListener listener) {
87 if ((listener != null) && (propertyName != null)) {
88 List<PropertyChangeListener> listeners =
89 selectedPropertiesChangeListeners.get(propertyName);
90
91 if (listeners == null) {
92 listeners = new ArrayList<PropertyChangeListener>();
93 selectedPropertiesChangeListeners.put(propertyName, listeners);
94 }
95
96 // RI compatibility
97 if (listener instanceof PropertyChangeListenerProxy) {
98 PropertyChangeListenerProxy proxy =
99 (PropertyChangeListenerProxy) listener;
100
101 listeners.add(new PropertyChangeListenerProxy(
102 proxy.getPropertyName(),
103 (PropertyChangeListener) proxy.getListener()));
104 } else {
105 listeners.add(listener);
106 }
107 }
108 }
109
110 public synchronized PropertyChangeListener[] getPropertyChangeListeners(
111 String propertyName) {
112 List<PropertyChangeListener> listeners = null;
113
114 if (propertyName != null) {
115 listeners = selectedPropertiesChangeListeners.get(propertyName);
116 }
117
118 return (listeners == null) ? new PropertyChangeListener[] {}
119 : listeners.toArray(
120 new PropertyChangeListener[listeners.size()]);
121 }
122
123 public void firePropertyChange(String propertyName, boolean oldValue,
124 boolean newValue) {
125 PropertyChangeEvent event = createPropertyChangeEvent(propertyName,
126 oldValue, newValue);
127 doFirePropertyChange(event);
128 }
129
130 public void fireIndexedPropertyChange(String propertyName, int index,
131 boolean oldValue, boolean newValue) {
132
133 if (oldValue != newValue) {
134 fireIndexedPropertyChange(propertyName, index, Boolean
135 .valueOf(oldValue), Boolean.valueOf(newValue));
136 }
137 }
138
139 public void firePropertyChange(String propertyName, int oldValue,
140 int newValue) {
141 PropertyChangeEvent event = createPropertyChangeEvent(propertyName,
142 oldValue, newValue);
143 doFirePropertyChange(event);
144 }
145
146 public void fireIndexedPropertyChange(String propertyName, int index,
147 int oldValue, int newValue) {
148
149 if (oldValue != newValue) {
150 fireIndexedPropertyChange(propertyName, index,
151 new Integer(oldValue), new Integer(newValue));
152 }
153 }
154
155 public synchronized boolean hasListeners(String propertyName) {
156 boolean result = allPropertiesChangeListeners.size() > 0;
157 if (!result && (propertyName != null)) {
158 List<PropertyChangeListener> listeners =
159 selectedPropertiesChangeListeners.get(propertyName);
160 if (listeners != null) {
161 result = listeners.size() > 0;
162 }
163 }
164 return result;
165 }
166
167 public synchronized void removePropertyChangeListener(
168 PropertyChangeListener listener) {
169 if (listener != null) {
170 if (listener instanceof PropertyChangeListenerProxy) {
171 String name = ((PropertyChangeListenerProxy) listener)
172 .getPropertyName();
173 PropertyChangeListener lst = (PropertyChangeListener)
174 ((PropertyChangeListenerProxy) listener).getListener();
175
176 removePropertyChangeListener(name, lst);
177 } else {
178 allPropertiesChangeListeners.remove(listener);
179 }
180 }
181 }
182
183 public synchronized void addPropertyChangeListener(
184 PropertyChangeListener listener) {
185 if (listener != null) {
186 if (listener instanceof PropertyChangeListenerProxy) {
187 String name = ((PropertyChangeListenerProxy) listener)
188 .getPropertyName();
189 PropertyChangeListener lst = (PropertyChangeListener)
190 ((PropertyChangeListenerProxy) listener).getListener();
191 addPropertyChangeListener(name, lst);
192 } else {
193 allPropertiesChangeListeners.add(listener);
194 }
195 }
196 }
197
198 public synchronized PropertyChangeListener[] getPropertyChangeListeners() {
199 ArrayList<PropertyChangeListener> result =
200 new ArrayList<PropertyChangeListener>(
201 allPropertiesChangeListeners);
202
203 for (String propertyName : selectedPropertiesChangeListeners.keySet()) {
204 List<PropertyChangeListener> selectedListeners =
205 selectedPropertiesChangeListeners.get(propertyName);
206
207 if (selectedListeners != null) {
208
209 for (PropertyChangeListener listener : selectedListeners) {
210 result.add(new PropertyChangeListenerProxy(propertyName,
211 listener));
212 }
213 }
214 }
215
216 return result.toArray(new PropertyChangeListener[result.size()]);
217 }
218
219 private void writeObject(ObjectOutputStream oos) throws IOException {
220 List<PropertyChangeListener> allSerializedPropertiesChangeListeners =
221 new ArrayList<PropertyChangeListener>();
222
223 for (PropertyChangeListener pcl : allPropertiesChangeListeners) {
224 if (pcl instanceof Serializable) {
225 allSerializedPropertiesChangeListeners.add(pcl);
226 }
227 }
228
229 Map<String, List<PropertyChangeListener>>
230 selectedSerializedPropertiesChangeListeners =
231 new HashMap<String, List<PropertyChangeListener>>();
232
233 for (String propertyName : selectedPropertiesChangeListeners.keySet()) {
234 List<PropertyChangeListener> keyValues =
235 selectedPropertiesChangeListeners.get(propertyName);
236
237 if (keyValues != null) {
238 List<PropertyChangeListener> serializedPropertiesChangeListeners
239 = new ArrayList<PropertyChangeListener>();
240
241 for (PropertyChangeListener pcl : keyValues) {
242 if (pcl instanceof Serializable) {
243 serializedPropertiesChangeListeners.add(pcl);
244 }
245 }
246
247 if (!serializedPropertiesChangeListeners.isEmpty()) {
248 selectedSerializedPropertiesChangeListeners.put(
249 propertyName, serializedPropertiesChangeListeners);
250 }
251 }
252 }
253
254 children = new Hashtable<String, List<PropertyChangeListener>>(
255 selectedSerializedPropertiesChangeListeners);
256 children.put("", allSerializedPropertiesChangeListeners); //$NON-NLS-1$
257 oos.writeObject(children);
258
259 Object source = null;
260 if (sourceBean instanceof Serializable) {
261 source = sourceBean;
262 }
263 oos.writeObject(source);
264
265 oos.writeInt(propertyChangeSupportSerializedDataVersion);
266 }
267
268 @SuppressWarnings("unchecked")
269 private void readObject(ObjectInputStream ois) throws IOException,
270 ClassNotFoundException {
271 children = (Hashtable<String, List<PropertyChangeListener>>) ois
272 .readObject();
273
274 selectedPropertiesChangeListeners = new HashMap<String, List<PropertyChangeListener>>(
275 children);
276 allPropertiesChangeListeners = selectedPropertiesChangeListeners
277 .remove(""); //$NON-NLS-1$
278 if (allPropertiesChangeListeners == null) {
279 allPropertiesChangeListeners = new ArrayList<PropertyChangeListener>();
280 }
281
282 sourceBean = ois.readObject();
283 propertyChangeSupportSerializedDataVersion = ois.readInt();
284 }
285
286 public void firePropertyChange(PropertyChangeEvent event) {
287 doFirePropertyChange(event);
288 }
289
290 private PropertyChangeEvent createPropertyChangeEvent(String propertyName,
291 Object oldValue, Object newValue) {
292 return new PropertyChangeEvent(sourceBean, propertyName, oldValue,
293 newValue);
294 }
295
296 private PropertyChangeEvent createPropertyChangeEvent(String propertyName,
297 boolean oldValue, boolean newValue) {
298 return new PropertyChangeEvent(sourceBean, propertyName, oldValue,
299 newValue);
300 }
301
302 private PropertyChangeEvent createPropertyChangeEvent(String propertyName,
303 int oldValue, int newValue) {
304 return new PropertyChangeEvent(sourceBean, propertyName, oldValue,
305 newValue);
306 }
307
308 private void doFirePropertyChange(PropertyChangeEvent event) {
309 String propertyName = event.getPropertyName();
310 Object oldValue = event.getOldValue();
311 Object newValue = event.getNewValue();
312
313 if ((newValue != null) && (oldValue != null)
314 && newValue.equals(oldValue)) {
315 return;
316 }
317
318 /*
319 * Copy the listeners collections so they can be modified while we fire
320 * events.
321 */
322
323 // Listeners to all property change events
324 PropertyChangeListener[] listensToAll;
325 // Listens to a given property change
326 PropertyChangeListener[] listensToOne = null;
327 synchronized (this) {
328 listensToAll = allPropertiesChangeListeners
329 .toArray(new PropertyChangeListener[allPropertiesChangeListeners
330 .size()]);
331
332 List<PropertyChangeListener> listeners = selectedPropertiesChangeListeners
333 .get(propertyName);
334 if (listeners != null) {
335 listensToOne = listeners
336 .toArray(new PropertyChangeListener[listeners.size()]);
337 }
338 }
339
340 // Fire the listeners
341 for (PropertyChangeListener listener : listensToAll) {
342 listener.propertyChange(event);
343 }
344 if (listensToOne != null) {
345 for (PropertyChangeListener listener : listensToOne) {
346 listener.propertyChange(event);
347 }
348 }
349 }
350
351}