Path: blob/master/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java
44222 views
/*1* Copyright (c) 2005, 2021, 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.internal;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 java.awt.geom.Rectangle2D;44import sun.awt.AWTAccessor;45import sun.awt.AppContext;46import sun.awt.SunToolkit;4748import java.util.concurrent.Callable;49import java.util.concurrent.ConcurrentHashMap;5051/*52* Note: This class has to be public. It's loaded from the VM like this:53* Class.forName(atName).newInstance();54*/55final public class AccessBridge {5657private static AccessBridge theAccessBridge;58private ObjectReferences references;59private EventHandler eventHandler;6061// Maps AccessibleRoles strings to AccessibleRoles.62private ConcurrentHashMap<String,AccessibleRole> accessibleRoleMap = new ConcurrentHashMap<>();6364/**65If the object's role is in the following array getVirtualAccessibleName66will use the extended search algorithm.67*/68private ArrayList<AccessibleRole> extendedVirtualNameSearchRoles = new ArrayList<>();69/**70If the role of the object's parent is in the following array71getVirtualAccessibleName will NOT use the extended search72algorithm even if the object's role is in the73extendedVirtualNameSearchRoles array.74*/75private ArrayList<AccessibleRole> noExtendedVirtualNameSearchParentRoles = new ArrayList<>();7677private static native boolean isSysWow();787980/**81* Load DLLs82*/83static {84initStatic();85}8687@SuppressWarnings("removal")88private static void initStatic() {89// Load the appropriate DLLs90boolean is32on64 = false;91if (System.getProperty("os.arch").equals("x86")) {92// 32 bit JRE93// Load jabsysinfo.dll so can determine Win bitness94java.security.AccessController.doPrivileged(95new java.security.PrivilegedAction<Void>() {96public Void run() {97System.loadLibrary("jabsysinfo");98return null;99}100}, null, new java.lang.RuntimePermission("loadLibrary.jabsysinfo")101);102if (isSysWow()) {103// 32 bit JRE on 64 bit OS104is32on64 = true;105java.security.AccessController.doPrivileged(106new java.security.PrivilegedAction<Void>() {107public Void run() {108System.loadLibrary("javaaccessbridge-32");109return null;110}111}, null, new java.lang.RuntimePermission("loadLibrary.javaaccessbridge-32")112);113}114}115if (!is32on64) {116// 32 bit JRE on 32 bit OS or 64 bit JRE on 64 bit OS117java.security.AccessController.doPrivileged(118new java.security.PrivilegedAction<Void>() {119public Void run() {120System.loadLibrary("javaaccessbridge");121return null;122}123}, null, new java.lang.RuntimePermission("loadLibrary.javaaccessbridge")124);125}126}127128/**129* AccessBridge constructor130*131* Note: This constructor has to be public. It's called from the VM like this:132* Class.forName(atName).newInstance();133*/134public AccessBridge() {135theAccessBridge = this;136references = new ObjectReferences();137138// initialize shutdown hook139Runtime runTime = Runtime.getRuntime();140shutdownHook hook = new shutdownHook();141runTime.addShutdownHook(new Thread(hook));142143// initialize AccessibleRole map144initAccessibleRoleMap();145146// initialize the methods that map HWNDs and Java top-level147// windows148initHWNDcalls();149150// is this a JVM we can use?151// install JDK 1.2 and later Swing ToolKit listener152EventQueueMonitor.isGUIInitialized();153154// start the Java event handler155eventHandler = new EventHandler(this);156157// register for menu selection events158MenuSelectionManager.defaultManager().addChangeListener(eventHandler);159160// register as a NativeWindowHandler161addNativeWindowHandler(new DefaultNativeWindowHandler());162163// start in a new thread164Thread abthread = new Thread(new dllRunner());165abthread.setDaemon(true);166abthread.start();167debugString("[INFO]:AccessBridge started");168}169170/*171* adaptor to run the AccessBridge DLL172*/173private class dllRunner implements Runnable {174public void run() {175runDLL();176}177}178179/*180* shutdown hook181*/182private class shutdownHook implements Runnable {183184public void run() {185debugString("[INFO]:***** shutdownHook: shutting down...");186javaShutdown();187}188}189190191/*192* Initialize the hashtable that maps Strings to AccessibleRoles.193*/194private void initAccessibleRoleMap() {195/*196* Initialize the AccessibleRoles map. This code uses methods in197* java.lang.reflect.* to build the map.198*/199try {200Class<?> clAccessibleRole = Class.forName ("javax.accessibility.AccessibleRole");201if (null != clAccessibleRole) {202AccessibleRole roleUnknown = AccessibleRole.UNKNOWN;203Field [] fields = clAccessibleRole.getFields ();204int i = 0;205for (i = 0; i < fields.length; i ++) {206Field f = fields [i];207if (javax.accessibility.AccessibleRole.class == f.getType ()) {208AccessibleRole nextRole = (AccessibleRole) (f.get (roleUnknown));209String nextRoleString = nextRole.toDisplayString (Locale.US);210accessibleRoleMap.put (nextRoleString, nextRole);211}212}213}214} catch (Exception e) {}215216/*217Build the extendedVirtualNameSearchRoles array list.218*/219extendedVirtualNameSearchRoles.add (AccessibleRole.COMBO_BOX);220try {221/*222Added in J2SE 1.4223*/224extendedVirtualNameSearchRoles.add (AccessibleRole.DATE_EDITOR);225} catch (NoSuchFieldError e) {}226extendedVirtualNameSearchRoles.add (AccessibleRole.LIST);227extendedVirtualNameSearchRoles.add (AccessibleRole.PASSWORD_TEXT);228extendedVirtualNameSearchRoles.add (AccessibleRole.SLIDER);229try {230/*231Added in J2SE 1.3232*/233extendedVirtualNameSearchRoles.add (AccessibleRole.SPIN_BOX);234} catch (NoSuchFieldError e) {}235extendedVirtualNameSearchRoles.add (AccessibleRole.TABLE);236extendedVirtualNameSearchRoles.add (AccessibleRole.TEXT);237extendedVirtualNameSearchRoles.add (AccessibleRole.UNKNOWN);238239noExtendedVirtualNameSearchParentRoles.add (AccessibleRole.TABLE);240noExtendedVirtualNameSearchParentRoles.add (AccessibleRole.TOOL_BAR);241}242243/**244* start the AccessBridge DLL running in its own thread245*/246private native void runDLL();247248/**249* debugging output (goes to OutputDebugStr())250*/251private native void sendDebugString(String debugStr);252253/**254* debugging output (goes to OutputDebugStr())255*/256private void debugString(String debugStr) {257sendDebugString(debugStr);258}259260/* ===== utility methods ===== */261262/**263* decrement the reference to the object (called by native code)264*/265private void decrementReference(Object o) {266references.decrement(o);267}268269/**270* get the java.version property from the JVM271*/272private String getJavaVersionProperty() {273String s = System.getProperty("java.version");274if (s != null) {275references.increment(s);276return s;277}278return null;279}280281/* ===== HWND/Java window mapping methods ===== */282283// Java toolkit methods for mapping HWNDs to Java components284private Method javaGetComponentFromNativeWindowHandleMethod;285private Method javaGetNativeWindowHandleFromComponentMethod;286287// native jawt methods for mapping HWNDs to Java components288private native int jawtGetNativeWindowHandleFromComponent(Component comp);289290private native Component jawtGetComponentFromNativeWindowHandle(int handle);291292Toolkit toolkit;293294/**295* map an HWND to an AWT Component296*/297private void initHWNDcalls() {298Class<?>[] integerParemter = new Class<?>[1];299integerParemter[0] = Integer.TYPE;300Class<?>[] componentParemter = new Class<?>[1];301try {302componentParemter[0] = Class.forName("java.awt.Component");303} catch (ClassNotFoundException e) {304debugString("[ERROR]:Exception: " + e.toString());305}306toolkit = Toolkit.getDefaultToolkit();307return;308}309310// native window handler interface311private interface NativeWindowHandler {312public Accessible getAccessibleFromNativeWindowHandle(int nativeHandle);313}314315// hash table of native window handle to AccessibleContext mappings316static private ConcurrentHashMap<Integer,AccessibleContext> windowHandleToContextMap = new ConcurrentHashMap<>();317318// hash table of AccessibleContext to native window handle mappings319static private ConcurrentHashMap<AccessibleContext,Integer> contextToWindowHandleMap = new ConcurrentHashMap<>();320321/*322* adds a virtual window handler to our hash tables323*/324static private void registerVirtualFrame(final Accessible a,325Integer nativeWindowHandle ) {326if (a != null) {327AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {328@Override329public AccessibleContext call() throws Exception {330return a.getAccessibleContext();331}332}, a);333windowHandleToContextMap.put(nativeWindowHandle, ac);334contextToWindowHandleMap.put(ac, nativeWindowHandle);335}336}337338/*339* removes a virtual window handler to our hash tables340*/341static private void revokeVirtualFrame(final Accessible a,342Integer nativeWindowHandle ) {343AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {344@Override345public AccessibleContext call() throws Exception {346return a.getAccessibleContext();347}348}, a);349windowHandleToContextMap.remove(nativeWindowHandle);350contextToWindowHandleMap.remove(ac);351}352353// vector of native window handlers354private static Vector<NativeWindowHandler> nativeWindowHandlers = new Vector<>();355356/*357* adds a native window handler to our list358*/359private static void addNativeWindowHandler(NativeWindowHandler handler) {360if (handler == null) {361throw new IllegalArgumentException();362}363nativeWindowHandlers.addElement(handler);364}365366/*367* removes a native window handler to our list368*/369private static boolean removeNativeWindowHandler(NativeWindowHandler handler) {370if (handler == null) {371throw new IllegalArgumentException();372}373return nativeWindowHandlers.removeElement(handler);374}375376/**377* verifies that a native window handle is a Java window378*/379private boolean isJavaWindow(int nativeHandle) {380AccessibleContext ac = getContextFromNativeWindowHandle(nativeHandle);381if (ac != null) {382saveContextToWindowHandleMapping(ac, nativeHandle);383return true;384}385return false;386}387388/*389* saves the mapping between an AccessibleContext and a window handle390*/391private void saveContextToWindowHandleMapping(AccessibleContext ac,392int nativeHandle) {393debugString("[INFO]:saveContextToWindowHandleMapping...");394if (ac == null) {395return;396}397if (! contextToWindowHandleMap.containsKey(ac)) {398debugString("[INFO]: saveContextToWindowHandleMapping: ac = "+ac+"; handle = "+nativeHandle);399contextToWindowHandleMap.put(ac, nativeHandle);400}401}402403/**404* maps a native window handle to an Accessible Context405*/406private AccessibleContext getContextFromNativeWindowHandle(int nativeHandle) {407// First, look for the Accessible in our hash table of408// virtual window handles.409AccessibleContext ac = windowHandleToContextMap.get(nativeHandle);410if(ac!=null) {411saveContextToWindowHandleMapping(ac, nativeHandle);412return ac;413}414415// Next, look for the native window handle in our vector416// of native window handles.417int numHandlers = nativeWindowHandlers.size();418for (int i = 0; i < numHandlers; i++) {419NativeWindowHandler nextHandler = nativeWindowHandlers.elementAt(i);420final Accessible a = nextHandler.getAccessibleFromNativeWindowHandle(nativeHandle);421if (a != null) {422ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {423@Override424public AccessibleContext call() throws Exception {425return a.getAccessibleContext();426}427}, a);428saveContextToWindowHandleMapping(ac, nativeHandle);429return ac;430}431}432// Not found.433return null;434}435436/**437* maps an AccessibleContext to a native window handle438* returns 0 on error439*/440private int getNativeWindowHandleFromContext(AccessibleContext ac) {441debugString("[INFO]: getNativeWindowHandleFromContext: ac = "+ac);442try {443return contextToWindowHandleMap.get(ac);444} catch (Exception ex) {445return 0;446}447}448449private class DefaultNativeWindowHandler implements NativeWindowHandler {450/*451* returns the Accessible associated with a native window452*/453public Accessible getAccessibleFromNativeWindowHandle(int nativeHandle) {454final Component c = jawtGetComponentFromNativeWindowHandle(nativeHandle);455if (c instanceof Accessible) {456AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {457@Override458public AccessibleContext call() throws Exception {459return c.getAccessibleContext();460}461}, c);462saveContextToWindowHandleMapping(ac, nativeHandle);463return (Accessible)c;464} else {465return null;466}467}468}469470/* ===== AccessibleContext methods =====*/471472/*473* returns the inner-most AccessibleContext in parent at Point(x, y)474*/475private AccessibleContext getAccessibleContextAt(int x, int y,476AccessibleContext parent) {477if (parent == null) {478return null;479}480if (windowHandleToContextMap != null &&481windowHandleToContextMap.containsValue(getRootAccessibleContext(parent))) {482// Path for applications that register their top-level483// windows with the AccessBridge (e.g., StarOffice 6.1)484return getAccessibleContextAt_1(x, y, parent);485} else {486// Path for applications that do not register487// their top-level windows with the AccessBridge488// (e.g., Swing/AWT applications)489return getAccessibleContextAt_2(x, y, parent);490}491}492493/*494* returns the root accessible context495*/496private AccessibleContext getRootAccessibleContext(final AccessibleContext ac) {497if (ac == null) {498return null;499}500return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {501@Override502public AccessibleContext call() throws Exception {503Accessible parent = ac.getAccessibleParent();504if (parent == null) {505return ac;506}507Accessible tmp = parent.getAccessibleContext().getAccessibleParent();508while (tmp != null) {509parent = tmp;510tmp = parent.getAccessibleContext().getAccessibleParent();511}512return parent.getAccessibleContext();513}514}, ac);515}516517/*518* StarOffice version that does not use the EventQueueMonitor519*/520private AccessibleContext getAccessibleContextAt_1(final int x, final int y,521final AccessibleContext parent) {522debugString("[INFO]: getAccessibleContextAt_1 called");523debugString(" -> x = " + x + " y = " + y + " parent = " + parent);524525if (parent == null) return null;526final AccessibleComponent acmp = InvocationUtils.invokeAndWait(new Callable<AccessibleComponent>() {527@Override528public AccessibleComponent call() throws Exception {529return parent.getAccessibleComponent();530}531}, parent);532if (acmp!=null) {533final Point loc = InvocationUtils.invokeAndWait(new Callable<Point>() {534@Override535public Point call() throws Exception {536return acmp.getLocation();537}538}, parent);539final Accessible a = InvocationUtils.invokeAndWait(new Callable<Accessible>() {540@Override541public Accessible call() throws Exception {542return acmp.getAccessibleAt(new Point(x - loc.x, y - loc.y));543}544}, parent);545if (a != null) {546AccessibleContext foundAC = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {547@Override548public AccessibleContext call() throws Exception {549return a.getAccessibleContext();550}551}, parent);552if (foundAC != null) {553if (foundAC != parent) {554// recurse down into the child555return getAccessibleContextAt_1(x - loc.x, y - loc.y,556foundAC);557} else558return foundAC;559}560}561}562return parent;563}564565/*566* AWT/Swing version567*/568private AccessibleContext getAccessibleContextAt_2(final int x, final int y,569AccessibleContext parent) {570debugString("[INFO]: getAccessibleContextAt_2 called");571debugString(" -> x = " + x + " y = " + y + " parent = " + parent);572573return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {574@Override575public AccessibleContext call() throws Exception {576Accessible a = EventQueueMonitor.getAccessibleAt(new Point(x, y));577if (a != null) {578AccessibleContext childAC = a.getAccessibleContext();579if (childAC != null) {580debugString("[INFO]: returning childAC = " + childAC);581return childAC;582}583}584return null;585}586}, parent);587}588589/**590* returns the Accessible that has focus591*/592private AccessibleContext getAccessibleContextWithFocus() {593Component c = AWTEventMonitor.getComponentWithFocus();594if (c != null) {595final Accessible a = Translator.getAccessible(c);596if (a != null) {597AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {598@Override599public AccessibleContext call() throws Exception {600return a.getAccessibleContext();601}602}, c);603if (ac != null) {604return ac;605}606}607}608return null;609}610611/**612* returns the AccessibleName from an AccessibleContext613*/614private String getAccessibleNameFromContext(final AccessibleContext ac) {615debugString("[INFO]: ***** ac = "+ac.getClass());616if (ac != null) {617String s = InvocationUtils.invokeAndWait(new Callable<String>() {618@Override619public String call() throws Exception {620return ac.getAccessibleName();621}622}, ac);623if (s != null) {624references.increment(s);625debugString("[INFO]: Returning AccessibleName from Context: " + s);626return s;627} else {628return null;629}630} else {631debugString("[INFO]: getAccessibleNameFromContext; ac = null!");632return null;633}634}635636/**637* Returns an AccessibleName for a component using an algorithm optimized638* for the JAWS screen reader. This method is only intended for JAWS. All639* other uses are entirely optional.640*/641private String getVirtualAccessibleNameFromContext(final AccessibleContext ac) {642if (null != ac) {643/*644Step 1:645=======646Determine if we can obtain the Virtual Accessible Name from the647Accessible Name or Accessible Description of the object.648*/649String nameString = InvocationUtils.invokeAndWait(new Callable<String>() {650@Override651public String call() throws Exception {652return ac.getAccessibleName();653}654}, ac);655if ( ( null != nameString ) && ( 0 != nameString.length () ) ) {656debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from AccessibleContext::getAccessibleName.");657references.increment (nameString);658return nameString;659}660String descriptionString = InvocationUtils.invokeAndWait(new Callable<String>() {661@Override662public String call() throws Exception {663return ac.getAccessibleDescription();664}665}, ac);666if ( ( null != descriptionString ) && ( 0 != descriptionString.length () ) ) {667debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from AccessibleContext::getAccessibleDescription.");668references.increment (descriptionString);669return descriptionString;670}671672debugString ("[WARN]: The Virtual Accessible Name was not found using AccessibleContext::getAccessibleDescription. or getAccessibleName");673/*674Step 2:675=======676Decide whether the extended name search algorithm should be677used for this object.678*/679boolean bExtendedSearch = false;680AccessibleRole role = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {681@Override682public AccessibleRole call() throws Exception {683return ac.getAccessibleRole();684}685}, ac);686AccessibleContext parentContext = null;687AccessibleRole parentRole = AccessibleRole.UNKNOWN;688689if ( extendedVirtualNameSearchRoles.contains (role) ) {690parentContext = getAccessibleParentFromContext (ac);691if ( null != parentContext ) {692final AccessibleContext parentContextInnerTemp = parentContext;693parentRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {694@Override695public AccessibleRole call() throws Exception {696return parentContextInnerTemp.getAccessibleRole();697}698}, ac);699if ( AccessibleRole.UNKNOWN != parentRole ) {700bExtendedSearch = true;701if ( noExtendedVirtualNameSearchParentRoles.contains (parentRole) ) {702bExtendedSearch = false;703}704}705}706}707708if (false == bExtendedSearch) {709debugString ("[INFO]: bk -- getVirtualAccessibleNameFromContext will not use the extended name search algorithm. role = " + ( role != null ? role.toDisplayString(Locale.US) : "null") );710/*711Step 3:712=======713We have determined that we should not use the extended name714search algorithm for this object (we must obtain the name of715the object from the object itself and not from neighboring716objects). However the object name cannot be obtained from717the Accessible Name or Accessible Description of the object.718719Handle several special cases here that might yield a value for720the Virtual Accessible Name. Return null if the object does721not match the criteria for any of these special cases.722*/723if (AccessibleRole.LABEL == role) {724/*725Does the label support the Accessible Text Interface?726*/727final AccessibleText at = InvocationUtils.invokeAndWait(new Callable<AccessibleText>() {728@Override729public AccessibleText call() throws Exception {730return ac.getAccessibleText();731}732}, ac);733if (null != at) {734int charCount = InvocationUtils.invokeAndWait(new Callable<Integer>() {735@Override736public Integer call() throws Exception {737return at.getCharCount();738}739}, ac);740String text = getAccessibleTextRangeFromContext (ac, 0, charCount);741if (null != text) {742debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from the Accessible Text of the LABEL object.");743references.increment (text);744return text;745}746}747/*748Does the label support the Accessible Icon Interface?749*/750debugString ("[INFO]: bk -- Attempting to obtain the Virtual Accessible Name from the Accessible Icon information.");751final AccessibleIcon [] ai = InvocationUtils.invokeAndWait(new Callable<AccessibleIcon[]>() {752@Override753public AccessibleIcon[] call() throws Exception {754return ac.getAccessibleIcon();755}756}, ac);757if ( (null != ai) && (ai.length > 0) ) {758String iconDescription = InvocationUtils.invokeAndWait(new Callable<String>() {759@Override760public String call() throws Exception {761return ai[0].getAccessibleIconDescription();762}763}, ac);764if (iconDescription != null){765debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from the description of the first Accessible Icon found in the LABEL object.");766references.increment (iconDescription);767return iconDescription;768}769} else {770parentContext = getAccessibleParentFromContext (ac);771if ( null != parentContext ) {772final AccessibleContext parentContextInnerTemp = parentContext;773parentRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {774@Override775public AccessibleRole call() throws Exception {776return parentContextInnerTemp.getAccessibleRole();777}778}, ac);779if ( AccessibleRole.TABLE == parentRole ) {780int indexInParent = InvocationUtils.invokeAndWait(new Callable<Integer>() {781@Override782public Integer call() throws Exception {783return ac.getAccessibleIndexInParent();784}785}, ac);786final AccessibleContext acTableCell = getAccessibleChildFromContext (parentContext, indexInParent);787debugString ("[INFO]: bk -- Making a second attempt to obtain the Virtual Accessible Name from the Accessible Icon information for the Table Cell.");788if (acTableCell != null) {789final AccessibleIcon [] aiRet =InvocationUtils.invokeAndWait(new Callable<AccessibleIcon[]>() {790@Override791public AccessibleIcon[] call() throws Exception {792return acTableCell.getAccessibleIcon();793}794}, ac);795if ( (null != aiRet) && (aiRet.length > 0) ) {796String iconDescription = InvocationUtils.invokeAndWait(new Callable<String>() {797@Override798public String call() throws Exception {799return aiRet[0].getAccessibleIconDescription();800}801}, ac);802if (iconDescription != null){803debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from the description of the first Accessible Icon found in the Table Cell object.");804references.increment (iconDescription);805return iconDescription;806}807}808}809}810}811}812} else if ( (AccessibleRole.TOGGLE_BUTTON == role) ||813(AccessibleRole.PUSH_BUTTON == role) ) {814/*815Does the button support the Accessible Icon Interface?816*/817debugString ("[INFO]: bk -- Attempting to obtain the Virtual Accessible Name from the Accessible Icon information.");818final AccessibleIcon [] ai = InvocationUtils.invokeAndWait(new Callable<AccessibleIcon[]>() {819@Override820public AccessibleIcon[] call() throws Exception {821return ac.getAccessibleIcon();822}823}, ac);824if ( (null != ai) && (ai.length > 0) ) {825String iconDescription = InvocationUtils.invokeAndWait(new Callable<String>() {826@Override827public String call() throws Exception {828return ai[0].getAccessibleIconDescription();829}830}, ac);831if (iconDescription != null){832debugString ("[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.");833references.increment (iconDescription);834return iconDescription;835}836}837} else if ( AccessibleRole.CHECK_BOX == role ) {838/*839NOTE: The only case I know of in which a check box does not840have a name is when that check box is contained in a table.841842In this case it would be appropriate to use the display string843of the check box object as the name (in US English the display844string is typically either "true" or "false").845846I am using the AccessibleValue interface to obtain the display847string of the check box. If the Accessible Value is 1, I am848returning Boolean.TRUE.toString (), If the Accessible Value is8490, I am returning Boolean.FALSE.toString (). If the Accessible850Value is some other number, I will return the display string of851the current numerical value of the check box.852*/853final AccessibleValue av = InvocationUtils.invokeAndWait(new Callable<AccessibleValue>() {854@Override855public AccessibleValue call() throws Exception {856return ac.getAccessibleValue();857}858}, ac);859if ( null != av ) {860nameString = null;861Number value = InvocationUtils.invokeAndWait(new Callable<Number>() {862@Override863public Number call() throws Exception {864return av.getCurrentAccessibleValue();865}866}, ac);867if ( null != value ) {868if ( 1 == value.intValue () ) {869nameString = Boolean.TRUE.toString ();870} else if ( 0 == value.intValue () ) {871nameString = Boolean.FALSE.toString ();872} else {873nameString = value.toString ();874}875if ( null != nameString ) {876references.increment (nameString);877return nameString;878}879}880}881}882return null;883}884885/*886+887Beginning of the extended name search888+889*/890final AccessibleContext parentContextOuterTemp = parentContext;891String parentName = InvocationUtils.invokeAndWait(new Callable<String>() {892@Override893public String call() throws Exception {894return parentContextOuterTemp.getAccessibleName();895}896}, ac);897String parentDescription = InvocationUtils.invokeAndWait(new Callable<String>() {898@Override899public String call() throws Exception {900return parentContextOuterTemp.getAccessibleDescription();901}902}, ac);903904/*905Step 4:906=======907Special case for Slider Bar objects.908*/909if ( (AccessibleRole.SLIDER == role) &&910(AccessibleRole.PANEL == parentRole) &&911(null != parentName) ) {912debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from the Accessible Name of the SLIDER object's parent object.");913references.increment (parentName);914return parentName;915}916917boolean bIsEditCombo = false;918919AccessibleContext testContext = ac;920/*921Step 5:922=======923Special case for Edit Combo Boxes924*/925if ( (AccessibleRole.TEXT == role) &&926(AccessibleRole.COMBO_BOX == parentRole) ) {927bIsEditCombo = true;928if (null != parentName) {929debugString ("[INFO]: bk -- The Virtual Accessible Name for this Edit Combo box was obtained from the Accessible Name of the object's parent object.");930references.increment (parentName);931return parentName;932} else if (null != parentDescription) {933debugString ("[INFO]: bk -- The Virtual Accessible Name for this Edit Combo box was obtained from the Accessible Description of the object's parent object.");934references.increment (parentDescription);935return parentDescription;936}937testContext = parentContext;938parentRole = AccessibleRole.UNKNOWN;939parentContext = getAccessibleParentFromContext (testContext);940if ( null != parentContext ) {941final AccessibleContext parentContextInnerTemp = parentContext;942parentRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {943@Override944public AccessibleRole call() throws Exception {945return parentContextInnerTemp.getAccessibleRole();946}947}, ac);948}949}950951/*952Step 6:953=======954Attempt to get the Virtual Accessible Name of the object using the955Accessible Relation Set Info (the LABELED_BY Accessible Relation).956*/957{958final AccessibleContext parentContextTempInner = parentContext;959AccessibleRelationSet ars = InvocationUtils.invokeAndWait(new Callable<AccessibleRelationSet>() {960@Override961public AccessibleRelationSet call() throws Exception {962return parentContextTempInner.getAccessibleRelationSet();963}964}, ac);965if ( ars != null && (ars.size () > 0) && (ars.contains (AccessibleRelation.LABELED_BY)) ) {966AccessibleRelation labeledByRelation = ars.get (AccessibleRelation.LABELED_BY);967if (labeledByRelation != null) {968Object [] targets = labeledByRelation.getTarget ();969Object o = targets [0];970if (o instanceof Accessible) {971AccessibleContext labelContext = ((Accessible)o).getAccessibleContext ();972if (labelContext != null) {973String labelName = labelContext.getAccessibleName ();974String labelDescription = labelContext.getAccessibleDescription ();975if (null != labelName) {976debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained using the LABELED_BY AccessibleRelation -- Name Case.");977references.increment (labelName);978return labelName;979} else if (null != labelDescription) {980debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained using the LABELED_BY AccessibleRelation -- Description Case.");981references.increment (labelDescription);982return labelDescription;983}984}985}986}987}988}989990//Note: add AccessibleContext to use InvocationUtils.invokeAndWait991/*992Step 7:993=======994Search for a label object that is positioned either just to the left995or just above the object and get the Accessible Name of the Label996object.997*/998int testIndexMax = 0;999int testX = 0;1000int testY = 0;1001int testWidth = 0;1002int testHeight = 0;1003int targetX = 0;1004int targetY = 0;1005final AccessibleContext tempContext = testContext;1006int testIndex = InvocationUtils.invokeAndWait(new Callable<Integer>() {1007@Override1008public Integer call() throws Exception {1009return tempContext.getAccessibleIndexInParent();1010}1011}, ac);1012if ( null != parentContext ) {1013final AccessibleContext parentContextInnerTemp = parentContext;1014testIndexMax = InvocationUtils.invokeAndWait(new Callable<Integer>() {1015@Override1016public Integer call() throws Exception {1017return parentContextInnerTemp.getAccessibleChildrenCount() - 1;1018}1019}, ac);1020}1021testX = getAccessibleXcoordFromContext (testContext);1022testY = getAccessibleYcoordFromContext (testContext);1023testWidth = getAccessibleWidthFromContext (testContext);1024testHeight = getAccessibleHeightFromContext (testContext);1025targetX = testX + 2;1026targetY = testY + 2;10271028int childIndex = testIndex - 1;1029/*Accessible child = null;1030AccessibleContext childContext = null;1031AccessibleRole childRole = AccessibleRole.UNKNOWN;*/1032int childX = 0;1033int childY = 0;1034int childWidth = 0;1035int childHeight = 0;1036String childName = null;1037String childDescription = null;1038while (childIndex >= 0) {1039final int childIndexTemp = childIndex;1040final AccessibleContext parentContextInnerTemp = parentContext;1041final Accessible child = InvocationUtils.invokeAndWait(new Callable<Accessible>() {1042@Override1043public Accessible call() throws Exception {1044return parentContextInnerTemp.getAccessibleChild(childIndexTemp);1045}1046}, ac);1047if ( null != child ) {1048final AccessibleContext childContext = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {1049@Override1050public AccessibleContext call() throws Exception {1051return child.getAccessibleContext();1052}1053}, ac);1054if ( null != childContext ) {1055AccessibleRole childRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {1056@Override1057public AccessibleRole call() throws Exception {1058return childContext.getAccessibleRole();1059}1060}, ac);1061if ( AccessibleRole.LABEL == childRole ) {1062childX = getAccessibleXcoordFromContext (childContext);1063childY = getAccessibleYcoordFromContext (childContext);1064childWidth = getAccessibleWidthFromContext (childContext);1065childHeight = getAccessibleHeightFromContext (childContext);1066if ( (childX < testX) &&1067((childY <= targetY) && (targetY <= (childY + childHeight))) ) {1068childName = InvocationUtils.invokeAndWait(new Callable<String>() {1069@Override1070public String call() throws Exception {1071return childContext.getAccessibleName();1072}1073}, ac);1074if ( null != childName ) {1075debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from Accessible Name of a LABEL object positioned to the left of the object.");1076references.increment (childName);1077return childName;1078}1079childDescription = InvocationUtils.invokeAndWait(new Callable<String>() {1080@Override1081public String call() throws Exception {1082return childContext.getAccessibleDescription();1083}1084}, ac);1085if ( null != childDescription ) {1086debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from Accessible Description of a LABEL object positioned to the left of the object.");1087references.increment (childDescription);1088return childDescription;1089}1090} else if ( (childY < targetY) &&1091((childX <= targetX) && (targetX <= (childX + childWidth))) ) {1092childName = InvocationUtils.invokeAndWait(new Callable<String>() {1093@Override1094public String call() throws Exception {1095return childContext.getAccessibleName();1096}1097}, ac);1098if ( null != childName ) {1099debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from Accessible Name of a LABEL object positioned above the object.");1100references.increment (childName);1101return childName;1102}1103childDescription = InvocationUtils.invokeAndWait(new Callable<String>() {1104@Override1105public String call() throws Exception {1106return childContext.getAccessibleDescription();1107}1108}, ac);1109if ( null != childDescription ) {1110debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from Accessible Description of a LABEL object positioned above the object.");1111references.increment (childDescription);1112return childDescription;1113}1114}1115}1116}1117}1118childIndex --;1119}1120childIndex = testIndex + 1;1121while (childIndex <= testIndexMax) {1122final int childIndexTemp = childIndex;1123final AccessibleContext parentContextInnerTemp = parentContext;1124final Accessible child = InvocationUtils.invokeAndWait(new Callable<Accessible>() {1125@Override1126public Accessible call() throws Exception {1127return parentContextInnerTemp.getAccessibleChild(childIndexTemp);1128}1129}, ac);1130if ( null != child ) {1131final AccessibleContext childContext = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {1132@Override1133public AccessibleContext call() throws Exception {1134return child.getAccessibleContext();1135}1136}, ac);1137if ( null != childContext ) {1138AccessibleRole childRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {1139@Override1140public AccessibleRole call() throws Exception {1141return childContext.getAccessibleRole();1142}1143}, ac);1144if ( AccessibleRole.LABEL == childRole ) {1145childX = getAccessibleXcoordFromContext (childContext);1146childY = getAccessibleYcoordFromContext (childContext);1147childWidth = getAccessibleWidthFromContext (childContext);1148childHeight = getAccessibleHeightFromContext (childContext);1149if ( (childX < testX) &&1150((childY <= targetY) && (targetY <= (childY + childHeight))) ) {1151childName = InvocationUtils.invokeAndWait(new Callable<String>() {1152@Override1153public String call() throws Exception {1154return childContext.getAccessibleName();1155}1156}, ac);1157if ( null != childName ) {1158debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from Accessible Name of a LABEL object positioned to the left of the object.");1159references.increment (childName);1160return childName;1161}1162childDescription = InvocationUtils.invokeAndWait(new Callable<String>() {1163@Override1164public String call() throws Exception {1165return childContext.getAccessibleDescription();1166}1167}, ac);1168if ( null != childDescription ) {1169debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from Accessible Description of a LABEL object positioned to the left of the object.");1170references.increment (childDescription);1171return childDescription;1172}1173} else if ( (childY < targetY) &&1174((childX <= targetX) && (targetX <= (childX + childWidth))) ) {1175childName = InvocationUtils.invokeAndWait(new Callable<String>() {1176@Override1177public String call() throws Exception {1178return childContext.getAccessibleName();1179}1180}, ac);1181if ( null != childName ) {1182debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from Accessible Name of a LABEL object positioned above the object.");1183references.increment (childName);1184return childName;1185}1186childDescription = InvocationUtils.invokeAndWait(new Callable<String>() {1187@Override1188public String call() throws Exception {1189return childContext.getAccessibleDescription();1190}1191}, ac);1192if ( null != childDescription ) {1193debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from Accessible Description of a LABEL object positioned above the object.");1194references.increment (childDescription);1195return childDescription;1196}1197}1198}1199}1200}1201childIndex ++;1202}1203/*1204Step 8:1205=======1206Special case for combo boxes and text objects, based on a1207similar special case I found in some of our internal JAWS code.12081209Search for a button object that is positioned either just to the left1210or just above the object and get the Accessible Name of the button1211object.1212*/1213if ( (AccessibleRole.TEXT == role) ||1214(AccessibleRole.COMBO_BOX == role) ||1215(bIsEditCombo) ) {1216childIndex = testIndex - 1;1217while (childIndex >= 0) {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.PUSH_BUTTON == childRole ) ||1241( AccessibleRole.TOGGLE_BUTTON == childRole )) {1242childX = getAccessibleXcoordFromContext (childContext);1243childY = getAccessibleYcoordFromContext (childContext);1244childWidth = getAccessibleWidthFromContext (childContext);1245childHeight = getAccessibleHeightFromContext (childContext);1246if ( (childX < testX) &&1247((childY <= targetY) && (targetY <= (childY + childHeight))) ) {1248childName = InvocationUtils.invokeAndWait(new Callable<String>() {1249@Override1250public String call() throws Exception {1251return childContext.getAccessibleName();1252}1253}, ac);1254if ( null != childName ) {1255debugString ("[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.");1256references.increment (childName);1257return childName;1258}1259childDescription = InvocationUtils.invokeAndWait(new Callable<String>() {1260@Override1261public String call() throws Exception {1262return childContext.getAccessibleDescription();1263}1264}, ac);1265if ( null != childDescription ) {1266debugString ("[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.");1267references.increment (childDescription);1268return childDescription;1269}1270}1271}1272}1273}1274childIndex --;1275}1276childIndex = testIndex + 1;1277while (childIndex <= testIndexMax) {1278final int childIndexTemp = childIndex;1279final AccessibleContext parentContextInnerTemp = parentContext;1280final Accessible child = InvocationUtils.invokeAndWait(new Callable<Accessible>() {1281@Override1282public Accessible call() throws Exception {1283return parentContextInnerTemp.getAccessibleChild(childIndexTemp);1284}1285}, ac);1286if ( null != child ) {1287final AccessibleContext childContext = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {1288@Override1289public AccessibleContext call() throws Exception {1290return child.getAccessibleContext();1291}1292}, ac);1293if ( null != childContext ) {1294AccessibleRole childRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {1295@Override1296public AccessibleRole call() throws Exception {1297return childContext.getAccessibleRole();1298}1299}, ac);1300if ( ( AccessibleRole.PUSH_BUTTON == childRole ) ||1301( AccessibleRole.TOGGLE_BUTTON == childRole ) ) {1302childX = getAccessibleXcoordFromContext (childContext);1303childY = getAccessibleYcoordFromContext (childContext);1304childWidth = getAccessibleWidthFromContext (childContext);1305childHeight = getAccessibleHeightFromContext (childContext);1306if ( (childX < testX) &&1307((childY <= targetY) && (targetY <= (childY + childHeight))) ) {1308childName = InvocationUtils.invokeAndWait(new Callable<String>() {1309@Override1310public String call() throws Exception {1311return childContext.getAccessibleName();1312}1313}, ac);1314if ( null != childName ) {1315debugString ("[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.");1316references.increment (childName);1317return childName;1318}1319childDescription = InvocationUtils.invokeAndWait(new Callable<String>() {1320@Override1321public String call() throws Exception {1322return childContext.getAccessibleDescription();1323}1324}, ac);1325if ( null != childDescription ) {1326debugString ("[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.");1327references.increment (childDescription);1328return childDescription;1329}1330}1331}1332}1333}1334childIndex ++;1335}1336}1337return null;1338} else {1339debugString ("[ERROR]: AccessBridge::getVirtualAccessibleNameFromContext error - ac == null.");1340return null;1341}1342}13431344/**1345* returns the AccessibleDescription from an AccessibleContext1346*/1347private String getAccessibleDescriptionFromContext(final AccessibleContext ac) {1348if (ac != null) {1349String s = InvocationUtils.invokeAndWait(new Callable<String>() {1350@Override1351public String call() throws Exception {1352return ac.getAccessibleDescription();1353}1354}, ac);1355if (s != null) {1356references.increment(s);1357debugString("[INFO]: Returning AccessibleDescription from Context: " + s);1358return s;1359}1360} else {1361debugString("[ERROR]: getAccessibleDescriptionFromContext; ac = null");1362}1363return null;1364}13651366/**1367* returns the AccessibleRole from an AccessibleContext1368*/1369private String getAccessibleRoleStringFromContext(final AccessibleContext ac) {1370if (ac != null) {1371AccessibleRole role = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {1372@Override1373public AccessibleRole call() throws Exception {1374return ac.getAccessibleRole();1375}1376}, ac);1377if (role != null) {1378String s = role.toDisplayString(Locale.US);1379if (s != null) {1380references.increment(s);1381debugString("[INFO]: Returning AccessibleRole from Context: " + s);1382return s;1383}1384}1385} else {1386debugString("[ERROR]: getAccessibleRoleStringFromContext; ac = null");1387}1388return null;1389}13901391/**1392* return the AccessibleRole from an AccessibleContext in the en_US locale1393*/1394private String getAccessibleRoleStringFromContext_en_US(final AccessibleContext ac) {1395return getAccessibleRoleStringFromContext(ac);1396}13971398/**1399* return the AccessibleStates from an AccessibleContext1400*/1401private String getAccessibleStatesStringFromContext(final AccessibleContext ac) {1402if (ac != null) {1403AccessibleStateSet stateSet = InvocationUtils.invokeAndWait(new Callable<AccessibleStateSet>() {1404@Override1405public AccessibleStateSet call() throws Exception {1406return ac.getAccessibleStateSet();1407}1408}, ac);1409if (stateSet != null) {1410String s = stateSet.toString();1411if (s != null &&1412s.indexOf(AccessibleState.MANAGES_DESCENDANTS.toDisplayString(Locale.US)) == -1) {1413// Indicate whether this component manages its own1414// children1415AccessibleRole role = InvocationUtils.invokeAndWait(() -> {1416return ac.getAccessibleRole();1417}, ac);1418if (role == AccessibleRole.LIST ||1419role == AccessibleRole.TABLE ||1420role == AccessibleRole.TREE) {1421s += ",";1422s += AccessibleState.MANAGES_DESCENDANTS.toDisplayString(Locale.US);1423}1424references.increment(s);1425debugString("[INFO]: Returning AccessibleStateSet from Context: " + s);1426return s;1427}1428}1429} else {1430debugString("[ERROR]: getAccessibleStatesStringFromContext; ac = null");1431}1432return null;1433}14341435/**1436* returns the AccessibleStates from an AccessibleContext in the en_US locale1437*/1438private String getAccessibleStatesStringFromContext_en_US(final AccessibleContext ac) {1439if (ac != null) {1440AccessibleStateSet stateSet = InvocationUtils.invokeAndWait(new Callable<AccessibleStateSet>() {1441@Override1442public AccessibleStateSet call() throws Exception {1443return ac.getAccessibleStateSet();1444}1445}, ac);1446if (stateSet != null) {1447String s = "";1448AccessibleState[] states = stateSet.toArray();1449if (states != null && states.length > 0) {1450s = states[0].toDisplayString(Locale.US);1451for (int i = 1; i < states.length; i++) {1452s = s + "," + states[i].toDisplayString(Locale.US);1453}1454}1455references.increment(s);1456debugString("[INFO]: Returning AccessibleStateSet en_US from Context: " + s);1457return s;1458}1459}1460debugString("[ERROR]: getAccessibleStatesStringFromContext; ac = null");1461return null;1462}14631464/**1465* returns the AccessibleParent from an AccessibleContext1466*/1467private AccessibleContext getAccessibleParentFromContext(final AccessibleContext ac) {1468if (ac==null)1469return null;1470return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {1471@Override1472public AccessibleContext call() throws Exception {1473Accessible a = ac.getAccessibleParent();1474if (a != null) {1475AccessibleContext apc = a.getAccessibleContext();1476if (apc != null) {1477return apc;1478}1479}1480return null;1481}1482}, ac);1483}14841485/**1486* returns the AccessibleIndexInParent from an AccessibleContext1487*/1488private int getAccessibleIndexInParentFromContext(final AccessibleContext ac) {1489if (ac==null)1490return -1;1491return InvocationUtils.invokeAndWait(new Callable<Integer>() {1492@Override1493public Integer call() throws Exception {1494return ac.getAccessibleIndexInParent();1495}1496}, ac);1497}14981499/**1500* returns the AccessibleChild count from an AccessibleContext1501*/1502private int getAccessibleChildrenCountFromContext(final AccessibleContext ac) {1503if (ac==null)1504return -1;1505return InvocationUtils.invokeAndWait(new Callable<Integer>() {1506@Override1507public Integer call() throws Exception {1508return ac.getAccessibleChildrenCount();1509}1510}, ac);1511}15121513/**1514* returns the AccessibleChild Context from an AccessibleContext1515*/1516private AccessibleContext getAccessibleChildFromContext(final AccessibleContext ac, final int index) {15171518if (ac == null) {1519return null;1520}15211522final JTable table = InvocationUtils.invokeAndWait(new Callable<JTable>() {1523@Override1524public JTable call() throws Exception {1525// work-around for AccessibleJTable.getCurrentAccessibleContext returning1526// wrong renderer component when cell contains more than one component1527Accessible parent = ac.getAccessibleParent();1528if (parent != null) {1529int indexInParent = ac.getAccessibleIndexInParent();1530Accessible child =1531parent.getAccessibleContext().getAccessibleChild(indexInParent);1532if (child instanceof JTable) {1533return (JTable) child;1534}1535}1536return null;1537}1538}, ac);15391540if (table == null) {1541return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {1542@Override1543public AccessibleContext call() throws Exception {1544Accessible a = ac.getAccessibleChild(index);1545if (a != null) {1546return a.getAccessibleContext();1547}1548return null;1549}1550}, ac);1551}15521553final AccessibleTable at = getAccessibleTableFromContext(ac);15541555final int row = getAccessibleTableRow(at, index);1556final int column = getAccessibleTableColumn(at, index);15571558return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {1559@Override1560public AccessibleContext call() throws Exception {1561TableCellRenderer renderer = table.getCellRenderer(row, column);1562if (renderer == null) {1563Class<?> columnClass = table.getColumnClass(column);1564renderer = table.getDefaultRenderer(columnClass);1565}1566Component component =1567renderer.getTableCellRendererComponent(table, table.getValueAt(row, column),1568false, false, row, column);1569if (component instanceof Accessible) {1570return component.getAccessibleContext();1571}1572return null;1573}1574}, ac);1575}15761577/**1578* returns the AccessibleComponent bounds on screen from an AccessibleContext1579*/1580private Rectangle getAccessibleBoundsOnScreenFromContext(final AccessibleContext ac) {1581if(ac==null)1582return null;1583return InvocationUtils.invokeAndWait(new Callable<Rectangle>() {1584@Override1585public Rectangle call() throws Exception {1586AccessibleComponent acmp = ac.getAccessibleComponent();1587if (acmp != null) {1588Rectangle r = acmp.getBounds();1589if (r != null) {1590try {1591Point p = acmp.getLocationOnScreen();1592if (p != null) {1593r.x = p.x;1594r.y = p.y;1595return r;1596}1597} catch (Exception e) {1598return null;1599}1600}1601}1602return null;1603}1604}, ac);1605}16061607/**1608* returns the AccessibleComponent x-coord from an AccessibleContext1609*/1610private int getAccessibleXcoordFromContext(AccessibleContext ac) {1611if (ac != null) {1612Rectangle r = getAccessibleBoundsOnScreenFromContext(ac);1613if (r != null) {1614debugString("[INFO]: Returning Accessible x coord from Context: " + r.x);1615return r.x;1616}1617} else {1618debugString("[ERROR]: getAccessibleXcoordFromContext ac = null");1619}1620return -1;1621}16221623/**1624* returns the AccessibleComponent y-coord from an AccessibleContext1625*/1626private int getAccessibleYcoordFromContext(AccessibleContext ac) {1627debugString("[INFO]: getAccessibleYcoordFromContext() called");1628if (ac != null) {1629Rectangle r = getAccessibleBoundsOnScreenFromContext(ac);1630if (r != null) {1631return r.y;1632}1633} else {1634debugString("[ERROR]: getAccessibleYcoordFromContext; ac = null");1635}1636return -1;1637}16381639/**1640* returns the AccessibleComponent height from an AccessibleContext1641*/1642private int getAccessibleHeightFromContext(AccessibleContext ac) {1643if (ac != null) {1644Rectangle r = getAccessibleBoundsOnScreenFromContext(ac);1645if (r != null) {1646return r.height;1647}1648} else {1649debugString("[ERROR]: getAccessibleHeightFromContext; ac = null");1650}1651return -1;1652}16531654/**1655* returns the AccessibleComponent width from an AccessibleContext1656*/1657private int getAccessibleWidthFromContext(AccessibleContext ac) {1658if (ac != null) {1659Rectangle r = getAccessibleBoundsOnScreenFromContext(ac);1660if (r != null) {1661return r.width;1662}1663} else {1664debugString("[ERROR]: getAccessibleWidthFromContext; ac = null");1665}1666return -1;1667}166816691670/**1671* returns the AccessibleComponent from an AccessibleContext1672*/1673private AccessibleComponent getAccessibleComponentFromContext(AccessibleContext ac) {1674if (ac != null) {1675AccessibleComponent acmp = InvocationUtils.invokeAndWait(() -> {1676return ac.getAccessibleComponent();1677}, ac);1678if (acmp != null) {1679debugString("[INFO]: Returning AccessibleComponent Context");1680return acmp;1681}1682} else {1683debugString("[ERROR]: getAccessibleComponentFromContext; ac = null");1684}1685return null;1686}16871688/**1689* returns the AccessibleAction from an AccessibleContext1690*/1691private AccessibleAction getAccessibleActionFromContext(final AccessibleContext ac) {1692debugString("[INFO]: Returning AccessibleAction Context");1693return ac == null ? null : InvocationUtils.invokeAndWait(new Callable<AccessibleAction>() {1694@Override1695public AccessibleAction call() throws Exception {1696return ac.getAccessibleAction();1697}1698}, ac);1699}17001701/**1702* returns the AccessibleSelection from an AccessibleContext1703*/1704private AccessibleSelection getAccessibleSelectionFromContext(final AccessibleContext ac) {1705return ac == null ? null : InvocationUtils.invokeAndWait(new Callable<AccessibleSelection>() {1706@Override1707public AccessibleSelection call() throws Exception {1708return ac.getAccessibleSelection();1709}1710}, ac);1711}17121713/**1714* return the AccessibleText from an AccessibleContext1715*/1716private AccessibleText getAccessibleTextFromContext(final AccessibleContext ac) {1717return ac == null ? null : InvocationUtils.invokeAndWait(new Callable<AccessibleText>() {1718@Override1719public AccessibleText call() throws Exception {1720return ac.getAccessibleText();1721}1722}, ac);1723}17241725/**1726* return the AccessibleComponent from an AccessibleContext1727*/1728private AccessibleValue getAccessibleValueFromContext(final AccessibleContext ac) {1729return ac == null ? null : InvocationUtils.invokeAndWait(new Callable<AccessibleValue>() {1730@Override1731public AccessibleValue call() throws Exception {1732return ac.getAccessibleValue();1733}1734}, ac);1735}17361737/* ===== AccessibleText methods ===== */17381739/**1740* returns the bounding rectangle for the text cursor1741* XXX1742*/1743private Rectangle getCaretLocation(final AccessibleContext ac) {1744debugString("[INFO]: getCaretLocation");1745if (ac==null)1746return null;1747return InvocationUtils.invokeAndWait(new Callable<Rectangle>() {1748@Override1749public Rectangle call() throws Exception {1750// workaround for JAAPI not returning cursor bounding rectangle1751Rectangle r = null;1752Accessible parent = ac.getAccessibleParent();1753if (parent instanceof Accessible) {1754int indexInParent = ac.getAccessibleIndexInParent();1755Accessible child =1756parent.getAccessibleContext().getAccessibleChild(indexInParent);17571758if (child instanceof JTextComponent) {1759JTextComponent text = (JTextComponent) child;1760try {1761r = text.modelToView2D(text.getCaretPosition()).getBounds();1762if (r != null) {1763Point p = text.getLocationOnScreen();1764r.translate(p.x, p.y);1765}1766} catch (BadLocationException ble) {1767}1768}1769}1770return r;1771}1772}, ac);1773}17741775/**1776* returns the x-coordinate for the text cursor rectangle1777*/1778private int getCaretLocationX(AccessibleContext ac) {1779Rectangle r = getCaretLocation(ac);1780if (r != null) {1781return r.x;1782} else {1783return -1;1784}1785}17861787/**1788* returns the y-coordinate for the text cursor rectangle1789*/1790private int getCaretLocationY(AccessibleContext ac) {1791Rectangle r = getCaretLocation(ac);1792if (r != null) {1793return r.y;1794} else {1795return -1;1796}1797}17981799/**1800* returns the height for the text cursor rectangle1801*/1802private int getCaretLocationHeight(AccessibleContext ac) {1803Rectangle r = getCaretLocation(ac);1804if (r != null) {1805return r.height;1806} else {1807return -1;1808}1809}18101811/**1812* returns the width for the text cursor rectangle1813*/1814private int getCaretLocationWidth(AccessibleContext ac) {1815Rectangle r = getCaretLocation(ac);1816if (r != null) {1817return r.width;1818} else {1819return -1;1820}1821}18221823/**1824* returns the character count from an AccessibleContext1825*/1826private int getAccessibleCharCountFromContext(final AccessibleContext ac) {1827if (ac==null)1828return -1;1829return InvocationUtils.invokeAndWait(new Callable<Integer>() {1830@Override1831public Integer call() throws Exception {1832AccessibleText at = ac.getAccessibleText();1833if (at != null) {1834return at.getCharCount();1835}1836return -1;1837}1838}, ac);1839}18401841/**1842* returns the caret position from an AccessibleContext1843*/1844private int getAccessibleCaretPositionFromContext(final AccessibleContext ac) {1845if (ac==null)1846return -1;1847return InvocationUtils.invokeAndWait(new Callable<Integer>() {1848@Override1849public Integer call() throws Exception {1850AccessibleText at = ac.getAccessibleText();1851if (at != null) {1852return at.getCaretPosition();1853}1854return -1;1855}1856}, ac);1857}18581859/**1860* Return the index at a specific point from an AccessibleContext1861* Point(x, y) is in screen coordinates.1862*/1863private int getAccessibleIndexAtPointFromContext(final AccessibleContext ac,1864final int x, final int y) {1865debugString("[INFO]: getAccessibleIndexAtPointFromContext: x = "+x+"; y = "+y);1866if (ac==null)1867return -1;1868return InvocationUtils.invokeAndWait(new Callable<Integer>() {1869@Override1870public Integer call() throws Exception {1871AccessibleText at = ac.getAccessibleText();1872AccessibleComponent acomp = ac.getAccessibleComponent();1873if (at != null && acomp != null) {1874// Convert x and y from screen coordinates to1875// local coordinates.1876try {1877Point p = acomp.getLocationOnScreen();1878int x1, y1;1879if (p != null) {1880x1 = x - p.x;1881if (x1 < 0) {1882x1 = 0;1883}1884y1 = y - p.y;1885if (y1 < 0) {1886y1 = 0;1887}18881889Point newPoint = new Point(x1, y1);1890int indexAtPoint = at.getIndexAtPoint(new Point(x1, y1));1891return indexAtPoint;1892}1893} catch (Exception e) {1894}1895}1896return -1;1897}1898}, ac);1899}19001901/**1902* return the letter at a specific point from an AccessibleContext1903*/1904private String getAccessibleLetterAtIndexFromContext(final AccessibleContext ac, final int index) {1905if (ac != null) {1906String s = InvocationUtils.invokeAndWait(new Callable<String>() {1907@Override1908public String call() throws Exception {1909AccessibleText at = ac.getAccessibleText();1910if (at == null) return null;1911return at.getAtIndex(AccessibleText.CHARACTER, index);1912}1913}, ac);1914if (s != null) {1915references.increment(s);1916return s;1917}1918} else {1919debugString("[ERROR]: getAccessibleLetterAtIndexFromContext; ac = null");1920}1921return null;1922}19231924/**1925* return the word at a specific point from an AccessibleContext1926*/1927private String getAccessibleWordAtIndexFromContext(final AccessibleContext ac, final int index) {1928if (ac != null) {1929String s = InvocationUtils.invokeAndWait(new Callable<String>() {1930@Override1931public String call() throws Exception {1932AccessibleText at = ac.getAccessibleText();1933if (at == null) return null;1934return at.getAtIndex(AccessibleText.WORD, index);1935}1936}, ac);1937if (s != null) {1938references.increment(s);1939return s;1940}1941} else {1942debugString("[ERROR]: getAccessibleWordAtIndexFromContext; ac = null");1943}1944return null;1945}19461947/**1948* return the sentence at a specific point from an AccessibleContext1949*/1950private String getAccessibleSentenceAtIndexFromContext(final AccessibleContext ac, final int index) {1951if (ac != null) {1952String s = InvocationUtils.invokeAndWait(new Callable<String>() {1953@Override1954public String call() throws Exception {1955AccessibleText at = ac.getAccessibleText();1956if (at == null) return null;1957return at.getAtIndex(AccessibleText.SENTENCE, index);1958}1959}, ac);1960if (s != null) {1961references.increment(s);1962return s;1963}1964} else {1965debugString("[ERROR]: getAccessibleSentenceAtIndexFromContext; ac = null");1966}1967return null;1968}19691970/**1971* return the text selection start from an AccessibleContext1972*/1973private int getAccessibleTextSelectionStartFromContext(final AccessibleContext ac) {1974if (ac == null) return -1;1975return InvocationUtils.invokeAndWait(new Callable<Integer>() {1976@Override1977public Integer call() throws Exception {1978AccessibleText at = ac.getAccessibleText();1979if (at != null) {1980return at.getSelectionStart();1981}1982return -1;1983}1984}, ac);1985}19861987/**1988* return the text selection end from an AccessibleContext1989*/1990private int getAccessibleTextSelectionEndFromContext(final AccessibleContext ac) {1991if (ac == null)1992return -1;1993return InvocationUtils.invokeAndWait(new Callable<Integer>() {1994@Override1995public Integer call() throws Exception {1996AccessibleText at = ac.getAccessibleText();1997if (at != null) {1998return at.getSelectionEnd();1999}2000return -1;2001}2002}, ac);2003}20042005/**2006* return the selected text from an AccessibleContext2007*/2008private String getAccessibleTextSelectedTextFromContext(final AccessibleContext ac) {2009if (ac != null) {2010String s = InvocationUtils.invokeAndWait(new Callable<String>() {2011@Override2012public String call() throws Exception {2013AccessibleText at = ac.getAccessibleText();2014if (at == null) return null;2015return at.getSelectedText();2016}2017}, ac);2018if (s != null) {2019references.increment(s);2020return s;2021}2022} else {2023debugString("[ERROR]: getAccessibleTextSelectedTextFromContext; ac = null");2024}2025return null;2026}20272028/**2029* return the attribute string at a given index from an AccessibleContext2030*/2031private String getAccessibleAttributesAtIndexFromContext(final AccessibleContext ac,2032final int index) {2033if (ac == null)2034return null;2035AttributeSet as = InvocationUtils.invokeAndWait(new Callable<AttributeSet>() {2036@Override2037public AttributeSet call() throws Exception {2038AccessibleText at = ac.getAccessibleText();2039if (at != null) {2040return at.getCharacterAttribute(index);2041}2042return null;2043}2044}, ac);2045String s = expandStyleConstants(as);2046if (s != null) {2047references.increment(s);2048return s;2049}2050return null;2051}20522053/**2054* Get line info: left index of line2055*2056* algorithm: cast back, doubling each time,2057* 'till find line boundaries2058*2059* return -1 if we can't get the info (e.g. index or at passed in2060* is bogus; etc.)2061*/2062private int getAccessibleTextLineLeftBoundsFromContext(final AccessibleContext ac,2063final int index) {2064if (ac == null)2065return -1;2066return InvocationUtils.invokeAndWait(new Callable<Integer>() {2067@Override2068public Integer call() throws Exception {2069AccessibleText at = ac.getAccessibleText();2070if (at != null) {2071int lineStart;2072int offset;2073Rectangle charRect;2074Rectangle indexRect = at.getCharacterBounds(index);2075int textLen = at.getCharCount();2076if (indexRect == null) {2077return -1;2078}2079// find the start of the line2080//2081offset = 1;2082lineStart = index - offset < 0 ? 0 : index - offset;2083charRect = at.getCharacterBounds(lineStart);2084// slouch behind beginning of line2085while (charRect != null2086&& charRect.y >= indexRect.y2087&& lineStart > 0) {2088offset = offset << 1;2089lineStart = index - offset < 0 ? 0 : index - offset;2090charRect = at.getCharacterBounds(lineStart);2091}2092if (lineStart == 0) { // special case: we're on the first line!2093// we found it!2094} else {2095offset = offset >> 1; // know boundary within last expansion2096// ground forward to beginning of line2097while (offset > 0) {2098charRect = at.getCharacterBounds(lineStart + offset);2099if (charRect.y < indexRect.y) { // still before line2100lineStart += offset;2101} else {2102// leave lineStart alone, it's close!2103}2104offset = offset >> 1;2105}2106// subtract one 'cause we're already too far...2107lineStart += 1;2108}2109return lineStart;2110}2111return -1;2112}2113}, ac);2114}21152116/**2117* Get line info: right index of line2118*2119* algorithm: cast back, doubling each time,2120* 'till find line boundaries2121*2122* return -1 if we can't get the info (e.g. index or at passed in2123* is bogus; etc.)2124*/2125private int getAccessibleTextLineRightBoundsFromContext(final AccessibleContext ac, final int index) {2126if(ac == null)2127return -1;2128return InvocationUtils.invokeAndWait(new Callable<Integer>() {2129@Override2130public Integer call() throws Exception {2131AccessibleText at = ac.getAccessibleText();2132if (at != null) {2133int lineEnd;2134int offset;2135Rectangle charRect;2136Rectangle indexRect = at.getCharacterBounds(index);2137int textLen = at.getCharCount();2138if (indexRect == null) {2139return -1;2140}2141// find the end of the line2142//2143offset = 1;2144lineEnd = index + offset > textLen - 12145? textLen - 1 : index + offset;2146charRect = at.getCharacterBounds(lineEnd);2147// push past end of line2148while (charRect != null &&2149charRect.y <= indexRect.y &&2150lineEnd < textLen - 1) {2151offset = offset << 1;2152lineEnd = index + offset > textLen - 12153? textLen - 1 : index + offset;2154charRect = at.getCharacterBounds(lineEnd);2155}2156if (lineEnd == textLen - 1) { // special case: on the last line!2157// we found it!2158} else {2159offset = offset >> 1; // know boundary within last expansion2160// pull back to end of line2161while (offset > 0) {2162charRect = at.getCharacterBounds(lineEnd - offset);2163if (charRect.y > indexRect.y) { // still beyond line2164lineEnd -= offset;2165} else {2166// leave lineEnd alone, it's close!2167}2168offset = offset >> 1;2169}2170// subtract one 'cause we're already too far...2171lineEnd -= 1;2172}2173return lineEnd;2174}2175return -1;2176}2177}, ac);2178}21792180/**2181* Get a range of text; null if indicies are bogus2182*/2183private String getAccessibleTextRangeFromContext(final AccessibleContext ac,2184final int start, final int end) {2185String s = InvocationUtils.invokeAndWait(new Callable<String>() {2186@Override2187public String call() throws Exception {2188if (ac != null) {2189AccessibleText at = ac.getAccessibleText();2190if (at != null) {2191// start - end is inclusive2192if (start > end) {2193return null;2194}2195if (end >= at.getCharCount()) {2196return null;2197}2198StringBuffer buf = new StringBuffer(end - start + 1);2199for (int i = start; i <= end; i++) {2200buf.append(at.getAtIndex(AccessibleText.CHARACTER, i));2201}2202return buf.toString();2203}2204}2205return null;2206}2207}, ac);2208if (s != null) {2209references.increment(s);2210return s;2211} else {2212return null;2213}2214}22152216/**2217* return the AttributeSet object at a given index from an AccessibleContext2218*/2219private AttributeSet getAccessibleAttributeSetAtIndexFromContext(final AccessibleContext ac,2220final int index) {2221return InvocationUtils.invokeAndWait(new Callable<AttributeSet>() {2222@Override2223public AttributeSet call() throws Exception {2224if (ac != null) {2225AccessibleText at = ac.getAccessibleText();2226if (at != null) {2227AttributeSet as = at.getCharacterAttribute(index);2228if (as != null) {2229AccessBridge.this.references.increment(as);2230return as;2231}2232}2233}2234return null;2235}2236}, ac);2237}223822392240/**2241* return the bounding rectangle at index from an AccessibleContext2242*/2243private Rectangle getAccessibleTextRectAtIndexFromContext(final AccessibleContext ac,2244final int index) {2245// want to do this in global coords, so need to combine w/ac global coords2246Rectangle r = InvocationUtils.invokeAndWait(new Callable<Rectangle>() {2247@Override2248public Rectangle call() throws Exception {2249// want to do this in global coords, so need to combine w/ac global coords2250if (ac != null) {2251AccessibleText at = ac.getAccessibleText();2252if (at != null) {2253Rectangle rect = at.getCharacterBounds(index);2254if (rect != null) {2255String s = at.getAtIndex(AccessibleText.CHARACTER, index);2256if (s != null && s.equals("\n")) {2257rect.width = 0;2258}2259return rect;2260}2261}2262}2263return null;2264}2265}, ac);2266Rectangle acRect = getAccessibleBoundsOnScreenFromContext(ac);2267if (r != null && acRect != null) {2268r.translate(acRect.x, acRect.y);2269return r;2270}2271return null;2272}22732274/**2275* return the AccessibleText character x-coord at index from an AccessibleContext2276*/2277private int getAccessibleXcoordTextRectAtIndexFromContext(AccessibleContext ac, int index) {2278if (ac != null) {2279Rectangle r = getAccessibleTextRectAtIndexFromContext(ac, index);2280if (r != null) {2281return r.x;2282}2283} else {2284debugString("[ERROR]: getAccessibleXcoordTextRectAtIndexFromContext; ac = null");2285}2286return -1;2287}22882289/**2290* return the AccessibleText character y-coord at index from an AccessibleContext2291*/2292private int getAccessibleYcoordTextRectAtIndexFromContext(AccessibleContext ac, int index) {2293if (ac != null) {2294Rectangle r = getAccessibleTextRectAtIndexFromContext(ac, index);2295if (r != null) {2296return r.y;2297}2298} else {2299debugString("[ERROR]: getAccessibleYcoordTextRectAtIndexFromContext; ac = null");2300}2301return -1;2302}23032304/**2305* return the AccessibleText character height at index from an AccessibleContext2306*/2307private int getAccessibleHeightTextRectAtIndexFromContext(AccessibleContext ac, int index) {2308if (ac != null) {2309Rectangle r = getAccessibleTextRectAtIndexFromContext(ac, index);2310if (r != null) {2311return r.height;2312}2313} else {2314debugString("[ERROR]: getAccessibleHeightTextRectAtIndexFromContext; ac = null");2315}2316return -1;2317}23182319/**2320* return the AccessibleText character width at index from an AccessibleContext2321*/2322private int getAccessibleWidthTextRectAtIndexFromContext(AccessibleContext ac, int index) {2323if (ac != null) {2324Rectangle r = getAccessibleTextRectAtIndexFromContext(ac, index);2325if (r != null) {2326return r.width;2327}2328} else {2329debugString("[ERROR]: getAccessibleWidthTextRectAtIndexFromContext; ac = null");2330}2331return -1;2332}23332334/* ===== AttributeSet methods for AccessibleText ===== */23352336/**2337* return the bold setting from an AttributeSet2338*/2339private boolean getBoldFromAttributeSet(AttributeSet as) {2340if (as != null) {2341return StyleConstants.isBold(as);2342} else {2343debugString("[ERROR]: getBoldFromAttributeSet; as = null");2344}2345return false;2346}23472348/**2349* return the italic setting from an AttributeSet2350*/2351private boolean getItalicFromAttributeSet(AttributeSet as) {2352if (as != null) {2353return StyleConstants.isItalic(as);2354} else {2355debugString("[ERROR]: getItalicFromAttributeSet; as = null");2356}2357return false;2358}23592360/**2361* return the underline setting from an AttributeSet2362*/2363private boolean getUnderlineFromAttributeSet(AttributeSet as) {2364if (as != null) {2365return StyleConstants.isUnderline(as);2366} else {2367debugString("[ERROR]: getUnderlineFromAttributeSet; as = null");2368}2369return false;2370}23712372/**2373* return the strikethrough setting from an AttributeSet2374*/2375private boolean getStrikethroughFromAttributeSet(AttributeSet as) {2376if (as != null) {2377return StyleConstants.isStrikeThrough(as);2378} else {2379debugString("[ERROR]: getStrikethroughFromAttributeSet; as = null");2380}2381return false;2382}23832384/**2385* return the superscript setting from an AttributeSet2386*/2387private boolean getSuperscriptFromAttributeSet(AttributeSet as) {2388if (as != null) {2389return StyleConstants.isSuperscript(as);2390} else {2391debugString("[ERROR]: getSuperscriptFromAttributeSet; as = null");2392}2393return false;2394}23952396/**2397* return the subscript setting from an AttributeSet2398*/2399private boolean getSubscriptFromAttributeSet(AttributeSet as) {2400if (as != null) {2401return StyleConstants.isSubscript(as);2402} else {2403debugString("[ERROR]: getSubscriptFromAttributeSet; as = null");2404}2405return false;2406}24072408/**2409* return the background color from an AttributeSet2410*/2411private String getBackgroundColorFromAttributeSet(AttributeSet as) {2412if (as != null) {2413String s = StyleConstants.getBackground(as).toString();2414if (s != null) {2415references.increment(s);2416return s;2417}2418} else {2419debugString("[ERROR]: getBackgroundColorFromAttributeSet; as = null");2420}2421return null;2422}24232424/**2425* return the foreground color from an AttributeSet2426*/2427private String getForegroundColorFromAttributeSet(AttributeSet as) {2428if (as != null) {2429String s = StyleConstants.getForeground(as).toString();2430if (s != null) {2431references.increment(s);2432return s;2433}2434} else {2435debugString("[ERROR]: getForegroundColorFromAttributeSet; as = null");2436}2437return null;2438}24392440/**2441* return the font family from an AttributeSet2442*/2443private String getFontFamilyFromAttributeSet(AttributeSet as) {2444if (as != null) {2445String s = StyleConstants.getFontFamily(as).toString();2446if (s != null) {2447references.increment(s);2448return s;2449}2450} else {2451debugString("[ERROR]: getFontFamilyFromAttributeSet; as = null");2452}2453return null;2454}24552456/**2457* return the font size from an AttributeSet2458*/2459private int getFontSizeFromAttributeSet(AttributeSet as) {2460if (as != null) {2461return StyleConstants.getFontSize(as);2462} else {2463debugString("[ERROR]: getFontSizeFromAttributeSet; as = null");2464}2465return -1;2466}24672468/**2469* return the alignment from an AttributeSet2470*/2471private int getAlignmentFromAttributeSet(AttributeSet as) {2472if (as != null) {2473return StyleConstants.getAlignment(as);2474} else {2475debugString("[ERROR]: getAlignmentFromAttributeSet; as = null");2476}2477return -1;2478}24792480/**2481* return the BiDi level from an AttributeSet2482*/2483private int getBidiLevelFromAttributeSet(AttributeSet as) {2484if (as != null) {2485return StyleConstants.getBidiLevel(as);2486} else {2487debugString("[ERROR]: getBidiLevelFromAttributeSet; as = null");2488}2489return -1;2490}249124922493/**2494* return the first line indent from an AttributeSet2495*/2496private float getFirstLineIndentFromAttributeSet(AttributeSet as) {2497if (as != null) {2498return StyleConstants.getFirstLineIndent(as);2499} else {2500debugString("[ERROR]: getFirstLineIndentFromAttributeSet; as = null");2501}2502return -1;2503}25042505/**2506* return the left indent from an AttributeSet2507*/2508private float getLeftIndentFromAttributeSet(AttributeSet as) {2509if (as != null) {2510return StyleConstants.getLeftIndent(as);2511} else {2512debugString("[ERROR]: getLeftIndentFromAttributeSet; as = null");2513}2514return -1;2515}25162517/**2518* return the right indent from an AttributeSet2519*/2520private float getRightIndentFromAttributeSet(AttributeSet as) {2521if (as != null) {2522return StyleConstants.getRightIndent(as);2523} else {2524debugString("[ERROR]: getRightIndentFromAttributeSet; as = null");2525}2526return -1;2527}25282529/**2530* return the line spacing from an AttributeSet2531*/2532private float getLineSpacingFromAttributeSet(AttributeSet as) {2533if (as != null) {2534return StyleConstants.getLineSpacing(as);2535} else {2536debugString("[ERROR]: getLineSpacingFromAttributeSet; as = null");2537}2538return -1;2539}25402541/**2542* return the space above from an AttributeSet2543*/2544private float getSpaceAboveFromAttributeSet(AttributeSet as) {2545if (as != null) {2546return StyleConstants.getSpaceAbove(as);2547} else {2548debugString("[ERROR]: getSpaceAboveFromAttributeSet; as = null");2549}2550return -1;2551}25522553/**2554* return the space below from an AttributeSet2555*/2556private float getSpaceBelowFromAttributeSet(AttributeSet as) {2557if (as != null) {2558return StyleConstants.getSpaceBelow(as);2559} else {2560debugString("[ERROR]: getSpaceBelowFromAttributeSet; as = null");2561}2562return -1;2563}25642565/**2566* Enumerate all StyleConstants in the AttributeSet2567*2568* We need to check explicitly, 'cause of the HTML package conversion2569* mechanism (they may not be stored as StyleConstants, just translated2570* to them when asked).2571*2572* (Use convenience methods where they are defined...)2573*2574* Not checking the following (which the IBM SNS guidelines says2575* should be defined):2576* - ComponentElementName2577* - IconElementName2578* - NameAttribute2579* - ResolveAttribute2580*/2581private String expandStyleConstants(AttributeSet as) {2582Color c;2583Object o;2584String attrString = "";25852586// ---------- check for various Character Constants25872588attrString += "BidiLevel = " + StyleConstants.getBidiLevel(as);25892590final Component comp = StyleConstants.getComponent(as);2591if (comp != null) {2592if (comp instanceof Accessible) {2593final AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {2594@Override2595public AccessibleContext call() throws Exception {2596return comp.getAccessibleContext();2597}2598}, comp);2599if (ac != null) {2600attrString += "; Accessible Component = " + InvocationUtils.invokeAndWait(new Callable<String>() {2601@Override2602public String call() throws Exception {2603return ac.getAccessibleName();2604}2605}, ac);2606} else {2607attrString += "; Innaccessible Component = " + comp;2608}2609} else {2610attrString += "; Innaccessible Component = " + comp;2611}2612}26132614Icon i = StyleConstants.getIcon(as);2615if (i != null) {2616if (i instanceof ImageIcon) {2617attrString += "; ImageIcon = " + ((ImageIcon) i).getDescription();2618} else {2619attrString += "; Icon = " + i;2620}2621}26222623attrString += "; FontFamily = " + StyleConstants.getFontFamily(as);26242625attrString += "; FontSize = " + StyleConstants.getFontSize(as);26262627if (StyleConstants.isBold(as)) {2628attrString += "; bold";2629}26302631if (StyleConstants.isItalic(as)) {2632attrString += "; italic";2633}26342635if (StyleConstants.isUnderline(as)) {2636attrString += "; underline";2637}26382639if (StyleConstants.isStrikeThrough(as)) {2640attrString += "; strikethrough";2641}26422643if (StyleConstants.isSuperscript(as)) {2644attrString += "; superscript";2645}26462647if (StyleConstants.isSubscript(as)) {2648attrString += "; subscript";2649}26502651c = StyleConstants.getForeground(as);2652if (c != null) {2653attrString += "; Foreground = " + c;2654}26552656c = StyleConstants.getBackground(as);2657if (c != null) {2658attrString += "; Background = " + c;2659}26602661attrString += "; FirstLineIndent = " + StyleConstants.getFirstLineIndent(as);26622663attrString += "; RightIndent = " + StyleConstants.getRightIndent(as);26642665attrString += "; LeftIndent = " + StyleConstants.getLeftIndent(as);26662667attrString += "; LineSpacing = " + StyleConstants.getLineSpacing(as);26682669attrString += "; SpaceAbove = " + StyleConstants.getSpaceAbove(as);26702671attrString += "; SpaceBelow = " + StyleConstants.getSpaceBelow(as);26722673attrString += "; Alignment = " + StyleConstants.getAlignment(as);26742675TabSet ts = StyleConstants.getTabSet(as);2676if (ts != null) {2677attrString += "; TabSet = " + ts;2678}26792680return attrString;2681}268226832684/* ===== AccessibleValue methods ===== */26852686/**2687* return the AccessibleValue current value from an AccessibleContext2688* returned using a String 'cause the value is a java Number2689*2690*/2691private String getCurrentAccessibleValueFromContext(final AccessibleContext ac) {2692if (ac != null) {2693final Number value = InvocationUtils.invokeAndWait(new Callable<Number>() {2694@Override2695public Number call() throws Exception {2696AccessibleValue av = ac.getAccessibleValue();2697if (av == null) return null;2698return av.getCurrentAccessibleValue();2699}2700}, ac);2701if (value != null) {2702String s = value.toString();2703if (s != null) {2704references.increment(s);2705return s;2706}2707}2708} else {2709debugString("[ERROR]: getCurrentAccessibleValueFromContext; ac = null");2710}2711return null;2712}27132714/**2715* return the AccessibleValue maximum value from an AccessibleContext2716* returned using a String 'cause the value is a java Number2717*2718*/2719private String getMaximumAccessibleValueFromContext(final AccessibleContext ac) {2720if (ac != null) {2721final Number value = InvocationUtils.invokeAndWait(new Callable<Number>() {2722@Override2723public Number call() throws Exception {2724AccessibleValue av = ac.getAccessibleValue();2725if (av == null) return null;2726return av.getMaximumAccessibleValue();2727}2728}, ac);2729if (value != null) {2730String s = value.toString();2731if (s != null) {2732references.increment(s);2733return s;2734}2735}2736} else {2737debugString("[ERROR]: getMaximumAccessibleValueFromContext; ac = null");2738}2739return null;2740}27412742/**2743* return the AccessibleValue minimum value from an AccessibleContext2744* returned using a String 'cause the value is a java Number2745*2746*/2747private String getMinimumAccessibleValueFromContext(final AccessibleContext ac) {2748if (ac != null) {2749final Number value = InvocationUtils.invokeAndWait(new Callable<Number>() {2750@Override2751public Number call() throws Exception {2752AccessibleValue av = ac.getAccessibleValue();2753if (av == null) return null;2754return av.getMinimumAccessibleValue();2755}2756}, ac);2757if (value != null) {2758String s = value.toString();2759if (s != null) {2760references.increment(s);2761return s;2762}2763}2764} else {2765debugString("[ERROR]: getMinimumAccessibleValueFromContext; ac = null");2766}2767return null;2768}276927702771/* ===== AccessibleSelection methods ===== */27722773/**2774* add to the AccessibleSelection of an AccessibleContext child i2775*2776*/2777private void addAccessibleSelectionFromContext(final AccessibleContext ac, final int i) {2778try {2779InvocationUtils.invokeAndWait(new Callable<Object>() {2780@Override2781public Object call() throws Exception {2782if (ac != null) {2783AccessibleSelection as = ac.getAccessibleSelection();2784if (as != null) {2785as.addAccessibleSelection(i);2786}2787}2788return null;2789}2790}, ac);2791} catch(Exception e){}2792}27932794/**2795* clear all of the AccessibleSelection of an AccessibleContex2796*2797*/2798private void clearAccessibleSelectionFromContext(final AccessibleContext ac) {2799try {2800InvocationUtils.invokeAndWait(new Callable<Object>() {2801@Override2802public Object call() throws Exception {2803AccessibleSelection as = ac.getAccessibleSelection();2804if (as != null) {2805as.clearAccessibleSelection();2806}2807return null;2808}2809}, ac);2810} catch(Exception e){}28112812}28132814/**2815* get the AccessibleContext of the i-th AccessibleSelection of an AccessibleContext2816*2817*/2818private AccessibleContext getAccessibleSelectionFromContext(final AccessibleContext ac, final int i) {2819return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {2820@Override2821public AccessibleContext call() throws Exception {2822if (ac != null) {2823AccessibleSelection as = ac.getAccessibleSelection();2824if (as != null) {2825Accessible a = as.getAccessibleSelection(i);2826if (a == null)2827return null;2828else2829return a.getAccessibleContext();2830}2831}2832return null;2833}2834}, ac);2835}28362837/**2838* get number of things selected in the AccessibleSelection of an AccessibleContext2839*2840*/2841private int getAccessibleSelectionCountFromContext(final AccessibleContext ac) {2842return InvocationUtils.invokeAndWait(new Callable<Integer>() {2843@Override2844public Integer call() throws Exception {2845if (ac != null) {2846AccessibleSelection as = ac.getAccessibleSelection();2847if (as != null) {2848return as.getAccessibleSelectionCount();2849}2850}2851return -1;2852}2853}, ac);2854}28552856/**2857* return true if the i-th child of the AccessibleSelection of an AccessibleContext is selected2858*2859*/2860private boolean isAccessibleChildSelectedFromContext(final AccessibleContext ac, final int i) {2861return InvocationUtils.invokeAndWait(new Callable<Boolean>() {2862@Override2863public Boolean call() throws Exception {2864if (ac != null) {2865AccessibleSelection as = ac.getAccessibleSelection();2866if (as != null) {2867return as.isAccessibleChildSelected(i);2868}2869}2870return false;2871}2872}, ac);2873}28742875/**2876* remove the i-th child from the AccessibleSelection of an AccessibleContext2877*2878*/2879private void removeAccessibleSelectionFromContext(final AccessibleContext ac, final int i) {2880InvocationUtils.invokeAndWait(new Callable<Object>() {2881@Override2882public Object call() throws Exception {2883if (ac != null) {2884AccessibleSelection as = ac.getAccessibleSelection();2885if (as != null) {2886as.removeAccessibleSelection(i);2887}2888}2889return null;2890}2891}, ac);2892}28932894/**2895* select all (if possible) of the children of the AccessibleSelection of an AccessibleContext2896*2897*/2898private void selectAllAccessibleSelectionFromContext(final AccessibleContext ac) {2899InvocationUtils.invokeAndWait(new Callable<Object>() {2900@Override2901public Object call() throws Exception {2902if (ac != null) {2903AccessibleSelection as = ac.getAccessibleSelection();2904if (as != null) {2905as.selectAllAccessibleSelection();2906}2907}2908return null;2909}2910}, ac);2911}29122913// ======== AccessibleTable ========29142915ConcurrentHashMap<AccessibleTable,AccessibleContext> hashtab = new ConcurrentHashMap<>();29162917/**2918* returns the AccessibleTable for an AccessibleContext2919*/2920private AccessibleTable getAccessibleTableFromContext(final AccessibleContext ac) {2921return InvocationUtils.invokeAndWait(new Callable<AccessibleTable>() {2922@Override2923public AccessibleTable call() throws Exception {2924if (ac != null) {2925AccessibleTable at = ac.getAccessibleTable();2926if (at != null) {2927AccessBridge.this.hashtab.put(at, ac);2928return at;2929}2930}2931return null;2932}2933}, ac);2934}293529362937/*2938* returns the AccessibleContext that contains an AccessibleTable2939*/2940private AccessibleContext getContextFromAccessibleTable(AccessibleTable at) {2941return hashtab.get(at);2942}29432944/*2945* returns the row count for an AccessibleTable2946*/2947private int getAccessibleTableRowCount(final AccessibleContext ac) {2948debugString("[INFO]: ##### getAccessibleTableRowCount");2949return InvocationUtils.invokeAndWait(new Callable<Integer>() {2950@Override2951public Integer call() throws Exception {2952if (ac != null) {2953AccessibleTable at = ac.getAccessibleTable();2954if (at != null) {2955return at.getAccessibleRowCount();2956}2957}2958return -1;2959}2960}, ac);2961}29622963/*2964* returns the column count for an AccessibleTable2965*/2966private int getAccessibleTableColumnCount(final AccessibleContext ac) {2967debugString("[INFO]: ##### getAccessibleTableColumnCount");2968return InvocationUtils.invokeAndWait(new Callable<Integer>() {2969@Override2970public Integer call() throws Exception {2971if (ac != null) {2972AccessibleTable at = ac.getAccessibleTable();2973if (at != null) {2974return at.getAccessibleColumnCount();2975}2976}2977return -1;2978}2979}, ac);2980}29812982/*2983* returns the AccessibleContext for an AccessibleTable cell2984*/2985private AccessibleContext getAccessibleTableCellAccessibleContext(final AccessibleTable at,2986final int row, final int column) {2987debugString("[INFO]: getAccessibleTableCellAccessibleContext: at = "+at.getClass());2988if (at == null) return null;2989return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {2990@Override2991public AccessibleContext call() throws Exception {2992if (!(at instanceof AccessibleContext)) {2993Accessible a = at.getAccessibleAt(row, column);2994if (a != null) {2995return a.getAccessibleContext();2996}2997} else {2998// work-around for AccessibleJTable.getCurrentAccessibleContext returning2999// wrong renderer component when cell contains more than one component3000AccessibleContext ac = (AccessibleContext) at;3001Accessible parent = ac.getAccessibleParent();3002if (parent != null) {3003int indexInParent = ac.getAccessibleIndexInParent();3004Accessible child =3005parent.getAccessibleContext().getAccessibleChild(indexInParent);3006if (child instanceof JTable) {3007JTable table = (JTable) child;30083009TableCellRenderer renderer = table.getCellRenderer(row, column);3010if (renderer == null) {3011Class<?> columnClass = table.getColumnClass(column);3012renderer = table.getDefaultRenderer(columnClass);3013}3014Component component =3015renderer.getTableCellRendererComponent(table, table.getValueAt(row, column),3016false, false, row, column);3017if (component instanceof Accessible) {3018return component.getAccessibleContext();3019}3020}3021}3022}3023return null;3024}3025}, getContextFromAccessibleTable(at));3026}30273028/*3029* returns the index of a cell at a given row and column in an AccessibleTable3030*/3031private int getAccessibleTableCellIndex(final AccessibleTable at, int row, int column) {3032debugString("[INFO]: ##### getAccessibleTableCellIndex: at="+at);3033if (at != null) {3034int cellIndex = row *3035InvocationUtils.invokeAndWait(new Callable<Integer>() {3036@Override3037public Integer call() throws Exception {3038return at.getAccessibleColumnCount();3039}3040}, getContextFromAccessibleTable(at)) +3041column;3042debugString("[INFO]: ##### getAccessibleTableCellIndex="+cellIndex);3043return cellIndex;3044}3045debugString("[ERROR]: ##### getAccessibleTableCellIndex FAILED");3046return -1;3047}30483049/*3050* returns the row extent of a cell at a given row and column in an AccessibleTable3051*/3052private int getAccessibleTableCellRowExtent(final AccessibleTable at, final int row, final int column) {3053debugString("[INFO]: ##### getAccessibleTableCellRowExtent");3054if (at != null) {3055int rowExtent = InvocationUtils.invokeAndWait(new Callable<Integer>() {3056@Override3057public Integer call() throws Exception {3058return at.getAccessibleRowExtentAt(row, column);3059}3060},3061getContextFromAccessibleTable(at));3062debugString("[INFO]: ##### getAccessibleTableCellRowExtent="+rowExtent);3063return rowExtent;3064}3065debugString("[ERROR]: ##### getAccessibleTableCellRowExtent FAILED");3066return -1;3067}30683069/*3070* returns the column extent of a cell at a given row and column in an AccessibleTable3071*/3072private int getAccessibleTableCellColumnExtent(final AccessibleTable at, final int row, final int column) {3073debugString("[INFO]: ##### getAccessibleTableCellColumnExtent");3074if (at != null) {3075int columnExtent = InvocationUtils.invokeAndWait(new Callable<Integer>() {3076@Override3077public Integer call() throws Exception {3078return at.getAccessibleColumnExtentAt(row, column);3079}3080},3081getContextFromAccessibleTable(at));3082debugString("[INFO]: ##### getAccessibleTableCellColumnExtent="+columnExtent);3083return columnExtent;3084}3085debugString("[ERROR]: ##### getAccessibleTableCellColumnExtent FAILED");3086return -1;3087}30883089/*3090* returns whether a cell is selected at a given row and column in an AccessibleTable3091*/3092private boolean isAccessibleTableCellSelected(final AccessibleTable at, final int row,3093final int column) {3094debugString("[INFO]: ##### isAccessibleTableCellSelected: ["+row+"]["+column+"]");3095if (at == null)3096return false;3097return InvocationUtils.invokeAndWait(new Callable<Boolean>() {3098@Override3099public Boolean call() throws Exception {3100boolean isSelected = false;3101Accessible a = at.getAccessibleAt(row, column);3102if (a != null) {3103AccessibleContext ac = a.getAccessibleContext();3104if (ac == null)3105return false;3106AccessibleStateSet as = ac.getAccessibleStateSet();3107if (as != null) {3108isSelected = as.contains(AccessibleState.SELECTED);3109}3110}3111return isSelected;3112}3113}, getContextFromAccessibleTable(at));3114}31153116/*3117* returns an AccessibleTable that represents the row header in an3118* AccessibleTable3119*/3120private AccessibleTable getAccessibleTableRowHeader(final AccessibleContext ac) {3121debugString("[INFO]: ##### getAccessibleTableRowHeader called");3122AccessibleTable at = InvocationUtils.invokeAndWait(new Callable<AccessibleTable>() {3123@Override3124public AccessibleTable call() throws Exception {3125if (ac != null) {3126AccessibleTable at = ac.getAccessibleTable();3127if (at != null) {3128return at.getAccessibleRowHeader();3129}3130}3131return null;3132}3133}, ac);3134if (at != null) {3135hashtab.put(at, ac);3136}3137return at;3138}31393140/*3141* returns an AccessibleTable that represents the column header in an3142* AccessibleTable3143*/3144private AccessibleTable getAccessibleTableColumnHeader(final AccessibleContext ac) {3145debugString("[INFO]: ##### getAccessibleTableColumnHeader");3146if (ac == null)3147return null;3148AccessibleTable at = InvocationUtils.invokeAndWait(new Callable<AccessibleTable>() {3149@Override3150public AccessibleTable call() throws Exception {3151// workaround for getAccessibleColumnHeader NPE3152// when the table header is null3153Accessible parent = ac.getAccessibleParent();3154if (parent != null) {3155int indexInParent = ac.getAccessibleIndexInParent();3156Accessible child =3157parent.getAccessibleContext().getAccessibleChild(indexInParent);3158if (child instanceof JTable) {3159JTable table = (JTable) child;3160if (table.getTableHeader() == null) {3161return null;3162}3163}3164}3165AccessibleTable at = ac.getAccessibleTable();3166if (at != null) {3167return at.getAccessibleColumnHeader();3168}3169return null;3170}3171}, ac);3172if (at != null) {3173hashtab.put(at, ac);3174}3175return at;3176}31773178/*3179* returns the number of row headers in an AccessibleTable that represents3180* the row header in an AccessibleTable3181*/3182private int getAccessibleTableRowHeaderRowCount(AccessibleContext ac) {31833184debugString("[INFO]: ##### getAccessibleTableRowHeaderRowCount called");3185if (ac != null) {3186final AccessibleTable atRowHeader = getAccessibleTableRowHeader(ac);3187if (atRowHeader != null) {3188return InvocationUtils.invokeAndWait(new Callable<Integer>() {3189@Override3190public Integer call() throws Exception {3191if (atRowHeader != null) {3192return atRowHeader.getAccessibleRowCount();3193}3194return -1;3195}3196}, ac);3197}3198}3199return -1;3200}32013202/*3203* returns the number of column headers in an AccessibleTable that represents3204* the row header in an AccessibleTable3205*/3206private int getAccessibleTableRowHeaderColumnCount(AccessibleContext ac) {3207debugString("[INFO]: ##### getAccessibleTableRowHeaderColumnCount called");3208if (ac != null) {3209final AccessibleTable atRowHeader = getAccessibleTableRowHeader(ac);3210if (atRowHeader != null) {3211return InvocationUtils.invokeAndWait(new Callable<Integer>() {3212@Override3213public Integer call() throws Exception {3214if (atRowHeader != null) {3215return atRowHeader.getAccessibleColumnCount();3216}3217return -1;3218}3219}, ac);3220}3221}3222debugString("[ERROR]: ##### getAccessibleTableRowHeaderColumnCount FAILED");3223return -1;3224}32253226/*3227* returns the number of row headers in an AccessibleTable that represents3228* the column header in an AccessibleTable3229*/3230private int getAccessibleTableColumnHeaderRowCount(AccessibleContext ac) {32313232debugString("[INFO]: ##### getAccessibleTableColumnHeaderRowCount");3233if (ac != null) {3234final AccessibleTable atColumnHeader = getAccessibleTableColumnHeader(ac);3235if (atColumnHeader != null) {3236return InvocationUtils.invokeAndWait(new Callable<Integer>() {3237@Override3238public Integer call() throws Exception {3239if (atColumnHeader != null) {3240return atColumnHeader.getAccessibleRowCount();3241}3242return -1;3243}3244}, ac);3245}3246}3247debugString("[ERROR]: ##### getAccessibleTableColumnHeaderRowCount FAILED");3248return -1;3249}32503251/*3252* returns the number of column headers in an AccessibleTable that represents3253* the column header in an AccessibleTable3254*/3255private int getAccessibleTableColumnHeaderColumnCount(AccessibleContext ac) {32563257debugString("[ERROR]: ##### getAccessibleTableColumnHeaderColumnCount");3258if (ac != null) {3259final AccessibleTable atColumnHeader = getAccessibleTableColumnHeader(ac);3260if (atColumnHeader != null) {3261return InvocationUtils.invokeAndWait(new Callable<Integer>() {3262@Override3263public Integer call() throws Exception {3264if (atColumnHeader != null) {3265return atColumnHeader.getAccessibleColumnCount();3266}3267return -1;3268}3269}, ac);3270}3271}3272debugString("[ERROR]: ##### getAccessibleTableColumnHeaderColumnCount FAILED");3273return -1;3274}32753276/*3277* returns the description of a row header in an AccessibleTable3278*/3279private AccessibleContext getAccessibleTableRowDescription(final AccessibleTable table,3280final int row) {3281return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {3282@Override3283public AccessibleContext call() throws Exception {3284if (table != null) {3285Accessible a = table.getAccessibleRowDescription(row);3286if (a != null) {3287return a.getAccessibleContext();3288}3289}3290return null;3291}3292}, getContextFromAccessibleTable(table));3293}32943295/*3296* returns the description of a column header in an AccessibleTable3297*/3298private AccessibleContext getAccessibleTableColumnDescription(final AccessibleTable at,3299final int column) {3300if (at == null)3301return null;3302return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {3303@Override3304public AccessibleContext call() throws Exception {3305Accessible a = at.getAccessibleColumnDescription(column);3306if (a != null) {3307return a.getAccessibleContext();3308}3309return null;3310}3311}, getContextFromAccessibleTable(at));3312}33133314/*3315* returns the number of rows selected in an AccessibleTable3316*/3317private int getAccessibleTableRowSelectionCount(final AccessibleTable at) {3318if (at != null) {3319return InvocationUtils.invokeAndWait(new Callable<Integer>() {3320@Override3321public Integer call() throws Exception {3322int[] selections = at.getSelectedAccessibleRows();3323if (selections != null)3324return selections.length;3325else3326return -1;3327}3328}, getContextFromAccessibleTable(at));3329}3330return -1;3331}33323333/*3334* returns the row number of the i-th selected row in an AccessibleTable3335*/3336private int getAccessibleTableRowSelections(final AccessibleTable at, final int i) {3337if (at != null) {3338return InvocationUtils.invokeAndWait(new Callable<Integer>() {3339@Override3340public Integer call() throws Exception {3341int[] selections = at.getSelectedAccessibleRows();3342if (selections.length > i) {3343return selections[i];3344}3345return -1;3346}3347}, getContextFromAccessibleTable(at));3348}3349return -1;3350}33513352/*3353* returns whether a row is selected in an AccessibleTable3354*/3355private boolean isAccessibleTableRowSelected(final AccessibleTable at,3356final int row) {3357if (at == null)3358return false;3359return InvocationUtils.invokeAndWait(new Callable<Boolean>() {3360@Override3361public Boolean call() throws Exception {3362return at.isAccessibleRowSelected(row);3363}3364}, getContextFromAccessibleTable(at));3365}33663367/*3368* returns whether a column is selected in an AccessibleTable3369*/3370private boolean isAccessibleTableColumnSelected(final AccessibleTable at,3371final int column) {3372if (at == null)3373return false;3374return InvocationUtils.invokeAndWait(new Callable<Boolean>() {3375@Override3376public Boolean call() throws Exception {3377return at.isAccessibleColumnSelected(column);3378}3379}, getContextFromAccessibleTable(at));3380}33813382/*3383* returns the number of columns selected in an AccessibleTable3384*/3385private int getAccessibleTableColumnSelectionCount(final AccessibleTable at) {3386if (at == null)3387return -1;3388return InvocationUtils.invokeAndWait(new Callable<Integer>() {3389@Override3390public Integer call() throws Exception {3391int[] selections = at.getSelectedAccessibleColumns();3392if (selections != null)3393return selections.length;3394else3395return -1;3396}3397}, getContextFromAccessibleTable(at));3398}33993400/*3401* returns the row number of the i-th selected row in an AccessibleTable3402*/3403private int getAccessibleTableColumnSelections(final AccessibleTable at, final int i) {3404if (at == null)3405return -1;3406return InvocationUtils.invokeAndWait(new Callable<Integer>() {3407@Override3408public Integer call() throws Exception {3409int[] selections = at.getSelectedAccessibleColumns();3410if (selections != null && selections.length > i) {3411return selections[i];3412}3413return -1;3414}3415}, getContextFromAccessibleTable(at));3416}34173418/* ===== AccessibleExtendedTable (since 1.4) ===== */34193420/*3421* returns the row number for a cell at a given index in an AccessibleTable3422*/3423private int getAccessibleTableRow(final AccessibleTable at, int index) {3424if (at == null)3425return -1;3426int colCount=InvocationUtils.invokeAndWait(new Callable<Integer>() {3427@Override3428public Integer call() throws Exception {3429return at.getAccessibleColumnCount();3430}3431}, getContextFromAccessibleTable(at));3432return index / colCount;3433}34343435/*3436* returns the column number for a cell at a given index in an AccessibleTable3437*/3438private int getAccessibleTableColumn(final AccessibleTable at, int index) {3439if (at == null)3440return -1;3441int colCount=InvocationUtils.invokeAndWait(new Callable<Integer>() {3442@Override3443public Integer call() throws Exception {3444return at.getAccessibleColumnCount();3445}3446}, getContextFromAccessibleTable(at));3447return index % colCount;3448}34493450/*3451* returns the index for a cell at a given row and column in an3452* AccessibleTable3453*/3454private int getAccessibleTableIndex(final AccessibleTable at, int row, int column) {3455if (at == null)3456return -1;3457int colCount = InvocationUtils.invokeAndWait(new Callable<Integer>() {3458@Override3459public Integer call() throws Exception {3460return at.getAccessibleColumnCount();3461}3462}, getContextFromAccessibleTable(at));3463return row * colCount + column;3464}34653466// ===== AccessibleRelationSet =====34673468/*3469* returns the number of relations in the AccessibleContext's3470* AccessibleRelationSet3471*/3472private int getAccessibleRelationCount(final AccessibleContext ac) {3473{3474if (ac != null) {3475AccessibleRelationSet ars = InvocationUtils.invokeAndWait(new Callable<AccessibleRelationSet>() {3476@Override3477public AccessibleRelationSet call() throws Exception {3478return ac.getAccessibleRelationSet();3479}3480}, ac);3481if (ars != null)3482return ars.size();3483}3484}3485return 0;3486}34873488/*3489* returns the ith relation key in the AccessibleContext's3490* AccessibleRelationSet3491*/3492private String getAccessibleRelationKey(final AccessibleContext ac, final int i) {3493return InvocationUtils.invokeAndWait(new Callable<String>() {3494@Override3495public String call() throws Exception {3496if (ac != null) {3497AccessibleRelationSet ars = ac.getAccessibleRelationSet();3498if (ars != null) {3499AccessibleRelation[] relations = ars.toArray();3500if (relations != null && i >= 0 && i < relations.length) {3501return relations[i].getKey();3502}3503}3504}3505return null;3506}3507}, ac);3508}35093510/*3511* returns the number of targets in a relation in the AccessibleContext's3512* AccessibleRelationSet3513*/3514private int getAccessibleRelationTargetCount(final AccessibleContext ac, final int i) {3515return InvocationUtils.invokeAndWait(new Callable<Integer>() {3516@Override3517public Integer call() throws Exception {3518if (ac != null) {3519AccessibleRelationSet ars = ac.getAccessibleRelationSet();3520if (ars != null) {3521AccessibleRelation[] relations = ars.toArray();3522if (relations != null && i >= 0 && i < relations.length) {3523Object[] targets = relations[i].getTarget();3524return targets.length;3525}3526}3527}3528return -1;3529}3530}, ac);3531}35323533/*3534* returns the jth target in the ith relation in the AccessibleContext's3535* AccessibleRelationSet3536*/3537private AccessibleContext getAccessibleRelationTarget(final AccessibleContext ac,3538final int i, final int j) {3539debugString("[INFO]: ***** getAccessibleRelationTarget");3540return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {3541@Override3542public AccessibleContext call() throws Exception {3543if (ac != null) {3544AccessibleRelationSet ars = ac.getAccessibleRelationSet();3545if (ars != null) {3546AccessibleRelation[] relations = ars.toArray();3547if (relations != null && i >= 0 && i < relations.length) {3548Object[] targets = relations[i].getTarget();3549if (targets != null && j >= 0 & j < targets.length) {3550Object o = targets[j];3551if (o instanceof Accessible) {3552return ((Accessible) o).getAccessibleContext();3553}3554}3555}3556}3557}3558return null;3559}3560}, ac);3561}35623563// ========= AccessibleHypertext =========35643565private Map<AccessibleHypertext, AccessibleContext> hyperTextContextMap = new WeakHashMap<>();3566private Map<AccessibleHyperlink, AccessibleContext> hyperLinkContextMap = new WeakHashMap<>();35673568/*3569* Returns the AccessibleHypertext3570*/3571private AccessibleHypertext getAccessibleHypertext(final AccessibleContext ac) {3572debugString("[INFO]: getAccessibleHyperlink");3573if (ac==null)3574return null;3575AccessibleHypertext hypertext = InvocationUtils.invokeAndWait(new Callable<AccessibleHypertext>() {3576@Override3577public AccessibleHypertext call() throws Exception {3578AccessibleText at = ac.getAccessibleText();3579if (!(at instanceof AccessibleHypertext)) {3580return null;3581}3582return ((AccessibleHypertext) at);3583}3584}, ac);3585hyperTextContextMap.put(hypertext, ac);3586return hypertext;3587}35883589/*3590* Returns the number of AccessibleHyperlinks3591*/3592private int getAccessibleHyperlinkCount(AccessibleContext ac) {3593debugString("[INFO]: getAccessibleHyperlinkCount");3594if (ac == null) {3595return 0;3596}3597final AccessibleHypertext hypertext = getAccessibleHypertext(ac);3598if (hypertext == null) {3599return 0;3600}3601//return hypertext.getLinkCount();3602return InvocationUtils.invokeAndWait(new Callable<Integer>() {3603@Override3604public Integer call() throws Exception {3605return hypertext.getLinkCount();3606}3607}, ac);3608}36093610/*3611* Returns the hyperlink at the specified index3612*/3613private AccessibleHyperlink getAccessibleHyperlink(final AccessibleHypertext hypertext, final int i) {3614debugString("[INFO]: getAccessibleHyperlink");3615if (hypertext == null) {3616return null;3617}3618AccessibleContext ac = hyperTextContextMap.get(hypertext);3619if ( i < 0 || i >=3620InvocationUtils.invokeAndWait(new Callable<Integer>() {3621@Override3622public Integer call() throws Exception {3623return hypertext.getLinkCount();3624}3625}, ac) ) {3626return null;3627}3628AccessibleHyperlink acLink = InvocationUtils.invokeAndWait(new Callable<AccessibleHyperlink>() {3629@Override3630public AccessibleHyperlink call() throws Exception {3631AccessibleHyperlink link = hypertext.getLink(i);3632if (link == null || (!link.isValid())) {3633return null;3634}3635return link;3636}3637}, ac);3638hyperLinkContextMap.put(acLink, ac);3639return acLink;3640}36413642/*3643* Returns the hyperlink object description3644*/3645private String getAccessibleHyperlinkText(final AccessibleHyperlink link) {3646debugString("[INFO]: getAccessibleHyperlinkText");3647if (link == null) {3648return null;3649}3650return InvocationUtils.invokeAndWait(new Callable<String>() {3651@Override3652public String call() throws Exception {3653Object o = link.getAccessibleActionDescription(0);3654if (o != null) {3655return o.toString();3656}3657return null;3658}3659}, hyperLinkContextMap.get(link));3660}36613662/*3663* Returns the hyperlink URL3664*/3665private String getAccessibleHyperlinkURL(final AccessibleHyperlink link) {3666debugString("[INFO]: getAccessibleHyperlinkURL");3667if (link == null) {3668return null;3669}3670return InvocationUtils.invokeAndWait(new Callable<String>() {3671@Override3672public String call() throws Exception {3673Object o = link.getAccessibleActionObject(0);3674if (o != null) {3675return o.toString();3676} else {3677return null;3678}3679}3680}, hyperLinkContextMap.get(link));3681}36823683/*3684* Returns the start index of the hyperlink text3685*/3686private int getAccessibleHyperlinkStartIndex(final AccessibleHyperlink link) {3687debugString("[INFO]: getAccessibleHyperlinkStartIndex");3688if (link == null) {3689return -1;3690}3691return InvocationUtils.invokeAndWait(new Callable<Integer>() {3692@Override3693public Integer call() throws Exception {3694return link.getStartIndex();3695}3696}, hyperLinkContextMap.get(link));3697}36983699/*3700* Returns the end index of the hyperlink text3701*/3702private int getAccessibleHyperlinkEndIndex(final AccessibleHyperlink link) {3703debugString("[INFO]: getAccessibleHyperlinkEndIndex");3704if (link == null) {3705return -1;3706}3707return InvocationUtils.invokeAndWait(new Callable<Integer>() {3708@Override3709public Integer call() throws Exception {3710return link.getEndIndex();3711}3712}, hyperLinkContextMap.get(link));3713}37143715/*3716* Returns the index into an array of hyperlinks that3717* is associated with this character index, or -1 if there3718* is no hyperlink associated with this index.3719*/3720private int getAccessibleHypertextLinkIndex(final AccessibleHypertext hypertext, final int charIndex) {3721debugString("[INFO]: getAccessibleHypertextLinkIndex: charIndex = "+charIndex);3722if (hypertext == null) {3723return -1;3724}3725int linkIndex = InvocationUtils.invokeAndWait(new Callable<Integer>() {3726@Override3727public Integer call() throws Exception {3728return hypertext.getLinkIndex(charIndex);3729}3730}, hyperTextContextMap.get(hypertext));3731debugString("[INFO]: getAccessibleHypertextLinkIndex returning "+linkIndex);3732return linkIndex;3733}37343735/*3736* Actives the hyperlink3737*/3738private boolean activateAccessibleHyperlink(final AccessibleContext ac,3739final AccessibleHyperlink link) {3740//debugString("activateAccessibleHyperlink: link = "+link.getClass());3741if (link == null) {3742return false;3743}3744boolean retval = InvocationUtils.invokeAndWait(new Callable<Boolean>() {3745@Override3746public Boolean call() throws Exception {3747return link.doAccessibleAction(0);3748}3749}, ac);3750debugString("[INFO]: activateAccessibleHyperlink: returning = "+retval);3751return retval;3752}375337543755// ============ AccessibleKeyBinding =============37563757/*3758* returns the component mnemonic3759*/3760private KeyStroke getMnemonic(final AccessibleContext ac) {3761if (ac == null)3762return null;3763return InvocationUtils.invokeAndWait(new Callable<KeyStroke>() {3764@Override3765public KeyStroke call() throws Exception {3766AccessibleComponent comp = ac.getAccessibleComponent();3767if (!(comp instanceof AccessibleExtendedComponent)) {3768return null;3769}3770AccessibleExtendedComponent aec = (AccessibleExtendedComponent) comp;3771if (aec != null) {3772AccessibleKeyBinding akb = aec.getAccessibleKeyBinding();3773if (akb != null) {3774Object o = akb.getAccessibleKeyBinding(0);3775if (o instanceof KeyStroke) {3776return (KeyStroke) o;3777}3778}3779}3780return null;3781}3782}, ac);3783}37843785/*3786* Returns the JMenuItem accelerator. Similar implementation is used on3787* macOS, see CAccessibility.getAcceleratorText(AccessibleContext).3788*/3789private KeyStroke getAccelerator(final AccessibleContext ac) {3790// workaround for getAccessibleKeyBinding not returning the3791// JMenuItem accelerator3792if (ac == null)3793return null;3794return InvocationUtils.invokeAndWait(new Callable<KeyStroke>() {3795@Override3796public KeyStroke call() throws Exception {3797Accessible parent = ac.getAccessibleParent();3798if (parent instanceof Accessible) {3799int indexInParent = ac.getAccessibleIndexInParent();3800Accessible child =3801parent.getAccessibleContext().getAccessibleChild(indexInParent);3802if (child instanceof JMenuItem) {3803JMenuItem menuItem = (JMenuItem) child;3804if (menuItem == null)3805return null;3806KeyStroke keyStroke = menuItem.getAccelerator();3807return keyStroke;3808}3809}3810return null;3811}3812}, ac);3813}38143815/*3816* returns 1-24 to indicate which F key is being used for a shortcut or 0 otherwise3817*/3818private int fKeyNumber(KeyStroke keyStroke) {3819if (keyStroke == null)3820return 0;3821int fKey = 0;3822String keyText = KeyEvent.getKeyText(keyStroke.getKeyCode());3823if (keyText != null && (keyText.length() == 2 || keyText.length() == 3)) {3824String prefix = keyText.substring(0, 1);3825if (prefix.equals("F")) {3826try {3827int suffix = Integer.parseInt(keyText.substring(1));3828if (suffix >= 1 && suffix <= 24) {3829fKey = suffix;3830}3831} catch (Exception e) { // ignore NumberFormatException3832}3833}3834}3835return fKey;3836}38373838/*3839* returns one of several important control characters or 0 otherwise3840*/3841private int controlCode(KeyStroke keyStroke) {3842if (keyStroke == null)3843return 0;3844int code = keyStroke.getKeyCode();3845switch (code) {3846case KeyEvent.VK_BACK_SPACE:3847case KeyEvent.VK_DELETE:3848case KeyEvent.VK_DOWN:3849case KeyEvent.VK_END:3850case KeyEvent.VK_HOME:3851case KeyEvent.VK_INSERT:3852case KeyEvent.VK_KP_DOWN:3853case KeyEvent.VK_KP_LEFT:3854case KeyEvent.VK_KP_RIGHT:3855case KeyEvent.VK_KP_UP:3856case KeyEvent.VK_LEFT:3857case KeyEvent.VK_PAGE_DOWN:3858case KeyEvent.VK_PAGE_UP:3859case KeyEvent.VK_RIGHT:3860case KeyEvent.VK_UP:3861break;3862default:3863code = 0;3864break;3865}3866return code;3867}38683869/*3870* returns the KeyStoke character3871*/3872private char getKeyChar(KeyStroke keyStroke) {3873// If the shortcut is an FKey return 1-243874if (keyStroke == null)3875return 0;3876int fKey = fKeyNumber(keyStroke);3877if (fKey != 0) {3878// return 0x00000001 through 0x000000183879debugString("[INFO]: Shortcut is: F" + fKey);3880return (char)fKey;3881}3882// If the accelerator is a control character, return it3883int keyCode = controlCode(keyStroke);3884if (keyCode != 0) {3885debugString("[INFO]: Shortcut is control character: " + Integer.toHexString(keyCode));3886return (char)keyCode;3887}3888String keyText = KeyEvent.getKeyText(keyStroke.getKeyCode());3889debugString("[INFO]: Shortcut is: " + keyText);3890if (keyText != null || keyText.length() > 0) {3891CharSequence seq = keyText.subSequence(0, 1);3892if (seq != null || seq.length() > 0) {3893return seq.charAt(0);3894}3895}3896return 0;3897}38983899/*3900* returns the KeyStroke modifiers as an int3901*/3902private int getModifiers(KeyStroke keyStroke) {3903if (keyStroke == null)3904return 0;3905debugString("[INFO]: In AccessBridge.getModifiers");3906// modifiers is a bit strip where bits 0-7 indicate a traditional modifier3907// such as Ctrl/Alt/Shift, bit 8 indicates an F key shortcut, and bit 9 indicates3908// a control code shortcut such as the delete key.39093910int modifiers = 0;3911// Is the shortcut an FKey?3912if (fKeyNumber(keyStroke) != 0) {3913modifiers |= 1 << 8;3914}3915// Is the shortcut a control code?3916if (controlCode(keyStroke) != 0) {3917modifiers |= 1 << 9;3918}3919// The following is needed in order to handle translated modifiers.3920// getKeyModifiersText doesn't work because for example in German Strg is3921// returned for Ctrl.39223923// There can be more than one modifier, e.g. if the modifier is ctrl + shift + B3924// the toString text is "shift ctrl pressed B". Need to parse through that.3925StringTokenizer st = new StringTokenizer(keyStroke.toString());3926while (st.hasMoreTokens()) {3927String text = st.nextToken();3928// Meta+Ctrl+Alt+Shift3929// 0-3 are shift, ctrl, meta, alt3930// 4-7 are for Solaris workstations (though not being used)3931if (text.startsWith("met")) {3932debugString("[INFO]: found meta");3933modifiers |= ActionEvent.META_MASK;3934}3935if (text.startsWith("ctr")) {3936debugString("[INFO]: found ctrl");3937modifiers |= ActionEvent.CTRL_MASK;3938}3939if (text.startsWith("alt")) {3940debugString("[INFO]: found alt");3941modifiers |= ActionEvent.ALT_MASK;3942}3943if (text.startsWith("shi")) {3944debugString(" found shift");3945modifiers |= ActionEvent.SHIFT_MASK;3946}3947}3948debugString("[INFO]: returning modifiers: 0x" + Integer.toHexString(modifiers));3949return modifiers;3950}39513952/*3953* returns the number of key bindings associated with this context3954*/3955private int getAccessibleKeyBindingsCount(AccessibleContext ac) {3956if (ac == null)3957return 0;3958int count = 0;39593960if (getMnemonic(ac) != null) {3961count++;3962}3963if (getAccelerator(ac) != null) {3964count++;3965}3966return count;3967}39683969/*3970* returns the key binding character at the specified index3971*/3972private char getAccessibleKeyBindingChar(AccessibleContext ac, int index) {3973if (ac == null)3974return 0;3975if((index == 0) && getMnemonic(ac)==null) {// special case when there is no mnemonic3976KeyStroke keyStroke = getAccelerator(ac);3977if (keyStroke != null) {3978return getKeyChar(keyStroke);3979}3980}3981if (index == 0) { // mnemonic3982KeyStroke keyStroke = getMnemonic(ac);3983if (keyStroke != null) {3984return getKeyChar(keyStroke);3985}3986} else if (index == 1) { // accelerator3987KeyStroke keyStroke = getAccelerator(ac);3988if (keyStroke != null) {3989return getKeyChar(keyStroke);3990}3991}3992return 0;3993}39943995/*3996* returns the key binding modifiers at the specified index3997*/3998private int getAccessibleKeyBindingModifiers(AccessibleContext ac, int index) {3999if (ac == null)4000return 0;4001if((index == 0) && getMnemonic(ac)==null) {// special case when there is no mnemonic4002KeyStroke keyStroke = getAccelerator(ac);4003if (keyStroke != null) {4004return getModifiers(keyStroke);4005}4006}4007if (index == 0) { // mnemonic4008KeyStroke keyStroke = getMnemonic(ac);4009if (keyStroke != null) {4010return getModifiers(keyStroke);4011}4012} else if (index == 1) { // accelerator4013KeyStroke keyStroke = getAccelerator(ac);4014if (keyStroke != null) {4015return getModifiers(keyStroke);4016}4017}4018return 0;4019}40204021// ========== AccessibleIcon ============40224023/*4024* return the number of icons associated with this context4025*/4026private int getAccessibleIconsCount(final AccessibleContext ac) {4027debugString("[INFO]: getAccessibleIconsCount");4028if (ac == null) {4029return 0;4030}4031return InvocationUtils.invokeAndWait(new Callable<Integer>() {4032@Override4033public Integer call() throws Exception {4034AccessibleIcon[] ai = ac.getAccessibleIcon();4035if (ai == null) {4036return 0;4037}4038return ai.length;4039}4040}, ac);4041}40424043/*4044* return icon description at the specified index4045*/4046private String getAccessibleIconDescription(final AccessibleContext ac, final int index) {4047debugString("[INFO]: getAccessibleIconDescription: index = "+index);4048if (ac == null) {4049return null;4050}4051return InvocationUtils.invokeAndWait(new Callable<String>() {4052@Override4053public String call() throws Exception {4054AccessibleIcon[] ai = ac.getAccessibleIcon();4055if (ai == null || index < 0 || index >= ai.length) {4056return null;4057}4058return ai[index].getAccessibleIconDescription();4059}4060}, ac);4061}40624063/*4064* return icon height at the specified index4065*/4066private int getAccessibleIconHeight(final AccessibleContext ac, final int index) {4067debugString("[INFO]: getAccessibleIconHeight: index = "+index);4068if (ac == null) {4069return 0;4070}4071return InvocationUtils.invokeAndWait(new Callable<Integer>() {4072@Override4073public Integer call() throws Exception {4074AccessibleIcon[] ai = ac.getAccessibleIcon();4075if (ai == null || index < 0 || index >= ai.length) {4076return 0;4077}4078return ai[index].getAccessibleIconHeight();4079}4080}, ac);4081}40824083/*4084* return icon width at the specified index4085*/4086private int getAccessibleIconWidth(final AccessibleContext ac, final int index) {4087debugString("[INFO]: getAccessibleIconWidth: index = "+index);4088if (ac == null) {4089return 0;4090}4091return InvocationUtils.invokeAndWait(new Callable<Integer>() {4092@Override4093public Integer call() throws Exception {4094AccessibleIcon[] ai = ac.getAccessibleIcon();4095if (ai == null || index < 0 || index >= ai.length) {4096return 0;4097}4098return ai[index].getAccessibleIconWidth();4099}4100}, ac);4101}41024103// ========= AccessibleAction ===========41044105/*4106* return the number of icons associated with this context4107*/4108private int getAccessibleActionsCount(final AccessibleContext ac) {4109debugString("[INFO]: getAccessibleActionsCount");4110if (ac == null) {4111return 0;4112}4113return InvocationUtils.invokeAndWait(new Callable<Integer>() {4114@Override4115public Integer call() throws Exception {4116AccessibleAction aa = ac.getAccessibleAction();4117if (aa == null)4118return 0;4119return aa.getAccessibleActionCount();4120}4121}, ac);4122}41234124/*4125* return icon description at the specified index4126*/4127private String getAccessibleActionName(final AccessibleContext ac, final int index) {4128debugString("[INFO]: getAccessibleActionName: index = "+index);4129if (ac == null) {4130return null;4131}4132return InvocationUtils.invokeAndWait(new Callable<String>() {4133@Override4134public String call() throws Exception {4135AccessibleAction aa = ac.getAccessibleAction();4136if (aa == null) {4137return null;4138}4139return aa.getAccessibleActionDescription(index);4140}4141}, ac);4142}4143/*4144* return icon description at the specified index4145*/4146private boolean doAccessibleActions(final AccessibleContext ac, final String name) {4147debugString("[INFO]: doAccessibleActions: action name = "+name);4148if (ac == null || name == null) {4149return false;4150}4151return InvocationUtils.invokeAndWait(new Callable<Boolean>() {4152@Override4153public Boolean call() throws Exception {4154AccessibleAction aa = ac.getAccessibleAction();4155if (aa == null) {4156return false;4157}4158int index = -1;4159int numActions = aa.getAccessibleActionCount();4160for (int i = 0; i < numActions; i++) {4161String actionName = aa.getAccessibleActionDescription(i);4162if (name.equals(actionName)) {4163index = i;4164break;4165}4166}4167if (index == -1) {4168return false;4169}4170boolean retval = aa.doAccessibleAction(index);4171return retval;4172}4173}, ac);4174}41754176/* ===== AT utility methods ===== */41774178/**4179* Sets the contents of an AccessibleContext that4180* implements AccessibleEditableText with the4181* specified text string.4182* Returns whether successful.4183*/4184private boolean setTextContents(final AccessibleContext ac, final String text) {4185debugString("[INFO]: setTextContents: ac = "+ac+"; text = "+text);41864187if (! (ac instanceof AccessibleEditableText)) {4188debugString("[WARN]: ac not instanceof AccessibleEditableText: "+ac);4189return false;4190}4191if (text == null) {4192debugString("[WARN]: text is null");4193return false;4194}41954196return InvocationUtils.invokeAndWait(new Callable<Boolean>() {4197@Override4198public Boolean call() throws Exception {4199// check whether the text field is editable4200AccessibleStateSet ass = ac.getAccessibleStateSet();4201if (!ass.contains(AccessibleState.ENABLED)) {4202return false;4203}4204((AccessibleEditableText) ac).setTextContents(text);4205return true;4206}4207}, ac);4208}42094210/**4211* Returns the Accessible Context of an Internal Frame object that is4212* the ancestor of a given object. If the object is an Internal Frame4213* object or an Internal Frame ancestor object was found, returns the4214* object's AccessibleContext.4215* If there is no ancestor object that has an Accessible Role of4216* Internal Frame, returns (AccessibleContext)0.4217*/4218private AccessibleContext getInternalFrame (AccessibleContext ac) {4219return getParentWithRole(ac, AccessibleRole.INTERNAL_FRAME.toString());4220}42214222/**4223* Returns the Accessible Context for the top level object in4224* a Java Window. This is same Accessible Context that is obtained4225* from GetAccessibleContextFromHWND for that window. Returns4226* (AccessibleContext)0 on error.4227*/4228private AccessibleContext getTopLevelObject (final AccessibleContext ac) {4229debugString("[INFO]: getTopLevelObject; ac = "+ac);4230if (ac == null) {4231return null;4232}4233return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {4234@Override4235public AccessibleContext call() throws Exception {4236if (ac.getAccessibleRole() == AccessibleRole.DIALOG) {4237// return the dialog, not the parent window4238return ac;4239}42404241Accessible parent = ac.getAccessibleParent();4242if (parent == null) {4243return ac;4244}4245Accessible tmp = parent;4246while (tmp != null && tmp.getAccessibleContext() != null) {4247AccessibleContext ac2 = tmp.getAccessibleContext();4248if (ac2 != null && ac2.getAccessibleRole() == AccessibleRole.DIALOG) {4249// return the dialog, not the parent window4250return ac2;4251}4252parent = tmp;4253tmp = parent.getAccessibleContext().getAccessibleParent();4254}4255return parent.getAccessibleContext();4256}4257}, ac);4258}42594260/**4261* Returns the parent AccessibleContext that has the specified AccessibleRole.4262* Returns null on error or if the AccessibleContext does not exist.4263*/4264private AccessibleContext getParentWithRole (final AccessibleContext ac,4265final String roleName) {4266debugString("[INFO]: getParentWithRole; ac = "+ac + "\n role = "+roleName);4267if (ac == null || roleName == null) {4268return null;4269}42704271return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {4272@Override4273public AccessibleContext call() throws Exception {4274AccessibleRole role = AccessBridge.this.accessibleRoleMap.get(roleName);4275if (role == null) {4276return ac;4277}42784279Accessible parent = ac.getAccessibleParent();4280if (parent == null && ac.getAccessibleRole() == role) {4281return ac;4282}42834284Accessible tmp = parent;4285AccessibleContext tmp_ac = null;42864287while (tmp != null && (tmp_ac = tmp.getAccessibleContext()) != null) {4288AccessibleRole ar = tmp_ac.getAccessibleRole();4289if (ar == role) {4290// found4291return tmp_ac;4292}4293parent = tmp;4294tmp = parent.getAccessibleContext().getAccessibleParent();4295}4296// not found4297return null;4298}4299}, ac);4300}43014302/**4303* Returns the parent AccessibleContext that has the specified AccessibleRole.4304* Otherwise, returns the top level object for the Java Window.4305* Returns (AccessibleContext)0 on error.4306*/4307private AccessibleContext getParentWithRoleElseRoot (AccessibleContext ac,4308String roleName) {4309AccessibleContext retval = getParentWithRole(ac, roleName);4310if (retval == null) {4311retval = getTopLevelObject(ac);4312}4313return retval;4314}43154316/**4317* Returns how deep in the object hierarchy a given object is.4318* The top most object in the object hierarchy has an object depth of 0.4319* Returns -1 on error.4320*/4321private int getObjectDepth(final AccessibleContext ac) {4322debugString("[INFO]: getObjectDepth: ac = "+ac);43234324if (ac == null) {4325return -1;4326}4327return InvocationUtils.invokeAndWait(new Callable<Integer>() {4328@Override4329public Integer call() throws Exception {4330int count = 0;4331Accessible parent = ac.getAccessibleParent();4332if (parent == null) {4333return count;4334}4335Accessible tmp = parent;4336while (tmp != null && tmp.getAccessibleContext() != null) {4337parent = tmp;4338tmp = parent.getAccessibleContext().getAccessibleParent();4339count++;4340}4341return count;4342}4343}, ac);4344}43454346/**4347* Returns the Accessible Context of the current ActiveDescendent of an object.4348* Returns (AccessibleContext)0 on error.4349*/4350private AccessibleContext getActiveDescendent (final AccessibleContext ac) {4351debugString("[INFO]: getActiveDescendent: ac = "+ac);4352if (ac == null) {4353return null;4354}4355// workaround for JTree bug where the only possible active4356// descendent is the JTree root4357final Accessible parent = InvocationUtils.invokeAndWait(new Callable<Accessible>() {4358@Override4359public Accessible call() throws Exception {4360return ac.getAccessibleParent();4361}4362}, ac);43634364if (parent != null) {4365Accessible child = InvocationUtils.invokeAndWait(new Callable<Accessible>() {4366@Override4367public Accessible call() throws Exception {4368int indexInParent = ac.getAccessibleIndexInParent();4369return parent.getAccessibleContext().getAccessibleChild(indexInParent);4370}4371}, ac);43724373if (child instanceof JTree) {4374// return the selected node4375final JTree tree = (JTree)child;4376return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {4377@Override4378public AccessibleContext call() throws Exception {4379return new AccessibleJTreeNode(tree,4380tree.getSelectionPath(),4381null);4382}4383}, child);4384}4385}43864387return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {4388@Override4389public AccessibleContext call() throws Exception {4390AccessibleSelection as = ac.getAccessibleSelection();4391if (as == null) {4392return null;4393}4394// assume single selection4395if (as.getAccessibleSelectionCount() != 1) {4396return null;4397}4398Accessible a = as.getAccessibleSelection(0);4399if (a == null) {4400return null;4401}4402return a.getAccessibleContext();4403}4404}, ac);4405}440644074408/**4409* Additional methods for Teton4410*/44114412/**4413* Gets the AccessibleName for a component based upon the JAWS algorithm.4414* Returns whether successful.4415*4416* Bug ID 4916682 - Implement JAWS AccessibleName policy4417*/4418private String getJAWSAccessibleName(final AccessibleContext ac) {4419debugString("[INFO]: getJAWSAccessibleName");4420if (ac == null) {4421return null;4422}4423// placeholder4424return InvocationUtils.invokeAndWait(new Callable<String>() {4425@Override4426public String call() throws Exception {4427return ac.getAccessibleName();4428}4429}, ac);4430}44314432/**4433* Request focus for a component. Returns whether successful;4434*4435* Bug ID 4944757 - requestFocus method needed4436*/4437private boolean requestFocus(final AccessibleContext ac) {4438debugString("[INFO]: requestFocus");4439if (ac == null) {4440return false;4441}4442return InvocationUtils.invokeAndWait(new Callable<Boolean>() {4443@Override4444public Boolean call() throws Exception {4445AccessibleComponent acomp = ac.getAccessibleComponent();4446if (acomp == null) {4447return false;4448}4449acomp.requestFocus();4450return ac.getAccessibleStateSet().contains(AccessibleState.FOCUSED);4451}4452}, ac);4453}44544455/**4456* Selects text between two indices. Selection includes the4457* text at the start index and the text at the end index. Returns4458* whether successful;4459*4460* Bug ID 4944758 - selectTextRange method needed4461*/4462private boolean selectTextRange(final AccessibleContext ac, final int startIndex, final int endIndex) {4463debugString("[INFO]: selectTextRange: start = "+startIndex+"; end = "+endIndex);4464if (ac == null) {4465return false;4466}4467return InvocationUtils.invokeAndWait(new Callable<Boolean>() {4468@Override4469public Boolean call() throws Exception {4470AccessibleText at = ac.getAccessibleText();4471if (!(at instanceof AccessibleEditableText)) {4472return false;4473}4474((AccessibleEditableText) at).selectText(startIndex, endIndex);44754476boolean result = at.getSelectionStart() == startIndex &&4477at.getSelectionEnd() == endIndex;4478return result;4479}4480}, ac);4481}44824483/**4484* Set the caret to a text position. Returns whether successful;4485*4486* Bug ID 4944770 - setCaretPosition method needed4487*/4488private boolean setCaretPosition(final AccessibleContext ac, final int position) {4489debugString("[INFO]: setCaretPosition: position = "+position);4490if (ac == null) {4491return false;4492}4493return InvocationUtils.invokeAndWait(new Callable<Boolean>() {4494@Override4495public Boolean call() throws Exception {4496AccessibleText at = ac.getAccessibleText();4497if (!(at instanceof AccessibleEditableText)) {4498return false;4499}4500((AccessibleEditableText) at).selectText(position, position);4501return at.getCaretPosition() == position;4502}4503}, ac);4504}45054506/**4507* Gets the number of visible children of an AccessibleContext.4508*4509* Bug ID 4944762- getVisibleChildren for list-like components needed4510*/4511private int _visibleChildrenCount;4512private AccessibleContext _visibleChild;4513private int _currentVisibleIndex;4514private boolean _foundVisibleChild;45154516private int getVisibleChildrenCount(AccessibleContext ac) {4517debugString("[INFO]: getVisibleChildrenCount");4518if (ac == null) {4519return -1;4520}4521_visibleChildrenCount = 0;4522_getVisibleChildrenCount(ac);4523debugString("[INFO]: _visibleChildrenCount = "+_visibleChildrenCount);4524return _visibleChildrenCount;4525}45264527/*4528* Recursively descends AccessibleContext and gets the number4529* of visible children4530*/4531private void _getVisibleChildrenCount(final AccessibleContext ac) {4532if (ac == null)4533return;4534if(ac instanceof AccessibleExtendedTable) {4535_getVisibleChildrenCount((AccessibleExtendedTable)ac);4536return;4537}4538int numChildren = InvocationUtils.invokeAndWait(new Callable<Integer>() {4539@Override4540public Integer call() throws Exception {4541return ac.getAccessibleChildrenCount();4542}4543}, ac);4544for (int i = 0; i < numChildren; i++) {4545final int idx = i;4546final AccessibleContext ac2 = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {4547@Override4548public AccessibleContext call() throws Exception {4549Accessible a = ac.getAccessibleChild(idx);4550if (a != null)4551return a.getAccessibleContext();4552else4553return null;4554}4555}, ac);4556if ( ac2 == null ||4557(!InvocationUtils.invokeAndWait(new Callable<Boolean>() {4558@Override4559public Boolean call() throws Exception {4560return ac2.getAccessibleStateSet().contains(AccessibleState.SHOWING);4561}4562}, ac))4563) {4564continue;4565}4566_visibleChildrenCount++;45674568if (InvocationUtils.invokeAndWait(new Callable<Integer>() {4569@Override4570public Integer call() throws Exception {4571return ac2.getAccessibleChildrenCount();4572}4573}, ac) > 0 ) {4574_getVisibleChildrenCount(ac2);4575}4576}4577}45784579/*4580* Recursively descends AccessibleContext and gets the number4581* of visible children. Stops search if get to invisible part of table.4582*/4583private void _getVisibleChildrenCount(final AccessibleExtendedTable acTable) {4584if (acTable == null)4585return;4586int lastVisibleRow = -1;4587int lastVisibleColumn = -1;4588boolean foundVisible = false;4589int rowCount = InvocationUtils.invokeAndWait(new Callable<Integer>() {4590@Override4591public Integer call() throws Exception {4592return acTable.getAccessibleRowCount();4593}4594}, acTable);4595int columnCount = InvocationUtils.invokeAndWait(new Callable<Integer>() {4596@Override4597public Integer call() throws Exception {4598return acTable.getAccessibleColumnCount();4599}4600}, acTable);4601for (int rowIdx = 0; rowIdx < rowCount; rowIdx++) {4602for (int columnIdx = 0; columnIdx < columnCount; columnIdx++) {4603if (lastVisibleRow != -1 && rowIdx > lastVisibleRow) {4604continue;4605}4606if (lastVisibleColumn != -1 && columnIdx > lastVisibleColumn) {4607continue;4608}4609int finalRowIdx = rowIdx;4610int finalColumnIdx = columnIdx;4611final AccessibleContext ac2 = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {4612@Override4613public AccessibleContext call() throws Exception {4614Accessible a = acTable.getAccessibleAt(finalRowIdx, finalColumnIdx);4615if (a == null)4616return null;4617else4618return a.getAccessibleContext();4619}4620}, acTable);4621if (ac2 == null ||4622(!InvocationUtils.invokeAndWait(new Callable<Boolean>() {4623@Override4624public Boolean call() throws Exception {4625return ac2.getAccessibleStateSet().contains(AccessibleState.SHOWING);4626}4627}, acTable))4628) {4629if (foundVisible) {4630if (columnIdx != 0 && lastVisibleColumn == -1) {4631//the same row, so we found the last visible column4632lastVisibleColumn = columnIdx - 1;4633} else if (columnIdx == 0 && lastVisibleRow == -1) {4634lastVisibleRow = rowIdx - 1;4635}4636}4637continue;4638}46394640foundVisible = true;46414642_visibleChildrenCount++;46434644if (InvocationUtils.invokeAndWait(new Callable<Integer>() {4645@Override4646public Integer call() throws Exception {4647return ac2.getAccessibleChildrenCount();4648}4649}, acTable) > 0) {4650_getVisibleChildrenCount(ac2);4651}4652}4653}4654}46554656/**4657* Gets the visible child of an AccessibleContext at the4658* specified index4659*4660* Bug ID 4944762- getVisibleChildren for list-like components needed4661*/4662private AccessibleContext getVisibleChild(AccessibleContext ac, int index) {4663debugString("[INFO]: getVisibleChild: index = "+index);4664if (ac == null) {4665return null;4666}4667_visibleChild = null;4668_currentVisibleIndex = 0;4669_foundVisibleChild = false;4670_getVisibleChild(ac, index);46714672if (_visibleChild != null) {4673debugString( "[INFO]: getVisibleChild: found child = " +4674InvocationUtils.invokeAndWait(new Callable<String>() {4675@Override4676public String call() throws Exception {4677return AccessBridge.this._visibleChild.getAccessibleName();4678}4679}, ac) );4680}4681return _visibleChild;4682}46834684/*4685* Recursively searchs AccessibleContext and finds the visible component4686* at the specified index4687*/4688private void _getVisibleChild(final AccessibleContext ac, final int index) {4689if (_visibleChild != null) {4690return;4691}4692if(ac instanceof AccessibleExtendedTable) {4693_getVisibleChild((AccessibleExtendedTable)ac, index);4694return;4695}4696int numChildren = InvocationUtils.invokeAndWait(new Callable<Integer>() {4697@Override4698public Integer call() throws Exception {4699return ac.getAccessibleChildrenCount();4700}4701}, ac);4702for (int i = 0; i < numChildren; i++) {4703final int idx=i;4704final AccessibleContext ac2 = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {4705@Override4706public AccessibleContext call() throws Exception {4707Accessible a = ac.getAccessibleChild(idx);4708if (a == null)4709return null;4710else4711return a.getAccessibleContext();4712}4713}, ac);4714if (ac2 == null ||4715(!InvocationUtils.invokeAndWait(new Callable<Boolean>() {4716@Override4717public Boolean call() throws Exception {4718return ac2.getAccessibleStateSet().contains(AccessibleState.SHOWING);4719}4720}, ac))) {4721continue;4722}4723if (!_foundVisibleChild && _currentVisibleIndex == index) {4724_visibleChild = ac2;4725_foundVisibleChild = true;4726return;4727}4728_currentVisibleIndex++;47294730if ( InvocationUtils.invokeAndWait(new Callable<Integer>() {4731@Override4732public Integer call() throws Exception {4733return ac2.getAccessibleChildrenCount();4734}4735}, ac) > 0 ) {4736_getVisibleChild(ac2, index);4737}4738}4739}47404741private void _getVisibleChild(final AccessibleExtendedTable acTable, final int index) {4742if (_visibleChild != null) {4743return;4744}4745int lastVisibleRow = -1;4746int lastVisibleColumn = -1;4747boolean foundVisible = false;4748int rowCount = InvocationUtils.invokeAndWait(new Callable<Integer>() {4749@Override4750public Integer call() throws Exception {4751return acTable.getAccessibleRowCount();4752}4753}, acTable);4754int columnCount = InvocationUtils.invokeAndWait(new Callable<Integer>() {4755@Override4756public Integer call() throws Exception {4757return acTable.getAccessibleColumnCount();4758}4759}, acTable);4760for (int rowIdx = 0; rowIdx < rowCount; rowIdx++) {4761for (int columnIdx = 0; columnIdx < columnCount; columnIdx++) {4762if (lastVisibleRow != -1 && rowIdx > lastVisibleRow) {4763continue;4764}4765if (lastVisibleColumn != -1 && columnIdx > lastVisibleColumn) {4766continue;4767}4768int finalRowIdx = rowIdx;4769int finalColumnIdx = columnIdx;4770final AccessibleContext ac2 = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {4771@Override4772public AccessibleContext call() throws Exception {4773Accessible a = acTable.getAccessibleAt(finalRowIdx, finalColumnIdx);4774if (a == null)4775return null;4776else4777return a.getAccessibleContext();4778}4779}, acTable);4780if (ac2 == null ||4781(!InvocationUtils.invokeAndWait(new Callable<Boolean>() {4782@Override4783public Boolean call() throws Exception {4784return ac2.getAccessibleStateSet().contains(AccessibleState.SHOWING);4785}4786}, acTable))) {4787if (foundVisible) {4788if (columnIdx != 0 && lastVisibleColumn == -1) {4789//the same row, so we found the last visible column4790lastVisibleColumn = columnIdx - 1;4791} else if (columnIdx == 0 && lastVisibleRow == -1) {4792lastVisibleRow = rowIdx - 1;4793}4794}4795continue;4796}4797foundVisible = true;47984799if (!_foundVisibleChild && _currentVisibleIndex == index) {4800_visibleChild = ac2;4801_foundVisibleChild = true;4802return;4803}4804_currentVisibleIndex++;48054806if (InvocationUtils.invokeAndWait(new Callable<Integer>() {4807@Override4808public Integer call() throws Exception {4809return ac2.getAccessibleChildrenCount();4810}4811}, acTable) > 0) {4812_getVisibleChild(ac2, index);4813}4814}4815}4816}48174818/* ===== Java object memory management code ===== */48194820/**4821* Class to track object references to ensure the4822* Java VM doesn't garbage collect them4823*/4824private class ObjectReferences {48254826private class Reference {4827private int value;48284829Reference(int i) {4830value = i;4831}48324833public String toString() {4834return ("refCount: " + value);4835}4836}48374838/**4839* table object references, to keep 'em from being garbage collected4840*/4841private ConcurrentHashMap<Object,Reference> refs;48424843/**4844* Constructor4845*/4846ObjectReferences() {4847refs = new ConcurrentHashMap<>(4);4848}48494850/**4851* Debugging: dump the contents of ObjectReferences' refs Hashtable4852*/4853String dump() {4854return refs.toString();4855}48564857/**4858* Increment ref count; set to 1 if we have no references for it4859*/4860void increment(Object o) {4861if (o == null){4862debugString("[WARN]: ObjectReferences::increment - Passed in object is null");4863return;4864}48654866if (refs.containsKey(o)) {4867(refs.get(o)).value++;4868} else {4869refs.put(o, new Reference(1));4870}4871}48724873/**4874* Decrement ref count; remove if count drops to 04875*/4876void decrement(Object o) {4877Reference aRef = refs.get(o);4878if (aRef != null) {4879aRef.value--;4880if (aRef.value == 0) {4881refs.remove(o);4882} else if (aRef.value < 0) {4883debugString("[ERROR]: decrementing reference count below 0");4884}4885} else {4886debugString("[ERROR]: object to decrement not in ObjectReferences table");4887}4888}48894890}48914892/* ===== event handling code ===== */48934894/**4895* native method for handling property change events4896*/4897private native void propertyCaretChange(PropertyChangeEvent e,4898AccessibleContext src,4899int oldValue, int newValue);4900private native void propertyDescriptionChange(PropertyChangeEvent e,4901AccessibleContext src,4902String oldValue, String newValue);4903private native void propertyNameChange(PropertyChangeEvent e,4904AccessibleContext src,4905String oldValue, String newValue);4906private native void propertySelectionChange(PropertyChangeEvent e,4907AccessibleContext src);4908private native void propertyStateChange(PropertyChangeEvent e,4909AccessibleContext src,4910String oldValue, String newValue);4911private native void propertyTextChange(PropertyChangeEvent e,4912AccessibleContext src);4913private native void propertyValueChange(PropertyChangeEvent e,4914AccessibleContext src,4915String oldValue, String newValue);4916private native void propertyVisibleDataChange(PropertyChangeEvent e,4917AccessibleContext src);4918private native void propertyChildChange(PropertyChangeEvent e,4919AccessibleContext src,4920AccessibleContext oldValue,4921AccessibleContext newValue);4922private native void propertyActiveDescendentChange(PropertyChangeEvent e,4923AccessibleContext src,4924AccessibleContext oldValue,4925AccessibleContext newValue);49264927private native void javaShutdown();49284929/**4930* native methods for handling focus events4931*/4932private native void focusGained(FocusEvent e, AccessibleContext src);4933private native void focusLost(FocusEvent e, AccessibleContext src);49344935/**4936* native method for handling caret events4937*/4938private native void caretUpdate(CaretEvent e, AccessibleContext src);49394940/**4941* native methods for handling mouse events4942*/4943private native void mouseClicked(MouseEvent e, AccessibleContext src);4944private native void mouseEntered(MouseEvent e, AccessibleContext src);4945private native void mouseExited(MouseEvent e, AccessibleContext src);4946private native void mousePressed(MouseEvent e, AccessibleContext src);4947private native void mouseReleased(MouseEvent e, AccessibleContext src);49484949/**4950* native methods for handling menu & popupMenu events4951*/4952private native void menuCanceled(MenuEvent e, AccessibleContext src);4953private native void menuDeselected(MenuEvent e, AccessibleContext src);4954private native void menuSelected(MenuEvent e, AccessibleContext src);4955private native void popupMenuCanceled(PopupMenuEvent e, AccessibleContext src);4956private native void popupMenuWillBecomeInvisible(PopupMenuEvent e,4957AccessibleContext src);4958private native void popupMenuWillBecomeVisible(PopupMenuEvent e,4959AccessibleContext src);49604961/* ===== event definitions ===== */49624963private static final long PROPERTY_CHANGE_EVENTS = 1;4964private static final long FOCUS_GAINED_EVENTS = 2;4965private static final long FOCUS_LOST_EVENTS = 4;4966private static final long FOCUS_EVENTS = (FOCUS_GAINED_EVENTS | FOCUS_LOST_EVENTS);49674968private static final long CARET_UPATE_EVENTS = 8;4969private static final long CARET_EVENTS = CARET_UPATE_EVENTS;49704971private static final long MOUSE_CLICKED_EVENTS = 16;4972private static final long MOUSE_ENTERED_EVENTS = 32;4973private static final long MOUSE_EXITED_EVENTS = 64;4974private static final long MOUSE_PRESSED_EVENTS = 128;4975private static final long MOUSE_RELEASED_EVENTS = 256;4976private static final long MOUSE_EVENTS = (MOUSE_CLICKED_EVENTS | MOUSE_ENTERED_EVENTS |4977MOUSE_EXITED_EVENTS | MOUSE_PRESSED_EVENTS |4978MOUSE_RELEASED_EVENTS);49794980private static final long MENU_CANCELED_EVENTS = 512;4981private static final long MENU_DESELECTED_EVENTS = 1024;4982private static final long MENU_SELECTED_EVENTS = 2048;4983private static final long MENU_EVENTS = (MENU_CANCELED_EVENTS | MENU_DESELECTED_EVENTS |4984MENU_SELECTED_EVENTS);49854986private static final long POPUPMENU_CANCELED_EVENTS = 4096;4987private static final long POPUPMENU_WILL_BECOME_INVISIBLE_EVENTS = 8192;4988private static final long POPUPMENU_WILL_BECOME_VISIBLE_EVENTS = 16384;4989private static final long POPUPMENU_EVENTS = (POPUPMENU_CANCELED_EVENTS |4990POPUPMENU_WILL_BECOME_INVISIBLE_EVENTS |4991POPUPMENU_WILL_BECOME_VISIBLE_EVENTS);49924993/* These use their own numbering scheme, to ensure sufficient expansion room */4994private static final long PROPERTY_NAME_CHANGE_EVENTS = 1;4995private static final long PROPERTY_DESCRIPTION_CHANGE_EVENTS = 2;4996private static final long PROPERTY_STATE_CHANGE_EVENTS = 4;4997private static final long PROPERTY_VALUE_CHANGE_EVENTS = 8;4998private static final long PROPERTY_SELECTION_CHANGE_EVENTS = 16;4999private static final long PROPERTY_TEXT_CHANGE_EVENTS = 32;5000private static final long PROPERTY_CARET_CHANGE_EVENTS = 64;5001private static final long PROPERTY_VISIBLEDATA_CHANGE_EVENTS = 128;5002private static final long PROPERTY_CHILD_CHANGE_EVENTS = 256;5003private static final long PROPERTY_ACTIVEDESCENDENT_CHANGE_EVENTS = 512;500450055006private static final long PROPERTY_EVENTS = (PROPERTY_NAME_CHANGE_EVENTS |5007PROPERTY_DESCRIPTION_CHANGE_EVENTS |5008PROPERTY_STATE_CHANGE_EVENTS |5009PROPERTY_VALUE_CHANGE_EVENTS |5010PROPERTY_SELECTION_CHANGE_EVENTS |5011PROPERTY_TEXT_CHANGE_EVENTS |5012PROPERTY_CARET_CHANGE_EVENTS |5013PROPERTY_VISIBLEDATA_CHANGE_EVENTS |5014PROPERTY_CHILD_CHANGE_EVENTS |5015PROPERTY_ACTIVEDESCENDENT_CHANGE_EVENTS);50165017/**5018* The EventHandler class listens for Java events and5019* forwards them to the AT5020*/5021private class EventHandler implements PropertyChangeListener,5022FocusListener, CaretListener,5023MenuListener, PopupMenuListener,5024MouseListener, WindowListener,5025ChangeListener {50265027private AccessBridge accessBridge;5028private long javaEventMask = 0;5029private long accessibilityEventMask = 0;50305031EventHandler(AccessBridge bridge) {5032accessBridge = bridge;50335034// Register to receive WINDOW_OPENED and WINDOW_CLOSED5035// events. Add the event source as a native window5036// handler is it implements NativeWindowHandler.5037// SwingEventMonitor.addWindowListener(this);5038}50395040// --------- Event Notification Registration methods50415042/**5043* Invoked the first time a window is made visible.5044*/5045public void windowOpened(WindowEvent e) {5046// If the window is a NativeWindowHandler, add it.5047Object o = null;5048if (e != null)5049o = e.getSource();5050if (o instanceof NativeWindowHandler) {5051addNativeWindowHandler((NativeWindowHandler)o);5052}5053}50545055/**5056* Invoked when the user attempts to close the window5057* from the window's system menu. If the program does not5058* explicitly hide or dispose the window while processing5059* this event, the window close operation will be canceled.5060*/5061public void windowClosing(WindowEvent e) {}50625063/**5064* Invoked when a window has been closed as the result5065* of calling dispose on the window.5066*/5067public void windowClosed(WindowEvent e) {5068// If the window is a NativeWindowHandler, remove it.5069Object o = null;5070if (e != null)5071o = e.getSource();5072if (o instanceof NativeWindowHandler) {5073removeNativeWindowHandler((NativeWindowHandler)o);5074}5075}50765077/**5078* Invoked when a window is changed from a normal to a5079* minimized state. For many platforms, a minimized window5080* is displayed as the icon specified in the window's5081* iconImage property.5082* @see java.awt.Frame#setIconImage5083*/5084public void windowIconified(WindowEvent e) {}50855086/**5087* Invoked when a window is changed from a minimized5088* to a normal state.5089*/5090public void windowDeiconified(WindowEvent e) {}50915092/**5093* Invoked when the Window is set to be the active Window. Only a Frame or5094* a Dialog can be the active Window. The native windowing system may5095* denote the active Window or its children with special decorations, such5096* as a highlighted title bar. The active Window is always either the5097* focused Window, or the first Frame or Dialog that is an owner of the5098* focused Window.5099*/5100public void windowActivated(WindowEvent e) {}51015102/**5103* Invoked when a Window is no longer the active Window. Only a Frame or a5104* Dialog can be the active Window. The native windowing system may denote5105* the active Window or its children with special decorations, such as a5106* highlighted title bar. The active Window is always either the focused5107* Window, or the first Frame or Dialog that is an owner of the focused5108* Window.5109*/5110public void windowDeactivated(WindowEvent e) {}51115112/**5113* Turn on event monitoring for the event type passed in5114* If necessary, add the appropriate event listener (if5115* no other event of that type is being listened for)5116*/5117void addJavaEventNotification(long type) {5118long newEventMask = javaEventMask | type;5119/*5120if ( ((javaEventMask & PROPERTY_EVENTS) == 0) &&5121((newEventMask & PROPERTY_EVENTS) != 0) ) {5122AccessibilityEventMonitor.addPropertyChangeListener(this);5123}5124*/5125if ( ((javaEventMask & FOCUS_EVENTS) == 0) &&5126((newEventMask & FOCUS_EVENTS) != 0) ) {5127SwingEventMonitor.addFocusListener(this);5128}5129if ( ((javaEventMask & CARET_EVENTS) == 0) &&5130((newEventMask & CARET_EVENTS) != 0) ) {5131SwingEventMonitor.addCaretListener(this);5132}5133if ( ((javaEventMask & MOUSE_EVENTS) == 0) &&5134((newEventMask & MOUSE_EVENTS) != 0) ) {5135SwingEventMonitor.addMouseListener(this);5136}5137if ( ((javaEventMask & MENU_EVENTS) == 0) &&5138((newEventMask & MENU_EVENTS) != 0) ) {5139SwingEventMonitor.addMenuListener(this);5140SwingEventMonitor.addPopupMenuListener(this);5141}5142if ( ((javaEventMask & POPUPMENU_EVENTS) == 0) &&5143((newEventMask & POPUPMENU_EVENTS) != 0) ) {5144SwingEventMonitor.addPopupMenuListener(this);5145}51465147javaEventMask = newEventMask;5148}51495150/**5151* Turn off event monitoring for the event type passed in5152* If necessary, remove the appropriate event listener (if5153* no other event of that type is being listened for)5154*/5155void removeJavaEventNotification(long type) {5156long newEventMask = javaEventMask & (~type);5157/*5158if ( ((javaEventMask & PROPERTY_EVENTS) != 0) &&5159((newEventMask & PROPERTY_EVENTS) == 0) ) {5160AccessibilityEventMonitor.removePropertyChangeListener(this);5161}5162*/5163if (((javaEventMask & FOCUS_EVENTS) != 0) &&5164((newEventMask & FOCUS_EVENTS) == 0)) {5165SwingEventMonitor.removeFocusListener(this);5166}5167if (((javaEventMask & CARET_EVENTS) != 0) &&5168((newEventMask & CARET_EVENTS) == 0)) {5169SwingEventMonitor.removeCaretListener(this);5170}5171if (((javaEventMask & MOUSE_EVENTS) == 0) &&5172((newEventMask & MOUSE_EVENTS) != 0)) {5173SwingEventMonitor.removeMouseListener(this);5174}5175if (((javaEventMask & MENU_EVENTS) == 0) &&5176((newEventMask & MENU_EVENTS) != 0)) {5177SwingEventMonitor.removeMenuListener(this);5178}5179if (((javaEventMask & POPUPMENU_EVENTS) == 0) &&5180((newEventMask & POPUPMENU_EVENTS) != 0)) {5181SwingEventMonitor.removePopupMenuListener(this);5182}51835184javaEventMask = newEventMask;5185}51865187/**5188* Turn on event monitoring for the event type passed in5189* If necessary, add the appropriate event listener (if5190* no other event of that type is being listened for)5191*/5192void addAccessibilityEventNotification(long type) {5193long newEventMask = accessibilityEventMask | type;5194if ( ((accessibilityEventMask & PROPERTY_EVENTS) == 0) &&5195((newEventMask & PROPERTY_EVENTS) != 0) ) {5196AccessibilityEventMonitor.addPropertyChangeListener(this);5197}5198accessibilityEventMask = newEventMask;5199}52005201/**5202* Turn off event monitoring for the event type passed in5203* If necessary, remove the appropriate event listener (if5204* no other event of that type is being listened for)5205*/5206void removeAccessibilityEventNotification(long type) {5207long newEventMask = accessibilityEventMask & (~type);5208if ( ((accessibilityEventMask & PROPERTY_EVENTS) != 0) &&5209((newEventMask & PROPERTY_EVENTS) == 0) ) {5210AccessibilityEventMonitor.removePropertyChangeListener(this);5211}5212accessibilityEventMask = newEventMask;5213}52145215/**5216* ------- property change event glue5217*/5218// This is invoked on the EDT , as5219public void propertyChange(PropertyChangeEvent e) {52205221accessBridge.debugString("[INFO]: propertyChange(" + e.toString() + ") called");52225223if (e != null && (accessibilityEventMask & PROPERTY_EVENTS) != 0) {5224Object o = e.getSource();5225AccessibleContext ac;52265227if (o instanceof AccessibleContext) {5228ac = (AccessibleContext) o;5229} else {5230Accessible a = Translator.getAccessible(e.getSource());5231if (a == null)5232return;5233else5234ac = a.getAccessibleContext();5235}5236if (ac != null) {5237InvocationUtils.registerAccessibleContext(ac, AppContext.getAppContext());52385239accessBridge.debugString("[INFO]: AccessibleContext: " + ac);5240String propertyName = e.getPropertyName();52415242if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_CARET_PROPERTY) == 0) {5243int oldValue = 0;5244int newValue = 0;52455246if (e.getOldValue() instanceof Integer) {5247oldValue = ((Integer) e.getOldValue()).intValue();5248}5249if (e.getNewValue() instanceof Integer) {5250newValue = ((Integer) e.getNewValue()).intValue();5251}5252accessBridge.debugString("[INFO]: - about to call propertyCaretChange() old value: " + oldValue + "new value: " + newValue);5253accessBridge.propertyCaretChange(e, ac, oldValue, newValue);52545255} else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_DESCRIPTION_PROPERTY) == 0) {5256String oldValue = null;5257String newValue = null;52585259if (e.getOldValue() != null) {5260oldValue = e.getOldValue().toString();5261}5262if (e.getNewValue() != null) {5263newValue = e.getNewValue().toString();5264}5265accessBridge.debugString("[INFO]: - about to call propertyDescriptionChange() old value: " + oldValue + "new value: " + newValue);5266accessBridge.propertyDescriptionChange(e, ac, oldValue, newValue);52675268} else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_NAME_PROPERTY) == 0) {5269String oldValue = null;5270String newValue = null;52715272if (e.getOldValue() != null) {5273oldValue = e.getOldValue().toString();5274}5275if (e.getNewValue() != null) {5276newValue = e.getNewValue().toString();5277}5278accessBridge.debugString("[INFO]: - about to call propertyNameChange() old value: " + oldValue + " new value: " + newValue);5279accessBridge.propertyNameChange(e, ac, oldValue, newValue);52805281} else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY) == 0) {5282accessBridge.debugString("[INFO]: - about to call propertySelectionChange() " + ac + " " + Thread.currentThread() + " " + e.getSource());52835284accessBridge.propertySelectionChange(e, ac);52855286} else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_STATE_PROPERTY) == 0) {5287String oldValue = null;5288String newValue = null;52895290// Localization fix requested by Oliver for EA-15291if (e.getOldValue() != null) {5292AccessibleState oldState = (AccessibleState) e.getOldValue();5293oldValue = oldState.toDisplayString(Locale.US);5294}5295if (e.getNewValue() != null) {5296AccessibleState newState = (AccessibleState) e.getNewValue();5297newValue = newState.toDisplayString(Locale.US);5298}52995300accessBridge.debugString("[INFO]: - about to call propertyStateChange()");5301accessBridge.propertyStateChange(e, ac, oldValue, newValue);53025303} else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_TEXT_PROPERTY) == 0) {5304accessBridge.debugString("[INFO]: - about to call propertyTextChange()");5305accessBridge.propertyTextChange(e, ac);53065307} else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_VALUE_PROPERTY) == 0) { // strings 'cause of floating point, etc.5308String oldValue = null;5309String newValue = null;53105311if (e.getOldValue() != null) {5312oldValue = e.getOldValue().toString();5313}5314if (e.getNewValue() != null) {5315newValue = e.getNewValue().toString();5316}5317accessBridge.debugString("[INFO]: - about to call propertyDescriptionChange()");5318accessBridge.propertyValueChange(e, ac, oldValue, newValue);53195320} else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY) == 0) {5321accessBridge.propertyVisibleDataChange(e, ac);53225323} else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_CHILD_PROPERTY) == 0) {5324AccessibleContext oldAC = null;5325AccessibleContext newAC = null;5326Accessible a;53275328if (e.getOldValue() instanceof AccessibleContext) {5329oldAC = (AccessibleContext) e.getOldValue();5330InvocationUtils.registerAccessibleContext(oldAC, AppContext.getAppContext());5331}5332if (e.getNewValue() instanceof AccessibleContext) {5333newAC = (AccessibleContext) e.getNewValue();5334InvocationUtils.registerAccessibleContext(newAC, AppContext.getAppContext());5335}5336accessBridge.debugString("[INFO]: - about to call propertyChildChange() old AC: " + oldAC + "new AC: " + newAC);5337accessBridge.propertyChildChange(e, ac, oldAC, newAC);53385339} else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY) == 0) {5340handleActiveDescendentEvent(e, ac);5341}5342}5343}5344}53455346/*5347* Handle an ActiveDescendent PropertyChangeEvent. This5348* method works around a JTree bug where ActiveDescendent5349* PropertyChangeEvents have the wrong parent.5350*/5351private AccessibleContext prevAC = null; // previous AccessibleContext53525353private void handleActiveDescendentEvent(PropertyChangeEvent e,5354AccessibleContext ac) {5355if (e == null || ac == null)5356return;5357AccessibleContext oldAC = null;5358AccessibleContext newAC = null;5359Accessible a;53605361// get the old active descendent5362if (e.getOldValue() instanceof Accessible) {5363oldAC = ((Accessible) e.getOldValue()).getAccessibleContext();5364} else if (e.getOldValue() instanceof Component) {5365a = Translator.getAccessible(e.getOldValue());5366if (a != null) {5367oldAC = a.getAccessibleContext();5368}5369}5370if (oldAC != null) {5371Accessible parent = oldAC.getAccessibleParent();5372if (parent instanceof JTree) {5373// use the previous AccessibleJTreeNode5374oldAC = prevAC;5375}5376}53775378// get the new active descendent5379if (e.getNewValue() instanceof Accessible) {5380newAC = ((Accessible) e.getNewValue()).getAccessibleContext();5381} else if (e.getNewValue() instanceof Component) {5382a = Translator.getAccessible(e.getNewValue());5383if (a != null) {5384newAC = a.getAccessibleContext();5385}5386}5387if (newAC != null) {5388Accessible parent = newAC.getAccessibleParent();5389if (parent instanceof JTree) {5390// use a new AccessibleJTreeNode with the right parent5391JTree tree = (JTree)parent;5392newAC = new AccessibleJTreeNode(tree,5393tree.getSelectionPath(),5394null);5395}5396}5397prevAC = newAC;53985399accessBridge.debugString("[INFO]: - about to call propertyActiveDescendentChange() AC: " + ac + " old AC: " + oldAC + "new AC: " + newAC);5400InvocationUtils.registerAccessibleContext(oldAC, AppContext.getAppContext());5401InvocationUtils.registerAccessibleContext(newAC, AppContext.getAppContext());5402accessBridge.propertyActiveDescendentChange(e, ac, oldAC, newAC);5403}54045405/**5406* ------- focus event glue5407*/5408private boolean stateChangeListenerAdded = false;54095410public void focusGained(FocusEvent e) {5411processFocusGained();5412}54135414public void stateChanged(ChangeEvent e) {5415processFocusGained();5416}54175418private void processFocusGained() {5419Component focusOwner = KeyboardFocusManager.5420getCurrentKeyboardFocusManager().getFocusOwner();5421if (focusOwner == null) {5422return;5423}54245425// Only menus and popup selections are handled by the JRootPane.5426if (focusOwner instanceof JRootPane) {5427MenuElement [] path =5428MenuSelectionManager.defaultManager().getSelectedPath();5429if (path.length > 1) {5430Component penult = path[path.length-2].getComponent();5431Component last = path[path.length-1].getComponent();54325433if (last instanceof JPopupMenu) {5434// This is a popup with nothing in the popup5435// selected. The menu itself is selected.5436FocusEvent e = new FocusEvent(penult, FocusEvent.FOCUS_GAINED);5437AccessibleContext context = penult.getAccessibleContext();5438InvocationUtils.registerAccessibleContext(context, SunToolkit.targetToAppContext(penult));5439accessBridge.focusGained(e, context);5440} else if (penult instanceof JPopupMenu) {5441// This is a popup with an item selected5442FocusEvent e =5443new FocusEvent(last, FocusEvent.FOCUS_GAINED);5444AccessibleContext focusedAC = last.getAccessibleContext();5445InvocationUtils.registerAccessibleContext(focusedAC, SunToolkit.targetToAppContext(last));5446accessBridge.debugString("[INFO]: - about to call focusGained() AC: " + focusedAC);5447accessBridge.focusGained(e, focusedAC);5448}5449}5450} else {5451// The focus owner has the selection.5452if (focusOwner instanceof Accessible) {5453FocusEvent e = new FocusEvent(focusOwner,5454FocusEvent.FOCUS_GAINED);5455AccessibleContext focusedAC = focusOwner.getAccessibleContext();5456InvocationUtils.registerAccessibleContext(focusedAC, SunToolkit.targetToAppContext(focusOwner));5457accessBridge.debugString("[INFO]: - about to call focusGained() AC: " + focusedAC);5458accessBridge.focusGained(e, focusedAC);5459}5460}5461}54625463public void focusLost(FocusEvent e) {5464if (e != null && (javaEventMask & FOCUS_LOST_EVENTS) != 0) {5465Accessible a = Translator.getAccessible(e.getSource());5466if (a != null) {5467accessBridge.debugString("[INFO]: - about to call focusLost() AC: " + a.getAccessibleContext());5468AccessibleContext context = a.getAccessibleContext();5469InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5470accessBridge.focusLost(e, context);5471}5472}5473}54745475/**5476* ------- caret event glue5477*/5478public void caretUpdate(CaretEvent e) {5479if (e != null && (javaEventMask & CARET_UPATE_EVENTS) != 0) {5480Accessible a = Translator.getAccessible(e.getSource());5481if (a != null) {5482AccessibleContext context = a.getAccessibleContext();5483InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5484accessBridge.caretUpdate(e, context);5485}5486}5487}54885489/**5490* ------- mouse event glue5491*/54925493public void mouseClicked(MouseEvent e) {5494if (e != null && (javaEventMask & MOUSE_CLICKED_EVENTS) != 0) {5495Accessible a = Translator.getAccessible(e.getSource());5496if (a != null) {5497AccessibleContext context = a.getAccessibleContext();5498InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5499accessBridge.mouseClicked(e, context);5500}5501}5502}55035504public void mouseEntered(MouseEvent e) {5505if (e != null && (javaEventMask & MOUSE_ENTERED_EVENTS) != 0) {5506Accessible a = Translator.getAccessible(e.getSource());5507if (a != null) {5508AccessibleContext context = a.getAccessibleContext();5509InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5510accessBridge.mouseEntered(e, context);5511}5512}5513}55145515public void mouseExited(MouseEvent e) {5516if (e != null && (javaEventMask & MOUSE_EXITED_EVENTS) != 0) {5517Accessible a = Translator.getAccessible(e.getSource());5518if (a != null) {5519AccessibleContext context = a.getAccessibleContext();5520InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5521accessBridge.mouseExited(e, context);5522}5523}5524}55255526public void mousePressed(MouseEvent e) {5527if (e != null && (javaEventMask & MOUSE_PRESSED_EVENTS) != 0) {5528Accessible a = Translator.getAccessible(e.getSource());5529if (a != null) {5530AccessibleContext context = a.getAccessibleContext();5531InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5532accessBridge.mousePressed(e, context);5533}5534}5535}55365537public void mouseReleased(MouseEvent e) {5538if (e != null && (javaEventMask & MOUSE_RELEASED_EVENTS) != 0) {5539Accessible a = Translator.getAccessible(e.getSource());5540if (a != null) {5541AccessibleContext context = a.getAccessibleContext();5542InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5543accessBridge.mouseReleased(e, context);5544}5545}5546}55475548/**5549* ------- menu event glue5550*/5551public void menuCanceled(MenuEvent e) {5552if (e != null && (javaEventMask & MENU_CANCELED_EVENTS) != 0) {5553Accessible a = Translator.getAccessible(e.getSource());5554if (a != null) {5555AccessibleContext context = a.getAccessibleContext();5556InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5557accessBridge.menuCanceled(e, context);5558}5559}5560}55615562public void menuDeselected(MenuEvent e) {5563if (e != null && (javaEventMask & MENU_DESELECTED_EVENTS) != 0) {5564Accessible a = Translator.getAccessible(e.getSource());5565if (a != null) {5566AccessibleContext context = a.getAccessibleContext();5567InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5568accessBridge.menuDeselected(e, context);5569}5570}5571}55725573public void menuSelected(MenuEvent e) {5574if (e != null && (javaEventMask & MENU_SELECTED_EVENTS) != 0) {5575Accessible a = Translator.getAccessible(e.getSource());5576if (a != null) {5577AccessibleContext context = a.getAccessibleContext();5578InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5579accessBridge.menuSelected(e, context);5580}5581}5582}55835584public void popupMenuCanceled(PopupMenuEvent e) {5585if (e != null && (javaEventMask & POPUPMENU_CANCELED_EVENTS) != 0) {5586Accessible a = Translator.getAccessible(e.getSource());5587if (a != null) {5588AccessibleContext context = a.getAccessibleContext();5589InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5590accessBridge.popupMenuCanceled(e, context);5591}5592}5593}55945595public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {5596if (e != null && (javaEventMask & POPUPMENU_WILL_BECOME_INVISIBLE_EVENTS) != 0) {5597Accessible a = Translator.getAccessible(e.getSource());5598if (a != null) {5599AccessibleContext context = a.getAccessibleContext();5600InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5601accessBridge.popupMenuWillBecomeInvisible(e, context);5602}5603}5604}56055606public void popupMenuWillBecomeVisible(PopupMenuEvent e) {5607if (e != null && (javaEventMask & POPUPMENU_WILL_BECOME_VISIBLE_EVENTS) != 0) {5608Accessible a = Translator.getAccessible(e.getSource());5609if (a != null) {5610AccessibleContext context = a.getAccessibleContext();5611InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());5612accessBridge.popupMenuWillBecomeVisible(e, context);5613}5614}5615}56165617} // End of EventHandler Class56185619// --------- Event Notification Registration methods56205621/**5622* Wrapper method around eventHandler.addJavaEventNotification()5623*/5624private void addJavaEventNotification(final long type) {5625EventQueue.invokeLater(new Runnable() {5626public void run(){5627eventHandler.addJavaEventNotification(type);5628}5629});5630}56315632/**5633* Wrapper method around eventHandler.removeJavaEventNotification()5634*/5635private void removeJavaEventNotification(final long type) {5636EventQueue.invokeLater(new Runnable() {5637public void run(){5638eventHandler.removeJavaEventNotification(type);5639}5640});5641}564256435644/**5645* Wrapper method around eventHandler.addAccessibilityEventNotification()5646*/5647private void addAccessibilityEventNotification(final long type) {5648EventQueue.invokeLater(new Runnable() {5649public void run(){5650eventHandler.addAccessibilityEventNotification(type);5651}5652});5653}56545655/**5656* Wrapper method around eventHandler.removeAccessibilityEventNotification()5657*/5658private void removeAccessibilityEventNotification(final long type) {5659EventQueue.invokeLater(new Runnable() {5660public void run(){5661eventHandler.removeAccessibilityEventNotification(type);5662}5663});5664}56655666/**5667******************************************************5668* All AccessibleRoles5669*5670* We shouldn't have to do this since it requires us5671* to synchronize the allAccessibleRoles array when5672* the AccessibleRoles class interface changes. However,5673* there is no Accessibility API method to get all5674* AccessibleRoles5675******************************************************5676*/5677private AccessibleRole [] allAccessibleRoles = {5678/**5679* Object is used to alert the user about something.5680*/5681AccessibleRole.ALERT,56825683/**5684* The header for a column of data.5685*/5686AccessibleRole.COLUMN_HEADER,56875688/**5689* Object that can be drawn into and is used to trap5690* events.5691* @see #FRAME5692* @see #GLASS_PANE5693* @see #LAYERED_PANE5694*/5695AccessibleRole.CANVAS,56965697/**5698* A list of choices the user can select from. Also optionally5699* allows the user to enter a choice of their own.5700*/5701AccessibleRole.COMBO_BOX,57025703/**5704* An iconified internal frame in a DESKTOP_PANE.5705* @see #DESKTOP_PANE5706* @see #INTERNAL_FRAME5707*/5708AccessibleRole.DESKTOP_ICON,57095710/**5711* A frame-like object that is clipped by a desktop pane. The5712* desktop pane, internal frame, and desktop icon objects are5713* often used to create multiple document interfaces within an5714* application.5715* @see #DESKTOP_ICON5716* @see #DESKTOP_PANE5717* @see #FRAME5718*/5719AccessibleRole.INTERNAL_FRAME,57205721/**5722* A pane that supports internal frames and5723* iconified versions of those internal frames.5724* @see #DESKTOP_ICON5725* @see #INTERNAL_FRAME5726*/5727AccessibleRole.DESKTOP_PANE,57285729/**5730* A specialized pane whose primary use is inside a DIALOG5731* @see #DIALOG5732*/5733AccessibleRole.OPTION_PANE,57345735/**5736* A top level window with no title or border.5737* @see #FRAME5738* @see #DIALOG5739*/5740AccessibleRole.WINDOW,57415742/**5743* A top level window with a title bar, border, menu bar, etc. It is5744* often used as the primary window for an application.5745* @see #DIALOG5746* @see #CANVAS5747* @see #WINDOW5748*/5749AccessibleRole.FRAME,57505751/**5752* A top level window with title bar and a border. A dialog is similar5753* to a frame, but it has fewer properties and is often used as a5754* secondary window for an application.5755* @see #FRAME5756* @see #WINDOW5757*/5758AccessibleRole.DIALOG,57595760/**5761* A specialized dialog that lets the user choose a color.5762*/5763AccessibleRole.COLOR_CHOOSER,576457655766/**5767* A pane that allows the user to navigate through5768* and select the contents of a directory. May be used5769* by a file chooser.5770* @see #FILE_CHOOSER5771*/5772AccessibleRole.DIRECTORY_PANE,57735774/**5775* A specialized dialog that displays the files in the directory5776* and lets the user select a file, browse a different directory,5777* or specify a filename. May use the directory pane to show the5778* contents of a directory.5779* @see #DIRECTORY_PANE5780*/5781AccessibleRole.FILE_CHOOSER,57825783/**5784* An object that fills up space in a user interface. It is often5785* used in interfaces to tweak the spacing between components,5786* but serves no other purpose.5787*/5788AccessibleRole.FILLER,57895790/**5791* A hypertext anchor5792*/5793// AccessibleRole.HYPERLINK,57945795/**5796* A small fixed size picture, typically used to decorate components.5797*/5798AccessibleRole.ICON,57995800/**5801* An object used to present an icon or short string in an interface.5802*/5803AccessibleRole.LABEL,58045805/**5806* A specialized pane that has a glass pane and a layered pane as its5807* children.5808* @see #GLASS_PANE5809* @see #LAYERED_PANE5810*/5811AccessibleRole.ROOT_PANE,58125813/**5814* A pane that is guaranteed to be painted on top5815* of all panes beneath it.5816* @see #ROOT_PANE5817* @see #CANVAS5818*/5819AccessibleRole.GLASS_PANE,58205821/**5822* A specialized pane that allows its children to be drawn in layers,5823* providing a form of stacking order. This is usually the pane that5824* holds the menu bar as well as the pane that contains most of the5825* visual components in a window.5826* @see #GLASS_PANE5827* @see #ROOT_PANE5828*/5829AccessibleRole.LAYERED_PANE,58305831/**5832* An object that presents a list of objects to the user and allows the5833* user to select one or more of them. A list is usually contained5834* within a scroll pane.5835* @see #SCROLL_PANE5836* @see #LIST_ITEM5837*/5838AccessibleRole.LIST,58395840/**5841* An object that presents an element in a list. A list is usually5842* contained within a scroll pane.5843* @see #SCROLL_PANE5844* @see #LIST5845*/5846AccessibleRole.LIST_ITEM,58475848/**5849* An object usually drawn at the top of the primary dialog box of5850* an application that contains a list of menus the user can choose5851* from. For example, a menu bar might contain menus for "File,"5852* "Edit," and "Help."5853* @see #MENU5854* @see #POPUP_MENU5855* @see #LAYERED_PANE5856*/5857AccessibleRole.MENU_BAR,58585859/**5860* A temporary window that is usually used to offer the user a5861* list of choices, and then hides when the user selects one of5862* those choices.5863* @see #MENU5864* @see #MENU_ITEM5865*/5866AccessibleRole.POPUP_MENU,58675868/**5869* An object usually found inside a menu bar that contains a list5870* of actions the user can choose from. A menu can have any object5871* as its children, but most often they are menu items, other menus,5872* or rudimentary objects such as radio buttons, check boxes, or5873* separators. For example, an application may have an "Edit" menu5874* that contains menu items for "Cut" and "Paste."5875* @see #MENU_BAR5876* @see #MENU_ITEM5877* @see #SEPARATOR5878* @see #RADIO_BUTTON5879* @see #CHECK_BOX5880* @see #POPUP_MENU5881*/5882AccessibleRole.MENU,58835884/**5885* An object usually contained in a menu that presents an action5886* the user can choose. For example, the "Cut" menu item in an5887* "Edit" menu would be an action the user can select to cut the5888* selected area of text in a document.5889* @see #MENU_BAR5890* @see #SEPARATOR5891* @see #POPUP_MENU5892*/5893AccessibleRole.MENU_ITEM,58945895/**5896* An object usually contained in a menu to provide a visual5897* and logical separation of the contents in a menu. For example,5898* the "File" menu of an application might contain menu items for5899* "Open," "Close," and "Exit," and will place a separator between5900* "Close" and "Exit" menu items.5901* @see #MENU5902* @see #MENU_ITEM5903*/5904AccessibleRole.SEPARATOR,59055906/**5907* An object that presents a series of panels (or page tabs), one at a5908* time, through some mechanism provided by the object. The most common5909* mechanism is a list of tabs at the top of the panel. The children of5910* a page tab list are all page tabs.5911* @see #PAGE_TAB5912*/5913AccessibleRole.PAGE_TAB_LIST,59145915/**5916* An object that is a child of a page tab list. Its sole child is5917* the panel that is to be presented to the user when the user5918* selects the page tab from the list of tabs in the page tab list.5919* @see #PAGE_TAB_LIST5920*/5921AccessibleRole.PAGE_TAB,59225923/**5924* A generic container that is often used to group objects.5925*/5926AccessibleRole.PANEL,59275928/**5929* An object used to indicate how much of a task has been completed.5930*/5931AccessibleRole.PROGRESS_BAR,59325933/**5934* A text object used for passwords, or other places where the5935* text contents is not shown visibly to the user5936*/5937AccessibleRole.PASSWORD_TEXT,59385939/**5940* An object the user can manipulate to tell the application to do5941* something.5942* @see #CHECK_BOX5943* @see #TOGGLE_BUTTON5944* @see #RADIO_BUTTON5945*/5946AccessibleRole.PUSH_BUTTON,59475948/**5949* A specialized push button that can be checked or unchecked, but5950* does not provide a separate indicator for the current state.5951* @see #PUSH_BUTTON5952* @see #CHECK_BOX5953* @see #RADIO_BUTTON5954*/5955AccessibleRole.TOGGLE_BUTTON,59565957/**5958* A choice that can be checked or unchecked and provides a5959* separate indicator for the current state.5960* @see #PUSH_BUTTON5961* @see #TOGGLE_BUTTON5962* @see #RADIO_BUTTON5963*/5964AccessibleRole.CHECK_BOX,59655966/**5967* A specialized check box that will cause other radio buttons in the5968* same group to become unchecked when this one is checked.5969* @see #PUSH_BUTTON5970* @see #TOGGLE_BUTTON5971* @see #CHECK_BOX5972*/5973AccessibleRole.RADIO_BUTTON,59745975/**5976* The header for a row of data.5977*/5978AccessibleRole.ROW_HEADER,59795980/**5981* An object that allows a user to incrementally view a large amount5982* of information. Its children can include scroll bars and a viewport.5983* @see #SCROLL_BAR5984* @see #VIEWPORT5985*/5986AccessibleRole.SCROLL_PANE,59875988/**5989* An object usually used to allow a user to incrementally view a5990* large amount of data. Usually used only by a scroll pane.5991* @see #SCROLL_PANE5992*/5993AccessibleRole.SCROLL_BAR,59945995/**5996* An object usually used in a scroll pane. It represents the portion5997* of the entire data that the user can see. As the user manipulates5998* the scroll bars, the contents of the viewport can change.5999* @see #SCROLL_PANE6000*/6001AccessibleRole.VIEWPORT,60026003/**6004* An object that allows the user to select from a bounded range. For6005* example, a slider might be used to select a number between 0 and 100.6006*/6007AccessibleRole.SLIDER,60086009/**6010* A specialized panel that presents two other panels at the same time.6011* Between the two panels is a divider the user can manipulate to make6012* one panel larger and the other panel smaller.6013*/6014AccessibleRole.SPLIT_PANE,60156016/**6017* An object used to present information in terms of rows and columns.6018* An example might include a spreadsheet application.6019*/6020AccessibleRole.TABLE,60216022/**6023* An object that presents text to the user. The text is usually6024* editable by the user as opposed to a label.6025* @see #LABEL6026*/6027AccessibleRole.TEXT,60286029/**6030* An object used to present hierarchical information to the user.6031* The individual nodes in the tree can be collapsed and expanded6032* to provide selective disclosure of the tree's contents.6033*/6034AccessibleRole.TREE,60356036/**6037* A bar or palette usually composed of push buttons or toggle buttons.6038* It is often used to provide the most frequently used functions for an6039* application.6040*/6041AccessibleRole.TOOL_BAR,60426043/**6044* An object that provides information about another object. The6045* accessibleDescription property of the tool tip is often displayed6046* to the user in a small "help bubble" when the user causes the6047* mouse to hover over the object associated with the tool tip.6048*/6049AccessibleRole.TOOL_TIP,60506051/**6052* An AWT component, but nothing else is known about it.6053* @see #SWING_COMPONENT6054* @see #UNKNOWN6055*/6056AccessibleRole.AWT_COMPONENT,60576058/**6059* A Swing component, but nothing else is known about it.6060* @see #AWT_COMPONENT6061* @see #UNKNOWN6062*/6063AccessibleRole.SWING_COMPONENT,60646065/**6066* The object contains some Accessible information, but its role is6067* not known.6068* @see #AWT_COMPONENT6069* @see #SWING_COMPONENT6070*/6071AccessibleRole.UNKNOWN,60726073// These roles are available since JDK 1.460746075/**6076* A STATUS_BAR is an simple component that can contain6077* multiple labels of status information to the user.6078AccessibleRole.STATUS_BAR,60796080/**6081* A DATE_EDITOR is a component that allows users to edit6082* java.util.Date and java.util.Time objects6083AccessibleRole.DATE_EDITOR,60846085/**6086* A SPIN_BOX is a simple spinner component and its main use6087* is for simple numbers.6088AccessibleRole.SPIN_BOX,60896090/**6091* A FONT_CHOOSER is a component that lets the user pick various6092* attributes for fonts.6093AccessibleRole.FONT_CHOOSER,60946095/**6096* A GROUP_BOX is a simple container that contains a border6097* around it and contains components inside it.6098AccessibleRole.GROUP_BOX60996100/**6101* Since JDK 1.56102*6103* A text header61046105AccessibleRole.HEADER,61066107/**6108* A text footer61096110AccessibleRole.FOOTER,61116112/**6113* A text paragraph61146115AccessibleRole.PARAGRAPH,61166117/**6118* A ruler is an object used to measure distance61196120AccessibleRole.RULER,61216122/**6123* A role indicating the object acts as a formula for6124* calculating a value. An example is a formula in6125* a spreadsheet cell.6126AccessibleRole.EDITBAR6127*/6128};61296130/**6131* This class implements accessibility support for the6132* <code>JTree</code> child. It provides an implementation of the6133* Java Accessibility API appropriate to tree nodes.6134*6135* Copied from JTree.java to work around a JTree bug where6136* ActiveDescendent PropertyChangeEvents contain the wrong6137* parent.6138*/6139/**6140* This class in invoked on the EDT as its part of ActiveDescendant,6141* hence the calls do not need to be specifically made on the EDT6142*/6143private class AccessibleJTreeNode extends AccessibleContext6144implements Accessible, AccessibleComponent, AccessibleSelection,6145AccessibleAction {61466147private JTree tree = null;6148private TreeModel treeModel = null;6149private Object obj = null;6150private TreePath path = null;6151private Accessible accessibleParent = null;6152private int index = 0;6153private boolean isLeaf = false;61546155/**6156* Constructs an AccessibleJTreeNode6157*/6158AccessibleJTreeNode(JTree t, TreePath p, Accessible ap) {6159tree = t;6160path = p;6161accessibleParent = ap;6162if (t != null)6163treeModel = t.getModel();6164if (p != null) {6165obj = p.getLastPathComponent();6166if (treeModel != null && obj != null) {6167isLeaf = treeModel.isLeaf(obj);6168}6169}6170debugString("[INFO]: AccessibleJTreeNode: name = "+getAccessibleName()+"; TreePath = "+p+"; parent = "+ap);6171}61726173private TreePath getChildTreePath(int i) {6174// Tree nodes can't be so complex that they have6175// two sets of children -> we're ignoring that case6176if (i < 0 || i >= getAccessibleChildrenCount() || path == null || treeModel == null) {6177return null;6178} else {6179Object childObj = treeModel.getChild(obj, i);6180Object[] objPath = path.getPath();6181Object[] objChildPath = new Object[objPath.length+1];6182java.lang.System.arraycopy(objPath, 0, objChildPath, 0, objPath.length);6183objChildPath[objChildPath.length-1] = childObj;6184return new TreePath(objChildPath);6185}6186}61876188/**6189* Get the AccessibleContext associated with this tree node.6190* In the implementation of the Java Accessibility API for6191* this class, return this object, which is its own6192* AccessibleContext.6193*6194* @return this object6195*/6196public AccessibleContext getAccessibleContext() {6197return this;6198}61996200private AccessibleContext getCurrentAccessibleContext() {6201Component c = getCurrentComponent();6202if (c instanceof Accessible) {6203return (c.getAccessibleContext());6204} else {6205return null;6206}6207}62086209private Component getCurrentComponent() {6210debugString("[INFO]: AccessibleJTreeNode: getCurrentComponent");6211// is the object visible?6212// if so, get row, selected, focus & leaf state,6213// and then get the renderer component and return it6214if (tree != null && tree.isVisible(path)) {6215TreeCellRenderer r = tree.getCellRenderer();6216if (r == null) {6217debugString("[WARN]: returning null 1");6218return null;6219}6220TreeUI ui = tree.getUI();6221if (ui != null) {6222int row = ui.getRowForPath(tree, path);6223boolean selected = tree.isPathSelected(path);6224boolean expanded = tree.isExpanded(path);6225boolean hasFocus = false; // how to tell?? -PK6226Component retval = r.getTreeCellRendererComponent(tree, obj,6227selected, expanded,6228isLeaf, row, hasFocus);6229debugString("[INFO]: returning = "+retval.getClass());6230return retval;6231}6232}6233debugString("[WARN]: returning null 2");6234return null;6235}62366237// AccessibleContext methods62386239/**6240* Get the accessible name of this object.6241*6242* @return the localized name of the object; null if this6243* object does not have a name6244*/6245public String getAccessibleName() {6246debugString("[INFO]: AccessibleJTreeNode: getAccessibleName");6247AccessibleContext ac = getCurrentAccessibleContext();6248if (ac != null) {6249String name = ac.getAccessibleName();6250if ((name != null) && (!name.isEmpty())) {6251String retval = ac.getAccessibleName();6252debugString("[INFO]: returning "+retval);6253return retval;6254} else {6255return null;6256}6257}6258if ((accessibleName != null) && (accessibleName.isEmpty())) {6259return accessibleName;6260} else {6261return null;6262}6263}62646265/**6266* Set the localized accessible name of this object.6267*6268* @param s the new localized name of the object.6269*/6270public void setAccessibleName(String s) {6271AccessibleContext ac = getCurrentAccessibleContext();6272if (ac != null) {6273ac.setAccessibleName(s);6274} else {6275super.setAccessibleName(s);6276}6277}62786279//6280// *** should check tooltip text for desc. (needs MouseEvent)6281//6282/**6283* Get the accessible description of this object.6284*6285* @return the localized description of the object; null if6286* this object does not have a description6287*/6288public String getAccessibleDescription() {6289AccessibleContext ac = getCurrentAccessibleContext();6290if (ac != null) {6291return ac.getAccessibleDescription();6292} else {6293return super.getAccessibleDescription();6294}6295}62966297/**6298* Set the accessible description of this object.6299*6300* @param s the new localized description of the object6301*/6302public void setAccessibleDescription(String s) {6303AccessibleContext ac = getCurrentAccessibleContext();6304if (ac != null) {6305ac.setAccessibleDescription(s);6306} else {6307super.setAccessibleDescription(s);6308}6309}63106311/**6312* Get the role of this object.6313*6314* @return an instance of AccessibleRole describing the role of the object6315* @see AccessibleRole6316*/6317public AccessibleRole getAccessibleRole() {6318AccessibleContext ac = getCurrentAccessibleContext();6319if (ac != null) {6320return ac.getAccessibleRole();6321} else {6322return AccessibleRole.UNKNOWN;6323}6324}63256326/**6327* Get the state set of this object.6328*6329* @return an instance of AccessibleStateSet containing the6330* current state set of the object6331* @see AccessibleState6332*/6333public AccessibleStateSet getAccessibleStateSet() {6334if (tree == null)6335return null;6336AccessibleContext ac = getCurrentAccessibleContext();6337AccessibleStateSet states;6338int row = tree.getUI().getRowForPath(tree,path);6339int lsr = tree.getLeadSelectionRow();6340if (ac != null) {6341states = ac.getAccessibleStateSet();6342} else {6343states = new AccessibleStateSet();6344}6345// need to test here, 'cause the underlying component6346// is a cellRenderer, which is never showing...6347if (isShowing()) {6348states.add(AccessibleState.SHOWING);6349} else if (states.contains(AccessibleState.SHOWING)) {6350states.remove(AccessibleState.SHOWING);6351}6352if (isVisible()) {6353states.add(AccessibleState.VISIBLE);6354} else if (states.contains(AccessibleState.VISIBLE)) {6355states.remove(AccessibleState.VISIBLE);6356}6357if (tree.isPathSelected(path)){6358states.add(AccessibleState.SELECTED);6359}6360if (lsr == row) {6361states.add(AccessibleState.ACTIVE);6362}6363if (!isLeaf) {6364states.add(AccessibleState.EXPANDABLE);6365}6366if (tree.isExpanded(path)) {6367states.add(AccessibleState.EXPANDED);6368} else {6369states.add(AccessibleState.COLLAPSED);6370}6371if (tree.isEditable()) {6372states.add(AccessibleState.EDITABLE);6373}6374return states;6375}63766377/**6378* Get the Accessible parent of this object.6379*6380* @return the Accessible parent of this object; null if this6381* object does not have an Accessible parent6382*/6383public Accessible getAccessibleParent() {6384// someone wants to know, so we need to create our parent6385// if we don't have one (hey, we're a talented kid!)6386if (accessibleParent == null && path != null) {6387Object[] objPath = path.getPath();6388if (objPath.length > 1) {6389Object objParent = objPath[objPath.length-2];6390if (treeModel != null) {6391index = treeModel.getIndexOfChild(objParent, obj);6392}6393Object[] objParentPath = new Object[objPath.length-1];6394java.lang.System.arraycopy(objPath, 0, objParentPath,63950, objPath.length-1);6396TreePath parentPath = new TreePath(objParentPath);6397accessibleParent = new AccessibleJTreeNode(tree,6398parentPath,6399null);6400this.setAccessibleParent(accessibleParent);6401} else if (treeModel != null) {6402accessibleParent = tree; // we're the top!6403index = 0; // we're an only child!6404this.setAccessibleParent(accessibleParent);6405}6406}6407return accessibleParent;6408}64096410/**6411* Get the index of this object in its accessible parent.6412*6413* @return the index of this object in its parent; -1 if this6414* object does not have an accessible parent.6415* @see #getAccessibleParent6416*/6417public int getAccessibleIndexInParent() {6418// index is invalid 'till we have an accessibleParent...6419if (accessibleParent == null) {6420getAccessibleParent();6421}6422if (path != null) {6423Object[] objPath = path.getPath();6424if (objPath.length > 1) {6425Object objParent = objPath[objPath.length-2];6426if (treeModel != null) {6427index = treeModel.getIndexOfChild(objParent, obj);6428}6429}6430}6431return index;6432}64336434/**6435* Returns the number of accessible children in the object.6436*6437* @return the number of accessible children in the object.6438*/6439public int getAccessibleChildrenCount() {6440// Tree nodes can't be so complex that they have6441// two sets of children -> we're ignoring that case6442if (obj != null && treeModel != null) {6443return treeModel.getChildCount(obj);6444}6445return 0;6446}64476448/**6449* Return the specified Accessible child of the object.6450*6451* @param i zero-based index of child6452* @return the Accessible child of the object6453*/6454public Accessible getAccessibleChild(int i) {6455// Tree nodes can't be so complex that they have6456// two sets of children -> we're ignoring that case6457if (i < 0 || i >= getAccessibleChildrenCount() || path == null || treeModel == null) {6458return null;6459} else {6460Object childObj = treeModel.getChild(obj, i);6461Object[] objPath = path.getPath();6462Object[] objChildPath = new Object[objPath.length+1];6463java.lang.System.arraycopy(objPath, 0, objChildPath, 0, objPath.length);6464objChildPath[objChildPath.length-1] = childObj;6465TreePath childPath = new TreePath(objChildPath);6466return new AccessibleJTreeNode(tree, childPath, this);6467}6468}64696470/**6471* Gets the locale of the component. If the component does not have6472* a locale, then the locale of its parent is returned.6473*6474* @return This component's locale. If this component does not have6475* a locale, the locale of its parent is returned.6476* @exception IllegalComponentStateException6477* If the Component does not have its own locale and has not yet6478* been added to a containment hierarchy such that the locale can be6479* determined from the containing parent.6480* @see #setLocale6481*/6482public Locale getLocale() {6483if (tree == null)6484return null;6485AccessibleContext ac = getCurrentAccessibleContext();6486if (ac != null) {6487return ac.getLocale();6488} else {6489return tree.getLocale();6490}6491}64926493/**6494* Add a PropertyChangeListener to the listener list.6495* The listener is registered for all properties.6496*6497* @param l The PropertyChangeListener to be added6498*/6499public void addPropertyChangeListener(PropertyChangeListener l) {6500AccessibleContext ac = getCurrentAccessibleContext();6501if (ac != null) {6502ac.addPropertyChangeListener(l);6503} else {6504super.addPropertyChangeListener(l);6505}6506}65076508/**6509* Remove a PropertyChangeListener from the listener list.6510* This removes a PropertyChangeListener that was registered6511* for all properties.6512*6513* @param l The PropertyChangeListener to be removed6514*/6515public void removePropertyChangeListener(PropertyChangeListener l) {6516AccessibleContext ac = getCurrentAccessibleContext();6517if (ac != null) {6518ac.removePropertyChangeListener(l);6519} else {6520super.removePropertyChangeListener(l);6521}6522}65236524/**6525* Get the AccessibleAction associated with this object. In the6526* implementation of the Java Accessibility API for this class,6527* return this object, which is responsible for implementing the6528* AccessibleAction interface on behalf of itself.6529*6530* @return this object6531*/6532public AccessibleAction getAccessibleAction() {6533return this;6534}65356536/**6537* Get the AccessibleComponent associated with this object. In the6538* implementation of the Java Accessibility API for this class,6539* return this object, which is responsible for implementing the6540* AccessibleComponent interface on behalf of itself.6541*6542* @return this object6543*/6544public AccessibleComponent getAccessibleComponent() {6545return this; // to override getBounds()6546}65476548/**6549* Get the AccessibleSelection associated with this object if one6550* exists. Otherwise return null.6551*6552* @return the AccessibleSelection, or null6553*/6554public AccessibleSelection getAccessibleSelection() {6555AccessibleContext ac = getCurrentAccessibleContext();6556if (ac != null && isLeaf) {6557return getCurrentAccessibleContext().getAccessibleSelection();6558} else {6559return this;6560}6561}65626563/**6564* Get the AccessibleText associated with this object if one6565* exists. Otherwise return null.6566*6567* @return the AccessibleText, or null6568*/6569public AccessibleText getAccessibleText() {6570AccessibleContext ac = getCurrentAccessibleContext();6571if (ac != null) {6572return getCurrentAccessibleContext().getAccessibleText();6573} else {6574return null;6575}6576}65776578/**6579* Get the AccessibleValue associated with this object if one6580* exists. Otherwise return null.6581*6582* @return the AccessibleValue, or null6583*/6584public AccessibleValue getAccessibleValue() {6585AccessibleContext ac = getCurrentAccessibleContext();6586if (ac != null) {6587return getCurrentAccessibleContext().getAccessibleValue();6588} else {6589return null;6590}6591}659265936594// AccessibleComponent methods65956596/**6597* Get the background color of this object.6598*6599* @return the background color, if supported, of the object;6600* otherwise, null6601*/6602public Color getBackground() {6603AccessibleContext ac = getCurrentAccessibleContext();6604if (ac instanceof AccessibleComponent) {6605return ((AccessibleComponent) ac).getBackground();6606} else {6607Component c = getCurrentComponent();6608if (c != null) {6609return c.getBackground();6610} else {6611return null;6612}6613}6614}66156616/**6617* Set the background color of this object.6618*6619* @param c the new Color for the background6620*/6621public void setBackground(Color c) {6622AccessibleContext ac = getCurrentAccessibleContext();6623if (ac instanceof AccessibleComponent) {6624((AccessibleComponent) ac).setBackground(c);6625} else {6626Component cp = getCurrentComponent();6627if ( cp != null) {6628cp.setBackground(c);6629}6630}6631}663266336634/**6635* Get the foreground color of this object.6636*6637* @return the foreground color, if supported, of the object;6638* otherwise, null6639*/6640public Color getForeground() {6641AccessibleContext ac = getCurrentAccessibleContext();6642if (ac instanceof AccessibleComponent) {6643return ((AccessibleComponent) ac).getForeground();6644} else {6645Component c = getCurrentComponent();6646if (c != null) {6647return c.getForeground();6648} else {6649return null;6650}6651}6652}66536654public void setForeground(Color c) {6655AccessibleContext ac = getCurrentAccessibleContext();6656if (ac instanceof AccessibleComponent) {6657((AccessibleComponent) ac).setForeground(c);6658} else {6659Component cp = getCurrentComponent();6660if (cp != null) {6661cp.setForeground(c);6662}6663}6664}66656666public Cursor getCursor() {6667AccessibleContext ac = getCurrentAccessibleContext();6668if (ac instanceof AccessibleComponent) {6669return ((AccessibleComponent) ac).getCursor();6670} else {6671Component c = getCurrentComponent();6672if (c != null) {6673return c.getCursor();6674} else {6675Accessible ap = getAccessibleParent();6676if (ap instanceof AccessibleComponent) {6677return ((AccessibleComponent) ap).getCursor();6678} else {6679return null;6680}6681}6682}6683}66846685public void setCursor(Cursor c) {6686AccessibleContext ac = getCurrentAccessibleContext();6687if (ac instanceof AccessibleComponent) {6688((AccessibleComponent) ac).setCursor(c);6689} else {6690Component cp = getCurrentComponent();6691if (cp != null) {6692cp.setCursor(c);6693}6694}6695}66966697public Font getFont() {6698AccessibleContext ac = getCurrentAccessibleContext();6699if (ac instanceof AccessibleComponent) {6700return ((AccessibleComponent) ac).getFont();6701} else {6702Component c = getCurrentComponent();6703if (c != null) {6704return c.getFont();6705} else {6706return null;6707}6708}6709}67106711public void setFont(Font f) {6712AccessibleContext ac = getCurrentAccessibleContext();6713if (ac instanceof AccessibleComponent) {6714((AccessibleComponent) ac).setFont(f);6715} else {6716Component c = getCurrentComponent();6717if (c != null) {6718c.setFont(f);6719}6720}6721}67226723public FontMetrics getFontMetrics(Font f) {6724AccessibleContext ac = getCurrentAccessibleContext();6725if (ac instanceof AccessibleComponent) {6726return ((AccessibleComponent) ac).getFontMetrics(f);6727} else {6728Component c = getCurrentComponent();6729if (c != null) {6730return c.getFontMetrics(f);6731} else {6732return null;6733}6734}6735}67366737public boolean isEnabled() {6738AccessibleContext ac = getCurrentAccessibleContext();6739if (ac instanceof AccessibleComponent) {6740return ((AccessibleComponent) ac).isEnabled();6741} else {6742Component c = getCurrentComponent();6743if (c != null) {6744return c.isEnabled();6745} else {6746return false;6747}6748}6749}67506751public void setEnabled(boolean b) {6752AccessibleContext ac = getCurrentAccessibleContext();6753if (ac instanceof AccessibleComponent) {6754((AccessibleComponent) ac).setEnabled(b);6755} else {6756Component c = getCurrentComponent();6757if (c != null) {6758c.setEnabled(b);6759}6760}6761}67626763public boolean isVisible() {6764if (tree == null)6765return false;6766Rectangle pathBounds = tree.getPathBounds(path);6767Rectangle parentBounds = tree.getVisibleRect();6768if ( pathBounds != null && parentBounds != null &&6769parentBounds.intersects(pathBounds) ) {6770return true;6771} else {6772return false;6773}6774}67756776public void setVisible(boolean b) {6777}67786779public boolean isShowing() {6780return (tree.isShowing() && isVisible());6781}67826783public boolean contains(Point p) {6784AccessibleContext ac = getCurrentAccessibleContext();6785if (ac instanceof AccessibleComponent) {6786Rectangle r = ((AccessibleComponent) ac).getBounds();6787return r.contains(p);6788} else {6789Component c = getCurrentComponent();6790if (c != null) {6791Rectangle r = c.getBounds();6792return r.contains(p);6793} else {6794return getBounds().contains(p);6795}6796}6797}67986799public Point getLocationOnScreen() {6800if (tree != null) {6801Point treeLocation = tree.getLocationOnScreen();6802Rectangle pathBounds = tree.getPathBounds(path);6803if (treeLocation != null && pathBounds != null) {6804Point nodeLocation = new Point(pathBounds.x,6805pathBounds.y);6806nodeLocation.translate(treeLocation.x, treeLocation.y);6807return nodeLocation;6808} else {6809return null;6810}6811} else {6812return null;6813}6814}68156816private Point getLocationInJTree() {6817Rectangle r = tree.getPathBounds(path);6818if (r != null) {6819return r.getLocation();6820} else {6821return null;6822}6823}68246825public Point getLocation() {6826Rectangle r = getBounds();6827if (r != null) {6828return r.getLocation();6829} else {6830return null;6831}6832}68336834public void setLocation(Point p) {6835}68366837public Rectangle getBounds() {6838if (tree == null)6839return null;6840Rectangle r = tree.getPathBounds(path);6841Accessible parent = getAccessibleParent();6842if (parent instanceof AccessibleJTreeNode) {6843Point parentLoc = ((AccessibleJTreeNode) parent).getLocationInJTree();6844if (parentLoc != null && r != null) {6845r.translate(-parentLoc.x, -parentLoc.y);6846} else {6847return null; // not visible!6848}6849}6850return r;6851}68526853public void setBounds(Rectangle r) {6854AccessibleContext ac = getCurrentAccessibleContext();6855if (ac instanceof AccessibleComponent) {6856((AccessibleComponent) ac).setBounds(r);6857} else {6858Component c = getCurrentComponent();6859if (c != null) {6860c.setBounds(r);6861}6862}6863}68646865public Dimension getSize() {6866return getBounds().getSize();6867}68686869public void setSize (Dimension d) {6870AccessibleContext ac = getCurrentAccessibleContext();6871if (ac instanceof AccessibleComponent) {6872((AccessibleComponent) ac).setSize(d);6873} else {6874Component c = getCurrentComponent();6875if (c != null) {6876c.setSize(d);6877}6878}6879}68806881/**6882* Returns the <code>Accessible</code> child, if one exists,6883* contained at the local coordinate <code>Point</code>.6884* Otherwise returns <code>null</code>.6885*6886* @param p point in local coordinates of this6887* <code>Accessible</code>6888* @return the <code>Accessible</code>, if it exists,6889* at the specified location; else <code>null</code>6890*/6891public Accessible getAccessibleAt(Point p) {6892AccessibleContext ac = getCurrentAccessibleContext();6893if (ac instanceof AccessibleComponent) {6894return ((AccessibleComponent) ac).getAccessibleAt(p);6895} else {6896return null;6897}6898}68996900public boolean isFocusTraversable() {6901AccessibleContext ac = getCurrentAccessibleContext();6902if (ac instanceof AccessibleComponent) {6903return ((AccessibleComponent) ac).isFocusTraversable();6904} else {6905Component c = getCurrentComponent();6906if (c != null) {6907return c.isFocusable();6908} else {6909return false;6910}6911}6912}69136914public void requestFocus() {6915AccessibleContext ac = getCurrentAccessibleContext();6916if (ac instanceof AccessibleComponent) {6917((AccessibleComponent) ac).requestFocus();6918} else {6919Component c = getCurrentComponent();6920if (c != null) {6921c.requestFocus();6922}6923}6924}69256926public void addFocusListener(FocusListener l) {6927AccessibleContext ac = getCurrentAccessibleContext();6928if (ac instanceof AccessibleComponent) {6929((AccessibleComponent) ac).addFocusListener(l);6930} else {6931Component c = getCurrentComponent();6932if (c != null) {6933c.addFocusListener(l);6934}6935}6936}69376938public void removeFocusListener(FocusListener l) {6939AccessibleContext ac = getCurrentAccessibleContext();6940if (ac instanceof AccessibleComponent) {6941((AccessibleComponent) ac).removeFocusListener(l);6942} else {6943Component c = getCurrentComponent();6944if (c != null) {6945c.removeFocusListener(l);6946}6947}6948}69496950// AccessibleSelection methods69516952/**6953* Returns the number of items currently selected.6954* If no items are selected, the return value will be 0.6955*6956* @return the number of items currently selected.6957*/6958public int getAccessibleSelectionCount() {6959int count = 0;6960int childCount = getAccessibleChildrenCount();6961for (int i = 0; i < childCount; i++) {6962TreePath childPath = getChildTreePath(i);6963if (tree.isPathSelected(childPath)) {6964count++;6965}6966}6967return count;6968}69696970/**6971* Returns an Accessible representing the specified selected item6972* in the object. If there isn't a selection, or there are6973* fewer items selected than the integer passed in, the return6974* value will be null.6975*6976* @param i the zero-based index of selected items6977* @return an Accessible containing the selected item6978*/6979public Accessible getAccessibleSelection(int i) {6980int childCount = getAccessibleChildrenCount();6981if (i < 0 || i >= childCount) {6982return null; // out of range6983}6984int count = 0;6985for (int j = 0; j < childCount && i >= count; j++) {6986TreePath childPath = getChildTreePath(j);6987if (tree.isPathSelected(childPath)) {6988if (count == i) {6989return new AccessibleJTreeNode(tree, childPath, this);6990} else {6991count++;6992}6993}6994}6995return null;6996}69976998/**6999* Returns true if the current child of this object is selected.7000*7001* @param i the zero-based index of the child in this Accessible7002* object.7003* @see AccessibleContext#getAccessibleChild7004*/7005public boolean isAccessibleChildSelected(int i) {7006int childCount = getAccessibleChildrenCount();7007if (i < 0 || i >= childCount) {7008return false; // out of range7009} else {7010TreePath childPath = getChildTreePath(i);7011return tree.isPathSelected(childPath);7012}7013}70147015/**7016* Adds the specified selected item in the object to the object's7017* selection. If the object supports multiple selections,7018* the specified item is added to any existing selection, otherwise7019* it replaces any existing selection in the object. If the7020* specified item is already selected, this method has no effect.7021*7022* @param i the zero-based index of selectable items7023*/7024public void addAccessibleSelection(int i) {7025if (tree == null)7026return;7027TreeModel model = tree.getModel();7028if (model != null) {7029if (i >= 0 && i < getAccessibleChildrenCount()) {7030TreePath path = getChildTreePath(i);7031tree.addSelectionPath(path);7032}7033}7034}70357036/**7037* Removes the specified selected item in the object from the7038* object's7039* selection. If the specified item isn't currently selected, this7040* method has no effect.7041*7042* @param i the zero-based index of selectable items7043*/7044public void removeAccessibleSelection(int i) {7045if (tree == null)7046return;7047TreeModel model = tree.getModel();7048if (model != null) {7049if (i >= 0 && i < getAccessibleChildrenCount()) {7050TreePath path = getChildTreePath(i);7051tree.removeSelectionPath(path);7052}7053}7054}70557056/**7057* Clears the selection in the object, so that nothing in the7058* object is selected.7059*/7060public void clearAccessibleSelection() {7061int childCount = getAccessibleChildrenCount();7062for (int i = 0; i < childCount; i++) {7063removeAccessibleSelection(i);7064}7065}70667067/**7068* Causes every selected item in the object to be selected7069* if the object supports multiple selections.7070*/7071public void selectAllAccessibleSelection() {7072if (tree == null)7073return;7074TreeModel model = tree.getModel();7075if (model != null) {7076int childCount = getAccessibleChildrenCount();7077TreePath path;7078for (int i = 0; i < childCount; i++) {7079path = getChildTreePath(i);7080tree.addSelectionPath(path);7081}7082}7083}70847085// AccessibleAction methods70867087/**7088* Returns the number of accessible actions available in this7089* tree node. If this node is not a leaf, there is at least7090* one action (toggle expand), in addition to any available7091* on the object behind the TreeCellRenderer.7092*7093* @return the number of Actions in this object7094*/7095public int getAccessibleActionCount() {7096AccessibleContext ac = getCurrentAccessibleContext();7097if (ac != null) {7098AccessibleAction aa = ac.getAccessibleAction();7099if (aa != null) {7100return (aa.getAccessibleActionCount() + (isLeaf ? 0 : 1));7101}7102}7103return isLeaf ? 0 : 1;7104}71057106/**7107* Return a description of the specified action of the tree node.7108* If this node is not a leaf, there is at least one action7109* description (toggle expand), in addition to any available7110* on the object behind the TreeCellRenderer.7111*7112* @param i zero-based index of the actions7113* @return a description of the action7114*/7115public String getAccessibleActionDescription(int i) {7116if (i < 0 || i >= getAccessibleActionCount()) {7117return null;7118}7119AccessibleContext ac = getCurrentAccessibleContext();7120if (i == 0) {7121// TIGER - 47666367122// return AccessibleAction.TOGGLE_EXPAND;7123return "toggle expand";7124} else if (ac != null) {7125AccessibleAction aa = ac.getAccessibleAction();7126if (aa != null) {7127return aa.getAccessibleActionDescription(i - 1);7128}7129}7130return null;7131}71327133/**7134* Perform the specified Action on the tree node. If this node7135* is not a leaf, there is at least one action which can be7136* done (toggle expand), in addition to any available on the7137* object behind the TreeCellRenderer.7138*7139* @param i zero-based index of actions7140* @return true if the the action was performed; else false.7141*/7142public boolean doAccessibleAction(int i) {7143if (i < 0 || i >= getAccessibleActionCount()) {7144return false;7145}7146AccessibleContext ac = getCurrentAccessibleContext();7147if (i == 0) {7148if (tree.isExpanded(path)) {7149tree.collapsePath(path);7150} else {7151tree.expandPath(path);7152}7153return true;7154} else if (ac != null) {7155AccessibleAction aa = ac.getAccessibleAction();7156if (aa != null) {7157return aa.doAccessibleAction(i - 1);7158}7159}7160return false;7161}71627163} // inner class AccessibleJTreeNode71647165/**7166* A helper class to perform {@code Callable} objects on the event dispatch thread appropriate7167* for the provided {@code AccessibleContext}.7168*/7169private static class InvocationUtils {71707171/**7172* Invokes a {@code Callable} in the {@code AppContext} of the given {@code Accessible}7173* and waits for it to finish blocking the caller thread.7174*7175* @param callable the {@code Callable} to invoke7176* @param accessibleTable the {@code AccessibleExtendedTable} which would be used to find the right context7177* for the task execution7178* @param <T> type parameter for the result value7179*7180* @return the result of the {@code Callable} execution7181*/7182public static <T> T invokeAndWait(final Callable<T> callable,7183final AccessibleExtendedTable accessibleTable) {7184if (accessibleTable instanceof AccessibleContext) {7185return invokeAndWait(callable, (AccessibleContext)accessibleTable);7186}7187throw new RuntimeException("Unmapped AccessibleContext used to dispatch event: " + accessibleTable);7188}71897190/**7191* Invokes a {@code Callable} in the {@code AppContext} of the given {@code Accessible}7192* and waits for it to finish blocking the caller thread.7193*7194* @param callable the {@code Callable} to invoke7195* @param accessible the {@code Accessible} which would be used to find the right context7196* for the task execution7197* @param <T> type parameter for the result value7198*7199* @return the result of the {@code Callable} execution7200*/7201public static <T> T invokeAndWait(final Callable<T> callable,7202final Accessible accessible) {7203if (accessible instanceof Component) {7204return invokeAndWait(callable, (Component)accessible);7205}7206if (accessible instanceof AccessibleContext) {7207// This case also covers the Translator7208return invokeAndWait(callable, (AccessibleContext)accessible);7209}7210throw new RuntimeException("Unmapped Accessible used to dispatch event: " + accessible);7211}72127213/**7214* Invokes a {@code Callable} in the {@code AppContext} of the given {@code Component}7215* and waits for it to finish blocking the caller thread.7216*7217* @param callable the {@code Callable} to invoke7218* @param component the {@code Component} which would be used to find the right context7219* for the task execution7220* @param <T> type parameter for the result value7221*7222* @return the result of the {@code Callable} execution7223*/7224public static <T> T invokeAndWait(final Callable<T> callable,7225final Component component) {7226return invokeAndWait(callable, SunToolkit.targetToAppContext(component));7227}72287229/**7230* Invokes a {@code Callable} in the {@code AppContext} mapped to the given {@code AccessibleContext}7231* and waits for it to finish blocking the caller thread.7232*7233* @param callable the {@code Callable} to invoke7234* @param accessibleContext the {@code AccessibleContext} which would be used to determine the right7235* context for the task execution.7236* @param <T> type parameter for the result value7237*7238* @return the result of the {@code Callable} execution7239*/7240public static <T> T invokeAndWait(final Callable<T> callable,7241final AccessibleContext accessibleContext) {7242AppContext targetContext = AWTAccessor.getAccessibleContextAccessor()7243.getAppContext(accessibleContext);7244if (targetContext != null) {7245return invokeAndWait(callable, targetContext);7246} else {7247// Normally this should not happen, unmapped context provided and7248// the target AppContext is unknown.72497250// Try to recover in case the context is a translator.7251if (accessibleContext instanceof Translator) {7252Object source = ((Translator)accessibleContext).getSource();7253if (source instanceof Component) {7254return invokeAndWait(callable, (Component)source);7255}7256}7257}7258throw new RuntimeException("Unmapped AccessibleContext used to dispatch event: " + accessibleContext);7259}72607261private static <T> T invokeAndWait(final Callable<T> callable,7262final AppContext targetAppContext) {7263final CallableWrapper<T> wrapper = new CallableWrapper<T>(callable);7264try {7265invokeAndWait(wrapper, targetAppContext);7266T result = wrapper.getResult();7267updateAppContextMap(result, targetAppContext);7268return result;7269} catch (final Exception e) {7270throw new RuntimeException(e);7271}7272}72737274private static void invokeAndWait(final Runnable runnable,7275final AppContext appContext)7276throws InterruptedException, InvocationTargetException {72777278EventQueue eq = SunToolkit.getSystemEventQueueImplPP(appContext);7279Object lock = new Object();7280Toolkit source = Toolkit.getDefaultToolkit();7281InvocationEvent event =7282new InvocationEvent(source, runnable, lock, true);7283synchronized (lock) {7284eq.postEvent(event);7285lock.wait();7286}72877288Throwable eventThrowable = event.getThrowable();7289if (eventThrowable != null) {7290throw new InvocationTargetException(eventThrowable);7291}7292}72937294/**7295* Maps the {@code AccessibleContext} to the {@code AppContext} which should be used7296* to dispatch events related to the {@code AccessibleContext}7297* @param accessibleContext the {@code AccessibleContext} for the mapping7298* @param targetContext the {@code AppContext} for the mapping7299*/7300public static void registerAccessibleContext(final AccessibleContext accessibleContext,7301final AppContext targetContext) {7302if (accessibleContext != null) {7303AWTAccessor.getAccessibleContextAccessor().setAppContext(accessibleContext, targetContext);7304}7305}73067307private static <T> void updateAppContextMap(final T accessibleContext,7308final AppContext targetContext) {7309if (accessibleContext instanceof AccessibleContext) {7310registerAccessibleContext((AccessibleContext)accessibleContext, targetContext);7311}7312}73137314private static class CallableWrapper<T> implements Runnable {7315private final Callable<T> callable;7316private volatile T object;7317private Exception e;73187319CallableWrapper(final Callable<T> callable) {7320this.callable = callable;7321}73227323public void run() {7324try {7325if (callable != null) {7326object = callable.call();7327}7328} catch (final Exception e) {7329this.e = e;7330}7331}73327333T getResult() throws Exception {7334if (e != null)7335throw e;7336return object;7337}7338}7339}7340}734173427343