Path: blob/jdk8u272-b10-aarch32-20201026/jdk/src/windows/classes/com/sun/java/accessibility/AccessBridge.java
83410 views
/*1* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.sun.java.accessibility;2627import java.awt.*;28import java.awt.event.*;29import java.util.*;30import java.lang.*;31import java.lang.reflect.*;3233import java.beans.*;34import javax.swing.*;35import javax.swing.event.*;36import javax.swing.text.*;37import javax.swing.tree.*;38import javax.swing.table.*;39import javax.swing.plaf.TreeUI;4041import javax.accessibility.*;42import com.sun.java.accessibility.util.*;43import sun.awt.AWTAccessor;44import sun.awt.AppContext;45import sun.awt.SunToolkit;4647import java.util.concurrent.Callable;48import java.util.concurrent.ConcurrentHashMap;49import java.util.concurrent.CountDownLatch;5051/*52* Note: This class has to be public. It's loaded from the VM like this:53* Class.forName(atName).newInstance();54*/55@jdk.Exported(false)56final public class AccessBridge extends AccessBridgeLoader {5758private final String AccessBridgeVersion =59"AccessBridge 2.0.4";6061private static AccessBridge theAccessBridge;62private ObjectReferences references;63private EventHandler eventHandler;64private boolean runningOnJDK1_4 = false;65private boolean runningOnJDK1_5 = false;6667// Maps AccessibleRoles strings to AccessibleRoles.68private ConcurrentHashMap<String,AccessibleRole> accessibleRoleMap = new ConcurrentHashMap<>();6970/**71If the object's role is in the following array getVirtualAccessibleName72will use the extended search algorithm.73*/74private ArrayList<AccessibleRole> extendedVirtualNameSearchRoles = new ArrayList<>();75/**76If the role of the object's parent is in the following array77getVirtualAccessibleName will NOT use the extended search78algorithm even if the object's role is in the79extendedVirtualNameSearchRoles array.80*/81private ArrayList<AccessibleRole> noExtendedVirtualNameSearchParentRoles = new ArrayList<>();8283/**84* AccessBridge constructor85*86* Note: This constructor has to be public. It's called from the VM like this:87* Class.forName(atName).newInstance();88*/89public AccessBridge() {90super();91theAccessBridge = this;92references = new ObjectReferences();9394// initialize shutdown hook95Runtime runTime = Runtime.getRuntime();96shutdownHook hook = new shutdownHook();97runTime.addShutdownHook(new Thread(hook));9899// initialize AccessibleRole map100initAccessibleRoleMap();101102// determine which version of the JDK is running103String version = getJavaVersionProperty();104debugString("[INFO]:JDK version = "+version);105runningOnJDK1_4 = (version.compareTo("1.4") >= 0);106runningOnJDK1_5 = (version.compareTo("1.5") >= 0);107108// initialize the methods that map HWNDs and Java top-level109// windows110if (initHWNDcalls() == true) {111112// is this a JVM we can use?113// install JDK 1.2 and later Swing ToolKit listener114EventQueueMonitor.isGUIInitialized();115116// start the Java event handler117eventHandler = new EventHandler(this);118119// register for menu selection events120if (runningOnJDK1_4) {121MenuSelectionManager.defaultManager().addChangeListener(eventHandler);122}123124// register as a NativeWindowHandler125addNativeWindowHandler(new DefaultNativeWindowHandler());126127// start in a new thread128Thread abthread = new Thread(new dllRunner());129abthread.setDaemon(true);130abthread.start();131debugString("[INFO]:AccessBridge started");132}133}134135/*136* adaptor to run the AccessBridge DLL137*/138private class dllRunner implements Runnable {139public void run() {140runDLL();141}142}143144/*145* shutdown hook146*/147private class shutdownHook implements Runnable {148149public void run() {150debugString("[INFO]:***** shutdownHook: shutting down...");151javaShutdown();152}153}154155156/*157* Initialize the hashtable that maps Strings to AccessibleRoles.158*/159private void initAccessibleRoleMap() {160/*161* Initialize the AccessibleRoles map. This code uses methods in162* java.lang.reflect.* to build the map.163*/164try {165Class<?> clAccessibleRole = Class.forName ("javax.accessibility.AccessibleRole");166if (null != clAccessibleRole) {167AccessibleRole roleUnknown = AccessibleRole.UNKNOWN;168Field [] fields = clAccessibleRole.getFields ();169int i = 0;170for (i = 0; i < fields.length; i ++) {171Field f = fields [i];172if (javax.accessibility.AccessibleRole.class == f.getType ()) {173AccessibleRole nextRole = (AccessibleRole) (f.get (roleUnknown));174String nextRoleString = nextRole.toDisplayString (Locale.US);175accessibleRoleMap.put (nextRoleString, nextRole);176}177}178}179} catch (Exception e) {}180181/*182Build the extendedVirtualNameSearchRoles array list. I chose this method183because some of the Accessible Roles that need to be added to it are not184available in all versions of the J2SE that we want to support.185*/186extendedVirtualNameSearchRoles.add (AccessibleRole.COMBO_BOX);187try {188/*189Added in J2SE 1.4190*/191extendedVirtualNameSearchRoles.add (AccessibleRole.DATE_EDITOR);192} catch (NoSuchFieldError e) {}193extendedVirtualNameSearchRoles.add (AccessibleRole.LIST);194extendedVirtualNameSearchRoles.add (AccessibleRole.PASSWORD_TEXT);195extendedVirtualNameSearchRoles.add (AccessibleRole.SLIDER);196try {197/*198Added in J2SE 1.3199*/200extendedVirtualNameSearchRoles.add (AccessibleRole.SPIN_BOX);201} catch (NoSuchFieldError e) {}202extendedVirtualNameSearchRoles.add (AccessibleRole.TABLE);203extendedVirtualNameSearchRoles.add (AccessibleRole.TEXT);204extendedVirtualNameSearchRoles.add (AccessibleRole.UNKNOWN);205206noExtendedVirtualNameSearchParentRoles.add (AccessibleRole.TABLE);207noExtendedVirtualNameSearchParentRoles.add (AccessibleRole.TOOL_BAR);208}209210/**211* start the AccessBridge DLL running in its own thread212*/213private native void runDLL();214215/**216* debugging output (goes to OutputDebugStr())217*/218private native void sendDebugString(String debugStr);219220/**221* debugging output (goes to OutputDebugStr())222*/223private void debugString(String debugStr) {224sendDebugString(debugStr);225}226227/* ===== utility methods ===== */228229/**230* decrement the reference to the object (called by native code)231*/232private void decrementReference(Object o) {233references.decrement(o);234}235236/**237* get the java.version property from the JVM238*/239private String getJavaVersionProperty() {240String s = System.getProperty("java.version");241if (s != null) {242references.increment(s);243return s;244}245return null;246}247248/**249* get the java.version property from the JVM250*/251private String getAccessBridgeVersion() {252String s = new String(AccessBridgeVersion);253references.increment(s);254return s;255}256257/* ===== HWND/Java window mapping methods ===== */258259// Java toolkit methods for mapping HWNDs to Java components260private Method javaGetComponentFromNativeWindowHandleMethod;261private Method javaGetNativeWindowHandleFromComponentMethod;262263// native jawt methods for mapping HWNDs to Java components264private native int isJAWTInstalled();265266private native int jawtGetNativeWindowHandleFromComponent(Component comp);267268private native Component jawtGetComponentFromNativeWindowHandle(int handle);269270Toolkit toolkit;271272/**273* map an HWND to an AWT Component274*/275private boolean initHWNDcalls() {276Class<?> integerParemter[] = new Class<?>[1];277integerParemter[0] = Integer.TYPE;278Class<?> componentParemter[] = new Class<?>[1];279try {280componentParemter[0] = Class.forName("java.awt.Component");281} catch (ClassNotFoundException e) {282debugString("[ERROR]:Exception: " + e.toString());283}284Object[] args = new Object[1];285Component c;286boolean returnVal = false;287288toolkit = Toolkit.getDefaultToolkit();289290if (useJAWT_DLL) {291returnVal = true;292} else {293// verify javaGetComponentFromNativeWindowHandle() method294// is present if JAWT.DLL is not installed295try {296javaGetComponentFromNativeWindowHandleMethod =297toolkit.getClass().getMethod(298"getComponentFromNativeWindowHandle", integerParemter);299if (javaGetComponentFromNativeWindowHandleMethod != null) {300try {301args[0] = new Integer(1);302c = (Component) javaGetComponentFromNativeWindowHandleMethod.invoke(toolkit, args);303returnVal = true;304} catch (InvocationTargetException e) {305debugString("[ERROR]:Exception: " + e.toString());306} catch (IllegalAccessException e) {307debugString("[ERROR]:Exception: " + e.toString());308}309}310} catch (NoSuchMethodException e) {311debugString("[ERROR]:Exception: " + e.toString());312} catch (SecurityException e) {313debugString("[ERROR]:Exception: " + e.toString());314}315316// verify getComponentFromNativeWindowHandle() method317// is present if JAWT.DLL is not installed318try {319javaGetNativeWindowHandleFromComponentMethod =320toolkit.getClass().getMethod(321"getNativeWindowHandleFromComponent", componentParemter);322if (javaGetNativeWindowHandleFromComponentMethod != null) {323try {324args[0] = new Button("OK"); // need some Component...325Integer i = (Integer) javaGetNativeWindowHandleFromComponentMethod.invoke(toolkit, args);326returnVal = true;327} catch (InvocationTargetException e) {328debugString("[ERROR]:Exception: " + e.toString());329} catch (IllegalAccessException e) {330debugString("[ERROR]:Exception: " + e.toString());331} catch (Exception e) {332debugString("[ERROR]:Exception: " + e.toString());333}334}335} catch (NoSuchMethodException e) {336debugString("[ERROR]:Exception: " + e.toString());337} catch (SecurityException e) {338debugString("[ERROR]:Exception: " + e.toString());339}340}341return returnVal;342}343344// native window handler interface345private interface NativeWindowHandler {346public Accessible getAccessibleFromNativeWindowHandle(int nativeHandle);347}348349// hash table of native window handle to AccessibleContext mappings350static private ConcurrentHashMap<Integer,AccessibleContext> windowHandleToContextMap = new ConcurrentHashMap<>();351352// hash table of AccessibleContext to native window handle mappings353static private ConcurrentHashMap<AccessibleContext,Integer> contextToWindowHandleMap = new ConcurrentHashMap<>();354355/*356* adds a virtual window handler to our hash tables357*/358static private void registerVirtualFrame(final Accessible a,359Integer nativeWindowHandle ) {360if (a != null) {361AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {362@Override363public AccessibleContext call() throws Exception {364return a.getAccessibleContext();365}366}, a);367windowHandleToContextMap.put(nativeWindowHandle, ac);368contextToWindowHandleMap.put(ac, nativeWindowHandle);369}370}371372/*373* removes a virtual window handler to our hash tables374*/375static private void revokeVirtualFrame(final Accessible a,376Integer nativeWindowHandle ) {377AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {378@Override379public AccessibleContext call() throws Exception {380return a.getAccessibleContext();381}382}, a);383windowHandleToContextMap.remove(nativeWindowHandle);384contextToWindowHandleMap.remove(ac);385}386387// vector of native window handlers388private static Vector<NativeWindowHandler> nativeWindowHandlers = new Vector<>();389390/*391* adds a native window handler to our list392*/393private static void addNativeWindowHandler(NativeWindowHandler handler) {394if (handler == null) {395throw new IllegalArgumentException();396}397nativeWindowHandlers.addElement(handler);398}399400/*401* removes a native window handler to our list402*/403private static boolean removeNativeWindowHandler(NativeWindowHandler handler) {404if (handler == null) {405throw new IllegalArgumentException();406}407return nativeWindowHandlers.removeElement(handler);408}409410/**411* verifies that a native window handle is a Java window412*/413private boolean isJavaWindow(int nativeHandle) {414AccessibleContext ac = getContextFromNativeWindowHandle(nativeHandle);415if (ac != null) {416saveContextToWindowHandleMapping(ac, nativeHandle);417return true;418}419return false;420}421422/*423* saves the mapping between an AccessibleContext and a window handle424*/425private void saveContextToWindowHandleMapping(AccessibleContext ac,426int nativeHandle) {427debugString("[INFO]:saveContextToWindowHandleMapping...");428if (ac == null) {429return;430}431if (! contextToWindowHandleMap.containsKey(ac)) {432debugString("[INFO]: saveContextToWindowHandleMapping: ac = "+ac+"; handle = "+nativeHandle);433contextToWindowHandleMap.put(ac, nativeHandle);434}435}436437/**438* maps a native window handle to an Accessible Context439*/440private AccessibleContext getContextFromNativeWindowHandle(int nativeHandle) {441// First, look for the Accessible in our hash table of442// virtual window handles.443AccessibleContext ac = windowHandleToContextMap.get(nativeHandle);444if(ac!=null) {445saveContextToWindowHandleMapping(ac, nativeHandle);446return ac;447}448449// Next, look for the native window handle in our vector450// of native window handles.451int numHandlers = nativeWindowHandlers.size();452for (int i = 0; i < numHandlers; i++) {453NativeWindowHandler nextHandler = nativeWindowHandlers.elementAt(i);454final Accessible a = nextHandler.getAccessibleFromNativeWindowHandle(nativeHandle);455if (a != null) {456ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {457@Override458public AccessibleContext call() throws Exception {459return a.getAccessibleContext();460}461}, a);462saveContextToWindowHandleMapping(ac, nativeHandle);463return ac;464}465}466// Not found.467return null;468}469470/**471* maps an AccessibleContext to a native window handle472* returns 0 on error473*/474private int getNativeWindowHandleFromContext(AccessibleContext ac) {475debugString("[INFO]: getNativeWindowHandleFromContext: ac = "+ac);476try {477return contextToWindowHandleMap.get(ac);478} catch (Exception ex) {479return 0;480}481}482483private class DefaultNativeWindowHandler implements NativeWindowHandler {484/*485* returns the Accessible associated with a native window486*/487public Accessible getAccessibleFromNativeWindowHandle(int nativeHandle) {488final Component c = getComponentFromNativeWindowHandle(nativeHandle);489if (c instanceof Accessible) {490AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {491@Override492public AccessibleContext call() throws Exception {493return c.getAccessibleContext();494}495}, c);496saveContextToWindowHandleMapping(ac, nativeHandle);497return (Accessible)c;498} else {499return null;500}501}502503/**504* map an HWND to an AWT Component505*/506private Component getComponentFromNativeWindowHandle(int nativeHandle) {507if (useJAWT_DLL) {508debugString("[INFO]:*** calling jawtGetComponentFromNativeWindowHandle");509return jawtGetComponentFromNativeWindowHandle(nativeHandle);510} else {511debugString("[INFO]:*** calling javaGetComponentFromNativeWindowHandle");512Object[] args = new Object[1];513if (javaGetComponentFromNativeWindowHandleMethod != null) {514try {515args[0] = nativeHandle;516Object o = javaGetComponentFromNativeWindowHandleMethod.invoke(toolkit, args);517if (o instanceof Accessible) {518final Accessible acc=(Accessible)o;519AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {520@Override521public AccessibleContext call() throws Exception {522return acc.getAccessibleContext();523}524}, (Component)o);525saveContextToWindowHandleMapping(ac,nativeHandle);526}527return (Component)o;528} catch (InvocationTargetException | IllegalAccessException e) {529debugString("[ERROR]:Exception: " + e.toString());530}531}532}533return null;534}535}536537/**538* map an AWT Component to an HWND539*/540private int getNativeWindowHandleFromComponent(final Component target) {541if (useJAWT_DLL) {542debugString("[INFO]:*** calling jawtGetNativeWindowHandleFromComponent");543return jawtGetNativeWindowHandleFromComponent(target);544} else {545Object[] args = new Object[1];546debugString("[INFO]:*** calling javaGetNativeWindowHandleFromComponent");547if (javaGetNativeWindowHandleFromComponentMethod != null) {548try {549args[0] = target;550Integer i = (Integer) javaGetNativeWindowHandleFromComponentMethod.invoke(toolkit, args);551// cache the mapping552AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {553@Override554public AccessibleContext call() throws Exception {555return target.getAccessibleContext();556}557}, target);558contextToWindowHandleMap.put(ac, i);559return i.intValue();560} catch (InvocationTargetException e) {561debugString("[ERROR]:Exception: " + e.toString());562} catch (IllegalAccessException e) {563debugString("[ERROR]:Exception: " + e.toString());564}565}566}567return -1;568}569570/* ===== AccessibleContext methods =====*/571572/*573* returns the inner-most AccessibleContext in parent at Point(x, y)574*/575private AccessibleContext getAccessibleContextAt(int x, int y,576AccessibleContext parent) {577if (parent == null) {578return null;579}580if (windowHandleToContextMap != null &&581windowHandleToContextMap.containsValue(getRootAccessibleContext(parent))) {582// Path for applications that register their top-level583// windows with the AccessBridge (e.g., StarOffice 6.1)584return getAccessibleContextAt_1(x, y, parent);585} else {586// Path for applications that do not register587// their top-level windows with the AccessBridge588// (e.g., Swing/AWT applications)589return getAccessibleContextAt_2(x, y, parent);590}591}592593/*594* returns the root accessible context595*/596private AccessibleContext getRootAccessibleContext(final AccessibleContext ac) {597if (ac == null) {598return null;599}600return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {601@Override602public AccessibleContext call() throws Exception {603Accessible parent = ac.getAccessibleParent();604if (parent == null) {605return ac;606}607Accessible tmp = parent.getAccessibleContext().getAccessibleParent();608while (tmp != null) {609parent = tmp;610tmp = parent.getAccessibleContext().getAccessibleParent();611}612return parent.getAccessibleContext();613}614}, ac);615}616617/*618* StarOffice version that does not use the EventQueueMonitor619*/620private AccessibleContext getAccessibleContextAt_1(final int x, final int y,621final AccessibleContext parent) {622debugString("[INFO]: getAccessibleContextAt_1 called");623debugString("[INFO]: -> x = " + x + " y = " + y + " parent = " + parent);624625if (parent == null) return null;626final AccessibleComponent acmp = InvocationUtils.invokeAndWait(new Callable<AccessibleComponent>() {627@Override628public AccessibleComponent call() throws Exception {629return parent.getAccessibleComponent();630}631}, parent);632if (acmp!=null) {633final Point loc = InvocationUtils.invokeAndWait(new Callable<Point>() {634@Override635public Point call() throws Exception {636return acmp.getLocation();637}638}, parent);639final Accessible a = InvocationUtils.invokeAndWait(new Callable<Accessible>() {640@Override641public Accessible call() throws Exception {642return acmp.getAccessibleAt(new Point(x - loc.x, y - loc.y));643}644}, parent);645if (a != null) {646AccessibleContext foundAC = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {647@Override648public AccessibleContext call() throws Exception {649return a.getAccessibleContext();650}651}, parent);652if (foundAC != null) {653if (foundAC != parent) {654// recurse down into the child655return getAccessibleContextAt_1(x - loc.x, y - loc.y,656foundAC);657} else658return foundAC;659}660}661}662return parent;663}664665/*666* AWT/Swing version667*/668private AccessibleContext getAccessibleContextAt_2(final int x, final int y,669AccessibleContext parent) {670debugString("[INFO]: getAccessibleContextAt_2 called");671debugString("[INFO]: -> x = " + x + " y = " + y + " parent = " + parent);672673return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {674@Override675public AccessibleContext call() throws Exception {676Accessible a = EventQueueMonitor.getAccessibleAt(new Point(x, y));677if (a != null) {678AccessibleContext childAC = a.getAccessibleContext();679if (childAC != null) {680debugString("[INFO]: returning childAC = " + childAC);681return childAC;682}683}684return null;685}686}, parent);687}688689/**690* returns the Accessible that has focus691*/692private AccessibleContext getAccessibleContextWithFocus() {693Component c = AWTEventMonitor.getComponentWithFocus();694if (c != null) {695final Accessible a = Translator.getAccessible(c);696if (a != null) {697AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {698@Override699public AccessibleContext call() throws Exception {700return a.getAccessibleContext();701}702}, c);703if (ac != null) {704return ac;705}706}707}708return null;709}710711/**712* returns the AccessibleName from an AccessibleContext713*/714private String getAccessibleNameFromContext(final AccessibleContext ac) {715debugString("[INFO]: ***** ac = "+ac.getClass());716if (ac != null) {717String s = InvocationUtils.invokeAndWait(new Callable<String>() {718@Override719public String call() throws Exception {720return ac.getAccessibleName();721}722}, ac);723if (s != null) {724references.increment(s);725debugString("[INFO]: Returning AccessibleName from Context: " + s);726return s;727} else {728return null;729}730} else {731debugString("[INFO]: getAccessibleNameFromContext; ac = null!");732return null;733}734}735736/**737* Returns an AccessibleName for a component using an algorithm optimized738* for the JAWS screen reader. This method is only intended for JAWS. All739* other uses are entirely optional.740*/741private String getVirtualAccessibleNameFromContext(final AccessibleContext ac) {742if (null != ac) {743/*744Step 1:745=======746Determine if we can obtain the Virtual Accessible Name from the747Accessible Name or Accessible Description of the object.748*/749String nameString = InvocationUtils.invokeAndWait(new Callable<String>() {750@Override751public String call() throws Exception {752return ac.getAccessibleName();753}754}, ac);755if ( ( null != nameString ) && ( 0 != nameString.length () ) ) {756debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from AccessibleContext::getAccessibleName.");757references.increment (nameString);758return nameString;759}760String descriptionString = InvocationUtils.invokeAndWait(new Callable<String>() {761@Override762public String call() throws Exception {763return ac.getAccessibleDescription();764}765}, ac);766if ( ( null != descriptionString ) && ( 0 != descriptionString.length () ) ) {767debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from AccessibleContext::getAccessibleDescription.");768references.increment (descriptionString);769return descriptionString;770}771772debugString ("[WARN]: The Virtual Accessible Name was not found using AccessibleContext::getAccessibleDescription. or getAccessibleName");773/*774Step 2:775=======776Decide whether the extended name search algorithm should be777used for this object.778*/779boolean bExtendedSearch = false;780AccessibleRole role = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {781@Override782public AccessibleRole call() throws Exception {783return ac.getAccessibleRole();784}785}, ac);786AccessibleContext parentContext = null;787AccessibleRole parentRole = AccessibleRole.UNKNOWN;788789if ( extendedVirtualNameSearchRoles.contains (role) ) {790parentContext = getAccessibleParentFromContext (ac);791if ( null != parentContext ) {792final AccessibleContext parentContextInnerTemp = parentContext;793parentRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {794@Override795public AccessibleRole call() throws Exception {796return parentContextInnerTemp.getAccessibleRole();797}798}, ac);799if ( AccessibleRole.UNKNOWN != parentRole ) {800bExtendedSearch = true;801if ( noExtendedVirtualNameSearchParentRoles.contains (parentRole) ) {802bExtendedSearch = false;803}804}805}806}807808if (false == bExtendedSearch) {809debugString ("[INFO]: bk -- getVirtualAccessibleNameFromContext will not use the extended name search algorithm. role = " + ( role != null ? role.toDisplayString(Locale.US) : "null") );810/*811Step 3:812=======813We have determined that we should not use the extended name814search algorithm for this object (we must obtain the name of815the object from the object itself and not from neighboring816objects). However the object name cannot be obtained from817the Accessible Name or Accessible Description of the object.818819Handle several special cases here that might yield a value for820the Virtual Accessible Name. Return null if the object does821not match the criteria for any of these special cases.822*/823if (AccessibleRole.LABEL == role) {824/*825Does the label support the Accessible Text Interface?826*/827final AccessibleText at = InvocationUtils.invokeAndWait(new Callable<AccessibleText>() {828@Override829public AccessibleText call() throws Exception {830return ac.getAccessibleText();831}832}, ac);833if (null != at) {834int charCount = InvocationUtils.invokeAndWait(new Callable<Integer>() {835@Override836public Integer call() throws Exception {837return at.getCharCount();838}839}, ac);840String text = getAccessibleTextRangeFromContext (ac, 0, charCount);841if (null != text) {842debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from the Accessible Text of the LABEL object.");843references.increment (text);844return text;845}846}847/*848Does the label support the Accessible Icon Interface?849*/850debugString ("[INFO]: bk -- Attempting to obtain the Virtual Accessible Name from the Accessible Icon information.");851final AccessibleIcon [] ai = InvocationUtils.invokeAndWait(new Callable<AccessibleIcon[]>() {852@Override853public AccessibleIcon[] call() throws Exception {854return ac.getAccessibleIcon();855}856}, ac);857if ( (null != ai) && (ai.length > 0) ) {858String iconDescription = InvocationUtils.invokeAndWait(new Callable<String>() {859@Override860public String call() throws Exception {861return ai[0].getAccessibleIconDescription();862}863}, ac);864if (iconDescription != null){865debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from the description of the first Accessible Icon found in the LABEL object.");866references.increment (iconDescription);867return iconDescription;868}869} else {870parentContext = getAccessibleParentFromContext (ac);871if ( null != parentContext ) {872final AccessibleContext parentContextInnerTemp = parentContext;873parentRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {874@Override875public AccessibleRole call() throws Exception {876return parentContextInnerTemp.getAccessibleRole();877}878}, ac);879if ( AccessibleRole.TABLE == parentRole ) {880int indexInParent = InvocationUtils.invokeAndWait(new Callable<Integer>() {881@Override882public Integer call() throws Exception {883return ac.getAccessibleIndexInParent();884}885}, ac);886final AccessibleContext acTableCell = getAccessibleChildFromContext (parentContext, indexInParent);887debugString ("[INFO]: bk -- Making a second attempt to obtain the Virtual Accessible Name from the Accessible Icon information for the Table Cell.");888if (acTableCell != null) {889final AccessibleIcon [] aiRet =InvocationUtils.invokeAndWait(new Callable<AccessibleIcon[]>() {890@Override891public AccessibleIcon[] call() throws Exception {892return acTableCell.getAccessibleIcon();893}894}, ac);895if ( (null != aiRet) && (aiRet.length > 0) ) {896String iconDescription = InvocationUtils.invokeAndWait(new Callable<String>() {897public String call() {898return aiRet[0].getAccessibleIconDescription ();899}900}, ac);901if (iconDescription != null){902debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from the description of the first Accessible Icon found in the Table Cell object.");903references.increment (iconDescription);904return iconDescription;905}906}907}908}909}910}911} else if ( (AccessibleRole.TOGGLE_BUTTON == role) ||912(AccessibleRole.PUSH_BUTTON == role) ) {913/*914Does the button support the Accessible Icon Interface?915*/916debugString ("[INFO]: bk -- Attempting to obtain the Virtual Accessible Name from the Accessible Icon information.");917final AccessibleIcon [] ai = InvocationUtils.invokeAndWait(new Callable<AccessibleIcon []>() {918public AccessibleIcon [] call() {919return ac.getAccessibleIcon ();920}921}, ac);922if ( (null != ai) && (ai.length > 0) ) {923String iconDescription = InvocationUtils.invokeAndWait(new Callable<String>() {924public String call() {925return ai[0].getAccessibleIconDescription ();926}927}, ac);928if (iconDescription != null){929debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from the description of the first Accessible Icon found in the TOGGLE_BUTTON or PUSH_BUTTON object.");930references.increment (iconDescription);931return iconDescription;932}933}934} else if ( AccessibleRole.CHECK_BOX == role ) {935/*936NOTE: The only case I know of in which a check box does not937have a name is when that check box is contained in a table.938939In this case it would be appropriate to use the display string940of the check box object as the name (in US English the display941string is typically either "true" or "false").942943I am using the AccessibleValue interface to obtain the display944string of the check box. If the Accessible Value is 1, I am945returning Boolean.TRUE.toString (), If the Accessible Value is9460, I am returning Boolean.FALSE.toString (). If the Accessible947Value is some other number, I will return the display string of948the current numerical value of the check box.949*/950final AccessibleValue av = InvocationUtils.invokeAndWait(new Callable<AccessibleValue>() {951@Override952public AccessibleValue call() throws Exception {953return ac.getAccessibleValue();954}955}, ac);956if ( null != av ) {957nameString = null;958Number value = InvocationUtils.invokeAndWait(new Callable<Number>() {959@Override960public Number call() throws Exception {961return av.getCurrentAccessibleValue();962}963}, ac);964if ( null != value ) {965if ( 1 == value.intValue () ) {966nameString = Boolean.TRUE.toString ();967} else if ( 0 == value.intValue () ) {968nameString = Boolean.FALSE.toString ();969} else {970nameString = value.toString ();971}972if ( null != nameString ) {973references.increment (nameString);974return nameString;975}976}977}978}979return null;980}981982/*983+984Beginning of the extended name search985+986*/987final AccessibleContext parentContextOuterTemp = parentContext;988String parentName = InvocationUtils.invokeAndWait(new Callable<String>() {989@Override990public String call() throws Exception {991return parentContextOuterTemp.getAccessibleName();992}993}, ac);994String parentDescription = InvocationUtils.invokeAndWait(new Callable<String>() {995@Override996public String call() throws Exception {997return parentContextOuterTemp.getAccessibleDescription();998}999}, ac);10001001/*1002Step 4:1003=======1004Special case for Slider Bar objects.1005*/1006if ( (AccessibleRole.SLIDER == role) &&1007(AccessibleRole.PANEL == parentRole) &&1008(null != parentName) ) {1009debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from the Accessible Name of the SLIDER object's parent object.");1010references.increment (parentName);1011return parentName;1012}10131014boolean bIsEditCombo = false;10151016AccessibleContext testContext = ac;1017/*1018Step 5:1019=======1020Special case for Edit Combo Boxes1021*/1022if ( (AccessibleRole.TEXT == role) &&1023(AccessibleRole.COMBO_BOX == parentRole) ) {1024bIsEditCombo = true;1025if (null != parentName) {1026debugString ("[INFO]: bk -- The Virtual Accessible Name for this Edit Combo box was obtained from the Accessible Name of the object's parent object.");1027references.increment (parentName);1028return parentName;1029} else if (null != parentDescription) {1030debugString ("[INFO]: bk -- The Virtual Accessible Name for this Edit Combo box was obtained from the Accessible Description of the object's parent object.");1031references.increment (parentDescription);1032return parentDescription;1033}1034testContext = parentContext;1035parentRole = AccessibleRole.UNKNOWN;1036parentContext = getAccessibleParentFromContext (testContext);1037if ( null != parentContext ) {1038final AccessibleContext parentContextInnerTemp = parentContext;1039parentRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {1040@Override1041public AccessibleRole call() throws Exception {1042return parentContextInnerTemp.getAccessibleRole();1043}1044}, ac);1045}1046}10471048/*1049Step 6:1050=======1051Attempt to get the Virtual Accessible Name of the object using the1052Accessible Relation Set Info (the LABELED_BY Accessible Relation).1053*/1054String version = getJavaVersionProperty ();1055if ( (null != version) && (version.compareTo ("1.3") >= 0) ) {1056final AccessibleContext parentContextTempInner = parentContext;1057AccessibleRelationSet ars = InvocationUtils.invokeAndWait(new Callable<AccessibleRelationSet>() {1058@Override1059public AccessibleRelationSet call() throws Exception {1060return parentContextTempInner.getAccessibleRelationSet();1061}1062}, ac);1063if ( ars != null && (ars.size () > 0) && (ars.contains (AccessibleRelation.LABELED_BY)) ) {1064AccessibleRelation labeledByRelation = ars.get (AccessibleRelation.LABELED_BY);1065if (labeledByRelation != null) {1066Object [] targets = labeledByRelation.getTarget ();1067Object o = targets [0];1068if (o instanceof Accessible) {1069AccessibleContext labelContext = ((Accessible)o).getAccessibleContext ();1070if (labelContext != null) {1071String labelName = labelContext.getAccessibleName ();1072String labelDescription = labelContext.getAccessibleDescription ();1073if (null != labelName) {1074debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained using the LABELED_BY AccessibleRelation -- Name Case.");1075references.increment (labelName);1076return labelName;1077} else if (null != labelDescription) {1078debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained using the LABELED_BY AccessibleRelation -- Description Case.");1079references.increment (labelDescription);1080return labelDescription;1081}1082}1083}1084}1085}1086} else {1087debugString ("[ERROR]:bk -- This version of Java does not support AccessibleContext::getAccessibleRelationSet.");1088}10891090//Note: add AccessibleContext to use InvocationUtils.invokeAndWait1091/*1092Step 7:1093=======1094Search for a label object that is positioned either just to the left1095or just above the object and get the Accessible Name of the Label1096object.1097*/1098int testIndexMax = 0;1099int testX = 0;1100int testY = 0;1101int testWidth = 0;1102int testHeight = 0;1103int targetX = 0;1104int targetY = 0;1105final AccessibleContext tempContext = testContext;1106int testIndex = InvocationUtils.invokeAndWait(new Callable<Integer>() {1107@Override1108public Integer call() throws Exception {1109return tempContext.getAccessibleIndexInParent();1110}1111}, ac);1112if ( null != parentContext ) {1113final AccessibleContext parentContextInnerTemp = parentContext;1114testIndexMax = InvocationUtils.invokeAndWait(new Callable<Integer>() {1115@Override1116public Integer call() throws Exception {1117return parentContextInnerTemp.getAccessibleChildrenCount() - 1;1118}1119}, ac);1120}1121testX = getAccessibleXcoordFromContext (testContext);1122testY = getAccessibleYcoordFromContext (testContext);1123testWidth = getAccessibleWidthFromContext (testContext);1124testHeight = getAccessibleHeightFromContext (testContext);1125targetX = testX + 2;1126targetY = testY + 2;11271128int childIndex = testIndex - 1;1129/*Accessible child = null;1130AccessibleContext childContext = null;1131AccessibleRole childRole = AccessibleRole.UNKNOWN;*/1132int childX = 0;1133int childY = 0;1134int childWidth = 0;1135int childHeight = 0;1136String childName = null;1137String childDescription = null;1138while (childIndex >= 0) {1139final int childIndexTemp = childIndex;1140final AccessibleContext parentContextInnerTemp = parentContext;1141final Accessible child = InvocationUtils.invokeAndWait(new Callable<Accessible>() {1142@Override1143public Accessible call() throws Exception {1144return parentContextInnerTemp.getAccessibleChild(childIndexTemp);1145}1146}, ac);1147if ( null != child ) {1148final AccessibleContext childContext = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {1149@Override1150public AccessibleContext call() throws Exception {1151return child.getAccessibleContext();1152}1153}, ac);1154if ( null != childContext ) {1155AccessibleRole childRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {1156@Override1157public AccessibleRole call() throws Exception {1158return childContext.getAccessibleRole();1159}1160}, ac);1161if ( AccessibleRole.LABEL == childRole ) {1162childX = getAccessibleXcoordFromContext (childContext);1163childY = getAccessibleYcoordFromContext (childContext);1164childWidth = getAccessibleWidthFromContext (childContext);1165childHeight = getAccessibleHeightFromContext (childContext);1166if ( (childX < testX) &&1167((childY <= targetY) && (targetY <= (childY + childHeight))) ) {1168childName = InvocationUtils.invokeAndWait(new Callable<String>() {1169public String call() {1170return childContext.getAccessibleName ();1171}1172}, ac);1173if ( null != childName ) {1174debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from Accessible Name of a LABEL object positioned to the left of the object.");1175references.increment (childName);1176return childName;1177}1178childDescription = InvocationUtils.invokeAndWait(new Callable<String>() {1179public String call() {1180return childContext.getAccessibleDescription ();1181}1182}, ac);1183if ( null != childDescription ) {1184debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from Accessible Description of a LABEL object positioned to the left of the object.");1185references.increment (childDescription);1186return childDescription;1187}1188} else if ( (childY < targetY) &&1189((childX <= targetX) && (targetX <= (childX + childWidth))) ) {1190childName = InvocationUtils.invokeAndWait(new Callable<String>() {1191public String call() {1192return childContext.getAccessibleName ();1193}1194}, ac);1195if ( null != childName ) {1196debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from Accessible Name of a LABEL object positioned above the object.");1197references.increment (childName);1198return childName;1199}1200childDescription = InvocationUtils.invokeAndWait(new Callable<String>() {1201public String call() {1202return childContext.getAccessibleDescription ();1203}1204}, ac);1205if ( null != childDescription ) {1206debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from Accessible Description of a LABEL object positioned above the object.");1207references.increment (childDescription);1208return childDescription;1209}1210}1211}1212}1213}1214childIndex --;1215}1216childIndex = testIndex + 1;1217while (childIndex <= testIndexMax) {1218final int childIndexTemp = childIndex;1219final AccessibleContext parentContextInnerTemp = parentContext;1220final Accessible child = InvocationUtils.invokeAndWait(new Callable<Accessible>() {1221@Override1222public Accessible call() throws Exception {1223return parentContextInnerTemp.getAccessibleChild(childIndexTemp);1224}1225}, ac);1226if ( null != child ) {1227final AccessibleContext childContext = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {1228@Override1229public AccessibleContext call() throws Exception {1230return child.getAccessibleContext();1231}1232}, ac);1233if ( null != childContext ) {1234AccessibleRole childRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {1235@Override1236public AccessibleRole call() throws Exception {1237return childContext.getAccessibleRole();1238}1239}, ac);1240if ( AccessibleRole.LABEL == childRole ) {1241childX = getAccessibleXcoordFromContext (childContext);1242childY = getAccessibleYcoordFromContext (childContext);1243childWidth = getAccessibleWidthFromContext (childContext);1244childHeight = getAccessibleHeightFromContext (childContext);1245if ( (childX < testX) &&1246((childY <= targetY) && (targetY <= (childY + childHeight))) ) {1247childName = InvocationUtils.invokeAndWait(new Callable<String>() {1248public String call() {1249return childContext.getAccessibleName ();1250}1251}, ac);1252if ( null != childName ) {1253debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from Accessible Name of a LABEL object positioned to the left of the object.");1254references.increment (childName);1255return childName;1256}1257childDescription = InvocationUtils.invokeAndWait(new Callable<String>() {1258public String call() {1259return childContext.getAccessibleDescription ();1260}1261}, ac);1262if ( null != childDescription ) {1263debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from Accessible Description of a LABEL object positioned to the left of the object.");1264references.increment (childDescription);1265return childDescription;1266}1267} else if ( (childY < targetY) &&1268((childX <= targetX) && (targetX <= (childX + childWidth))) ) {1269childName = InvocationUtils.invokeAndWait(new Callable<String>() {1270public String call() {1271return childContext.getAccessibleName ();1272}1273}, ac);1274if ( null != childName ) {1275debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from Accessible Name of a LABEL object positioned above the object.");1276references.increment (childName);1277return childName;1278}1279childDescription = InvocationUtils.invokeAndWait(new Callable<String>() {1280public String call() {1281return childContext.getAccessibleDescription ();1282}1283}, ac);1284if ( null != childDescription ) {1285debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from Accessible Description of a LABEL object positioned above the object.");1286references.increment (childDescription);1287return childDescription;1288}1289}1290}1291}1292}1293childIndex ++;1294}1295/*1296Step 8:1297=======1298Special case for combo boxes and text objects, based on a1299similar special case I found in some of our internal JAWS code.13001301Search for a button object that is positioned either just to the left1302or just above the object and get the Accessible Name of the button1303object.1304*/1305if ( (AccessibleRole.TEXT == role) ||1306(AccessibleRole.COMBO_BOX == role) ||1307(bIsEditCombo) ) {1308childIndex = testIndex - 1;1309while (childIndex >= 0) {1310final int childIndexTemp = childIndex;1311final AccessibleContext parentContextInnerTemp = parentContext;1312final Accessible child = InvocationUtils.invokeAndWait(new Callable<Accessible>() {1313@Override1314public Accessible call() throws Exception {1315return parentContextInnerTemp.getAccessibleChild(childIndexTemp);1316}1317}, ac);1318if ( null != child ) {1319final AccessibleContext childContext = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {1320@Override1321public AccessibleContext call() throws Exception {1322return child.getAccessibleContext();1323}1324}, ac);1325if ( null != childContext ) {1326AccessibleRole childRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {1327@Override1328public AccessibleRole call() throws Exception {1329return childContext.getAccessibleRole();1330}1331}, ac);1332if ( ( AccessibleRole.PUSH_BUTTON == childRole ) ||1333( AccessibleRole.TOGGLE_BUTTON == childRole )) {1334childX = getAccessibleXcoordFromContext (childContext);1335childY = getAccessibleYcoordFromContext (childContext);1336childWidth = getAccessibleWidthFromContext (childContext);1337childHeight = getAccessibleHeightFromContext (childContext);1338if ( (childX < testX) &&1339((childY <= targetY) && (targetY <= (childY + childHeight))) ) {1340childName = InvocationUtils.invokeAndWait(new Callable<String>() {1341public String call() {1342return childContext.getAccessibleName ();1343}1344}, ac);1345if ( null != childName ) {1346debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from Accessible Name of a PUSH_BUTTON or TOGGLE_BUTTON object positioned to the left of the object.");1347references.increment (childName);1348return childName;1349}1350childDescription = InvocationUtils.invokeAndWait(new Callable<String>() {1351public String call() {1352return childContext.getAccessibleDescription ();1353}1354}, ac);1355if ( null != childDescription ) {1356debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from Accessible Description of a PUSH_BUTTON or TOGGLE_BUTTON object positioned to the left of the object.");1357references.increment (childDescription);1358return childDescription;1359}1360}1361}1362}1363}1364childIndex --;1365}1366childIndex = testIndex + 1;1367while (childIndex <= testIndexMax) {1368final int childIndexTemp = childIndex;1369final AccessibleContext parentContextInnerTemp = parentContext;1370final Accessible child = InvocationUtils.invokeAndWait(new Callable<Accessible>() {1371@Override1372public Accessible call() throws Exception {1373return parentContextInnerTemp.getAccessibleChild(childIndexTemp);1374}1375}, ac);1376if ( null != child ) {1377final AccessibleContext childContext = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {1378@Override1379public AccessibleContext call() throws Exception {1380return child.getAccessibleContext();1381}1382}, ac);1383if ( null != childContext ) {1384AccessibleRole childRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {1385@Override1386public AccessibleRole call() throws Exception {1387return childContext.getAccessibleRole();1388}1389}, ac);1390if ( ( AccessibleRole.PUSH_BUTTON == childRole ) ||1391( AccessibleRole.TOGGLE_BUTTON == childRole ) ) {1392childX = getAccessibleXcoordFromContext (childContext);1393childY = getAccessibleYcoordFromContext (childContext);1394childWidth = getAccessibleWidthFromContext (childContext);1395childHeight = getAccessibleHeightFromContext (childContext);1396if ( (childX < testX) &&1397((childY <= targetY) && (targetY <= (childY + childHeight))) ) {1398childName = InvocationUtils.invokeAndWait(new Callable<String>() {1399public String call() {1400return childContext.getAccessibleName();1401}1402}, ac);1403if ( null != childName ) {1404debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from Accessible Name of a PUSH_BUTTON or TOGGLE_BUTTON object positioned to the left of the object.");1405references.increment (childName);1406return childName;1407}1408childDescription = InvocationUtils.invokeAndWait(new Callable<String>() {1409public String call() {1410return childContext.getAccessibleDescription ();1411}1412}, ac);1413if ( null != childDescription ) {1414debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from Accessible Description of a PUSH_BUTTON or TOGGLE_BUTTON object positioned to the left of the object.");1415references.increment (childDescription);1416return childDescription;1417}1418}1419}1420}1421}1422childIndex ++;1423}1424}1425return null;1426} else {1427debugString ("[ERROR]: AccessBridge::getVirtualAccessibleNameFromContext error - ac == null.");1428return null;1429}1430}14311432/**1433* returns the AccessibleDescription from an AccessibleContext1434*/1435private String getAccessibleDescriptionFromContext(final AccessibleContext ac) {1436if (ac != null) {1437String s = InvocationUtils.invokeAndWait(new Callable<String>() {1438@Override1439public String call() throws Exception {1440return ac.getAccessibleDescription();1441}1442}, ac);1443if (s != null) {1444references.increment(s);1445debugString("[INFO]: Returning AccessibleDescription from Context: " + s);1446return s;1447}1448} else {1449debugString("[ERROR]: getAccessibleDescriptionFromContext; ac = null");1450}1451return null;1452}14531454/**1455* returns the AccessibleRole from an AccessibleContext1456*/1457private String getAccessibleRoleStringFromContext(final AccessibleContext ac) {1458if (ac != null) {1459AccessibleRole role = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {1460@Override1461public AccessibleRole call() throws Exception {1462return ac.getAccessibleRole();1463}1464}, ac);1465if (role != null) {1466String s = role.toDisplayString(Locale.US);1467if (s != null) {1468references.increment(s);1469debugString("[INFO]: Returning AccessibleRole from Context: " + s);1470return s;1471}1472}1473} else {1474debugString("[ERROR]: getAccessibleRoleStringFromContext; ac = null");1475}1476return null;1477}14781479/**1480* return the AccessibleRole from an AccessibleContext in the en_US locale1481*/1482private String getAccessibleRoleStringFromContext_en_US(final AccessibleContext ac) {1483return getAccessibleRoleStringFromContext(ac);1484}14851486/**1487* return the AccessibleStates from an AccessibleContext1488*/1489private String getAccessibleStatesStringFromContext(final AccessibleContext ac) {1490if (ac != null) {1491AccessibleStateSet stateSet = InvocationUtils.invokeAndWait(new Callable<AccessibleStateSet>() {1492@Override1493public AccessibleStateSet call() throws Exception {1494return ac.getAccessibleStateSet();1495}1496}, ac);1497if (stateSet != null) {1498String s = stateSet.toString();1499if (s != null &&1500s.indexOf(AccessibleState.MANAGES_DESCENDANTS.toDisplayString(Locale.US)) == -1) {1501// Indicate whether this component manages its own1502// children1503AccessibleRole role = InvocationUtils.invokeAndWait(() -> {1504return ac.getAccessibleRole();1505}, ac);1506if (role == AccessibleRole.LIST ||1507role == AccessibleRole.TABLE ||1508role == AccessibleRole.TREE) {1509s += ",";1510s += AccessibleState.MANAGES_DESCENDANTS.toDisplayString(Locale.US);1511}1512references.increment(s);1513debugString("[INFO]: Returning AccessibleStateSet from Context: " + s);1514return s;1515}1516}1517} else {1518debugString("[ERROR]: getAccessibleStatesStringFromContext; ac = null");1519}1520return null;1521}15221523/**1524* returns the AccessibleStates from an AccessibleContext in the en_US locale1525*/1526private String getAccessibleStatesStringFromContext_en_US(final AccessibleContext ac) {1527if (ac != null) {1528AccessibleStateSet stateSet = InvocationUtils.invokeAndWait(new Callable<AccessibleStateSet>() {1529@Override1530public AccessibleStateSet call() throws Exception {1531return ac.getAccessibleStateSet();1532}1533}, ac);1534if (stateSet != null) {1535String s = "";1536AccessibleState[] states = stateSet.toArray();1537if (states != null && states.length > 0) {1538s = states[0].toDisplayString(Locale.US);1539for (int i = 1; i < states.length; i++) {1540s = s + "," + states[i].toDisplayString(Locale.US);1541}1542}1543references.increment(s);1544debugString("[INFO]: Returning AccessibleStateSet en_US from Context: " + s);1545return s;1546}1547}1548debugString("[ERROR]: getAccessibleStatesStringFromContext; ac = null");1549return null;1550}15511552private int getNonVisibleChildrenCountTillIndex(AccessibleContext parentAC, int index) {1553if (parentAC != null && index >= 0 && index < parentAC.getAccessibleChildrenCount()) {1554int nonVisibleChildrenCount = 0;1555for (int i = 0; i <= index; i++) {1556if (!parentAC.getAccessibleChild(i).getAccessibleContext().getAccessibleStateSet().contains(AccessibleState.VISIBLE)) {1557nonVisibleChildrenCount++;1558}1559}1560return nonVisibleChildrenCount;1561}1562return 0;1563}15641565private Accessible getVisibleChildAtIndex(AccessibleContext parentAC, int index) {1566if (parentAC != null && index >= 0 && index < parentAC.getAccessibleChildrenCount()) {1567int visibleIndex = -1;1568int childrenCount = parentAC.getAccessibleChildrenCount();1569for (int i = 0; i <= childrenCount; i++) {1570Accessible child = parentAC.getAccessibleChild(i);1571if (child != null) {1572AccessibleContext ac = child.getAccessibleContext();1573if (ac != null && ac.getAccessibleStateSet().contains(AccessibleState.VISIBLE)) {1574visibleIndex++;1575}1576if (visibleIndex == index) {1577return child;1578}1579}1580}1581}1582return null;1583}1584/**1585* returns the AccessibleParent from an AccessibleContext1586*/1587private AccessibleContext getAccessibleParentFromContext(final AccessibleContext ac) {1588if (ac==null)1589return null;1590return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {1591@Override1592public AccessibleContext call() throws Exception {1593Accessible a = ac.getAccessibleParent();1594if (a != null) {1595AccessibleContext apc = a.getAccessibleContext();1596if (apc != null) {1597return apc;1598}1599}1600return null;1601}1602}, ac);1603}16041605/**1606* returns the AccessibleIndexInParent from an AccessibleContext1607*/1608private int getAccessibleIndexInParentFromContext(final AccessibleContext ac) {1609if (ac==null)1610return -1;1611return InvocationUtils.invokeAndWait(new Callable<Integer>() {1612@Override1613public Integer call() throws Exception {1614int indexInParent = ac.getAccessibleIndexInParent();1615Accessible parent = ac.getAccessibleParent();1616if (parent != null) {1617indexInParent -= getNonVisibleChildrenCountTillIndex(parent.getAccessibleContext(), indexInParent);1618}1619return indexInParent;1620}1621}, ac);1622}16231624/**1625* returns the AccessibleChild count from an AccessibleContext1626*/1627private int getAccessibleChildrenCountFromContext(final AccessibleContext ac) {1628if (ac==null)1629return -1;1630return InvocationUtils.invokeAndWait(new Callable<Integer>() {1631@Override1632public Integer call() throws Exception {1633int childrenCount = ac.getAccessibleChildrenCount();1634return childrenCount - getNonVisibleChildrenCountTillIndex(ac, childrenCount - 1);1635}1636}, ac);1637}16381639/**1640* returns the AccessibleChild Context from an AccessibleContext1641*/1642private AccessibleContext getAccessibleChildFromContext(final AccessibleContext ac, final int index) {16431644if (ac == null) {1645return null;1646}16471648final JTable table = InvocationUtils.invokeAndWait(new Callable<JTable>() {1649@Override1650public JTable call() throws Exception {1651// work-around for AccessibleJTable.getCurrentAccessibleContext returning1652// wrong renderer component when cell contains more than one component1653Accessible parent = ac.getAccessibleParent();1654if (parent != null) {1655int indexInParent = ac.getAccessibleIndexInParent();1656Accessible child =1657parent.getAccessibleContext().getAccessibleChild(indexInParent);1658if (child instanceof JTable) {1659return (JTable) child;1660}1661}1662return null;1663}1664}, ac);16651666if (table == null) {1667return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {1668@Override1669public AccessibleContext call() throws Exception {1670Accessible a = getVisibleChildAtIndex(ac, index);1671if (a != null) {1672return a.getAccessibleContext();1673}1674return null;1675}1676}, ac);1677}16781679final AccessibleTable at = getAccessibleTableFromContext(ac);16801681final int row = getAccessibleTableRow(at, index);1682final int column = getAccessibleTableColumn(at, index);16831684return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {1685@Override1686public AccessibleContext call() throws Exception {1687TableCellRenderer renderer = table.getCellRenderer(row, column);1688if (renderer == null) {1689Class<?> columnClass = table.getColumnClass(column);1690renderer = table.getDefaultRenderer(columnClass);1691}1692Component component =1693renderer.getTableCellRendererComponent(table, table.getValueAt(row, column),1694false, false, row, column);1695if (component instanceof Accessible) {1696return component.getAccessibleContext();1697}1698return null;1699}1700}, ac);1701}17021703/**1704* returns the AccessibleComponent bounds on screen from an AccessibleContext1705*/1706private Rectangle getAccessibleBoundsOnScreenFromContext(final AccessibleContext ac) {1707if(ac==null)1708return null;1709return InvocationUtils.invokeAndWait(new Callable<Rectangle>() {1710@Override1711public Rectangle call() throws Exception {1712AccessibleComponent acmp = ac.getAccessibleComponent();1713if (acmp != null) {1714Rectangle r = acmp.getBounds();1715if (r != null) {1716try {1717Point p = acmp.getLocationOnScreen();1718if (p != null) {1719r.x = p.x;1720r.y = p.y;1721return r;1722}1723} catch (Exception e) {1724return null;1725}1726}1727}1728return null;1729}1730}, ac);1731}17321733/**1734* returns the AccessibleComponent x-coord from an AccessibleContext1735*/1736private int getAccessibleXcoordFromContext(AccessibleContext ac) {1737if (ac != null) {1738Rectangle r = getAccessibleBoundsOnScreenFromContext(ac);1739if (r != null) {1740debugString("[INFO]: Returning Accessible x coord from Context: " + r.x);1741return r.x;1742}1743} else {1744debugString("[ERROR]: getAccessibleXcoordFromContext ac = null");1745}1746return -1;1747}17481749/**1750* returns the AccessibleComponent y-coord from an AccessibleContext1751*/1752private int getAccessibleYcoordFromContext(AccessibleContext ac) {1753debugString("[INFO]: getAccessibleYcoordFromContext() called");1754if (ac != null) {1755Rectangle r = getAccessibleBoundsOnScreenFromContext(ac);1756if (r != null) {1757return r.y;1758}1759} else {1760debugString("[ERROR]: getAccessibleYcoordFromContext; ac = null");1761}1762return -1;1763}17641765/**1766* returns the AccessibleComponent height from an AccessibleContext1767*/1768private int getAccessibleHeightFromContext(AccessibleContext ac) {1769if (ac != null) {1770Rectangle r = getAccessibleBoundsOnScreenFromContext(ac);1771if (r != null) {1772return r.height;1773}1774} else {1775debugString("[ERROR]: getAccessibleHeightFromContext; ac = null");1776}1777return -1;1778}17791780/**1781* returns the AccessibleComponent width from an AccessibleContext1782*/1783private int getAccessibleWidthFromContext(AccessibleContext ac) {1784if (ac != null) {1785Rectangle r = getAccessibleBoundsOnScreenFromContext(ac);1786if (r != null) {1787return r.width;1788}1789} else {1790debugString("[ERROR]: getAccessibleWidthFromContext; ac = null");1791}1792return -1;1793}179417951796/**1797* returns the AccessibleComponent from an AccessibleContext1798*/1799private AccessibleComponent getAccessibleComponentFromContext(AccessibleContext ac) {1800if (ac != null) {1801AccessibleComponent acmp = InvocationUtils.invokeAndWait(() -> {1802return ac.getAccessibleComponent();1803}, ac);1804if (acmp != null) {1805debugString("[INFO]: Returning AccessibleComponent Context");1806return acmp;1807}1808} else {1809debugString("[ERROR]: getAccessibleComponentFromContext; ac = null");1810}1811return null;1812}18131814/**1815* returns the AccessibleAction from an AccessibleContext1816*/1817private AccessibleAction getAccessibleActionFromContext(final AccessibleContext ac) {1818debugString("[INFO]: Returning AccessibleAction Context");1819return ac == null ? null : InvocationUtils.invokeAndWait(new Callable<AccessibleAction>() {1820@Override1821public AccessibleAction call() throws Exception {1822return ac.getAccessibleAction();1823}1824}, ac);1825}18261827/**1828* returns the AccessibleSelection from an AccessibleContext1829*/1830private AccessibleSelection getAccessibleSelectionFromContext(final AccessibleContext ac) {1831return ac == null ? null : InvocationUtils.invokeAndWait(new Callable<AccessibleSelection>() {1832@Override1833public AccessibleSelection call() throws Exception {1834return ac.getAccessibleSelection();1835}1836}, ac);1837}18381839/**1840* return the AccessibleText from an AccessibleContext1841*/1842private AccessibleText getAccessibleTextFromContext(final AccessibleContext ac) {1843return ac == null ? null : InvocationUtils.invokeAndWait(new Callable<AccessibleText>() {1844@Override1845public AccessibleText call() throws Exception {1846return ac.getAccessibleText();1847}1848}, ac);1849}18501851/**1852* return the AccessibleComponent from an AccessibleContext1853*/1854private AccessibleValue getAccessibleValueFromContext(final AccessibleContext ac) {1855return ac == null ? null : InvocationUtils.invokeAndWait(new Callable<AccessibleValue>() {1856@Override1857public AccessibleValue call() throws Exception {1858return ac.getAccessibleValue();1859}1860}, ac);1861}18621863/* ===== AccessibleText methods ===== */18641865/**1866* returns the bounding rectangle for the text cursor1867* XXX1868*/1869private Rectangle getCaretLocation(final AccessibleContext ac) {1870debugString("[INFO]: getCaretLocation");1871if (ac==null)1872return null;1873return InvocationUtils.invokeAndWait(new Callable<Rectangle>() {1874@Override1875public Rectangle call() throws Exception {1876// workaround for JAAPI not returning cursor bounding rectangle1877Rectangle r = null;1878Accessible parent = ac.getAccessibleParent();1879if (parent instanceof Accessible) {1880int indexInParent = ac.getAccessibleIndexInParent();1881Accessible child =1882parent.getAccessibleContext().getAccessibleChild(indexInParent);18831884if (child instanceof JTextComponent) {1885JTextComponent text = (JTextComponent) child;1886try {1887r = text.modelToView(text.getCaretPosition());1888if (r != null) {1889Point p = text.getLocationOnScreen();1890r.translate(p.x, p.y);1891}1892} catch (BadLocationException ble) {1893}1894}1895}1896return r;1897}1898}, ac);1899}19001901/**1902* returns the x-coordinate for the text cursor rectangle1903*/1904private int getCaretLocationX(AccessibleContext ac) {1905Rectangle r = getCaretLocation(ac);1906if (r != null) {1907return r.x;1908} else {1909return -1;1910}1911}19121913/**1914* returns the y-coordinate for the text cursor rectangle1915*/1916private int getCaretLocationY(AccessibleContext ac) {1917Rectangle r = getCaretLocation(ac);1918if (r != null) {1919return r.y;1920} else {1921return -1;1922}1923}19241925/**1926* returns the height for the text cursor rectangle1927*/1928private int getCaretLocationHeight(AccessibleContext ac) {1929Rectangle r = getCaretLocation(ac);1930if (r != null) {1931return r.height;1932} else {1933return -1;1934}1935}19361937/**1938* returns the width for the text cursor rectangle1939*/1940private int getCaretLocationWidth(AccessibleContext ac) {1941Rectangle r = getCaretLocation(ac);1942if (r != null) {1943return r.width;1944} else {1945return -1;1946}1947}19481949/**1950* returns the character count from an AccessibleContext1951*/1952private int getAccessibleCharCountFromContext(final AccessibleContext ac) {1953if (ac==null)1954return -1;1955return InvocationUtils.invokeAndWait(new Callable<Integer>() {1956@Override1957public Integer call() throws Exception {1958AccessibleText at = ac.getAccessibleText();1959if (at != null) {1960return at.getCharCount();1961}1962return -1;1963}1964}, ac);1965}19661967/**1968* returns the caret position from an AccessibleContext1969*/1970private int getAccessibleCaretPositionFromContext(final AccessibleContext ac) {1971if (ac==null)1972return -1;1973return InvocationUtils.invokeAndWait(new Callable<Integer>() {1974@Override1975public Integer call() throws Exception {1976AccessibleText at = ac.getAccessibleText();1977if (at != null) {1978return at.getCaretPosition();1979}1980return -1;1981}1982}, ac);1983}19841985/**1986* Return the index at a specific point from an AccessibleContext1987* Point(x, y) is in screen coordinates.1988*/1989private int getAccessibleIndexAtPointFromContext(final AccessibleContext ac,1990final int x, final int y) {1991debugString("[INFO]: getAccessibleIndexAtPointFromContext: x = "+x+"; y = "+y);1992if (ac==null)1993return -1;1994return InvocationUtils.invokeAndWait(new Callable<Integer>() {1995@Override1996public Integer call() throws Exception {1997AccessibleText at = ac.getAccessibleText();1998AccessibleComponent acomp = ac.getAccessibleComponent();1999if (at != null && acomp != null) {2000// Convert x and y from screen coordinates to2001// local coordinates.2002try {2003Point p = acomp.getLocationOnScreen();2004int x1, y1;2005if (p != null) {2006x1 = x - p.x;2007if (x1 < 0) {2008x1 = 0;2009}2010y1 = y - p.y;2011if (y1 < 0) {2012y1 = 0;2013}20142015Point newPoint = new Point(x1, y1);2016int indexAtPoint = at.getIndexAtPoint(new Point(x1, y1));2017return indexAtPoint;2018}2019} catch (Exception e) {2020}2021}2022return -1;2023}2024}, ac);2025}20262027/**2028* return the letter at a specific point from an AccessibleContext2029*/2030private String getAccessibleLetterAtIndexFromContext(final AccessibleContext ac, final int index) {2031if (ac != null) {2032String s = InvocationUtils.invokeAndWait(new Callable<String>() {2033@Override2034public String call() throws Exception {2035AccessibleText at = ac.getAccessibleText();2036if (at == null) return null;2037return at.getAtIndex(AccessibleText.CHARACTER, index);2038}2039}, ac);2040if (s != null) {2041references.increment(s);2042return s;2043}2044} else {2045debugString("[ERROR]: getAccessibleLetterAtIndexFromContext; ac = null");2046}2047return null;2048}20492050/**2051* return the word at a specific point from an AccessibleContext2052*/2053private String getAccessibleWordAtIndexFromContext(final AccessibleContext ac, final int index) {2054if (ac != null) {2055String s = InvocationUtils.invokeAndWait(new Callable<String>() {2056@Override2057public String call() throws Exception {2058AccessibleText at = ac.getAccessibleText();2059if (at == null) return null;2060return at.getAtIndex(AccessibleText.WORD, index);2061}2062}, ac);2063if (s != null) {2064references.increment(s);2065return s;2066}2067} else {2068debugString("[ERROR]: getAccessibleWordAtIndexFromContext; ac = null");2069}2070return null;2071}20722073/**2074* return the sentence at a specific point from an AccessibleContext2075*/2076private String getAccessibleSentenceAtIndexFromContext(final AccessibleContext ac, final int index) {2077if (ac != null) {2078String s = InvocationUtils.invokeAndWait(new Callable<String>() {2079@Override2080public String call() throws Exception {2081AccessibleText at = ac.getAccessibleText();2082if (at == null) return null;2083return at.getAtIndex(AccessibleText.SENTENCE, index);2084}2085}, ac);2086if (s != null) {2087references.increment(s);2088return s;2089}2090} else {2091debugString("[ERROR]: getAccessibleSentenceAtIndexFromContext; ac = null");2092}2093return null;2094}20952096/**2097* return the text selection start from an AccessibleContext2098*/2099private int getAccessibleTextSelectionStartFromContext(final AccessibleContext ac) {2100if (ac == null) return -1;2101return InvocationUtils.invokeAndWait(new Callable<Integer>() {2102@Override2103public Integer call() throws Exception {2104AccessibleText at = ac.getAccessibleText();2105if (at != null) {2106return at.getSelectionStart();2107}2108return -1;2109}2110}, ac);2111}21122113/**2114* return the text selection end from an AccessibleContext2115*/2116private int getAccessibleTextSelectionEndFromContext(final AccessibleContext ac) {2117if (ac == null)2118return -1;2119return InvocationUtils.invokeAndWait(new Callable<Integer>() {2120@Override2121public Integer call() throws Exception {2122AccessibleText at = ac.getAccessibleText();2123if (at != null) {2124return at.getSelectionEnd();2125}2126return -1;2127}2128}, ac);2129}21302131/**2132* return the selected text from an AccessibleContext2133*/2134private String getAccessibleTextSelectedTextFromContext(final AccessibleContext ac) {2135if (ac != null) {2136String s = InvocationUtils.invokeAndWait(new Callable<String>() {2137@Override2138public String call() throws Exception {2139AccessibleText at = ac.getAccessibleText();2140if (at == null) return null;2141return at.getSelectedText();2142}2143}, ac);2144if (s != null) {2145references.increment(s);2146return s;2147}2148} else {2149debugString("[ERROR]: getAccessibleTextSelectedTextFromContext; ac = null");2150}2151return null;2152}21532154/**2155* return the attribute string at a given index from an AccessibleContext2156*/2157private String getAccessibleAttributesAtIndexFromContext(final AccessibleContext ac,2158final int index) {2159if (ac == null)2160return null;2161AttributeSet as = InvocationUtils.invokeAndWait(new Callable<AttributeSet>() {2162@Override2163public AttributeSet call() throws Exception {2164AccessibleText at = ac.getAccessibleText();2165if (at != null) {2166return at.getCharacterAttribute(index);2167}2168return null;2169}2170}, ac);2171String s = expandStyleConstants(as);2172if (s != null) {2173references.increment(s);2174return s;2175}2176return null;2177}21782179/**2180* Get line info: left index of line2181*2182* algorithm: cast back, doubling each time,2183* 'till find line boundaries2184*2185* return -1 if we can't get the info (e.g. index or at passed in2186* is bogus; etc.)2187*/2188private int getAccessibleTextLineLeftBoundsFromContext(final AccessibleContext ac,2189final int index) {2190if (ac == null)2191return -1;2192return InvocationUtils.invokeAndWait(new Callable<Integer>() {2193@Override2194public Integer call() throws Exception {2195AccessibleText at = ac.getAccessibleText();2196if (at != null) {2197int lineStart;2198int offset;2199Rectangle charRect;2200Rectangle indexRect = at.getCharacterBounds(index);2201int textLen = at.getCharCount();2202if (indexRect == null) {2203return -1;2204}2205// find the start of the line2206//2207offset = 1;2208lineStart = index - offset < 0 ? 0 : index - offset;2209charRect = at.getCharacterBounds(lineStart);2210// slouch behind beginning of line2211while (charRect != null2212&& charRect.y >= indexRect.y2213&& lineStart > 0) {2214offset = offset << 1;2215lineStart = index - offset < 0 ? 0 : index - offset;2216charRect = at.getCharacterBounds(lineStart);2217}2218if (lineStart == 0) { // special case: we're on the first line!2219// we found it!2220} else {2221offset = offset >> 1; // know boundary within last expansion2222// ground forward to beginning of line2223while (offset > 0) {2224charRect = at.getCharacterBounds(lineStart + offset);2225if (charRect.y < indexRect.y) { // still before line2226lineStart += offset;2227} else {2228// leave lineStart alone, it's close!2229}2230offset = offset >> 1;2231}2232// subtract one 'cause we're already too far...2233lineStart += 1;2234}2235return lineStart;2236}2237return -1;2238}2239}, ac);2240}22412242/**2243* Get line info: right index of line2244*2245* algorithm: cast back, doubling each time,2246* 'till find line boundaries2247*2248* return -1 if we can't get the info (e.g. index or at passed in2249* is bogus; etc.)2250*/2251private int getAccessibleTextLineRightBoundsFromContext(final AccessibleContext ac, final int index) {2252if(ac == null)2253return -1;2254return InvocationUtils.invokeAndWait(new Callable<Integer>() {2255@Override2256public Integer call() throws Exception {2257AccessibleText at = ac.getAccessibleText();2258if (at != null) {2259int lineEnd;2260int offset;2261Rectangle charRect;2262Rectangle indexRect = at.getCharacterBounds(index);2263int textLen = at.getCharCount();2264if (indexRect == null) {2265return -1;2266}2267// find the end of the line2268//2269offset = 1;2270lineEnd = index + offset > textLen - 12271? textLen - 1 : index + offset;2272charRect = at.getCharacterBounds(lineEnd);2273// push past end of line2274while (charRect != null &&2275charRect.y <= indexRect.y &&2276lineEnd < textLen - 1) {2277offset = offset << 1;2278lineEnd = index + offset > textLen - 12279? textLen - 1 : index + offset;2280charRect = at.getCharacterBounds(lineEnd);2281}2282if (lineEnd == textLen - 1) { // special case: on the last line!2283// we found it!2284} else {2285offset = offset >> 1; // know boundary within last expansion2286// pull back to end of line2287while (offset > 0) {2288charRect = at.getCharacterBounds(lineEnd - offset);2289if (charRect.y > indexRect.y) { // still beyond line2290lineEnd -= offset;2291} else {2292// leave lineEnd alone, it's close!2293}2294offset = offset >> 1;2295}2296// subtract one 'cause we're already too far...2297lineEnd -= 1;2298}2299return lineEnd;2300}2301return -1;2302}2303}, ac);2304}23052306/**2307* Get a range of text; null if indicies are bogus2308*/2309private String getAccessibleTextRangeFromContext(final AccessibleContext ac,2310final int start, final int end) {2311String s = InvocationUtils.invokeAndWait(new Callable<String>() {2312@Override2313public String call() throws Exception {2314if (ac != null) {2315AccessibleText at = ac.getAccessibleText();2316if (at != null) {2317// start - end is inclusive2318if (start > end) {2319return null;2320}2321if (end >= at.getCharCount()) {2322return null;2323}2324StringBuffer buf = new StringBuffer(end - start + 1);2325for (int i = start; i <= end; i++) {2326buf.append(at.getAtIndex(AccessibleText.CHARACTER, i));2327}2328return buf.toString();2329}2330}2331return null;2332}2333}, ac);2334if (s != null) {2335references.increment(s);2336return s;2337} else {2338return null;2339}2340}23412342/**2343* return the AttributeSet object at a given index from an AccessibleContext2344*/2345private AttributeSet getAccessibleAttributeSetAtIndexFromContext(final AccessibleContext ac,2346final int index) {2347return InvocationUtils.invokeAndWait(new Callable<AttributeSet>() {2348@Override2349public AttributeSet call() throws Exception {2350if (ac != null) {2351AccessibleText at = ac.getAccessibleText();2352if (at != null) {2353AttributeSet as = at.getCharacterAttribute(index);2354if (as != null) {2355AccessBridge.this.references.increment(as);2356return as;2357}2358}2359}2360return null;2361}2362}, ac);2363}236423652366/**2367* return the bounding rectangle at index from an AccessibleContext2368*/2369private Rectangle getAccessibleTextRectAtIndexFromContext(final AccessibleContext ac,2370final int index) {2371// want to do this in global coords, so need to combine w/ac global coords2372Rectangle r = InvocationUtils.invokeAndWait(new Callable<Rectangle>() {2373@Override2374public Rectangle call() throws Exception {2375// want to do this in global coords, so need to combine w/ac global coords2376if (ac != null) {2377AccessibleText at = ac.getAccessibleText();2378if (at != null) {2379Rectangle rect = at.getCharacterBounds(index);2380if (rect != null) {2381String s = at.getAtIndex(AccessibleText.CHARACTER, index);2382if (s != null && s.equals("\n")) {2383rect.width = 0;2384}2385return rect;2386}2387}2388}2389return null;2390}2391}, ac);2392Rectangle acRect = getAccessibleBoundsOnScreenFromContext(ac);2393if (r != null && acRect != null) {2394r.translate(acRect.x, acRect.y);2395return r;2396}2397return null;2398}23992400/**2401* return the AccessibleText character x-coord at index from an AccessibleContext2402*/2403private int getAccessibleXcoordTextRectAtIndexFromContext(AccessibleContext ac, int index) {2404if (ac != null) {2405Rectangle r = getAccessibleTextRectAtIndexFromContext(ac, index);2406if (r != null) {2407return r.x;2408}2409} else {2410debugString("[ERROR]: getAccessibleXcoordTextRectAtIndexFromContext; ac = null");2411}2412return -1;2413}24142415/**2416* return the AccessibleText character y-coord at index from an AccessibleContext2417*/2418private int getAccessibleYcoordTextRectAtIndexFromContext(AccessibleContext ac, int index) {2419if (ac != null) {2420Rectangle r = getAccessibleTextRectAtIndexFromContext(ac, index);2421if (r != null) {2422return r.y;2423}2424} else {2425debugString("[ERROR]: getAccessibleYcoordTextRectAtIndexFromContext; ac = null");2426}2427return -1;2428}24292430/**2431* return the AccessibleText character height at index from an AccessibleContext2432*/2433private int getAccessibleHeightTextRectAtIndexFromContext(AccessibleContext ac, int index) {2434if (ac != null) {2435Rectangle r = getAccessibleTextRectAtIndexFromContext(ac, index);2436if (r != null) {2437return r.height;2438}2439} else {2440debugString("[ERROR]: getAccessibleHeightTextRectAtIndexFromContext; ac = null");2441}2442return -1;2443}24442445/**2446* return the AccessibleText character width at index from an AccessibleContext2447*/2448private int getAccessibleWidthTextRectAtIndexFromContext(AccessibleContext ac, int index) {2449if (ac != null) {2450Rectangle r = getAccessibleTextRectAtIndexFromContext(ac, index);2451if (r != null) {2452return r.width;2453}2454} else {2455debugString("[ERROR]: getAccessibleWidthTextRectAtIndexFromContext; ac = null");2456}2457return -1;2458}24592460/* ===== AttributeSet methods for AccessibleText ===== */24612462/**2463* return the bold setting from an AttributeSet2464*/2465private boolean getBoldFromAttributeSet(AttributeSet as) {2466if (as != null) {2467return StyleConstants.isBold(as);2468} else {2469debugString("[ERROR]: getBoldFromAttributeSet; as = null");2470}2471return false;2472}24732474/**2475* return the italic setting from an AttributeSet2476*/2477private boolean getItalicFromAttributeSet(AttributeSet as) {2478if (as != null) {2479return StyleConstants.isItalic(as);2480} else {2481debugString("[ERROR]: getItalicFromAttributeSet; as = null");2482}2483return false;2484}24852486/**2487* return the underline setting from an AttributeSet2488*/2489private boolean getUnderlineFromAttributeSet(AttributeSet as) {2490if (as != null) {2491return StyleConstants.isUnderline(as);2492} else {2493debugString("[ERROR]: getUnderlineFromAttributeSet; as = null");2494}2495return false;2496}24972498/**2499* return the strikethrough setting from an AttributeSet2500*/2501private boolean getStrikethroughFromAttributeSet(AttributeSet as) {2502if (as != null) {2503return StyleConstants.isStrikeThrough(as);2504} else {2505debugString("[ERROR]: getStrikethroughFromAttributeSet; as = null");2506}2507return false;2508}25092510/**2511* return the superscript setting from an AttributeSet2512*/2513private boolean getSuperscriptFromAttributeSet(AttributeSet as) {2514if (as != null) {2515return StyleConstants.isSuperscript(as);2516} else {2517debugString("[ERROR]: getSuperscriptFromAttributeSet; as = null");2518}2519return false;2520}25212522/**2523* return the subscript setting from an AttributeSet2524*/2525private boolean getSubscriptFromAttributeSet(AttributeSet as) {2526if (as != null) {2527return StyleConstants.isSubscript(as);2528} else {2529debugString("[ERROR]: getSubscriptFromAttributeSet; as = null");2530}2531return false;2532}25332534/**2535* return the background color from an AttributeSet2536*/2537private String getBackgroundColorFromAttributeSet(AttributeSet as) {2538if (as != null) {2539String s = StyleConstants.getBackground(as).toString();2540if (s != null) {2541references.increment(s);2542return s;2543}2544} else {2545debugString("[ERROR]: getBackgroundColorFromAttributeSet; as = null");2546}2547return null;2548}25492550/**2551* return the foreground color from an AttributeSet2552*/2553private String getForegroundColorFromAttributeSet(AttributeSet as) {2554if (as != null) {2555String s = StyleConstants.getForeground(as).toString();2556if (s != null) {2557references.increment(s);2558return s;2559}2560} else {2561debugString("[ERROR]: getForegroundColorFromAttributeSet; as = null");2562}2563return null;2564}25652566/**2567* return the font family from an AttributeSet2568*/2569private String getFontFamilyFromAttributeSet(AttributeSet as) {2570if (as != null) {2571String s = StyleConstants.getFontFamily(as).toString();2572if (s != null) {2573references.increment(s);2574return s;2575}2576} else {2577debugString("[ERROR]: getFontFamilyFromAttributeSet; as = null");2578}2579return null;2580}25812582/**2583* return the font size from an AttributeSet2584*/2585private int getFontSizeFromAttributeSet(AttributeSet as) {2586if (as != null) {2587return StyleConstants.getFontSize(as);2588} else {2589debugString("[ERROR]: getFontSizeFromAttributeSet; as = null");2590}2591return -1;2592}25932594/**2595* return the alignment from an AttributeSet2596*/2597private int getAlignmentFromAttributeSet(AttributeSet as) {2598if (as != null) {2599return StyleConstants.getAlignment(as);2600} else {2601debugString("[ERROR]: getAlignmentFromAttributeSet; as = null");2602}2603return -1;2604}26052606/**2607* return the BiDi level from an AttributeSet2608*/2609private int getBidiLevelFromAttributeSet(AttributeSet as) {2610if (as != null) {2611return StyleConstants.getBidiLevel(as);2612} else {2613debugString("[ERROR]: getBidiLevelFromAttributeSet; as = null");2614}2615return -1;2616}261726182619/**2620* return the first line indent from an AttributeSet2621*/2622private float getFirstLineIndentFromAttributeSet(AttributeSet as) {2623if (as != null) {2624return StyleConstants.getFirstLineIndent(as);2625} else {2626debugString("[ERROR]: getFirstLineIndentFromAttributeSet; as = null");2627}2628return -1;2629}26302631/**2632* return the left indent from an AttributeSet2633*/2634private float getLeftIndentFromAttributeSet(AttributeSet as) {2635if (as != null) {2636return StyleConstants.getLeftIndent(as);2637} else {2638debugString("[ERROR]: getLeftIndentFromAttributeSet; as = null");2639}2640return -1;2641}26422643/**2644* return the right indent from an AttributeSet2645*/2646private float getRightIndentFromAttributeSet(AttributeSet as) {2647if (as != null) {2648return StyleConstants.getRightIndent(as);2649} else {2650debugString("[ERROR]: getRightIndentFromAttributeSet; as = null");2651}2652return -1;2653}26542655/**2656* return the line spacing from an AttributeSet2657*/2658private float getLineSpacingFromAttributeSet(AttributeSet as) {2659if (as != null) {2660return StyleConstants.getLineSpacing(as);2661} else {2662debugString("[ERROR]: getLineSpacingFromAttributeSet; as = null");2663}2664return -1;2665}26662667/**2668* return the space above from an AttributeSet2669*/2670private float getSpaceAboveFromAttributeSet(AttributeSet as) {2671if (as != null) {2672return StyleConstants.getSpaceAbove(as);2673} else {2674debugString("[ERROR]: getSpaceAboveFromAttributeSet; as = null");2675}2676return -1;2677}26782679/**2680* return the space below from an AttributeSet2681*/2682private float getSpaceBelowFromAttributeSet(AttributeSet as) {2683if (as != null) {2684return StyleConstants.getSpaceBelow(as);2685} else {2686debugString("[ERROR]: getSpaceBelowFromAttributeSet; as = null");2687}2688return -1;2689}26902691/**2692* Enumerate all StyleConstants in the AttributeSet2693*2694* We need to check explicitly, 'cause of the HTML package conversion2695* mechanism (they may not be stored as StyleConstants, just translated2696* to them when asked).2697*2698* (Use convenience methods where they are defined...)2699*2700* Not checking the following (which the IBM SNS guidelines says2701* should be defined):2702* - ComponentElementName2703* - IconElementName2704* - NameAttribute2705* - ResolveAttribute2706*/2707private String expandStyleConstants(AttributeSet as) {2708Color c;2709Object o;2710String attrString = "";27112712// ---------- check for various Character Constants27132714attrString += "BidiLevel = " + StyleConstants.getBidiLevel(as);27152716final Component comp = StyleConstants.getComponent(as);2717if (comp != null) {2718if (comp instanceof Accessible) {2719final AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {2720@Override2721public AccessibleContext call() throws Exception {2722return comp.getAccessibleContext();2723}2724}, comp);2725if (ac != null) {2726attrString += "; Accessible Component = " + InvocationUtils.invokeAndWait(new Callable<String>() {2727@Override2728public String call() throws Exception {2729return ac.getAccessibleName();2730}2731}, ac);2732} else {2733attrString += "; Innaccessible Component = " + comp;2734}2735} else {2736attrString += "; Innaccessible Component = " + comp;2737}2738}27392740Icon i = StyleConstants.getIcon(as);2741if (i != null) {2742if (i instanceof ImageIcon) {2743attrString += "; ImageIcon = " + ((ImageIcon) i).getDescription();2744} else {2745attrString += "; Icon = " + i;2746}2747}27482749attrString += "; FontFamily = " + StyleConstants.getFontFamily(as);27502751attrString += "; FontSize = " + StyleConstants.getFontSize(as);27522753if (StyleConstants.isBold(as)) {2754attrString += "; bold";2755}27562757if (StyleConstants.isItalic(as)) {2758attrString += "; italic";2759}27602761if (StyleConstants.isUnderline(as)) {2762attrString += "; underline";2763}27642765if (StyleConstants.isStrikeThrough(as)) {2766attrString += "; strikethrough";2767}27682769if (StyleConstants.isSuperscript(as)) {2770attrString += "; superscript";2771}27722773if (StyleConstants.isSubscript(as)) {2774attrString += "; subscript";2775}27762777c = StyleConstants.getForeground(as);2778if (c != null) {2779attrString += "; Foreground = " + c;2780}27812782c = StyleConstants.getBackground(as);2783if (c != null) {2784attrString += "; Background = " + c;2785}27862787attrString += "; FirstLineIndent = " + StyleConstants.getFirstLineIndent(as);27882789attrString += "; RightIndent = " + StyleConstants.getRightIndent(as);27902791attrString += "; LeftIndent = " + StyleConstants.getLeftIndent(as);27922793attrString += "; LineSpacing = " + StyleConstants.getLineSpacing(as);27942795attrString += "; SpaceAbove = " + StyleConstants.getSpaceAbove(as);27962797attrString += "; SpaceBelow = " + StyleConstants.getSpaceBelow(as);27982799attrString += "; Alignment = " + StyleConstants.getAlignment(as);28002801TabSet ts = StyleConstants.getTabSet(as);2802if (ts != null) {2803attrString += "; TabSet = " + ts;2804}28052806return attrString;2807}280828092810/* ===== AccessibleValue methods ===== */28112812/**2813* return the AccessibleValue current value from an AccessibleContext2814* returned using a String 'cause the value is a java Number2815*2816*/2817private String getCurrentAccessibleValueFromContext(final AccessibleContext ac) {2818if (ac != null) {2819final Number value = InvocationUtils.invokeAndWait(new Callable<Number>() {2820@Override2821public Number call() throws Exception {2822AccessibleValue av = ac.getAccessibleValue();2823if (av == null) return null;2824return av.getCurrentAccessibleValue();2825}2826}, ac);2827if (value != null) {2828String s = value.toString();2829if (s != null) {2830references.increment(s);2831return s;2832}2833}2834} else {2835debugString("[ERROR]: getCurrentAccessibleValueFromContext; ac = null");2836}2837return null;2838}28392840/**2841* return the AccessibleValue maximum value from an AccessibleContext2842* returned using a String 'cause the value is a java Number2843*2844*/2845private String getMaximumAccessibleValueFromContext(final AccessibleContext ac) {2846if (ac != null) {2847final Number value = InvocationUtils.invokeAndWait(new Callable<Number>() {2848@Override2849public Number call() throws Exception {2850AccessibleValue av = ac.getAccessibleValue();2851if (av == null) return null;2852return av.getMaximumAccessibleValue();2853}2854}, ac);2855if (value != null) {2856String s = value.toString();2857if (s != null) {2858references.increment(s);2859return s;2860}2861}2862} else {2863debugString("[ERROR]: getMaximumAccessibleValueFromContext; ac = null");2864}2865return null;2866}28672868/**2869* return the AccessibleValue minimum value from an AccessibleContext2870* returned using a String 'cause the value is a java Number2871*2872*/2873private String getMinimumAccessibleValueFromContext(final AccessibleContext ac) {2874if (ac != null) {2875final Number value = InvocationUtils.invokeAndWait(new Callable<Number>() {2876@Override2877public Number call() throws Exception {2878AccessibleValue av = ac.getAccessibleValue();2879if (av == null) return null;2880return av.getMinimumAccessibleValue();2881}2882}, ac);2883if (value != null) {2884String s = value.toString();2885if (s != null) {2886references.increment(s);2887return s;2888}2889}2890} else {2891debugString("[ERROR]: getMinimumAccessibleValueFromContext; ac = null");2892}2893return null;2894}289528962897/* ===== AccessibleSelection methods ===== */28982899/**2900* add to the AccessibleSelection of an AccessibleContext child i2901*2902*/2903private void addAccessibleSelectionFromContext(final AccessibleContext ac, final int i) {2904try {2905InvocationUtils.invokeAndWait(new Callable<Object>() {2906@Override2907public Object call() throws Exception {2908if (ac != null) {2909AccessibleSelection as = ac.getAccessibleSelection();2910if (as != null) {2911as.addAccessibleSelection(i);2912}2913}2914return null;2915}2916}, ac);2917} catch(Exception e){}2918}29192920/**2921* clear all of the AccessibleSelection of an AccessibleContex2922*2923*/2924private void clearAccessibleSelectionFromContext(final AccessibleContext ac) {2925try {2926InvocationUtils.invokeAndWait(new Callable<Object>() {2927@Override2928public Object call() throws Exception {2929AccessibleSelection as = ac.getAccessibleSelection();2930if (as != null) {2931as.clearAccessibleSelection();2932}2933return null;2934}2935}, ac);2936} catch(Exception e){}29372938}29392940/**2941* get the AccessibleContext of the i-th AccessibleSelection of an AccessibleContext2942*2943*/2944private AccessibleContext getAccessibleSelectionFromContext(final AccessibleContext ac, final int i) {2945return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {2946@Override2947public AccessibleContext call() throws Exception {2948if (ac != null) {2949AccessibleSelection as = ac.getAccessibleSelection();2950if (as != null) {2951Accessible a = as.getAccessibleSelection(i);2952if (a == null)2953return null;2954else2955return a.getAccessibleContext();2956}2957}2958return null;2959}2960}, ac);2961}29622963/**2964* get number of things selected in the AccessibleSelection of an AccessibleContext2965*2966*/2967private int getAccessibleSelectionCountFromContext(final AccessibleContext ac) {2968return InvocationUtils.invokeAndWait(new Callable<Integer>() {2969@Override2970public Integer call() throws Exception {2971if (ac != null) {2972AccessibleSelection as = ac.getAccessibleSelection();2973if (as != null) {2974return as.getAccessibleSelectionCount();2975}2976}2977return -1;2978}2979}, ac);2980}29812982/**2983* return true if the i-th child of the AccessibleSelection of an AccessibleContext is selected2984*2985*/2986private boolean isAccessibleChildSelectedFromContext(final AccessibleContext ac, final int i) {2987return InvocationUtils.invokeAndWait(new Callable<Boolean>() {2988@Override2989public Boolean call() throws Exception {2990if (ac != null) {2991AccessibleSelection as = ac.getAccessibleSelection();2992if (as != null) {2993return as.isAccessibleChildSelected(i);2994}2995}2996return false;2997}2998}, ac);2999}30003001/**3002* remove the i-th child from the AccessibleSelection of an AccessibleContext3003*3004*/3005private void removeAccessibleSelectionFromContext(final AccessibleContext ac, final int i) {3006InvocationUtils.invokeAndWait(new Callable<Object>() {3007@Override3008public Object call() throws Exception {3009if (ac != null) {3010AccessibleSelection as = ac.getAccessibleSelection();3011if (as != null) {3012as.removeAccessibleSelection(i);3013}3014}3015return null;3016}3017}, ac);3018}30193020/**3021* select all (if possible) of the children of the AccessibleSelection of an AccessibleContext3022*3023*/3024private void selectAllAccessibleSelectionFromContext(final AccessibleContext ac) {3025InvocationUtils.invokeAndWait(new Callable<Object>() {3026@Override3027public Object call() throws Exception {3028if (ac != null) {3029AccessibleSelection as = ac.getAccessibleSelection();3030if (as != null) {3031as.selectAllAccessibleSelection();3032}3033}3034return null;3035}3036}, ac);3037}30383039// ======== AccessibleTable ========30403041ConcurrentHashMap<AccessibleTable,AccessibleContext> hashtab = new ConcurrentHashMap<>();30423043/**3044* returns the AccessibleTable for an AccessibleContext3045*/3046private AccessibleTable getAccessibleTableFromContext(final AccessibleContext ac) {3047String version = getJavaVersionProperty();3048if ((version != null && version.compareTo("1.3") >= 0)) {3049return InvocationUtils.invokeAndWait(new Callable<AccessibleTable>() {3050@Override3051public AccessibleTable call() throws Exception {3052if (ac != null) {3053AccessibleTable at = ac.getAccessibleTable();3054if (at != null) {3055AccessBridge.this.hashtab.put(at, ac);3056return at;3057}3058}3059return null;3060}3061}, ac);3062}3063return null;3064}306530663067/*3068* returns the AccessibleContext that contains an AccessibleTable3069*/3070private AccessibleContext getContextFromAccessibleTable(AccessibleTable at) {3071return hashtab.get(at);3072}30733074/*3075* returns the row count for an AccessibleTable3076*/3077private int getAccessibleTableRowCount(final AccessibleContext ac) {3078debugString("[INFO]: ##### getAccessibleTableRowCount");3079return InvocationUtils.invokeAndWait(new Callable<Integer>() {3080@Override3081public Integer call() throws Exception {3082if (ac != null) {3083AccessibleTable at = ac.getAccessibleTable();3084if (at != null) {3085return at.getAccessibleRowCount();3086}3087}3088return -1;3089}3090}, ac);3091}30923093/*3094* returns the column count for an AccessibleTable3095*/3096private int getAccessibleTableColumnCount(final AccessibleContext ac) {3097debugString("[INFO]: ##### getAccessibleTableColumnCount");3098return InvocationUtils.invokeAndWait(new Callable<Integer>() {3099@Override3100public Integer call() throws Exception {3101if (ac != null) {3102AccessibleTable at = ac.getAccessibleTable();3103if (at != null) {3104return at.getAccessibleColumnCount();3105}3106}3107return -1;3108}3109}, ac);3110}31113112/*3113* returns the AccessibleContext for an AccessibleTable cell3114*/3115private AccessibleContext getAccessibleTableCellAccessibleContext(final AccessibleTable at,3116final int row, final int column) {3117debugString("[INFO]: getAccessibleTableCellAccessibleContext: at = "+at.getClass());3118if (at == null) return null;3119return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {3120@Override3121public AccessibleContext call() throws Exception {3122if (!(at instanceof AccessibleContext)) {3123Accessible a = at.getAccessibleAt(row, column);3124if (a != null) {3125return a.getAccessibleContext();3126}3127} else {3128// work-around for AccessibleJTable.getCurrentAccessibleContext returning3129// wrong renderer component when cell contains more than one component3130AccessibleContext ac = (AccessibleContext) at;3131Accessible parent = ac.getAccessibleParent();3132if (parent != null) {3133int indexInParent = ac.getAccessibleIndexInParent();3134Accessible child =3135parent.getAccessibleContext().getAccessibleChild(indexInParent);3136if (child instanceof JTable) {3137JTable table = (JTable) child;31383139TableCellRenderer renderer = table.getCellRenderer(row, column);3140if (renderer == null) {3141Class<?> columnClass = table.getColumnClass(column);3142renderer = table.getDefaultRenderer(columnClass);3143}3144Component component =3145renderer.getTableCellRendererComponent(table, table.getValueAt(row, column),3146false, false, row, column);3147if (component instanceof Accessible) {3148return component.getAccessibleContext();3149}3150}3151}3152}3153return null;3154}3155}, getContextFromAccessibleTable(at));3156}31573158/*3159* returns the index of a cell at a given row and column in an AccessibleTable3160*/3161private int getAccessibleTableCellIndex(final AccessibleTable at, int row, int column) {3162debugString("[INFO]: ##### getAccessibleTableCellIndex: at="+at);3163if (at != null) {3164int cellIndex = row *3165InvocationUtils.invokeAndWait(new Callable<Integer>() {3166@Override3167public Integer call() throws Exception {3168return at.getAccessibleColumnCount();3169}3170}, getContextFromAccessibleTable(at)) +3171column;3172debugString("[INFO]: ##### getAccessibleTableCellIndex="+cellIndex);3173return cellIndex;3174}3175debugString("[ERROR]: ##### getAccessibleTableCellIndex FAILED");3176return -1;3177}31783179/*3180* returns the row extent of a cell at a given row and column in an AccessibleTable3181*/3182private int getAccessibleTableCellRowExtent(final AccessibleTable at, final int row, final int column) {3183debugString("[INFO]: ##### getAccessibleTableCellRowExtent");3184if (at != null) {3185int rowExtent = InvocationUtils.invokeAndWait(new Callable<Integer>() {3186@Override3187public Integer call() throws Exception {3188return at.getAccessibleRowExtentAt(row, column);3189}3190},3191getContextFromAccessibleTable(at));3192debugString("[INFO]: ##### getAccessibleTableCellRowExtent="+rowExtent);3193return rowExtent;3194}3195debugString("[ERROR]: ##### getAccessibleTableCellRowExtent FAILED");3196return -1;3197}31983199/*3200* returns the column extent of a cell at a given row and column in an AccessibleTable3201*/3202private int getAccessibleTableCellColumnExtent(final AccessibleTable at, final int row, final int column) {3203debugString("[INFO]: ##### getAccessibleTableCellColumnExtent");3204if (at != null) {3205int columnExtent = InvocationUtils.invokeAndWait(new Callable<Integer>() {3206@Override3207public Integer call() throws Exception {3208return at.getAccessibleColumnExtentAt(row, column);3209}3210},3211getContextFromAccessibleTable(at));3212debugString("[INFO]: ##### getAccessibleTableCellColumnExtent="+columnExtent);3213return columnExtent;3214}3215debugString("[ERROR]: ##### getAccessibleTableCellColumnExtent FAILED");3216return -1;3217}32183219/*3220* returns whether a cell is selected at a given row and column in an AccessibleTable3221*/3222private boolean isAccessibleTableCellSelected(final AccessibleTable at, final int row,3223final int column) {3224debugString("[INFO]: ##### isAccessibleTableCellSelected: ["+row+"]["+column+"]");3225if (at == null)3226return false;3227return InvocationUtils.invokeAndWait(new Callable<Boolean>() {3228@Override3229public Boolean call() throws Exception {3230boolean isSelected = false;3231Accessible a = at.getAccessibleAt(row, column);3232if (a != null) {3233AccessibleContext ac = a.getAccessibleContext();3234if (ac == null)3235return false;3236AccessibleStateSet as = ac.getAccessibleStateSet();3237if (as != null) {3238isSelected = as.contains(AccessibleState.SELECTED);3239}3240}3241return isSelected;3242}3243}, getContextFromAccessibleTable(at));3244}32453246/*3247* returns an AccessibleTable that represents the row header in an3248* AccessibleTable3249*/3250private AccessibleTable getAccessibleTableRowHeader(final AccessibleContext ac) {3251debugString("[INFO]: ##### getAccessibleTableRowHeader called");3252AccessibleTable at = InvocationUtils.invokeAndWait(new Callable<AccessibleTable>() {3253@Override3254public AccessibleTable call() throws Exception {3255if (ac != null) {3256AccessibleTable at = ac.getAccessibleTable();3257if (at != null) {3258return at.getAccessibleRowHeader();3259}3260}3261return null;3262}3263}, ac);3264if (at != null) {3265hashtab.put(at, ac);3266}3267return at;3268}32693270/*3271* returns an AccessibleTable that represents the column header in an3272* AccessibleTable3273*/3274private AccessibleTable getAccessibleTableColumnHeader(final AccessibleContext ac) {3275debugString("[INFO]: ##### getAccessibleTableColumnHeader");3276if (ac == null)3277return null;3278AccessibleTable at = InvocationUtils.invokeAndWait(new Callable<AccessibleTable>() {3279@Override3280public AccessibleTable call() throws Exception {3281// workaround for getAccessibleColumnHeader NPE3282// when the table header is null3283Accessible parent = ac.getAccessibleParent();3284if (parent != null) {3285int indexInParent = ac.getAccessibleIndexInParent();3286Accessible child =3287parent.getAccessibleContext().getAccessibleChild(indexInParent);3288if (child instanceof JTable) {3289JTable table = (JTable) child;3290if (table.getTableHeader() == null) {3291return null;3292}3293}3294}3295AccessibleTable at = ac.getAccessibleTable();3296if (at != null) {3297return at.getAccessibleColumnHeader();3298}3299return null;3300}3301}, ac);3302if (at != null) {3303hashtab.put(at, ac);3304}3305return at;3306}33073308/*3309* returns the number of row headers in an AccessibleTable that represents3310* the row header in an AccessibleTable3311*/3312private int getAccessibleTableRowHeaderRowCount(AccessibleContext ac) {33133314debugString("[INFO]: ##### getAccessibleTableRowHeaderRowCount called");3315if (ac != null) {3316final AccessibleTable atRowHeader = getAccessibleTableRowHeader(ac);3317if (atRowHeader != null) {3318return InvocationUtils.invokeAndWait(new Callable<Integer>() {3319@Override3320public Integer call() throws Exception {3321if (atRowHeader != null) {3322return atRowHeader.getAccessibleRowCount();3323}3324return -1;3325}3326}, ac);3327}3328}3329return -1;3330}33313332/*3333* returns the number of column headers in an AccessibleTable that represents3334* the row header in an AccessibleTable3335*/3336private int getAccessibleTableRowHeaderColumnCount(AccessibleContext ac) {3337debugString("[INFO]: ##### getAccessibleTableRowHeaderColumnCount called");3338if (ac != null) {3339final AccessibleTable atRowHeader = getAccessibleTableRowHeader(ac);3340if (atRowHeader != null) {3341return InvocationUtils.invokeAndWait(new Callable<Integer>() {3342@Override3343public Integer call() throws Exception {3344if (atRowHeader != null) {3345return atRowHeader.getAccessibleColumnCount();3346}3347return -1;3348}3349}, ac);3350}3351}3352debugString("[ERROR]: ##### getAccessibleTableRowHeaderColumnCount FAILED");3353return -1;3354}33553356/*3357* returns the number of row headers in an AccessibleTable that represents3358* the column header in an AccessibleTable3359*/3360private int getAccessibleTableColumnHeaderRowCount(AccessibleContext ac) {33613362debugString("[INFO]: ##### getAccessibleTableColumnHeaderRowCount");3363if (ac != null) {3364final AccessibleTable atColumnHeader = getAccessibleTableColumnHeader(ac);3365if (atColumnHeader != null) {3366return InvocationUtils.invokeAndWait(new Callable<Integer>() {3367@Override3368public Integer call() throws Exception {3369if (atColumnHeader != null) {3370return atColumnHeader.getAccessibleRowCount();3371}3372return -1;3373}3374}, ac);3375}3376}3377debugString("[ERROR]: ##### getAccessibleTableColumnHeaderRowCount FAILED");3378return -1;3379}33803381/*3382* returns the number of column headers in an AccessibleTable that represents3383* the column header in an AccessibleTable3384*/3385private int getAccessibleTableColumnHeaderColumnCount(AccessibleContext ac) {33863387debugString("[ERROR]: ##### getAccessibleTableColumnHeaderColumnCount");3388if (ac != null) {3389final AccessibleTable atColumnHeader = getAccessibleTableColumnHeader(ac);3390if (atColumnHeader != null) {3391return InvocationUtils.invokeAndWait(new Callable<Integer>() {3392@Override3393public Integer call() throws Exception {3394if (atColumnHeader != null) {3395return atColumnHeader.getAccessibleColumnCount();3396}3397return -1;3398}3399}, ac);3400}3401}3402debugString("[ERROR]: ##### getAccessibleTableColumnHeaderColumnCount FAILED");3403return -1;3404}34053406/*3407* returns the description of a row header in an AccessibleTable3408*/3409private AccessibleContext getAccessibleTableRowDescription(final AccessibleTable table,3410final int row) {3411return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {3412@Override3413public AccessibleContext call() throws Exception {3414if (table != null) {3415Accessible a = table.getAccessibleRowDescription(row);3416if (a != null) {3417return a.getAccessibleContext();3418}3419}3420return null;3421}3422}, getContextFromAccessibleTable(table));3423}34243425/*3426* returns the description of a column header in an AccessibleTable3427*/3428private AccessibleContext getAccessibleTableColumnDescription(final AccessibleTable at,3429final int column) {3430if (at == null)3431return null;3432return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {3433@Override3434public AccessibleContext call() throws Exception {3435Accessible a = at.getAccessibleColumnDescription(column);3436if (a != null) {3437return a.getAccessibleContext();3438}3439return null;3440}3441}, getContextFromAccessibleTable(at));3442}34433444/*3445* returns the number of rows selected in an AccessibleTable3446*/3447private int getAccessibleTableRowSelectionCount(final AccessibleTable at) {3448if (at != null) {3449return InvocationUtils.invokeAndWait(new Callable<Integer>() {3450@Override3451public Integer call() throws Exception {3452int[] selections = at.getSelectedAccessibleRows();3453if (selections != null)3454return selections.length;3455else3456return -1;3457}3458}, getContextFromAccessibleTable(at));3459}3460return -1;3461}34623463/*3464* returns the row number of the i-th selected row in an AccessibleTable3465*/3466private int getAccessibleTableRowSelections(final AccessibleTable at, final int i) {3467if (at != null) {3468return InvocationUtils.invokeAndWait(new Callable<Integer>() {3469@Override3470public Integer call() throws Exception {3471int[] selections = at.getSelectedAccessibleRows();3472if (selections.length > i) {3473return selections[i];3474}3475return -1;3476}3477}, getContextFromAccessibleTable(at));3478}3479return -1;3480}34813482/*3483* returns whether a row is selected in an AccessibleTable3484*/3485private boolean isAccessibleTableRowSelected(final AccessibleTable at,3486final int row) {3487if (at == null)3488return false;3489return InvocationUtils.invokeAndWait(new Callable<Boolean>() {3490@Override3491public Boolean call() throws Exception {3492return at.isAccessibleRowSelected(row);3493}3494}, getContextFromAccessibleTable(at));3495}34963497/*3498* returns whether a column is selected in an AccessibleTable3499*/3500private boolean isAccessibleTableColumnSelected(final AccessibleTable at,3501final int column) {3502if (at == null)3503return false;3504return InvocationUtils.invokeAndWait(new Callable<Boolean>() {3505@Override3506public Boolean call() throws Exception {3507return at.isAccessibleColumnSelected(column);3508}3509}, getContextFromAccessibleTable(at));3510}35113512/*3513* returns the number of columns selected in an AccessibleTable3514*/3515private int getAccessibleTableColumnSelectionCount(final AccessibleTable at) {3516if (at == null)3517return -1;3518return InvocationUtils.invokeAndWait(new Callable<Integer>() {3519@Override3520public Integer call() throws Exception {3521int[] selections = at.getSelectedAccessibleColumns();3522if (selections != null)3523return selections.length;3524else3525return -1;3526}3527}, getContextFromAccessibleTable(at));3528}35293530/*3531* returns the row number of the i-th selected row in an AccessibleTable3532*/3533private int getAccessibleTableColumnSelections(final AccessibleTable at, final int i) {3534if (at == null)3535return -1;3536return InvocationUtils.invokeAndWait(new Callable<Integer>() {3537@Override3538public Integer call() throws Exception {3539int[] selections = at.getSelectedAccessibleColumns();3540if (selections != null && selections.length > i) {3541return selections[i];3542}3543return -1;3544}3545}, getContextFromAccessibleTable(at));3546}35473548/* ===== AccessibleExtendedTable (since 1.4) ===== */35493550/*3551* returns the row number for a cell at a given index in an AccessibleTable3552*/3553private int getAccessibleTableRow(final AccessibleTable at, int index) {3554if (at == null)3555return -1;3556int colCount=InvocationUtils.invokeAndWait(new Callable<Integer>() {3557@Override3558public Integer call() throws Exception {3559return at.getAccessibleColumnCount();3560}3561}, getContextFromAccessibleTable(at));3562return index / colCount;3563}35643565/*3566* returns the column number for a cell at a given index in an AccessibleTable3567*/3568private int getAccessibleTableColumn(final AccessibleTable at, int index) {3569if (at == null)3570return -1;3571int colCount=InvocationUtils.invokeAndWait(new Callable<Integer>() {3572@Override3573public Integer call() throws Exception {3574return at.getAccessibleColumnCount();3575}3576}, getContextFromAccessibleTable(at));3577return index % colCount;3578}35793580/*3581* returns the index for a cell at a given row and column in an3582* AccessibleTable3583*/3584private int getAccessibleTableIndex(final AccessibleTable at, int row, int column) {3585if (at == null)3586return -1;3587int colCount = InvocationUtils.invokeAndWait(new Callable<Integer>() {3588@Override3589public Integer call() throws Exception {3590return at.getAccessibleColumnCount();3591}3592}, getContextFromAccessibleTable(at));3593return row * colCount + column;3594}35953596// ===== AccessibleRelationSet =====35973598/*3599* returns the number of relations in the AccessibleContext's3600* AccessibleRelationSet3601*/3602private int getAccessibleRelationCount(final AccessibleContext ac) {3603String version = getJavaVersionProperty();3604if ((version != null && version.compareTo("1.3") >= 0)) {3605if (ac != null) {3606AccessibleRelationSet ars = InvocationUtils.invokeAndWait(new Callable<AccessibleRelationSet>() {3607@Override3608public AccessibleRelationSet call() throws Exception {3609return ac.getAccessibleRelationSet();3610}3611}, ac);3612if (ars != null)3613return ars.size();3614}3615}3616return 0;3617}36183619/*3620* returns the ith relation key in the AccessibleContext's3621* AccessibleRelationSet3622*/3623private String getAccessibleRelationKey(final AccessibleContext ac, final int i) {3624return InvocationUtils.invokeAndWait(new Callable<String>() {3625@Override3626public String call() throws Exception {3627if (ac != null) {3628AccessibleRelationSet ars = ac.getAccessibleRelationSet();3629if (ars != null) {3630AccessibleRelation[] relations = ars.toArray();3631if (relations != null && i >= 0 && i < relations.length) {3632return relations[i].getKey();3633}3634}3635}3636return null;3637}3638}, ac);3639}36403641/*3642* returns the number of targets in a relation in the AccessibleContext's3643* AccessibleRelationSet3644*/3645private int getAccessibleRelationTargetCount(final AccessibleContext ac, final int i) {3646return InvocationUtils.invokeAndWait(new Callable<Integer>() {3647@Override3648public Integer call() throws Exception {3649if (ac != null) {3650AccessibleRelationSet ars = ac.getAccessibleRelationSet();3651if (ars != null) {3652AccessibleRelation[] relations = ars.toArray();3653if (relations != null && i >= 0 && i < relations.length) {3654Object[] targets = relations[i].getTarget();3655if (targets != null) {3656int targetCount = targets.length -3657getNonVisibleTargetCountTillIndex(targets, targets.length - 1);3658return targetCount;3659}3660}3661}3662}3663return -1;3664}3665}, ac);3666}36673668/*3669* returns the jth target in the ith relation in the AccessibleContext's3670* AccessibleRelationSet3671*/3672private AccessibleContext getAccessibleRelationTarget(final AccessibleContext ac,3673final int i, final int j) {3674debugString("[INFO]: ***** getAccessibleRelationTarget");3675return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {3676@Override3677public AccessibleContext call() throws Exception {3678if (ac != null) {3679AccessibleRelationSet ars = ac.getAccessibleRelationSet();3680if (ars != null) {3681AccessibleRelation[] relations = ars.toArray();3682if (relations != null && i >= 0 && i < relations.length) {3683Object[] targets = relations[i].getTarget();3684if (targets != null && j >= 0 & j < targets.length) {3685Object o = getVisibleTargetAtIndex(targets, j);3686if (o instanceof Accessible) {3687return ((Accessible) o).getAccessibleContext();3688}3689}3690}3691}3692}3693return null;3694}3695}, ac);3696}36973698private Object getVisibleTargetAtIndex(Object[] targets, int index) {3699if (index >= 0 && index < targets.length) {3700int visibleTargetIndex = -1;3701for (int i = 0; i < targets.length; i++) {3702if (targets[i] instanceof Accessible) {3703AccessibleContext ac = ((Accessible) targets[i]).getAccessibleContext();3704if (ac != null && ac.getAccessibleStateSet().contains(AccessibleState.VISIBLE)) {3705visibleTargetIndex++;3706}3707if (visibleTargetIndex == index) {3708return targets[i];3709}3710}3711}3712}3713return null;3714}37153716private int getNonVisibleTargetCountTillIndex(Object[] targets, int index) {3717if (index >= 0 && index < targets.length) {3718int nonVisibleTargetsCount = 0;3719for (int i = 0; i <= index; i++) {3720if (targets[i] instanceof Accessible) {3721AccessibleContext ac = ((Accessible) targets[i]).getAccessibleContext();3722if (ac != null && !ac.getAccessibleStateSet().contains(AccessibleState.VISIBLE)) {3723nonVisibleTargetsCount++;3724}3725}3726}3727return nonVisibleTargetsCount;3728}3729return 0;3730}37313732// ========= AccessibleHypertext =========37333734private Map<AccessibleHypertext, AccessibleContext> hyperTextContextMap = new WeakHashMap<>();3735private Map<AccessibleHyperlink, AccessibleContext> hyperLinkContextMap = new WeakHashMap<>();37363737/*3738* Returns the AccessibleHypertext3739*/3740private AccessibleHypertext getAccessibleHypertext(final AccessibleContext ac) {3741debugString("[INFO]: getAccessibleHyperlink");3742if (ac==null)3743return null;3744AccessibleHypertext hypertext = InvocationUtils.invokeAndWait(new Callable<AccessibleHypertext>() {3745@Override3746public AccessibleHypertext call() throws Exception {3747AccessibleText at = ac.getAccessibleText();3748if (!(at instanceof AccessibleHypertext)) {3749return null;3750}3751return ((AccessibleHypertext) at);3752}3753}, ac);3754hyperTextContextMap.put(hypertext, ac);3755return hypertext;3756}37573758/*3759* Returns the number of AccessibleHyperlinks3760*/3761private int getAccessibleHyperlinkCount(AccessibleContext ac) {3762debugString("[INFO]: getAccessibleHyperlinkCount");3763if (ac == null) {3764return 0;3765}3766final AccessibleHypertext hypertext = getAccessibleHypertext(ac);3767if (hypertext == null) {3768return 0;3769}3770//return hypertext.getLinkCount();3771return InvocationUtils.invokeAndWait(new Callable<Integer>() {3772@Override3773public Integer call() throws Exception {3774return hypertext.getLinkCount();3775}3776}, ac);3777}37783779/*3780* Returns the hyperlink at the specified index3781*/3782private AccessibleHyperlink getAccessibleHyperlink(final AccessibleHypertext hypertext, final int i) {3783debugString("[INFO]: getAccessibleHyperlink");3784if (hypertext == null) {3785return null;3786}3787AccessibleContext ac = hyperTextContextMap.get(hypertext);3788if ( i < 0 || i >=3789InvocationUtils.invokeAndWait(new Callable<Integer>() {3790@Override3791public Integer call() throws Exception {3792return hypertext.getLinkCount();3793}3794}, ac) ) {3795return null;3796}3797AccessibleHyperlink acLink = InvocationUtils.invokeAndWait(new Callable<AccessibleHyperlink>() {3798@Override3799public AccessibleHyperlink call() throws Exception {3800AccessibleHyperlink link = hypertext.getLink(i);3801if (link == null || (!link.isValid())) {3802return null;3803}3804return link;3805}3806}, ac);3807hyperLinkContextMap.put(acLink, ac);3808return acLink;3809}38103811/*3812* Returns the hyperlink object description3813*/3814private String getAccessibleHyperlinkText(final AccessibleHyperlink link) {3815debugString("[INFO]: getAccessibleHyperlinkText");3816if (link == null) {3817return null;3818}3819return InvocationUtils.invokeAndWait(new Callable<String>() {3820@Override3821public String call() throws Exception {3822Object o = link.getAccessibleActionDescription(0);3823if (o != null) {3824return o.toString();3825}3826return null;3827}3828}, hyperLinkContextMap.get(link));3829}38303831/*3832* Returns the hyperlink URL3833*/3834private String getAccessibleHyperlinkURL(final AccessibleHyperlink link) {3835debugString("[INFO]: getAccessibleHyperlinkURL");3836if (link == null) {3837return null;3838}3839return InvocationUtils.invokeAndWait(new Callable<String>() {3840@Override3841public String call() throws Exception {3842Object o = link.getAccessibleActionObject(0);3843if (o != null) {3844return o.toString();3845} else {3846return null;3847}3848}3849}, hyperLinkContextMap.get(link));3850}38513852/*3853* Returns the start index of the hyperlink text3854*/3855private int getAccessibleHyperlinkStartIndex(final AccessibleHyperlink link) {3856debugString("[INFO]: getAccessibleHyperlinkStartIndex");3857if (link == null) {3858return -1;3859}3860return InvocationUtils.invokeAndWait(new Callable<Integer>() {3861@Override3862public Integer call() throws Exception {3863return link.getStartIndex();3864}3865}, hyperLinkContextMap.get(link));3866}38673868/*3869* Returns the end index of the hyperlink text3870*/3871private int getAccessibleHyperlinkEndIndex(final AccessibleHyperlink link) {3872debugString("[INFO]: getAccessibleHyperlinkEndIndex");3873if (link == null) {3874return -1;3875}3876return InvocationUtils.invokeAndWait(new Callable<Integer>() {3877@Override3878public Integer call() throws Exception {3879return link.getEndIndex();3880}3881}, hyperLinkContextMap.get(link));3882}38833884/*3885* Returns the index into an array of hyperlinks that3886* is associated with this character index, or -1 if there3887* is no hyperlink associated with this index.3888*/3889private int getAccessibleHypertextLinkIndex(final AccessibleHypertext hypertext, final int charIndex) {3890debugString("[INFO]: getAccessibleHypertextLinkIndex: charIndex = "+charIndex);3891if (hypertext == null) {3892return -1;3893}3894int linkIndex = InvocationUtils.invokeAndWait(new Callable<Integer>() {3895@Override3896public Integer call() throws Exception {3897return hypertext.getLinkIndex(charIndex);3898}3899}, hyperTextContextMap.get(hypertext));3900debugString("[INFO]: getAccessibleHypertextLinkIndex returning "+linkIndex);3901return linkIndex;3902}39033904/*3905* Actives the hyperlink3906*/3907private boolean activateAccessibleHyperlink(final AccessibleContext ac,3908final AccessibleHyperlink link) {3909//debugString("activateAccessibleHyperlink: link = "+link.getClass());3910if (link == null) {3911return false;3912}3913boolean retval = InvocationUtils.invokeAndWait(new Callable<Boolean>() {3914@Override3915public Boolean call() throws Exception {3916return link.doAccessibleAction(0);3917}3918}, ac);3919debugString("[INFO]: activateAccessibleHyperlink: returning = "+retval);3920return retval;3921}392239233924// ============ AccessibleKeyBinding =============39253926/*3927* returns the component mnemonic3928*/3929private KeyStroke getMnemonic(final AccessibleContext ac) {3930if (ac == null)3931return null;3932return InvocationUtils.invokeAndWait(new Callable<KeyStroke>() {3933@Override3934public KeyStroke call() throws Exception {3935AccessibleComponent comp = ac.getAccessibleComponent();3936if (!(comp instanceof AccessibleExtendedComponent)) {3937return null;3938}3939AccessibleExtendedComponent aec = (AccessibleExtendedComponent) comp;3940if (aec != null) {3941AccessibleKeyBinding akb = aec.getAccessibleKeyBinding();3942if (akb != null) {3943Object o = akb.getAccessibleKeyBinding(0);3944if (o instanceof KeyStroke) {3945return (KeyStroke) o;3946}3947}3948}3949return null;3950}3951}, ac);3952}39533954/*3955* returns the JMenuItem accelerator3956*/3957private KeyStroke getAccelerator(final AccessibleContext ac) {3958// workaround for getAccessibleKeyBinding not returning the3959// JMenuItem accelerator3960if (ac == null)3961return null;3962return InvocationUtils.invokeAndWait(new Callable<KeyStroke>() {3963@Override3964public KeyStroke call() throws Exception {3965Accessible parent = ac.getAccessibleParent();3966if (parent instanceof Accessible) {3967int indexInParent = ac.getAccessibleIndexInParent();3968Accessible child =3969parent.getAccessibleContext().getAccessibleChild(indexInParent);3970if (child instanceof JMenuItem) {3971JMenuItem menuItem = (JMenuItem) child;3972if (menuItem == null)3973return null;3974KeyStroke keyStroke = menuItem.getAccelerator();3975return keyStroke;3976}3977}3978return null;3979}3980}, ac);3981}39823983/*3984* returns 1-24 to indicate which F key is being used for a shortcut or 0 otherwise3985*/3986private int fKeyNumber(KeyStroke keyStroke) {3987if (keyStroke == null)3988return 0;3989int fKey = 0;3990String keyText = KeyEvent.getKeyText(keyStroke.getKeyCode());3991if (keyText != null && (keyText.length() == 2 || keyText.length() == 3)) {3992String prefix = keyText.substring(0, 1);3993if (prefix.equals("F")) {3994try {3995int suffix = Integer.parseInt(keyText.substring(1));3996if (suffix >= 1 && suffix <= 24) {3997fKey = suffix;3998}3999} catch (Exception e) { // ignore NumberFormatException4000}4001}4002}4003return fKey;4004}40054006/*4007* returns one of several important control characters or 0 otherwise4008*/4009private int controlCode(KeyStroke keyStroke) {4010if (keyStroke == null)4011return 0;4012int code = keyStroke.getKeyCode();4013switch (code) {4014case KeyEvent.VK_BACK_SPACE:4015case KeyEvent.VK_DELETE:4016case KeyEvent.VK_DOWN:4017case KeyEvent.VK_END:4018case KeyEvent.VK_HOME:4019case KeyEvent.VK_INSERT:4020case KeyEvent.VK_KP_DOWN:4021case KeyEvent.VK_KP_LEFT:4022case KeyEvent.VK_KP_RIGHT:4023case KeyEvent.VK_KP_UP:4024case KeyEvent.VK_LEFT:4025case KeyEvent.VK_PAGE_DOWN:4026case KeyEvent.VK_PAGE_UP:4027case KeyEvent.VK_RIGHT:4028case KeyEvent.VK_UP:4029break;4030default:4031code = 0;4032break;4033}4034return code;4035}40364037/*4038* returns the KeyStoke character4039*/4040private char getKeyChar(KeyStroke keyStroke) {4041// If the shortcut is an FKey return 1-244042if (keyStroke == null)4043return 0;4044int fKey = fKeyNumber(keyStroke);4045if (fKey != 0) {4046// return 0x00000001 through 0x000000184047debugString("[INFO]: Shortcut is: F" + fKey);4048return (char)fKey;4049}4050// If the accelerator is a control character, return it4051int keyCode = controlCode(keyStroke);4052if (keyCode != 0) {4053debugString("[INFO]: Shortcut is control character: " + Integer.toHexString(keyCode));4054return (char)keyCode;4055}4056String keyText = KeyEvent.getKeyText(keyStroke.getKeyCode());4057debugString("[INFO]: Shortcut is: " + keyText);4058if (keyText != null || keyText.length() > 0) {4059CharSequence seq = keyText.subSequence(0, 1);4060if (seq != null || seq.length() > 0) {4061return seq.charAt(0);4062}4063}4064return 0;4065}40664067/*4068* returns the KeyStroke modifiers as an int4069*/4070private int getModifiers(KeyStroke keyStroke) {4071if (keyStroke == null)4072return 0;4073debugString("[INFO]: In AccessBridge.getModifiers");4074// modifiers is a bit strip where bits 0-7 indicate a traditional modifier4075// such as Ctrl/Alt/Shift, bit 8 indicates an F key shortcut, and bit 9 indicates4076// a control code shortcut such as the delete key.40774078int modifiers = 0;4079// Is the shortcut an FKey?4080if (fKeyNumber(keyStroke) != 0) {4081modifiers |= 1 << 8;4082}4083// Is the shortcut a control code?4084if (controlCode(keyStroke) != 0) {4085modifiers |= 1 << 9;4086}4087// The following is needed in order to handle translated modifiers.4088// getKeyModifiersText doesn't work because for example in German Strg is4089// returned for Ctrl.40904091// There can be more than one modifier, e.g. if the modifier is ctrl + shift + B4092// the toString text is "shift ctrl pressed B". Need to parse through that.4093StringTokenizer st = new StringTokenizer(keyStroke.toString());4094while (st.hasMoreTokens()) {4095String text = st.nextToken();4096// Meta+Ctrl+Alt+Shift4097// 0-3 are shift, ctrl, meta, alt4098// 4-7 are for Solaris workstations (though not being used)4099if (text.startsWith("met")) {4100debugString("[INFO]: found meta");4101modifiers |= ActionEvent.META_MASK;4102}4103if (text.startsWith("ctr")) {4104debugString("[INFO]: found ctrl");4105modifiers |= ActionEvent.CTRL_MASK;4106}4107if (text.startsWith("alt")) {4108debugString("[INFO]: found alt");4109modifiers |= ActionEvent.ALT_MASK;4110}4111if (text.startsWith("shi")) {4112debugString("[INFO]: found shift");4113modifiers |= ActionEvent.SHIFT_MASK;4114}4115}4116debugString("[INFO]: returning modifiers: 0x" + Integer.toHexString(modifiers));4117return modifiers;4118}41194120/*4121* returns the number of key bindings associated with this context4122*/4123private int getAccessibleKeyBindingsCount(AccessibleContext ac) {4124if (ac == null || (! runningOnJDK1_4) )4125return 0;4126int count = 0;41274128if (getMnemonic(ac) != null) {4129count++;4130}4131if (getAccelerator(ac) != null) {4132count++;4133}4134return count;4135}41364137/*4138* returns the key binding character at the specified index4139*/4140private char getAccessibleKeyBindingChar(AccessibleContext ac, int index) {4141if (ac == null || (! runningOnJDK1_4) )4142return 0;4143if((index == 0) && getMnemonic(ac)==null) {// special case when there is no mnemonic4144KeyStroke keyStroke = getAccelerator(ac);4145if (keyStroke != null) {4146return getKeyChar(keyStroke);4147}4148}4149if (index == 0) { // mnemonic4150KeyStroke keyStroke = getMnemonic(ac);4151if (keyStroke != null) {4152return getKeyChar(keyStroke);4153}4154} else if (index == 1) { // accelerator4155KeyStroke keyStroke = getAccelerator(ac);4156if (keyStroke != null) {4157return getKeyChar(keyStroke);4158}4159}4160return 0;4161}41624163/*4164* returns the key binding modifiers at the specified index4165*/4166private int getAccessibleKeyBindingModifiers(AccessibleContext ac, int index) {4167if (ac == null || (! runningOnJDK1_4) )4168return 0;4169if((index == 0) && getMnemonic(ac)==null) {// special case when there is no mnemonic4170KeyStroke keyStroke = getAccelerator(ac);4171if (keyStroke != null) {4172return getModifiers(keyStroke);4173}4174}4175if (index == 0) { // mnemonic4176KeyStroke keyStroke = getMnemonic(ac);4177if (keyStroke != null) {4178return getModifiers(keyStroke);4179}4180} else if (index == 1) { // accelerator4181KeyStroke keyStroke = getAccelerator(ac);4182if (keyStroke != null) {4183return getModifiers(keyStroke);4184}4185}4186return 0;4187}41884189// ========== AccessibleIcon ============41904191/*4192* return the number of icons associated with this context4193*/4194private int getAccessibleIconsCount(final AccessibleContext ac) {4195debugString("[INFO]: getAccessibleIconsCount");4196if (ac == null) {4197return 0;4198}4199return InvocationUtils.invokeAndWait(new Callable<Integer>() {4200@Override4201public Integer call() throws Exception {4202AccessibleIcon[] ai = ac.getAccessibleIcon();4203if (ai == null) {4204return 0;4205}4206return ai.length;4207}4208}, ac);4209}42104211/*4212* return icon description at the specified index4213*/4214private String getAccessibleIconDescription(final AccessibleContext ac, final int index) {4215debugString("[INFO]: getAccessibleIconDescription: index = "+index);4216if (ac == null) {4217return null;4218}4219return InvocationUtils.invokeAndWait(new Callable<String>() {4220@Override4221public String call() throws Exception {4222AccessibleIcon[] ai = ac.getAccessibleIcon();4223if (ai == null || index < 0 || index >= ai.length) {4224return null;4225}4226return ai[index].getAccessibleIconDescription();4227}4228}, ac);4229}42304231/*4232* return icon height at the specified index4233*/4234private int getAccessibleIconHeight(final AccessibleContext ac, final int index) {4235debugString("[INFO]: getAccessibleIconHeight: index = "+index);4236if (ac == null) {4237return 0;4238}4239return InvocationUtils.invokeAndWait(new Callable<Integer>() {4240@Override4241public Integer call() throws Exception {4242AccessibleIcon[] ai = ac.getAccessibleIcon();4243if (ai == null || index < 0 || index >= ai.length) {4244return 0;4245}4246return ai[index].getAccessibleIconHeight();4247}4248}, ac);4249}42504251/*4252* return icon width at the specified index4253*/4254private int getAccessibleIconWidth(final AccessibleContext ac, final int index) {4255debugString("[INFO]: getAccessibleIconWidth: index = "+index);4256if (ac == null) {4257return 0;4258}4259return InvocationUtils.invokeAndWait(new Callable<Integer>() {4260@Override4261public Integer call() throws Exception {4262AccessibleIcon[] ai = ac.getAccessibleIcon();4263if (ai == null || index < 0 || index >= ai.length) {4264return 0;4265}4266return ai[index].getAccessibleIconWidth();4267}4268}, ac);4269}42704271// ========= AccessibleAction ===========42724273/*4274* return the number of icons associated with this context4275*/4276private int getAccessibleActionsCount(final AccessibleContext ac) {4277debugString("[INFO]: getAccessibleActionsCount");4278if (ac == null) {4279return 0;4280}4281return InvocationUtils.invokeAndWait(new Callable<Integer>() {4282@Override4283public Integer call() throws Exception {4284AccessibleAction aa = ac.getAccessibleAction();4285if (aa == null)4286return 0;4287return aa.getAccessibleActionCount();4288}4289}, ac);4290}42914292/*4293* return icon description at the specified index4294*/4295private String getAccessibleActionName(final AccessibleContext ac, final int index) {4296debugString("[INFO]: getAccessibleActionName: index = "+index);4297if (ac == null) {4298return null;4299}4300return InvocationUtils.invokeAndWait(new Callable<String>() {4301@Override4302public String call() throws Exception {4303AccessibleAction aa = ac.getAccessibleAction();4304if (aa == null) {4305return null;4306}4307return aa.getAccessibleActionDescription(index);4308}4309}, ac);4310}4311/*4312* return icon description at the specified index4313*/4314private boolean doAccessibleActions(final AccessibleContext ac, final String name) {4315debugString("[INFO]: doAccessibleActions: action name = "+name);4316if (ac == null || name == null) {4317return false;4318}4319return InvocationUtils.invokeAndWait(new Callable<Boolean>() {4320@Override4321public Boolean call() throws Exception {4322AccessibleAction aa = ac.getAccessibleAction();4323if (aa == null) {4324return false;4325}4326int index = -1;4327int numActions = aa.getAccessibleActionCount();4328for (int i = 0; i < numActions; i++) {4329String actionName = aa.getAccessibleActionDescription(i);4330if (name.equals(actionName)) {4331index = i;4332break;4333}4334}4335if (index == -1) {4336return false;4337}4338boolean retval = aa.doAccessibleAction(index);4339return retval;4340}4341}, ac);4342}43434344/* ===== AT utility methods ===== */43454346/**4347* Sets the contents of an AccessibleContext that4348* implements AccessibleEditableText with the4349* specified text string.4350* Returns whether successful.4351*/4352private boolean setTextContents(final AccessibleContext ac, final String text) {4353debugString("[INFO]: setTextContents: ac = "+ac+"; text = "+text);43544355if (! (ac instanceof AccessibleEditableText)) {4356debugString("[WARN]: ac not instanceof AccessibleEditableText: "+ac);4357return false;4358}4359if (text == null) {4360debugString("[WARN]: text is null");4361return false;4362}43634364return InvocationUtils.invokeAndWait(new Callable<Boolean>() {4365@Override4366public Boolean call() throws Exception {4367// check whether the text field is editable4368AccessibleStateSet ass = ac.getAccessibleStateSet();4369if (!ass.contains(AccessibleState.ENABLED)) {4370return false;4371}4372((AccessibleEditableText) ac).setTextContents(text);4373return true;4374}4375}, ac);4376}43774378/**4379* Returns the Accessible Context of an Internal Frame object that is4380* the ancestor of a given object. If the object is an Internal Frame4381* object or an Internal Frame ancestor object was found, returns the4382* object's AccessibleContext.4383* If there is no ancestor object that has an Accessible Role of4384* Internal Frame, returns (AccessibleContext)0.4385*/4386private AccessibleContext getInternalFrame (AccessibleContext ac) {4387return getParentWithRole(ac, AccessibleRole.INTERNAL_FRAME.toString());4388}43894390/**4391* Returns the Accessible Context for the top level object in4392* a Java Window. This is same Accessible Context that is obtained4393* from GetAccessibleContextFromHWND for that window. Returns4394* (AccessibleContext)0 on error.4395*/4396private AccessibleContext getTopLevelObject (final AccessibleContext ac) {4397debugString("[INFO]: getTopLevelObject; ac = "+ac);4398if (ac == null) {4399return null;4400}4401return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {4402@Override4403public AccessibleContext call() throws Exception {4404if (ac.getAccessibleRole() == AccessibleRole.DIALOG) {4405// return the dialog, not the parent window4406return ac;4407}44084409Accessible parent = ac.getAccessibleParent();4410if (parent == null) {4411return ac;4412}4413Accessible tmp = parent;4414while (tmp != null && tmp.getAccessibleContext() != null) {4415AccessibleContext ac2 = tmp.getAccessibleContext();4416if (ac2 != null && ac2.getAccessibleRole() == AccessibleRole.DIALOG) {4417// return the dialog, not the parent window4418return ac2;4419}4420parent = tmp;4421tmp = parent.getAccessibleContext().getAccessibleParent();4422}4423return parent.getAccessibleContext();4424}4425}, ac);4426}44274428/**4429* Returns the parent AccessibleContext that has the specified AccessibleRole.4430* Returns null on error or if the AccessibleContext does not exist.4431*/4432private AccessibleContext getParentWithRole (final AccessibleContext ac,4433final String roleName) {4434debugString("[INFO]: getParentWithRole; ac = "+ac + "\n role = "+roleName);4435if (ac == null || roleName == null) {4436return null;4437}44384439return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {4440@Override4441public AccessibleContext call() throws Exception {4442AccessibleRole role = AccessBridge.this.accessibleRoleMap.get(roleName);4443if (role == null) {4444return ac;4445}44464447Accessible parent = ac.getAccessibleParent();4448if (parent == null && ac.getAccessibleRole() == role) {4449return ac;4450}44514452Accessible tmp = parent;4453AccessibleContext tmp_ac = null;44544455while (tmp != null && (tmp_ac = tmp.getAccessibleContext()) != null) {4456AccessibleRole ar = tmp_ac.getAccessibleRole();4457if (ar == role) {4458// found4459return tmp_ac;4460}4461parent = tmp;4462tmp = parent.getAccessibleContext().getAccessibleParent();4463}4464// not found4465return null;4466}4467}, ac);4468}44694470/**4471* Returns the parent AccessibleContext that has the specified AccessibleRole.4472* Otherwise, returns the top level object for the Java Window.4473* Returns (AccessibleContext)0 on error.4474*/4475private AccessibleContext getParentWithRoleElseRoot (AccessibleContext ac,4476String roleName) {4477AccessibleContext retval = getParentWithRole(ac, roleName);4478if (retval == null) {4479retval = getTopLevelObject(ac);4480}4481return retval;4482}44834484/**4485* Returns how deep in the object hierarchy a given object is.4486* The top most object in the object hierarchy has an object depth of 0.4487* Returns -1 on error.4488*/4489private int getObjectDepth(final AccessibleContext ac) {4490debugString("[INFO]: getObjectDepth: ac = "+ac);44914492if (ac == null) {4493return -1;4494}4495return InvocationUtils.invokeAndWait(new Callable<Integer>() {4496@Override4497public Integer call() throws Exception {4498int count = 0;4499Accessible parent = ac.getAccessibleParent();4500if (parent == null) {4501return count;4502}4503Accessible tmp = parent;4504while (tmp != null && tmp.getAccessibleContext() != null) {4505parent = tmp;4506tmp = parent.getAccessibleContext().getAccessibleParent();4507count++;4508}4509return count;4510}4511}, ac);4512}45134514/**4515* Returns the Accessible Context of the current ActiveDescendent of an object.4516* Returns (AccessibleContext)0 on error.4517*/4518private AccessibleContext getActiveDescendent (final AccessibleContext ac) {4519debugString("[INFO]: getActiveDescendent: ac = "+ac);4520if (ac == null) {4521return null;4522}4523// workaround for JTree bug where the only possible active4524// descendent is the JTree root4525final Accessible parent = InvocationUtils.invokeAndWait(new Callable<Accessible>() {4526@Override4527public Accessible call() throws Exception {4528return ac.getAccessibleParent();4529}4530}, ac);45314532if (parent != null) {4533Accessible child = InvocationUtils.invokeAndWait(new Callable<Accessible>() {4534@Override4535public Accessible call() throws Exception {4536int indexInParent = ac.getAccessibleIndexInParent();4537return parent.getAccessibleContext().getAccessibleChild(indexInParent);4538}4539}, ac);45404541if (child instanceof JTree) {4542// return the selected node4543final JTree tree = (JTree)child;4544return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {4545@Override4546public AccessibleContext call() throws Exception {4547return new AccessibleJTreeNode(tree,4548tree.getSelectionPath(),4549null);4550}4551}, child);4552}4553}45544555return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {4556@Override4557public AccessibleContext call() throws Exception {4558AccessibleSelection as = ac.getAccessibleSelection();4559if (as == null) {4560return null;4561}4562// assume single selection4563if (as.getAccessibleSelectionCount() != 1) {4564return null;4565}4566Accessible a = as.getAccessibleSelection(0);4567if (a == null) {4568return null;4569}4570return a.getAccessibleContext();4571}4572}, ac);4573}457445754576/**4577* Additional methods for Teton4578*/45794580/**4581* Gets the AccessibleName for a component based upon the JAWS algorithm.4582* Returns whether successful.4583*4584* Bug ID 4916682 - Implement JAWS AccessibleName policy4585*/4586private String getJAWSAccessibleName(final AccessibleContext ac) {4587debugString("[INFO]: getJAWSAccessibleName");4588if (ac == null) {4589return null;4590}4591// placeholder4592return InvocationUtils.invokeAndWait(new Callable<String>() {4593@Override4594public String call() throws Exception {4595return ac.getAccessibleName();4596}4597}, ac);4598}45994600/**4601* Request focus for a component. Returns whether successful;4602*4603* Bug ID 4944757 - requestFocus method needed4604*/4605private boolean requestFocus(final AccessibleContext ac) {4606debugString("[INFO]: requestFocus");4607if (ac == null) {4608return false;4609}4610return InvocationUtils.invokeAndWait(new Callable<Boolean>() {4611@Override4612public Boolean call() throws Exception {4613AccessibleComponent acomp = ac.getAccessibleComponent();4614if (acomp == null) {4615return false;4616}4617acomp.requestFocus();4618return ac.getAccessibleStateSet().contains(AccessibleState.FOCUSED);4619}4620}, ac);4621}46224623/**4624* Selects text between two indices. Selection includes the4625* text at the start index and the text at the end index. Returns4626* whether successful;4627*4628* Bug ID 4944758 - selectTextRange method needed4629*/4630private boolean selectTextRange(final AccessibleContext ac, final int startIndex, final int endIndex) {4631debugString("[INFO]: selectTextRange: start = "+startIndex+"; end = "+endIndex);4632if (ac == null) {4633return false;4634}4635return InvocationUtils.invokeAndWait(new Callable<Boolean>() {4636@Override4637public Boolean call() throws Exception {4638AccessibleText at = ac.getAccessibleText();4639if (!(at instanceof AccessibleEditableText)) {4640return false;4641}4642((AccessibleEditableText) at).selectText(startIndex, endIndex);46434644boolean result = at.getSelectionStart() == startIndex &&4645at.getSelectionEnd() == endIndex;4646return result;4647}4648}, ac);4649}46504651/**4652* Set the caret to a text position. Returns whether successful;4653*4654* Bug ID 4944770 - setCaretPosition method needed4655*/4656private boolean setCaretPosition(final AccessibleContext ac, final int position) {4657debugString("[INFO]: setCaretPosition: position = "+position);4658if (ac == null) {4659return false;4660}4661return InvocationUtils.invokeAndWait(new Callable<Boolean>() {4662@Override4663public Boolean call() throws Exception {4664AccessibleText at = ac.getAccessibleText();4665if (!(at instanceof AccessibleEditableText)) {4666return false;4667}4668((AccessibleEditableText) at).selectText(position, position);4669return at.getCaretPosition() == position;4670}4671}, ac);4672}46734674/**4675* Gets the number of visible children of an AccessibleContext.4676*4677* Bug ID 4944762- getVisibleChildren for list-like components needed4678*/4679private int _visibleChildrenCount;4680private AccessibleContext _visibleChild;4681private int _currentVisibleIndex;4682private boolean _foundVisibleChild;46834684private int getVisibleChildrenCount(AccessibleContext ac) {4685debugString("[INFO]: getVisibleChildrenCount");4686if (ac == null) {4687return -1;4688}4689_visibleChildrenCount = 0;4690_getVisibleChildrenCount(ac);4691debugString("[INFO]: _visibleChildrenCount = "+_visibleChildrenCount);4692return _visibleChildrenCount;4693}46944695/*4696* Recursively descends AccessibleContext and gets the number4697* of visible children4698*/4699private void _getVisibleChildrenCount(final AccessibleContext ac) {4700if (ac == null)4701return;4702if(ac instanceof AccessibleExtendedTable) {4703_getVisibleChildrenCount((AccessibleExtendedTable)ac);4704return;4705}4706int numChildren = InvocationUtils.invokeAndWait(new Callable<Integer>() {4707@Override4708public Integer call() throws Exception {4709return ac.getAccessibleChildrenCount();4710}4711}, ac);4712for (int i = 0; i < numChildren; i++) {4713final int idx = i;4714final AccessibleContext ac2 = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {4715@Override4716public AccessibleContext call() throws Exception {4717Accessible a = ac.getAccessibleChild(idx);4718if (a != null)4719return a.getAccessibleContext();4720else4721return null;4722}4723}, ac);4724if ( ac2 == null ||4725(!InvocationUtils.invokeAndWait(new Callable<Boolean>() {4726@Override4727public Boolean call() throws Exception {4728return ac2.getAccessibleStateSet().contains(AccessibleState.SHOWING);4729}4730}, ac))4731) {4732continue;4733}4734_visibleChildrenCount++;47354736if (InvocationUtils.invokeAndWait(new Callable<Integer>() {4737@Override4738public Integer call() throws Exception {4739return ac2.getAccessibleChildrenCount();4740}4741}, ac) > 0 ) {4742_getVisibleChildrenCount(ac2);4743}4744}4745}47464747/*4748* Recursively descends AccessibleContext and gets the number4749* of visible children. Stops search if get to invisible part of table.4750*/4751private void _getVisibleChildrenCount(final AccessibleExtendedTable acTable) {4752if (acTable == null)4753return;4754int lastVisibleRow = -1;4755int lastVisibleColumn = -1;4756boolean foundVisible = false;4757int rowCount = InvocationUtils.invokeAndWait(new Callable<Integer>() {4758@Override4759public Integer call() throws Exception {4760return acTable.getAccessibleRowCount();4761}4762}, acTable);4763int columnCount = InvocationUtils.invokeAndWait(new Callable<Integer>() {4764@Override4765public Integer call() throws Exception {4766return acTable.getAccessibleColumnCount();4767}4768}, acTable);4769for (int rowIdx = 0; rowIdx < rowCount; rowIdx++) {4770for (int columnIdx = 0; columnIdx < columnCount; columnIdx++) {4771if (lastVisibleRow != -1 && rowIdx > lastVisibleRow) {4772continue;4773}4774if (lastVisibleColumn != -1 && columnIdx > lastVisibleColumn) {4775continue;4776}4777int finalRowIdx = rowIdx;4778int finalColumnIdx = columnIdx;4779final AccessibleContext ac2 = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {4780@Override4781public AccessibleContext call() throws Exception {4782Accessible a = acTable.getAccessibleAt(finalRowIdx, finalColumnIdx);4783if (a == null)4784return null;4785else4786return a.getAccessibleContext();4787}4788}, acTable);4789if (ac2 == null ||4790(!InvocationUtils.invokeAndWait(new Callable<Boolean>() {4791@Override4792public Boolean call() throws Exception {4793return ac2.getAccessibleStateSet().contains(AccessibleState.SHOWING);4794}4795}, acTable))4796) {4797if (foundVisible) {4798if (columnIdx != 0 && lastVisibleColumn == -1) {4799//the same row, so we found the last visible column4800lastVisibleColumn = columnIdx - 1;4801} else if (columnIdx == 0 && lastVisibleRow == -1) {4802lastVisibleRow = rowIdx - 1;4803}4804}4805continue;4806}48074808foundVisible = true;48094810_visibleChildrenCount++;48114812if (InvocationUtils.invokeAndWait(new Callable<Integer>() {4813@Override4814public Integer call() throws Exception {4815return ac2.getAccessibleChildrenCount();4816}4817}, acTable) > 0) {4818_getVisibleChildrenCount(ac2);4819}4820}4821}4822}48234824/**4825* Gets the visible child of an AccessibleContext at the4826* specified index4827*4828* Bug ID 4944762- getVisibleChildren for list-like components needed4829*/4830private AccessibleContext getVisibleChild(AccessibleContext ac, int index) {4831debugString("[INFO]: getVisibleChild: index = "+index);4832if (ac == null) {4833return null;4834}4835_visibleChild = null;4836_currentVisibleIndex = 0;4837_foundVisibleChild = false;4838_getVisibleChild(ac, index);48394840if (_visibleChild != null) {4841debugString( "[INFO]: getVisibleChild: found child = " +4842InvocationUtils.invokeAndWait(new Callable<String>() {4843@Override4844public String call() throws Exception {4845return AccessBridge.this._visibleChild.getAccessibleName();4846}4847}, ac) );4848}4849return _visibleChild;4850}48514852/*4853* Recursively searchs AccessibleContext and finds the visible component4854* at the specified index4855*/4856private void _getVisibleChild(final AccessibleContext ac, final int index) {4857if (_visibleChild != null) {4858return;4859}4860if(ac instanceof AccessibleExtendedTable) {4861_getVisibleChild((AccessibleExtendedTable)ac, index);4862return;4863}4864int numChildren = InvocationUtils.invokeAndWait(new Callable<Integer>() {4865@Override4866public Integer call() throws Exception {4867return ac.getAccessibleChildrenCount();4868}4869}, ac);4870for (int i = 0; i < numChildren; i++) {4871final int idx=i;4872final AccessibleContext ac2 = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {4873@Override4874public AccessibleContext call() throws Exception {4875Accessible a = ac.getAccessibleChild(idx);4876if (a == null)4877return null;4878else4879return a.getAccessibleContext();4880}4881}, ac);4882if (ac2 == null ||4883(!InvocationUtils.invokeAndWait(new Callable<Boolean>() {4884@Override4885public Boolean call() throws Exception {4886return ac2.getAccessibleStateSet().contains(AccessibleState.SHOWING);4887}4888}, ac))) {4889continue;4890}4891if (!_foundVisibleChild && _currentVisibleIndex == index) {4892_visibleChild = ac2;4893_foundVisibleChild = true;4894return;4895}4896_currentVisibleIndex++;48974898if ( InvocationUtils.invokeAndWait(new Callable<Integer>() {4899@Override4900public Integer call() throws Exception {4901return ac2.getAccessibleChildrenCount();4902}4903}, ac) > 0 ) {4904_getVisibleChild(ac2, index);4905}4906}4907}49084909private void _getVisibleChild(final AccessibleExtendedTable acTable, final int index) {4910if (_visibleChild != null) {4911return;4912}4913int lastVisibleRow = -1;4914int lastVisibleColumn = -1;4915boolean foundVisible = false;4916int rowCount = InvocationUtils.invokeAndWait(new Callable<Integer>() {4917@Override4918public Integer call() throws Exception {4919return acTable.getAccessibleRowCount();4920}4921}, acTable);4922int columnCount = InvocationUtils.invokeAndWait(new Callable<Integer>() {4923@Override4924public Integer call() throws Exception {4925return acTable.getAccessibleColumnCount();4926}4927}, acTable);4928for (int rowIdx = 0; rowIdx < rowCount; rowIdx++) {4929for (int columnIdx = 0; columnIdx < columnCount; columnIdx++) {4930if (lastVisibleRow != -1 && rowIdx > lastVisibleRow) {4931continue;4932}4933if (lastVisibleColumn != -1 && columnIdx > lastVisibleColumn) {4934continue;4935}4936int finalRowIdx = rowIdx;4937int finalColumnIdx = columnIdx;4938final AccessibleContext ac2 = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {4939@Override4940public AccessibleContext call() throws Exception {4941Accessible a = acTable.getAccessibleAt(finalRowIdx, finalColumnIdx);4942if (a == null)4943return null;4944else4945return a.getAccessibleContext();4946}4947}, acTable);4948if (ac2 == null ||4949(!InvocationUtils.invokeAndWait(new Callable<Boolean>() {4950@Override4951public Boolean call() throws Exception {4952return ac2.getAccessibleStateSet().contains(AccessibleState.SHOWING);4953}4954}, acTable))) {4955if (foundVisible) {4956if (columnIdx != 0 && lastVisibleColumn == -1) {4957//the same row, so we found the last visible column4958lastVisibleColumn = columnIdx - 1;4959} else if (columnIdx == 0 && lastVisibleRow == -1) {4960lastVisibleRow = rowIdx - 1;4961}4962}4963continue;4964}4965foundVisible = true;49664967if (!_foundVisibleChild && _currentVisibleIndex == index) {4968_visibleChild = ac2;4969_foundVisibleChild = true;4970return;4971}4972_currentVisibleIndex++;49734974if (InvocationUtils.invokeAndWait(new Callable<Integer>() {4975@Override4976public Integer call() throws Exception {4977return ac2.getAccessibleChildrenCount();4978}4979}, acTable) > 0) {4980_getVisibleChild(ac2, index);4981}4982}4983}4984}49854986/* ===== Java object memory management code ===== */49874988/**4989* Class to track object references to ensure the4990* Java VM doesn't garbage collect them4991*/4992private class ObjectReferences {49934994private class Reference {4995private int value;49964997Reference(int i) {4998value = i;4999}50005001public String toString() {5002return ("refCount: " + value);5003}5004}50055006/**5007* table object references, to keep 'em from being garbage collected5008*/5009private ConcurrentHashMap<Object,Reference> refs;50105011/**5012* Constructor5013*/5014ObjectReferences() {5015refs = new ConcurrentHashMap<>(4);5016}50175018/**5019* Debugging: dump the contents of ObjectReferences' refs Hashtable5020*/5021String dump() {5022return refs.toString();5023}50245025/**5026* Increment ref count; set to 1 if we have no references for it5027*/5028void increment(Object o) {5029if (o == null){5030debugString("[WARN]: ObjectReferences::increment - Passed in object is null");5031return;5032}50335034if (refs.containsKey(o)) {5035(refs.get(o)).value++;5036} else {5037refs.put(o, new Reference(1));5038}5039}50405041/**5042* Decrement ref count; remove if count drops to 05043*/5044void decrement(Object o) {5045Reference aRef = refs.get(o);5046if (aRef != null) {5047aRef.value--;5048if (aRef.value == 0) {5049refs.remove(o);5050} else if (aRef.value < 0) {5051debugString("[ERROR]: decrementing reference count below 0");5052}5053} else {5054debugString("[ERROR]: object to decrement not in ObjectReferences table");5055}5056}50575058}50595060/* ===== event handling code ===== */50615062/**5063* native method for handling property change events5064*/5065private native void propertyCaretChange(PropertyChangeEvent e,5066AccessibleContext src,5067int oldValue, int newValue);5068private native void propertyDescriptionChange(PropertyChangeEvent e,5069AccessibleContext src,5070String oldValue, String newValue);5071private native void propertyNameChange(PropertyChangeEvent e,5072AccessibleContext src,5073String oldValue, String newValue);5074private native void propertySelectionChange(PropertyChangeEvent e,5075AccessibleContext src);5076private native void propertyStateChange(PropertyChangeEvent e,5077AccessibleContext src,5078String oldValue, String newValue);5079private native void propertyTextChange(PropertyChangeEvent e,5080AccessibleContext src);5081private native void propertyValueChange(PropertyChangeEvent e,5082AccessibleContext src,5083String oldValue, String newValue);5084private native void propertyVisibleDataChange(PropertyChangeEvent e,5085AccessibleContext src);5086private native void propertyChildChange(PropertyChangeEvent e,5087AccessibleContext src,5088AccessibleContext oldValue,5089AccessibleContext newValue);5090private native void propertyActiveDescendentChange(PropertyChangeEvent e,5091AccessibleContext src,5092AccessibleContext oldValue,5093AccessibleContext newValue);50945095private native void javaShutdown();50965097/**5098* native methods for handling focus events5099*/5100private native void focusGained(FocusEvent e, AccessibleContext src);5101private native void focusLost(FocusEvent e, AccessibleContext src);51025103/**5104* native method for handling caret events5105*/5106private native void caretUpdate(CaretEvent e, AccessibleContext src);51075108/**5109* native methods for handling mouse events5110*/5111private native void mouseClicked(MouseEvent e, AccessibleContext src);5112private native void mouseEntered(MouseEvent e, AccessibleContext src);5113private native void mouseExited(MouseEvent e, AccessibleContext src);5114private native void mousePressed(MouseEvent e, AccessibleContext src);5115private native void mouseReleased(MouseEvent e, AccessibleContext src);51165117/**5118* native methods for handling menu & popupMenu events5119*/5120private native void menuCanceled(MenuEvent e, AccessibleContext src);5121private native void menuDeselected(MenuEvent e, AccessibleContext src);5122private native void menuSelected(MenuEvent e, AccessibleContext src);5123private native void popupMenuCanceled(PopupMenuEvent e, AccessibleContext src);5124private native void popupMenuWillBecomeInvisible(PopupMenuEvent e,5125AccessibleContext src);5126private native void popupMenuWillBecomeVisible(PopupMenuEvent e,5127AccessibleContext src);51285129/* ===== event definitions ===== */51305131private static final long PROPERTY_CHANGE_EVENTS = 1;5132private static final long FOCUS_GAINED_EVENTS = 2;5133private static final long FOCUS_LOST_EVENTS = 4;5134private static final long FOCUS_EVENTS = (FOCUS_GAINED_EVENTS | FOCUS_LOST_EVENTS);51355136private static final long CARET_UPATE_EVENTS = 8;5137private static final long CARET_EVENTS = CARET_UPATE_EVENTS;51385139private static final long MOUSE_CLICKED_EVENTS = 16;5140private static final long MOUSE_ENTERED_EVENTS = 32;5141private static final long MOUSE_EXITED_EVENTS = 64;5142private static final long MOUSE_PRESSED_EVENTS = 128;5143private static final long MOUSE_RELEASED_EVENTS = 256;5144private static final long MOUSE_EVENTS = (MOUSE_CLICKED_EVENTS | MOUSE_ENTERED_EVENTS |5145MOUSE_EXITED_EVENTS | MOUSE_PRESSED_EVENTS |5146MOUSE_RELEASED_EVENTS);51475148private static final long MENU_CANCELED_EVENTS = 512;5149private static final long MENU_DESELECTED_EVENTS = 1024;5150private static final long MENU_SELECTED_EVENTS = 2048;5151private static final long MENU_EVENTS = (MENU_CANCELED_EVENTS | MENU_DESELECTED_EVENTS |5152MENU_SELECTED_EVENTS);51535154private static final long POPUPMENU_CANCELED_EVENTS = 4096;5155private static final long POPUPMENU_WILL_BECOME_INVISIBLE_EVENTS = 8192;5156private static final long POPUPMENU_WILL_BECOME_VISIBLE_EVENTS = 16384;5157private static final long POPUPMENU_EVENTS = (POPUPMENU_CANCELED_EVENTS |5158POPUPMENU_WILL_BECOME_INVISIBLE_EVENTS |5159POPUPMENU_WILL_BECOME_VISIBLE_EVENTS);51605161/* These use their own numbering scheme, to ensure sufficient expansion room */5162private static final long PROPERTY_NAME_CHANGE_EVENTS = 1;5163private static final long PROPERTY_DESCRIPTION_CHANGE_EVENTS = 2;5164private static final long PROPERTY_STATE_CHANGE_EVENTS = 4;5165private static final long PROPERTY_VALUE_CHANGE_EVENTS = 8;5166private static final long PROPERTY_SELECTION_CHANGE_EVENTS = 16;5167private static final long PROPERTY_TEXT_CHANGE_EVENTS = 32;5168private static final long PROPERTY_CARET_CHANGE_EVENTS = 64;5169private static final long PROPERTY_VISIBLEDATA_CHANGE_EVENTS = 128;5170private static final long PROPERTY_CHILD_CHANGE_EVENTS = 256;5171private static final long PROPERTY_ACTIVEDESCENDENT_CHANGE_EVENTS = 512;517251735174private static final long PROPERTY_EVENTS = (PROPERTY_NAME_CHANGE_EVENTS |5175PROPERTY_DESCRIPTION_CHANGE_EVENTS |5176PROPERTY_STATE_CHANGE_EVENTS |5177PROPERTY_VALUE_CHANGE_EVENTS |5178PROPERTY_SELECTION_CHANGE_EVENTS |5179PROPERTY_TEXT_CHANGE_EVENTS |5180PROPERTY_CARET_CHANGE_EVENTS |5181PROPERTY_VISIBLEDATA_CHANGE_EVENTS |5182PROPERTY_CHILD_CHANGE_EVENTS |5183PROPERTY_ACTIVEDESCENDENT_CHANGE_EVENTS);51845185/**5186* The EventHandler class listens for Java events and5187* forwards them to the AT5188*/5189private class EventHandler implements PropertyChangeListener,5190FocusListener, CaretListener,5191MenuListener, PopupMenuListener,5192MouseListener, WindowListener,5193ChangeListener {51945195private AccessBridge accessBridge;5196private long javaEventMask = 0;5197private long accessibilityEventMask = 0;51985199EventHandler(AccessBridge bridge) {5200accessBridge = bridge;52015202// Register to receive WINDOW_OPENED and WINDOW_CLOSED5203// events. Add the event source as a native window5204// handler is it implements NativeWindowHandler.5205// SwingEventMonitor.addWindowListener(this);5206}52075208// --------- Event Notification Registration methods52095210/**5211* Invoked the first time a window is made visible.5212*/5213public void windowOpened(WindowEvent e) {5214// If the window is a NativeWindowHandler, add it.5215Object o = null;5216if (e != null)5217o = e.getSource();5218if (o instanceof NativeWindowHandler) {5219addNativeWindowHandler((NativeWindowHandler)o);5220}5221}52225223/**5224* Invoked when the user attempts to close the window5225* from the window's system menu. If the program does not5226* explicitly hide or dispose the window while processing5227* this event, the window close operation will be canceled.5228*/5229public void windowClosing(WindowEvent e) {}52305231/**5232* Invoked when a window has been closed as the result5233* of calling dispose on the window.5234*/5235public void windowClosed(WindowEvent e) {5236// If the window is a NativeWindowHandler, remove it.5237Object o = null;5238if (e != null)5239o = e.getSource();5240if (o instanceof NativeWindowHandler) {5241removeNativeWindowHandler((NativeWindowHandler)o);5242}5243}52445245/**5246* Invoked when a window is changed from a normal to a5247* minimized state. For many platforms, a minimized window5248* is displayed as the icon specified in the window's5249* iconImage property.5250* @see java.awt.Frame#setIconImage5251*/5252public void windowIconified(WindowEvent e) {}52535254/**5255* Invoked when a window is changed from a minimized5256* to a normal state.5257*/5258public void windowDeiconified(WindowEvent e) {}52595260/**5261* Invoked when the Window is set to be the active Window. Only a Frame or5262* a Dialog can be the active Window. The native windowing system may5263* denote the active Window or its children with special decorations, such5264* as a highlighted title bar. The active Window is always either the5265* focused Window, or the first Frame or Dialog that is an owner of the5266* focused Window.5267*/5268public void windowActivated(WindowEvent e) {}52695270/**5271* Invoked when a Window is no longer the active Window. Only a Frame or a5272* Dialog can be the active Window. The native windowing system may denote5273* the active Window or its children with special decorations, such as a5274* highlighted title bar. The active Window is always either the focused5275* Window, or the first Frame or Dialog that is an owner of the focused5276* Window.5277*/5278public void windowDeactivated(WindowEvent e) {}52795280/**5281* Turn on event monitoring for the event type passed in5282* If necessary, add the appropriate event listener (if5283* no other event of that type is being listened for)5284*/5285void addJavaEventNotification(long type) {5286long newEventMask = javaEventMask | type;5287/*5288if ( ((javaEventMask & PROPERTY_EVENTS) == 0) &&5289((newEventMask & PROPERTY_EVENTS) != 0) ) {5290AccessibilityEventMonitor.addPropertyChangeListener(this);5291}5292*/5293if ( ((javaEventMask & FOCUS_EVENTS) == 0) &&5294((newEventMask & FOCUS_EVENTS) != 0) ) {5295SwingEventMonitor.addFocusListener(this);5296}5297if ( ((javaEventMask & CARET_EVENTS) == 0) &&5298((newEventMask & CARET_EVENTS) != 0) ) {5299SwingEventMonitor.addCaretListener(this);5300}5301if ( ((javaEventMask & MOUSE_EVENTS) == 0) &&5302((newEventMask & MOUSE_EVENTS) != 0) ) {5303SwingEventMonitor.addMouseListener(this);5304}5305if ( ((javaEventMask & MENU_EVENTS) == 0) &&5306((newEventMask & MENU_EVENTS) != 0) ) {5307SwingEventMonitor.addMenuListener(this);5308SwingEventMonitor.addPopupMenuListener(this);5309}5310if ( ((javaEventMask & POPUPMENU_EVENTS) == 0) &&5311((newEventMask & POPUPMENU_EVENTS) != 0) ) {5312SwingEventMonitor.addPopupMenuListener(this);5313}53145315javaEventMask = newEventMask;5316}53175318/**5319* Turn off event monitoring for the event type passed in5320* If necessary, remove the appropriate event listener (if5321* no other event of that type is being listened for)5322*/5323void removeJavaEventNotification(long type) {5324long newEventMask = javaEventMask & (~type);5325/*5326if ( ((javaEventMask & PROPERTY_EVENTS) != 0) &&5327((newEventMask & PROPERTY_EVENTS) == 0) ) {5328AccessibilityEventMonitor.removePropertyChangeListener(this);5329}5330*/5331if (((javaEventMask & FOCUS_EVENTS) != 0) &&5332((newEventMask & FOCUS_EVENTS) == 0)) {5333SwingEventMonitor.removeFocusListener(this);5334}5335if (((javaEventMask & CARET_EVENTS) != 0) &&5336((newEventMask & CARET_EVENTS) == 0)) {5337SwingEventMonitor.removeCaretListener(this);5338}5339if (((javaEventMask & MOUSE_EVENTS) == 0) &&5340((newEventMask & MOUSE_EVENTS) != 0)) {5341SwingEventMonitor.removeMouseListener(this);5342}5343if (((javaEventMask & MENU_EVENTS) == 0) &&5344((newEventMask & MENU_EVENTS) != 0)) {5345SwingEventMonitor.removeMenuListener(this);5346}5347if (((javaEventMask & POPUPMENU_EVENTS) == 0) &&5348((newEventMask & POPUPMENU_EVENTS) != 0)) {5349SwingEventMonitor.removePopupMenuListener(this);5350}53515352javaEventMask = newEventMask;5353}53545355/**5356* Turn on event monitoring for the event type passed in5357* If necessary, add the appropriate event listener (if5358* no other event of that type is being listened for)5359*/5360void addAccessibilityEventNotification(long type) {5361long newEventMask = accessibilityEventMask | type;5362if ( ((accessibilityEventMask & PROPERTY_EVENTS) == 0) &&5363((newEventMask & PROPERTY_EVENTS) != 0) ) {5364AccessibilityEventMonitor.addPropertyChangeListener(this);5365}5366accessibilityEventMask = newEventMask;5367}53685369/**5370* Turn off event monitoring for the event type passed in5371* If necessary, remove the appropriate event listener (if5372* no other event of that type is being listened for)5373*/5374void removeAccessibilityEventNotification(long type) {5375long newEventMask = accessibilityEventMask & (~type);5376if ( ((accessibilityEventMask & PROPERTY_EVENTS) != 0) &&5377((newEventMask & PROPERTY_EVENTS) == 0) ) {5378AccessibilityEventMonitor.removePropertyChangeListener(this);5379}5380accessibilityEventMask = newEventMask;5381}53825383/**5384* ------- property change event glue5385*/5386// This is invoked on the EDT , as5387public void propertyChange(PropertyChangeEvent e) {53885389accessBridge.debugString("[INFO]: propertyChange(" + e.toString() + ") called");53905391if (e != null && (accessibilityEventMask & PROPERTY_EVENTS) != 0) {5392Object o = e.getSource();5393AccessibleContext ac;53945395if (o instanceof AccessibleContext) {5396ac = (AccessibleContext) o;5397} else {5398Accessible a = Translator.getAccessible(e.getSource());5399if (a == null)5400return;5401else5402ac = a.getAccessibleContext();5403}5404if (ac != null) {5405InvocationUtils.registerAccessibleContext(ac, AppContext.getAppContext());54065407accessBridge.debugString("[INFO]: AccessibleContext: " + ac);5408String propertyName = e.getPropertyName();54095410if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_CARET_PROPERTY) == 0) {5411int oldValue = 0;5412int newValue = 0;54135414if (e.getOldValue() instanceof Integer) {5415oldValue = ((Integer) e.getOldValue()).intValue();5416}5417if (e.getNewValue() instanceof Integer) {5418newValue = ((Integer) e.getNewValue()).intValue();5419}5420accessBridge.debugString("[INFO]: - about to call propertyCaretChange() old value: " + oldValue + "new value: " + newValue);5421accessBridge.propertyCaretChange(e, ac, oldValue, newValue);54225423} else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_DESCRIPTION_PROPERTY) == 0) {5424String oldValue = null;5425String newValue = null;54265427if (e.getOldValue() != null) {5428oldValue = e.getOldValue().toString();5429}5430if (e.getNewValue() != null) {5431newValue = e.getNewValue().toString();5432}5433accessBridge.debugString("[INFO]: - about to call propertyDescriptionChange() old value: " + oldValue + "new value: " + newValue);5434accessBridge.propertyDescriptionChange(e, ac, oldValue, newValue);54355436} else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_NAME_PROPERTY) == 0) {5437String oldValue = null;5438String newValue = null;54395440if (e.getOldValue() != null) {5441oldValue = e.getOldValue().toString();5442}5443if (e.getNewValue() != null) {5444newValue = e.getNewValue().toString();5445}5446accessBridge.debugString("[INFO]: - about to call propertyNameChange() old value: " + oldValue + " new value: " + newValue);5447accessBridge.propertyNameChange(e, ac, oldValue, newValue);54485449} else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY) == 0) {5450accessBridge.debugString("[INFO]: - about to call propertySelectionChange() " + ac + " " + Thread.currentThread() + " " + e.getSource());54515452accessBridge.propertySelectionChange(e, ac);54535454} else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_STATE_PROPERTY) == 0) {5455String oldValue = null;5456String newValue = null;54575458// Localization fix requested by Oliver for EA-15459if (e.getOldValue() != null) {5460AccessibleState oldState = (AccessibleState) e.getOldValue();5461oldValue = oldState.toDisplayString(Locale.US);5462}5463if (e.getNewValue() != null) {5464AccessibleState newState = (AccessibleState) e.getNewValue();5465newValue = newState.toDisplayString(Locale.US);5466}54675468accessBridge.debugString("[INFO]: - about to call propertyStateChange()");5469accessBridge.propertyStateChange(e, ac, oldValue, newValue);54705471} else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_TEXT_PROPERTY) == 0) {5472accessBridge.debugString("[INFO]: - about to call propertyTextChange()");5473accessBridge.propertyTextChange(e, ac);54745475} else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_VALUE_PROPERTY) == 0) { // strings 'cause of floating point, etc.5476String oldValue = null;5477String newValue = null;54785479if (e.getOldValue() != null) {5480oldValue = e.getOldValue().toString();5481}5482if (e.getNewValue() != null) {5483newValue = e.getNewValue().toString();5484}5485accessBridge.debugString("[INFO]: - about to call propertyDescriptionChange()");5486accessBridge.propertyValueChange(e, ac, oldValue, newValue);54875488} else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY) == 0) {5489accessBridge.propertyVisibleDataChange(e, ac);54905491} else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_CHILD_PROPERTY) == 0) {5492AccessibleContext oldAC = null;5493AccessibleContext newAC = null;5494Accessible a;54955496if (e.getOldValue() instanceof AccessibleContext) {5497oldAC = (AccessibleContext) e.getOldValue();5498InvocationUtils.registerAccessibleContext(oldAC, AppContext.getAppContext());5499}5500if (e.getNewValue() instanceof AccessibleContext) {5501newAC = (AccessibleContext) e.getNewValue();5502InvocationUtils.registerAccessibleContext(newAC, AppContext.getAppContext());5503}5504accessBridge.debugString("[INFO]: - about to call propertyChildChange() old AC: " + oldAC + "new AC: " + newAC);5505accessBridge.propertyChildChange(e, ac, oldAC, newAC);55065507} else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY) == 0) {5508handleActiveDescendentEvent(e, ac);5509}5510}5511}5512}55135514/*5515* Handle an ActiveDescendent PropertyChangeEvent. This5516* method works around a JTree bug where ActiveDescendent5517* PropertyChangeEvents have the wrong parent.5518*/5519private AccessibleContext prevAC = null; // previous AccessibleContext55205521private void handleActiveDescendentEvent(PropertyChangeEvent e,5522AccessibleContext ac) {5523if (e == null || ac == null)5524return;5525AccessibleContext oldAC = null;5526AccessibleContext newAC = null;5527Accessible a;55285529// get the old active descendent5530if (e.getOldValue() instanceof Accessible) {5531oldAC = ((Accessible) e.getOldValue()).getAccessibleContext();5532} else if (e.getOldValue() instanceof Component) {5533a = Translator.getAccessible(e.getOldValue());5534if (a != null) {5535oldAC = a.getAccessibleContext();5536}5537}5538if (oldAC != null) {5539Accessible parent = oldAC.getAccessibleParent();5540if (parent instanceof JTree) {5541// use the previous AccessibleJTreeNode5542oldAC = prevAC;5543}5544}55455546// get the new active descendent5547if (e.getNewValue() instanceof Accessible) {5548newAC = ((Accessible) e.getNewValue()).getAccessibleContext();5549} else if (e.getNewValue() instanceof Component) {5550a = Translator.getAccessible(e.getNewValue());5551if (a != null) {5552newAC = a.getAccessibleContext();5553}5554}5555if (newAC != null) {5556Accessible parent = newAC.getAccessibleParent();5557if (parent instanceof JTree) {5558// use a new AccessibleJTreeNode with the right parent5559JTree tree = (JTree)parent;5560newAC = new AccessibleJTreeNode(tree,5561tree.getSelectionPath(),5562null);5563}5564}5565prevAC = newAC;55665567accessBridge.debugString("[INFO]: - about to call propertyActiveDescendentChange() AC: " + ac + " old AC: " + oldAC + "new AC: " + newAC);5568InvocationUtils.registerAccessibleContext(oldAC, AppContext.getAppContext());5569InvocationUtils.registerAccessibleContext(newAC, AppContext.getAppContext());5570accessBridge.propertyActiveDescendentChange(e, ac, oldAC, newAC);5571}55725573/**5574* ------- focus event glue5575*/5576private boolean stateChangeListenerAdded = false;55775578public void focusGained(FocusEvent e) {5579if (runningOnJDK1_4) {5580processFocusGained();5581} else {5582if ((javaEventMask & FOCUS_GAINED_EVENTS) != 0) {5583Accessible a = Translator.getAccessible(e.getSource());5584if (a != null) {5585AccessibleContext context = a.getAccessibleContext();5586InvocationUtils.registerAccessibleContext(context, SunToolkit.targetToAppContext(e.getSource()));5587accessBridge.focusGained(e, context);5588}5589}5590}5591}55925593public void stateChanged(ChangeEvent e) {5594processFocusGained();5595}55965597private void processFocusGained() {5598Component focusOwner = KeyboardFocusManager.5599getCurrentKeyboardFocusManager().getFocusOwner();5600if (focusOwner == null) {5601return;5602}56035604// Only menus and popup selections are handled by the JRootPane.5605if (focusOwner instanceof JRootPane) {5606MenuElement [] path =5607MenuSelectionManager.defaultManager().getSelectedPath();5608if (path.length > 1) {5609Component penult = path[path.length-2].getComponent();5610Component last = path[path.length-1].getComponent();56115612if (last instanceof JPopupMenu) {5613// This is a popup with nothing in the popup5614// selected. The menu itself is selected.5615FocusEvent e = new FocusEvent(penult, FocusEvent.FOCUS_GAINED);5616AccessibleContext context = penult.getAccessibleContext();5617InvocationUtils.registerAccessibleContext(context, SunToolkit.targetToAppContext(penult));5618accessBridge.focusGained(e, context);5619} else if (penult instanceof JPopupMenu) {5620// This is a popup with an item selected5621FocusEvent e =5622new FocusEvent(last, FocusEvent.FOCUS_GAINED);5623AccessibleContext focusedAC = last.getAccessibleContext();5624InvocationUtils.registerAccessibleContext(focusedAC, SunToolkit.targetToAppContext(last));5625accessBridge.debugString("[INFO]: - about to call focusGained() AC: " + focusedAC);5626accessBridge.focusGained(e, focusedAC);5627}5628}5629} else {5630// The focus owner has the selection.5631if (focusOwner instanceof Accessible) {5632FocusEvent e = new FocusEvent(focusOwner,5633FocusEvent.FOCUS_GAINED);5634AccessibleContext focusedAC = focusOwner.getAccessibleContext();5635InvocationUtils.registerAccessibleContext(focusedAC, SunToolkit.targetToAppContext(focusOwner));5636accessBridge.debugString("[INFO]: - about to call focusGained() AC: " + focusedAC);5637accessBridge.focusGained(e, focusedAC);5638}5639}5640}56415642public void focusLost(FocusEvent e) {5643if (e != null && (javaEventMask & FOCUS_LOST_EVENTS) != 0) {5644Accessible a = Translator.getAccessible(e.getSource());5645if (a != null) {5646accessBridge.debugString("[INFO]: - about to call focusLost() AC: " + a.getAccessibleContext());5647AccessibleContext context = a.getAccessibleContext();5648InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5649accessBridge.focusLost(e, context);5650}5651}5652}56535654/**5655* ------- caret event glue5656*/5657public void caretUpdate(CaretEvent e) {5658if (e != null && (javaEventMask & CARET_UPATE_EVENTS) != 0) {5659Accessible a = Translator.getAccessible(e.getSource());5660if (a != null) {5661AccessibleContext context = a.getAccessibleContext();5662InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5663accessBridge.caretUpdate(e, context);5664}5665}5666}56675668/**5669* ------- mouse event glue5670*/56715672public void mouseClicked(MouseEvent e) {5673if (e != null && (javaEventMask & MOUSE_CLICKED_EVENTS) != 0) {5674Accessible a = Translator.getAccessible(e.getSource());5675if (a != null) {5676AccessibleContext context = a.getAccessibleContext();5677InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5678accessBridge.mouseClicked(e, context);5679}5680}5681}56825683public void mouseEntered(MouseEvent e) {5684if (e != null && (javaEventMask & MOUSE_ENTERED_EVENTS) != 0) {5685Accessible a = Translator.getAccessible(e.getSource());5686if (a != null) {5687AccessibleContext context = a.getAccessibleContext();5688InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5689accessBridge.mouseEntered(e, context);5690}5691}5692}56935694public void mouseExited(MouseEvent e) {5695if (e != null && (javaEventMask & MOUSE_EXITED_EVENTS) != 0) {5696Accessible a = Translator.getAccessible(e.getSource());5697if (a != null) {5698AccessibleContext context = a.getAccessibleContext();5699InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5700accessBridge.mouseExited(e, context);5701}5702}5703}57045705public void mousePressed(MouseEvent e) {5706if (e != null && (javaEventMask & MOUSE_PRESSED_EVENTS) != 0) {5707Accessible a = Translator.getAccessible(e.getSource());5708if (a != null) {5709AccessibleContext context = a.getAccessibleContext();5710InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5711accessBridge.mousePressed(e, context);5712}5713}5714}57155716public void mouseReleased(MouseEvent e) {5717if (e != null && (javaEventMask & MOUSE_RELEASED_EVENTS) != 0) {5718Accessible a = Translator.getAccessible(e.getSource());5719if (a != null) {5720AccessibleContext context = a.getAccessibleContext();5721InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5722accessBridge.mouseReleased(e, context);5723}5724}5725}57265727/**5728* ------- menu event glue5729*/5730public void menuCanceled(MenuEvent e) {5731if (e != null && (javaEventMask & MENU_CANCELED_EVENTS) != 0) {5732Accessible a = Translator.getAccessible(e.getSource());5733if (a != null) {5734AccessibleContext context = a.getAccessibleContext();5735InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5736accessBridge.menuCanceled(e, context);5737}5738}5739}57405741public void menuDeselected(MenuEvent e) {5742if (e != null && (javaEventMask & MENU_DESELECTED_EVENTS) != 0) {5743Accessible a = Translator.getAccessible(e.getSource());5744if (a != null) {5745AccessibleContext context = a.getAccessibleContext();5746InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5747accessBridge.menuDeselected(e, context);5748}5749}5750}57515752public void menuSelected(MenuEvent e) {5753if (e != null && (javaEventMask & MENU_SELECTED_EVENTS) != 0) {5754Accessible a = Translator.getAccessible(e.getSource());5755if (a != null) {5756AccessibleContext context = a.getAccessibleContext();5757InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5758accessBridge.menuSelected(e, context);5759}5760}5761}57625763public void popupMenuCanceled(PopupMenuEvent e) {5764if (e != null && (javaEventMask & POPUPMENU_CANCELED_EVENTS) != 0) {5765Accessible a = Translator.getAccessible(e.getSource());5766if (a != null) {5767AccessibleContext context = a.getAccessibleContext();5768InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5769accessBridge.popupMenuCanceled(e, context);5770}5771}5772}57735774public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {5775if (e != null && (javaEventMask & POPUPMENU_WILL_BECOME_INVISIBLE_EVENTS) != 0) {5776Accessible a = Translator.getAccessible(e.getSource());5777if (a != null) {5778AccessibleContext context = a.getAccessibleContext();5779InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5780accessBridge.popupMenuWillBecomeInvisible(e, context);5781}5782}5783}57845785public void popupMenuWillBecomeVisible(PopupMenuEvent e) {5786if (e != null && (javaEventMask & POPUPMENU_WILL_BECOME_VISIBLE_EVENTS) != 0) {5787Accessible a = Translator.getAccessible(e.getSource());5788if (a != null) {5789AccessibleContext context = a.getAccessibleContext();5790InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5791accessBridge.popupMenuWillBecomeVisible(e, context);5792}5793}5794}57955796} // End of EventHandler Class57975798// --------- Event Notification Registration methods57995800/**5801* Wrapper method around eventHandler.addJavaEventNotification()5802*/5803private void addJavaEventNotification(final long type) {5804EventQueue.invokeLater(new Runnable() {5805public void run(){5806eventHandler.addJavaEventNotification(type);5807}5808});5809}58105811/**5812* Wrapper method around eventHandler.removeJavaEventNotification()5813*/5814private void removeJavaEventNotification(final long type) {5815EventQueue.invokeLater(new Runnable() {5816public void run(){5817eventHandler.removeJavaEventNotification(type);5818}5819});5820}582158225823/**5824* Wrapper method around eventHandler.addAccessibilityEventNotification()5825*/5826private void addAccessibilityEventNotification(final long type) {5827EventQueue.invokeLater(new Runnable() {5828public void run(){5829eventHandler.addAccessibilityEventNotification(type);5830}5831});5832}58335834/**5835* Wrapper method around eventHandler.removeAccessibilityEventNotification()5836*/5837private void removeAccessibilityEventNotification(final long type) {5838EventQueue.invokeLater(new Runnable() {5839public void run(){5840eventHandler.removeAccessibilityEventNotification(type);5841}5842});5843}58445845/**5846******************************************************5847* All AccessibleRoles5848*5849* We shouldn't have to do this since it requires us5850* to synchronize the allAccessibleRoles array when5851* the AccessibleRoles class interface changes. However,5852* there is no Accessibility API method to get all5853* AccessibleRoles5854******************************************************5855*/5856private AccessibleRole [] allAccessibleRoles = {5857/**5858* Object is used to alert the user about something.5859*/5860AccessibleRole.ALERT,58615862/**5863* The header for a column of data.5864*/5865AccessibleRole.COLUMN_HEADER,58665867/**5868* Object that can be drawn into and is used to trap5869* events.5870* @see #FRAME5871* @see #GLASS_PANE5872* @see #LAYERED_PANE5873*/5874AccessibleRole.CANVAS,58755876/**5877* A list of choices the user can select from. Also optionally5878* allows the user to enter a choice of their own.5879*/5880AccessibleRole.COMBO_BOX,58815882/**5883* An iconified internal frame in a DESKTOP_PANE.5884* @see #DESKTOP_PANE5885* @see #INTERNAL_FRAME5886*/5887AccessibleRole.DESKTOP_ICON,58885889/**5890* A frame-like object that is clipped by a desktop pane. The5891* desktop pane, internal frame, and desktop icon objects are5892* often used to create multiple document interfaces within an5893* application.5894* @see #DESKTOP_ICON5895* @see #DESKTOP_PANE5896* @see #FRAME5897*/5898AccessibleRole.INTERNAL_FRAME,58995900/**5901* A pane that supports internal frames and5902* iconified versions of those internal frames.5903* @see #DESKTOP_ICON5904* @see #INTERNAL_FRAME5905*/5906AccessibleRole.DESKTOP_PANE,59075908/**5909* A specialized pane whose primary use is inside a DIALOG5910* @see #DIALOG5911*/5912AccessibleRole.OPTION_PANE,59135914/**5915* A top level window with no title or border.5916* @see #FRAME5917* @see #DIALOG5918*/5919AccessibleRole.WINDOW,59205921/**5922* A top level window with a title bar, border, menu bar, etc. It is5923* often used as the primary window for an application.5924* @see #DIALOG5925* @see #CANVAS5926* @see #WINDOW5927*/5928AccessibleRole.FRAME,59295930/**5931* A top level window with title bar and a border. A dialog is similar5932* to a frame, but it has fewer properties and is often used as a5933* secondary window for an application.5934* @see #FRAME5935* @see #WINDOW5936*/5937AccessibleRole.DIALOG,59385939/**5940* A specialized dialog that lets the user choose a color.5941*/5942AccessibleRole.COLOR_CHOOSER,594359445945/**5946* A pane that allows the user to navigate through5947* and select the contents of a directory. May be used5948* by a file chooser.5949* @see #FILE_CHOOSER5950*/5951AccessibleRole.DIRECTORY_PANE,59525953/**5954* A specialized dialog that displays the files in the directory5955* and lets the user select a file, browse a different directory,5956* or specify a filename. May use the directory pane to show the5957* contents of a directory.5958* @see #DIRECTORY_PANE5959*/5960AccessibleRole.FILE_CHOOSER,59615962/**5963* An object that fills up space in a user interface. It is often5964* used in interfaces to tweak the spacing between components,5965* but serves no other purpose.5966*/5967AccessibleRole.FILLER,59685969/**5970* A hypertext anchor5971*/5972// AccessibleRole.HYPERLINK,59735974/**5975* A small fixed size picture, typically used to decorate components.5976*/5977AccessibleRole.ICON,59785979/**5980* An object used to present an icon or short string in an interface.5981*/5982AccessibleRole.LABEL,59835984/**5985* A specialized pane that has a glass pane and a layered pane as its5986* children.5987* @see #GLASS_PANE5988* @see #LAYERED_PANE5989*/5990AccessibleRole.ROOT_PANE,59915992/**5993* A pane that is guaranteed to be painted on top5994* of all panes beneath it.5995* @see #ROOT_PANE5996* @see #CANVAS5997*/5998AccessibleRole.GLASS_PANE,59996000/**6001* A specialized pane that allows its children to be drawn in layers,6002* providing a form of stacking order. This is usually the pane that6003* holds the menu bar as well as the pane that contains most of the6004* visual components in a window.6005* @see #GLASS_PANE6006* @see #ROOT_PANE6007*/6008AccessibleRole.LAYERED_PANE,60096010/**6011* An object that presents a list of objects to the user and allows the6012* user to select one or more of them. A list is usually contained6013* within a scroll pane.6014* @see #SCROLL_PANE6015* @see #LIST_ITEM6016*/6017AccessibleRole.LIST,60186019/**6020* An object that presents an element in a list. A list is usually6021* contained within a scroll pane.6022* @see #SCROLL_PANE6023* @see #LIST6024*/6025AccessibleRole.LIST_ITEM,60266027/**6028* An object usually drawn at the top of the primary dialog box of6029* an application that contains a list of menus the user can choose6030* from. For example, a menu bar might contain menus for "File,"6031* "Edit," and "Help."6032* @see #MENU6033* @see #POPUP_MENU6034* @see #LAYERED_PANE6035*/6036AccessibleRole.MENU_BAR,60376038/**6039* A temporary window that is usually used to offer the user a6040* list of choices, and then hides when the user selects one of6041* those choices.6042* @see #MENU6043* @see #MENU_ITEM6044*/6045AccessibleRole.POPUP_MENU,60466047/**6048* An object usually found inside a menu bar that contains a list6049* of actions the user can choose from. A menu can have any object6050* as its children, but most often they are menu items, other menus,6051* or rudimentary objects such as radio buttons, check boxes, or6052* separators. For example, an application may have an "Edit" menu6053* that contains menu items for "Cut" and "Paste."6054* @see #MENU_BAR6055* @see #MENU_ITEM6056* @see #SEPARATOR6057* @see #RADIO_BUTTON6058* @see #CHECK_BOX6059* @see #POPUP_MENU6060*/6061AccessibleRole.MENU,60626063/**6064* An object usually contained in a menu that presents an action6065* the user can choose. For example, the "Cut" menu item in an6066* "Edit" menu would be an action the user can select to cut the6067* selected area of text in a document.6068* @see #MENU_BAR6069* @see #SEPARATOR6070* @see #POPUP_MENU6071*/6072AccessibleRole.MENU_ITEM,60736074/**6075* An object usually contained in a menu to provide a visual6076* and logical separation of the contents in a menu. For example,6077* the "File" menu of an application might contain menu items for6078* "Open," "Close," and "Exit," and will place a separator between6079* "Close" and "Exit" menu items.6080* @see #MENU6081* @see #MENU_ITEM6082*/6083AccessibleRole.SEPARATOR,60846085/**6086* An object that presents a series of panels (or page tabs), one at a6087* time, through some mechanism provided by the object. The most common6088* mechanism is a list of tabs at the top of the panel. The children of6089* a page tab list are all page tabs.6090* @see #PAGE_TAB6091*/6092AccessibleRole.PAGE_TAB_LIST,60936094/**6095* An object that is a child of a page tab list. Its sole child is6096* the panel that is to be presented to the user when the user6097* selects the page tab from the list of tabs in the page tab list.6098* @see #PAGE_TAB_LIST6099*/6100AccessibleRole.PAGE_TAB,61016102/**6103* A generic container that is often used to group objects.6104*/6105AccessibleRole.PANEL,61066107/**6108* An object used to indicate how much of a task has been completed.6109*/6110AccessibleRole.PROGRESS_BAR,61116112/**6113* A text object used for passwords, or other places where the6114* text contents is not shown visibly to the user6115*/6116AccessibleRole.PASSWORD_TEXT,61176118/**6119* An object the user can manipulate to tell the application to do6120* something.6121* @see #CHECK_BOX6122* @see #TOGGLE_BUTTON6123* @see #RADIO_BUTTON6124*/6125AccessibleRole.PUSH_BUTTON,61266127/**6128* A specialized push button that can be checked or unchecked, but6129* does not provide a separate indicator for the current state.6130* @see #PUSH_BUTTON6131* @see #CHECK_BOX6132* @see #RADIO_BUTTON6133*/6134AccessibleRole.TOGGLE_BUTTON,61356136/**6137* A choice that can be checked or unchecked and provides a6138* separate indicator for the current state.6139* @see #PUSH_BUTTON6140* @see #TOGGLE_BUTTON6141* @see #RADIO_BUTTON6142*/6143AccessibleRole.CHECK_BOX,61446145/**6146* A specialized check box that will cause other radio buttons in the6147* same group to become unchecked when this one is checked.6148* @see #PUSH_BUTTON6149* @see #TOGGLE_BUTTON6150* @see #CHECK_BOX6151*/6152AccessibleRole.RADIO_BUTTON,61536154/**6155* The header for a row of data.6156*/6157AccessibleRole.ROW_HEADER,61586159/**6160* An object that allows a user to incrementally view a large amount6161* of information. Its children can include scroll bars and a viewport.6162* @see #SCROLL_BAR6163* @see #VIEWPORT6164*/6165AccessibleRole.SCROLL_PANE,61666167/**6168* An object usually used to allow a user to incrementally view a6169* large amount of data. Usually used only by a scroll pane.6170* @see #SCROLL_PANE6171*/6172AccessibleRole.SCROLL_BAR,61736174/**6175* An object usually used in a scroll pane. It represents the portion6176* of the entire data that the user can see. As the user manipulates6177* the scroll bars, the contents of the viewport can change.6178* @see #SCROLL_PANE6179*/6180AccessibleRole.VIEWPORT,61816182/**6183* An object that allows the user to select from a bounded range. For6184* example, a slider might be used to select a number between 0 and 100.6185*/6186AccessibleRole.SLIDER,61876188/**6189* A specialized panel that presents two other panels at the same time.6190* Between the two panels is a divider the user can manipulate to make6191* one panel larger and the other panel smaller.6192*/6193AccessibleRole.SPLIT_PANE,61946195/**6196* An object used to present information in terms of rows and columns.6197* An example might include a spreadsheet application.6198*/6199AccessibleRole.TABLE,62006201/**6202* An object that presents text to the user. The text is usually6203* editable by the user as opposed to a label.6204* @see #LABEL6205*/6206AccessibleRole.TEXT,62076208/**6209* An object used to present hierarchical information to the user.6210* The individual nodes in the tree can be collapsed and expanded6211* to provide selective disclosure of the tree's contents.6212*/6213AccessibleRole.TREE,62146215/**6216* A bar or palette usually composed of push buttons or toggle buttons.6217* It is often used to provide the most frequently used functions for an6218* application.6219*/6220AccessibleRole.TOOL_BAR,62216222/**6223* An object that provides information about another object. The6224* accessibleDescription property of the tool tip is often displayed6225* to the user in a small "help bubble" when the user causes the6226* mouse to hover over the object associated with the tool tip.6227*/6228AccessibleRole.TOOL_TIP,62296230/**6231* An AWT component, but nothing else is known about it.6232* @see #SWING_COMPONENT6233* @see #UNKNOWN6234*/6235AccessibleRole.AWT_COMPONENT,62366237/**6238* A Swing component, but nothing else is known about it.6239* @see #AWT_COMPONENT6240* @see #UNKNOWN6241*/6242AccessibleRole.SWING_COMPONENT,62436244/**6245* The object contains some Accessible information, but its role is6246* not known.6247* @see #AWT_COMPONENT6248* @see #SWING_COMPONENT6249*/6250AccessibleRole.UNKNOWN,62516252// These roles are only available in JDK 1.462536254/**6255* A STATUS_BAR is an simple component that can contain6256* multiple labels of status information to the user.6257AccessibleRole.STATUS_BAR,62586259/**6260* A DATE_EDITOR is a component that allows users to edit6261* java.util.Date and java.util.Time objects6262AccessibleRole.DATE_EDITOR,62636264/**6265* A SPIN_BOX is a simple spinner component and its main use6266* is for simple numbers.6267AccessibleRole.SPIN_BOX,62686269/**6270* A FONT_CHOOSER is a component that lets the user pick various6271* attributes for fonts.6272AccessibleRole.FONT_CHOOSER,62736274/**6275* A GROUP_BOX is a simple container that contains a border6276* around it and contains components inside it.6277AccessibleRole.GROUP_BOX62786279/**6280* Since JDK 1.56281*6282* A text header62836284AccessibleRole.HEADER,62856286/**6287* A text footer62886289AccessibleRole.FOOTER,62906291/**6292* A text paragraph62936294AccessibleRole.PARAGRAPH,62956296/**6297* A ruler is an object used to measure distance62986299AccessibleRole.RULER,63006301/**6302* A role indicating the object acts as a formula for6303* calculating a value. An example is a formula in6304* a spreadsheet cell.6305AccessibleRole.EDITBAR6306*/6307};63086309/**6310* This class implements accessibility support for the6311* <code>JTree</code> child. It provides an implementation of the6312* Java Accessibility API appropriate to tree nodes.6313*6314* Copied from JTree.java to work around a JTree bug where6315* ActiveDescendent PropertyChangeEvents contain the wrong6316* parent.6317*/6318/**6319* This class in invoked on the EDT as its part of ActiveDescendant,6320* hence the calls do not need to be specifically made on the EDT6321*/6322private class AccessibleJTreeNode extends AccessibleContext6323implements Accessible, AccessibleComponent, AccessibleSelection,6324AccessibleAction {63256326private JTree tree = null;6327private TreeModel treeModel = null;6328private Object obj = null;6329private TreePath path = null;6330private Accessible accessibleParent = null;6331private int index = 0;6332private boolean isLeaf = false;63336334/**6335* Constructs an AccessibleJTreeNode6336*/6337AccessibleJTreeNode(JTree t, TreePath p, Accessible ap) {6338tree = t;6339path = p;6340accessibleParent = ap;6341if (t != null)6342treeModel = t.getModel();6343if (p != null) {6344obj = p.getLastPathComponent();6345if (treeModel != null && obj != null) {6346isLeaf = treeModel.isLeaf(obj);6347}6348}6349debugString("[INFO]: AccessibleJTreeNode: name = "+getAccessibleName()+"; TreePath = "+p+"; parent = "+ap);6350}63516352private TreePath getChildTreePath(int i) {6353// Tree nodes can't be so complex that they have6354// two sets of children -> we're ignoring that case6355if (i < 0 || i >= getAccessibleChildrenCount() || path == null || treeModel == null) {6356return null;6357} else {6358Object childObj = treeModel.getChild(obj, i);6359Object[] objPath = path.getPath();6360Object[] objChildPath = new Object[objPath.length+1];6361java.lang.System.arraycopy(objPath, 0, objChildPath, 0, objPath.length);6362objChildPath[objChildPath.length-1] = childObj;6363return new TreePath(objChildPath);6364}6365}63666367/**6368* Get the AccessibleContext associated with this tree node.6369* In the implementation of the Java Accessibility API for6370* this class, return this object, which is its own6371* AccessibleContext.6372*6373* @return this object6374*/6375public AccessibleContext getAccessibleContext() {6376return this;6377}63786379private AccessibleContext getCurrentAccessibleContext() {6380Component c = getCurrentComponent();6381if (c instanceof Accessible) {6382return (c.getAccessibleContext());6383} else {6384return null;6385}6386}63876388private Component getCurrentComponent() {6389debugString("[INFO]: AccessibleJTreeNode: getCurrentComponent");6390// is the object visible?6391// if so, get row, selected, focus & leaf state,6392// and then get the renderer component and return it6393if (tree != null && tree.isVisible(path)) {6394TreeCellRenderer r = tree.getCellRenderer();6395if (r == null) {6396debugString("[WARN]: returning null 1");6397return null;6398}6399TreeUI ui = tree.getUI();6400if (ui != null) {6401int row = ui.getRowForPath(tree, path);6402boolean selected = tree.isPathSelected(path);6403boolean expanded = tree.isExpanded(path);6404boolean hasFocus = false; // how to tell?? -PK6405Component retval = r.getTreeCellRendererComponent(tree, obj,6406selected, expanded,6407isLeaf, row, hasFocus);6408debugString("[INFO]: returning = "+retval.getClass());6409return retval;6410}6411}6412debugString("[WARN]: returning null 2");6413return null;6414}64156416// AccessibleContext methods64176418/**6419* Get the accessible name of this object.6420*6421* @return the localized name of the object; null if this6422* object does not have a name6423*/6424public String getAccessibleName() {6425debugString("[INFO]: AccessibleJTreeNode: getAccessibleName");6426AccessibleContext ac = getCurrentAccessibleContext();6427if (ac != null) {6428String name = ac.getAccessibleName();6429if ((name != null) && (!name.isEmpty())) {6430String retval = ac.getAccessibleName();6431debugString("[INFO]: returning "+retval);6432return retval;6433} else {6434return null;6435}6436}6437if ((accessibleName != null) && (accessibleName.isEmpty())) {6438return accessibleName;6439} else {6440return null;6441}6442}64436444/**6445* Set the localized accessible name of this object.6446*6447* @param s the new localized name of the object.6448*/6449public void setAccessibleName(String s) {6450AccessibleContext ac = getCurrentAccessibleContext();6451if (ac != null) {6452ac.setAccessibleName(s);6453} else {6454super.setAccessibleName(s);6455}6456}64576458//6459// *** should check tooltip text for desc. (needs MouseEvent)6460//6461/**6462* Get the accessible description of this object.6463*6464* @return the localized description of the object; null if6465* this object does not have a description6466*/6467public String getAccessibleDescription() {6468AccessibleContext ac = getCurrentAccessibleContext();6469if (ac != null) {6470return ac.getAccessibleDescription();6471} else {6472return super.getAccessibleDescription();6473}6474}64756476/**6477* Set the accessible description of this object.6478*6479* @param s the new localized description of the object6480*/6481public void setAccessibleDescription(String s) {6482AccessibleContext ac = getCurrentAccessibleContext();6483if (ac != null) {6484ac.setAccessibleDescription(s);6485} else {6486super.setAccessibleDescription(s);6487}6488}64896490/**6491* Get the role of this object.6492*6493* @return an instance of AccessibleRole describing the role of the object6494* @see AccessibleRole6495*/6496public AccessibleRole getAccessibleRole() {6497AccessibleContext ac = getCurrentAccessibleContext();6498if (ac != null) {6499return ac.getAccessibleRole();6500} else {6501return AccessibleRole.UNKNOWN;6502}6503}65046505/**6506* Get the state set of this object.6507*6508* @return an instance of AccessibleStateSet containing the6509* current state set of the object6510* @see AccessibleState6511*/6512public AccessibleStateSet getAccessibleStateSet() {6513if (tree == null)6514return null;6515AccessibleContext ac = getCurrentAccessibleContext();6516AccessibleStateSet states;6517int row = tree.getUI().getRowForPath(tree,path);6518int lsr = tree.getLeadSelectionRow();6519if (ac != null) {6520states = ac.getAccessibleStateSet();6521} else {6522states = new AccessibleStateSet();6523}6524// need to test here, 'cause the underlying component6525// is a cellRenderer, which is never showing...6526if (isShowing()) {6527states.add(AccessibleState.SHOWING);6528} else if (states.contains(AccessibleState.SHOWING)) {6529states.remove(AccessibleState.SHOWING);6530}6531if (isVisible()) {6532states.add(AccessibleState.VISIBLE);6533} else if (states.contains(AccessibleState.VISIBLE)) {6534states.remove(AccessibleState.VISIBLE);6535}6536if (tree.isPathSelected(path)){6537states.add(AccessibleState.SELECTED);6538}6539if (lsr == row) {6540states.add(AccessibleState.ACTIVE);6541}6542if (!isLeaf) {6543states.add(AccessibleState.EXPANDABLE);6544}6545if (tree.isExpanded(path)) {6546states.add(AccessibleState.EXPANDED);6547} else {6548states.add(AccessibleState.COLLAPSED);6549}6550if (tree.isEditable()) {6551states.add(AccessibleState.EDITABLE);6552}6553return states;6554}65556556/**6557* Get the Accessible parent of this object.6558*6559* @return the Accessible parent of this object; null if this6560* object does not have an Accessible parent6561*/6562public Accessible getAccessibleParent() {6563// someone wants to know, so we need to create our parent6564// if we don't have one (hey, we're a talented kid!)6565if (accessibleParent == null && path != null) {6566Object[] objPath = path.getPath();6567if (objPath.length > 1) {6568Object objParent = objPath[objPath.length-2];6569if (treeModel != null) {6570index = treeModel.getIndexOfChild(objParent, obj);6571}6572Object[] objParentPath = new Object[objPath.length-1];6573java.lang.System.arraycopy(objPath, 0, objParentPath,65740, objPath.length-1);6575TreePath parentPath = new TreePath(objParentPath);6576accessibleParent = new AccessibleJTreeNode(tree,6577parentPath,6578null);6579this.setAccessibleParent(accessibleParent);6580} else if (treeModel != null) {6581accessibleParent = tree; // we're the top!6582index = 0; // we're an only child!6583this.setAccessibleParent(accessibleParent);6584}6585}6586return accessibleParent;6587}65886589/**6590* Get the index of this object in its accessible parent.6591*6592* @return the index of this object in its parent; -1 if this6593* object does not have an accessible parent.6594* @see #getAccessibleParent6595*/6596public int getAccessibleIndexInParent() {6597// index is invalid 'till we have an accessibleParent...6598if (accessibleParent == null) {6599getAccessibleParent();6600}6601if (path != null) {6602Object[] objPath = path.getPath();6603if (objPath.length > 1) {6604Object objParent = objPath[objPath.length-2];6605if (treeModel != null) {6606index = treeModel.getIndexOfChild(objParent, obj);6607}6608}6609}6610return index;6611}66126613/**6614* Returns the number of accessible children in the object.6615*6616* @return the number of accessible children in the object.6617*/6618public int getAccessibleChildrenCount() {6619// Tree nodes can't be so complex that they have6620// two sets of children -> we're ignoring that case6621if (obj != null && treeModel != null) {6622return treeModel.getChildCount(obj);6623}6624return 0;6625}66266627/**6628* Return the specified Accessible child of the object.6629*6630* @param i zero-based index of child6631* @return the Accessible child of the object6632*/6633public Accessible getAccessibleChild(int i) {6634// Tree nodes can't be so complex that they have6635// two sets of children -> we're ignoring that case6636if (i < 0 || i >= getAccessibleChildrenCount() || path == null || treeModel == null) {6637return null;6638} else {6639Object childObj = treeModel.getChild(obj, i);6640Object[] objPath = path.getPath();6641Object[] objChildPath = new Object[objPath.length+1];6642java.lang.System.arraycopy(objPath, 0, objChildPath, 0, objPath.length);6643objChildPath[objChildPath.length-1] = childObj;6644TreePath childPath = new TreePath(objChildPath);6645return new AccessibleJTreeNode(tree, childPath, this);6646}6647}66486649/**6650* Gets the locale of the component. If the component does not have6651* a locale, then the locale of its parent is returned.6652*6653* @return This component's locale. If this component does not have6654* a locale, the locale of its parent is returned.6655* @exception IllegalComponentStateException6656* If the Component does not have its own locale and has not yet6657* been added to a containment hierarchy such that the locale can be6658* determined from the containing parent.6659* @see #setLocale6660*/6661public Locale getLocale() {6662if (tree == null)6663return null;6664AccessibleContext ac = getCurrentAccessibleContext();6665if (ac != null) {6666return ac.getLocale();6667} else {6668return tree.getLocale();6669}6670}66716672/**6673* Add a PropertyChangeListener to the listener list.6674* The listener is registered for all properties.6675*6676* @param l The PropertyChangeListener to be added6677*/6678public void addPropertyChangeListener(PropertyChangeListener l) {6679AccessibleContext ac = getCurrentAccessibleContext();6680if (ac != null) {6681ac.addPropertyChangeListener(l);6682} else {6683super.addPropertyChangeListener(l);6684}6685}66866687/**6688* Remove a PropertyChangeListener from the listener list.6689* This removes a PropertyChangeListener that was registered6690* for all properties.6691*6692* @param l The PropertyChangeListener to be removed6693*/6694public void removePropertyChangeListener(PropertyChangeListener l) {6695AccessibleContext ac = getCurrentAccessibleContext();6696if (ac != null) {6697ac.removePropertyChangeListener(l);6698} else {6699super.removePropertyChangeListener(l);6700}6701}67026703/**6704* Get the AccessibleAction associated with this object. In the6705* implementation of the Java Accessibility API for this class,6706* return this object, which is responsible for implementing the6707* AccessibleAction interface on behalf of itself.6708*6709* @return this object6710*/6711public AccessibleAction getAccessibleAction() {6712return this;6713}67146715/**6716* Get the AccessibleComponent associated with this object. In the6717* implementation of the Java Accessibility API for this class,6718* return this object, which is responsible for implementing the6719* AccessibleComponent interface on behalf of itself.6720*6721* @return this object6722*/6723public AccessibleComponent getAccessibleComponent() {6724return this; // to override getBounds()6725}67266727/**6728* Get the AccessibleSelection associated with this object if one6729* exists. Otherwise return null.6730*6731* @return the AccessibleSelection, or null6732*/6733public AccessibleSelection getAccessibleSelection() {6734AccessibleContext ac = getCurrentAccessibleContext();6735if (ac != null && isLeaf) {6736return getCurrentAccessibleContext().getAccessibleSelection();6737} else {6738return this;6739}6740}67416742/**6743* Get the AccessibleText associated with this object if one6744* exists. Otherwise return null.6745*6746* @return the AccessibleText, or null6747*/6748public AccessibleText getAccessibleText() {6749AccessibleContext ac = getCurrentAccessibleContext();6750if (ac != null) {6751return getCurrentAccessibleContext().getAccessibleText();6752} else {6753return null;6754}6755}67566757/**6758* Get the AccessibleValue associated with this object if one6759* exists. Otherwise return null.6760*6761* @return the AccessibleValue, or null6762*/6763public AccessibleValue getAccessibleValue() {6764AccessibleContext ac = getCurrentAccessibleContext();6765if (ac != null) {6766return getCurrentAccessibleContext().getAccessibleValue();6767} else {6768return null;6769}6770}677167726773// AccessibleComponent methods67746775/**6776* Get the background color of this object.6777*6778* @return the background color, if supported, of the object;6779* otherwise, null6780*/6781public Color getBackground() {6782AccessibleContext ac = getCurrentAccessibleContext();6783if (ac instanceof AccessibleComponent) {6784return ((AccessibleComponent) ac).getBackground();6785} else {6786Component c = getCurrentComponent();6787if (c != null) {6788return c.getBackground();6789} else {6790return null;6791}6792}6793}67946795/**6796* Set the background color of this object.6797*6798* @param c the new Color for the background6799*/6800public void setBackground(Color c) {6801AccessibleContext ac = getCurrentAccessibleContext();6802if (ac instanceof AccessibleComponent) {6803((AccessibleComponent) ac).setBackground(c);6804} else {6805Component cp = getCurrentComponent();6806if ( cp != null) {6807cp.setBackground(c);6808}6809}6810}681168126813/**6814* Get the foreground color of this object.6815*6816* @return the foreground color, if supported, of the object;6817* otherwise, null6818*/6819public Color getForeground() {6820AccessibleContext ac = getCurrentAccessibleContext();6821if (ac instanceof AccessibleComponent) {6822return ((AccessibleComponent) ac).getForeground();6823} else {6824Component c = getCurrentComponent();6825if (c != null) {6826return c.getForeground();6827} else {6828return null;6829}6830}6831}68326833public void setForeground(Color c) {6834AccessibleContext ac = getCurrentAccessibleContext();6835if (ac instanceof AccessibleComponent) {6836((AccessibleComponent) ac).setForeground(c);6837} else {6838Component cp = getCurrentComponent();6839if (cp != null) {6840cp.setForeground(c);6841}6842}6843}68446845public Cursor getCursor() {6846AccessibleContext ac = getCurrentAccessibleContext();6847if (ac instanceof AccessibleComponent) {6848return ((AccessibleComponent) ac).getCursor();6849} else {6850Component c = getCurrentComponent();6851if (c != null) {6852return c.getCursor();6853} else {6854Accessible ap = getAccessibleParent();6855if (ap instanceof AccessibleComponent) {6856return ((AccessibleComponent) ap).getCursor();6857} else {6858return null;6859}6860}6861}6862}68636864public void setCursor(Cursor c) {6865AccessibleContext ac = getCurrentAccessibleContext();6866if (ac instanceof AccessibleComponent) {6867((AccessibleComponent) ac).setCursor(c);6868} else {6869Component cp = getCurrentComponent();6870if (cp != null) {6871cp.setCursor(c);6872}6873}6874}68756876public Font getFont() {6877AccessibleContext ac = getCurrentAccessibleContext();6878if (ac instanceof AccessibleComponent) {6879return ((AccessibleComponent) ac).getFont();6880} else {6881Component c = getCurrentComponent();6882if (c != null) {6883return c.getFont();6884} else {6885return null;6886}6887}6888}68896890public void setFont(Font f) {6891AccessibleContext ac = getCurrentAccessibleContext();6892if (ac instanceof AccessibleComponent) {6893((AccessibleComponent) ac).setFont(f);6894} else {6895Component c = getCurrentComponent();6896if (c != null) {6897c.setFont(f);6898}6899}6900}69016902public FontMetrics getFontMetrics(Font f) {6903AccessibleContext ac = getCurrentAccessibleContext();6904if (ac instanceof AccessibleComponent) {6905return ((AccessibleComponent) ac).getFontMetrics(f);6906} else {6907Component c = getCurrentComponent();6908if (c != null) {6909return c.getFontMetrics(f);6910} else {6911return null;6912}6913}6914}69156916public boolean isEnabled() {6917AccessibleContext ac = getCurrentAccessibleContext();6918if (ac instanceof AccessibleComponent) {6919return ((AccessibleComponent) ac).isEnabled();6920} else {6921Component c = getCurrentComponent();6922if (c != null) {6923return c.isEnabled();6924} else {6925return false;6926}6927}6928}69296930public void setEnabled(boolean b) {6931AccessibleContext ac = getCurrentAccessibleContext();6932if (ac instanceof AccessibleComponent) {6933((AccessibleComponent) ac).setEnabled(b);6934} else {6935Component c = getCurrentComponent();6936if (c != null) {6937c.setEnabled(b);6938}6939}6940}69416942public boolean isVisible() {6943if (tree == null)6944return false;6945Rectangle pathBounds = tree.getPathBounds(path);6946Rectangle parentBounds = tree.getVisibleRect();6947if ( pathBounds != null && parentBounds != null &&6948parentBounds.intersects(pathBounds) ) {6949return true;6950} else {6951return false;6952}6953}69546955public void setVisible(boolean b) {6956}69576958public boolean isShowing() {6959return (tree.isShowing() && isVisible());6960}69616962public boolean contains(Point p) {6963AccessibleContext ac = getCurrentAccessibleContext();6964if (ac instanceof AccessibleComponent) {6965Rectangle r = ((AccessibleComponent) ac).getBounds();6966return r.contains(p);6967} else {6968Component c = getCurrentComponent();6969if (c != null) {6970Rectangle r = c.getBounds();6971return r.contains(p);6972} else {6973return getBounds().contains(p);6974}6975}6976}69776978public Point getLocationOnScreen() {6979if (tree != null) {6980Point treeLocation = tree.getLocationOnScreen();6981Rectangle pathBounds = tree.getPathBounds(path);6982if (treeLocation != null && pathBounds != null) {6983Point nodeLocation = new Point(pathBounds.x,6984pathBounds.y);6985nodeLocation.translate(treeLocation.x, treeLocation.y);6986return nodeLocation;6987} else {6988return null;6989}6990} else {6991return null;6992}6993}69946995private Point getLocationInJTree() {6996Rectangle r = tree.getPathBounds(path);6997if (r != null) {6998return r.getLocation();6999} else {7000return null;7001}7002}70037004public Point getLocation() {7005Rectangle r = getBounds();7006if (r != null) {7007return r.getLocation();7008} else {7009return null;7010}7011}70127013public void setLocation(Point p) {7014}70157016public Rectangle getBounds() {7017if (tree == null)7018return null;7019Rectangle r = tree.getPathBounds(path);7020Accessible parent = getAccessibleParent();7021if (parent instanceof AccessibleJTreeNode) {7022Point parentLoc = ((AccessibleJTreeNode) parent).getLocationInJTree();7023if (parentLoc != null && r != null) {7024r.translate(-parentLoc.x, -parentLoc.y);7025} else {7026return null; // not visible!7027}7028}7029return r;7030}70317032public void setBounds(Rectangle r) {7033AccessibleContext ac = getCurrentAccessibleContext();7034if (ac instanceof AccessibleComponent) {7035((AccessibleComponent) ac).setBounds(r);7036} else {7037Component c = getCurrentComponent();7038if (c != null) {7039c.setBounds(r);7040}7041}7042}70437044public Dimension getSize() {7045return getBounds().getSize();7046}70477048public void setSize (Dimension d) {7049AccessibleContext ac = getCurrentAccessibleContext();7050if (ac instanceof AccessibleComponent) {7051((AccessibleComponent) ac).setSize(d);7052} else {7053Component c = getCurrentComponent();7054if (c != null) {7055c.setSize(d);7056}7057}7058}70597060/**7061* Returns the <code>Accessible</code> child, if one exists,7062* contained at the local coordinate <code>Point</code>.7063* Otherwise returns <code>null</code>.7064*7065* @param p point in local coordinates of this7066* <code>Accessible</code>7067* @return the <code>Accessible</code>, if it exists,7068* at the specified location; else <code>null</code>7069*/7070public Accessible getAccessibleAt(Point p) {7071AccessibleContext ac = getCurrentAccessibleContext();7072if (ac instanceof AccessibleComponent) {7073return ((AccessibleComponent) ac).getAccessibleAt(p);7074} else {7075return null;7076}7077}70787079public boolean isFocusTraversable() {7080AccessibleContext ac = getCurrentAccessibleContext();7081if (ac instanceof AccessibleComponent) {7082return ((AccessibleComponent) ac).isFocusTraversable();7083} else {7084Component c = getCurrentComponent();7085if (c != null) {7086return c.isFocusable();7087} else {7088return false;7089}7090}7091}70927093public void requestFocus() {7094AccessibleContext ac = getCurrentAccessibleContext();7095if (ac instanceof AccessibleComponent) {7096((AccessibleComponent) ac).requestFocus();7097} else {7098Component c = getCurrentComponent();7099if (c != null) {7100c.requestFocus();7101}7102}7103}71047105public void addFocusListener(FocusListener l) {7106AccessibleContext ac = getCurrentAccessibleContext();7107if (ac instanceof AccessibleComponent) {7108((AccessibleComponent) ac).addFocusListener(l);7109} else {7110Component c = getCurrentComponent();7111if (c != null) {7112c.addFocusListener(l);7113}7114}7115}71167117public void removeFocusListener(FocusListener l) {7118AccessibleContext ac = getCurrentAccessibleContext();7119if (ac instanceof AccessibleComponent) {7120((AccessibleComponent) ac).removeFocusListener(l);7121} else {7122Component c = getCurrentComponent();7123if (c != null) {7124c.removeFocusListener(l);7125}7126}7127}71287129// AccessibleSelection methods71307131/**7132* Returns the number of items currently selected.7133* If no items are selected, the return value will be 0.7134*7135* @return the number of items currently selected.7136*/7137public int getAccessibleSelectionCount() {7138int count = 0;7139int childCount = getAccessibleChildrenCount();7140for (int i = 0; i < childCount; i++) {7141TreePath childPath = getChildTreePath(i);7142if (tree.isPathSelected(childPath)) {7143count++;7144}7145}7146return count;7147}71487149/**7150* Returns an Accessible representing the specified selected item7151* in the object. If there isn't a selection, or there are7152* fewer items selected than the integer passed in, the return7153* value will be null.7154*7155* @param i the zero-based index of selected items7156* @return an Accessible containing the selected item7157*/7158public Accessible getAccessibleSelection(int i) {7159int childCount = getAccessibleChildrenCount();7160if (i < 0 || i >= childCount) {7161return null; // out of range7162}7163int count = 0;7164for (int j = 0; j < childCount && i >= count; j++) {7165TreePath childPath = getChildTreePath(j);7166if (tree.isPathSelected(childPath)) {7167if (count == i) {7168return new AccessibleJTreeNode(tree, childPath, this);7169} else {7170count++;7171}7172}7173}7174return null;7175}71767177/**7178* Returns true if the current child of this object is selected.7179*7180* @param i the zero-based index of the child in this Accessible7181* object.7182* @see AccessibleContext#getAccessibleChild7183*/7184public boolean isAccessibleChildSelected(int i) {7185int childCount = getAccessibleChildrenCount();7186if (i < 0 || i >= childCount) {7187return false; // out of range7188} else {7189TreePath childPath = getChildTreePath(i);7190return tree.isPathSelected(childPath);7191}7192}71937194/**7195* Adds the specified selected item in the object to the object's7196* selection. If the object supports multiple selections,7197* the specified item is added to any existing selection, otherwise7198* it replaces any existing selection in the object. If the7199* specified item is already selected, this method has no effect.7200*7201* @param i the zero-based index of selectable items7202*/7203public void addAccessibleSelection(int i) {7204if (tree == null)7205return;7206TreeModel model = tree.getModel();7207if (model != null) {7208if (i >= 0 && i < getAccessibleChildrenCount()) {7209TreePath path = getChildTreePath(i);7210tree.addSelectionPath(path);7211}7212}7213}72147215/**7216* Removes the specified selected item in the object from the7217* object's7218* selection. If the specified item isn't currently selected, this7219* method has no effect.7220*7221* @param i the zero-based index of selectable items7222*/7223public void removeAccessibleSelection(int i) {7224if (tree == null)7225return;7226TreeModel model = tree.getModel();7227if (model != null) {7228if (i >= 0 && i < getAccessibleChildrenCount()) {7229TreePath path = getChildTreePath(i);7230tree.removeSelectionPath(path);7231}7232}7233}72347235/**7236* Clears the selection in the object, so that nothing in the7237* object is selected.7238*/7239public void clearAccessibleSelection() {7240int childCount = getAccessibleChildrenCount();7241for (int i = 0; i < childCount; i++) {7242removeAccessibleSelection(i);7243}7244}72457246/**7247* Causes every selected item in the object to be selected7248* if the object supports multiple selections.7249*/7250public void selectAllAccessibleSelection() {7251if (tree == null)7252return;7253TreeModel model = tree.getModel();7254if (model != null) {7255int childCount = getAccessibleChildrenCount();7256TreePath path;7257for (int i = 0; i < childCount; i++) {7258path = getChildTreePath(i);7259tree.addSelectionPath(path);7260}7261}7262}72637264// AccessibleAction methods72657266/**7267* Returns the number of accessible actions available in this7268* tree node. If this node is not a leaf, there is at least7269* one action (toggle expand), in addition to any available7270* on the object behind the TreeCellRenderer.7271*7272* @return the number of Actions in this object7273*/7274public int getAccessibleActionCount() {7275AccessibleContext ac = getCurrentAccessibleContext();7276if (ac != null) {7277AccessibleAction aa = ac.getAccessibleAction();7278if (aa != null) {7279return (aa.getAccessibleActionCount() + (isLeaf ? 0 : 1));7280}7281}7282return isLeaf ? 0 : 1;7283}72847285/**7286* Return a description of the specified action of the tree node.7287* If this node is not a leaf, there is at least one action7288* description (toggle expand), in addition to any available7289* on the object behind the TreeCellRenderer.7290*7291* @param i zero-based index of the actions7292* @return a description of the action7293*/7294public String getAccessibleActionDescription(int i) {7295if (i < 0 || i >= getAccessibleActionCount()) {7296return null;7297}7298AccessibleContext ac = getCurrentAccessibleContext();7299if (i == 0) {7300// TIGER - 47666367301// return AccessibleAction.TOGGLE_EXPAND;7302return "toggle expand";7303} else if (ac != null) {7304AccessibleAction aa = ac.getAccessibleAction();7305if (aa != null) {7306return aa.getAccessibleActionDescription(i - 1);7307}7308}7309return null;7310}73117312/**7313* Perform the specified Action on the tree node. If this node7314* is not a leaf, there is at least one action which can be7315* done (toggle expand), in addition to any available on the7316* object behind the TreeCellRenderer.7317*7318* @param i zero-based index of actions7319* @return true if the the action was performed; else false.7320*/7321public boolean doAccessibleAction(int i) {7322if (i < 0 || i >= getAccessibleActionCount()) {7323return false;7324}7325AccessibleContext ac = getCurrentAccessibleContext();7326if (i == 0) {7327if (tree.isExpanded(path)) {7328tree.collapsePath(path);7329} else {7330tree.expandPath(path);7331}7332return true;7333} else if (ac != null) {7334AccessibleAction aa = ac.getAccessibleAction();7335if (aa != null) {7336return aa.doAccessibleAction(i - 1);7337}7338}7339return false;7340}73417342} // inner class AccessibleJTreeNode73437344/**7345* A helper class to perform {@code Callable} objects on the event dispatch thread appropriate7346* for the provided {@code AccessibleContext}.7347*/7348private static class InvocationUtils {73497350/**7351* Invokes a {@code Callable} in the {@code AppContext} of the given {@code Accessible}7352* and waits for it to finish blocking the caller thread.7353*7354* @param callable the {@code Callable} to invoke7355* @param accessibleTable the {@code AccessibleExtendedTable} which would be used to find the right context7356* for the task execution7357* @param <T> type parameter for the result value7358*7359* @return the result of the {@code Callable} execution7360*/7361public static <T> T invokeAndWait(final Callable<T> callable,7362final AccessibleExtendedTable accessibleTable) {7363if (accessibleTable instanceof AccessibleContext) {7364return invokeAndWait(callable, (AccessibleContext)accessibleTable);7365}7366throw new RuntimeException("Unmapped AccessibleContext used to dispatch event: " + accessibleTable);7367}73687369/**7370* Invokes a {@code Callable} in the {@code AppContext} of the given {@code Accessible}7371* and waits for it to finish blocking the caller thread.7372*7373* @param callable the {@code Callable} to invoke7374* @param accessible the {@code Accessible} which would be used to find the right context7375* for the task execution7376* @param <T> type parameter for the result value7377*7378* @return the result of the {@code Callable} execution7379*/7380public static <T> T invokeAndWait(final Callable<T> callable,7381final Accessible accessible) {7382if (accessible instanceof Component) {7383return invokeAndWait(callable, (Component)accessible);7384}7385if (accessible instanceof AccessibleContext) {7386// This case also covers the Translator7387return invokeAndWait(callable, (AccessibleContext)accessible);7388}7389throw new RuntimeException("Unmapped Accessible used to dispatch event: " + accessible);7390}73917392/**7393* Invokes a {@code Callable} in the {@code AppContext} of the given {@code Component}7394* and waits for it to finish blocking the caller thread.7395*7396* @param callable the {@code Callable} to invoke7397* @param component the {@code Component} which would be used to find the right context7398* for the task execution7399* @param <T> type parameter for the result value7400*7401* @return the result of the {@code Callable} execution7402*/7403public static <T> T invokeAndWait(final Callable<T> callable,7404final Component component) {7405return invokeAndWait(callable, SunToolkit.targetToAppContext(component));7406}74077408/**7409* Invokes a {@code Callable} in the {@code AppContext} mapped to the given {@code AccessibleContext}7410* and waits for it to finish blocking the caller thread.7411*7412* @param callable the {@code Callable} to invoke7413* @param accessibleContext the {@code AccessibleContext} which would be used to determine the right7414* context for the task execution.7415* @param <T> type parameter for the result value7416*7417* @return the result of the {@code Callable} execution7418*/7419public static <T> T invokeAndWait(final Callable<T> callable,7420final AccessibleContext accessibleContext) {7421AppContext targetContext = AWTAccessor.getAccessibleContextAccessor()7422.getAppContext(accessibleContext);7423if (targetContext != null) {7424return invokeAndWait(callable, targetContext);7425} else {7426// Normally this should not happen, unmapped context provided and7427// the target AppContext is unknown.74287429// Try to recover in case the context is a translator.7430if (accessibleContext instanceof Translator) {7431Object source = ((Translator)accessibleContext).getSource();7432if (source instanceof Component) {7433return invokeAndWait(callable, (Component)source);7434}7435}7436}7437throw new RuntimeException("Unmapped AccessibleContext used to dispatch event: " + accessibleContext);7438}74397440private static <T> T invokeAndWait(final Callable<T> callable,7441final AppContext targetAppContext) {7442final CallableWrapper<T> wrapper = new CallableWrapper<T>(callable);7443try {7444invokeAndWait(wrapper, targetAppContext);7445T result = wrapper.getResult();7446updateAppContextMap(result, targetAppContext);7447return result;7448} catch (final Exception e) {7449throw new RuntimeException(e);7450}7451}74527453private static void invokeAndWait(final Runnable runnable,7454final AppContext appContext)7455throws InterruptedException, InvocationTargetException {74567457EventQueue eq = SunToolkit.getSystemEventQueueImplPP(appContext);7458Object lock = new Object();7459Toolkit source = Toolkit.getDefaultToolkit();7460InvocationEvent event =7461new InvocationEvent(source, runnable, lock, true);7462synchronized (lock) {7463eq.postEvent(event);7464lock.wait();7465}74667467Throwable eventThrowable = event.getThrowable();7468if (eventThrowable != null) {7469throw new InvocationTargetException(eventThrowable);7470}7471}74727473/**7474* Maps the {@code AccessibleContext} to the {@code AppContext} which should be used7475* to dispatch events related to the {@code AccessibleContext}7476* @param accessibleContext the {@code AccessibleContext} for the mapping7477* @param targetContext the {@code AppContext} for the mapping7478*/7479public static void registerAccessibleContext(final AccessibleContext accessibleContext,7480final AppContext targetContext) {7481if (accessibleContext != null) {7482AWTAccessor.getAccessibleContextAccessor().setAppContext(accessibleContext, targetContext);7483}7484}74857486private static <T> void updateAppContextMap(final T accessibleContext,7487final AppContext targetContext) {7488if (accessibleContext instanceof AccessibleContext) {7489registerAccessibleContext((AccessibleContext)accessibleContext, targetContext);7490}7491}74927493private static class CallableWrapper<T> implements Runnable {7494private final Callable<T> callable;7495private volatile T object;7496private Exception e;74977498CallableWrapper(final Callable<T> callable) {7499this.callable = callable;7500}75017502public void run() {7503try {7504if (callable != null) {7505object = callable.call();7506}7507} catch (final Exception e) {7508this.e = e;7509}7510}75117512T getResult() throws Exception {7513if (e != null)7514throw e;7515return object;7516}7517}7518}7519}752075217522