1 /*
   2  * Copyright (c) 2005, 2015, 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 
  26 package com.sun.java.accessibility.util;
  27 
  28 import java.util.*;
  29 import java.beans.*;
  30 import java.awt.*;
  31 import java.awt.event.*;
  32 import javax.accessibility.*;
  33 
  34 /**
  35  * <P>The {@code AccessibilityListenerList} is a copy of the Swing
  36  * {@link javax.swing.event.EventListenerList EventListerList} class.
  37  *
  38  */
  39 
  40 @jdk.Exported
  41 public class AccessibilityListenerList {
  42     /* A null array to be shared by all empty listener lists */
  43     private final static Object[] NULL_ARRAY = new Object[0];
  44 
  45     /**
  46      * The list of listener type, listener pairs
  47      */
  48     protected transient Object[] listenerList = NULL_ARRAY;
  49 
  50     /**
  51      * Passes back the event listener list as an array of listener type, listener pairs.
  52      * Note that for performance reasons, this implementation passes back the actual
  53      * data structure in which the listener data is stored internally. This method
  54      * is guaranteed to pass back a non-null array, so that no null-checking
  55      * is required in fire methods. A zero-length array of Object is returned if
  56      * there are currently no listeners.
  57      * <p>
  58      * Absolutely no modification of the data contained in this array should be
  59      * made.  If any such manipulation is necessary, it should be done on a copy
  60      * of the array returned rather than the array itself.
  61      * 
  62      * @return an array of listener type, listener pairs.
  63      */
  64     public Object[] getListenerList() {
  65         return listenerList;
  66     }
  67 
  68     /**
  69      * Returns the total number of listeners for this listener list.
  70      * 
  71      * @return the total number of listeners for this listener list.
  72      */
  73     public int getListenerCount() {
  74         return listenerList.length/2;
  75     }
  76 
  77     /**
  78      * Return the total number of listeners of the supplied type
  79      * for this listener list.
  80      * 
  81      * @param t the type of the listener to be counted
  82      * @return the number of listeners found
  83      */
  84     public int getListenerCount(Class t) {
  85         int count = 0;
  86         Object[] lList = listenerList;
  87         for (int i = 0; i < lList.length; i+=2) {
  88             if (t == (Class)lList[i])
  89                 count++;
  90         }
  91         return count;
  92     }
  93 
  94     /**
  95      * Add the listener as a listener of the specified type.
  96      * 
  97      * @param t the type of the listener to be added
  98      * @param l the listener to be added
  99      */
 100     public synchronized void add(Class t, EventListener l) {
 101         if (!t.isInstance(l)) {
 102             throw new IllegalArgumentException("Listener " + l +
 103                                          " is not of type " + t);
 104         }
 105         if (l ==null) {
 106             throw new IllegalArgumentException("Listener " + l +
 107                                          " is null");
 108         }
 109         if (listenerList == NULL_ARRAY) {
 110             // if this is the first listener added,
 111             // initialize the lists
 112             listenerList = new Object[] { t, l };
 113         } else {
 114             // Otherwise copy the array and add the new listener
 115             int i = listenerList.length;
 116             Object[] tmp = new Object[i+2];
 117             System.arraycopy(listenerList, 0, tmp, 0, i);
 118 
 119             tmp[i] = t;
 120             tmp[i+1] = l;
 121 
 122             listenerList = tmp;
 123         }
 124     }
 125 
 126     /**
 127      * Remove the listener as a listener of the specified type.
 128      * 
 129      * @param t the type of the listener to be removed
 130      * @param l the listener to be removed
 131      */
 132     public synchronized void remove(Class t, EventListener l) {
 133         if (!t.isInstance(l)) {
 134             throw new IllegalArgumentException("Listener " + l +
 135                                          " is not of type " + t);
 136         }
 137         if (l ==null) {
 138             throw new IllegalArgumentException("Listener " + l +
 139                                          " is null");
 140         }
 141 
 142         // Is l on the list?
 143         int index = -1;
 144         for (int i = listenerList.length-2; i>=0; i-=2) {
 145             if ((listenerList[i]==t) && (listenerList[i+1] == l)) {
 146                 index = i;
 147                 break;
 148             }
 149         }
 150 
 151         // If so,  remove it
 152         if (index != -1) {
 153             Object[] tmp = new Object[listenerList.length-2];
 154             // Copy the list up to index
 155             System.arraycopy(listenerList, 0, tmp, 0, index);
 156             // Copy from two past the index, up to
 157             // the end of tmp (which is two elements
 158             // shorter than the old list)
 159             if (index < tmp.length)
 160                 System.arraycopy(listenerList, index+2, tmp, index,
 161                                  tmp.length - index);
 162             // set the listener array to the new array or null
 163             listenerList = (tmp.length == 0) ? NULL_ARRAY : tmp;
 164             }
 165     }
 166 
 167     /**
 168      * Return a string representation of the {@code AccessibilityListenerList}.
 169      * 
 170      * @return a string representation of the {@code AccessibilityListenerList}.
 171      */
 172     public String toString() {
 173         Object[] lList = listenerList;
 174         String s = "EventListenerList: ";
 175         s += lList.length/2 + " listeners: ";
 176         for (int i = 0 ; i <= lList.length-2 ; i+=2) {
 177             s += " type " + ((Class)lList[i]).getName();
 178             s += " listener " + lList[i+1];
 179         }
 180         return s;
 181     }
 182 }