/*
 * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.java.accessibility.util;

import java.util.*;
import java.beans.*;
import java.awt.*;
import java.awt.event.*;
import javax.accessibility.*;

AccessibilityEventMonitor implements a PropertyChange listener on every UI object that implements interface Accessible in the Java Virtual Machine. The events captured by these listeners are made available through listeners supported by AccessibilityEventMonitor. With this, all the individual events on each of the UI object instances are funneled into one set of PropertyChange listeners.

This class depends upon EventQueueMonitor, which provides the base level support for capturing the top-level containers as they are created.

/** * <P>{@code AccessibilityEventMonitor} implements a PropertyChange listener * on every UI object that implements interface {@code Accessible} in the Java * Virtual Machine. The events captured by these listeners are made available * through listeners supported by {@code AccessibilityEventMonitor}. * With this, all the individual events on each of the UI object * instances are funneled into one set of PropertyChange listeners. * <p>This class depends upon {@link EventQueueMonitor}, which provides the base * level support for capturing the top-level containers as they are created. * */
public class AccessibilityEventMonitor { // listeners
The current list of registered PropertyChangeListener classes.
See Also:
/** * The current list of registered {@link java.beans.PropertyChangeListener * PropertyChangeListener} classes. * * @see #addPropertyChangeListener * @see #removePropertyChangeListener */
static protected final AccessibilityListenerList listenerList = new AccessibilityListenerList();
The actual listener that is installed on the component instances. This listener calls the other registered listeners when an event occurs. By doing things this way, the actual number of listeners installed on a component instance is drastically reduced.
/** * The actual listener that is installed on the component instances. * This listener calls the other registered listeners when an event * occurs. By doing things this way, the actual number of listeners * installed on a component instance is drastically reduced. */
static private final AccessibilityEventListener accessibilityListener = new AccessibilityEventListener();
Adds the specified listener to receive all PropertyChange events on each UI object instance in the Java Virtual Machine as they occur.

Note: This listener is automatically added to all component instances created after this method is called. In addition, it is only added to UI object instances that support this listener type.

Params:
  • l – the listener to add
See Also:
/** * Adds the specified listener to receive all PropertyChange events on * each UI object instance in the Java Virtual Machine as they occur. * <P>Note: This listener is automatically added to all component * instances created after this method is called. In addition, it * is only added to UI object instances that support this listener type. * * @param l the listener to add * * @see #removePropertyChangeListener */
static public void addPropertyChangeListener(PropertyChangeListener l) { if (listenerList.getListenerCount(PropertyChangeListener.class) == 0) { accessibilityListener.installListeners(); } listenerList.add(PropertyChangeListener.class, l); }
Removes the specified listener so it no longer receives PropertyChange events when they occur.
Params:
  • l – the listener to remove
See Also:
  • addPropertyChangeListener
/** * Removes the specified listener so it no longer receives PropertyChange * events when they occur. * @see #addPropertyChangeListener * @param l the listener to remove */
static public void removePropertyChangeListener(PropertyChangeListener l) { listenerList.remove(PropertyChangeListener.class, l); if (listenerList.getListenerCount(PropertyChangeListener.class) == 0) { accessibilityListener.removeListeners(); } }
AccessibilityEventListener is the class that does all the work for AccessibilityEventMonitor. It is not intended for use by any other class except AccessibilityEventMonitor.
/** * AccessibilityEventListener is the class that does all the work for * AccessibilityEventMonitor. It is not intended for use by any other * class except AccessibilityEventMonitor. * */
static class AccessibilityEventListener implements TopLevelWindowListener, PropertyChangeListener {
Create a new instance of this class and install it on each component instance in the virtual machine that supports any of the currently registered listeners in AccessibilityEventMonitor. Also registers itself as a TopLevelWindowListener with EventQueueMonitor so it can automatically add new listeners to new components.
See Also:
/** * Create a new instance of this class and install it on each component * instance in the virtual machine that supports any of the currently * registered listeners in AccessibilityEventMonitor. Also registers * itself as a TopLevelWindowListener with EventQueueMonitor so it can * automatically add new listeners to new components. * @see EventQueueMonitor * @see AccessibilityEventMonitor */
public AccessibilityEventListener() { EventQueueMonitor.addTopLevelWindowListener(this); }
Installs PropertyChange listeners on all Accessible objects based upon the current topLevelWindows cached by EventQueueMonitor.
See Also:
/** * Installs PropertyChange listeners on all Accessible objects based * upon the current topLevelWindows cached by EventQueueMonitor. * @see EventQueueMonitor * @see AWTEventMonitor */
protected void installListeners() { Window topLevelWindows[] = EventQueueMonitor.getTopLevelWindows(); if (topLevelWindows != null) { for (int i = 0; i < topLevelWindows.length; i++) { if (topLevelWindows[i] instanceof Accessible) { installListeners((Accessible) topLevelWindows[i]); } } } }
Installs PropertyChange listeners to the Accessible object, and it's children (so long as the object isn't of TRANSIENT state).
Params:
  • a – the Accessible object to add listeners to
/** * Installs PropertyChange listeners to the Accessible object, and it's * children (so long as the object isn't of TRANSIENT state). * @param a the Accessible object to add listeners to */
protected void installListeners(Accessible a) { installListeners(a.getAccessibleContext()); }
Installs PropertyChange listeners to the AccessibleContext object, and it's * children (so long as the object isn't of TRANSIENT state).
Params:
  • a – the Accessible object to add listeners to
/** * Installs PropertyChange listeners to the AccessibleContext object, * and it's * children (so long as the object isn't of TRANSIENT state). * @param a the Accessible object to add listeners to */
private void installListeners(AccessibleContext ac) { if (ac != null) { AccessibleStateSet states = ac.getAccessibleStateSet(); if (!states.contains(AccessibleState.TRANSIENT)) { ac.addPropertyChangeListener(this); /* * Don't add listeners to transient children. Components * with transient children should return an AccessibleStateSet * containing AccessibleState.MANAGES_DESCENDANTS. Components * may not explicitly return the MANAGES_DESCENDANTS state. * In this case, don't add listeners to the children of * lists, tables and trees. */ AccessibleStateSet set = ac.getAccessibleStateSet(); if (set.contains(_AccessibleState.MANAGES_DESCENDANTS)) { return; } AccessibleRole role = ac.getAccessibleRole(); if (role == AccessibleRole.LIST || role == AccessibleRole.TREE) { return; } if (role == AccessibleRole.TABLE) { // handle Oracle tables containing tables Accessible child = ac.getAccessibleChild(0); if (child != null) { AccessibleContext ac2 = child.getAccessibleContext(); if (ac2 != null) { role = ac2.getAccessibleRole(); if (role != null && role != AccessibleRole.TABLE) { return; } } } } int count = ac.getAccessibleChildrenCount(); for (int i = 0; i < count; i++) { Accessible child = ac.getAccessibleChild(i); if (child != null) { installListeners(child); } } } } }
Removes PropertyChange listeners on all Accessible objects based upon the topLevelWindows cached by EventQueueMonitor.
Params:
  • eventID – the event ID
See Also:
/** * Removes PropertyChange listeners on all Accessible objects based * upon the topLevelWindows cached by EventQueueMonitor. * @param eventID the event ID * @see EventID */
protected void removeListeners() { Window topLevelWindows[] = EventQueueMonitor.getTopLevelWindows(); if (topLevelWindows != null) { for (int i = 0; i < topLevelWindows.length; i++) { if (topLevelWindows[i] instanceof Accessible) { removeListeners((Accessible) topLevelWindows[i]); } } } }
Removes PropertyChange listeners for the given Accessible object, it's children (so long as the object isn't of TRANSIENT state).
Params:
  • a – the Accessible object to remove listeners from
/** * Removes PropertyChange listeners for the given Accessible object, * it's children (so long as the object isn't of TRANSIENT state). * @param a the Accessible object to remove listeners from */
protected void removeListeners(Accessible a) { removeListeners(a.getAccessibleContext()); }
Removes PropertyChange listeners for the given AccessibleContext object, it's children (so long as the object isn't of TRANSIENT state).
Params:
  • a – the Accessible object to remove listeners from
/** * Removes PropertyChange listeners for the given AccessibleContext * object, it's children (so long as the object isn't of TRANSIENT * state). * @param a the Accessible object to remove listeners from */
private void removeListeners(AccessibleContext ac) { if (ac != null) { // Listeners are not added to transient components. AccessibleStateSet states = ac.getAccessibleStateSet(); if (!states.contains(AccessibleState.TRANSIENT)) { ac.removePropertyChangeListener(this); /* * Listeners are not added to transient children. Components * with transient children should return an AccessibleStateSet * containing AccessibleState.MANAGES_DESCENDANTS. Components * may not explicitly return the MANAGES_DESCENDANTS state. * In this case, don't remove listeners from the children of * lists, tables and trees. */ if (states.contains(_AccessibleState.MANAGES_DESCENDANTS)) { return; } AccessibleRole role = ac.getAccessibleRole(); if (role == AccessibleRole.LIST || role == AccessibleRole.TABLE || role == AccessibleRole.TREE) { return; } int count = ac.getAccessibleChildrenCount(); for (int i = 0; i < count; i++) { Accessible child = ac.getAccessibleChild(i); if (child != null) { removeListeners(child); } } } } } /********************************************************************/ /* */ /* Listener Interface Methods */ /* */ /********************************************************************/ /* TopLevelWindow Methods ***************************************/
Called when top level window is created.
See Also:
/** * Called when top level window is created. * @see EventQueueMonitor * @see EventQueueMonitor#addTopLevelWindowListener */
public void topLevelWindowCreated(Window w) { if (w instanceof Accessible) { installListeners((Accessible) w); } }
Called when top level window is destroyed.
See Also:
/** * Called when top level window is destroyed. * @see EventQueueMonitor * @see EventQueueMonitor#addTopLevelWindowListener */
public void topLevelWindowDestroyed(Window w) { if (w instanceof Accessible) { removeListeners((Accessible) w); } } /* PropertyChangeListener Methods **************************************/ public void propertyChange(PropertyChangeEvent e) { // propogate the event Object[] listeners = AccessibilityEventMonitor.listenerList.getListenerList(); for (int i = listeners.length-2; i>=0; i-=2) { if (listeners[i]==PropertyChangeListener.class) { ((PropertyChangeListener)listeners[i+1]).propertyChange(e); } } // handle childbirth/death String name = e.getPropertyName(); if (name.compareTo(AccessibleContext.ACCESSIBLE_CHILD_PROPERTY) == 0) { Object oldValue = e.getOldValue(); Object newValue = e.getNewValue(); if ((oldValue == null) ^ (newValue == null)) { // one null, not both if (oldValue != null) { // this Accessible is a child that's going away if (oldValue instanceof Accessible) { Accessible a = (Accessible) oldValue; removeListeners(a.getAccessibleContext()); } else if (oldValue instanceof AccessibleContext) { removeListeners((AccessibleContext) oldValue); } } else if (newValue != null) { // this Accessible is a child was just born if (newValue instanceof Accessible) { Accessible a = (Accessible) newValue; installListeners(a.getAccessibleContext()); } else if (newValue instanceof AccessibleContext) { installListeners((AccessibleContext) newValue); } } } else { System.out.println("ERROR in usage of PropertyChangeEvents for: " + e.toString()); } } } } } /* * workaround for no public AccessibleState constructor */ class _AccessibleState extends AccessibleState {
Indicates this object is responsible for managing its subcomponents. This is typically used for trees and tables that have a large number of subcomponents and where the objects are created only when needed and otherwise remain virtual. The application should not manage the subcomponents directly.
/** * Indicates this object is responsible for managing its * subcomponents. This is typically used for trees and tables * that have a large number of subcomponents and where the * objects are created only when needed and otherwise remain virtual. * The application should not manage the subcomponents directly. */
public static final _AccessibleState MANAGES_DESCENDANTS = new _AccessibleState ("managesDescendants");
Creates a new AccessibleState using the given locale independent key. This should not be a public method. Instead, it is used to create the constants in this file to make it a strongly typed enumeration. Subclasses of this class should enforce similar policy.

The key String should be a locale independent key for the state. It is not intended to be used as the actual String to display to the user. To get the localized string, use toDisplayString.

Params:
  • key – the locale independent name of the state.
See Also:
/** * Creates a new AccessibleState using the given locale independent key. * This should not be a public method. Instead, it is used to create * the constants in this file to make it a strongly typed enumeration. * Subclasses of this class should enforce similar policy. * <p> * The key String should be a locale independent key for the state. * It is not intended to be used as the actual String to display * to the user. To get the localized string, use toDisplayString. * * @param key the locale independent name of the state. * @see AccessibleBundle#toDisplayString */
protected _AccessibleState(String key) { super(key); } }