1 /*
   2  * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package java.awt;
  26 
  27 import java.awt.event.*;
  28 import java.lang.reflect.Array;
  29 import java.util.EventListener;
  30 import java.io.Serializable;
  31 import java.io.ObjectOutputStream;
  32 import java.io.IOException;
  33 import java.util.EventListener;
  34 
  35 
  36 /**
  37  * {@code AWTEventMulticaster} implements efficient and thread-safe multi-cast
  38  * event dispatching for the AWT events defined in the {@code java.awt.event}
  39  * package.
  40  * <p>
  41  * The following example illustrates how to use this class:
  42  *
  43  * <pre><code>
  44  * public myComponent extends Component {
  45  *     ActionListener actionListener = null;
  46  *
  47  *     public synchronized void addActionListener(ActionListener l) {
  48  *         actionListener = AWTEventMulticaster.add(actionListener, l);
  49  *     }
  50  *     public synchronized void removeActionListener(ActionListener l) {
  51  *         actionListener = AWTEventMulticaster.remove(actionListener, l);
  52  *     }
  53  *     public void processEvent(AWTEvent e) {
  54  *         // when event occurs which causes "action" semantic
  55  *         ActionListener listener = actionListener;
  56  *         if (listener != null) {
  57  *             listener.actionPerformed(new ActionEvent());
  58  *         }
  59  *     }
  60  * }
  61  * </code></pre>
  62  * The important point to note is the first argument to the {@code
  63  * add} and {@code remove} methods is the field maintaining the
  64  * listeners. In addition you must assign the result of the {@code add}
  65  * and {@code remove} methods to the field maintaining the listeners.
  66  * <p>
  67  * {@code AWTEventMulticaster} is implemented as a pair of {@code
  68  * EventListeners} that are set at construction time. {@code
  69  * AWTEventMulticaster} is immutable. The {@code add} and {@code
  70  * remove} methods do not alter {@code AWTEventMulticaster} in
  71  * anyway. If necessary, a new {@code AWTEventMulticaster} is
  72  * created. In this way it is safe to add and remove listeners during
  73  * the process of an event dispatching.  However, event listeners
  74  * added during the process of an event dispatch operation are not
  75  * notified of the event currently being dispatched.
  76  * <p>
  77  * All of the {@code add} methods allow {@code null} arguments. If the
  78  * first argument is {@code null}, the second argument is returned. If
  79  * the first argument is not {@code null} and the second argument is
  80  * {@code null}, the first argument is returned. If both arguments are
  81  * {@code non-null}, a new {@code AWTEventMulticaster} is created using
  82  * the two arguments and returned.
  83  * <p>
  84  * For the {@code remove} methods that take two arguments, the following is
  85  * returned:
  86  * <ul>
  87  *   <li>{@code null}, if the first argument is {@code null}, or
  88  *       the arguments are equal, by way of {@code ==}.
  89  *   <li>the first argument, if the first argument is not an instance of
  90  *       {@code AWTEventMulticaster}.
  91  *   <li>result of invoking {@code remove(EventListener)} on the
  92  *       first argument, supplying the second argument to the
  93  *       {@code remove(EventListener)} method.
  94  * </ul>
  95  * <p>Swing makes use of
  96  * {@link javax.swing.event.EventListenerList EventListenerList} for
  97  * similar logic. Refer to it for details.
  98  *
  99  * @see javax.swing.event.EventListenerList
 100  *
 101  * @author      John Rose
 102  * @author      Amy Fowler
 103  * @since       1.1
 104  */
 105 
 106 public class AWTEventMulticaster implements
 107     ComponentListener, ContainerListener, FocusListener, KeyListener,
 108     MouseListener, MouseMotionListener, WindowListener, WindowFocusListener,
 109     WindowStateListener, ActionListener, ItemListener, AdjustmentListener,
 110     TextListener, InputMethodListener, HierarchyListener,
 111     HierarchyBoundsListener, MouseWheelListener {
 112 
 113     /**
 114      * A variable in the event chain (listener-a)
 115      */
 116     protected final EventListener a;
 117 
 118     /**
 119      * A variable in the event chain (listener-b)
 120      */
 121     protected final EventListener b;
 122 
 123     /**
 124      * Creates an event multicaster instance which chains listener-a
 125      * with listener-b. Input parameters <code>a</code> and <code>b</code>
 126      * should not be <code>null</code>, though implementations may vary in
 127      * choosing whether or not to throw <code>NullPointerException</code>
 128      * in that case.
 129      * @param a listener-a
 130      * @param b listener-b
 131      */
 132     protected AWTEventMulticaster(EventListener a, EventListener b) {
 133         this.a = a; this.b = b;
 134     }
 135 
 136     /**
 137      * Removes a listener from this multicaster.
 138      * <p>
 139      * The returned multicaster contains all the listeners in this
 140      * multicaster with the exception of all occurrences of {@code oldl}.
 141      * If the resulting multicaster contains only one regular listener
 142      * the regular listener may be returned.  If the resulting multicaster
 143      * is empty, then {@code null} may be returned instead.
 144      * <p>
 145      * No exception is thrown if {@code oldl} is {@code null}.
 146      *
 147      * @param oldl the listener to be removed
 148      * @return resulting listener
 149      */
 150     protected EventListener remove(EventListener oldl) {
 151         if (oldl == a)  return b;
 152         if (oldl == b)  return a;
 153         EventListener a2 = removeInternal(a, oldl);
 154         EventListener b2 = removeInternal(b, oldl);
 155         if (a2 == a && b2 == b) {
 156             return this;        // it's not here
 157         }
 158         return addInternal(a2, b2);
 159     }
 160 
 161     /**
 162      * Handles the componentResized event by invoking the
 163      * componentResized methods on listener-a and listener-b.
 164      * @param e the component event
 165      */
 166     public void componentResized(ComponentEvent e) {
 167         ((ComponentListener)a).componentResized(e);
 168         ((ComponentListener)b).componentResized(e);
 169     }
 170 
 171     /**
 172      * Handles the componentMoved event by invoking the
 173      * componentMoved methods on listener-a and listener-b.
 174      * @param e the component event
 175      */
 176     public void componentMoved(ComponentEvent e) {
 177         ((ComponentListener)a).componentMoved(e);
 178         ((ComponentListener)b).componentMoved(e);
 179     }
 180 
 181     /**
 182      * Handles the componentShown event by invoking the
 183      * componentShown methods on listener-a and listener-b.
 184      * @param e the component event
 185      */
 186     public void componentShown(ComponentEvent e) {
 187         ((ComponentListener)a).componentShown(e);
 188         ((ComponentListener)b).componentShown(e);
 189     }
 190 
 191     /**
 192      * Handles the componentHidden event by invoking the
 193      * componentHidden methods on listener-a and listener-b.
 194      * @param e the component event
 195      */
 196     public void componentHidden(ComponentEvent e) {
 197         ((ComponentListener)a).componentHidden(e);
 198         ((ComponentListener)b).componentHidden(e);
 199     }
 200 
 201     /**
 202      * Handles the componentAdded container event by invoking the
 203      * componentAdded methods on listener-a and listener-b.
 204      * @param e the component event
 205      */
 206     public void componentAdded(ContainerEvent e) {
 207         ((ContainerListener)a).componentAdded(e);
 208         ((ContainerListener)b).componentAdded(e);
 209     }
 210 
 211     /**
 212      * Handles the componentRemoved container event by invoking the
 213      * componentRemoved methods on listener-a and listener-b.
 214      * @param e the component event
 215      */
 216     public void componentRemoved(ContainerEvent e) {
 217         ((ContainerListener)a).componentRemoved(e);
 218         ((ContainerListener)b).componentRemoved(e);
 219     }
 220 
 221     /**
 222      * Handles the focusGained event by invoking the
 223      * focusGained methods on listener-a and listener-b.
 224      * @param e the focus event
 225      */
 226     public void focusGained(FocusEvent e) {
 227         ((FocusListener)a).focusGained(e);
 228         ((FocusListener)b).focusGained(e);
 229     }
 230 
 231     /**
 232      * Handles the focusLost event by invoking the
 233      * focusLost methods on listener-a and listener-b.
 234      * @param e the focus event
 235      */
 236     public void focusLost(FocusEvent e) {
 237         ((FocusListener)a).focusLost(e);
 238         ((FocusListener)b).focusLost(e);
 239     }
 240 
 241     /**
 242      * Handles the keyTyped event by invoking the
 243      * keyTyped methods on listener-a and listener-b.
 244      * @param e the key event
 245      */
 246     public void keyTyped(KeyEvent e) {
 247         ((KeyListener)a).keyTyped(e);
 248         ((KeyListener)b).keyTyped(e);
 249     }
 250 
 251     /**
 252      * Handles the keyPressed event by invoking the
 253      * keyPressed methods on listener-a and listener-b.
 254      * @param e the key event
 255      */
 256     public void keyPressed(KeyEvent e) {
 257         ((KeyListener)a).keyPressed(e);
 258         ((KeyListener)b).keyPressed(e);
 259     }
 260 
 261     /**
 262      * Handles the keyReleased event by invoking the
 263      * keyReleased methods on listener-a and listener-b.
 264      * @param e the key event
 265      */
 266     public void keyReleased(KeyEvent e) {
 267         ((KeyListener)a).keyReleased(e);
 268         ((KeyListener)b).keyReleased(e);
 269     }
 270 
 271     /**
 272      * Handles the mouseClicked event by invoking the
 273      * mouseClicked methods on listener-a and listener-b.
 274      * @param e the mouse event
 275      */
 276     public void mouseClicked(MouseEvent e) {
 277         ((MouseListener)a).mouseClicked(e);
 278         ((MouseListener)b).mouseClicked(e);
 279     }
 280 
 281     /**
 282      * Handles the mousePressed event by invoking the
 283      * mousePressed methods on listener-a and listener-b.
 284      * @param e the mouse event
 285      */
 286     public void mousePressed(MouseEvent e) {
 287         ((MouseListener)a).mousePressed(e);
 288         ((MouseListener)b).mousePressed(e);
 289     }
 290 
 291     /**
 292      * Handles the mouseReleased event by invoking the
 293      * mouseReleased methods on listener-a and listener-b.
 294      * @param e the mouse event
 295      */
 296     public void mouseReleased(MouseEvent e) {
 297         ((MouseListener)a).mouseReleased(e);
 298         ((MouseListener)b).mouseReleased(e);
 299     }
 300 
 301     /**
 302      * Handles the mouseEntered event by invoking the
 303      * mouseEntered methods on listener-a and listener-b.
 304      * @param e the mouse event
 305      */
 306     public void mouseEntered(MouseEvent e) {
 307         ((MouseListener)a).mouseEntered(e);
 308         ((MouseListener)b).mouseEntered(e);
 309     }
 310 
 311     /**
 312      * Handles the mouseExited event by invoking the
 313      * mouseExited methods on listener-a and listener-b.
 314      * @param e the mouse event
 315      */
 316     public void mouseExited(MouseEvent e) {
 317         ((MouseListener)a).mouseExited(e);
 318         ((MouseListener)b).mouseExited(e);
 319     }
 320 
 321     /**
 322      * Handles the mouseDragged event by invoking the
 323      * mouseDragged methods on listener-a and listener-b.
 324      * @param e the mouse event
 325      */
 326     public void mouseDragged(MouseEvent e) {
 327         ((MouseMotionListener)a).mouseDragged(e);
 328         ((MouseMotionListener)b).mouseDragged(e);
 329     }
 330 
 331     /**
 332      * Handles the mouseMoved event by invoking the
 333      * mouseMoved methods on listener-a and listener-b.
 334      * @param e the mouse event
 335      */
 336     public void mouseMoved(MouseEvent e) {
 337         ((MouseMotionListener)a).mouseMoved(e);
 338         ((MouseMotionListener)b).mouseMoved(e);
 339     }
 340 
 341     /**
 342      * Handles the windowOpened event by invoking the
 343      * windowOpened methods on listener-a and listener-b.
 344      * @param e the window event
 345      */
 346     public void windowOpened(WindowEvent e) {
 347         ((WindowListener)a).windowOpened(e);
 348         ((WindowListener)b).windowOpened(e);
 349     }
 350 
 351     /**
 352      * Handles the windowClosing event by invoking the
 353      * windowClosing methods on listener-a and listener-b.
 354      * @param e the window event
 355      */
 356     public void windowClosing(WindowEvent e) {
 357         ((WindowListener)a).windowClosing(e);
 358         ((WindowListener)b).windowClosing(e);
 359     }
 360 
 361     /**
 362      * Handles the windowClosed event by invoking the
 363      * windowClosed methods on listener-a and listener-b.
 364      * @param e the window event
 365      */
 366     public void windowClosed(WindowEvent e) {
 367         ((WindowListener)a).windowClosed(e);
 368         ((WindowListener)b).windowClosed(e);
 369     }
 370 
 371     /**
 372      * Handles the windowIconified event by invoking the
 373      * windowIconified methods on listener-a and listener-b.
 374      * @param e the window event
 375      */
 376     public void windowIconified(WindowEvent e) {
 377         ((WindowListener)a).windowIconified(e);
 378         ((WindowListener)b).windowIconified(e);
 379     }
 380 
 381     /**
 382      * Handles the windowDeiconified event by invoking the
 383      * windowDeiconified methods on listener-a and listener-b.
 384      * @param e the window event
 385      */
 386     public void windowDeiconified(WindowEvent e) {
 387         ((WindowListener)a).windowDeiconified(e);
 388         ((WindowListener)b).windowDeiconified(e);
 389     }
 390 
 391     /**
 392      * Handles the windowActivated event by invoking the
 393      * windowActivated methods on listener-a and listener-b.
 394      * @param e the window event
 395      */
 396     public void windowActivated(WindowEvent e) {
 397         ((WindowListener)a).windowActivated(e);
 398         ((WindowListener)b).windowActivated(e);
 399     }
 400 
 401     /**
 402      * Handles the windowDeactivated event by invoking the
 403      * windowDeactivated methods on listener-a and listener-b.
 404      * @param e the window event
 405      */
 406     public void windowDeactivated(WindowEvent e) {
 407         ((WindowListener)a).windowDeactivated(e);
 408         ((WindowListener)b).windowDeactivated(e);
 409     }
 410 
 411     /**
 412      * Handles the windowStateChanged event by invoking the
 413      * windowStateChanged methods on listener-a and listener-b.
 414      * @param e the window event
 415      * @since 1.4
 416      */
 417     public void windowStateChanged(WindowEvent e) {
 418         ((WindowStateListener)a).windowStateChanged(e);
 419         ((WindowStateListener)b).windowStateChanged(e);
 420     }
 421 
 422 
 423     /**
 424      * Handles the windowGainedFocus event by invoking the windowGainedFocus
 425      * methods on listener-a and listener-b.
 426      * @param e the window event
 427      * @since 1.4
 428      */
 429     public void windowGainedFocus(WindowEvent e) {
 430         ((WindowFocusListener)a).windowGainedFocus(e);
 431         ((WindowFocusListener)b).windowGainedFocus(e);
 432     }
 433 
 434     /**
 435      * Handles the windowLostFocus event by invoking the windowLostFocus
 436      * methods on listener-a and listener-b.
 437      * @param e the window event
 438      * @since 1.4
 439      */
 440     public void windowLostFocus(WindowEvent e) {
 441         ((WindowFocusListener)a).windowLostFocus(e);
 442         ((WindowFocusListener)b).windowLostFocus(e);
 443     }
 444 
 445     /**
 446      * Handles the actionPerformed event by invoking the
 447      * actionPerformed methods on listener-a and listener-b.
 448      * @param e the action event
 449      */
 450     public void actionPerformed(ActionEvent e) {
 451         ((ActionListener)a).actionPerformed(e);
 452         ((ActionListener)b).actionPerformed(e);
 453     }
 454 
 455     /**
 456      * Handles the itemStateChanged event by invoking the
 457      * itemStateChanged methods on listener-a and listener-b.
 458      * @param e the item event
 459      */
 460     public void itemStateChanged(ItemEvent e) {
 461         ((ItemListener)a).itemStateChanged(e);
 462         ((ItemListener)b).itemStateChanged(e);
 463     }
 464 
 465     /**
 466      * Handles the adjustmentValueChanged event by invoking the
 467      * adjustmentValueChanged methods on listener-a and listener-b.
 468      * @param e the adjustment event
 469      */
 470     public void adjustmentValueChanged(AdjustmentEvent e) {
 471         ((AdjustmentListener)a).adjustmentValueChanged(e);
 472         ((AdjustmentListener)b).adjustmentValueChanged(e);
 473     }
 474     public void textValueChanged(TextEvent e) {
 475         ((TextListener)a).textValueChanged(e);
 476         ((TextListener)b).textValueChanged(e);
 477     }
 478 
 479     /**
 480      * Handles the inputMethodTextChanged event by invoking the
 481      * inputMethodTextChanged methods on listener-a and listener-b.
 482      * @param e the item event
 483      */
 484     public void inputMethodTextChanged(InputMethodEvent e) {
 485        ((InputMethodListener)a).inputMethodTextChanged(e);
 486        ((InputMethodListener)b).inputMethodTextChanged(e);
 487     }
 488 
 489     /**
 490      * Handles the caretPositionChanged event by invoking the
 491      * caretPositionChanged methods on listener-a and listener-b.
 492      * @param e the item event
 493      */
 494     public void caretPositionChanged(InputMethodEvent e) {
 495        ((InputMethodListener)a).caretPositionChanged(e);
 496        ((InputMethodListener)b).caretPositionChanged(e);
 497     }
 498 
 499     /**
 500      * Handles the hierarchyChanged event by invoking the
 501      * hierarchyChanged methods on listener-a and listener-b.
 502      * @param e the item event
 503      * @since 1.3
 504      */
 505     public void hierarchyChanged(HierarchyEvent e) {
 506         ((HierarchyListener)a).hierarchyChanged(e);
 507         ((HierarchyListener)b).hierarchyChanged(e);
 508     }
 509 
 510     /**
 511      * Handles the ancestorMoved event by invoking the
 512      * ancestorMoved methods on listener-a and listener-b.
 513      * @param e the item event
 514      * @since 1.3
 515      */
 516     public void ancestorMoved(HierarchyEvent e) {
 517         ((HierarchyBoundsListener)a).ancestorMoved(e);
 518         ((HierarchyBoundsListener)b).ancestorMoved(e);
 519     }
 520 
 521     /**
 522      * Handles the ancestorResized event by invoking the
 523      * ancestorResized methods on listener-a and listener-b.
 524      * @param e the item event
 525      * @since 1.3
 526      */
 527     public void ancestorResized(HierarchyEvent e) {
 528         ((HierarchyBoundsListener)a).ancestorResized(e);
 529         ((HierarchyBoundsListener)b).ancestorResized(e);
 530     }
 531 
 532     /**
 533      * Handles the mouseWheelMoved event by invoking the
 534      * mouseWheelMoved methods on listener-a and listener-b.
 535      * @param e the mouse event
 536      * @since 1.4
 537      */
 538     public void mouseWheelMoved(MouseWheelEvent e) {
 539         ((MouseWheelListener)a).mouseWheelMoved(e);
 540         ((MouseWheelListener)b).mouseWheelMoved(e);
 541     }
 542 
 543     /**
 544      * Adds component-listener-a with component-listener-b and
 545      * returns the resulting multicast listener.
 546      * @param a component-listener-a
 547      * @param b component-listener-b
 548      * @return the resulting listener
 549      */
 550     public static ComponentListener add(ComponentListener a, ComponentListener b) {
 551         return (ComponentListener)addInternal(a, b);
 552     }
 553 
 554     /**
 555      * Adds container-listener-a with container-listener-b and
 556      * returns the resulting multicast listener.
 557      * @param a container-listener-a
 558      * @param b container-listener-b
 559      * @return the resulting listener
 560      */
 561     public static ContainerListener add(ContainerListener a, ContainerListener b) {
 562         return (ContainerListener)addInternal(a, b);
 563     }
 564 
 565     /**
 566      * Adds focus-listener-a with focus-listener-b and
 567      * returns the resulting multicast listener.
 568      * @param a focus-listener-a
 569      * @param b focus-listener-b
 570      * @return the resulting listener
 571      */
 572     public static FocusListener add(FocusListener a, FocusListener b) {
 573         return (FocusListener)addInternal(a, b);
 574     }
 575 
 576     /**
 577      * Adds key-listener-a with key-listener-b and
 578      * returns the resulting multicast listener.
 579      * @param a key-listener-a
 580      * @param b key-listener-b
 581      * @return the resulting listener
 582      */
 583     public static KeyListener add(KeyListener a, KeyListener b) {
 584         return (KeyListener)addInternal(a, b);
 585     }
 586 
 587     /**
 588      * Adds mouse-listener-a with mouse-listener-b and
 589      * returns the resulting multicast listener.
 590      * @param a mouse-listener-a
 591      * @param b mouse-listener-b
 592      * @return the resulting listener
 593      */
 594     public static MouseListener add(MouseListener a, MouseListener b) {
 595         return (MouseListener)addInternal(a, b);
 596     }
 597 
 598     /**
 599      * Adds mouse-motion-listener-a with mouse-motion-listener-b and
 600      * returns the resulting multicast listener.
 601      * @param a mouse-motion-listener-a
 602      * @param b mouse-motion-listener-b
 603      * @return the resulting listener
 604      */
 605     public static MouseMotionListener add(MouseMotionListener a, MouseMotionListener b) {
 606         return (MouseMotionListener)addInternal(a, b);
 607     }
 608 
 609     /**
 610      * Adds window-listener-a with window-listener-b and
 611      * returns the resulting multicast listener.
 612      * @param a window-listener-a
 613      * @param b window-listener-b
 614      * @return the resulting listener
 615      */
 616     public static WindowListener add(WindowListener a, WindowListener b) {
 617         return (WindowListener)addInternal(a, b);
 618     }
 619 
 620     /**
 621      * Adds window-state-listener-a with window-state-listener-b
 622      * and returns the resulting multicast listener.
 623      * @param a window-state-listener-a
 624      * @param b window-state-listener-b
 625      * @return the resulting listener
 626      * @since 1.4
 627      */
 628     @SuppressWarnings("overloads")
 629     public static WindowStateListener add(WindowStateListener a,
 630                                           WindowStateListener b) {
 631         return (WindowStateListener)addInternal(a, b);
 632     }
 633 
 634     /**
 635      * Adds window-focus-listener-a with window-focus-listener-b
 636      * and returns the resulting multicast listener.
 637      * @param a window-focus-listener-a
 638      * @param b window-focus-listener-b
 639      * @return the resulting listener
 640      * @since 1.4
 641      */
 642     public static WindowFocusListener add(WindowFocusListener a,
 643                                           WindowFocusListener b) {
 644         return (WindowFocusListener)addInternal(a, b);
 645     }
 646 
 647     /**
 648      * Adds action-listener-a with action-listener-b and
 649      * returns the resulting multicast listener.
 650      * @param a action-listener-a
 651      * @param b action-listener-b
 652      * @return the resulting listener
 653      */
 654     @SuppressWarnings("overloads")
 655     public static ActionListener add(ActionListener a, ActionListener b) {
 656         return (ActionListener)addInternal(a, b);
 657     }
 658 
 659     /**
 660      * Adds item-listener-a with item-listener-b and
 661      * returns the resulting multicast listener.
 662      * @param a item-listener-a
 663      * @param b item-listener-b
 664      * @return the resulting listener
 665      */
 666     @SuppressWarnings("overloads")
 667     public static ItemListener add(ItemListener a, ItemListener b) {
 668         return (ItemListener)addInternal(a, b);
 669     }
 670 
 671     /**
 672      * Adds adjustment-listener-a with adjustment-listener-b and
 673      * returns the resulting multicast listener.
 674      * @param a adjustment-listener-a
 675      * @param b adjustment-listener-b
 676      * @return the resulting listener
 677      */
 678     @SuppressWarnings("overloads")
 679     public static AdjustmentListener add(AdjustmentListener a, AdjustmentListener b) {
 680         return (AdjustmentListener)addInternal(a, b);
 681     }
 682 
 683     /**
 684      * Adds text-listener-a with text-listener-b and
 685      * returns the resulting multicast listener.
 686      *
 687      * @param  a text-listener-a
 688      * @param  b text-listener-b
 689      * @return the resulting listener
 690      */
 691     @SuppressWarnings("overloads")
 692     public static TextListener add(TextListener a, TextListener b) {
 693         return (TextListener)addInternal(a, b);
 694     }
 695 
 696     /**
 697      * Adds input-method-listener-a with input-method-listener-b and
 698      * returns the resulting multicast listener.
 699      * @param a input-method-listener-a
 700      * @param b input-method-listener-b
 701      * @return the resulting listener
 702      */
 703      public static InputMethodListener add(InputMethodListener a, InputMethodListener b) {
 704         return (InputMethodListener)addInternal(a, b);
 705      }
 706 
 707     /**
 708      * Adds hierarchy-listener-a with hierarchy-listener-b and
 709      * returns the resulting multicast listener.
 710      * @param a hierarchy-listener-a
 711      * @param b hierarchy-listener-b
 712      * @return the resulting listener
 713      * @since 1.3
 714      */
 715     @SuppressWarnings("overloads")
 716      public static HierarchyListener add(HierarchyListener a, HierarchyListener b) {
 717         return (HierarchyListener)addInternal(a, b);
 718      }
 719 
 720     /**
 721      * Adds hierarchy-bounds-listener-a with hierarchy-bounds-listener-b and
 722      * returns the resulting multicast listener.
 723      * @param a hierarchy-bounds-listener-a
 724      * @param b hierarchy-bounds-listener-b
 725      * @return the resulting listener
 726      * @since 1.3
 727      */
 728      public static HierarchyBoundsListener add(HierarchyBoundsListener a, HierarchyBoundsListener b) {
 729         return (HierarchyBoundsListener)addInternal(a, b);
 730      }
 731 
 732     /**
 733      * Adds mouse-wheel-listener-a with mouse-wheel-listener-b and
 734      * returns the resulting multicast listener.
 735      * @param a mouse-wheel-listener-a
 736      * @param b mouse-wheel-listener-b
 737      * @return the resulting listener
 738      * @since 1.4
 739      */
 740     @SuppressWarnings("overloads")
 741     public static MouseWheelListener add(MouseWheelListener a,
 742                                          MouseWheelListener b) {
 743         return (MouseWheelListener)addInternal(a, b);
 744     }
 745 
 746     /**
 747      * Removes the old component-listener from component-listener-l and
 748      * returns the resulting multicast listener.
 749      * @param l component-listener-l
 750      * @param oldl the component-listener being removed
 751      * @return the resulting listener
 752      */
 753     public static ComponentListener remove(ComponentListener l, ComponentListener oldl) {
 754         return (ComponentListener) removeInternal(l, oldl);
 755     }
 756 
 757     /**
 758      * Removes the old container-listener from container-listener-l and
 759      * returns the resulting multicast listener.
 760      * @param l container-listener-l
 761      * @param oldl the container-listener being removed
 762      * @return the resulting listener
 763      */
 764     public static ContainerListener remove(ContainerListener l, ContainerListener oldl) {
 765         return (ContainerListener) removeInternal(l, oldl);
 766     }
 767 
 768     /**
 769      * Removes the old focus-listener from focus-listener-l and
 770      * returns the resulting multicast listener.
 771      * @param l focus-listener-l
 772      * @param oldl the focus-listener being removed
 773      * @return the resulting listener
 774      */
 775     public static FocusListener remove(FocusListener l, FocusListener oldl) {
 776         return (FocusListener) removeInternal(l, oldl);
 777     }
 778 
 779     /**
 780      * Removes the old key-listener from key-listener-l and
 781      * returns the resulting multicast listener.
 782      * @param l key-listener-l
 783      * @param oldl the key-listener being removed
 784      * @return the resulting listener
 785      */
 786     public static KeyListener remove(KeyListener l, KeyListener oldl) {
 787         return (KeyListener) removeInternal(l, oldl);
 788     }
 789 
 790     /**
 791      * Removes the old mouse-listener from mouse-listener-l and
 792      * returns the resulting multicast listener.
 793      * @param l mouse-listener-l
 794      * @param oldl the mouse-listener being removed
 795      * @return the resulting listener
 796      */
 797     public static MouseListener remove(MouseListener l, MouseListener oldl) {
 798         return (MouseListener) removeInternal(l, oldl);
 799     }
 800 
 801     /**
 802      * Removes the old mouse-motion-listener from mouse-motion-listener-l
 803      * and returns the resulting multicast listener.
 804      * @param l mouse-motion-listener-l
 805      * @param oldl the mouse-motion-listener being removed
 806      * @return the resulting listener
 807      */
 808     public static MouseMotionListener remove(MouseMotionListener l, MouseMotionListener oldl) {
 809         return (MouseMotionListener) removeInternal(l, oldl);
 810     }
 811 
 812     /**
 813      * Removes the old window-listener from window-listener-l and
 814      * returns the resulting multicast listener.
 815      * @param l window-listener-l
 816      * @param oldl the window-listener being removed
 817      * @return the resulting listener
 818      */
 819     public static WindowListener remove(WindowListener l, WindowListener oldl) {
 820         return (WindowListener) removeInternal(l, oldl);
 821     }
 822 
 823     /**
 824      * Removes the old window-state-listener from window-state-listener-l
 825      * and returns the resulting multicast listener.
 826      * @param l window-state-listener-l
 827      * @param oldl the window-state-listener being removed
 828      * @return the resulting listener
 829      * @since 1.4
 830      */
 831     @SuppressWarnings("overloads")
 832     public static WindowStateListener remove(WindowStateListener l,
 833                                              WindowStateListener oldl) {
 834         return (WindowStateListener) removeInternal(l, oldl);
 835     }
 836 
 837     /**
 838      * Removes the old window-focus-listener from window-focus-listener-l
 839      * and returns the resulting multicast listener.
 840      * @param l window-focus-listener-l
 841      * @param oldl the window-focus-listener being removed
 842      * @return the resulting listener
 843      * @since 1.4
 844      */
 845     public static WindowFocusListener remove(WindowFocusListener l,
 846                                              WindowFocusListener oldl) {
 847         return (WindowFocusListener) removeInternal(l, oldl);
 848     }
 849 
 850     /**
 851      * Removes the old action-listener from action-listener-l and
 852      * returns the resulting multicast listener.
 853      * @param l action-listener-l
 854      * @param oldl the action-listener being removed
 855      * @return the resulting listener
 856      */
 857     @SuppressWarnings("overloads")
 858     public static ActionListener remove(ActionListener l, ActionListener oldl) {
 859         return (ActionListener) removeInternal(l, oldl);
 860     }
 861 
 862     /**
 863      * Removes the old item-listener from item-listener-l and
 864      * returns the resulting multicast listener.
 865      * @param l item-listener-l
 866      * @param oldl the item-listener being removed
 867      * @return the resulting listener
 868      */
 869     @SuppressWarnings("overloads")
 870     public static ItemListener remove(ItemListener l, ItemListener oldl) {
 871         return (ItemListener) removeInternal(l, oldl);
 872     }
 873 
 874     /**
 875      * Removes the old adjustment-listener from adjustment-listener-l and
 876      * returns the resulting multicast listener.
 877      * @param l adjustment-listener-l
 878      * @param oldl the adjustment-listener being removed
 879      * @return the resulting listener
 880      */
 881     @SuppressWarnings("overloads")
 882     public static AdjustmentListener remove(AdjustmentListener l, AdjustmentListener oldl) {
 883         return (AdjustmentListener) removeInternal(l, oldl);
 884     }
 885 
 886     /**
 887      * Removes the old text-listener from text-listener-l and
 888      * returns the resulting multicast listener.
 889      *
 890      * @param  l text-listener-l
 891      * @param  oldl the text-listener being removed
 892      * @return the resulting listener
 893      */
 894     @SuppressWarnings("overloads")
 895     public static TextListener remove(TextListener l, TextListener oldl) {
 896         return (TextListener) removeInternal(l, oldl);
 897     }
 898 
 899     /**
 900      * Removes the old input-method-listener from input-method-listener-l and
 901      * returns the resulting multicast listener.
 902      * @param l input-method-listener-l
 903      * @param oldl the input-method-listener being removed
 904      * @return the resulting listener
 905      */
 906     public static InputMethodListener remove(InputMethodListener l, InputMethodListener oldl) {
 907         return (InputMethodListener) removeInternal(l, oldl);
 908     }
 909 
 910     /**
 911      * Removes the old hierarchy-listener from hierarchy-listener-l and
 912      * returns the resulting multicast listener.
 913      * @param l hierarchy-listener-l
 914      * @param oldl the hierarchy-listener being removed
 915      * @return the resulting listener
 916      * @since 1.3
 917      */
 918     @SuppressWarnings("overloads")
 919     public static HierarchyListener remove(HierarchyListener l, HierarchyListener oldl) {
 920         return (HierarchyListener) removeInternal(l, oldl);
 921     }
 922 
 923     /**
 924      * Removes the old hierarchy-bounds-listener from
 925      * hierarchy-bounds-listener-l and returns the resulting multicast
 926      * listener.
 927      * @param l hierarchy-bounds-listener-l
 928      * @param oldl the hierarchy-bounds-listener being removed
 929      * @return the resulting listener
 930      * @since 1.3
 931      */
 932     public static HierarchyBoundsListener remove(HierarchyBoundsListener l, HierarchyBoundsListener oldl) {
 933         return (HierarchyBoundsListener) removeInternal(l, oldl);
 934     }
 935 
 936     /**
 937      * Removes the old mouse-wheel-listener from mouse-wheel-listener-l
 938      * and returns the resulting multicast listener.
 939      * @param l mouse-wheel-listener-l
 940      * @param oldl the mouse-wheel-listener being removed
 941      * @return the resulting listener
 942      * @since 1.4
 943      */
 944     @SuppressWarnings("overloads")
 945     public static MouseWheelListener remove(MouseWheelListener l,
 946                                             MouseWheelListener oldl) {
 947       return (MouseWheelListener) removeInternal(l, oldl);
 948     }
 949 
 950     /**
 951      * Returns the resulting multicast listener from adding listener-a
 952      * and listener-b together.
 953      * If listener-a is null, it returns listener-b;
 954      * If listener-b is null, it returns listener-a
 955      * If neither are null, then it creates and returns
 956      * a new AWTEventMulticaster instance which chains a with b.
 957      * @param a event listener-a
 958      * @param b event listener-b
 959      * @return the resulting listener
 960      */
 961     protected static EventListener addInternal(EventListener a, EventListener b) {
 962         if (a == null)  return b;
 963         if (b == null)  return a;
 964         return new AWTEventMulticaster(a, b);
 965     }
 966 
 967     /**
 968      * Returns the resulting multicast listener after removing the
 969      * old listener from listener-l.
 970      * If listener-l equals the old listener OR listener-l is null,
 971      * returns null.
 972      * Else if listener-l is an instance of AWTEventMulticaster,
 973      * then it removes the old listener from it.
 974      * Else, returns listener l.
 975      * @param l the listener being removed from
 976      * @param oldl the listener being removed
 977      * @return the resulting listener
 978      */
 979     protected static EventListener removeInternal(EventListener l, EventListener oldl) {
 980         if (l == oldl || l == null) {
 981             return null;
 982         } else if (l instanceof AWTEventMulticaster) {
 983             return ((AWTEventMulticaster)l).remove(oldl);
 984         } else {
 985             return l;           // it's not here
 986         }
 987     }
 988 
 989 
 990    /**
 991     * Serialization support. Saves all Serializable listeners
 992     * to a serialization stream.
 993     *
 994     * @param  s the stream to save to
 995     * @param  k a prefix stream to put before each serializable listener
 996     * @throws IOException if serialization fails
 997     */
 998     protected void saveInternal(ObjectOutputStream s, String k) throws IOException {
 999         if (a instanceof AWTEventMulticaster) {
1000             ((AWTEventMulticaster)a).saveInternal(s, k);
1001         }
1002         else if (a instanceof Serializable) {
1003             s.writeObject(k);
1004             s.writeObject(a);
1005         }
1006 
1007         if (b instanceof AWTEventMulticaster) {
1008             ((AWTEventMulticaster)b).saveInternal(s, k);
1009         }
1010         else if (b instanceof Serializable) {
1011             s.writeObject(k);
1012             s.writeObject(b);
1013         }
1014     }
1015 
1016    /**
1017     * Saves a Serializable listener chain to a serialization stream.
1018     *
1019     * @param  s the stream to save to
1020     * @param  k a prefix stream to put before each serializable listener
1021     * @param  l the listener chain to save
1022     * @throws IOException if serialization fails
1023     */
1024     protected static void save(ObjectOutputStream s, String k, EventListener l) throws IOException {
1025       if (l == null) {
1026           return;
1027       }
1028       else if (l instanceof AWTEventMulticaster) {
1029           ((AWTEventMulticaster)l).saveInternal(s, k);
1030       }
1031       else if (l instanceof Serializable) {
1032            s.writeObject(k);
1033            s.writeObject(l);
1034       }
1035     }
1036 
1037     /*
1038      * Recursive method which returns a count of the number of listeners in
1039      * EventListener, handling the (common) case of l actually being an
1040      * AWTEventMulticaster.  Additionally, only listeners of type listenerType
1041      * are counted.  Method modified to fix bug 4513402.  -bchristi
1042      */
1043     private static int getListenerCount(EventListener l, Class<?> listenerType) {
1044         if (l instanceof AWTEventMulticaster) {
1045             AWTEventMulticaster mc = (AWTEventMulticaster)l;
1046             return getListenerCount(mc.a, listenerType) +
1047              getListenerCount(mc.b, listenerType);
1048         }
1049         else {
1050             // Only count listeners of correct type
1051             return listenerType.isInstance(l) ? 1 : 0;
1052         }
1053     }
1054 
1055     /*
1056      * Recursive method which populates EventListener array a with EventListeners
1057      * from l.  l is usually an AWTEventMulticaster.  Bug 4513402 revealed that
1058      * if l differed in type from the element type of a, an ArrayStoreException
1059      * would occur.  Now l is only inserted into a if it's of the appropriate
1060      * type.  -bchristi
1061      */
1062     private static int populateListenerArray(EventListener[] a, EventListener l, int index) {
1063         if (l instanceof AWTEventMulticaster) {
1064             AWTEventMulticaster mc = (AWTEventMulticaster)l;
1065             int lhs = populateListenerArray(a, mc.a, index);
1066             return populateListenerArray(a, mc.b, lhs);
1067         }
1068         else if (a.getClass().getComponentType().isInstance(l)) {
1069             a[index] = l;
1070             return index + 1;
1071         }
1072         // Skip nulls, instances of wrong class
1073         else {
1074             return index;
1075         }
1076     }
1077 
1078     /**
1079      * Returns an array of all the objects chained as
1080      * <code><em>Foo</em>Listener</code>s by the specified
1081      * <code>java.util.EventListener</code>.
1082      * <code><em>Foo</em>Listener</code>s are chained by the
1083      * <code>AWTEventMulticaster</code> using the
1084      * <code>add<em>Foo</em>Listener</code> method.
1085      * If a <code>null</code> listener is specified, this method returns an
1086      * empty array. If the specified listener is not an instance of
1087      * <code>AWTEventMulticaster</code>, this method returns an array which
1088      * contains only the specified listener. If no such listeners are chained,
1089      * this method returns an empty array.
1090      *
1091      * @param l the specified <code>java.util.EventListener</code>
1092      * @param listenerType the type of listeners requested; this parameter
1093      *          should specify an interface that descends from
1094      *          <code>java.util.EventListener</code>
1095      * @return an array of all objects chained as
1096      *          <code><em>Foo</em>Listener</code>s by the specified multicast
1097      *          listener, or an empty array if no such listeners have been
1098      *          chained by the specified multicast listener
1099      * @exception NullPointerException if the specified
1100      *             {@code listenertype} parameter is {@code null}
1101      * @exception ClassCastException if <code>listenerType</code>
1102      *          doesn't specify a class or interface that implements
1103      *          <code>java.util.EventListener</code>
1104      *
1105      * @since 1.4
1106      */
1107     @SuppressWarnings("unchecked")
1108     public static <T extends EventListener> T[]
1109         getListeners(EventListener l, Class<T> listenerType)
1110     {
1111         if (listenerType == null) {
1112             throw new NullPointerException ("Listener type should not be null");
1113         }
1114 
1115         int n = getListenerCount(l, listenerType);
1116         T[] result = (T[])Array.newInstance(listenerType, n);
1117         populateListenerArray(result, l, 0);
1118         return result;
1119     }
1120 }