OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [java/] [beans/] [PropertyChangeSupport.java] - Blame information for rev 772

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 771 jeremybenn
/* PropertyChangeSupport.java -- support to manage property change listeners
2
   Copyright (C) 1998, 1999, 2000, 2002, 2005, 2006
3
   Free Software Foundation, Inc.
4
 
5
This file is part of GNU Classpath.
6
 
7
GNU Classpath is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2, or (at your option)
10
any later version.
11
 
12
GNU Classpath is distributed in the hope that it will be useful, but
13
WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
General Public License for more details.
16
 
17
You should have received a copy of the GNU General Public License
18
along with GNU Classpath; see the file COPYING.  If not, write to the
19
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20
02110-1301 USA.
21
 
22
Linking this library statically or dynamically with other modules is
23
making a combined work based on this library.  Thus, the terms and
24
conditions of the GNU General Public License cover the whole
25
combination.
26
 
27
As a special exception, the copyright holders of this library give you
28
permission to link this library with independent modules to produce an
29
executable, regardless of the license terms of these independent
30
modules, and to copy and distribute the resulting executable under
31
terms of your choice, provided that you also meet, for each linked
32
independent module, the terms and conditions of the license of that
33
module.  An independent module is a module which is not derived from
34
or based on this library.  If you modify this library, you may extend
35
this exception to your version of the library, but you are not
36
obligated to do so.  If you do not wish to do so, delete this
37
exception statement from your version. */
38
 
39
 
40
package java.beans;
41
 
42
import java.io.IOException;
43
import java.io.ObjectInputStream;
44
import java.io.ObjectOutputStream;
45
import java.io.Serializable;
46
import java.util.ArrayList;
47
import java.util.Arrays;
48
import java.util.Hashtable;
49
import java.util.Iterator;
50
import java.util.Map.Entry;
51
import java.util.Vector;
52
 
53
/**
54
 * PropertyChangeSupport makes it easy to fire property change events and
55
 * handle listeners. It allows chaining of listeners, as well as filtering
56
 * by property name. In addition, it will serialize only those listeners
57
 * which are serializable, ignoring the others without problem. This class
58
 * is thread-safe.
59
 *
60
 * @author John Keiser
61
 * @author Eric Blake (ebb9@email.byu.edu)
62
 * @since 1.1
63
 * @status updated to 1.4
64
 */
65
public class PropertyChangeSupport implements Serializable
66
{
67
  /**
68
   * Compatible with JDK 1.1+.
69
   */
70
  private static final long serialVersionUID = 6401253773779951803L;
71
 
72
  /**
73
   * Maps property names (String) to named listeners (PropertyChangeSupport).
74
   * If this is a child instance, this field will be null.
75
   *
76
   * @serial the map of property names to named listener managers
77
   * @since 1.2
78
   */
79
  private Hashtable children;
80
 
81
  /**
82
   * The non-null source object for any generated events.
83
   *
84
   * @serial the event source
85
   */
86
  private final Object source;
87
 
88
  /**
89
   * A field to compare serialization versions - this class uses version 2.
90
   *
91
   * @serial the serialization format
92
   */
93
  private static final int propertyChangeSupportSerializedDataVersion = 2;
94
 
95
  /**
96
   * The list of all registered property listeners. If this instance was
97
   * created by user code, this only holds the global listeners (ie. not tied
98
   * to a name), and may be null. If it was created by this class, as a
99
   * helper for named properties, then this vector will be non-null, and this
100
   * instance appears as a value in the <code>children</code> hashtable of
101
   * another instance, so that the listeners are tied to the key of that
102
   * hashtable entry.
103
   */
104
  private transient Vector listeners;
105
 
106
  /**
107
   * Create a PropertyChangeSupport to work with a specific source bean.
108
   *
109
   * @param source the source bean to use
110
   * @throws NullPointerException if source is null
111
   */
112
  public PropertyChangeSupport(Object source)
113
  {
114
    this.source = source;
115
    if (source == null)
116
      throw new NullPointerException();
117
  }
118
 
119
  /**
120
   * Adds a PropertyChangeListener to the list of global listeners. All
121
   * property change events will be sent to this listener. The listener add
122
   * is not unique: that is, <em>n</em> adds with the same listener will
123
   * result in <em>n</em> events being sent to that listener for every
124
   * property change. Adding a null listener is silently ignored.
125
   * This method will unwrap a PropertyChangeListenerProxy,
126
   * registering the underlying delegate to the named property list.
127
   *
128
   * @param l the listener to add
129
   */
130
  public synchronized void addPropertyChangeListener(PropertyChangeListener l)
131
  {
132
    if (l == null)
133
      return;
134
 
135
    if (l instanceof PropertyChangeListenerProxy)
136
      {
137
        PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l;
138
        addPropertyChangeListener(p.propertyName,
139
                                  (PropertyChangeListener) p.getListener());
140
      }
141
    else
142
      {
143
        if (listeners == null)
144
          listeners = new Vector();
145
        listeners.add(l);
146
      }
147
  }
148
 
149
  /**
150
   * Removes a PropertyChangeListener from the list of global listeners. If
151
   * any specific properties are being listened on, they must be deregistered
152
   * by themselves; this will only remove the general listener to all
153
   * properties. If <code>add()</code> has been called multiple times for a
154
   * particular listener, <code>remove()</code> will have to be called the
155
   * same number of times to deregister it. This method will unwrap a
156
   * PropertyChangeListenerProxy, removing the underlying delegate from the
157
   * named property list.
158
   *
159
   * @param l the listener to remove
160
   */
161
  public synchronized void
162
    removePropertyChangeListener(PropertyChangeListener l)
163
  {
164
    if (l instanceof PropertyChangeListenerProxy)
165
      {
166
        PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l;
167
        removePropertyChangeListener(p.propertyName,
168
                                     (PropertyChangeListener) p.getListener());
169
      }
170
    else if (listeners != null)
171
      {
172
        listeners.remove(l);
173
        if (listeners.isEmpty())
174
          listeners = null;
175
      }
176
  }
177
 
178
  /**
179
   * Returns an array of all registered property change listeners. Those that
180
   * were registered under a name will be wrapped in a
181
   * <code>PropertyChangeListenerProxy</code>, so you must check whether the
182
   * listener is an instance of the proxy class in order to see what name the
183
   * real listener is registered under. If there are no registered listeners,
184
   * this returns an empty array.
185
   *
186
   * @return the array of registered listeners
187
   * @see PropertyChangeListenerProxy
188
   * @since 1.4
189
   */
190
  public synchronized PropertyChangeListener[] getPropertyChangeListeners()
191
  {
192
    ArrayList list = new ArrayList();
193
    if (listeners != null)
194
      list.addAll(listeners);
195
    if (children != null)
196
      {
197
        int i = children.size();
198
        Iterator iter = children.entrySet().iterator();
199
        while (--i >= 0)
200
          {
201
            Entry e = (Entry) iter.next();
202
            String name = (String) e.getKey();
203
            Vector v = ((PropertyChangeSupport) e.getValue()).listeners;
204
            int j = v.size();
205
            while (--j >= 0)
206
              list.add(new PropertyChangeListenerProxy
207
                (name, (PropertyChangeListener) v.get(j)));
208
          }
209
      }
210
    return (PropertyChangeListener[])
211
      list.toArray(new PropertyChangeListener[list.size()]);
212
  }
213
 
214
  /**
215
   * Adds a PropertyChangeListener listening on the specified property. Events
216
   * will be sent to the listener only if the property name matches. The
217
   * listener add is not unique; that is, <em>n</em> adds on a particular
218
   * property for a particular listener will result in <em>n</em> events
219
   * being sent to that listener when that property is changed. The effect is
220
   * cumulative, too; if you are registered to listen to receive events on
221
   * all property changes, and then you register on a particular property,
222
   * you will receive change events for that property twice. Adding a null
223
   * listener is silently ignored. This method will unwrap a
224
   * PropertyChangeListenerProxy, registering the underlying
225
   * delegate to the named property list if the names match, and discarding
226
   * it otherwise.
227
   *
228
   * @param propertyName the name of the property to listen on
229
   * @param l the listener to add
230
   * @throws NullPointerException if propertyName is null
231
   */
232
  public synchronized void addPropertyChangeListener(String propertyName,
233
                                                     PropertyChangeListener l)
234
  {
235
    if (l == null)
236
      return;
237
 
238
    while (l instanceof PropertyChangeListenerProxy)
239
      {
240
        PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l;
241
        if (propertyName == null ? p.propertyName != null
242
            : ! propertyName.equals(p.propertyName))
243
          return;
244
        l = (PropertyChangeListener) p.getListener();
245
      }
246
    PropertyChangeSupport s = null;
247
    if (children == null)
248
      children = new Hashtable();
249
    else
250
      s = (PropertyChangeSupport) children.get(propertyName);
251
    if (s == null)
252
      {
253
        s = new PropertyChangeSupport(source);
254
        s.listeners = new Vector();
255
        children.put(propertyName, s);
256
      }
257
    s.listeners.add(l);
258
  }
259
 
260
  /**
261
   * Removes a PropertyChangeListener from listening to a specific property.
262
   * If <code>add()</code> has been called multiple times for a particular
263
   * listener on a property, <code>remove()</code> will have to be called the
264
   * same number of times to deregister it. This method will unwrap a
265
   * PropertyChangeListenerProxy, removing the underlying delegate from the
266
   * named property list if the names match.
267
   *
268
   * @param propertyName the property to stop listening on
269
   * @param l the listener to remove
270
   * @throws NullPointerException if propertyName is null
271
   */
272
  public synchronized void
273
    removePropertyChangeListener(String propertyName, PropertyChangeListener l)
274
  {
275
    if (children == null)
276
      return;
277
    PropertyChangeSupport s
278
      = (PropertyChangeSupport) children.get(propertyName);
279
    if (s == null)
280
      return;
281
    while (l instanceof PropertyChangeListenerProxy)
282
      {
283
        PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l;
284
        if (propertyName == null ? p.propertyName != null
285
            : ! propertyName.equals(p.propertyName))
286
          return;
287
        l = (PropertyChangeListener) p.getListener();
288
      }
289
    s.listeners.remove(l);
290
    if (s.listeners.isEmpty())
291
      {
292
        children.remove(propertyName);
293
        if (children.isEmpty())
294
          children = null;
295
      }
296
  }
297
 
298
  /**
299
   * Returns an array of all property change listeners registered under the
300
   * given property name. If there are no registered listeners, or
301
   * propertyName is null, this returns an empty array.
302
   *
303
   * @return the array of registered listeners
304
   * @since 1.4
305
   */
306
  public synchronized PropertyChangeListener[]
307
    getPropertyChangeListeners(String propertyName)
308
  {
309
    if (children == null || propertyName == null)
310
      return new PropertyChangeListener[0];
311
    PropertyChangeSupport s
312
      = (PropertyChangeSupport) children.get(propertyName);
313
    if (s == null)
314
      return new PropertyChangeListener[0];
315
    return (PropertyChangeListener[])
316
      s.listeners.toArray(new PropertyChangeListener[s.listeners.size()]);
317
  }
318
 
319
  /**
320
   * Fire a PropertyChangeEvent containing the old and new values of the
321
   * property to all the global listeners, and to all the listeners for the
322
   * specified property name. This does nothing if old and new are non-null
323
   * and equal.
324
   *
325
   * @param propertyName the name of the property that changed
326
   * @param oldVal the old value
327
   * @param newVal the new value
328
   */
329
  public void firePropertyChange(String propertyName,
330
                                 Object oldVal, Object newVal)
331
  {
332
    firePropertyChange(new PropertyChangeEvent(source, propertyName,
333
                                               oldVal, newVal));
334
  }
335
 
336
  /**
337
   * Fire a PropertyChangeEvent containing the old and new values of the
338
   * property to all the global listeners, and to all the listeners for the
339
   * specified property name. This does nothing if old and new are equal.
340
   *
341
   * @param propertyName the name of the property that changed
342
   * @param oldVal the old value
343
   * @param newVal the new value
344
   */
345
  public void firePropertyChange(String propertyName, int oldVal, int newVal)
346
  {
347
    if (oldVal != newVal)
348
      firePropertyChange(new PropertyChangeEvent(source, propertyName,
349
                                                 Integer.valueOf(oldVal),
350
                                                 Integer.valueOf(newVal)));
351
  }
352
 
353
  /**
354
   * Fire a PropertyChangeEvent containing the old and new values of the
355
   * property to all the global listeners, and to all the listeners for the
356
   * specified property name. This does nothing if old and new are equal.
357
   *
358
   * @param propertyName the name of the property that changed
359
   * @param oldVal the old value
360
   * @param newVal the new value
361
   */
362
  public void firePropertyChange(String propertyName,
363
                                 boolean oldVal, boolean newVal)
364
  {
365
    if (oldVal != newVal)
366
      firePropertyChange(new PropertyChangeEvent(source, propertyName,
367
                                                 Boolean.valueOf(oldVal),
368
                                                 Boolean.valueOf(newVal)));
369
  }
370
 
371
  /**
372
   * Fire a PropertyChangeEvent to all the global listeners, and to all the
373
   * listeners for the specified property name. This does nothing if old and
374
   * new values of the event are equal.
375
   *
376
   * @param event the event to fire
377
   * @throws NullPointerException if event is null
378
   */
379
  public void firePropertyChange(PropertyChangeEvent event)
380
  {
381
    if (event.oldValue != null && event.oldValue.equals(event.newValue))
382
      return;
383
    Vector v = listeners; // Be thread-safe.
384
    if (v != null)
385
      {
386
        int i = v.size();
387
        while (--i >= 0)
388
          ((PropertyChangeListener) v.get(i)).propertyChange(event);
389
      }
390
    Hashtable h = children; // Be thread-safe.
391
    if (h != null && event.propertyName != null)
392
      {
393
        PropertyChangeSupport s
394
          = (PropertyChangeSupport) h.get(event.propertyName);
395
        if (s != null)
396
          {
397
            v = s.listeners; // Be thread-safe.
398
            int i = v == null ? 0 : v.size();
399
            while (--i >= 0)
400
              ((PropertyChangeListener) v.get(i)).propertyChange(event);
401
          }
402
      }
403
  }
404
 
405
  /**
406
   * Fire an indexed property change event.  This will only fire
407
   * an event if the old and new values are not equal and not null.
408
   * @param name the name of the property which changed
409
   * @param index the index of the property which changed
410
   * @param oldValue the old value of the property
411
   * @param newValue the new value of the property
412
   * @since 1.5
413
   */
414
  public void fireIndexedPropertyChange(String name, int index,
415
                                        Object oldValue, Object newValue)
416
  {
417
    // Argument checking is done in firePropertyChange(PropertyChangeEvent) .
418
    firePropertyChange(new IndexedPropertyChangeEvent(source, name,
419
                                                      oldValue, newValue,
420
                                                      index));
421
  }
422
 
423
  /**
424
   * Fire an indexed property change event.  This will only fire
425
   * an event if the old and new values are not equal.
426
   * @param name the name of the property which changed
427
   * @param index the index of the property which changed
428
   * @param oldValue the old value of the property
429
   * @param newValue the new value of the property
430
   * @since 1.5
431
   */
432
  public void fireIndexedPropertyChange(String name, int index,
433
                                        int oldValue, int newValue)
434
  {
435
    if (oldValue != newValue)
436
      fireIndexedPropertyChange(name, index, Integer.valueOf(oldValue),
437
                                Integer.valueOf(newValue));
438
  }
439
 
440
  /**
441
   * Fire an indexed property change event.  This will only fire
442
   * an event if the old and new values are not equal.
443
   * @param name the name of the property which changed
444
   * @param index the index of the property which changed
445
   * @param oldValue the old value of the property
446
   * @param newValue the new value of the property
447
   * @since 1.5
448
   */
449
  public void fireIndexedPropertyChange(String name, int index,
450
                                        boolean oldValue, boolean newValue)
451
  {
452
    if (oldValue != newValue)
453
      fireIndexedPropertyChange(name, index, Boolean.valueOf(oldValue),
454
                                Boolean.valueOf(newValue));
455
  }
456
 
457
  /**
458
   * Tell whether the specified property is being listened on or not. This
459
   * will only return <code>true</code> if there are listeners on all
460
   * properties or if there is a listener specifically on this property.
461
   *
462
   * @param propertyName the property that may be listened on
463
   * @return whether the property is being listened on
464
   */
465
  public synchronized boolean hasListeners(String propertyName)
466
  {
467
    return listeners != null || (children != null
468
                                 && children.get(propertyName) != null);
469
  }
470
 
471
  /**
472
   * Saves the state of the object to the stream.
473
   *
474
   * @param s the stream to write to
475
   * @throws IOException if anything goes wrong
476
   * @serialData this writes out a null-terminated list of serializable
477
   *             global property change listeners (the listeners for a named
478
   *             property are written out as the global listeners of the
479
   *             children, when the children hashtable is saved)
480
   */
481
  private synchronized void writeObject(ObjectOutputStream s)
482
    throws IOException
483
  {
484
    s.defaultWriteObject();
485
    if (listeners != null)
486
      {
487
        int i = listeners.size();
488
        while (--i >= 0)
489
          if (listeners.get(i) instanceof Serializable)
490
            s.writeObject(listeners.get(i));
491
      }
492
    s.writeObject(null);
493
  }
494
 
495
  /**
496
   * Reads the object back from stream (deserialization).
497
   *
498
   * XXX Since serialization for 1.1 streams was not documented, this may
499
   * not work if propertyChangeSupportSerializedDataVersion is 1.
500
   *
501
   * @param s the stream to read from
502
   * @throws IOException if reading the stream fails
503
   * @throws ClassNotFoundException if deserialization fails
504
   * @serialData this reads in a null-terminated list of serializable
505
   *             global property change listeners (the listeners for a named
506
   *             property are written out as the global listeners of the
507
   *             children, when the children hashtable is saved)
508
   */
509
  private void readObject(ObjectInputStream s)
510
    throws IOException, ClassNotFoundException
511
  {
512
    s.defaultReadObject();
513
    PropertyChangeListener l = (PropertyChangeListener) s.readObject();
514
    while (l != null)
515
      {
516
        addPropertyChangeListener(l);
517
        l = (PropertyChangeListener) s.readObject();
518
      }
519
    // Sun is not as careful with children as we are, and lets some proxys
520
    // in that can never receive events. So, we clean up anything that got
521
    // serialized, to make sure our invariants hold.
522
    if (children != null)
523
      {
524
        int i = children.size();
525
        Iterator iter = children.entrySet().iterator();
526
        while (--i >= 0)
527
          {
528
            Entry e = (Entry) iter.next();
529
            String name = (String) e.getKey();
530
            PropertyChangeSupport pcs = (PropertyChangeSupport) e.getValue();
531
            if (pcs.listeners == null)
532
              pcs.listeners = new Vector();
533
            if (pcs.children != null)
534
              pcs.listeners.addAll
535
                (Arrays.asList(pcs.getPropertyChangeListeners(name)));
536
            if (pcs.listeners.size() == 0)
537
              iter.remove();
538
            else
539
              pcs.children = null;
540
          }
541
        if (children.size() == 0)
542
          children = null;
543
      }
544
  }
545
} // class PropertyChangeSupport

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.