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