Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/classes/com/sun/java/accessibility/AccessBridge.java
32303 views
/*1* Copyright (c) 2005, 2018, 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}15511552/**1553* returns the AccessibleParent from an AccessibleContext1554*/1555private AccessibleContext getAccessibleParentFromContext(final AccessibleContext ac) {1556if (ac==null)1557return null;1558return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {1559@Override1560public AccessibleContext call() throws Exception {1561Accessible a = ac.getAccessibleParent();1562if (a != null) {1563AccessibleContext apc = a.getAccessibleContext();1564if (apc != null) {1565return apc;1566}1567}1568return null;1569}1570}, ac);1571}15721573/**1574* returns the AccessibleIndexInParent from an AccessibleContext1575*/1576private int getAccessibleIndexInParentFromContext(final AccessibleContext ac) {1577if (ac==null)1578return -1;1579return InvocationUtils.invokeAndWait(new Callable<Integer>() {1580@Override1581public Integer call() throws Exception {1582return ac.getAccessibleIndexInParent();1583}1584}, ac);1585}15861587/**1588* returns the AccessibleChild count from an AccessibleContext1589*/1590private int getAccessibleChildrenCountFromContext(final AccessibleContext ac) {1591if (ac==null)1592return -1;1593return InvocationUtils.invokeAndWait(new Callable<Integer>() {1594@Override1595public Integer call() throws Exception {1596return ac.getAccessibleChildrenCount();1597}1598}, ac);1599}16001601/**1602* returns the AccessibleChild Context from an AccessibleContext1603*/1604private AccessibleContext getAccessibleChildFromContext(final AccessibleContext ac, final int index) {16051606if (ac == null) {1607return null;1608}16091610final JTable table = InvocationUtils.invokeAndWait(new Callable<JTable>() {1611@Override1612public JTable call() throws Exception {1613// work-around for AccessibleJTable.getCurrentAccessibleContext returning1614// wrong renderer component when cell contains more than one component1615Accessible parent = ac.getAccessibleParent();1616if (parent != null) {1617int indexInParent = ac.getAccessibleIndexInParent();1618Accessible child =1619parent.getAccessibleContext().getAccessibleChild(indexInParent);1620if (child instanceof JTable) {1621return (JTable) child;1622}1623}1624return null;1625}1626}, ac);16271628if (table == null) {1629return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {1630@Override1631public AccessibleContext call() throws Exception {1632Accessible a = ac.getAccessibleChild(index);1633if (a != null) {1634return a.getAccessibleContext();1635}1636return null;1637}1638}, ac);1639}16401641final AccessibleTable at = getAccessibleTableFromContext(ac);16421643final int row = getAccessibleTableRow(at, index);1644final int column = getAccessibleTableColumn(at, index);16451646return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {1647@Override1648public AccessibleContext call() throws Exception {1649TableCellRenderer renderer = table.getCellRenderer(row, column);1650if (renderer == null) {1651Class<?> columnClass = table.getColumnClass(column);1652renderer = table.getDefaultRenderer(columnClass);1653}1654Component component =1655renderer.getTableCellRendererComponent(table, table.getValueAt(row, column),1656false, false, row, column);1657if (component instanceof Accessible) {1658return component.getAccessibleContext();1659}1660return null;1661}1662}, ac);1663}16641665/**1666* returns the AccessibleComponent bounds on screen from an AccessibleContext1667*/1668private Rectangle getAccessibleBoundsOnScreenFromContext(final AccessibleContext ac) {1669if(ac==null)1670return null;1671return InvocationUtils.invokeAndWait(new Callable<Rectangle>() {1672@Override1673public Rectangle call() throws Exception {1674AccessibleComponent acmp = ac.getAccessibleComponent();1675if (acmp != null) {1676Rectangle r = acmp.getBounds();1677if (r != null) {1678try {1679Point p = acmp.getLocationOnScreen();1680if (p != null) {1681r.x = p.x;1682r.y = p.y;1683return r;1684}1685} catch (Exception e) {1686return null;1687}1688}1689}1690return null;1691}1692}, ac);1693}16941695/**1696* returns the AccessibleComponent x-coord from an AccessibleContext1697*/1698private int getAccessibleXcoordFromContext(AccessibleContext ac) {1699if (ac != null) {1700Rectangle r = getAccessibleBoundsOnScreenFromContext(ac);1701if (r != null) {1702debugString("[INFO]: Returning Accessible x coord from Context: " + r.x);1703return r.x;1704}1705} else {1706debugString("[ERROR]: getAccessibleXcoordFromContext ac = null");1707}1708return -1;1709}17101711/**1712* returns the AccessibleComponent y-coord from an AccessibleContext1713*/1714private int getAccessibleYcoordFromContext(AccessibleContext ac) {1715debugString("[INFO]: getAccessibleYcoordFromContext() called");1716if (ac != null) {1717Rectangle r = getAccessibleBoundsOnScreenFromContext(ac);1718if (r != null) {1719return r.y;1720}1721} else {1722debugString("[ERROR]: getAccessibleYcoordFromContext; ac = null");1723}1724return -1;1725}17261727/**1728* returns the AccessibleComponent height from an AccessibleContext1729*/1730private int getAccessibleHeightFromContext(AccessibleContext ac) {1731if (ac != null) {1732Rectangle r = getAccessibleBoundsOnScreenFromContext(ac);1733if (r != null) {1734return r.height;1735}1736} else {1737debugString("[ERROR]: getAccessibleHeightFromContext; ac = null");1738}1739return -1;1740}17411742/**1743* returns the AccessibleComponent width from an AccessibleContext1744*/1745private int getAccessibleWidthFromContext(AccessibleContext ac) {1746if (ac != null) {1747Rectangle r = getAccessibleBoundsOnScreenFromContext(ac);1748if (r != null) {1749return r.width;1750}1751} else {1752debugString("[ERROR]: getAccessibleWidthFromContext; ac = null");1753}1754return -1;1755}175617571758/**1759* returns the AccessibleComponent from an AccessibleContext1760*/1761private AccessibleComponent getAccessibleComponentFromContext(AccessibleContext ac) {1762if (ac != null) {1763AccessibleComponent acmp = InvocationUtils.invokeAndWait(() -> {1764return ac.getAccessibleComponent();1765}, ac);1766if (acmp != null) {1767debugString("[INFO]: Returning AccessibleComponent Context");1768return acmp;1769}1770} else {1771debugString("[ERROR]: getAccessibleComponentFromContext; ac = null");1772}1773return null;1774}17751776/**1777* returns the AccessibleAction from an AccessibleContext1778*/1779private AccessibleAction getAccessibleActionFromContext(final AccessibleContext ac) {1780debugString("[INFO]: Returning AccessibleAction Context");1781return ac == null ? null : InvocationUtils.invokeAndWait(new Callable<AccessibleAction>() {1782@Override1783public AccessibleAction call() throws Exception {1784return ac.getAccessibleAction();1785}1786}, ac);1787}17881789/**1790* returns the AccessibleSelection from an AccessibleContext1791*/1792private AccessibleSelection getAccessibleSelectionFromContext(final AccessibleContext ac) {1793return ac == null ? null : InvocationUtils.invokeAndWait(new Callable<AccessibleSelection>() {1794@Override1795public AccessibleSelection call() throws Exception {1796return ac.getAccessibleSelection();1797}1798}, ac);1799}18001801/**1802* return the AccessibleText from an AccessibleContext1803*/1804private AccessibleText getAccessibleTextFromContext(final AccessibleContext ac) {1805return ac == null ? null : InvocationUtils.invokeAndWait(new Callable<AccessibleText>() {1806@Override1807public AccessibleText call() throws Exception {1808return ac.getAccessibleText();1809}1810}, ac);1811}18121813/**1814* return the AccessibleComponent from an AccessibleContext1815*/1816private AccessibleValue getAccessibleValueFromContext(final AccessibleContext ac) {1817return ac == null ? null : InvocationUtils.invokeAndWait(new Callable<AccessibleValue>() {1818@Override1819public AccessibleValue call() throws Exception {1820return ac.getAccessibleValue();1821}1822}, ac);1823}18241825/* ===== AccessibleText methods ===== */18261827/**1828* returns the bounding rectangle for the text cursor1829* XXX1830*/1831private Rectangle getCaretLocation(final AccessibleContext ac) {1832debugString("[INFO]: getCaretLocation");1833if (ac==null)1834return null;1835return InvocationUtils.invokeAndWait(new Callable<Rectangle>() {1836@Override1837public Rectangle call() throws Exception {1838// workaround for JAAPI not returning cursor bounding rectangle1839Rectangle r = null;1840Accessible parent = ac.getAccessibleParent();1841if (parent instanceof Accessible) {1842int indexInParent = ac.getAccessibleIndexInParent();1843Accessible child =1844parent.getAccessibleContext().getAccessibleChild(indexInParent);18451846if (child instanceof JTextComponent) {1847JTextComponent text = (JTextComponent) child;1848try {1849r = text.modelToView(text.getCaretPosition());1850if (r != null) {1851Point p = text.getLocationOnScreen();1852r.translate(p.x, p.y);1853}1854} catch (BadLocationException ble) {1855}1856}1857}1858return r;1859}1860}, ac);1861}18621863/**1864* returns the x-coordinate for the text cursor rectangle1865*/1866private int getCaretLocationX(AccessibleContext ac) {1867Rectangle r = getCaretLocation(ac);1868if (r != null) {1869return r.x;1870} else {1871return -1;1872}1873}18741875/**1876* returns the y-coordinate for the text cursor rectangle1877*/1878private int getCaretLocationY(AccessibleContext ac) {1879Rectangle r = getCaretLocation(ac);1880if (r != null) {1881return r.y;1882} else {1883return -1;1884}1885}18861887/**1888* returns the height for the text cursor rectangle1889*/1890private int getCaretLocationHeight(AccessibleContext ac) {1891Rectangle r = getCaretLocation(ac);1892if (r != null) {1893return r.height;1894} else {1895return -1;1896}1897}18981899/**1900* returns the width for the text cursor rectangle1901*/1902private int getCaretLocationWidth(AccessibleContext ac) {1903Rectangle r = getCaretLocation(ac);1904if (r != null) {1905return r.width;1906} else {1907return -1;1908}1909}19101911/**1912* returns the character count from an AccessibleContext1913*/1914private int getAccessibleCharCountFromContext(final AccessibleContext ac) {1915if (ac==null)1916return -1;1917return InvocationUtils.invokeAndWait(new Callable<Integer>() {1918@Override1919public Integer call() throws Exception {1920AccessibleText at = ac.getAccessibleText();1921if (at != null) {1922return at.getCharCount();1923}1924return -1;1925}1926}, ac);1927}19281929/**1930* returns the caret position from an AccessibleContext1931*/1932private int getAccessibleCaretPositionFromContext(final AccessibleContext ac) {1933if (ac==null)1934return -1;1935return InvocationUtils.invokeAndWait(new Callable<Integer>() {1936@Override1937public Integer call() throws Exception {1938AccessibleText at = ac.getAccessibleText();1939if (at != null) {1940return at.getCaretPosition();1941}1942return -1;1943}1944}, ac);1945}19461947/**1948* Return the index at a specific point from an AccessibleContext1949* Point(x, y) is in screen coordinates.1950*/1951private int getAccessibleIndexAtPointFromContext(final AccessibleContext ac,1952final int x, final int y) {1953debugString("[INFO]: getAccessibleIndexAtPointFromContext: x = "+x+"; y = "+y);1954if (ac==null)1955return -1;1956return InvocationUtils.invokeAndWait(new Callable<Integer>() {1957@Override1958public Integer call() throws Exception {1959AccessibleText at = ac.getAccessibleText();1960AccessibleComponent acomp = ac.getAccessibleComponent();1961if (at != null && acomp != null) {1962// Convert x and y from screen coordinates to1963// local coordinates.1964try {1965Point p = acomp.getLocationOnScreen();1966int x1, y1;1967if (p != null) {1968x1 = x - p.x;1969if (x1 < 0) {1970x1 = 0;1971}1972y1 = y - p.y;1973if (y1 < 0) {1974y1 = 0;1975}19761977Point newPoint = new Point(x1, y1);1978int indexAtPoint = at.getIndexAtPoint(new Point(x1, y1));1979return indexAtPoint;1980}1981} catch (Exception e) {1982}1983}1984return -1;1985}1986}, ac);1987}19881989/**1990* return the letter at a specific point from an AccessibleContext1991*/1992private String getAccessibleLetterAtIndexFromContext(final AccessibleContext ac, final int index) {1993if (ac != null) {1994String s = InvocationUtils.invokeAndWait(new Callable<String>() {1995@Override1996public String call() throws Exception {1997AccessibleText at = ac.getAccessibleText();1998if (at == null) return null;1999return at.getAtIndex(AccessibleText.CHARACTER, index);2000}2001}, ac);2002if (s != null) {2003references.increment(s);2004return s;2005}2006} else {2007debugString("[ERROR]: getAccessibleLetterAtIndexFromContext; ac = null");2008}2009return null;2010}20112012/**2013* return the word at a specific point from an AccessibleContext2014*/2015private String getAccessibleWordAtIndexFromContext(final AccessibleContext ac, final int index) {2016if (ac != null) {2017String s = InvocationUtils.invokeAndWait(new Callable<String>() {2018@Override2019public String call() throws Exception {2020AccessibleText at = ac.getAccessibleText();2021if (at == null) return null;2022return at.getAtIndex(AccessibleText.WORD, index);2023}2024}, ac);2025if (s != null) {2026references.increment(s);2027return s;2028}2029} else {2030debugString("[ERROR]: getAccessibleWordAtIndexFromContext; ac = null");2031}2032return null;2033}20342035/**2036* return the sentence at a specific point from an AccessibleContext2037*/2038private String getAccessibleSentenceAtIndexFromContext(final AccessibleContext ac, final int index) {2039if (ac != null) {2040String s = InvocationUtils.invokeAndWait(new Callable<String>() {2041@Override2042public String call() throws Exception {2043AccessibleText at = ac.getAccessibleText();2044if (at == null) return null;2045return at.getAtIndex(AccessibleText.SENTENCE, index);2046}2047}, ac);2048if (s != null) {2049references.increment(s);2050return s;2051}2052} else {2053debugString("[ERROR]: getAccessibleSentenceAtIndexFromContext; ac = null");2054}2055return null;2056}20572058/**2059* return the text selection start from an AccessibleContext2060*/2061private int getAccessibleTextSelectionStartFromContext(final AccessibleContext ac) {2062if (ac == null) return -1;2063return InvocationUtils.invokeAndWait(new Callable<Integer>() {2064@Override2065public Integer call() throws Exception {2066AccessibleText at = ac.getAccessibleText();2067if (at != null) {2068return at.getSelectionStart();2069}2070return -1;2071}2072}, ac);2073}20742075/**2076* return the text selection end from an AccessibleContext2077*/2078private int getAccessibleTextSelectionEndFromContext(final AccessibleContext ac) {2079if (ac == null)2080return -1;2081return InvocationUtils.invokeAndWait(new Callable<Integer>() {2082@Override2083public Integer call() throws Exception {2084AccessibleText at = ac.getAccessibleText();2085if (at != null) {2086return at.getSelectionEnd();2087}2088return -1;2089}2090}, ac);2091}20922093/**2094* return the selected text from an AccessibleContext2095*/2096private String getAccessibleTextSelectedTextFromContext(final AccessibleContext ac) {2097if (ac != null) {2098String s = InvocationUtils.invokeAndWait(new Callable<String>() {2099@Override2100public String call() throws Exception {2101AccessibleText at = ac.getAccessibleText();2102if (at == null) return null;2103return at.getSelectedText();2104}2105}, ac);2106if (s != null) {2107references.increment(s);2108return s;2109}2110} else {2111debugString("[ERROR]: getAccessibleTextSelectedTextFromContext; ac = null");2112}2113return null;2114}21152116/**2117* return the attribute string at a given index from an AccessibleContext2118*/2119private String getAccessibleAttributesAtIndexFromContext(final AccessibleContext ac,2120final int index) {2121if (ac == null)2122return null;2123AttributeSet as = InvocationUtils.invokeAndWait(new Callable<AttributeSet>() {2124@Override2125public AttributeSet call() throws Exception {2126AccessibleText at = ac.getAccessibleText();2127if (at != null) {2128return at.getCharacterAttribute(index);2129}2130return null;2131}2132}, ac);2133String s = expandStyleConstants(as);2134if (s != null) {2135references.increment(s);2136return s;2137}2138return null;2139}21402141/**2142* Get line info: left index of line2143*2144* algorithm: cast back, doubling each time,2145* 'till find line boundaries2146*2147* return -1 if we can't get the info (e.g. index or at passed in2148* is bogus; etc.)2149*/2150private int getAccessibleTextLineLeftBoundsFromContext(final AccessibleContext ac,2151final int index) {2152if (ac == null)2153return -1;2154return InvocationUtils.invokeAndWait(new Callable<Integer>() {2155@Override2156public Integer call() throws Exception {2157AccessibleText at = ac.getAccessibleText();2158if (at != null) {2159int lineStart;2160int offset;2161Rectangle charRect;2162Rectangle indexRect = at.getCharacterBounds(index);2163int textLen = at.getCharCount();2164if (indexRect == null) {2165return -1;2166}2167// find the start of the line2168//2169offset = 1;2170lineStart = index - offset < 0 ? 0 : index - offset;2171charRect = at.getCharacterBounds(lineStart);2172// slouch behind beginning of line2173while (charRect != null2174&& charRect.y >= indexRect.y2175&& lineStart > 0) {2176offset = offset << 1;2177lineStart = index - offset < 0 ? 0 : index - offset;2178charRect = at.getCharacterBounds(lineStart);2179}2180if (lineStart == 0) { // special case: we're on the first line!2181// we found it!2182} else {2183offset = offset >> 1; // know boundary within last expansion2184// ground forward to beginning of line2185while (offset > 0) {2186charRect = at.getCharacterBounds(lineStart + offset);2187if (charRect.y < indexRect.y) { // still before line2188lineStart += offset;2189} else {2190// leave lineStart alone, it's close!2191}2192offset = offset >> 1;2193}2194// subtract one 'cause we're already too far...2195lineStart += 1;2196}2197return lineStart;2198}2199return -1;2200}2201}, ac);2202}22032204/**2205* Get line info: right index of line2206*2207* algorithm: cast back, doubling each time,2208* 'till find line boundaries2209*2210* return -1 if we can't get the info (e.g. index or at passed in2211* is bogus; etc.)2212*/2213private int getAccessibleTextLineRightBoundsFromContext(final AccessibleContext ac, final int index) {2214if(ac == null)2215return -1;2216return InvocationUtils.invokeAndWait(new Callable<Integer>() {2217@Override2218public Integer call() throws Exception {2219AccessibleText at = ac.getAccessibleText();2220if (at != null) {2221int lineEnd;2222int offset;2223Rectangle charRect;2224Rectangle indexRect = at.getCharacterBounds(index);2225int textLen = at.getCharCount();2226if (indexRect == null) {2227return -1;2228}2229// find the end of the line2230//2231offset = 1;2232lineEnd = index + offset > textLen - 12233? textLen - 1 : index + offset;2234charRect = at.getCharacterBounds(lineEnd);2235// push past end of line2236while (charRect != null &&2237charRect.y <= indexRect.y &&2238lineEnd < textLen - 1) {2239offset = offset << 1;2240lineEnd = index + offset > textLen - 12241? textLen - 1 : index + offset;2242charRect = at.getCharacterBounds(lineEnd);2243}2244if (lineEnd == textLen - 1) { // special case: on the last line!2245// we found it!2246} else {2247offset = offset >> 1; // know boundary within last expansion2248// pull back to end of line2249while (offset > 0) {2250charRect = at.getCharacterBounds(lineEnd - offset);2251if (charRect.y > indexRect.y) { // still beyond line2252lineEnd -= offset;2253} else {2254// leave lineEnd alone, it's close!2255}2256offset = offset >> 1;2257}2258// subtract one 'cause we're already too far...2259lineEnd -= 1;2260}2261return lineEnd;2262}2263return -1;2264}2265}, ac);2266}22672268/**2269* Get a range of text; null if indicies are bogus2270*/2271private String getAccessibleTextRangeFromContext(final AccessibleContext ac,2272final int start, final int end) {2273String s = InvocationUtils.invokeAndWait(new Callable<String>() {2274@Override2275public String call() throws Exception {2276if (ac != null) {2277AccessibleText at = ac.getAccessibleText();2278if (at != null) {2279// start - end is inclusive2280if (start > end) {2281return null;2282}2283if (end >= at.getCharCount()) {2284return null;2285}2286StringBuffer buf = new StringBuffer(end - start + 1);2287for (int i = start; i <= end; i++) {2288buf.append(at.getAtIndex(AccessibleText.CHARACTER, i));2289}2290return buf.toString();2291}2292}2293return null;2294}2295}, ac);2296if (s != null) {2297references.increment(s);2298return s;2299} else {2300return null;2301}2302}23032304/**2305* return the AttributeSet object at a given index from an AccessibleContext2306*/2307private AttributeSet getAccessibleAttributeSetAtIndexFromContext(final AccessibleContext ac,2308final int index) {2309return InvocationUtils.invokeAndWait(new Callable<AttributeSet>() {2310@Override2311public AttributeSet call() throws Exception {2312if (ac != null) {2313AccessibleText at = ac.getAccessibleText();2314if (at != null) {2315AttributeSet as = at.getCharacterAttribute(index);2316if (as != null) {2317AccessBridge.this.references.increment(as);2318return as;2319}2320}2321}2322return null;2323}2324}, ac);2325}232623272328/**2329* return the bounding rectangle at index from an AccessibleContext2330*/2331private Rectangle getAccessibleTextRectAtIndexFromContext(final AccessibleContext ac,2332final int index) {2333// want to do this in global coords, so need to combine w/ac global coords2334Rectangle r = InvocationUtils.invokeAndWait(new Callable<Rectangle>() {2335@Override2336public Rectangle call() throws Exception {2337// want to do this in global coords, so need to combine w/ac global coords2338if (ac != null) {2339AccessibleText at = ac.getAccessibleText();2340if (at != null) {2341Rectangle rect = at.getCharacterBounds(index);2342if (rect != null) {2343String s = at.getAtIndex(AccessibleText.CHARACTER, index);2344if (s != null && s.equals("\n")) {2345rect.width = 0;2346}2347return rect;2348}2349}2350}2351return null;2352}2353}, ac);2354Rectangle acRect = getAccessibleBoundsOnScreenFromContext(ac);2355if (r != null && acRect != null) {2356r.translate(acRect.x, acRect.y);2357return r;2358}2359return null;2360}23612362/**2363* return the AccessibleText character x-coord at index from an AccessibleContext2364*/2365private int getAccessibleXcoordTextRectAtIndexFromContext(AccessibleContext ac, int index) {2366if (ac != null) {2367Rectangle r = getAccessibleTextRectAtIndexFromContext(ac, index);2368if (r != null) {2369return r.x;2370}2371} else {2372debugString("[ERROR]: getAccessibleXcoordTextRectAtIndexFromContext; ac = null");2373}2374return -1;2375}23762377/**2378* return the AccessibleText character y-coord at index from an AccessibleContext2379*/2380private int getAccessibleYcoordTextRectAtIndexFromContext(AccessibleContext ac, int index) {2381if (ac != null) {2382Rectangle r = getAccessibleTextRectAtIndexFromContext(ac, index);2383if (r != null) {2384return r.y;2385}2386} else {2387debugString("[ERROR]: getAccessibleYcoordTextRectAtIndexFromContext; ac = null");2388}2389return -1;2390}23912392/**2393* return the AccessibleText character height at index from an AccessibleContext2394*/2395private int getAccessibleHeightTextRectAtIndexFromContext(AccessibleContext ac, int index) {2396if (ac != null) {2397Rectangle r = getAccessibleTextRectAtIndexFromContext(ac, index);2398if (r != null) {2399return r.height;2400}2401} else {2402debugString("[ERROR]: getAccessibleHeightTextRectAtIndexFromContext; ac = null");2403}2404return -1;2405}24062407/**2408* return the AccessibleText character width at index from an AccessibleContext2409*/2410private int getAccessibleWidthTextRectAtIndexFromContext(AccessibleContext ac, int index) {2411if (ac != null) {2412Rectangle r = getAccessibleTextRectAtIndexFromContext(ac, index);2413if (r != null) {2414return r.width;2415}2416} else {2417debugString("[ERROR]: getAccessibleWidthTextRectAtIndexFromContext; ac = null");2418}2419return -1;2420}24212422/* ===== AttributeSet methods for AccessibleText ===== */24232424/**2425* return the bold setting from an AttributeSet2426*/2427private boolean getBoldFromAttributeSet(AttributeSet as) {2428if (as != null) {2429return StyleConstants.isBold(as);2430} else {2431debugString("[ERROR]: getBoldFromAttributeSet; as = null");2432}2433return false;2434}24352436/**2437* return the italic setting from an AttributeSet2438*/2439private boolean getItalicFromAttributeSet(AttributeSet as) {2440if (as != null) {2441return StyleConstants.isItalic(as);2442} else {2443debugString("[ERROR]: getItalicFromAttributeSet; as = null");2444}2445return false;2446}24472448/**2449* return the underline setting from an AttributeSet2450*/2451private boolean getUnderlineFromAttributeSet(AttributeSet as) {2452if (as != null) {2453return StyleConstants.isUnderline(as);2454} else {2455debugString("[ERROR]: getUnderlineFromAttributeSet; as = null");2456}2457return false;2458}24592460/**2461* return the strikethrough setting from an AttributeSet2462*/2463private boolean getStrikethroughFromAttributeSet(AttributeSet as) {2464if (as != null) {2465return StyleConstants.isStrikeThrough(as);2466} else {2467debugString("[ERROR]: getStrikethroughFromAttributeSet; as = null");2468}2469return false;2470}24712472/**2473* return the superscript setting from an AttributeSet2474*/2475private boolean getSuperscriptFromAttributeSet(AttributeSet as) {2476if (as != null) {2477return StyleConstants.isSuperscript(as);2478} else {2479debugString("[ERROR]: getSuperscriptFromAttributeSet; as = null");2480}2481return false;2482}24832484/**2485* return the subscript setting from an AttributeSet2486*/2487private boolean getSubscriptFromAttributeSet(AttributeSet as) {2488if (as != null) {2489return StyleConstants.isSubscript(as);2490} else {2491debugString("[ERROR]: getSubscriptFromAttributeSet; as = null");2492}2493return false;2494}24952496/**2497* return the background color from an AttributeSet2498*/2499private String getBackgroundColorFromAttributeSet(AttributeSet as) {2500if (as != null) {2501String s = StyleConstants.getBackground(as).toString();2502if (s != null) {2503references.increment(s);2504return s;2505}2506} else {2507debugString("[ERROR]: getBackgroundColorFromAttributeSet; as = null");2508}2509return null;2510}25112512/**2513* return the foreground color from an AttributeSet2514*/2515private String getForegroundColorFromAttributeSet(AttributeSet as) {2516if (as != null) {2517String s = StyleConstants.getForeground(as).toString();2518if (s != null) {2519references.increment(s);2520return s;2521}2522} else {2523debugString("[ERROR]: getForegroundColorFromAttributeSet; as = null");2524}2525return null;2526}25272528/**2529* return the font family from an AttributeSet2530*/2531private String getFontFamilyFromAttributeSet(AttributeSet as) {2532if (as != null) {2533String s = StyleConstants.getFontFamily(as).toString();2534if (s != null) {2535references.increment(s);2536return s;2537}2538} else {2539debugString("[ERROR]: getFontFamilyFromAttributeSet; as = null");2540}2541return null;2542}25432544/**2545* return the font size from an AttributeSet2546*/2547private int getFontSizeFromAttributeSet(AttributeSet as) {2548if (as != null) {2549return StyleConstants.getFontSize(as);2550} else {2551debugString("[ERROR]: getFontSizeFromAttributeSet; as = null");2552}2553return -1;2554}25552556/**2557* return the alignment from an AttributeSet2558*/2559private int getAlignmentFromAttributeSet(AttributeSet as) {2560if (as != null) {2561return StyleConstants.getAlignment(as);2562} else {2563debugString("[ERROR]: getAlignmentFromAttributeSet; as = null");2564}2565return -1;2566}25672568/**2569* return the BiDi level from an AttributeSet2570*/2571private int getBidiLevelFromAttributeSet(AttributeSet as) {2572if (as != null) {2573return StyleConstants.getBidiLevel(as);2574} else {2575debugString("[ERROR]: getBidiLevelFromAttributeSet; as = null");2576}2577return -1;2578}257925802581/**2582* return the first line indent from an AttributeSet2583*/2584private float getFirstLineIndentFromAttributeSet(AttributeSet as) {2585if (as != null) {2586return StyleConstants.getFirstLineIndent(as);2587} else {2588debugString("[ERROR]: getFirstLineIndentFromAttributeSet; as = null");2589}2590return -1;2591}25922593/**2594* return the left indent from an AttributeSet2595*/2596private float getLeftIndentFromAttributeSet(AttributeSet as) {2597if (as != null) {2598return StyleConstants.getLeftIndent(as);2599} else {2600debugString("[ERROR]: getLeftIndentFromAttributeSet; as = null");2601}2602return -1;2603}26042605/**2606* return the right indent from an AttributeSet2607*/2608private float getRightIndentFromAttributeSet(AttributeSet as) {2609if (as != null) {2610return StyleConstants.getRightIndent(as);2611} else {2612debugString("[ERROR]: getRightIndentFromAttributeSet; as = null");2613}2614return -1;2615}26162617/**2618* return the line spacing from an AttributeSet2619*/2620private float getLineSpacingFromAttributeSet(AttributeSet as) {2621if (as != null) {2622return StyleConstants.getLineSpacing(as);2623} else {2624debugString("[ERROR]: getLineSpacingFromAttributeSet; as = null");2625}2626return -1;2627}26282629/**2630* return the space above from an AttributeSet2631*/2632private float getSpaceAboveFromAttributeSet(AttributeSet as) {2633if (as != null) {2634return StyleConstants.getSpaceAbove(as);2635} else {2636debugString("[ERROR]: getSpaceAboveFromAttributeSet; as = null");2637}2638return -1;2639}26402641/**2642* return the space below from an AttributeSet2643*/2644private float getSpaceBelowFromAttributeSet(AttributeSet as) {2645if (as != null) {2646return StyleConstants.getSpaceBelow(as);2647} else {2648debugString("[ERROR]: getSpaceBelowFromAttributeSet; as = null");2649}2650return -1;2651}26522653/**2654* Enumerate all StyleConstants in the AttributeSet2655*2656* We need to check explicitly, 'cause of the HTML package conversion2657* mechanism (they may not be stored as StyleConstants, just translated2658* to them when asked).2659*2660* (Use convenience methods where they are defined...)2661*2662* Not checking the following (which the IBM SNS guidelines says2663* should be defined):2664* - ComponentElementName2665* - IconElementName2666* - NameAttribute2667* - ResolveAttribute2668*/2669private String expandStyleConstants(AttributeSet as) {2670Color c;2671Object o;2672String attrString = "";26732674// ---------- check for various Character Constants26752676attrString += "BidiLevel = " + StyleConstants.getBidiLevel(as);26772678final Component comp = StyleConstants.getComponent(as);2679if (comp != null) {2680if (comp instanceof Accessible) {2681final AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {2682@Override2683public AccessibleContext call() throws Exception {2684return comp.getAccessibleContext();2685}2686}, comp);2687if (ac != null) {2688attrString += "; Accessible Component = " + InvocationUtils.invokeAndWait(new Callable<String>() {2689@Override2690public String call() throws Exception {2691return ac.getAccessibleName();2692}2693}, ac);2694} else {2695attrString += "; Innaccessible Component = " + comp;2696}2697} else {2698attrString += "; Innaccessible Component = " + comp;2699}2700}27012702Icon i = StyleConstants.getIcon(as);2703if (i != null) {2704if (i instanceof ImageIcon) {2705attrString += "; ImageIcon = " + ((ImageIcon) i).getDescription();2706} else {2707attrString += "; Icon = " + i;2708}2709}27102711attrString += "; FontFamily = " + StyleConstants.getFontFamily(as);27122713attrString += "; FontSize = " + StyleConstants.getFontSize(as);27142715if (StyleConstants.isBold(as)) {2716attrString += "; bold";2717}27182719if (StyleConstants.isItalic(as)) {2720attrString += "; italic";2721}27222723if (StyleConstants.isUnderline(as)) {2724attrString += "; underline";2725}27262727if (StyleConstants.isStrikeThrough(as)) {2728attrString += "; strikethrough";2729}27302731if (StyleConstants.isSuperscript(as)) {2732attrString += "; superscript";2733}27342735if (StyleConstants.isSubscript(as)) {2736attrString += "; subscript";2737}27382739c = StyleConstants.getForeground(as);2740if (c != null) {2741attrString += "; Foreground = " + c;2742}27432744c = StyleConstants.getBackground(as);2745if (c != null) {2746attrString += "; Background = " + c;2747}27482749attrString += "; FirstLineIndent = " + StyleConstants.getFirstLineIndent(as);27502751attrString += "; RightIndent = " + StyleConstants.getRightIndent(as);27522753attrString += "; LeftIndent = " + StyleConstants.getLeftIndent(as);27542755attrString += "; LineSpacing = " + StyleConstants.getLineSpacing(as);27562757attrString += "; SpaceAbove = " + StyleConstants.getSpaceAbove(as);27582759attrString += "; SpaceBelow = " + StyleConstants.getSpaceBelow(as);27602761attrString += "; Alignment = " + StyleConstants.getAlignment(as);27622763TabSet ts = StyleConstants.getTabSet(as);2764if (ts != null) {2765attrString += "; TabSet = " + ts;2766}27672768return attrString;2769}277027712772/* ===== AccessibleValue methods ===== */27732774/**2775* return the AccessibleValue current value from an AccessibleContext2776* returned using a String 'cause the value is a java Number2777*2778*/2779private String getCurrentAccessibleValueFromContext(final AccessibleContext ac) {2780if (ac != null) {2781final Number value = InvocationUtils.invokeAndWait(new Callable<Number>() {2782@Override2783public Number call() throws Exception {2784AccessibleValue av = ac.getAccessibleValue();2785if (av == null) return null;2786return av.getCurrentAccessibleValue();2787}2788}, ac);2789if (value != null) {2790String s = value.toString();2791if (s != null) {2792references.increment(s);2793return s;2794}2795}2796} else {2797debugString("[ERROR]: getCurrentAccessibleValueFromContext; ac = null");2798}2799return null;2800}28012802/**2803* return the AccessibleValue maximum value from an AccessibleContext2804* returned using a String 'cause the value is a java Number2805*2806*/2807private String getMaximumAccessibleValueFromContext(final AccessibleContext ac) {2808if (ac != null) {2809final Number value = InvocationUtils.invokeAndWait(new Callable<Number>() {2810@Override2811public Number call() throws Exception {2812AccessibleValue av = ac.getAccessibleValue();2813if (av == null) return null;2814return av.getMaximumAccessibleValue();2815}2816}, ac);2817if (value != null) {2818String s = value.toString();2819if (s != null) {2820references.increment(s);2821return s;2822}2823}2824} else {2825debugString("[ERROR]: getMaximumAccessibleValueFromContext; ac = null");2826}2827return null;2828}28292830/**2831* return the AccessibleValue minimum value from an AccessibleContext2832* returned using a String 'cause the value is a java Number2833*2834*/2835private String getMinimumAccessibleValueFromContext(final AccessibleContext ac) {2836if (ac != null) {2837final Number value = InvocationUtils.invokeAndWait(new Callable<Number>() {2838@Override2839public Number call() throws Exception {2840AccessibleValue av = ac.getAccessibleValue();2841if (av == null) return null;2842return av.getMinimumAccessibleValue();2843}2844}, ac);2845if (value != null) {2846String s = value.toString();2847if (s != null) {2848references.increment(s);2849return s;2850}2851}2852} else {2853debugString("[ERROR]: getMinimumAccessibleValueFromContext; ac = null");2854}2855return null;2856}285728582859/* ===== AccessibleSelection methods ===== */28602861/**2862* add to the AccessibleSelection of an AccessibleContext child i2863*2864*/2865private void addAccessibleSelectionFromContext(final AccessibleContext ac, final int i) {2866try {2867InvocationUtils.invokeAndWait(new Callable<Object>() {2868@Override2869public Object call() throws Exception {2870if (ac != null) {2871AccessibleSelection as = ac.getAccessibleSelection();2872if (as != null) {2873as.addAccessibleSelection(i);2874}2875}2876return null;2877}2878}, ac);2879} catch(Exception e){}2880}28812882/**2883* clear all of the AccessibleSelection of an AccessibleContex2884*2885*/2886private void clearAccessibleSelectionFromContext(final AccessibleContext ac) {2887try {2888InvocationUtils.invokeAndWait(new Callable<Object>() {2889@Override2890public Object call() throws Exception {2891AccessibleSelection as = ac.getAccessibleSelection();2892if (as != null) {2893as.clearAccessibleSelection();2894}2895return null;2896}2897}, ac);2898} catch(Exception e){}28992900}29012902/**2903* get the AccessibleContext of the i-th AccessibleSelection of an AccessibleContext2904*2905*/2906private AccessibleContext getAccessibleSelectionFromContext(final AccessibleContext ac, final int i) {2907return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {2908@Override2909public AccessibleContext call() throws Exception {2910if (ac != null) {2911AccessibleSelection as = ac.getAccessibleSelection();2912if (as != null) {2913Accessible a = as.getAccessibleSelection(i);2914if (a == null)2915return null;2916else2917return a.getAccessibleContext();2918}2919}2920return null;2921}2922}, ac);2923}29242925/**2926* get number of things selected in the AccessibleSelection of an AccessibleContext2927*2928*/2929private int getAccessibleSelectionCountFromContext(final AccessibleContext ac) {2930return InvocationUtils.invokeAndWait(new Callable<Integer>() {2931@Override2932public Integer call() throws Exception {2933if (ac != null) {2934AccessibleSelection as = ac.getAccessibleSelection();2935if (as != null) {2936return as.getAccessibleSelectionCount();2937}2938}2939return -1;2940}2941}, ac);2942}29432944/**2945* return true if the i-th child of the AccessibleSelection of an AccessibleContext is selected2946*2947*/2948private boolean isAccessibleChildSelectedFromContext(final AccessibleContext ac, final int i) {2949return InvocationUtils.invokeAndWait(new Callable<Boolean>() {2950@Override2951public Boolean call() throws Exception {2952if (ac != null) {2953AccessibleSelection as = ac.getAccessibleSelection();2954if (as != null) {2955return as.isAccessibleChildSelected(i);2956}2957}2958return false;2959}2960}, ac);2961}29622963/**2964* remove the i-th child from the AccessibleSelection of an AccessibleContext2965*2966*/2967private void removeAccessibleSelectionFromContext(final AccessibleContext ac, final int i) {2968InvocationUtils.invokeAndWait(new Callable<Object>() {2969@Override2970public Object call() throws Exception {2971if (ac != null) {2972AccessibleSelection as = ac.getAccessibleSelection();2973if (as != null) {2974as.removeAccessibleSelection(i);2975}2976}2977return null;2978}2979}, ac);2980}29812982/**2983* select all (if possible) of the children of the AccessibleSelection of an AccessibleContext2984*2985*/2986private void selectAllAccessibleSelectionFromContext(final AccessibleContext ac) {2987InvocationUtils.invokeAndWait(new Callable<Object>() {2988@Override2989public Object call() throws Exception {2990if (ac != null) {2991AccessibleSelection as = ac.getAccessibleSelection();2992if (as != null) {2993as.selectAllAccessibleSelection();2994}2995}2996return null;2997}2998}, ac);2999}30003001// ======== AccessibleTable ========30023003ConcurrentHashMap<AccessibleTable,AccessibleContext> hashtab = new ConcurrentHashMap<>();30043005/**3006* returns the AccessibleTable for an AccessibleContext3007*/3008private AccessibleTable getAccessibleTableFromContext(final AccessibleContext ac) {3009String version = getJavaVersionProperty();3010if ((version != null && version.compareTo("1.3") >= 0)) {3011return InvocationUtils.invokeAndWait(new Callable<AccessibleTable>() {3012@Override3013public AccessibleTable call() throws Exception {3014if (ac != null) {3015AccessibleTable at = ac.getAccessibleTable();3016if (at != null) {3017AccessBridge.this.hashtab.put(at, ac);3018return at;3019}3020}3021return null;3022}3023}, ac);3024}3025return null;3026}302730283029/*3030* returns the AccessibleContext that contains an AccessibleTable3031*/3032private AccessibleContext getContextFromAccessibleTable(AccessibleTable at) {3033return hashtab.get(at);3034}30353036/*3037* returns the row count for an AccessibleTable3038*/3039private int getAccessibleTableRowCount(final AccessibleContext ac) {3040debugString("[INFO]: ##### getAccessibleTableRowCount");3041return InvocationUtils.invokeAndWait(new Callable<Integer>() {3042@Override3043public Integer call() throws Exception {3044if (ac != null) {3045AccessibleTable at = ac.getAccessibleTable();3046if (at != null) {3047return at.getAccessibleRowCount();3048}3049}3050return -1;3051}3052}, ac);3053}30543055/*3056* returns the column count for an AccessibleTable3057*/3058private int getAccessibleTableColumnCount(final AccessibleContext ac) {3059debugString("[INFO]: ##### getAccessibleTableColumnCount");3060return InvocationUtils.invokeAndWait(new Callable<Integer>() {3061@Override3062public Integer call() throws Exception {3063if (ac != null) {3064AccessibleTable at = ac.getAccessibleTable();3065if (at != null) {3066return at.getAccessibleColumnCount();3067}3068}3069return -1;3070}3071}, ac);3072}30733074/*3075* returns the AccessibleContext for an AccessibleTable cell3076*/3077private AccessibleContext getAccessibleTableCellAccessibleContext(final AccessibleTable at,3078final int row, final int column) {3079debugString("[INFO]: getAccessibleTableCellAccessibleContext: at = "+at.getClass());3080if (at == null) return null;3081return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {3082@Override3083public AccessibleContext call() throws Exception {3084if (!(at instanceof AccessibleContext)) {3085Accessible a = at.getAccessibleAt(row, column);3086if (a != null) {3087return a.getAccessibleContext();3088}3089} else {3090// work-around for AccessibleJTable.getCurrentAccessibleContext returning3091// wrong renderer component when cell contains more than one component3092AccessibleContext ac = (AccessibleContext) at;3093Accessible parent = ac.getAccessibleParent();3094if (parent != null) {3095int indexInParent = ac.getAccessibleIndexInParent();3096Accessible child =3097parent.getAccessibleContext().getAccessibleChild(indexInParent);3098if (child instanceof JTable) {3099JTable table = (JTable) child;31003101TableCellRenderer renderer = table.getCellRenderer(row, column);3102if (renderer == null) {3103Class<?> columnClass = table.getColumnClass(column);3104renderer = table.getDefaultRenderer(columnClass);3105}3106Component component =3107renderer.getTableCellRendererComponent(table, table.getValueAt(row, column),3108false, false, row, column);3109if (component instanceof Accessible) {3110return component.getAccessibleContext();3111}3112}3113}3114}3115return null;3116}3117}, getContextFromAccessibleTable(at));3118}31193120/*3121* returns the index of a cell at a given row and column in an AccessibleTable3122*/3123private int getAccessibleTableCellIndex(final AccessibleTable at, int row, int column) {3124debugString("[INFO]: ##### getAccessibleTableCellIndex: at="+at);3125if (at != null) {3126int cellIndex = row *3127InvocationUtils.invokeAndWait(new Callable<Integer>() {3128@Override3129public Integer call() throws Exception {3130return at.getAccessibleColumnCount();3131}3132}, getContextFromAccessibleTable(at)) +3133column;3134debugString("[INFO]: ##### getAccessibleTableCellIndex="+cellIndex);3135return cellIndex;3136}3137debugString("[ERROR]: ##### getAccessibleTableCellIndex FAILED");3138return -1;3139}31403141/*3142* returns the row extent of a cell at a given row and column in an AccessibleTable3143*/3144private int getAccessibleTableCellRowExtent(final AccessibleTable at, final int row, final int column) {3145debugString("[INFO]: ##### getAccessibleTableCellRowExtent");3146if (at != null) {3147int rowExtent = InvocationUtils.invokeAndWait(new Callable<Integer>() {3148@Override3149public Integer call() throws Exception {3150return at.getAccessibleRowExtentAt(row, column);3151}3152},3153getContextFromAccessibleTable(at));3154debugString("[INFO]: ##### getAccessibleTableCellRowExtent="+rowExtent);3155return rowExtent;3156}3157debugString("[ERROR]: ##### getAccessibleTableCellRowExtent FAILED");3158return -1;3159}31603161/*3162* returns the column extent of a cell at a given row and column in an AccessibleTable3163*/3164private int getAccessibleTableCellColumnExtent(final AccessibleTable at, final int row, final int column) {3165debugString("[INFO]: ##### getAccessibleTableCellColumnExtent");3166if (at != null) {3167int columnExtent = InvocationUtils.invokeAndWait(new Callable<Integer>() {3168@Override3169public Integer call() throws Exception {3170return at.getAccessibleColumnExtentAt(row, column);3171}3172},3173getContextFromAccessibleTable(at));3174debugString("[INFO]: ##### getAccessibleTableCellColumnExtent="+columnExtent);3175return columnExtent;3176}3177debugString("[ERROR]: ##### getAccessibleTableCellColumnExtent FAILED");3178return -1;3179}31803181/*3182* returns whether a cell is selected at a given row and column in an AccessibleTable3183*/3184private boolean isAccessibleTableCellSelected(final AccessibleTable at, final int row,3185final int column) {3186debugString("[INFO]: ##### isAccessibleTableCellSelected: ["+row+"]["+column+"]");3187if (at == null)3188return false;3189return InvocationUtils.invokeAndWait(new Callable<Boolean>() {3190@Override3191public Boolean call() throws Exception {3192boolean isSelected = false;3193Accessible a = at.getAccessibleAt(row, column);3194if (a != null) {3195AccessibleContext ac = a.getAccessibleContext();3196if (ac == null)3197return false;3198AccessibleStateSet as = ac.getAccessibleStateSet();3199if (as != null) {3200isSelected = as.contains(AccessibleState.SELECTED);3201}3202}3203return isSelected;3204}3205}, getContextFromAccessibleTable(at));3206}32073208/*3209* returns an AccessibleTable that represents the row header in an3210* AccessibleTable3211*/3212private AccessibleTable getAccessibleTableRowHeader(final AccessibleContext ac) {3213debugString("[INFO]: ##### getAccessibleTableRowHeader called");3214AccessibleTable at = InvocationUtils.invokeAndWait(new Callable<AccessibleTable>() {3215@Override3216public AccessibleTable call() throws Exception {3217if (ac != null) {3218AccessibleTable at = ac.getAccessibleTable();3219if (at != null) {3220return at.getAccessibleRowHeader();3221}3222}3223return null;3224}3225}, ac);3226if (at != null) {3227hashtab.put(at, ac);3228}3229return at;3230}32313232/*3233* returns an AccessibleTable that represents the column header in an3234* AccessibleTable3235*/3236private AccessibleTable getAccessibleTableColumnHeader(final AccessibleContext ac) {3237debugString("[INFO]: ##### getAccessibleTableColumnHeader");3238if (ac == null)3239return null;3240AccessibleTable at = InvocationUtils.invokeAndWait(new Callable<AccessibleTable>() {3241@Override3242public AccessibleTable call() throws Exception {3243// workaround for getAccessibleColumnHeader NPE3244// when the table header is null3245Accessible parent = ac.getAccessibleParent();3246if (parent != null) {3247int indexInParent = ac.getAccessibleIndexInParent();3248Accessible child =3249parent.getAccessibleContext().getAccessibleChild(indexInParent);3250if (child instanceof JTable) {3251JTable table = (JTable) child;3252if (table.getTableHeader() == null) {3253return null;3254}3255}3256}3257AccessibleTable at = ac.getAccessibleTable();3258if (at != null) {3259return at.getAccessibleColumnHeader();3260}3261return null;3262}3263}, ac);3264if (at != null) {3265hashtab.put(at, ac);3266}3267return at;3268}32693270/*3271* returns the number of row headers in an AccessibleTable that represents3272* the row header in an AccessibleTable3273*/3274private int getAccessibleTableRowHeaderRowCount(AccessibleContext ac) {32753276debugString("[INFO]: ##### getAccessibleTableRowHeaderRowCount called");3277if (ac != null) {3278final AccessibleTable atRowHeader = getAccessibleTableRowHeader(ac);3279if (atRowHeader != null) {3280return InvocationUtils.invokeAndWait(new Callable<Integer>() {3281@Override3282public Integer call() throws Exception {3283if (atRowHeader != null) {3284return atRowHeader.getAccessibleRowCount();3285}3286return -1;3287}3288}, ac);3289}3290}3291return -1;3292}32933294/*3295* returns the number of column headers in an AccessibleTable that represents3296* the row header in an AccessibleTable3297*/3298private int getAccessibleTableRowHeaderColumnCount(AccessibleContext ac) {3299debugString("[INFO]: ##### getAccessibleTableRowHeaderColumnCount called");3300if (ac != null) {3301final AccessibleTable atRowHeader = getAccessibleTableRowHeader(ac);3302if (atRowHeader != null) {3303return InvocationUtils.invokeAndWait(new Callable<Integer>() {3304@Override3305public Integer call() throws Exception {3306if (atRowHeader != null) {3307return atRowHeader.getAccessibleColumnCount();3308}3309return -1;3310}3311}, ac);3312}3313}3314debugString("[ERROR]: ##### getAccessibleTableRowHeaderColumnCount FAILED");3315return -1;3316}33173318/*3319* returns the number of row headers in an AccessibleTable that represents3320* the column header in an AccessibleTable3321*/3322private int getAccessibleTableColumnHeaderRowCount(AccessibleContext ac) {33233324debugString("[INFO]: ##### getAccessibleTableColumnHeaderRowCount");3325if (ac != null) {3326final AccessibleTable atColumnHeader = getAccessibleTableColumnHeader(ac);3327if (atColumnHeader != null) {3328return InvocationUtils.invokeAndWait(new Callable<Integer>() {3329@Override3330public Integer call() throws Exception {3331if (atColumnHeader != null) {3332return atColumnHeader.getAccessibleRowCount();3333}3334return -1;3335}3336}, ac);3337}3338}3339debugString("[ERROR]: ##### getAccessibleTableColumnHeaderRowCount FAILED");3340return -1;3341}33423343/*3344* returns the number of column headers in an AccessibleTable that represents3345* the column header in an AccessibleTable3346*/3347private int getAccessibleTableColumnHeaderColumnCount(AccessibleContext ac) {33483349debugString("[ERROR]: ##### getAccessibleTableColumnHeaderColumnCount");3350if (ac != null) {3351final AccessibleTable atColumnHeader = getAccessibleTableColumnHeader(ac);3352if (atColumnHeader != null) {3353return InvocationUtils.invokeAndWait(new Callable<Integer>() {3354@Override3355public Integer call() throws Exception {3356if (atColumnHeader != null) {3357return atColumnHeader.getAccessibleColumnCount();3358}3359return -1;3360}3361}, ac);3362}3363}3364debugString("[ERROR]: ##### getAccessibleTableColumnHeaderColumnCount FAILED");3365return -1;3366}33673368/*3369* returns the description of a row header in an AccessibleTable3370*/3371private AccessibleContext getAccessibleTableRowDescription(final AccessibleTable table,3372final int row) {3373return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {3374@Override3375public AccessibleContext call() throws Exception {3376if (table != null) {3377Accessible a = table.getAccessibleRowDescription(row);3378if (a != null) {3379return a.getAccessibleContext();3380}3381}3382return null;3383}3384}, getContextFromAccessibleTable(table));3385}33863387/*3388* returns the description of a column header in an AccessibleTable3389*/3390private AccessibleContext getAccessibleTableColumnDescription(final AccessibleTable at,3391final int column) {3392if (at == null)3393return null;3394return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {3395@Override3396public AccessibleContext call() throws Exception {3397Accessible a = at.getAccessibleColumnDescription(column);3398if (a != null) {3399return a.getAccessibleContext();3400}3401return null;3402}3403}, getContextFromAccessibleTable(at));3404}34053406/*3407* returns the number of rows selected in an AccessibleTable3408*/3409private int getAccessibleTableRowSelectionCount(final AccessibleTable at) {3410if (at != null) {3411return InvocationUtils.invokeAndWait(new Callable<Integer>() {3412@Override3413public Integer call() throws Exception {3414int[] selections = at.getSelectedAccessibleRows();3415if (selections != null)3416return selections.length;3417else3418return -1;3419}3420}, getContextFromAccessibleTable(at));3421}3422return -1;3423}34243425/*3426* returns the row number of the i-th selected row in an AccessibleTable3427*/3428private int getAccessibleTableRowSelections(final AccessibleTable at, final int i) {3429if (at != null) {3430return InvocationUtils.invokeAndWait(new Callable<Integer>() {3431@Override3432public Integer call() throws Exception {3433int[] selections = at.getSelectedAccessibleRows();3434if (selections.length > i) {3435return selections[i];3436}3437return -1;3438}3439}, getContextFromAccessibleTable(at));3440}3441return -1;3442}34433444/*3445* returns whether a row is selected in an AccessibleTable3446*/3447private boolean isAccessibleTableRowSelected(final AccessibleTable at,3448final int row) {3449if (at == null)3450return false;3451return InvocationUtils.invokeAndWait(new Callable<Boolean>() {3452@Override3453public Boolean call() throws Exception {3454return at.isAccessibleRowSelected(row);3455}3456}, getContextFromAccessibleTable(at));3457}34583459/*3460* returns whether a column is selected in an AccessibleTable3461*/3462private boolean isAccessibleTableColumnSelected(final AccessibleTable at,3463final int column) {3464if (at == null)3465return false;3466return InvocationUtils.invokeAndWait(new Callable<Boolean>() {3467@Override3468public Boolean call() throws Exception {3469return at.isAccessibleColumnSelected(column);3470}3471}, getContextFromAccessibleTable(at));3472}34733474/*3475* returns the number of columns selected in an AccessibleTable3476*/3477private int getAccessibleTableColumnSelectionCount(final AccessibleTable at) {3478if (at == null)3479return -1;3480return InvocationUtils.invokeAndWait(new Callable<Integer>() {3481@Override3482public Integer call() throws Exception {3483int[] selections = at.getSelectedAccessibleColumns();3484if (selections != null)3485return selections.length;3486else3487return -1;3488}3489}, getContextFromAccessibleTable(at));3490}34913492/*3493* returns the row number of the i-th selected row in an AccessibleTable3494*/3495private int getAccessibleTableColumnSelections(final AccessibleTable at, final int i) {3496if (at == null)3497return -1;3498return InvocationUtils.invokeAndWait(new Callable<Integer>() {3499@Override3500public Integer call() throws Exception {3501int[] selections = at.getSelectedAccessibleColumns();3502if (selections != null && selections.length > i) {3503return selections[i];3504}3505return -1;3506}3507}, getContextFromAccessibleTable(at));3508}35093510/* ===== AccessibleExtendedTable (since 1.4) ===== */35113512/*3513* returns the row number for a cell at a given index in an AccessibleTable3514*/3515private int getAccessibleTableRow(final AccessibleTable at, int index) {3516if (at == null)3517return -1;3518int colCount=InvocationUtils.invokeAndWait(new Callable<Integer>() {3519@Override3520public Integer call() throws Exception {3521return at.getAccessibleColumnCount();3522}3523}, getContextFromAccessibleTable(at));3524return index / colCount;3525}35263527/*3528* returns the column number for a cell at a given index in an AccessibleTable3529*/3530private int getAccessibleTableColumn(final AccessibleTable at, int index) {3531if (at == null)3532return -1;3533int colCount=InvocationUtils.invokeAndWait(new Callable<Integer>() {3534@Override3535public Integer call() throws Exception {3536return at.getAccessibleColumnCount();3537}3538}, getContextFromAccessibleTable(at));3539return index % colCount;3540}35413542/*3543* returns the index for a cell at a given row and column in an3544* AccessibleTable3545*/3546private int getAccessibleTableIndex(final AccessibleTable at, int row, int column) {3547if (at == null)3548return -1;3549int colCount = InvocationUtils.invokeAndWait(new Callable<Integer>() {3550@Override3551public Integer call() throws Exception {3552return at.getAccessibleColumnCount();3553}3554}, getContextFromAccessibleTable(at));3555return row * colCount + column;3556}35573558// ===== AccessibleRelationSet =====35593560/*3561* returns the number of relations in the AccessibleContext's3562* AccessibleRelationSet3563*/3564private int getAccessibleRelationCount(final AccessibleContext ac) {3565String version = getJavaVersionProperty();3566if ((version != null && version.compareTo("1.3") >= 0)) {3567if (ac != null) {3568AccessibleRelationSet ars = InvocationUtils.invokeAndWait(new Callable<AccessibleRelationSet>() {3569@Override3570public AccessibleRelationSet call() throws Exception {3571return ac.getAccessibleRelationSet();3572}3573}, ac);3574if (ars != null)3575return ars.size();3576}3577}3578return 0;3579}35803581/*3582* returns the ith relation key in the AccessibleContext's3583* AccessibleRelationSet3584*/3585private String getAccessibleRelationKey(final AccessibleContext ac, final int i) {3586return InvocationUtils.invokeAndWait(new Callable<String>() {3587@Override3588public String call() throws Exception {3589if (ac != null) {3590AccessibleRelationSet ars = ac.getAccessibleRelationSet();3591if (ars != null) {3592AccessibleRelation[] relations = ars.toArray();3593if (relations != null && i >= 0 && i < relations.length) {3594return relations[i].getKey();3595}3596}3597}3598return null;3599}3600}, ac);3601}36023603/*3604* returns the number of targets in a relation in the AccessibleContext's3605* AccessibleRelationSet3606*/3607private int getAccessibleRelationTargetCount(final AccessibleContext ac, final int i) {3608return InvocationUtils.invokeAndWait(new Callable<Integer>() {3609@Override3610public Integer call() throws Exception {3611if (ac != null) {3612AccessibleRelationSet ars = ac.getAccessibleRelationSet();3613if (ars != null) {3614AccessibleRelation[] relations = ars.toArray();3615if (relations != null && i >= 0 && i < relations.length) {3616Object[] targets = relations[i].getTarget();3617return targets.length;3618}3619}3620}3621return -1;3622}3623}, ac);3624}36253626/*3627* returns the jth target in the ith relation in the AccessibleContext's3628* AccessibleRelationSet3629*/3630private AccessibleContext getAccessibleRelationTarget(final AccessibleContext ac,3631final int i, final int j) {3632debugString("[INFO]: ***** getAccessibleRelationTarget");3633return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {3634@Override3635public AccessibleContext call() throws Exception {3636if (ac != null) {3637AccessibleRelationSet ars = ac.getAccessibleRelationSet();3638if (ars != null) {3639AccessibleRelation[] relations = ars.toArray();3640if (relations != null && i >= 0 && i < relations.length) {3641Object[] targets = relations[i].getTarget();3642if (targets != null && j >= 0 & j < targets.length) {3643Object o = targets[j];3644if (o instanceof Accessible) {3645return ((Accessible) o).getAccessibleContext();3646}3647}3648}3649}3650}3651return null;3652}3653}, ac);3654}36553656// ========= AccessibleHypertext =========36573658private Map<AccessibleHypertext, AccessibleContext> hyperTextContextMap = new WeakHashMap<>();3659private Map<AccessibleHyperlink, AccessibleContext> hyperLinkContextMap = new WeakHashMap<>();36603661/*3662* Returns the AccessibleHypertext3663*/3664private AccessibleHypertext getAccessibleHypertext(final AccessibleContext ac) {3665debugString("[INFO]: getAccessibleHyperlink");3666if (ac==null)3667return null;3668AccessibleHypertext hypertext = InvocationUtils.invokeAndWait(new Callable<AccessibleHypertext>() {3669@Override3670public AccessibleHypertext call() throws Exception {3671AccessibleText at = ac.getAccessibleText();3672if (!(at instanceof AccessibleHypertext)) {3673return null;3674}3675return ((AccessibleHypertext) at);3676}3677}, ac);3678hyperTextContextMap.put(hypertext, ac);3679return hypertext;3680}36813682/*3683* Returns the number of AccessibleHyperlinks3684*/3685private int getAccessibleHyperlinkCount(AccessibleContext ac) {3686debugString("[INFO]: getAccessibleHyperlinkCount");3687if (ac == null) {3688return 0;3689}3690final AccessibleHypertext hypertext = getAccessibleHypertext(ac);3691if (hypertext == null) {3692return 0;3693}3694//return hypertext.getLinkCount();3695return InvocationUtils.invokeAndWait(new Callable<Integer>() {3696@Override3697public Integer call() throws Exception {3698return hypertext.getLinkCount();3699}3700}, ac);3701}37023703/*3704* Returns the hyperlink at the specified index3705*/3706private AccessibleHyperlink getAccessibleHyperlink(final AccessibleHypertext hypertext, final int i) {3707debugString("[INFO]: getAccessibleHyperlink");3708if (hypertext == null) {3709return null;3710}3711AccessibleContext ac = hyperTextContextMap.get(hypertext);3712if ( i < 0 || i >=3713InvocationUtils.invokeAndWait(new Callable<Integer>() {3714@Override3715public Integer call() throws Exception {3716return hypertext.getLinkCount();3717}3718}, ac) ) {3719return null;3720}3721AccessibleHyperlink acLink = InvocationUtils.invokeAndWait(new Callable<AccessibleHyperlink>() {3722@Override3723public AccessibleHyperlink call() throws Exception {3724AccessibleHyperlink link = hypertext.getLink(i);3725if (link == null || (!link.isValid())) {3726return null;3727}3728return link;3729}3730}, ac);3731hyperLinkContextMap.put(acLink, ac);3732return acLink;3733}37343735/*3736* Returns the hyperlink object description3737*/3738private String getAccessibleHyperlinkText(final AccessibleHyperlink link) {3739debugString("[INFO]: getAccessibleHyperlinkText");3740if (link == null) {3741return null;3742}3743return InvocationUtils.invokeAndWait(new Callable<String>() {3744@Override3745public String call() throws Exception {3746Object o = link.getAccessibleActionDescription(0);3747if (o != null) {3748return o.toString();3749}3750return null;3751}3752}, hyperLinkContextMap.get(link));3753}37543755/*3756* Returns the hyperlink URL3757*/3758private String getAccessibleHyperlinkURL(final AccessibleHyperlink link) {3759debugString("[INFO]: getAccessibleHyperlinkURL");3760if (link == null) {3761return null;3762}3763return InvocationUtils.invokeAndWait(new Callable<String>() {3764@Override3765public String call() throws Exception {3766Object o = link.getAccessibleActionObject(0);3767if (o != null) {3768return o.toString();3769} else {3770return null;3771}3772}3773}, hyperLinkContextMap.get(link));3774}37753776/*3777* Returns the start index of the hyperlink text3778*/3779private int getAccessibleHyperlinkStartIndex(final AccessibleHyperlink link) {3780debugString("[INFO]: getAccessibleHyperlinkStartIndex");3781if (link == null) {3782return -1;3783}3784return InvocationUtils.invokeAndWait(new Callable<Integer>() {3785@Override3786public Integer call() throws Exception {3787return link.getStartIndex();3788}3789}, hyperLinkContextMap.get(link));3790}37913792/*3793* Returns the end index of the hyperlink text3794*/3795private int getAccessibleHyperlinkEndIndex(final AccessibleHyperlink link) {3796debugString("[INFO]: getAccessibleHyperlinkEndIndex");3797if (link == null) {3798return -1;3799}3800return InvocationUtils.invokeAndWait(new Callable<Integer>() {3801@Override3802public Integer call() throws Exception {3803return link.getEndIndex();3804}3805}, hyperLinkContextMap.get(link));3806}38073808/*3809* Returns the index into an array of hyperlinks that3810* is associated with this character index, or -1 if there3811* is no hyperlink associated with this index.3812*/3813private int getAccessibleHypertextLinkIndex(final AccessibleHypertext hypertext, final int charIndex) {3814debugString("[INFO]: getAccessibleHypertextLinkIndex: charIndex = "+charIndex);3815if (hypertext == null) {3816return -1;3817}3818int linkIndex = InvocationUtils.invokeAndWait(new Callable<Integer>() {3819@Override3820public Integer call() throws Exception {3821return hypertext.getLinkIndex(charIndex);3822}3823}, hyperTextContextMap.get(hypertext));3824debugString("[INFO]: getAccessibleHypertextLinkIndex returning "+linkIndex);3825return linkIndex;3826}38273828/*3829* Actives the hyperlink3830*/3831private boolean activateAccessibleHyperlink(final AccessibleContext ac,3832final AccessibleHyperlink link) {3833//debugString("activateAccessibleHyperlink: link = "+link.getClass());3834if (link == null) {3835return false;3836}3837boolean retval = InvocationUtils.invokeAndWait(new Callable<Boolean>() {3838@Override3839public Boolean call() throws Exception {3840return link.doAccessibleAction(0);3841}3842}, ac);3843debugString("[INFO]: activateAccessibleHyperlink: returning = "+retval);3844return retval;3845}384638473848// ============ AccessibleKeyBinding =============38493850/*3851* returns the component mnemonic3852*/3853private KeyStroke getMnemonic(final AccessibleContext ac) {3854if (ac == null)3855return null;3856return InvocationUtils.invokeAndWait(new Callable<KeyStroke>() {3857@Override3858public KeyStroke call() throws Exception {3859AccessibleComponent comp = ac.getAccessibleComponent();3860if (!(comp instanceof AccessibleExtendedComponent)) {3861return null;3862}3863AccessibleExtendedComponent aec = (AccessibleExtendedComponent) comp;3864if (aec != null) {3865AccessibleKeyBinding akb = aec.getAccessibleKeyBinding();3866if (akb != null) {3867Object o = akb.getAccessibleKeyBinding(0);3868if (o instanceof KeyStroke) {3869return (KeyStroke) o;3870}3871}3872}3873return null;3874}3875}, ac);3876}38773878/*3879* returns the JMenuItem accelerator3880*/3881private KeyStroke getAccelerator(final AccessibleContext ac) {3882// workaround for getAccessibleKeyBinding not returning the3883// JMenuItem accelerator3884if (ac == null)3885return null;3886return InvocationUtils.invokeAndWait(new Callable<KeyStroke>() {3887@Override3888public KeyStroke call() throws Exception {3889Accessible parent = ac.getAccessibleParent();3890if (parent instanceof Accessible) {3891int indexInParent = ac.getAccessibleIndexInParent();3892Accessible child =3893parent.getAccessibleContext().getAccessibleChild(indexInParent);3894if (child instanceof JMenuItem) {3895JMenuItem menuItem = (JMenuItem) child;3896if (menuItem == null)3897return null;3898KeyStroke keyStroke = menuItem.getAccelerator();3899return keyStroke;3900}3901}3902return null;3903}3904}, ac);3905}39063907/*3908* returns 1-24 to indicate which F key is being used for a shortcut or 0 otherwise3909*/3910private int fKeyNumber(KeyStroke keyStroke) {3911if (keyStroke == null)3912return 0;3913int fKey = 0;3914String keyText = KeyEvent.getKeyText(keyStroke.getKeyCode());3915if (keyText != null && (keyText.length() == 2 || keyText.length() == 3)) {3916String prefix = keyText.substring(0, 1);3917if (prefix.equals("F")) {3918try {3919int suffix = Integer.parseInt(keyText.substring(1));3920if (suffix >= 1 && suffix <= 24) {3921fKey = suffix;3922}3923} catch (Exception e) { // ignore NumberFormatException3924}3925}3926}3927return fKey;3928}39293930/*3931* returns one of several important control characters or 0 otherwise3932*/3933private int controlCode(KeyStroke keyStroke) {3934if (keyStroke == null)3935return 0;3936int code = keyStroke.getKeyCode();3937switch (code) {3938case KeyEvent.VK_BACK_SPACE:3939case KeyEvent.VK_DELETE:3940case KeyEvent.VK_DOWN:3941case KeyEvent.VK_END:3942case KeyEvent.VK_HOME:3943case KeyEvent.VK_INSERT:3944case KeyEvent.VK_KP_DOWN:3945case KeyEvent.VK_KP_LEFT:3946case KeyEvent.VK_KP_RIGHT:3947case KeyEvent.VK_KP_UP:3948case KeyEvent.VK_LEFT:3949case KeyEvent.VK_PAGE_DOWN:3950case KeyEvent.VK_PAGE_UP:3951case KeyEvent.VK_RIGHT:3952case KeyEvent.VK_UP:3953break;3954default:3955code = 0;3956break;3957}3958return code;3959}39603961/*3962* returns the KeyStoke character3963*/3964private char getKeyChar(KeyStroke keyStroke) {3965// If the shortcut is an FKey return 1-243966if (keyStroke == null)3967return 0;3968int fKey = fKeyNumber(keyStroke);3969if (fKey != 0) {3970// return 0x00000001 through 0x000000183971debugString("[INFO]: Shortcut is: F" + fKey);3972return (char)fKey;3973}3974// If the accelerator is a control character, return it3975int keyCode = controlCode(keyStroke);3976if (keyCode != 0) {3977debugString("[INFO]: Shortcut is control character: " + Integer.toHexString(keyCode));3978return (char)keyCode;3979}3980String keyText = KeyEvent.getKeyText(keyStroke.getKeyCode());3981debugString("[INFO]: Shortcut is: " + keyText);3982if (keyText != null || keyText.length() > 0) {3983CharSequence seq = keyText.subSequence(0, 1);3984if (seq != null || seq.length() > 0) {3985return seq.charAt(0);3986}3987}3988return 0;3989}39903991/*3992* returns the KeyStroke modifiers as an int3993*/3994private int getModifiers(KeyStroke keyStroke) {3995if (keyStroke == null)3996return 0;3997debugString("[INFO]: In AccessBridge.getModifiers");3998// modifiers is a bit strip where bits 0-7 indicate a traditional modifier3999// such as Ctrl/Alt/Shift, bit 8 indicates an F key shortcut, and bit 9 indicates4000// a control code shortcut such as the delete key.40014002int modifiers = 0;4003// Is the shortcut an FKey?4004if (fKeyNumber(keyStroke) != 0) {4005modifiers |= 1 << 8;4006}4007// Is the shortcut a control code?4008if (controlCode(keyStroke) != 0) {4009modifiers |= 1 << 9;4010}4011// The following is needed in order to handle translated modifiers.4012// getKeyModifiersText doesn't work because for example in German Strg is4013// returned for Ctrl.40144015// There can be more than one modifier, e.g. if the modifier is ctrl + shift + B4016// the toString text is "shift ctrl pressed B". Need to parse through that.4017StringTokenizer st = new StringTokenizer(keyStroke.toString());4018while (st.hasMoreTokens()) {4019String text = st.nextToken();4020// Meta+Ctrl+Alt+Shift4021// 0-3 are shift, ctrl, meta, alt4022// 4-7 are for Solaris workstations (though not being used)4023if (text.startsWith("met")) {4024debugString("[INFO]: found meta");4025modifiers |= ActionEvent.META_MASK;4026}4027if (text.startsWith("ctr")) {4028debugString("[INFO]: found ctrl");4029modifiers |= ActionEvent.CTRL_MASK;4030}4031if (text.startsWith("alt")) {4032debugString("[INFO]: found alt");4033modifiers |= ActionEvent.ALT_MASK;4034}4035if (text.startsWith("shi")) {4036debugString("[INFO]: found shift");4037modifiers |= ActionEvent.SHIFT_MASK;4038}4039}4040debugString("[INFO]: returning modifiers: 0x" + Integer.toHexString(modifiers));4041return modifiers;4042}40434044/*4045* returns the number of key bindings associated with this context4046*/4047private int getAccessibleKeyBindingsCount(AccessibleContext ac) {4048if (ac == null || (! runningOnJDK1_4) )4049return 0;4050int count = 0;40514052if (getMnemonic(ac) != null) {4053count++;4054}4055if (getAccelerator(ac) != null) {4056count++;4057}4058return count;4059}40604061/*4062* returns the key binding character at the specified index4063*/4064private char getAccessibleKeyBindingChar(AccessibleContext ac, int index) {4065if (ac == null || (! runningOnJDK1_4) )4066return 0;4067if((index == 0) && getMnemonic(ac)==null) {// special case when there is no mnemonic4068KeyStroke keyStroke = getAccelerator(ac);4069if (keyStroke != null) {4070return getKeyChar(keyStroke);4071}4072}4073if (index == 0) { // mnemonic4074KeyStroke keyStroke = getMnemonic(ac);4075if (keyStroke != null) {4076return getKeyChar(keyStroke);4077}4078} else if (index == 1) { // accelerator4079KeyStroke keyStroke = getAccelerator(ac);4080if (keyStroke != null) {4081return getKeyChar(keyStroke);4082}4083}4084return 0;4085}40864087/*4088* returns the key binding modifiers at the specified index4089*/4090private int getAccessibleKeyBindingModifiers(AccessibleContext ac, int index) {4091if (ac == null || (! runningOnJDK1_4) )4092return 0;4093if((index == 0) && getMnemonic(ac)==null) {// special case when there is no mnemonic4094KeyStroke keyStroke = getAccelerator(ac);4095if (keyStroke != null) {4096return getModifiers(keyStroke);4097}4098}4099if (index == 0) { // mnemonic4100KeyStroke keyStroke = getMnemonic(ac);4101if (keyStroke != null) {4102return getModifiers(keyStroke);4103}4104} else if (index == 1) { // accelerator4105KeyStroke keyStroke = getAccelerator(ac);4106if (keyStroke != null) {4107return getModifiers(keyStroke);4108}4109}4110return 0;4111}41124113// ========== AccessibleIcon ============41144115/*4116* return the number of icons associated with this context4117*/4118private int getAccessibleIconsCount(final AccessibleContext ac) {4119debugString("[INFO]: getAccessibleIconsCount");4120if (ac == null) {4121return 0;4122}4123return InvocationUtils.invokeAndWait(new Callable<Integer>() {4124@Override4125public Integer call() throws Exception {4126AccessibleIcon[] ai = ac.getAccessibleIcon();4127if (ai == null) {4128return 0;4129}4130return ai.length;4131}4132}, ac);4133}41344135/*4136* return icon description at the specified index4137*/4138private String getAccessibleIconDescription(final AccessibleContext ac, final int index) {4139debugString("[INFO]: getAccessibleIconDescription: index = "+index);4140if (ac == null) {4141return null;4142}4143return InvocationUtils.invokeAndWait(new Callable<String>() {4144@Override4145public String call() throws Exception {4146AccessibleIcon[] ai = ac.getAccessibleIcon();4147if (ai == null || index < 0 || index >= ai.length) {4148return null;4149}4150return ai[index].getAccessibleIconDescription();4151}4152}, ac);4153}41544155/*4156* return icon height at the specified index4157*/4158private int getAccessibleIconHeight(final AccessibleContext ac, final int index) {4159debugString("[INFO]: getAccessibleIconHeight: index = "+index);4160if (ac == null) {4161return 0;4162}4163return InvocationUtils.invokeAndWait(new Callable<Integer>() {4164@Override4165public Integer call() throws Exception {4166AccessibleIcon[] ai = ac.getAccessibleIcon();4167if (ai == null || index < 0 || index >= ai.length) {4168return 0;4169}4170return ai[index].getAccessibleIconHeight();4171}4172}, ac);4173}41744175/*4176* return icon width at the specified index4177*/4178private int getAccessibleIconWidth(final AccessibleContext ac, final int index) {4179debugString("[INFO]: getAccessibleIconWidth: index = "+index);4180if (ac == null) {4181return 0;4182}4183return InvocationUtils.invokeAndWait(new Callable<Integer>() {4184@Override4185public Integer call() throws Exception {4186AccessibleIcon[] ai = ac.getAccessibleIcon();4187if (ai == null || index < 0 || index >= ai.length) {4188return 0;4189}4190return ai[index].getAccessibleIconWidth();4191}4192}, ac);4193}41944195// ========= AccessibleAction ===========41964197/*4198* return the number of icons associated with this context4199*/4200private int getAccessibleActionsCount(final AccessibleContext ac) {4201debugString("[INFO]: getAccessibleActionsCount");4202if (ac == null) {4203return 0;4204}4205return InvocationUtils.invokeAndWait(new Callable<Integer>() {4206@Override4207public Integer call() throws Exception {4208AccessibleAction aa = ac.getAccessibleAction();4209if (aa == null)4210return 0;4211return aa.getAccessibleActionCount();4212}4213}, ac);4214}42154216/*4217* return icon description at the specified index4218*/4219private String getAccessibleActionName(final AccessibleContext ac, final int index) {4220debugString("[INFO]: getAccessibleActionName: index = "+index);4221if (ac == null) {4222return null;4223}4224return InvocationUtils.invokeAndWait(new Callable<String>() {4225@Override4226public String call() throws Exception {4227AccessibleAction aa = ac.getAccessibleAction();4228if (aa == null) {4229return null;4230}4231return aa.getAccessibleActionDescription(index);4232}4233}, ac);4234}4235/*4236* return icon description at the specified index4237*/4238private boolean doAccessibleActions(final AccessibleContext ac, final String name) {4239debugString("[INFO]: doAccessibleActions: action name = "+name);4240if (ac == null || name == null) {4241return false;4242}4243return InvocationUtils.invokeAndWait(new Callable<Boolean>() {4244@Override4245public Boolean call() throws Exception {4246AccessibleAction aa = ac.getAccessibleAction();4247if (aa == null) {4248return false;4249}4250int index = -1;4251int numActions = aa.getAccessibleActionCount();4252for (int i = 0; i < numActions; i++) {4253String actionName = aa.getAccessibleActionDescription(i);4254if (name.equals(actionName)) {4255index = i;4256break;4257}4258}4259if (index == -1) {4260return false;4261}4262boolean retval = aa.doAccessibleAction(index);4263return retval;4264}4265}, ac);4266}42674268/* ===== AT utility methods ===== */42694270/**4271* Sets the contents of an AccessibleContext that4272* implements AccessibleEditableText with the4273* specified text string.4274* Returns whether successful.4275*/4276private boolean setTextContents(final AccessibleContext ac, final String text) {4277debugString("[INFO]: setTextContents: ac = "+ac+"; text = "+text);42784279if (! (ac instanceof AccessibleEditableText)) {4280debugString("[WARN]: ac not instanceof AccessibleEditableText: "+ac);4281return false;4282}4283if (text == null) {4284debugString("[WARN]: text is null");4285return false;4286}42874288return InvocationUtils.invokeAndWait(new Callable<Boolean>() {4289@Override4290public Boolean call() throws Exception {4291// check whether the text field is editable4292AccessibleStateSet ass = ac.getAccessibleStateSet();4293if (!ass.contains(AccessibleState.ENABLED)) {4294return false;4295}4296((AccessibleEditableText) ac).setTextContents(text);4297return true;4298}4299}, ac);4300}43014302/**4303* Returns the Accessible Context of an Internal Frame object that is4304* the ancestor of a given object. If the object is an Internal Frame4305* object or an Internal Frame ancestor object was found, returns the4306* object's AccessibleContext.4307* If there is no ancestor object that has an Accessible Role of4308* Internal Frame, returns (AccessibleContext)0.4309*/4310private AccessibleContext getInternalFrame (AccessibleContext ac) {4311return getParentWithRole(ac, AccessibleRole.INTERNAL_FRAME.toString());4312}43134314/**4315* Returns the Accessible Context for the top level object in4316* a Java Window. This is same Accessible Context that is obtained4317* from GetAccessibleContextFromHWND for that window. Returns4318* (AccessibleContext)0 on error.4319*/4320private AccessibleContext getTopLevelObject (final AccessibleContext ac) {4321debugString("[INFO]: getTopLevelObject; ac = "+ac);4322if (ac == null) {4323return null;4324}4325return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {4326@Override4327public AccessibleContext call() throws Exception {4328if (ac.getAccessibleRole() == AccessibleRole.DIALOG) {4329// return the dialog, not the parent window4330return ac;4331}43324333Accessible parent = ac.getAccessibleParent();4334if (parent == null) {4335return ac;4336}4337Accessible tmp = parent;4338while (tmp != null && tmp.getAccessibleContext() != null) {4339AccessibleContext ac2 = tmp.getAccessibleContext();4340if (ac2 != null && ac2.getAccessibleRole() == AccessibleRole.DIALOG) {4341// return the dialog, not the parent window4342return ac2;4343}4344parent = tmp;4345tmp = parent.getAccessibleContext().getAccessibleParent();4346}4347return parent.getAccessibleContext();4348}4349}, ac);4350}43514352/**4353* Returns the parent AccessibleContext that has the specified AccessibleRole.4354* Returns null on error or if the AccessibleContext does not exist.4355*/4356private AccessibleContext getParentWithRole (final AccessibleContext ac,4357final String roleName) {4358debugString("[INFO]: getParentWithRole; ac = "+ac + "\n role = "+roleName);4359if (ac == null || roleName == null) {4360return null;4361}43624363return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {4364@Override4365public AccessibleContext call() throws Exception {4366AccessibleRole role = AccessBridge.this.accessibleRoleMap.get(roleName);4367if (role == null) {4368return ac;4369}43704371Accessible parent = ac.getAccessibleParent();4372if (parent == null && ac.getAccessibleRole() == role) {4373return ac;4374}43754376Accessible tmp = parent;4377AccessibleContext tmp_ac = null;43784379while (tmp != null && (tmp_ac = tmp.getAccessibleContext()) != null) {4380AccessibleRole ar = tmp_ac.getAccessibleRole();4381if (ar == role) {4382// found4383return tmp_ac;4384}4385parent = tmp;4386tmp = parent.getAccessibleContext().getAccessibleParent();4387}4388// not found4389return null;4390}4391}, ac);4392}43934394/**4395* Returns the parent AccessibleContext that has the specified AccessibleRole.4396* Otherwise, returns the top level object for the Java Window.4397* Returns (AccessibleContext)0 on error.4398*/4399private AccessibleContext getParentWithRoleElseRoot (AccessibleContext ac,4400String roleName) {4401AccessibleContext retval = getParentWithRole(ac, roleName);4402if (retval == null) {4403retval = getTopLevelObject(ac);4404}4405return retval;4406}44074408/**4409* Returns how deep in the object hierarchy a given object is.4410* The top most object in the object hierarchy has an object depth of 0.4411* Returns -1 on error.4412*/4413private int getObjectDepth(final AccessibleContext ac) {4414debugString("[INFO]: getObjectDepth: ac = "+ac);44154416if (ac == null) {4417return -1;4418}4419return InvocationUtils.invokeAndWait(new Callable<Integer>() {4420@Override4421public Integer call() throws Exception {4422int count = 0;4423Accessible parent = ac.getAccessibleParent();4424if (parent == null) {4425return count;4426}4427Accessible tmp = parent;4428while (tmp != null && tmp.getAccessibleContext() != null) {4429parent = tmp;4430tmp = parent.getAccessibleContext().getAccessibleParent();4431count++;4432}4433return count;4434}4435}, ac);4436}44374438/**4439* Returns the Accessible Context of the current ActiveDescendent of an object.4440* Returns (AccessibleContext)0 on error.4441*/4442private AccessibleContext getActiveDescendent (final AccessibleContext ac) {4443debugString("[INFO]: getActiveDescendent: ac = "+ac);4444if (ac == null) {4445return null;4446}4447// workaround for JTree bug where the only possible active4448// descendent is the JTree root4449final Accessible parent = InvocationUtils.invokeAndWait(new Callable<Accessible>() {4450@Override4451public Accessible call() throws Exception {4452return ac.getAccessibleParent();4453}4454}, ac);44554456if (parent != null) {4457Accessible child = InvocationUtils.invokeAndWait(new Callable<Accessible>() {4458@Override4459public Accessible call() throws Exception {4460int indexInParent = ac.getAccessibleIndexInParent();4461return parent.getAccessibleContext().getAccessibleChild(indexInParent);4462}4463}, ac);44644465if (child instanceof JTree) {4466// return the selected node4467final JTree tree = (JTree)child;4468return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {4469@Override4470public AccessibleContext call() throws Exception {4471return new AccessibleJTreeNode(tree,4472tree.getSelectionPath(),4473null);4474}4475}, child);4476}4477}44784479return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {4480@Override4481public AccessibleContext call() throws Exception {4482AccessibleSelection as = ac.getAccessibleSelection();4483if (as == null) {4484return null;4485}4486// assume single selection4487if (as.getAccessibleSelectionCount() != 1) {4488return null;4489}4490Accessible a = as.getAccessibleSelection(0);4491if (a == null) {4492return null;4493}4494return a.getAccessibleContext();4495}4496}, ac);4497}449844994500/**4501* Additional methods for Teton4502*/45034504/**4505* Gets the AccessibleName for a component based upon the JAWS algorithm.4506* Returns whether successful.4507*4508* Bug ID 4916682 - Implement JAWS AccessibleName policy4509*/4510private String getJAWSAccessibleName(final AccessibleContext ac) {4511debugString("[INFO]: getJAWSAccessibleName");4512if (ac == null) {4513return null;4514}4515// placeholder4516return InvocationUtils.invokeAndWait(new Callable<String>() {4517@Override4518public String call() throws Exception {4519return ac.getAccessibleName();4520}4521}, ac);4522}45234524/**4525* Request focus for a component. Returns whether successful;4526*4527* Bug ID 4944757 - requestFocus method needed4528*/4529private boolean requestFocus(final AccessibleContext ac) {4530debugString("[INFO]: requestFocus");4531if (ac == null) {4532return false;4533}4534return InvocationUtils.invokeAndWait(new Callable<Boolean>() {4535@Override4536public Boolean call() throws Exception {4537AccessibleComponent acomp = ac.getAccessibleComponent();4538if (acomp == null) {4539return false;4540}4541acomp.requestFocus();4542return ac.getAccessibleStateSet().contains(AccessibleState.FOCUSED);4543}4544}, ac);4545}45464547/**4548* Selects text between two indices. Selection includes the4549* text at the start index and the text at the end index. Returns4550* whether successful;4551*4552* Bug ID 4944758 - selectTextRange method needed4553*/4554private boolean selectTextRange(final AccessibleContext ac, final int startIndex, final int endIndex) {4555debugString("[INFO]: selectTextRange: start = "+startIndex+"; end = "+endIndex);4556if (ac == null) {4557return false;4558}4559return InvocationUtils.invokeAndWait(new Callable<Boolean>() {4560@Override4561public Boolean call() throws Exception {4562AccessibleText at = ac.getAccessibleText();4563if (!(at instanceof AccessibleEditableText)) {4564return false;4565}4566((AccessibleEditableText) at).selectText(startIndex, endIndex);45674568boolean result = at.getSelectionStart() == startIndex &&4569at.getSelectionEnd() == endIndex;4570return result;4571}4572}, ac);4573}45744575/**4576* Set the caret to a text position. Returns whether successful;4577*4578* Bug ID 4944770 - setCaretPosition method needed4579*/4580private boolean setCaretPosition(final AccessibleContext ac, final int position) {4581debugString("[INFO]: setCaretPosition: position = "+position);4582if (ac == null) {4583return false;4584}4585return InvocationUtils.invokeAndWait(new Callable<Boolean>() {4586@Override4587public Boolean call() throws Exception {4588AccessibleText at = ac.getAccessibleText();4589if (!(at instanceof AccessibleEditableText)) {4590return false;4591}4592((AccessibleEditableText) at).selectText(position, position);4593return at.getCaretPosition() == position;4594}4595}, ac);4596}45974598/**4599* Gets the number of visible children of an AccessibleContext.4600*4601* Bug ID 4944762- getVisibleChildren for list-like components needed4602*/4603private int _visibleChildrenCount;4604private AccessibleContext _visibleChild;4605private int _currentVisibleIndex;4606private boolean _foundVisibleChild;46074608private int getVisibleChildrenCount(AccessibleContext ac) {4609debugString("[INFO]: getVisibleChildrenCount");4610if (ac == null) {4611return -1;4612}4613_visibleChildrenCount = 0;4614_getVisibleChildrenCount(ac);4615debugString("[INFO]: _visibleChildrenCount = "+_visibleChildrenCount);4616return _visibleChildrenCount;4617}46184619/*4620* Recursively descends AccessibleContext and gets the number4621* of visible children4622*/4623private void _getVisibleChildrenCount(final AccessibleContext ac) {4624if (ac == null)4625return;4626if(ac instanceof AccessibleExtendedTable) {4627_getVisibleChildrenCount((AccessibleExtendedTable)ac);4628return;4629}4630int numChildren = InvocationUtils.invokeAndWait(new Callable<Integer>() {4631@Override4632public Integer call() throws Exception {4633return ac.getAccessibleChildrenCount();4634}4635}, ac);4636for (int i = 0; i < numChildren; i++) {4637final int idx = i;4638final AccessibleContext ac2 = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {4639@Override4640public AccessibleContext call() throws Exception {4641Accessible a = ac.getAccessibleChild(idx);4642if (a != null)4643return a.getAccessibleContext();4644else4645return null;4646}4647}, ac);4648if ( ac2 == null ||4649(!InvocationUtils.invokeAndWait(new Callable<Boolean>() {4650@Override4651public Boolean call() throws Exception {4652return ac2.getAccessibleStateSet().contains(AccessibleState.SHOWING);4653}4654}, ac))4655) {4656continue;4657}4658_visibleChildrenCount++;46594660if (InvocationUtils.invokeAndWait(new Callable<Integer>() {4661@Override4662public Integer call() throws Exception {4663return ac2.getAccessibleChildrenCount();4664}4665}, ac) > 0 ) {4666_getVisibleChildrenCount(ac2);4667}4668}4669}46704671/*4672* Recursively descends AccessibleContext and gets the number4673* of visible children. Stops search if get to invisible part of table.4674*/4675private void _getVisibleChildrenCount(final AccessibleExtendedTable acTable) {4676if (acTable == null)4677return;4678int lastVisibleRow = -1;4679int lastVisibleColumn = -1;4680boolean foundVisible = false;4681int rowCount = InvocationUtils.invokeAndWait(new Callable<Integer>() {4682@Override4683public Integer call() throws Exception {4684return acTable.getAccessibleRowCount();4685}4686}, acTable);4687int columnCount = InvocationUtils.invokeAndWait(new Callable<Integer>() {4688@Override4689public Integer call() throws Exception {4690return acTable.getAccessibleColumnCount();4691}4692}, acTable);4693for (int rowIdx = 0; rowIdx < rowCount; rowIdx++) {4694for (int columnIdx = 0; columnIdx < columnCount; columnIdx++) {4695if (lastVisibleRow != -1 && rowIdx > lastVisibleRow) {4696continue;4697}4698if (lastVisibleColumn != -1 && columnIdx > lastVisibleColumn) {4699continue;4700}4701int finalRowIdx = rowIdx;4702int finalColumnIdx = columnIdx;4703final AccessibleContext ac2 = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {4704@Override4705public AccessibleContext call() throws Exception {4706Accessible a = acTable.getAccessibleAt(finalRowIdx, finalColumnIdx);4707if (a == null)4708return null;4709else4710return a.getAccessibleContext();4711}4712}, acTable);4713if (ac2 == null ||4714(!InvocationUtils.invokeAndWait(new Callable<Boolean>() {4715@Override4716public Boolean call() throws Exception {4717return ac2.getAccessibleStateSet().contains(AccessibleState.SHOWING);4718}4719}, acTable))4720) {4721if (foundVisible) {4722if (columnIdx != 0 && lastVisibleColumn == -1) {4723//the same row, so we found the last visible column4724lastVisibleColumn = columnIdx - 1;4725} else if (columnIdx == 0 && lastVisibleRow == -1) {4726lastVisibleRow = rowIdx - 1;4727}4728}4729continue;4730}47314732foundVisible = true;47334734_visibleChildrenCount++;47354736if (InvocationUtils.invokeAndWait(new Callable<Integer>() {4737@Override4738public Integer call() throws Exception {4739return ac2.getAccessibleChildrenCount();4740}4741}, acTable) > 0) {4742_getVisibleChildrenCount(ac2);4743}4744}4745}4746}47474748/**4749* Gets the visible child of an AccessibleContext at the4750* specified index4751*4752* Bug ID 4944762- getVisibleChildren for list-like components needed4753*/4754private AccessibleContext getVisibleChild(AccessibleContext ac, int index) {4755debugString("[INFO]: getVisibleChild: index = "+index);4756if (ac == null) {4757return null;4758}4759_visibleChild = null;4760_currentVisibleIndex = 0;4761_foundVisibleChild = false;4762_getVisibleChild(ac, index);47634764if (_visibleChild != null) {4765debugString( "[INFO]: getVisibleChild: found child = " +4766InvocationUtils.invokeAndWait(new Callable<String>() {4767@Override4768public String call() throws Exception {4769return AccessBridge.this._visibleChild.getAccessibleName();4770}4771}, ac) );4772}4773return _visibleChild;4774}47754776/*4777* Recursively searchs AccessibleContext and finds the visible component4778* at the specified index4779*/4780private void _getVisibleChild(final AccessibleContext ac, final int index) {4781if (_visibleChild != null) {4782return;4783}4784if(ac instanceof AccessibleExtendedTable) {4785_getVisibleChild((AccessibleExtendedTable)ac, index);4786return;4787}4788int numChildren = InvocationUtils.invokeAndWait(new Callable<Integer>() {4789@Override4790public Integer call() throws Exception {4791return ac.getAccessibleChildrenCount();4792}4793}, ac);4794for (int i = 0; i < numChildren; i++) {4795final int idx=i;4796final AccessibleContext ac2 = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {4797@Override4798public AccessibleContext call() throws Exception {4799Accessible a = ac.getAccessibleChild(idx);4800if (a == null)4801return null;4802else4803return a.getAccessibleContext();4804}4805}, ac);4806if (ac2 == null ||4807(!InvocationUtils.invokeAndWait(new Callable<Boolean>() {4808@Override4809public Boolean call() throws Exception {4810return ac2.getAccessibleStateSet().contains(AccessibleState.SHOWING);4811}4812}, ac))) {4813continue;4814}4815if (!_foundVisibleChild && _currentVisibleIndex == index) {4816_visibleChild = ac2;4817_foundVisibleChild = true;4818return;4819}4820_currentVisibleIndex++;48214822if ( InvocationUtils.invokeAndWait(new Callable<Integer>() {4823@Override4824public Integer call() throws Exception {4825return ac2.getAccessibleChildrenCount();4826}4827}, ac) > 0 ) {4828_getVisibleChild(ac2, index);4829}4830}4831}48324833private void _getVisibleChild(final AccessibleExtendedTable acTable, final int index) {4834if (_visibleChild != null) {4835return;4836}4837int lastVisibleRow = -1;4838int lastVisibleColumn = -1;4839boolean foundVisible = false;4840int rowCount = InvocationUtils.invokeAndWait(new Callable<Integer>() {4841@Override4842public Integer call() throws Exception {4843return acTable.getAccessibleRowCount();4844}4845}, acTable);4846int columnCount = InvocationUtils.invokeAndWait(new Callable<Integer>() {4847@Override4848public Integer call() throws Exception {4849return acTable.getAccessibleColumnCount();4850}4851}, acTable);4852for (int rowIdx = 0; rowIdx < rowCount; rowIdx++) {4853for (int columnIdx = 0; columnIdx < columnCount; columnIdx++) {4854if (lastVisibleRow != -1 && rowIdx > lastVisibleRow) {4855continue;4856}4857if (lastVisibleColumn != -1 && columnIdx > lastVisibleColumn) {4858continue;4859}4860int finalRowIdx = rowIdx;4861int finalColumnIdx = columnIdx;4862final AccessibleContext ac2 = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {4863@Override4864public AccessibleContext call() throws Exception {4865Accessible a = acTable.getAccessibleAt(finalRowIdx, finalColumnIdx);4866if (a == null)4867return null;4868else4869return a.getAccessibleContext();4870}4871}, acTable);4872if (ac2 == null ||4873(!InvocationUtils.invokeAndWait(new Callable<Boolean>() {4874@Override4875public Boolean call() throws Exception {4876return ac2.getAccessibleStateSet().contains(AccessibleState.SHOWING);4877}4878}, acTable))) {4879if (foundVisible) {4880if (columnIdx != 0 && lastVisibleColumn == -1) {4881//the same row, so we found the last visible column4882lastVisibleColumn = columnIdx - 1;4883} else if (columnIdx == 0 && lastVisibleRow == -1) {4884lastVisibleRow = rowIdx - 1;4885}4886}4887continue;4888}4889foundVisible = true;48904891if (!_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}, acTable) > 0) {4904_getVisibleChild(ac2, index);4905}4906}4907}4908}49094910/* ===== Java object memory management code ===== */49114912/**4913* Class to track object references to ensure the4914* Java VM doesn't garbage collect them4915*/4916private class ObjectReferences {49174918private class Reference {4919private int value;49204921Reference(int i) {4922value = i;4923}49244925public String toString() {4926return ("refCount: " + value);4927}4928}49294930/**4931* table object references, to keep 'em from being garbage collected4932*/4933private ConcurrentHashMap<Object,Reference> refs;49344935/**4936* Constructor4937*/4938ObjectReferences() {4939refs = new ConcurrentHashMap<>(4);4940}49414942/**4943* Debugging: dump the contents of ObjectReferences' refs Hashtable4944*/4945String dump() {4946return refs.toString();4947}49484949/**4950* Increment ref count; set to 1 if we have no references for it4951*/4952void increment(Object o) {4953if (o == null){4954debugString("[WARN]: ObjectReferences::increment - Passed in object is null");4955return;4956}49574958if (refs.containsKey(o)) {4959(refs.get(o)).value++;4960} else {4961refs.put(o, new Reference(1));4962}4963}49644965/**4966* Decrement ref count; remove if count drops to 04967*/4968void decrement(Object o) {4969Reference aRef = refs.get(o);4970if (aRef != null) {4971aRef.value--;4972if (aRef.value == 0) {4973refs.remove(o);4974} else if (aRef.value < 0) {4975debugString("[ERROR]: decrementing reference count below 0");4976}4977} else {4978debugString("[ERROR]: object to decrement not in ObjectReferences table");4979}4980}49814982}49834984/* ===== event handling code ===== */49854986/**4987* native method for handling property change events4988*/4989private native void propertyCaretChange(PropertyChangeEvent e,4990AccessibleContext src,4991int oldValue, int newValue);4992private native void propertyDescriptionChange(PropertyChangeEvent e,4993AccessibleContext src,4994String oldValue, String newValue);4995private native void propertyNameChange(PropertyChangeEvent e,4996AccessibleContext src,4997String oldValue, String newValue);4998private native void propertySelectionChange(PropertyChangeEvent e,4999AccessibleContext src);5000private native void propertyStateChange(PropertyChangeEvent e,5001AccessibleContext src,5002String oldValue, String newValue);5003private native void propertyTextChange(PropertyChangeEvent e,5004AccessibleContext src);5005private native void propertyValueChange(PropertyChangeEvent e,5006AccessibleContext src,5007String oldValue, String newValue);5008private native void propertyVisibleDataChange(PropertyChangeEvent e,5009AccessibleContext src);5010private native void propertyChildChange(PropertyChangeEvent e,5011AccessibleContext src,5012AccessibleContext oldValue,5013AccessibleContext newValue);5014private native void propertyActiveDescendentChange(PropertyChangeEvent e,5015AccessibleContext src,5016AccessibleContext oldValue,5017AccessibleContext newValue);50185019private native void javaShutdown();50205021/**5022* native methods for handling focus events5023*/5024private native void focusGained(FocusEvent e, AccessibleContext src);5025private native void focusLost(FocusEvent e, AccessibleContext src);50265027/**5028* native method for handling caret events5029*/5030private native void caretUpdate(CaretEvent e, AccessibleContext src);50315032/**5033* native methods for handling mouse events5034*/5035private native void mouseClicked(MouseEvent e, AccessibleContext src);5036private native void mouseEntered(MouseEvent e, AccessibleContext src);5037private native void mouseExited(MouseEvent e, AccessibleContext src);5038private native void mousePressed(MouseEvent e, AccessibleContext src);5039private native void mouseReleased(MouseEvent e, AccessibleContext src);50405041/**5042* native methods for handling menu & popupMenu events5043*/5044private native void menuCanceled(MenuEvent e, AccessibleContext src);5045private native void menuDeselected(MenuEvent e, AccessibleContext src);5046private native void menuSelected(MenuEvent e, AccessibleContext src);5047private native void popupMenuCanceled(PopupMenuEvent e, AccessibleContext src);5048private native void popupMenuWillBecomeInvisible(PopupMenuEvent e,5049AccessibleContext src);5050private native void popupMenuWillBecomeVisible(PopupMenuEvent e,5051AccessibleContext src);50525053/* ===== event definitions ===== */50545055private static final long PROPERTY_CHANGE_EVENTS = 1;5056private static final long FOCUS_GAINED_EVENTS = 2;5057private static final long FOCUS_LOST_EVENTS = 4;5058private static final long FOCUS_EVENTS = (FOCUS_GAINED_EVENTS | FOCUS_LOST_EVENTS);50595060private static final long CARET_UPATE_EVENTS = 8;5061private static final long CARET_EVENTS = CARET_UPATE_EVENTS;50625063private static final long MOUSE_CLICKED_EVENTS = 16;5064private static final long MOUSE_ENTERED_EVENTS = 32;5065private static final long MOUSE_EXITED_EVENTS = 64;5066private static final long MOUSE_PRESSED_EVENTS = 128;5067private static final long MOUSE_RELEASED_EVENTS = 256;5068private static final long MOUSE_EVENTS = (MOUSE_CLICKED_EVENTS | MOUSE_ENTERED_EVENTS |5069MOUSE_EXITED_EVENTS | MOUSE_PRESSED_EVENTS |5070MOUSE_RELEASED_EVENTS);50715072private static final long MENU_CANCELED_EVENTS = 512;5073private static final long MENU_DESELECTED_EVENTS = 1024;5074private static final long MENU_SELECTED_EVENTS = 2048;5075private static final long MENU_EVENTS = (MENU_CANCELED_EVENTS | MENU_DESELECTED_EVENTS |5076MENU_SELECTED_EVENTS);50775078private static final long POPUPMENU_CANCELED_EVENTS = 4096;5079private static final long POPUPMENU_WILL_BECOME_INVISIBLE_EVENTS = 8192;5080private static final long POPUPMENU_WILL_BECOME_VISIBLE_EVENTS = 16384;5081private static final long POPUPMENU_EVENTS = (POPUPMENU_CANCELED_EVENTS |5082POPUPMENU_WILL_BECOME_INVISIBLE_EVENTS |5083POPUPMENU_WILL_BECOME_VISIBLE_EVENTS);50845085/* These use their own numbering scheme, to ensure sufficient expansion room */5086private static final long PROPERTY_NAME_CHANGE_EVENTS = 1;5087private static final long PROPERTY_DESCRIPTION_CHANGE_EVENTS = 2;5088private static final long PROPERTY_STATE_CHANGE_EVENTS = 4;5089private static final long PROPERTY_VALUE_CHANGE_EVENTS = 8;5090private static final long PROPERTY_SELECTION_CHANGE_EVENTS = 16;5091private static final long PROPERTY_TEXT_CHANGE_EVENTS = 32;5092private static final long PROPERTY_CARET_CHANGE_EVENTS = 64;5093private static final long PROPERTY_VISIBLEDATA_CHANGE_EVENTS = 128;5094private static final long PROPERTY_CHILD_CHANGE_EVENTS = 256;5095private static final long PROPERTY_ACTIVEDESCENDENT_CHANGE_EVENTS = 512;509650975098private static final long PROPERTY_EVENTS = (PROPERTY_NAME_CHANGE_EVENTS |5099PROPERTY_DESCRIPTION_CHANGE_EVENTS |5100PROPERTY_STATE_CHANGE_EVENTS |5101PROPERTY_VALUE_CHANGE_EVENTS |5102PROPERTY_SELECTION_CHANGE_EVENTS |5103PROPERTY_TEXT_CHANGE_EVENTS |5104PROPERTY_CARET_CHANGE_EVENTS |5105PROPERTY_VISIBLEDATA_CHANGE_EVENTS |5106PROPERTY_CHILD_CHANGE_EVENTS |5107PROPERTY_ACTIVEDESCENDENT_CHANGE_EVENTS);51085109/**5110* The EventHandler class listens for Java events and5111* forwards them to the AT5112*/5113private class EventHandler implements PropertyChangeListener,5114FocusListener, CaretListener,5115MenuListener, PopupMenuListener,5116MouseListener, WindowListener,5117ChangeListener {51185119private AccessBridge accessBridge;5120private long javaEventMask = 0;5121private long accessibilityEventMask = 0;51225123EventHandler(AccessBridge bridge) {5124accessBridge = bridge;51255126// Register to receive WINDOW_OPENED and WINDOW_CLOSED5127// events. Add the event source as a native window5128// handler is it implements NativeWindowHandler.5129// SwingEventMonitor.addWindowListener(this);5130}51315132// --------- Event Notification Registration methods51335134/**5135* Invoked the first time a window is made visible.5136*/5137public void windowOpened(WindowEvent e) {5138// If the window is a NativeWindowHandler, add it.5139Object o = null;5140if (e != null)5141o = e.getSource();5142if (o instanceof NativeWindowHandler) {5143addNativeWindowHandler((NativeWindowHandler)o);5144}5145}51465147/**5148* Invoked when the user attempts to close the window5149* from the window's system menu. If the program does not5150* explicitly hide or dispose the window while processing5151* this event, the window close operation will be canceled.5152*/5153public void windowClosing(WindowEvent e) {}51545155/**5156* Invoked when a window has been closed as the result5157* of calling dispose on the window.5158*/5159public void windowClosed(WindowEvent e) {5160// If the window is a NativeWindowHandler, remove it.5161Object o = null;5162if (e != null)5163o = e.getSource();5164if (o instanceof NativeWindowHandler) {5165removeNativeWindowHandler((NativeWindowHandler)o);5166}5167}51685169/**5170* Invoked when a window is changed from a normal to a5171* minimized state. For many platforms, a minimized window5172* is displayed as the icon specified in the window's5173* iconImage property.5174* @see java.awt.Frame#setIconImage5175*/5176public void windowIconified(WindowEvent e) {}51775178/**5179* Invoked when a window is changed from a minimized5180* to a normal state.5181*/5182public void windowDeiconified(WindowEvent e) {}51835184/**5185* Invoked when the Window is set to be the active Window. Only a Frame or5186* a Dialog can be the active Window. The native windowing system may5187* denote the active Window or its children with special decorations, such5188* as a highlighted title bar. The active Window is always either the5189* focused Window, or the first Frame or Dialog that is an owner of the5190* focused Window.5191*/5192public void windowActivated(WindowEvent e) {}51935194/**5195* Invoked when a Window is no longer the active Window. Only a Frame or a5196* Dialog can be the active Window. The native windowing system may denote5197* the active Window or its children with special decorations, such as a5198* highlighted title bar. The active Window is always either the focused5199* Window, or the first Frame or Dialog that is an owner of the focused5200* Window.5201*/5202public void windowDeactivated(WindowEvent e) {}52035204/**5205* Turn on event monitoring for the event type passed in5206* If necessary, add the appropriate event listener (if5207* no other event of that type is being listened for)5208*/5209void addJavaEventNotification(long type) {5210long newEventMask = javaEventMask | type;5211/*5212if ( ((javaEventMask & PROPERTY_EVENTS) == 0) &&5213((newEventMask & PROPERTY_EVENTS) != 0) ) {5214AccessibilityEventMonitor.addPropertyChangeListener(this);5215}5216*/5217if ( ((javaEventMask & FOCUS_EVENTS) == 0) &&5218((newEventMask & FOCUS_EVENTS) != 0) ) {5219SwingEventMonitor.addFocusListener(this);5220}5221if ( ((javaEventMask & CARET_EVENTS) == 0) &&5222((newEventMask & CARET_EVENTS) != 0) ) {5223SwingEventMonitor.addCaretListener(this);5224}5225if ( ((javaEventMask & MOUSE_EVENTS) == 0) &&5226((newEventMask & MOUSE_EVENTS) != 0) ) {5227SwingEventMonitor.addMouseListener(this);5228}5229if ( ((javaEventMask & MENU_EVENTS) == 0) &&5230((newEventMask & MENU_EVENTS) != 0) ) {5231SwingEventMonitor.addMenuListener(this);5232SwingEventMonitor.addPopupMenuListener(this);5233}5234if ( ((javaEventMask & POPUPMENU_EVENTS) == 0) &&5235((newEventMask & POPUPMENU_EVENTS) != 0) ) {5236SwingEventMonitor.addPopupMenuListener(this);5237}52385239javaEventMask = newEventMask;5240}52415242/**5243* Turn off event monitoring for the event type passed in5244* If necessary, remove the appropriate event listener (if5245* no other event of that type is being listened for)5246*/5247void removeJavaEventNotification(long type) {5248long newEventMask = javaEventMask & (~type);5249/*5250if ( ((javaEventMask & PROPERTY_EVENTS) != 0) &&5251((newEventMask & PROPERTY_EVENTS) == 0) ) {5252AccessibilityEventMonitor.removePropertyChangeListener(this);5253}5254*/5255if (((javaEventMask & FOCUS_EVENTS) != 0) &&5256((newEventMask & FOCUS_EVENTS) == 0)) {5257SwingEventMonitor.removeFocusListener(this);5258}5259if (((javaEventMask & CARET_EVENTS) != 0) &&5260((newEventMask & CARET_EVENTS) == 0)) {5261SwingEventMonitor.removeCaretListener(this);5262}5263if (((javaEventMask & MOUSE_EVENTS) == 0) &&5264((newEventMask & MOUSE_EVENTS) != 0)) {5265SwingEventMonitor.removeMouseListener(this);5266}5267if (((javaEventMask & MENU_EVENTS) == 0) &&5268((newEventMask & MENU_EVENTS) != 0)) {5269SwingEventMonitor.removeMenuListener(this);5270}5271if (((javaEventMask & POPUPMENU_EVENTS) == 0) &&5272((newEventMask & POPUPMENU_EVENTS) != 0)) {5273SwingEventMonitor.removePopupMenuListener(this);5274}52755276javaEventMask = newEventMask;5277}52785279/**5280* Turn on event monitoring for the event type passed in5281* If necessary, add the appropriate event listener (if5282* no other event of that type is being listened for)5283*/5284void addAccessibilityEventNotification(long type) {5285long newEventMask = accessibilityEventMask | type;5286if ( ((accessibilityEventMask & PROPERTY_EVENTS) == 0) &&5287((newEventMask & PROPERTY_EVENTS) != 0) ) {5288AccessibilityEventMonitor.addPropertyChangeListener(this);5289}5290accessibilityEventMask = newEventMask;5291}52925293/**5294* Turn off event monitoring for the event type passed in5295* If necessary, remove the appropriate event listener (if5296* no other event of that type is being listened for)5297*/5298void removeAccessibilityEventNotification(long type) {5299long newEventMask = accessibilityEventMask & (~type);5300if ( ((accessibilityEventMask & PROPERTY_EVENTS) != 0) &&5301((newEventMask & PROPERTY_EVENTS) == 0) ) {5302AccessibilityEventMonitor.removePropertyChangeListener(this);5303}5304accessibilityEventMask = newEventMask;5305}53065307/**5308* ------- property change event glue5309*/5310// This is invoked on the EDT , as5311public void propertyChange(PropertyChangeEvent e) {53125313accessBridge.debugString("[INFO]: propertyChange(" + e.toString() + ") called");53145315if (e != null && (accessibilityEventMask & PROPERTY_EVENTS) != 0) {5316Object o = e.getSource();5317AccessibleContext ac;53185319if (o instanceof AccessibleContext) {5320ac = (AccessibleContext) o;5321} else {5322Accessible a = Translator.getAccessible(e.getSource());5323if (a == null)5324return;5325else5326ac = a.getAccessibleContext();5327}5328if (ac != null) {5329InvocationUtils.registerAccessibleContext(ac, AppContext.getAppContext());53305331accessBridge.debugString("[INFO]: AccessibleContext: " + ac);5332String propertyName = e.getPropertyName();53335334if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_CARET_PROPERTY) == 0) {5335int oldValue = 0;5336int newValue = 0;53375338if (e.getOldValue() instanceof Integer) {5339oldValue = ((Integer) e.getOldValue()).intValue();5340}5341if (e.getNewValue() instanceof Integer) {5342newValue = ((Integer) e.getNewValue()).intValue();5343}5344accessBridge.debugString("[INFO]: - about to call propertyCaretChange() old value: " + oldValue + "new value: " + newValue);5345accessBridge.propertyCaretChange(e, ac, oldValue, newValue);53465347} else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_DESCRIPTION_PROPERTY) == 0) {5348String oldValue = null;5349String newValue = null;53505351if (e.getOldValue() != null) {5352oldValue = e.getOldValue().toString();5353}5354if (e.getNewValue() != null) {5355newValue = e.getNewValue().toString();5356}5357accessBridge.debugString("[INFO]: - about to call propertyDescriptionChange() old value: " + oldValue + "new value: " + newValue);5358accessBridge.propertyDescriptionChange(e, ac, oldValue, newValue);53595360} else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_NAME_PROPERTY) == 0) {5361String oldValue = null;5362String newValue = null;53635364if (e.getOldValue() != null) {5365oldValue = e.getOldValue().toString();5366}5367if (e.getNewValue() != null) {5368newValue = e.getNewValue().toString();5369}5370accessBridge.debugString("[INFO]: - about to call propertyNameChange() old value: " + oldValue + " new value: " + newValue);5371accessBridge.propertyNameChange(e, ac, oldValue, newValue);53725373} else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY) == 0) {5374accessBridge.debugString("[INFO]: - about to call propertySelectionChange() " + ac + " " + Thread.currentThread() + " " + e.getSource());53755376accessBridge.propertySelectionChange(e, ac);53775378} else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_STATE_PROPERTY) == 0) {5379String oldValue = null;5380String newValue = null;53815382// Localization fix requested by Oliver for EA-15383if (e.getOldValue() != null) {5384AccessibleState oldState = (AccessibleState) e.getOldValue();5385oldValue = oldState.toDisplayString(Locale.US);5386}5387if (e.getNewValue() != null) {5388AccessibleState newState = (AccessibleState) e.getNewValue();5389newValue = newState.toDisplayString(Locale.US);5390}53915392accessBridge.debugString("[INFO]: - about to call propertyStateChange()");5393accessBridge.propertyStateChange(e, ac, oldValue, newValue);53945395} else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_TEXT_PROPERTY) == 0) {5396accessBridge.debugString("[INFO]: - about to call propertyTextChange()");5397accessBridge.propertyTextChange(e, ac);53985399} else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_VALUE_PROPERTY) == 0) { // strings 'cause of floating point, etc.5400String oldValue = null;5401String newValue = null;54025403if (e.getOldValue() != null) {5404oldValue = e.getOldValue().toString();5405}5406if (e.getNewValue() != null) {5407newValue = e.getNewValue().toString();5408}5409accessBridge.debugString("[INFO]: - about to call propertyDescriptionChange()");5410accessBridge.propertyValueChange(e, ac, oldValue, newValue);54115412} else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY) == 0) {5413accessBridge.propertyVisibleDataChange(e, ac);54145415} else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_CHILD_PROPERTY) == 0) {5416AccessibleContext oldAC = null;5417AccessibleContext newAC = null;5418Accessible a;54195420if (e.getOldValue() instanceof AccessibleContext) {5421oldAC = (AccessibleContext) e.getOldValue();5422InvocationUtils.registerAccessibleContext(oldAC, AppContext.getAppContext());5423}5424if (e.getNewValue() instanceof AccessibleContext) {5425newAC = (AccessibleContext) e.getNewValue();5426InvocationUtils.registerAccessibleContext(newAC, AppContext.getAppContext());5427}5428accessBridge.debugString("[INFO]: - about to call propertyChildChange() old AC: " + oldAC + "new AC: " + newAC);5429accessBridge.propertyChildChange(e, ac, oldAC, newAC);54305431} else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY) == 0) {5432handleActiveDescendentEvent(e, ac);5433}5434}5435}5436}54375438/*5439* Handle an ActiveDescendent PropertyChangeEvent. This5440* method works around a JTree bug where ActiveDescendent5441* PropertyChangeEvents have the wrong parent.5442*/5443private AccessibleContext prevAC = null; // previous AccessibleContext54445445private void handleActiveDescendentEvent(PropertyChangeEvent e,5446AccessibleContext ac) {5447if (e == null || ac == null)5448return;5449AccessibleContext oldAC = null;5450AccessibleContext newAC = null;5451Accessible a;54525453// get the old active descendent5454if (e.getOldValue() instanceof Accessible) {5455oldAC = ((Accessible) e.getOldValue()).getAccessibleContext();5456} else if (e.getOldValue() instanceof Component) {5457a = Translator.getAccessible(e.getOldValue());5458if (a != null) {5459oldAC = a.getAccessibleContext();5460}5461}5462if (oldAC != null) {5463Accessible parent = oldAC.getAccessibleParent();5464if (parent instanceof JTree) {5465// use the previous AccessibleJTreeNode5466oldAC = prevAC;5467}5468}54695470// get the new active descendent5471if (e.getNewValue() instanceof Accessible) {5472newAC = ((Accessible) e.getNewValue()).getAccessibleContext();5473} else if (e.getNewValue() instanceof Component) {5474a = Translator.getAccessible(e.getNewValue());5475if (a != null) {5476newAC = a.getAccessibleContext();5477}5478}5479if (newAC != null) {5480Accessible parent = newAC.getAccessibleParent();5481if (parent instanceof JTree) {5482// use a new AccessibleJTreeNode with the right parent5483JTree tree = (JTree)parent;5484newAC = new AccessibleJTreeNode(tree,5485tree.getSelectionPath(),5486null);5487}5488}5489prevAC = newAC;54905491accessBridge.debugString("[INFO]: - about to call propertyActiveDescendentChange() AC: " + ac + " old AC: " + oldAC + "new AC: " + newAC);5492InvocationUtils.registerAccessibleContext(oldAC, AppContext.getAppContext());5493InvocationUtils.registerAccessibleContext(newAC, AppContext.getAppContext());5494accessBridge.propertyActiveDescendentChange(e, ac, oldAC, newAC);5495}54965497/**5498* ------- focus event glue5499*/5500private boolean stateChangeListenerAdded = false;55015502public void focusGained(FocusEvent e) {5503if (runningOnJDK1_4) {5504processFocusGained();5505} else {5506if ((javaEventMask & FOCUS_GAINED_EVENTS) != 0) {5507Accessible a = Translator.getAccessible(e.getSource());5508if (a != null) {5509AccessibleContext context = a.getAccessibleContext();5510InvocationUtils.registerAccessibleContext(context, SunToolkit.targetToAppContext(e.getSource()));5511accessBridge.focusGained(e, context);5512}5513}5514}5515}55165517public void stateChanged(ChangeEvent e) {5518processFocusGained();5519}55205521private void processFocusGained() {5522Component focusOwner = KeyboardFocusManager.5523getCurrentKeyboardFocusManager().getFocusOwner();5524if (focusOwner == null) {5525return;5526}55275528// Only menus and popup selections are handled by the JRootPane.5529if (focusOwner instanceof JRootPane) {5530MenuElement [] path =5531MenuSelectionManager.defaultManager().getSelectedPath();5532if (path.length > 1) {5533Component penult = path[path.length-2].getComponent();5534Component last = path[path.length-1].getComponent();55355536if (last instanceof JPopupMenu) {5537// This is a popup with nothing in the popup5538// selected. The menu itself is selected.5539FocusEvent e = new FocusEvent(penult, FocusEvent.FOCUS_GAINED);5540AccessibleContext context = penult.getAccessibleContext();5541InvocationUtils.registerAccessibleContext(context, SunToolkit.targetToAppContext(penult));5542accessBridge.focusGained(e, context);5543} else if (penult instanceof JPopupMenu) {5544// This is a popup with an item selected5545FocusEvent e =5546new FocusEvent(last, FocusEvent.FOCUS_GAINED);5547AccessibleContext focusedAC = last.getAccessibleContext();5548InvocationUtils.registerAccessibleContext(focusedAC, SunToolkit.targetToAppContext(last));5549accessBridge.debugString("[INFO]: - about to call focusGained() AC: " + focusedAC);5550accessBridge.focusGained(e, focusedAC);5551}5552}5553} else {5554// The focus owner has the selection.5555if (focusOwner instanceof Accessible) {5556FocusEvent e = new FocusEvent(focusOwner,5557FocusEvent.FOCUS_GAINED);5558AccessibleContext focusedAC = focusOwner.getAccessibleContext();5559InvocationUtils.registerAccessibleContext(focusedAC, SunToolkit.targetToAppContext(focusOwner));5560accessBridge.debugString("[INFO]: - about to call focusGained() AC: " + focusedAC);5561accessBridge.focusGained(e, focusedAC);5562}5563}5564}55655566public void focusLost(FocusEvent e) {5567if (e != null && (javaEventMask & FOCUS_LOST_EVENTS) != 0) {5568Accessible a = Translator.getAccessible(e.getSource());5569if (a != null) {5570accessBridge.debugString("[INFO]: - about to call focusLost() AC: " + a.getAccessibleContext());5571AccessibleContext context = a.getAccessibleContext();5572InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5573accessBridge.focusLost(e, context);5574}5575}5576}55775578/**5579* ------- caret event glue5580*/5581public void caretUpdate(CaretEvent e) {5582if (e != null && (javaEventMask & CARET_UPATE_EVENTS) != 0) {5583Accessible a = Translator.getAccessible(e.getSource());5584if (a != null) {5585AccessibleContext context = a.getAccessibleContext();5586InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5587accessBridge.caretUpdate(e, context);5588}5589}5590}55915592/**5593* ------- mouse event glue5594*/55955596public void mouseClicked(MouseEvent e) {5597if (e != null && (javaEventMask & MOUSE_CLICKED_EVENTS) != 0) {5598Accessible a = Translator.getAccessible(e.getSource());5599if (a != null) {5600AccessibleContext context = a.getAccessibleContext();5601InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5602accessBridge.mouseClicked(e, context);5603}5604}5605}56065607public void mouseEntered(MouseEvent e) {5608if (e != null && (javaEventMask & MOUSE_ENTERED_EVENTS) != 0) {5609Accessible a = Translator.getAccessible(e.getSource());5610if (a != null) {5611AccessibleContext context = a.getAccessibleContext();5612InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5613accessBridge.mouseEntered(e, context);5614}5615}5616}56175618public void mouseExited(MouseEvent e) {5619if (e != null && (javaEventMask & MOUSE_EXITED_EVENTS) != 0) {5620Accessible a = Translator.getAccessible(e.getSource());5621if (a != null) {5622AccessibleContext context = a.getAccessibleContext();5623InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5624accessBridge.mouseExited(e, context);5625}5626}5627}56285629public void mousePressed(MouseEvent e) {5630if (e != null && (javaEventMask & MOUSE_PRESSED_EVENTS) != 0) {5631Accessible a = Translator.getAccessible(e.getSource());5632if (a != null) {5633AccessibleContext context = a.getAccessibleContext();5634InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5635accessBridge.mousePressed(e, context);5636}5637}5638}56395640public void mouseReleased(MouseEvent e) {5641if (e != null && (javaEventMask & MOUSE_RELEASED_EVENTS) != 0) {5642Accessible a = Translator.getAccessible(e.getSource());5643if (a != null) {5644AccessibleContext context = a.getAccessibleContext();5645InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5646accessBridge.mouseReleased(e, context);5647}5648}5649}56505651/**5652* ------- menu event glue5653*/5654public void menuCanceled(MenuEvent e) {5655if (e != null && (javaEventMask & MENU_CANCELED_EVENTS) != 0) {5656Accessible a = Translator.getAccessible(e.getSource());5657if (a != null) {5658AccessibleContext context = a.getAccessibleContext();5659InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5660accessBridge.menuCanceled(e, context);5661}5662}5663}56645665public void menuDeselected(MenuEvent e) {5666if (e != null && (javaEventMask & MENU_DESELECTED_EVENTS) != 0) {5667Accessible a = Translator.getAccessible(e.getSource());5668if (a != null) {5669AccessibleContext context = a.getAccessibleContext();5670InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5671accessBridge.menuDeselected(e, context);5672}5673}5674}56755676public void menuSelected(MenuEvent e) {5677if (e != null && (javaEventMask & MENU_SELECTED_EVENTS) != 0) {5678Accessible a = Translator.getAccessible(e.getSource());5679if (a != null) {5680AccessibleContext context = a.getAccessibleContext();5681InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5682accessBridge.menuSelected(e, context);5683}5684}5685}56865687public void popupMenuCanceled(PopupMenuEvent e) {5688if (e != null && (javaEventMask & POPUPMENU_CANCELED_EVENTS) != 0) {5689Accessible a = Translator.getAccessible(e.getSource());5690if (a != null) {5691AccessibleContext context = a.getAccessibleContext();5692InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5693accessBridge.popupMenuCanceled(e, context);5694}5695}5696}56975698public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {5699if (e != null && (javaEventMask & POPUPMENU_WILL_BECOME_INVISIBLE_EVENTS) != 0) {5700Accessible a = Translator.getAccessible(e.getSource());5701if (a != null) {5702AccessibleContext context = a.getAccessibleContext();5703InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5704accessBridge.popupMenuWillBecomeInvisible(e, context);5705}5706}5707}57085709public void popupMenuWillBecomeVisible(PopupMenuEvent e) {5710if (e != null && (javaEventMask & POPUPMENU_WILL_BECOME_VISIBLE_EVENTS) != 0) {5711Accessible a = Translator.getAccessible(e.getSource());5712if (a != null) {5713AccessibleContext context = a.getAccessibleContext();5714InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5715accessBridge.popupMenuWillBecomeVisible(e, context);5716}5717}5718}57195720} // End of EventHandler Class57215722// --------- Event Notification Registration methods57235724/**5725* Wrapper method around eventHandler.addJavaEventNotification()5726*/5727private void addJavaEventNotification(final long type) {5728EventQueue.invokeLater(new Runnable() {5729public void run(){5730eventHandler.addJavaEventNotification(type);5731}5732});5733}57345735/**5736* Wrapper method around eventHandler.removeJavaEventNotification()5737*/5738private void removeJavaEventNotification(final long type) {5739EventQueue.invokeLater(new Runnable() {5740public void run(){5741eventHandler.removeJavaEventNotification(type);5742}5743});5744}574557465747/**5748* Wrapper method around eventHandler.addAccessibilityEventNotification()5749*/5750private void addAccessibilityEventNotification(final long type) {5751EventQueue.invokeLater(new Runnable() {5752public void run(){5753eventHandler.addAccessibilityEventNotification(type);5754}5755});5756}57575758/**5759* Wrapper method around eventHandler.removeAccessibilityEventNotification()5760*/5761private void removeAccessibilityEventNotification(final long type) {5762EventQueue.invokeLater(new Runnable() {5763public void run(){5764eventHandler.removeAccessibilityEventNotification(type);5765}5766});5767}57685769/**5770******************************************************5771* All AccessibleRoles5772*5773* We shouldn't have to do this since it requires us5774* to synchronize the allAccessibleRoles array when5775* the AccessibleRoles class interface changes. However,5776* there is no Accessibility API method to get all5777* AccessibleRoles5778******************************************************5779*/5780private AccessibleRole [] allAccessibleRoles = {5781/**5782* Object is used to alert the user about something.5783*/5784AccessibleRole.ALERT,57855786/**5787* The header for a column of data.5788*/5789AccessibleRole.COLUMN_HEADER,57905791/**5792* Object that can be drawn into and is used to trap5793* events.5794* @see #FRAME5795* @see #GLASS_PANE5796* @see #LAYERED_PANE5797*/5798AccessibleRole.CANVAS,57995800/**5801* A list of choices the user can select from. Also optionally5802* allows the user to enter a choice of their own.5803*/5804AccessibleRole.COMBO_BOX,58055806/**5807* An iconified internal frame in a DESKTOP_PANE.5808* @see #DESKTOP_PANE5809* @see #INTERNAL_FRAME5810*/5811AccessibleRole.DESKTOP_ICON,58125813/**5814* A frame-like object that is clipped by a desktop pane. The5815* desktop pane, internal frame, and desktop icon objects are5816* often used to create multiple document interfaces within an5817* application.5818* @see #DESKTOP_ICON5819* @see #DESKTOP_PANE5820* @see #FRAME5821*/5822AccessibleRole.INTERNAL_FRAME,58235824/**5825* A pane that supports internal frames and5826* iconified versions of those internal frames.5827* @see #DESKTOP_ICON5828* @see #INTERNAL_FRAME5829*/5830AccessibleRole.DESKTOP_PANE,58315832/**5833* A specialized pane whose primary use is inside a DIALOG5834* @see #DIALOG5835*/5836AccessibleRole.OPTION_PANE,58375838/**5839* A top level window with no title or border.5840* @see #FRAME5841* @see #DIALOG5842*/5843AccessibleRole.WINDOW,58445845/**5846* A top level window with a title bar, border, menu bar, etc. It is5847* often used as the primary window for an application.5848* @see #DIALOG5849* @see #CANVAS5850* @see #WINDOW5851*/5852AccessibleRole.FRAME,58535854/**5855* A top level window with title bar and a border. A dialog is similar5856* to a frame, but it has fewer properties and is often used as a5857* secondary window for an application.5858* @see #FRAME5859* @see #WINDOW5860*/5861AccessibleRole.DIALOG,58625863/**5864* A specialized dialog that lets the user choose a color.5865*/5866AccessibleRole.COLOR_CHOOSER,586758685869/**5870* A pane that allows the user to navigate through5871* and select the contents of a directory. May be used5872* by a file chooser.5873* @see #FILE_CHOOSER5874*/5875AccessibleRole.DIRECTORY_PANE,58765877/**5878* A specialized dialog that displays the files in the directory5879* and lets the user select a file, browse a different directory,5880* or specify a filename. May use the directory pane to show the5881* contents of a directory.5882* @see #DIRECTORY_PANE5883*/5884AccessibleRole.FILE_CHOOSER,58855886/**5887* An object that fills up space in a user interface. It is often5888* used in interfaces to tweak the spacing between components,5889* but serves no other purpose.5890*/5891AccessibleRole.FILLER,58925893/**5894* A hypertext anchor5895*/5896// AccessibleRole.HYPERLINK,58975898/**5899* A small fixed size picture, typically used to decorate components.5900*/5901AccessibleRole.ICON,59025903/**5904* An object used to present an icon or short string in an interface.5905*/5906AccessibleRole.LABEL,59075908/**5909* A specialized pane that has a glass pane and a layered pane as its5910* children.5911* @see #GLASS_PANE5912* @see #LAYERED_PANE5913*/5914AccessibleRole.ROOT_PANE,59155916/**5917* A pane that is guaranteed to be painted on top5918* of all panes beneath it.5919* @see #ROOT_PANE5920* @see #CANVAS5921*/5922AccessibleRole.GLASS_PANE,59235924/**5925* A specialized pane that allows its children to be drawn in layers,5926* providing a form of stacking order. This is usually the pane that5927* holds the menu bar as well as the pane that contains most of the5928* visual components in a window.5929* @see #GLASS_PANE5930* @see #ROOT_PANE5931*/5932AccessibleRole.LAYERED_PANE,59335934/**5935* An object that presents a list of objects to the user and allows the5936* user to select one or more of them. A list is usually contained5937* within a scroll pane.5938* @see #SCROLL_PANE5939* @see #LIST_ITEM5940*/5941AccessibleRole.LIST,59425943/**5944* An object that presents an element in a list. A list is usually5945* contained within a scroll pane.5946* @see #SCROLL_PANE5947* @see #LIST5948*/5949AccessibleRole.LIST_ITEM,59505951/**5952* An object usually drawn at the top of the primary dialog box of5953* an application that contains a list of menus the user can choose5954* from. For example, a menu bar might contain menus for "File,"5955* "Edit," and "Help."5956* @see #MENU5957* @see #POPUP_MENU5958* @see #LAYERED_PANE5959*/5960AccessibleRole.MENU_BAR,59615962/**5963* A temporary window that is usually used to offer the user a5964* list of choices, and then hides when the user selects one of5965* those choices.5966* @see #MENU5967* @see #MENU_ITEM5968*/5969AccessibleRole.POPUP_MENU,59705971/**5972* An object usually found inside a menu bar that contains a list5973* of actions the user can choose from. A menu can have any object5974* as its children, but most often they are menu items, other menus,5975* or rudimentary objects such as radio buttons, check boxes, or5976* separators. For example, an application may have an "Edit" menu5977* that contains menu items for "Cut" and "Paste."5978* @see #MENU_BAR5979* @see #MENU_ITEM5980* @see #SEPARATOR5981* @see #RADIO_BUTTON5982* @see #CHECK_BOX5983* @see #POPUP_MENU5984*/5985AccessibleRole.MENU,59865987/**5988* An object usually contained in a menu that presents an action5989* the user can choose. For example, the "Cut" menu item in an5990* "Edit" menu would be an action the user can select to cut the5991* selected area of text in a document.5992* @see #MENU_BAR5993* @see #SEPARATOR5994* @see #POPUP_MENU5995*/5996AccessibleRole.MENU_ITEM,59975998/**5999* An object usually contained in a menu to provide a visual6000* and logical separation of the contents in a menu. For example,6001* the "File" menu of an application might contain menu items for6002* "Open," "Close," and "Exit," and will place a separator between6003* "Close" and "Exit" menu items.6004* @see #MENU6005* @see #MENU_ITEM6006*/6007AccessibleRole.SEPARATOR,60086009/**6010* An object that presents a series of panels (or page tabs), one at a6011* time, through some mechanism provided by the object. The most common6012* mechanism is a list of tabs at the top of the panel. The children of6013* a page tab list are all page tabs.6014* @see #PAGE_TAB6015*/6016AccessibleRole.PAGE_TAB_LIST,60176018/**6019* An object that is a child of a page tab list. Its sole child is6020* the panel that is to be presented to the user when the user6021* selects the page tab from the list of tabs in the page tab list.6022* @see #PAGE_TAB_LIST6023*/6024AccessibleRole.PAGE_TAB,60256026/**6027* A generic container that is often used to group objects.6028*/6029AccessibleRole.PANEL,60306031/**6032* An object used to indicate how much of a task has been completed.6033*/6034AccessibleRole.PROGRESS_BAR,60356036/**6037* A text object used for passwords, or other places where the6038* text contents is not shown visibly to the user6039*/6040AccessibleRole.PASSWORD_TEXT,60416042/**6043* An object the user can manipulate to tell the application to do6044* something.6045* @see #CHECK_BOX6046* @see #TOGGLE_BUTTON6047* @see #RADIO_BUTTON6048*/6049AccessibleRole.PUSH_BUTTON,60506051/**6052* A specialized push button that can be checked or unchecked, but6053* does not provide a separate indicator for the current state.6054* @see #PUSH_BUTTON6055* @see #CHECK_BOX6056* @see #RADIO_BUTTON6057*/6058AccessibleRole.TOGGLE_BUTTON,60596060/**6061* A choice that can be checked or unchecked and provides a6062* separate indicator for the current state.6063* @see #PUSH_BUTTON6064* @see #TOGGLE_BUTTON6065* @see #RADIO_BUTTON6066*/6067AccessibleRole.CHECK_BOX,60686069/**6070* A specialized check box that will cause other radio buttons in the6071* same group to become unchecked when this one is checked.6072* @see #PUSH_BUTTON6073* @see #TOGGLE_BUTTON6074* @see #CHECK_BOX6075*/6076AccessibleRole.RADIO_BUTTON,60776078/**6079* The header for a row of data.6080*/6081AccessibleRole.ROW_HEADER,60826083/**6084* An object that allows a user to incrementally view a large amount6085* of information. Its children can include scroll bars and a viewport.6086* @see #SCROLL_BAR6087* @see #VIEWPORT6088*/6089AccessibleRole.SCROLL_PANE,60906091/**6092* An object usually used to allow a user to incrementally view a6093* large amount of data. Usually used only by a scroll pane.6094* @see #SCROLL_PANE6095*/6096AccessibleRole.SCROLL_BAR,60976098/**6099* An object usually used in a scroll pane. It represents the portion6100* of the entire data that the user can see. As the user manipulates6101* the scroll bars, the contents of the viewport can change.6102* @see #SCROLL_PANE6103*/6104AccessibleRole.VIEWPORT,61056106/**6107* An object that allows the user to select from a bounded range. For6108* example, a slider might be used to select a number between 0 and 100.6109*/6110AccessibleRole.SLIDER,61116112/**6113* A specialized panel that presents two other panels at the same time.6114* Between the two panels is a divider the user can manipulate to make6115* one panel larger and the other panel smaller.6116*/6117AccessibleRole.SPLIT_PANE,61186119/**6120* An object used to present information in terms of rows and columns.6121* An example might include a spreadsheet application.6122*/6123AccessibleRole.TABLE,61246125/**6126* An object that presents text to the user. The text is usually6127* editable by the user as opposed to a label.6128* @see #LABEL6129*/6130AccessibleRole.TEXT,61316132/**6133* An object used to present hierarchical information to the user.6134* The individual nodes in the tree can be collapsed and expanded6135* to provide selective disclosure of the tree's contents.6136*/6137AccessibleRole.TREE,61386139/**6140* A bar or palette usually composed of push buttons or toggle buttons.6141* It is often used to provide the most frequently used functions for an6142* application.6143*/6144AccessibleRole.TOOL_BAR,61456146/**6147* An object that provides information about another object. The6148* accessibleDescription property of the tool tip is often displayed6149* to the user in a small "help bubble" when the user causes the6150* mouse to hover over the object associated with the tool tip.6151*/6152AccessibleRole.TOOL_TIP,61536154/**6155* An AWT component, but nothing else is known about it.6156* @see #SWING_COMPONENT6157* @see #UNKNOWN6158*/6159AccessibleRole.AWT_COMPONENT,61606161/**6162* A Swing component, but nothing else is known about it.6163* @see #AWT_COMPONENT6164* @see #UNKNOWN6165*/6166AccessibleRole.SWING_COMPONENT,61676168/**6169* The object contains some Accessible information, but its role is6170* not known.6171* @see #AWT_COMPONENT6172* @see #SWING_COMPONENT6173*/6174AccessibleRole.UNKNOWN,61756176// These roles are only available in JDK 1.461776178/**6179* A STATUS_BAR is an simple component that can contain6180* multiple labels of status information to the user.6181AccessibleRole.STATUS_BAR,61826183/**6184* A DATE_EDITOR is a component that allows users to edit6185* java.util.Date and java.util.Time objects6186AccessibleRole.DATE_EDITOR,61876188/**6189* A SPIN_BOX is a simple spinner component and its main use6190* is for simple numbers.6191AccessibleRole.SPIN_BOX,61926193/**6194* A FONT_CHOOSER is a component that lets the user pick various6195* attributes for fonts.6196AccessibleRole.FONT_CHOOSER,61976198/**6199* A GROUP_BOX is a simple container that contains a border6200* around it and contains components inside it.6201AccessibleRole.GROUP_BOX62026203/**6204* Since JDK 1.56205*6206* A text header62076208AccessibleRole.HEADER,62096210/**6211* A text footer62126213AccessibleRole.FOOTER,62146215/**6216* A text paragraph62176218AccessibleRole.PARAGRAPH,62196220/**6221* A ruler is an object used to measure distance62226223AccessibleRole.RULER,62246225/**6226* A role indicating the object acts as a formula for6227* calculating a value. An example is a formula in6228* a spreadsheet cell.6229AccessibleRole.EDITBAR6230*/6231};62326233/**6234* This class implements accessibility support for the6235* <code>JTree</code> child. It provides an implementation of the6236* Java Accessibility API appropriate to tree nodes.6237*6238* Copied from JTree.java to work around a JTree bug where6239* ActiveDescendent PropertyChangeEvents contain the wrong6240* parent.6241*/6242/**6243* This class in invoked on the EDT as its part of ActiveDescendant,6244* hence the calls do not need to be specifically made on the EDT6245*/6246private class AccessibleJTreeNode extends AccessibleContext6247implements Accessible, AccessibleComponent, AccessibleSelection,6248AccessibleAction {62496250private JTree tree = null;6251private TreeModel treeModel = null;6252private Object obj = null;6253private TreePath path = null;6254private Accessible accessibleParent = null;6255private int index = 0;6256private boolean isLeaf = false;62576258/**6259* Constructs an AccessibleJTreeNode6260*/6261AccessibleJTreeNode(JTree t, TreePath p, Accessible ap) {6262tree = t;6263path = p;6264accessibleParent = ap;6265if (t != null)6266treeModel = t.getModel();6267if (p != null) {6268obj = p.getLastPathComponent();6269if (treeModel != null && obj != null) {6270isLeaf = treeModel.isLeaf(obj);6271}6272}6273debugString("[INFO]: AccessibleJTreeNode: name = "+getAccessibleName()+"; TreePath = "+p+"; parent = "+ap);6274}62756276private TreePath getChildTreePath(int i) {6277// Tree nodes can't be so complex that they have6278// two sets of children -> we're ignoring that case6279if (i < 0 || i >= getAccessibleChildrenCount() || path == null || treeModel == null) {6280return null;6281} else {6282Object childObj = treeModel.getChild(obj, i);6283Object[] objPath = path.getPath();6284Object[] objChildPath = new Object[objPath.length+1];6285java.lang.System.arraycopy(objPath, 0, objChildPath, 0, objPath.length);6286objChildPath[objChildPath.length-1] = childObj;6287return new TreePath(objChildPath);6288}6289}62906291/**6292* Get the AccessibleContext associated with this tree node.6293* In the implementation of the Java Accessibility API for6294* this class, return this object, which is its own6295* AccessibleContext.6296*6297* @return this object6298*/6299public AccessibleContext getAccessibleContext() {6300return this;6301}63026303private AccessibleContext getCurrentAccessibleContext() {6304Component c = getCurrentComponent();6305if (c instanceof Accessible) {6306return (c.getAccessibleContext());6307} else {6308return null;6309}6310}63116312private Component getCurrentComponent() {6313debugString("[INFO]: AccessibleJTreeNode: getCurrentComponent");6314// is the object visible?6315// if so, get row, selected, focus & leaf state,6316// and then get the renderer component and return it6317if (tree != null && tree.isVisible(path)) {6318TreeCellRenderer r = tree.getCellRenderer();6319if (r == null) {6320debugString("[WARN]: returning null 1");6321return null;6322}6323TreeUI ui = tree.getUI();6324if (ui != null) {6325int row = ui.getRowForPath(tree, path);6326boolean selected = tree.isPathSelected(path);6327boolean expanded = tree.isExpanded(path);6328boolean hasFocus = false; // how to tell?? -PK6329Component retval = r.getTreeCellRendererComponent(tree, obj,6330selected, expanded,6331isLeaf, row, hasFocus);6332debugString("[INFO]: returning = "+retval.getClass());6333return retval;6334}6335}6336debugString("[WARN]: returning null 2");6337return null;6338}63396340// AccessibleContext methods63416342/**6343* Get the accessible name of this object.6344*6345* @return the localized name of the object; null if this6346* object does not have a name6347*/6348public String getAccessibleName() {6349debugString("[INFO]: AccessibleJTreeNode: getAccessibleName");6350AccessibleContext ac = getCurrentAccessibleContext();6351if (ac != null) {6352String name = ac.getAccessibleName();6353if ((name != null) && (!name.isEmpty())) {6354String retval = ac.getAccessibleName();6355debugString("[INFO]: returning "+retval);6356return retval;6357} else {6358return null;6359}6360}6361if ((accessibleName != null) && (accessibleName.isEmpty())) {6362return accessibleName;6363} else {6364return null;6365}6366}63676368/**6369* Set the localized accessible name of this object.6370*6371* @param s the new localized name of the object.6372*/6373public void setAccessibleName(String s) {6374AccessibleContext ac = getCurrentAccessibleContext();6375if (ac != null) {6376ac.setAccessibleName(s);6377} else {6378super.setAccessibleName(s);6379}6380}63816382//6383// *** should check tooltip text for desc. (needs MouseEvent)6384//6385/**6386* Get the accessible description of this object.6387*6388* @return the localized description of the object; null if6389* this object does not have a description6390*/6391public String getAccessibleDescription() {6392AccessibleContext ac = getCurrentAccessibleContext();6393if (ac != null) {6394return ac.getAccessibleDescription();6395} else {6396return super.getAccessibleDescription();6397}6398}63996400/**6401* Set the accessible description of this object.6402*6403* @param s the new localized description of the object6404*/6405public void setAccessibleDescription(String s) {6406AccessibleContext ac = getCurrentAccessibleContext();6407if (ac != null) {6408ac.setAccessibleDescription(s);6409} else {6410super.setAccessibleDescription(s);6411}6412}64136414/**6415* Get the role of this object.6416*6417* @return an instance of AccessibleRole describing the role of the object6418* @see AccessibleRole6419*/6420public AccessibleRole getAccessibleRole() {6421AccessibleContext ac = getCurrentAccessibleContext();6422if (ac != null) {6423return ac.getAccessibleRole();6424} else {6425return AccessibleRole.UNKNOWN;6426}6427}64286429/**6430* Get the state set of this object.6431*6432* @return an instance of AccessibleStateSet containing the6433* current state set of the object6434* @see AccessibleState6435*/6436public AccessibleStateSet getAccessibleStateSet() {6437if (tree == null)6438return null;6439AccessibleContext ac = getCurrentAccessibleContext();6440AccessibleStateSet states;6441int row = tree.getUI().getRowForPath(tree,path);6442int lsr = tree.getLeadSelectionRow();6443if (ac != null) {6444states = ac.getAccessibleStateSet();6445} else {6446states = new AccessibleStateSet();6447}6448// need to test here, 'cause the underlying component6449// is a cellRenderer, which is never showing...6450if (isShowing()) {6451states.add(AccessibleState.SHOWING);6452} else if (states.contains(AccessibleState.SHOWING)) {6453states.remove(AccessibleState.SHOWING);6454}6455if (isVisible()) {6456states.add(AccessibleState.VISIBLE);6457} else if (states.contains(AccessibleState.VISIBLE)) {6458states.remove(AccessibleState.VISIBLE);6459}6460if (tree.isPathSelected(path)){6461states.add(AccessibleState.SELECTED);6462}6463if (lsr == row) {6464states.add(AccessibleState.ACTIVE);6465}6466if (!isLeaf) {6467states.add(AccessibleState.EXPANDABLE);6468}6469if (tree.isExpanded(path)) {6470states.add(AccessibleState.EXPANDED);6471} else {6472states.add(AccessibleState.COLLAPSED);6473}6474if (tree.isEditable()) {6475states.add(AccessibleState.EDITABLE);6476}6477return states;6478}64796480/**6481* Get the Accessible parent of this object.6482*6483* @return the Accessible parent of this object; null if this6484* object does not have an Accessible parent6485*/6486public Accessible getAccessibleParent() {6487// someone wants to know, so we need to create our parent6488// if we don't have one (hey, we're a talented kid!)6489if (accessibleParent == null && path != null) {6490Object[] objPath = path.getPath();6491if (objPath.length > 1) {6492Object objParent = objPath[objPath.length-2];6493if (treeModel != null) {6494index = treeModel.getIndexOfChild(objParent, obj);6495}6496Object[] objParentPath = new Object[objPath.length-1];6497java.lang.System.arraycopy(objPath, 0, objParentPath,64980, objPath.length-1);6499TreePath parentPath = new TreePath(objParentPath);6500accessibleParent = new AccessibleJTreeNode(tree,6501parentPath,6502null);6503this.setAccessibleParent(accessibleParent);6504} else if (treeModel != null) {6505accessibleParent = tree; // we're the top!6506index = 0; // we're an only child!6507this.setAccessibleParent(accessibleParent);6508}6509}6510return accessibleParent;6511}65126513/**6514* Get the index of this object in its accessible parent.6515*6516* @return the index of this object in its parent; -1 if this6517* object does not have an accessible parent.6518* @see #getAccessibleParent6519*/6520public int getAccessibleIndexInParent() {6521// index is invalid 'till we have an accessibleParent...6522if (accessibleParent == null) {6523getAccessibleParent();6524}6525if (path != null) {6526Object[] objPath = path.getPath();6527if (objPath.length > 1) {6528Object objParent = objPath[objPath.length-2];6529if (treeModel != null) {6530index = treeModel.getIndexOfChild(objParent, obj);6531}6532}6533}6534return index;6535}65366537/**6538* Returns the number of accessible children in the object.6539*6540* @return the number of accessible children in the object.6541*/6542public int getAccessibleChildrenCount() {6543// Tree nodes can't be so complex that they have6544// two sets of children -> we're ignoring that case6545if (obj != null && treeModel != null) {6546return treeModel.getChildCount(obj);6547}6548return 0;6549}65506551/**6552* Return the specified Accessible child of the object.6553*6554* @param i zero-based index of child6555* @return the Accessible child of the object6556*/6557public Accessible getAccessibleChild(int i) {6558// Tree nodes can't be so complex that they have6559// two sets of children -> we're ignoring that case6560if (i < 0 || i >= getAccessibleChildrenCount() || path == null || treeModel == null) {6561return null;6562} else {6563Object childObj = treeModel.getChild(obj, i);6564Object[] objPath = path.getPath();6565Object[] objChildPath = new Object[objPath.length+1];6566java.lang.System.arraycopy(objPath, 0, objChildPath, 0, objPath.length);6567objChildPath[objChildPath.length-1] = childObj;6568TreePath childPath = new TreePath(objChildPath);6569return new AccessibleJTreeNode(tree, childPath, this);6570}6571}65726573/**6574* Gets the locale of the component. If the component does not have6575* a locale, then the locale of its parent is returned.6576*6577* @return This component's locale. If this component does not have6578* a locale, the locale of its parent is returned.6579* @exception IllegalComponentStateException6580* If the Component does not have its own locale and has not yet6581* been added to a containment hierarchy such that the locale can be6582* determined from the containing parent.6583* @see #setLocale6584*/6585public Locale getLocale() {6586if (tree == null)6587return null;6588AccessibleContext ac = getCurrentAccessibleContext();6589if (ac != null) {6590return ac.getLocale();6591} else {6592return tree.getLocale();6593}6594}65956596/**6597* Add a PropertyChangeListener to the listener list.6598* The listener is registered for all properties.6599*6600* @param l The PropertyChangeListener to be added6601*/6602public void addPropertyChangeListener(PropertyChangeListener l) {6603AccessibleContext ac = getCurrentAccessibleContext();6604if (ac != null) {6605ac.addPropertyChangeListener(l);6606} else {6607super.addPropertyChangeListener(l);6608}6609}66106611/**6612* Remove a PropertyChangeListener from the listener list.6613* This removes a PropertyChangeListener that was registered6614* for all properties.6615*6616* @param l The PropertyChangeListener to be removed6617*/6618public void removePropertyChangeListener(PropertyChangeListener l) {6619AccessibleContext ac = getCurrentAccessibleContext();6620if (ac != null) {6621ac.removePropertyChangeListener(l);6622} else {6623super.removePropertyChangeListener(l);6624}6625}66266627/**6628* Get the AccessibleAction associated with this object. In the6629* implementation of the Java Accessibility API for this class,6630* return this object, which is responsible for implementing the6631* AccessibleAction interface on behalf of itself.6632*6633* @return this object6634*/6635public AccessibleAction getAccessibleAction() {6636return this;6637}66386639/**6640* Get the AccessibleComponent associated with this object. In the6641* implementation of the Java Accessibility API for this class,6642* return this object, which is responsible for implementing the6643* AccessibleComponent interface on behalf of itself.6644*6645* @return this object6646*/6647public AccessibleComponent getAccessibleComponent() {6648return this; // to override getBounds()6649}66506651/**6652* Get the AccessibleSelection associated with this object if one6653* exists. Otherwise return null.6654*6655* @return the AccessibleSelection, or null6656*/6657public AccessibleSelection getAccessibleSelection() {6658AccessibleContext ac = getCurrentAccessibleContext();6659if (ac != null && isLeaf) {6660return getCurrentAccessibleContext().getAccessibleSelection();6661} else {6662return this;6663}6664}66656666/**6667* Get the AccessibleText associated with this object if one6668* exists. Otherwise return null.6669*6670* @return the AccessibleText, or null6671*/6672public AccessibleText getAccessibleText() {6673AccessibleContext ac = getCurrentAccessibleContext();6674if (ac != null) {6675return getCurrentAccessibleContext().getAccessibleText();6676} else {6677return null;6678}6679}66806681/**6682* Get the AccessibleValue associated with this object if one6683* exists. Otherwise return null.6684*6685* @return the AccessibleValue, or null6686*/6687public AccessibleValue getAccessibleValue() {6688AccessibleContext ac = getCurrentAccessibleContext();6689if (ac != null) {6690return getCurrentAccessibleContext().getAccessibleValue();6691} else {6692return null;6693}6694}669566966697// AccessibleComponent methods66986699/**6700* Get the background color of this object.6701*6702* @return the background color, if supported, of the object;6703* otherwise, null6704*/6705public Color getBackground() {6706AccessibleContext ac = getCurrentAccessibleContext();6707if (ac instanceof AccessibleComponent) {6708return ((AccessibleComponent) ac).getBackground();6709} else {6710Component c = getCurrentComponent();6711if (c != null) {6712return c.getBackground();6713} else {6714return null;6715}6716}6717}67186719/**6720* Set the background color of this object.6721*6722* @param c the new Color for the background6723*/6724public void setBackground(Color c) {6725AccessibleContext ac = getCurrentAccessibleContext();6726if (ac instanceof AccessibleComponent) {6727((AccessibleComponent) ac).setBackground(c);6728} else {6729Component cp = getCurrentComponent();6730if ( cp != null) {6731cp.setBackground(c);6732}6733}6734}673567366737/**6738* Get the foreground color of this object.6739*6740* @return the foreground color, if supported, of the object;6741* otherwise, null6742*/6743public Color getForeground() {6744AccessibleContext ac = getCurrentAccessibleContext();6745if (ac instanceof AccessibleComponent) {6746return ((AccessibleComponent) ac).getForeground();6747} else {6748Component c = getCurrentComponent();6749if (c != null) {6750return c.getForeground();6751} else {6752return null;6753}6754}6755}67566757public void setForeground(Color c) {6758AccessibleContext ac = getCurrentAccessibleContext();6759if (ac instanceof AccessibleComponent) {6760((AccessibleComponent) ac).setForeground(c);6761} else {6762Component cp = getCurrentComponent();6763if (cp != null) {6764cp.setForeground(c);6765}6766}6767}67686769public Cursor getCursor() {6770AccessibleContext ac = getCurrentAccessibleContext();6771if (ac instanceof AccessibleComponent) {6772return ((AccessibleComponent) ac).getCursor();6773} else {6774Component c = getCurrentComponent();6775if (c != null) {6776return c.getCursor();6777} else {6778Accessible ap = getAccessibleParent();6779if (ap instanceof AccessibleComponent) {6780return ((AccessibleComponent) ap).getCursor();6781} else {6782return null;6783}6784}6785}6786}67876788public void setCursor(Cursor c) {6789AccessibleContext ac = getCurrentAccessibleContext();6790if (ac instanceof AccessibleComponent) {6791((AccessibleComponent) ac).setCursor(c);6792} else {6793Component cp = getCurrentComponent();6794if (cp != null) {6795cp.setCursor(c);6796}6797}6798}67996800public Font getFont() {6801AccessibleContext ac = getCurrentAccessibleContext();6802if (ac instanceof AccessibleComponent) {6803return ((AccessibleComponent) ac).getFont();6804} else {6805Component c = getCurrentComponent();6806if (c != null) {6807return c.getFont();6808} else {6809return null;6810}6811}6812}68136814public void setFont(Font f) {6815AccessibleContext ac = getCurrentAccessibleContext();6816if (ac instanceof AccessibleComponent) {6817((AccessibleComponent) ac).setFont(f);6818} else {6819Component c = getCurrentComponent();6820if (c != null) {6821c.setFont(f);6822}6823}6824}68256826public FontMetrics getFontMetrics(Font f) {6827AccessibleContext ac = getCurrentAccessibleContext();6828if (ac instanceof AccessibleComponent) {6829return ((AccessibleComponent) ac).getFontMetrics(f);6830} else {6831Component c = getCurrentComponent();6832if (c != null) {6833return c.getFontMetrics(f);6834} else {6835return null;6836}6837}6838}68396840public boolean isEnabled() {6841AccessibleContext ac = getCurrentAccessibleContext();6842if (ac instanceof AccessibleComponent) {6843return ((AccessibleComponent) ac).isEnabled();6844} else {6845Component c = getCurrentComponent();6846if (c != null) {6847return c.isEnabled();6848} else {6849return false;6850}6851}6852}68536854public void setEnabled(boolean b) {6855AccessibleContext ac = getCurrentAccessibleContext();6856if (ac instanceof AccessibleComponent) {6857((AccessibleComponent) ac).setEnabled(b);6858} else {6859Component c = getCurrentComponent();6860if (c != null) {6861c.setEnabled(b);6862}6863}6864}68656866public boolean isVisible() {6867if (tree == null)6868return false;6869Rectangle pathBounds = tree.getPathBounds(path);6870Rectangle parentBounds = tree.getVisibleRect();6871if ( pathBounds != null && parentBounds != null &&6872parentBounds.intersects(pathBounds) ) {6873return true;6874} else {6875return false;6876}6877}68786879public void setVisible(boolean b) {6880}68816882public boolean isShowing() {6883return (tree.isShowing() && isVisible());6884}68856886public boolean contains(Point p) {6887AccessibleContext ac = getCurrentAccessibleContext();6888if (ac instanceof AccessibleComponent) {6889Rectangle r = ((AccessibleComponent) ac).getBounds();6890return r.contains(p);6891} else {6892Component c = getCurrentComponent();6893if (c != null) {6894Rectangle r = c.getBounds();6895return r.contains(p);6896} else {6897return getBounds().contains(p);6898}6899}6900}69016902public Point getLocationOnScreen() {6903if (tree != null) {6904Point treeLocation = tree.getLocationOnScreen();6905Rectangle pathBounds = tree.getPathBounds(path);6906if (treeLocation != null && pathBounds != null) {6907Point nodeLocation = new Point(pathBounds.x,6908pathBounds.y);6909nodeLocation.translate(treeLocation.x, treeLocation.y);6910return nodeLocation;6911} else {6912return null;6913}6914} else {6915return null;6916}6917}69186919private Point getLocationInJTree() {6920Rectangle r = tree.getPathBounds(path);6921if (r != null) {6922return r.getLocation();6923} else {6924return null;6925}6926}69276928public Point getLocation() {6929Rectangle r = getBounds();6930if (r != null) {6931return r.getLocation();6932} else {6933return null;6934}6935}69366937public void setLocation(Point p) {6938}69396940public Rectangle getBounds() {6941if (tree == null)6942return null;6943Rectangle r = tree.getPathBounds(path);6944Accessible parent = getAccessibleParent();6945if (parent instanceof AccessibleJTreeNode) {6946Point parentLoc = ((AccessibleJTreeNode) parent).getLocationInJTree();6947if (parentLoc != null && r != null) {6948r.translate(-parentLoc.x, -parentLoc.y);6949} else {6950return null; // not visible!6951}6952}6953return r;6954}69556956public void setBounds(Rectangle r) {6957AccessibleContext ac = getCurrentAccessibleContext();6958if (ac instanceof AccessibleComponent) {6959((AccessibleComponent) ac).setBounds(r);6960} else {6961Component c = getCurrentComponent();6962if (c != null) {6963c.setBounds(r);6964}6965}6966}69676968public Dimension getSize() {6969return getBounds().getSize();6970}69716972public void setSize (Dimension d) {6973AccessibleContext ac = getCurrentAccessibleContext();6974if (ac instanceof AccessibleComponent) {6975((AccessibleComponent) ac).setSize(d);6976} else {6977Component c = getCurrentComponent();6978if (c != null) {6979c.setSize(d);6980}6981}6982}69836984/**6985* Returns the <code>Accessible</code> child, if one exists,6986* contained at the local coordinate <code>Point</code>.6987* Otherwise returns <code>null</code>.6988*6989* @param p point in local coordinates of this6990* <code>Accessible</code>6991* @return the <code>Accessible</code>, if it exists,6992* at the specified location; else <code>null</code>6993*/6994public Accessible getAccessibleAt(Point p) {6995AccessibleContext ac = getCurrentAccessibleContext();6996if (ac instanceof AccessibleComponent) {6997return ((AccessibleComponent) ac).getAccessibleAt(p);6998} else {6999return null;7000}7001}70027003public boolean isFocusTraversable() {7004AccessibleContext ac = getCurrentAccessibleContext();7005if (ac instanceof AccessibleComponent) {7006return ((AccessibleComponent) ac).isFocusTraversable();7007} else {7008Component c = getCurrentComponent();7009if (c != null) {7010return c.isFocusable();7011} else {7012return false;7013}7014}7015}70167017public void requestFocus() {7018AccessibleContext ac = getCurrentAccessibleContext();7019if (ac instanceof AccessibleComponent) {7020((AccessibleComponent) ac).requestFocus();7021} else {7022Component c = getCurrentComponent();7023if (c != null) {7024c.requestFocus();7025}7026}7027}70287029public void addFocusListener(FocusListener l) {7030AccessibleContext ac = getCurrentAccessibleContext();7031if (ac instanceof AccessibleComponent) {7032((AccessibleComponent) ac).addFocusListener(l);7033} else {7034Component c = getCurrentComponent();7035if (c != null) {7036c.addFocusListener(l);7037}7038}7039}70407041public void removeFocusListener(FocusListener l) {7042AccessibleContext ac = getCurrentAccessibleContext();7043if (ac instanceof AccessibleComponent) {7044((AccessibleComponent) ac).removeFocusListener(l);7045} else {7046Component c = getCurrentComponent();7047if (c != null) {7048c.removeFocusListener(l);7049}7050}7051}70527053// AccessibleSelection methods70547055/**7056* Returns the number of items currently selected.7057* If no items are selected, the return value will be 0.7058*7059* @return the number of items currently selected.7060*/7061public int getAccessibleSelectionCount() {7062int count = 0;7063int childCount = getAccessibleChildrenCount();7064for (int i = 0; i < childCount; i++) {7065TreePath childPath = getChildTreePath(i);7066if (tree.isPathSelected(childPath)) {7067count++;7068}7069}7070return count;7071}70727073/**7074* Returns an Accessible representing the specified selected item7075* in the object. If there isn't a selection, or there are7076* fewer items selected than the integer passed in, the return7077* value will be null.7078*7079* @param i the zero-based index of selected items7080* @return an Accessible containing the selected item7081*/7082public Accessible getAccessibleSelection(int i) {7083int childCount = getAccessibleChildrenCount();7084if (i < 0 || i >= childCount) {7085return null; // out of range7086}7087int count = 0;7088for (int j = 0; j < childCount && i >= count; j++) {7089TreePath childPath = getChildTreePath(j);7090if (tree.isPathSelected(childPath)) {7091if (count == i) {7092return new AccessibleJTreeNode(tree, childPath, this);7093} else {7094count++;7095}7096}7097}7098return null;7099}71007101/**7102* Returns true if the current child of this object is selected.7103*7104* @param i the zero-based index of the child in this Accessible7105* object.7106* @see AccessibleContext#getAccessibleChild7107*/7108public boolean isAccessibleChildSelected(int i) {7109int childCount = getAccessibleChildrenCount();7110if (i < 0 || i >= childCount) {7111return false; // out of range7112} else {7113TreePath childPath = getChildTreePath(i);7114return tree.isPathSelected(childPath);7115}7116}71177118/**7119* Adds the specified selected item in the object to the object's7120* selection. If the object supports multiple selections,7121* the specified item is added to any existing selection, otherwise7122* it replaces any existing selection in the object. If the7123* specified item is already selected, this method has no effect.7124*7125* @param i the zero-based index of selectable items7126*/7127public void addAccessibleSelection(int i) {7128if (tree == null)7129return;7130TreeModel model = tree.getModel();7131if (model != null) {7132if (i >= 0 && i < getAccessibleChildrenCount()) {7133TreePath path = getChildTreePath(i);7134tree.addSelectionPath(path);7135}7136}7137}71387139/**7140* Removes the specified selected item in the object from the7141* object's7142* selection. If the specified item isn't currently selected, this7143* method has no effect.7144*7145* @param i the zero-based index of selectable items7146*/7147public void removeAccessibleSelection(int i) {7148if (tree == null)7149return;7150TreeModel model = tree.getModel();7151if (model != null) {7152if (i >= 0 && i < getAccessibleChildrenCount()) {7153TreePath path = getChildTreePath(i);7154tree.removeSelectionPath(path);7155}7156}7157}71587159/**7160* Clears the selection in the object, so that nothing in the7161* object is selected.7162*/7163public void clearAccessibleSelection() {7164int childCount = getAccessibleChildrenCount();7165for (int i = 0; i < childCount; i++) {7166removeAccessibleSelection(i);7167}7168}71697170/**7171* Causes every selected item in the object to be selected7172* if the object supports multiple selections.7173*/7174public void selectAllAccessibleSelection() {7175if (tree == null)7176return;7177TreeModel model = tree.getModel();7178if (model != null) {7179int childCount = getAccessibleChildrenCount();7180TreePath path;7181for (int i = 0; i < childCount; i++) {7182path = getChildTreePath(i);7183tree.addSelectionPath(path);7184}7185}7186}71877188// AccessibleAction methods71897190/**7191* Returns the number of accessible actions available in this7192* tree node. If this node is not a leaf, there is at least7193* one action (toggle expand), in addition to any available7194* on the object behind the TreeCellRenderer.7195*7196* @return the number of Actions in this object7197*/7198public int getAccessibleActionCount() {7199AccessibleContext ac = getCurrentAccessibleContext();7200if (ac != null) {7201AccessibleAction aa = ac.getAccessibleAction();7202if (aa != null) {7203return (aa.getAccessibleActionCount() + (isLeaf ? 0 : 1));7204}7205}7206return isLeaf ? 0 : 1;7207}72087209/**7210* Return a description of the specified action of the tree node.7211* If this node is not a leaf, there is at least one action7212* description (toggle expand), in addition to any available7213* on the object behind the TreeCellRenderer.7214*7215* @param i zero-based index of the actions7216* @return a description of the action7217*/7218public String getAccessibleActionDescription(int i) {7219if (i < 0 || i >= getAccessibleActionCount()) {7220return null;7221}7222AccessibleContext ac = getCurrentAccessibleContext();7223if (i == 0) {7224// TIGER - 47666367225// return AccessibleAction.TOGGLE_EXPAND;7226return "toggle expand";7227} else if (ac != null) {7228AccessibleAction aa = ac.getAccessibleAction();7229if (aa != null) {7230return aa.getAccessibleActionDescription(i - 1);7231}7232}7233return null;7234}72357236/**7237* Perform the specified Action on the tree node. If this node7238* is not a leaf, there is at least one action which can be7239* done (toggle expand), in addition to any available on the7240* object behind the TreeCellRenderer.7241*7242* @param i zero-based index of actions7243* @return true if the the action was performed; else false.7244*/7245public boolean doAccessibleAction(int i) {7246if (i < 0 || i >= getAccessibleActionCount()) {7247return false;7248}7249AccessibleContext ac = getCurrentAccessibleContext();7250if (i == 0) {7251if (tree.isExpanded(path)) {7252tree.collapsePath(path);7253} else {7254tree.expandPath(path);7255}7256return true;7257} else if (ac != null) {7258AccessibleAction aa = ac.getAccessibleAction();7259if (aa != null) {7260return aa.doAccessibleAction(i - 1);7261}7262}7263return false;7264}72657266} // inner class AccessibleJTreeNode72677268/**7269* A helper class to perform {@code Callable} objects on the event dispatch thread appropriate7270* for the provided {@code AccessibleContext}.7271*/7272private static class InvocationUtils {72737274/**7275* Invokes a {@code Callable} in the {@code AppContext} of the given {@code Accessible}7276* and waits for it to finish blocking the caller thread.7277*7278* @param callable the {@code Callable} to invoke7279* @param accessibleTable the {@code AccessibleExtendedTable} which would be used to find the right context7280* for the task execution7281* @param <T> type parameter for the result value7282*7283* @return the result of the {@code Callable} execution7284*/7285public static <T> T invokeAndWait(final Callable<T> callable,7286final AccessibleExtendedTable accessibleTable) {7287if (accessibleTable instanceof AccessibleContext) {7288return invokeAndWait(callable, (AccessibleContext)accessibleTable);7289}7290throw new RuntimeException("Unmapped AccessibleContext used to dispatch event: " + accessibleTable);7291}72927293/**7294* Invokes a {@code Callable} in the {@code AppContext} of the given {@code Accessible}7295* and waits for it to finish blocking the caller thread.7296*7297* @param callable the {@code Callable} to invoke7298* @param accessible the {@code Accessible} which would be used to find the right context7299* for the task execution7300* @param <T> type parameter for the result value7301*7302* @return the result of the {@code Callable} execution7303*/7304public static <T> T invokeAndWait(final Callable<T> callable,7305final Accessible accessible) {7306if (accessible instanceof Component) {7307return invokeAndWait(callable, (Component)accessible);7308}7309if (accessible instanceof AccessibleContext) {7310// This case also covers the Translator7311return invokeAndWait(callable, (AccessibleContext)accessible);7312}7313throw new RuntimeException("Unmapped Accessible used to dispatch event: " + accessible);7314}73157316/**7317* Invokes a {@code Callable} in the {@code AppContext} of the given {@code Component}7318* and waits for it to finish blocking the caller thread.7319*7320* @param callable the {@code Callable} to invoke7321* @param component the {@code Component} which would be used to find the right context7322* for the task execution7323* @param <T> type parameter for the result value7324*7325* @return the result of the {@code Callable} execution7326*/7327public static <T> T invokeAndWait(final Callable<T> callable,7328final Component component) {7329return invokeAndWait(callable, SunToolkit.targetToAppContext(component));7330}73317332/**7333* Invokes a {@code Callable} in the {@code AppContext} mapped to the given {@code AccessibleContext}7334* and waits for it to finish blocking the caller thread.7335*7336* @param callable the {@code Callable} to invoke7337* @param accessibleContext the {@code AccessibleContext} which would be used to determine the right7338* context for the task execution.7339* @param <T> type parameter for the result value7340*7341* @return the result of the {@code Callable} execution7342*/7343public static <T> T invokeAndWait(final Callable<T> callable,7344final AccessibleContext accessibleContext) {7345AppContext targetContext = AWTAccessor.getAccessibleContextAccessor()7346.getAppContext(accessibleContext);7347if (targetContext != null) {7348return invokeAndWait(callable, targetContext);7349} else {7350// Normally this should not happen, unmapped context provided and7351// the target AppContext is unknown.73527353// Try to recover in case the context is a translator.7354if (accessibleContext instanceof Translator) {7355Object source = ((Translator)accessibleContext).getSource();7356if (source instanceof Component) {7357return invokeAndWait(callable, (Component)source);7358}7359}7360}7361throw new RuntimeException("Unmapped AccessibleContext used to dispatch event: " + accessibleContext);7362}73637364private static <T> T invokeAndWait(final Callable<T> callable,7365final AppContext targetAppContext) {7366final CallableWrapper<T> wrapper = new CallableWrapper<T>(callable);7367try {7368invokeAndWait(wrapper, targetAppContext);7369T result = wrapper.getResult();7370updateAppContextMap(result, targetAppContext);7371return result;7372} catch (final Exception e) {7373throw new RuntimeException(e);7374}7375}73767377private static void invokeAndWait(final Runnable runnable,7378final AppContext appContext)7379throws InterruptedException, InvocationTargetException {73807381EventQueue eq = SunToolkit.getSystemEventQueueImplPP(appContext);7382Object lock = new Object();7383Toolkit source = Toolkit.getDefaultToolkit();7384InvocationEvent event =7385new InvocationEvent(source, runnable, lock, true);7386synchronized (lock) {7387eq.postEvent(event);7388lock.wait();7389}73907391Throwable eventThrowable = event.getThrowable();7392if (eventThrowable != null) {7393throw new InvocationTargetException(eventThrowable);7394}7395}73967397/**7398* Maps the {@code AccessibleContext} to the {@code AppContext} which should be used7399* to dispatch events related to the {@code AccessibleContext}7400* @param accessibleContext the {@code AccessibleContext} for the mapping7401* @param targetContext the {@code AppContext} for the mapping7402*/7403public static void registerAccessibleContext(final AccessibleContext accessibleContext,7404final AppContext targetContext) {7405if (accessibleContext != null) {7406AWTAccessor.getAccessibleContextAccessor().setAppContext(accessibleContext, targetContext);7407}7408}74097410private static <T> void updateAppContextMap(final T accessibleContext,7411final AppContext targetContext) {7412if (accessibleContext instanceof AccessibleContext) {7413registerAccessibleContext((AccessibleContext)accessibleContext, targetContext);7414}7415}74167417private static class CallableWrapper<T> implements Runnable {7418private final Callable<T> callable;7419private volatile T object;7420private Exception e;74217422CallableWrapper(final Callable<T> callable) {7423this.callable = callable;7424}74257426public void run() {7427try {7428if (callable != null) {7429object = callable.call();7430}7431} catch (final Exception e) {7432this.e = e;7433}7434}74357436T getResult() throws Exception {7437if (e != null)7438throw e;7439return object;7440}7441}7442}7443}744474457446