jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/AccessibilityEventMonitor.java
changeset 39934 9c84ee88dd3a
parent 39933 c0dd0f198453
parent 39922 e613affb88d1
child 39935 6016bd47edc9
equal deleted inserted replaced
39933:c0dd0f198453 39934:9c84ee88dd3a
     1 /*
       
     2  * Copyright (c) 2002, 2016, 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 sun.lwawt.macosx;
       
    27 
       
    28 import java.beans.PropertyChangeEvent;
       
    29 import java.beans.PropertyChangeListener;
       
    30 import javax.accessibility.Accessible;
       
    31 import javax.accessibility.AccessibleContext;
       
    32 import javax.accessibility.AccessibleRole;
       
    33 import javax.accessibility.AccessibleState;
       
    34 import javax.accessibility.AccessibleStateSet;
       
    35 import javax.swing.event.EventListenerList;
       
    36 
       
    37 /**
       
    38  * <P>{@code AccessibilityEventMonitor} implements a PropertyChange listener
       
    39  * on every UI object that implements interface {@code Accessible} in the Java
       
    40  * Virtual Machine.  The events captured by these listeners are made available
       
    41  * through listeners supported by {@code AccessibilityEventMonitor}.
       
    42  * With this, all the individual events on each of the UI object
       
    43  * instances are funneled into one set of PropertyChange listeners.
       
    44  *
       
    45  * This code is a subset of com.sun.java.accessibility.util.AccessibilityEventMonitor
       
    46  * which resides in module jdk.accessibility.  Due to modularization the code in
       
    47  * this package, java.desktop, can not be dependent on code in jdk.accessibility.
       
    48  */
       
    49 
       
    50 class AccessibilityEventMonitor {
       
    51 
       
    52     /**
       
    53      * The current list of registered {@link java.beans.PropertyChangeListener
       
    54      * PropertyChangeListener} classes.
       
    55      *
       
    56      * @see #addPropertyChangeListener
       
    57      */
       
    58     private static final EventListenerList listenerList =
       
    59         new EventListenerList();
       
    60 
       
    61 
       
    62     /**
       
    63      * The actual listener that is installed on the component instances.
       
    64      * This listener calls the other registered listeners when an event
       
    65      * occurs.  By doing things this way, the actual number of listeners
       
    66      * installed on a component instance is drastically reduced.
       
    67      */
       
    68     private static final AccessibilityEventListener accessibilityListener =
       
    69         new AccessibilityEventListener();
       
    70 
       
    71     /**
       
    72      * Adds the specified listener to receive all PropertyChange events on
       
    73      * each UI object instance in the Java Virtual Machine as they occur.
       
    74      * <P>Note: This listener is automatically added to all component
       
    75      * instances created after this method is called.  In addition, it
       
    76      * is only added to UI object instances that support this listener type.
       
    77      *
       
    78      * @param l the listener to add
       
    79      * @param a  the Accessible object to add the PropertyChangeListener to
       
    80      */
       
    81 
       
    82     static void addPropertyChangeListener(PropertyChangeListener l, Accessible a) {
       
    83         if (listenerList.getListenerCount(PropertyChangeListener.class) == 0) {
       
    84             accessibilityListener.installListeners(a);
       
    85         }
       
    86         listenerList.add(PropertyChangeListener.class, l);
       
    87     }
       
    88 
       
    89     /**
       
    90      * AccessibilityEventListener is the class that does all the work for
       
    91      * AccessibilityEventMonitor.  It is not intended for use by any other
       
    92      * class except AccessibilityEventMonitor.
       
    93      */
       
    94 
       
    95     private static class AccessibilityEventListener implements PropertyChangeListener {
       
    96 
       
    97         /**
       
    98          * Installs PropertyChange listeners to the Accessible object, and its
       
    99          * children (so long as the object isn't of TRANSIENT state).
       
   100          *
       
   101          * @param a the Accessible object to add listeners to
       
   102          */
       
   103         private void installListeners(Accessible a) {
       
   104             installListeners(a.getAccessibleContext());
       
   105         }
       
   106 
       
   107         /**
       
   108          * Installs PropertyChange listeners to the AccessibleContext object,
       
   109          * and its * children (so long as the object isn't of TRANSIENT state).
       
   110          *
       
   111          * @param ac the AccessibleContext to add listeners to
       
   112          */
       
   113         private void installListeners(AccessibleContext ac) {
       
   114 
       
   115             if (ac != null) {
       
   116                 AccessibleStateSet states = ac.getAccessibleStateSet();
       
   117                 if (!states.contains(AccessibleState.TRANSIENT)) {
       
   118                     ac.addPropertyChangeListener(this);
       
   119                     /*
       
   120                      * Don't add listeners to transient children. Components
       
   121                      * with transient children should return an AccessibleStateSet
       
   122                      * containing AccessibleState.MANAGES_DESCENDANTS. Components
       
   123                      * may not explicitly return the MANAGES_DESCENDANTS state.
       
   124                      * In this case, don't add listeners to the children of
       
   125                      * lists, tables and trees.
       
   126                      */
       
   127                     AccessibleStateSet set = ac.getAccessibleStateSet();
       
   128                     if (set.contains(AccessibleState.MANAGES_DESCENDANTS)) {
       
   129                         return;
       
   130                     }
       
   131                     AccessibleRole role = ac.getAccessibleRole();
       
   132                     if ( role == AccessibleRole.LIST ||
       
   133                          role == AccessibleRole.TREE ) {
       
   134                         return;
       
   135                     }
       
   136                     if (role == AccessibleRole.TABLE) {
       
   137                         // handle Oracle tables containing tables
       
   138                         Accessible child = ac.getAccessibleChild(0);
       
   139                         if (child != null) {
       
   140                             AccessibleContext ac2 = child.getAccessibleContext();
       
   141                             if (ac2 != null) {
       
   142                                 role = ac2.getAccessibleRole();
       
   143                                 if (role != null && role != AccessibleRole.TABLE) {
       
   144                                     return;
       
   145                                 }
       
   146                             }
       
   147                         }
       
   148                     }
       
   149                     int count = ac.getAccessibleChildrenCount();
       
   150                     for (int i = 0; i < count; i++) {
       
   151                         Accessible child = ac.getAccessibleChild(i);
       
   152                         if (child != null) {
       
   153                             installListeners(child);
       
   154                         }
       
   155                     }
       
   156                 }
       
   157             }
       
   158         }
       
   159 
       
   160         /**
       
   161          * Removes PropertyChange listeners for the given Accessible object,
       
   162          * its children (so long as the object isn't of TRANSIENT state).
       
   163          *
       
   164          * @param a the Accessible object to remove listeners from
       
   165          */
       
   166         private void removeListeners(Accessible a) {
       
   167             removeListeners(a.getAccessibleContext());
       
   168         }
       
   169 
       
   170         /**
       
   171          * Removes PropertyChange listeners for the given AccessibleContext
       
   172          * object, its children (so long as the object isn't of TRANSIENT
       
   173          * state).
       
   174          *
       
   175          * @param a the Accessible object to remove listeners from
       
   176          */
       
   177         private void removeListeners(AccessibleContext ac) {
       
   178 
       
   179             if (ac != null) {
       
   180                 // Listeners are not added to transient components.
       
   181                 AccessibleStateSet states = ac.getAccessibleStateSet();
       
   182                 if (!states.contains(AccessibleState.TRANSIENT)) {
       
   183                     ac.removePropertyChangeListener(this);
       
   184                     /*
       
   185                      * Listeners are not added to transient children. Components
       
   186                      * with transient children should return an AccessibleStateSet
       
   187                      * containing AccessibleState.MANAGES_DESCENDANTS. Components
       
   188                      * may not explicitly return the MANAGES_DESCENDANTS state.
       
   189                      * In this case, don't remove listeners from the children of
       
   190                      * lists, tables and trees.
       
   191                      */
       
   192                     if (states.contains(AccessibleState.MANAGES_DESCENDANTS)) {
       
   193                         return;
       
   194                     }
       
   195                     AccessibleRole role = ac.getAccessibleRole();
       
   196                     if ( role == AccessibleRole.LIST ||
       
   197                          role == AccessibleRole.TABLE ||
       
   198                          role == AccessibleRole.TREE ) {
       
   199                         return;
       
   200                     }
       
   201                     int count = ac.getAccessibleChildrenCount();
       
   202                     for (int i = 0; i < count; i++) {
       
   203                         Accessible child = ac.getAccessibleChild(i);
       
   204                         if (child != null) {
       
   205                             removeListeners(child);
       
   206                         }
       
   207                     }
       
   208                 }
       
   209             }
       
   210         }
       
   211 
       
   212         @Override
       
   213         public void propertyChange(PropertyChangeEvent e) {
       
   214             // propogate the event
       
   215             Object[] listeners =
       
   216                 AccessibilityEventMonitor.listenerList.getListenerList();
       
   217             for (int i = listeners.length-2; i>=0; i-=2) {
       
   218                 if (listeners[i]==PropertyChangeListener.class) {
       
   219                     ((PropertyChangeListener)listeners[i+1]).propertyChange(e);
       
   220                 }
       
   221             }
       
   222 
       
   223             // handle childbirth/death
       
   224             String name = e.getPropertyName();
       
   225             if (name.compareTo(AccessibleContext.ACCESSIBLE_CHILD_PROPERTY) == 0) {
       
   226                 Object oldValue = e.getOldValue();
       
   227                 Object newValue = e.getNewValue();
       
   228 
       
   229                 if ((oldValue == null) ^ (newValue == null)) { // one null, not both
       
   230                     if (oldValue != null) {
       
   231                         // this Accessible is a child that's going away
       
   232                         if (oldValue instanceof Accessible) {
       
   233                             Accessible a = (Accessible) oldValue;
       
   234                             removeListeners(a.getAccessibleContext());
       
   235                         } else if (oldValue instanceof AccessibleContext) {
       
   236                             removeListeners((AccessibleContext) oldValue);
       
   237                         }
       
   238                     } else if (newValue != null) {
       
   239                         // this Accessible is a child was just born
       
   240                         if (newValue instanceof Accessible) {
       
   241                             Accessible a = (Accessible) newValue;
       
   242                             installListeners(a.getAccessibleContext());
       
   243                         } else if (newValue instanceof AccessibleContext) {
       
   244                             installListeners((AccessibleContext) newValue);
       
   245                         }
       
   246                     }
       
   247                 } else {
       
   248                     System.out.println("ERROR in usage of PropertyChangeEvents for: " + e.toString());
       
   249                 }
       
   250             }
       
   251         }
       
   252     }
       
   253 }