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