< prev index next >

src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java

Print this page




 143         // windows
 144         initHWNDcalls();
 145 
 146         // is this a JVM we can use?
 147         // install JDK 1.2 and later Swing ToolKit listener
 148         EventQueueMonitor.isGUIInitialized();
 149 
 150         // start the Java event handler
 151         eventHandler = new EventHandler(this);
 152 
 153         // register for menu selection events
 154         MenuSelectionManager.defaultManager().addChangeListener(eventHandler);
 155 
 156         // register as a NativeWindowHandler
 157         addNativeWindowHandler(new DefaultNativeWindowHandler());
 158 
 159         // start in a new thread
 160         Thread abthread = new Thread(new dllRunner());
 161         abthread.setDaemon(true);
 162         abthread.start();
 163         debugString("AccessBridge started");
 164     }
 165 
 166     /*
 167      * adaptor to run the AccessBridge DLL
 168      */
 169     private class dllRunner implements Runnable {
 170         public void run() {
 171             runDLL();
 172         }
 173     }
 174 
 175     /*
 176      * shutdown hook
 177      */
 178     private class shutdownHook implements Runnable {
 179 
 180         public void run() {
 181             debugString("***** shutdownHook: shutting down...");
 182             javaShutdown();
 183         }
 184     }
 185 
 186 
 187     /*
 188      * Initialize the hashtable that maps Strings to AccessibleRoles.
 189      */
 190     private void initAccessibleRoleMap() {
 191         /*
 192          * Initialize the AccessibleRoles map. This code uses methods in
 193          * java.lang.reflect.* to build the map.
 194          */
 195         try {
 196             Class<?> clAccessibleRole = Class.forName ("javax.accessibility.AccessibleRole");
 197             if (null != clAccessibleRole) {
 198                 AccessibleRole roleUnknown = AccessibleRole.UNKNOWN;
 199                 Field [] fields = clAccessibleRole.getFields ();
 200                 int i = 0;
 201                 for (i = 0; i < fields.length; i ++) {


 280     private Method javaGetComponentFromNativeWindowHandleMethod;
 281     private Method javaGetNativeWindowHandleFromComponentMethod;
 282 
 283     // native jawt methods for mapping HWNDs to Java components
 284     private native int jawtGetNativeWindowHandleFromComponent(Component comp);
 285 
 286     private native Component jawtGetComponentFromNativeWindowHandle(int handle);
 287 
 288     Toolkit toolkit;
 289 
 290     /**
 291      * map an HWND to an AWT Component
 292      */
 293     private void initHWNDcalls() {
 294         Class<?>[] integerParemter = new Class<?>[1];
 295         integerParemter[0] = Integer.TYPE;
 296         Class<?>[] componentParemter = new Class<?>[1];
 297         try {
 298             componentParemter[0] = Class.forName("java.awt.Component");
 299         } catch (ClassNotFoundException e) {
 300             debugString("Exception: " + e.toString());
 301         }
 302         toolkit = Toolkit.getDefaultToolkit();
 303         return;
 304     }
 305 
 306     // native window handler interface
 307     private interface NativeWindowHandler {
 308         public Accessible getAccessibleFromNativeWindowHandle(int nativeHandle);
 309     }
 310 
 311     // hash table of native window handle to AccessibleContext mappings
 312     static private ConcurrentHashMap<Integer,AccessibleContext> windowHandleToContextMap = new ConcurrentHashMap<>();
 313 
 314     // hash table of AccessibleContext to native window handle mappings
 315     static private ConcurrentHashMap<AccessibleContext,Integer> contextToWindowHandleMap = new ConcurrentHashMap<>();
 316 
 317     /*
 318      * adds a virtual window handler to our hash tables
 319      */
 320     static private void registerVirtualFrame(final Accessible a,


 369         return nativeWindowHandlers.removeElement(handler);
 370     }
 371 
 372     /**
 373      * verifies that a native window handle is a Java window
 374      */
 375     private boolean isJavaWindow(int nativeHandle) {
 376         AccessibleContext ac = getContextFromNativeWindowHandle(nativeHandle);
 377         if (ac != null) {
 378             saveContextToWindowHandleMapping(ac, nativeHandle);
 379             return true;
 380         }
 381         return false;
 382     }
 383 
 384     /*
 385      * saves the mapping between an AccessibleContext and a window handle
 386      */
 387     private void saveContextToWindowHandleMapping(AccessibleContext ac,
 388                                                   int nativeHandle) {
 389         debugString("saveContextToWindowHandleMapping...");
 390         if (ac == null) {
 391             return;
 392         }
 393         if (! contextToWindowHandleMap.containsKey(ac)) {
 394             debugString("saveContextToWindowHandleMapping: ac = "+ac+"; handle = "+nativeHandle);
 395             contextToWindowHandleMap.put(ac, nativeHandle);
 396         }
 397     }
 398 
 399     /**
 400      * maps a native window handle to an Accessible Context
 401      */
 402     private AccessibleContext getContextFromNativeWindowHandle(int nativeHandle) {
 403         // First, look for the Accessible in our hash table of
 404         // virtual window handles.
 405         AccessibleContext ac = windowHandleToContextMap.get(nativeHandle);
 406         if(ac!=null) {
 407             saveContextToWindowHandleMapping(ac, nativeHandle);
 408             return ac;
 409         }
 410 
 411         // Next, look for the native window handle in our vector
 412         // of native window handles.
 413         int numHandlers = nativeWindowHandlers.size();
 414         for (int i = 0; i < numHandlers; i++) {


 417             if (a != null) {
 418                 ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
 419                     @Override
 420                     public AccessibleContext call() throws Exception {
 421                         return a.getAccessibleContext();
 422                     }
 423                 }, a);
 424                 saveContextToWindowHandleMapping(ac, nativeHandle);
 425                 return ac;
 426             }
 427         }
 428         // Not found.
 429         return null;
 430     }
 431 
 432     /**
 433      * maps an AccessibleContext to a native window handle
 434      *     returns 0 on error
 435      */
 436     private int getNativeWindowHandleFromContext(AccessibleContext ac) {
 437     debugString("getNativeWindowHandleFromContext: ac = "+ac);
 438         try {
 439             return contextToWindowHandleMap.get(ac);
 440         } catch (Exception ex) {
 441             return 0;
 442         }
 443     }
 444 
 445     private class DefaultNativeWindowHandler implements NativeWindowHandler {
 446         /*
 447         * returns the Accessible associated with a native window
 448         */
 449         public Accessible getAccessibleFromNativeWindowHandle(int nativeHandle) {
 450             final Component c = jawtGetComponentFromNativeWindowHandle(nativeHandle);
 451             if (c instanceof Accessible) {
 452                 AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
 453                     @Override
 454                     public AccessibleContext call() throws Exception {
 455                         return c.getAccessibleContext();
 456                     }
 457                 }, c);


 498             public AccessibleContext call() throws Exception {
 499                 Accessible parent = ac.getAccessibleParent();
 500                 if (parent == null) {
 501                     return ac;
 502                 }
 503                 Accessible tmp = parent.getAccessibleContext().getAccessibleParent();
 504                 while (tmp != null) {
 505                     parent = tmp;
 506                     tmp = parent.getAccessibleContext().getAccessibleParent();
 507                 }
 508                 return parent.getAccessibleContext();
 509             }
 510         }, ac);
 511     }
 512 
 513     /*
 514      * StarOffice version that does not use the EventQueueMonitor
 515      */
 516     private AccessibleContext getAccessibleContextAt_1(final int x, final int y,
 517                                                       final AccessibleContext parent) {
 518         debugString(" : getAccessibleContextAt_1 called");
 519         debugString("   -> x = " + x + " y = " + y + " parent = " + parent);
 520 
 521         if (parent == null) return null;
 522             final AccessibleComponent acmp = InvocationUtils.invokeAndWait(new Callable<AccessibleComponent>() {
 523                 @Override
 524                 public AccessibleComponent call() throws Exception {
 525                     return parent.getAccessibleComponent();
 526                 }
 527             }, parent);
 528         if (acmp!=null) {
 529             final Point loc = InvocationUtils.invokeAndWait(new Callable<Point>() {
 530                 @Override
 531                 public Point call() throws Exception {
 532                     return acmp.getLocation();
 533                 }
 534             }, parent);
 535             final Accessible a = InvocationUtils.invokeAndWait(new Callable<Accessible>() {
 536                 @Override
 537                 public Accessible call() throws Exception {
 538                     return acmp.getAccessibleAt(new Point(x - loc.x, y - loc.y));


 546                     }
 547                 }, parent);
 548                 if (foundAC != null) {
 549                     if (foundAC != parent) {
 550                         // recurse down into the child
 551                         return getAccessibleContextAt_1(x - loc.x, y - loc.y,
 552                                                         foundAC);
 553                     } else
 554                         return foundAC;
 555                 }
 556             }
 557         }
 558         return parent;
 559     }
 560 
 561     /*
 562      * AWT/Swing version
 563      */
 564     private AccessibleContext getAccessibleContextAt_2(final int x, final int y,
 565                                                       AccessibleContext parent) {
 566         debugString("getAccessibleContextAt_2 called");
 567         debugString("   -> x = " + x + " y = " + y + " parent = " + parent);
 568 
 569         return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
 570             @Override
 571             public AccessibleContext call() throws Exception {
 572                 Accessible a = EventQueueMonitor.getAccessibleAt(new Point(x, y));
 573                 if (a != null) {
 574                     AccessibleContext childAC = a.getAccessibleContext();
 575                     if (childAC != null) {
 576                         debugString("   returning childAC = " + childAC);
 577                         return childAC;
 578                     }
 579                 }
 580                 return null;
 581             }
 582         }, parent);
 583     }
 584 
 585     /**
 586      * returns the Accessible that has focus
 587      */
 588     private AccessibleContext getAccessibleContextWithFocus() {
 589         Component c = AWTEventMonitor.getComponentWithFocus();
 590         if (c != null) {
 591             final Accessible a = Translator.getAccessible(c);
 592             if (a != null) {
 593                 AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
 594                     @Override
 595                     public AccessibleContext call() throws Exception {
 596                         return a.getAccessibleContext();
 597                     }
 598                 }, c);
 599                 if (ac != null) {
 600                     return ac;
 601                 }
 602             }
 603         }
 604         return null;
 605     }
 606 
 607     /**
 608      * returns the AccessibleName from an AccessibleContext
 609      */
 610     private String getAccessibleNameFromContext(final AccessibleContext ac) {
 611         debugString("***** ac = "+ac.getClass());
 612         if (ac != null) {
 613             String s = InvocationUtils.invokeAndWait(new Callable<String>() {
 614                 @Override
 615                 public String call() throws Exception {
 616                     return ac.getAccessibleName();
 617                 }
 618             }, ac);
 619             if (s != null) {
 620                 references.increment(s);
 621                 debugString("Returning AccessibleName from Context: " + s);
 622                 return s;
 623             } else {
 624                 return null;
 625             }
 626         } else {
 627             debugString("getAccessibleNameFromContext; ac = null!");
 628             return null;
 629         }
 630     }
 631 
 632     /**
 633      * Returns an AccessibleName for a component using an algorithm optimized
 634      * for the JAWS screen reader.  This method is only intended for JAWS. All
 635      * other uses are entirely optional.
 636      */
 637     private String getVirtualAccessibleNameFromContext(final AccessibleContext ac) {
 638         if (null != ac) {
 639             /*
 640             Step 1:
 641             =======
 642             Determine if we can obtain the Virtual Accessible Name from the
 643             Accessible Name or Accessible Description of the object.
 644             */
 645             String nameString = InvocationUtils.invokeAndWait(new Callable<String>() {
 646                 @Override
 647                 public String call() throws Exception {
 648                     return ac.getAccessibleName();
 649                 }
 650             }, ac);
 651             if ( ( null != nameString ) && ( 0 != nameString.length () ) ) {
 652                 debugString ("bk -- The Virtual Accessible Name was obtained from AccessibleContext::getAccessibleName.");
 653                 references.increment (nameString);
 654                 return nameString;
 655             }
 656             String descriptionString = InvocationUtils.invokeAndWait(new Callable<String>() {
 657                 @Override
 658                 public String call() throws Exception {
 659                     return ac.getAccessibleDescription();
 660                 }
 661             }, ac);
 662             if ( ( null != descriptionString ) && ( 0 != descriptionString.length () ) ) {
 663                 debugString ("bk -- The Virtual Accessible Name was obtained from AccessibleContext::getAccessibleDescription.");
 664                 references.increment (descriptionString);
 665                 return descriptionString;
 666             }
 667 
 668             debugString ("The Virtual Accessible Name was not found using AccessibleContext::getAccessibleDescription. or getAccessibleName");
 669             /*
 670             Step 2:
 671             =======
 672             Decide whether the extended name search algorithm should be
 673             used for this object.
 674             */
 675             boolean bExtendedSearch = false;
 676             AccessibleRole role = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {
 677                 @Override
 678                 public AccessibleRole call() throws Exception {
 679                     return ac.getAccessibleRole();
 680                 }
 681             }, ac);
 682             AccessibleContext parentContext = null;
 683             AccessibleRole parentRole = AccessibleRole.UNKNOWN;
 684 
 685             if ( extendedVirtualNameSearchRoles.contains (role) ) {
 686                 parentContext = getAccessibleParentFromContext (ac);
 687                 if ( null != parentContext ) {
 688                     final AccessibleContext parentContextInnerTemp = parentContext;
 689                     parentRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {
 690                         @Override
 691                         public AccessibleRole call() throws Exception {
 692                             return parentContextInnerTemp.getAccessibleRole();
 693                         }
 694                     }, ac);
 695                     if ( AccessibleRole.UNKNOWN != parentRole ) {
 696                         bExtendedSearch = true;
 697                         if ( noExtendedVirtualNameSearchParentRoles.contains (parentRole) ) {
 698                             bExtendedSearch = false;
 699                         }
 700                     }
 701                 }
 702             }
 703 
 704             if (false == bExtendedSearch) {
 705                 debugString ("bk -- getVirtualAccessibleNameFromContext will not use the extended name search algorithm.  role = " + ( role != null ? role.toDisplayString(Locale.US) : "null") );
 706                 /*
 707                 Step 3:
 708                 =======
 709                 We have determined that we should not use the extended name
 710                 search algorithm for this object (we must obtain the name of
 711                 the object from the object itself and not from neighboring
 712                 objects).  However the object name cannot be obtained from
 713                 the Accessible Name or Accessible Description of the object.
 714 
 715                 Handle several special cases here that might yield a value for
 716                 the Virtual Accessible Name.  Return null if the object does
 717                 not match the criteria for any of these special cases.
 718                 */
 719                 if (AccessibleRole.LABEL == role) {
 720                     /*
 721                     Does the label support the Accessible Text Interface?
 722                     */
 723                     final AccessibleText at = InvocationUtils.invokeAndWait(new Callable<AccessibleText>() {
 724                         @Override
 725                         public AccessibleText call() throws Exception {
 726                             return ac.getAccessibleText();
 727                         }
 728                     }, ac);
 729                     if (null != at) {
 730                         int charCount = InvocationUtils.invokeAndWait(new Callable<Integer>() {
 731                             @Override
 732                             public Integer call() throws Exception {
 733                                 return at.getCharCount();
 734                             }
 735                         }, ac);
 736                         String text = getAccessibleTextRangeFromContext (ac, 0, charCount);
 737                         if (null != text) {
 738                             debugString ("bk -- The Virtual Accessible Name was obtained from the Accessible Text of the LABEL object.");
 739                             references.increment (text);
 740                             return text;
 741                         }
 742                     }
 743                     /*
 744                     Does the label support the Accessible Icon Interface?
 745                     */
 746                     debugString ("bk -- Attempting to obtain the Virtual Accessible Name from the Accessible Icon information.");
 747                     final AccessibleIcon [] ai = InvocationUtils.invokeAndWait(new Callable<AccessibleIcon[]>() {
 748                         @Override
 749                         public AccessibleIcon[] call() throws Exception {
 750                             return ac.getAccessibleIcon();
 751                         }
 752                     }, ac);
 753                     if ( (null != ai) && (ai.length > 0) ) {
 754                         String iconDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
 755                             @Override
 756                             public String call() throws Exception {
 757                                 return ai[0].getAccessibleIconDescription();
 758                             }
 759                         }, ac);
 760                         if (iconDescription != null){
 761                             debugString ("bk -- The Virtual Accessible Name was obtained from the description of the first Accessible Icon found in the LABEL object.");
 762                             references.increment (iconDescription);
 763                             return iconDescription;
 764                         }
 765                     } else {
 766                         parentContext = getAccessibleParentFromContext (ac);
 767                         if ( null != parentContext ) {
 768                             final AccessibleContext parentContextInnerTemp = parentContext;
 769                             parentRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {
 770                                 @Override
 771                                 public AccessibleRole call() throws Exception {
 772                                     return parentContextInnerTemp.getAccessibleRole();
 773                                 }
 774                             }, ac);
 775                             if ( AccessibleRole.TABLE == parentRole ) {
 776                                 int indexInParent = InvocationUtils.invokeAndWait(new Callable<Integer>() {
 777                                     @Override
 778                                     public Integer call() throws Exception {
 779                                         return ac.getAccessibleIndexInParent();
 780                                     }
 781                                 }, ac);
 782                                 final AccessibleContext acTableCell = getAccessibleChildFromContext (parentContext, indexInParent);
 783                                 debugString ("bk -- Making a second attempt to obtain the Virtual Accessible Name from the Accessible Icon information for the Table Cell.");
 784                                 if (acTableCell != null) {
 785                                     final AccessibleIcon [] aiRet =InvocationUtils.invokeAndWait(new Callable<AccessibleIcon[]>() {
 786                                         @Override
 787                                         public AccessibleIcon[] call() throws Exception {
 788                                             return acTableCell.getAccessibleIcon();
 789                                         }
 790                                     }, ac);
 791                                     if ( (null != aiRet) && (aiRet.length > 0) ) {
 792                                         String iconDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
 793                                             @Override
 794                                             public String call() throws Exception {
 795                                                 return aiRet[0].getAccessibleIconDescription();
 796                                             }
 797                                         }, ac);
 798                                         if (iconDescription != null){
 799                                             debugString ("bk -- The Virtual Accessible Name was obtained from the description of the first Accessible Icon found in the Table Cell object.");
 800                                             references.increment (iconDescription);
 801                                             return iconDescription;
 802                                         }
 803                                     }
 804                                 }
 805                             }
 806                         }
 807                     }
 808                 } else if ( (AccessibleRole.TOGGLE_BUTTON == role) ||
 809                             (AccessibleRole.PUSH_BUTTON == role) ) {
 810                     /*
 811                     Does the button support the Accessible Icon Interface?
 812                     */
 813                     debugString ("bk -- Attempting to obtain the Virtual Accessible Name from the Accessible Icon information.");
 814                     final AccessibleIcon [] ai = InvocationUtils.invokeAndWait(new Callable<AccessibleIcon[]>() {
 815                         @Override
 816                         public AccessibleIcon[] call() throws Exception {
 817                             return ac.getAccessibleIcon();
 818                         }
 819                     }, ac);
 820                     if ( (null != ai) && (ai.length > 0) ) {
 821                         String iconDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
 822                             @Override
 823                             public String call() throws Exception {
 824                                 return ai[0].getAccessibleIconDescription();
 825                             }
 826                         }, ac);
 827                         if (iconDescription != null){
 828                             debugString ("bk -- The Virtual Accessible Name was obtained from the description of the first Accessible Icon found in the TOGGLE_BUTTON or PUSH_BUTTON object.");
 829                             references.increment (iconDescription);
 830                             return iconDescription;
 831                         }
 832                     }
 833                 } else if ( AccessibleRole.CHECK_BOX == role ) {
 834                     /*
 835                     NOTE: The only case I know of in which a check box does not
 836                     have a name is when that check box is contained in a table.
 837 
 838                     In this case it would be appropriate to use the display string
 839                     of the check box object as the name (in US English the display
 840                     string is typically either "true" or "false").
 841 
 842                     I am using the AccessibleValue interface to obtain the display
 843                     string of the check box.  If the Accessible Value is 1, I am
 844                     returning Boolean.TRUE.toString (),  If the Accessible Value is
 845                     0, I am returning Boolean.FALSE.toString ().  If the Accessible
 846                     Value is some other number, I will return the display string of
 847                     the current numerical value of the check box.
 848                     */


 888                 @Override
 889                 public String call() throws Exception {
 890                     return parentContextOuterTemp.getAccessibleName();
 891                 }
 892             }, ac);
 893             String parentDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
 894                 @Override
 895                 public String call() throws Exception {
 896                     return parentContextOuterTemp.getAccessibleDescription();
 897                 }
 898             }, ac);
 899 
 900             /*
 901             Step 4:
 902             =======
 903             Special case for Slider Bar objects.
 904             */
 905             if ( (AccessibleRole.SLIDER == role) &&
 906                  (AccessibleRole.PANEL == parentRole) &&
 907                  (null != parentName) ) {
 908                 debugString ("bk -- The Virtual Accessible Name was obtained from the Accessible Name of the SLIDER object's parent object.");
 909                 references.increment (parentName);
 910                 return parentName;
 911             }
 912 
 913             boolean bIsEditCombo = false;
 914 
 915             AccessibleContext testContext = ac;
 916             /*
 917             Step 5:
 918             =======
 919             Special case for Edit Combo Boxes
 920             */
 921             if ( (AccessibleRole.TEXT == role) &&
 922                  (AccessibleRole.COMBO_BOX == parentRole) ) {
 923                 bIsEditCombo = true;
 924                 if (null != parentName) {
 925                     debugString ("bk -- The Virtual Accessible Name for this Edit Combo box was obtained from the Accessible Name of the object's parent object.");
 926                     references.increment (parentName);
 927                     return parentName;
 928                 } else if (null != parentDescription) {
 929                     debugString ("bk -- The Virtual Accessible Name for this Edit Combo box was obtained from the Accessible Description of the object's parent object.");
 930                     references.increment (parentDescription);
 931                     return parentDescription;
 932                 }
 933                 testContext = parentContext;
 934                 parentRole = AccessibleRole.UNKNOWN;
 935                 parentContext = getAccessibleParentFromContext (testContext);
 936                 if ( null != parentContext ) {
 937                     final AccessibleContext parentContextInnerTemp = parentContext;
 938                     parentRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {
 939                         @Override
 940                         public AccessibleRole call() throws Exception {
 941                             return parentContextInnerTemp.getAccessibleRole();
 942                         }
 943                     }, ac);
 944                 }
 945             }
 946 
 947             /*
 948             Step 6:
 949             =======


 952             */
 953             {
 954                 final AccessibleContext parentContextTempInner = parentContext;
 955                 AccessibleRelationSet ars = InvocationUtils.invokeAndWait(new Callable<AccessibleRelationSet>() {
 956                     @Override
 957                     public AccessibleRelationSet call() throws Exception {
 958                         return parentContextTempInner.getAccessibleRelationSet();
 959                     }
 960                 }, ac);
 961                 if ( ars != null && (ars.size () > 0) && (ars.contains (AccessibleRelation.LABELED_BY)) ) {
 962                     AccessibleRelation labeledByRelation = ars.get (AccessibleRelation.LABELED_BY);
 963                     if (labeledByRelation != null) {
 964                         Object [] targets = labeledByRelation.getTarget ();
 965                         Object o = targets [0];
 966                         if (o instanceof Accessible) {
 967                             AccessibleContext labelContext = ((Accessible)o).getAccessibleContext ();
 968                             if (labelContext != null) {
 969                                 String labelName = labelContext.getAccessibleName ();
 970                                 String labelDescription = labelContext.getAccessibleDescription ();
 971                                 if (null != labelName) {
 972                                     debugString ("bk -- The Virtual Accessible Name was obtained using the LABELED_BY AccessibleRelation -- Name Case.");
 973                                     references.increment (labelName);
 974                                     return labelName;
 975                                 } else if (null != labelDescription) {
 976                                     debugString ("bk -- The Virtual Accessible Name was obtained using the LABELED_BY AccessibleRelation -- Description Case.");
 977                                     references.increment (labelDescription);
 978                                     return labelDescription;
 979                                 }
 980                             }
 981                         }
 982                     }
 983                 }
 984             }
 985 
 986             //Note: add AccessibleContext to use InvocationUtils.invokeAndWait
 987             /*
 988             Step 7:
 989             =======
 990             Search for a label object that is positioned either just to the left
 991             or just above the object and get the Accessible Name of the Label
 992             object.
 993             */
 994             int testIndexMax = 0;
 995             int testX = 0;
 996             int testY = 0;


1051                         AccessibleRole childRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {
1052                             @Override
1053                             public AccessibleRole call() throws Exception {
1054                                 return childContext.getAccessibleRole();
1055                             }
1056                         }, ac);
1057                         if ( AccessibleRole.LABEL == childRole ) {
1058                             childX = getAccessibleXcoordFromContext (childContext);
1059                             childY = getAccessibleYcoordFromContext (childContext);
1060                             childWidth = getAccessibleWidthFromContext (childContext);
1061                             childHeight = getAccessibleHeightFromContext (childContext);
1062                             if ( (childX < testX) &&
1063                                  ((childY <= targetY) && (targetY <= (childY + childHeight))) ) {
1064                                 childName = InvocationUtils.invokeAndWait(new Callable<String>() {
1065                                     @Override
1066                                     public String call() throws Exception {
1067                                         return childContext.getAccessibleName();
1068                                     }
1069                                 }, ac);
1070                                 if ( null != childName ) {
1071                                     debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Name of a LABEL object positioned to the left of the object.");
1072                                     references.increment (childName);
1073                                     return childName;
1074                                 }
1075                                 childDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
1076                                     @Override
1077                                     public String call() throws Exception {
1078                                         return childContext.getAccessibleDescription();
1079                                     }
1080                                 }, ac);
1081                                 if ( null != childDescription ) {
1082                                     debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Description of a LABEL object positioned to the left of the object.");
1083                                     references.increment (childDescription);
1084                                     return childDescription;
1085                                 }
1086                             } else if ( (childY < targetY) &&
1087                                         ((childX <= targetX) && (targetX <= (childX + childWidth))) ) {
1088                                 childName = InvocationUtils.invokeAndWait(new Callable<String>() {
1089                                     @Override
1090                                     public String call() throws Exception {
1091                                         return childContext.getAccessibleName();
1092                                     }
1093                                 }, ac);
1094                                 if ( null != childName ) {
1095                                     debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Name of a LABEL object positioned above the object.");
1096                                     references.increment (childName);
1097                                     return childName;
1098                                 }
1099                                 childDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
1100                                     @Override
1101                                     public String call() throws Exception {
1102                                         return childContext.getAccessibleDescription();
1103                                     }
1104                                 }, ac);
1105                                 if ( null != childDescription ) {
1106                                     debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Description of a LABEL object positioned above the object.");
1107                                     references.increment (childDescription);
1108                                     return childDescription;
1109                                 }
1110                             }
1111                         }
1112                     }
1113                 }
1114                 childIndex --;
1115             }
1116             childIndex = testIndex + 1;
1117             while (childIndex <= testIndexMax) {
1118                 final int childIndexTemp = childIndex;
1119                 final AccessibleContext parentContextInnerTemp = parentContext;
1120                 final Accessible child  =  InvocationUtils.invokeAndWait(new Callable<Accessible>() {
1121                     @Override
1122                     public Accessible call() throws Exception {
1123                         return parentContextInnerTemp.getAccessibleChild(childIndexTemp);
1124                     }
1125                 }, ac);
1126                 if ( null != child ) {


1134                         AccessibleRole childRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {
1135                             @Override
1136                             public AccessibleRole call() throws Exception {
1137                                 return childContext.getAccessibleRole();
1138                             }
1139                         }, ac);
1140                         if ( AccessibleRole.LABEL == childRole ) {
1141                             childX = getAccessibleXcoordFromContext (childContext);
1142                             childY = getAccessibleYcoordFromContext (childContext);
1143                             childWidth = getAccessibleWidthFromContext (childContext);
1144                             childHeight = getAccessibleHeightFromContext (childContext);
1145                             if ( (childX < testX) &&
1146                                  ((childY <= targetY) && (targetY <= (childY + childHeight))) ) {
1147                                 childName = InvocationUtils.invokeAndWait(new Callable<String>() {
1148                                     @Override
1149                                     public String call() throws Exception {
1150                                         return childContext.getAccessibleName();
1151                                     }
1152                                 }, ac);
1153                                 if ( null != childName ) {
1154                                     debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Name of a LABEL object positioned to the left of the object.");
1155                                     references.increment (childName);
1156                                     return childName;
1157                                 }
1158                                 childDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
1159                                     @Override
1160                                     public String call() throws Exception {
1161                                         return childContext.getAccessibleDescription();
1162                                     }
1163                                 }, ac);
1164                                 if ( null != childDescription ) {
1165                                     debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Description of a LABEL object positioned to the left of the object.");
1166                                     references.increment (childDescription);
1167                                     return childDescription;
1168                                 }
1169                             } else if ( (childY < targetY) &&
1170                                         ((childX <= targetX) && (targetX <= (childX + childWidth))) ) {
1171                                 childName = InvocationUtils.invokeAndWait(new Callable<String>() {
1172                                     @Override
1173                                     public String call() throws Exception {
1174                                         return childContext.getAccessibleName();
1175                                     }
1176                                 }, ac);
1177                                 if ( null != childName ) {
1178                                     debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Name of a LABEL object positioned above the object.");
1179                                     references.increment (childName);
1180                                     return childName;
1181                                 }
1182                                 childDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
1183                                     @Override
1184                                     public String call() throws Exception {
1185                                         return childContext.getAccessibleDescription();
1186                                     }
1187                                 }, ac);
1188                                 if ( null != childDescription ) {
1189                                     debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Description of a LABEL object positioned above the object.");
1190                                     references.increment (childDescription);
1191                                     return childDescription;
1192                                 }
1193                             }
1194                         }
1195                     }
1196                 }
1197                 childIndex ++;
1198             }
1199             /*
1200             Step 8:
1201             =======
1202             Special case for combo boxes and text objects, based on a
1203             similar special case I found in some of our internal JAWS code.
1204 
1205             Search for a button object that is positioned either just to the left
1206             or just above the object and get the Accessible Name of the button
1207             object.
1208             */
1209             if ( (AccessibleRole.TEXT == role) ||


1231                                 @Override
1232                                 public AccessibleRole call() throws Exception {
1233                                     return childContext.getAccessibleRole();
1234                                 }
1235                             }, ac);
1236                             if ( ( AccessibleRole.PUSH_BUTTON == childRole ) ||
1237                                  ( AccessibleRole.TOGGLE_BUTTON == childRole )) {
1238                                 childX = getAccessibleXcoordFromContext (childContext);
1239                                 childY = getAccessibleYcoordFromContext (childContext);
1240                                 childWidth = getAccessibleWidthFromContext (childContext);
1241                                 childHeight = getAccessibleHeightFromContext (childContext);
1242                                 if ( (childX < testX) &&
1243                                      ((childY <= targetY) && (targetY <= (childY + childHeight))) ) {
1244                                     childName = InvocationUtils.invokeAndWait(new Callable<String>() {
1245                                         @Override
1246                                         public String call() throws Exception {
1247                                             return childContext.getAccessibleName();
1248                                         }
1249                                     }, ac);
1250                                     if ( null != childName ) {
1251                                         debugString ("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.");
1252                                         references.increment (childName);
1253                                         return childName;
1254                                     }
1255                                     childDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
1256                                         @Override
1257                                         public String call() throws Exception {
1258                                             return childContext.getAccessibleDescription();
1259                                         }
1260                                     }, ac);
1261                                     if ( null != childDescription ) {
1262                                         debugString ("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.");
1263                                         references.increment (childDescription);
1264                                         return childDescription;
1265                                     }
1266                                 }
1267                             }
1268                         }
1269                     }
1270                     childIndex --;
1271                 }
1272                 childIndex = testIndex + 1;
1273                 while (childIndex <= testIndexMax) {
1274                     final int childIndexTemp = childIndex;
1275                     final AccessibleContext parentContextInnerTemp = parentContext;
1276                     final Accessible child  =  InvocationUtils.invokeAndWait(new Callable<Accessible>() {
1277                         @Override
1278                         public Accessible call() throws Exception {
1279                             return parentContextInnerTemp.getAccessibleChild(childIndexTemp);
1280                         }
1281                     }, ac);
1282                     if ( null != child ) {


1291                                 @Override
1292                                 public AccessibleRole call() throws Exception {
1293                                     return childContext.getAccessibleRole();
1294                                 }
1295                             }, ac);
1296                             if ( ( AccessibleRole.PUSH_BUTTON == childRole ) ||
1297                                     ( AccessibleRole.TOGGLE_BUTTON == childRole ) ) {
1298                                 childX = getAccessibleXcoordFromContext (childContext);
1299                                 childY = getAccessibleYcoordFromContext (childContext);
1300                                 childWidth = getAccessibleWidthFromContext (childContext);
1301                                 childHeight = getAccessibleHeightFromContext (childContext);
1302                                 if ( (childX < testX) &&
1303                                      ((childY <= targetY) && (targetY <= (childY + childHeight))) ) {
1304                                     childName = InvocationUtils.invokeAndWait(new Callable<String>() {
1305                                         @Override
1306                                         public String call() throws Exception {
1307                                             return childContext.getAccessibleName();
1308                                         }
1309                                     }, ac);
1310                                     if ( null != childName ) {
1311                                         debugString ("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.");
1312                                         references.increment (childName);
1313                                         return childName;
1314                                     }
1315                                     childDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
1316                                         @Override
1317                                         public String call() throws Exception {
1318                                             return childContext.getAccessibleDescription();
1319                                         }
1320                                     }, ac);
1321                                     if ( null != childDescription ) {
1322                                         debugString ("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.");
1323                                         references.increment (childDescription);
1324                                         return childDescription;
1325                                     }
1326                                 }
1327                             }
1328                         }
1329                     }
1330                     childIndex ++;
1331                 }
1332             }
1333             return null;
1334         } else {
1335             debugString ("AccessBridge::getVirtualAccessibleNameFromContext error - ac == null.");
1336             return null;
1337         }
1338     }
1339 
1340     /**
1341      * returns the AccessibleDescription from an AccessibleContext
1342      */
1343     private String getAccessibleDescriptionFromContext(final AccessibleContext ac) {
1344         if (ac != null) {
1345             String s = InvocationUtils.invokeAndWait(new Callable<String>() {
1346                 @Override
1347                 public String call() throws Exception {
1348                     return ac.getAccessibleDescription();
1349                 }
1350             }, ac);
1351             if (s != null) {
1352                 references.increment(s);
1353                 debugString("Returning AccessibleDescription from Context: " + s);
1354                 return s;
1355             }
1356         } else {
1357             debugString("getAccessibleDescriptionFromContext; ac = null");
1358         }
1359         return null;
1360     }
1361 
1362     /**
1363      * returns the AccessibleRole from an AccessibleContext
1364      */
1365     private String getAccessibleRoleStringFromContext(final AccessibleContext ac) {
1366         if (ac != null) {
1367             AccessibleRole role = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {
1368                 @Override
1369                 public AccessibleRole call() throws Exception {
1370                     return ac.getAccessibleRole();
1371                 }
1372             }, ac);
1373             if (role != null) {
1374                 String s = role.toDisplayString(Locale.US);
1375                 if (s != null) {
1376                     references.increment(s);
1377                     debugString("Returning AccessibleRole from Context: " + s);
1378                     return s;
1379                 }
1380             }
1381         } else {
1382             debugString("getAccessibleRoleStringFromContext; ac = null");
1383         }
1384         return null;
1385     }
1386 
1387     /**
1388      * return the AccessibleRole from an AccessibleContext in the en_US locale
1389      */
1390     private String getAccessibleRoleStringFromContext_en_US(final AccessibleContext ac) {
1391         return getAccessibleRoleStringFromContext(ac);
1392     }
1393 
1394     /**
1395      * return the AccessibleStates from an AccessibleContext
1396      */
1397     private String getAccessibleStatesStringFromContext(final AccessibleContext ac) {
1398         if (ac != null) {
1399             AccessibleStateSet stateSet = InvocationUtils.invokeAndWait(new Callable<AccessibleStateSet>() {
1400                 @Override
1401                 public AccessibleStateSet call() throws Exception {
1402                     return ac.getAccessibleStateSet();
1403                 }
1404             }, ac);
1405             if (stateSet != null) {
1406                 String s = stateSet.toString();
1407                 if (s != null &&
1408                     s.indexOf(AccessibleState.MANAGES_DESCENDANTS.toDisplayString(Locale.US)) == -1) {
1409                     // Indicate whether this component manages its own
1410                     // children
1411                     AccessibleRole role = InvocationUtils.invokeAndWait(() -> {
1412                             return ac.getAccessibleRole();
1413                         }, ac);
1414                     if (role == AccessibleRole.LIST ||
1415                         role == AccessibleRole.TABLE ||
1416                         role == AccessibleRole.TREE) {
1417                         s += ",";
1418                         s += AccessibleState.MANAGES_DESCENDANTS.toDisplayString(Locale.US);
1419                     }
1420                     references.increment(s);
1421                     debugString("Returning AccessibleStateSet from Context: " + s);
1422                     return s;
1423                 }
1424             }
1425         } else {
1426             debugString("getAccessibleStatesStringFromContext; ac = null");
1427         }
1428         return null;
1429     }
1430 
1431     /**
1432      * returns the AccessibleStates from an AccessibleContext in the en_US locale
1433      */
1434     private String getAccessibleStatesStringFromContext_en_US(final AccessibleContext ac) {
1435         if (ac != null) {
1436             AccessibleStateSet stateSet = InvocationUtils.invokeAndWait(new Callable<AccessibleStateSet>() {
1437                 @Override
1438                 public AccessibleStateSet call() throws Exception {
1439                     return ac.getAccessibleStateSet();
1440                 }
1441             }, ac);
1442             if (stateSet != null) {
1443                 String s = "";
1444                 AccessibleState[] states = stateSet.toArray();
1445                 if (states != null && states.length > 0) {
1446                     s = states[0].toDisplayString(Locale.US);
1447                     for (int i = 1; i < states.length; i++) {
1448                         s = s + "," + states[i].toDisplayString(Locale.US);
1449                     }
1450                 }
1451                 references.increment(s);
1452                 debugString("Returning AccessibleStateSet en_US from Context: " + s);
1453                 return s;
1454             }
1455         }
1456         debugString("getAccessibleStatesStringFromContext; ac = null");
1457         return null;
1458     }
1459 
1460     /**
1461      * returns the AccessibleParent from an AccessibleContext
1462      */
1463     private AccessibleContext getAccessibleParentFromContext(final AccessibleContext ac) {
1464         if (ac==null)
1465             return null;
1466         return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
1467             @Override
1468             public AccessibleContext call() throws Exception {
1469                 Accessible a = ac.getAccessibleParent();
1470                 if (a != null) {
1471                     AccessibleContext apc = a.getAccessibleContext();
1472                     if (apc != null) {
1473                         return apc;
1474                     }
1475                 }
1476                 return null;


1590                                 r.y = p.y;
1591                                 return r;
1592                             }
1593                         } catch (Exception e) {
1594                             return null;
1595                         }
1596                     }
1597                 }
1598                 return null;
1599             }
1600         }, ac);
1601     }
1602 
1603     /**
1604      * returns the AccessibleComponent x-coord from an AccessibleContext
1605      */
1606     private int getAccessibleXcoordFromContext(AccessibleContext ac) {
1607         if (ac != null) {
1608             Rectangle r = getAccessibleBoundsOnScreenFromContext(ac);
1609             if (r != null) {
1610                 debugString(" - Returning Accessible x coord from Context: " + r.x);
1611                 return r.x;
1612             }
1613         } else {
1614             debugString("getAccessibleXcoordFromContext ac = null");
1615         }
1616         return -1;
1617     }
1618 
1619     /**
1620      * returns the AccessibleComponent y-coord from an AccessibleContext
1621      */
1622     private int getAccessibleYcoordFromContext(AccessibleContext ac) {
1623         debugString("getAccessibleYcoordFromContext() called");
1624         if (ac != null) {
1625             Rectangle r = getAccessibleBoundsOnScreenFromContext(ac);
1626             if (r != null) {
1627                 return r.y;
1628             }
1629         } else {
1630         debugString("getAccessibleYcoordFromContext; ac = null");
1631         }
1632         return -1;
1633     }
1634 
1635     /**
1636      * returns the AccessibleComponent height from an AccessibleContext
1637      */
1638     private int getAccessibleHeightFromContext(AccessibleContext ac) {
1639         if (ac != null) {
1640             Rectangle r = getAccessibleBoundsOnScreenFromContext(ac);
1641             if (r != null) {
1642                 return r.height;
1643             }
1644         } else {
1645             debugString("getAccessibleHeightFromContext; ac = null");
1646         }
1647         return -1;
1648     }
1649 
1650     /**
1651      * returns the AccessibleComponent width from an AccessibleContext
1652      */
1653     private int getAccessibleWidthFromContext(AccessibleContext ac) {
1654         if (ac != null) {
1655             Rectangle r = getAccessibleBoundsOnScreenFromContext(ac);
1656             if (r != null) {
1657                 return r.width;
1658             }
1659         } else {
1660             debugString("getAccessibleWidthFromContext; ac = null");
1661         }
1662         return -1;
1663     }
1664 
1665 
1666     /**
1667      * returns the AccessibleComponent from an AccessibleContext
1668      */
1669     private AccessibleComponent getAccessibleComponentFromContext(AccessibleContext ac) {
1670         if (ac != null) {
1671             AccessibleComponent acmp = InvocationUtils.invokeAndWait(() -> {
1672                     return ac.getAccessibleComponent();
1673                 }, ac);
1674             if (acmp != null) {
1675                 debugString("Returning AccessibleComponent Context");
1676                 return acmp;
1677             }
1678         } else {
1679             debugString("getAccessibleComponentFromContext; ac = null");
1680         }
1681         return null;
1682     }
1683 
1684     /**
1685      * returns the AccessibleAction from an AccessibleContext
1686      */
1687     private AccessibleAction getAccessibleActionFromContext(final AccessibleContext ac) {
1688         debugString("Returning AccessibleAction Context");
1689         return ac == null ? null : InvocationUtils.invokeAndWait(new Callable<AccessibleAction>() {
1690             @Override
1691             public AccessibleAction call() throws Exception {
1692                 return ac.getAccessibleAction();
1693             }
1694         }, ac);
1695     }
1696 
1697     /**
1698      * returns the AccessibleSelection from an AccessibleContext
1699      */
1700     private AccessibleSelection getAccessibleSelectionFromContext(final AccessibleContext ac) {
1701         return ac == null ? null : InvocationUtils.invokeAndWait(new Callable<AccessibleSelection>() {
1702             @Override
1703             public AccessibleSelection call() throws Exception {
1704                 return ac.getAccessibleSelection();
1705             }
1706         }, ac);
1707     }
1708 


1720 
1721     /**
1722      * return the AccessibleComponent from an AccessibleContext
1723      */
1724     private AccessibleValue getAccessibleValueFromContext(final AccessibleContext ac) {
1725         return ac == null ? null : InvocationUtils.invokeAndWait(new Callable<AccessibleValue>() {
1726             @Override
1727             public AccessibleValue call() throws Exception {
1728                 return ac.getAccessibleValue();
1729             }
1730         }, ac);
1731     }
1732 
1733     /* ===== AccessibleText methods ===== */
1734 
1735     /**
1736      * returns the bounding rectangle for the text cursor
1737      * XXX
1738      */
1739     private Rectangle getCaretLocation(final AccessibleContext ac) {
1740     debugString("getCaretLocation");
1741         if (ac==null)
1742             return null;
1743         return InvocationUtils.invokeAndWait(new Callable<Rectangle>() {
1744             @Override
1745             public Rectangle call() throws Exception {
1746                 // workaround for JAAPI not returning cursor bounding rectangle
1747                 Rectangle r = null;
1748                 Accessible parent = ac.getAccessibleParent();
1749                 if (parent instanceof Accessible) {
1750                     int indexInParent = ac.getAccessibleIndexInParent();
1751                     Accessible child =
1752                             parent.getAccessibleContext().getAccessibleChild(indexInParent);
1753 
1754                     if (child instanceof JTextComponent) {
1755                         JTextComponent text = (JTextComponent) child;
1756                         try {
1757                             r = text.modelToView2D(text.getCaretPosition()).getBounds();
1758                             if (r != null) {
1759                                 Point p = text.getLocationOnScreen();
1760                                 r.translate(p.x, p.y);


1841         if (ac==null)
1842             return -1;
1843         return InvocationUtils.invokeAndWait(new Callable<Integer>() {
1844             @Override
1845             public Integer call() throws Exception {
1846                 AccessibleText at = ac.getAccessibleText();
1847                 if (at != null) {
1848                     return at.getCaretPosition();
1849                 }
1850                 return -1;
1851             }
1852         }, ac);
1853     }
1854 
1855     /**
1856      * Return the index at a specific point from an AccessibleContext
1857      * Point(x, y) is in screen coordinates.
1858      */
1859     private int getAccessibleIndexAtPointFromContext(final AccessibleContext ac,
1860                                                     final int x, final int y) {
1861         debugString("getAccessibleIndexAtPointFromContext: x = "+x+"; y = "+y);
1862         if (ac==null)
1863             return -1;
1864         return InvocationUtils.invokeAndWait(new Callable<Integer>() {
1865             @Override
1866             public Integer call() throws Exception {
1867                 AccessibleText at = ac.getAccessibleText();
1868                 AccessibleComponent acomp = ac.getAccessibleComponent();
1869                 if (at != null && acomp != null) {
1870                     // Convert x and y from screen coordinates to
1871                     // local coordinates.
1872                     try {
1873                         Point p = acomp.getLocationOnScreen();
1874                         int x1, y1;
1875                         if (p != null) {
1876                             x1 = x - p.x;
1877                             if (x1 < 0) {
1878                                 x1 = 0;
1879                             }
1880                             y1 = y - p.y;
1881                             if (y1 < 0) {


1895     }
1896 
1897     /**
1898      * return the letter at a specific point from an AccessibleContext
1899      */
1900     private String getAccessibleLetterAtIndexFromContext(final AccessibleContext ac, final int index) {
1901         if (ac != null) {
1902             String s = InvocationUtils.invokeAndWait(new Callable<String>() {
1903                 @Override
1904                 public String call() throws Exception {
1905                     AccessibleText at = ac.getAccessibleText();
1906                     if (at == null) return null;
1907                     return at.getAtIndex(AccessibleText.CHARACTER, index);
1908                 }
1909             }, ac);
1910             if (s != null) {
1911                 references.increment(s);
1912                 return s;
1913             }
1914         } else {
1915             debugString("getAccessibleLetterAtIndexFromContext; ac = null");
1916         }
1917         return null;
1918     }
1919 
1920     /**
1921      * return the word at a specific point from an AccessibleContext
1922      */
1923     private String getAccessibleWordAtIndexFromContext(final AccessibleContext ac, final int index) {
1924         if (ac != null) {
1925             String s = InvocationUtils.invokeAndWait(new Callable<String>() {
1926                 @Override
1927                 public String call() throws Exception {
1928                     AccessibleText at = ac.getAccessibleText();
1929                     if (at == null) return null;
1930                     return at.getAtIndex(AccessibleText.WORD, index);
1931                 }
1932             }, ac);
1933             if (s != null) {
1934                 references.increment(s);
1935                 return s;
1936             }
1937         } else {
1938             debugString("getAccessibleWordAtIndexFromContext; ac = null");
1939         }
1940         return null;
1941     }
1942 
1943     /**
1944      * return the sentence at a specific point from an AccessibleContext
1945      */
1946     private String getAccessibleSentenceAtIndexFromContext(final AccessibleContext ac, final int index) {
1947         if (ac != null) {
1948             String s = InvocationUtils.invokeAndWait(new Callable<String>() {
1949                 @Override
1950                 public String call() throws Exception {
1951                     AccessibleText at = ac.getAccessibleText();
1952                     if (at == null) return null;
1953                     return at.getAtIndex(AccessibleText.SENTENCE, index);
1954                 }
1955             }, ac);
1956             if (s != null) {
1957                 references.increment(s);
1958                 return s;
1959             }
1960         } else {
1961             debugString("getAccessibleSentenceAtIndexFromContext; ac = null");
1962         }
1963         return null;
1964     }
1965 
1966     /**
1967      * return the text selection start from an AccessibleContext
1968      */
1969     private int getAccessibleTextSelectionStartFromContext(final AccessibleContext ac) {
1970         if (ac == null) return -1;
1971         return InvocationUtils.invokeAndWait(new Callable<Integer>() {
1972             @Override
1973             public Integer call() throws Exception {
1974                 AccessibleText at = ac.getAccessibleText();
1975                 if (at != null) {
1976                     return at.getSelectionStart();
1977                 }
1978                 return -1;
1979             }
1980         }, ac);
1981     }


1999     }
2000 
2001     /**
2002      * return the selected text from an AccessibleContext
2003      */
2004     private String getAccessibleTextSelectedTextFromContext(final AccessibleContext ac) {
2005         if (ac != null) {
2006             String s = InvocationUtils.invokeAndWait(new Callable<String>() {
2007                 @Override
2008                 public String call() throws Exception {
2009                     AccessibleText at = ac.getAccessibleText();
2010                     if (at == null) return null;
2011                     return at.getSelectedText();
2012                 }
2013             }, ac);
2014             if (s != null) {
2015                 references.increment(s);
2016                 return s;
2017             }
2018         } else {
2019             debugString("getAccessibleTextSelectedTextFromContext; ac = null");
2020         }
2021         return null;
2022     }
2023 
2024     /**
2025      * return the attribute string at a given index from an AccessibleContext
2026      */
2027     private String getAccessibleAttributesAtIndexFromContext(final AccessibleContext ac,
2028                                                              final int index) {
2029         if (ac == null)
2030             return null;
2031         AttributeSet as = InvocationUtils.invokeAndWait(new Callable<AttributeSet>() {
2032             @Override
2033             public AttributeSet call() throws Exception {
2034                 AccessibleText at = ac.getAccessibleText();
2035                 if (at != null) {
2036                     return at.getCharacterAttribute(index);
2037                 }
2038                 return null;
2039             }


2260             }
2261         }, ac);
2262         Rectangle acRect = getAccessibleBoundsOnScreenFromContext(ac);
2263         if (r != null && acRect != null) {
2264             r.translate(acRect.x, acRect.y);
2265             return r;
2266         }
2267         return null;
2268     }
2269 
2270     /**
2271      * return the AccessibleText character x-coord at index from an AccessibleContext
2272      */
2273     private int getAccessibleXcoordTextRectAtIndexFromContext(AccessibleContext ac, int index) {
2274         if (ac != null) {
2275             Rectangle r = getAccessibleTextRectAtIndexFromContext(ac, index);
2276             if (r != null) {
2277                 return r.x;
2278             }
2279         } else {
2280             debugString("getAccessibleXcoordTextRectAtIndexFromContext; ac = null");
2281         }
2282         return -1;
2283     }
2284 
2285     /**
2286      * return the AccessibleText character y-coord at index from an AccessibleContext
2287      */
2288     private int getAccessibleYcoordTextRectAtIndexFromContext(AccessibleContext ac, int index) {
2289         if (ac != null) {
2290             Rectangle r = getAccessibleTextRectAtIndexFromContext(ac, index);
2291             if (r != null) {
2292                 return r.y;
2293             }
2294         } else {
2295             debugString("getAccessibleYcoordTextRectAtIndexFromContext; ac = null");
2296         }
2297         return -1;
2298     }
2299 
2300     /**
2301      * return the AccessibleText character height at index from an AccessibleContext
2302      */
2303     private int getAccessibleHeightTextRectAtIndexFromContext(AccessibleContext ac, int index) {
2304         if (ac != null) {
2305             Rectangle r = getAccessibleTextRectAtIndexFromContext(ac, index);
2306             if (r != null) {
2307                 return r.height;
2308             }
2309         } else {
2310             debugString("getAccessibleHeightTextRectAtIndexFromContext; ac = null");
2311         }
2312         return -1;
2313     }
2314 
2315     /**
2316      * return the AccessibleText character width at index from an AccessibleContext
2317      */
2318     private int getAccessibleWidthTextRectAtIndexFromContext(AccessibleContext ac, int index) {
2319         if (ac != null) {
2320             Rectangle r = getAccessibleTextRectAtIndexFromContext(ac, index);
2321             if (r != null) {
2322                 return r.width;
2323             }
2324         } else {
2325             debugString("getAccessibleWidthTextRectAtIndexFromContext; ac = null");
2326         }
2327         return -1;
2328     }
2329 
2330     /* ===== AttributeSet methods for AccessibleText ===== */
2331 
2332     /**
2333      * return the bold setting from an AttributeSet
2334      */
2335     private boolean getBoldFromAttributeSet(AttributeSet as) {
2336         if (as != null) {
2337             return StyleConstants.isBold(as);
2338         } else {
2339             debugString("getBoldFromAttributeSet; as = null");
2340         }
2341         return false;
2342     }
2343 
2344     /**
2345      * return the italic setting from an AttributeSet
2346      */
2347     private boolean getItalicFromAttributeSet(AttributeSet as) {
2348         if (as != null) {
2349             return StyleConstants.isItalic(as);
2350         } else {
2351             debugString("getItalicFromAttributeSet; as = null");
2352         }
2353         return false;
2354     }
2355 
2356     /**
2357      * return the underline setting from an AttributeSet
2358      */
2359     private boolean getUnderlineFromAttributeSet(AttributeSet as) {
2360         if (as != null) {
2361             return StyleConstants.isUnderline(as);
2362         } else {
2363             debugString("getUnderlineFromAttributeSet; as = null");
2364         }
2365         return false;
2366     }
2367 
2368     /**
2369      * return the strikethrough setting from an AttributeSet
2370      */
2371     private boolean getStrikethroughFromAttributeSet(AttributeSet as) {
2372         if (as != null) {
2373             return StyleConstants.isStrikeThrough(as);
2374         } else {
2375             debugString("getStrikethroughFromAttributeSet; as = null");
2376         }
2377         return false;
2378     }
2379 
2380     /**
2381      * return the superscript setting from an AttributeSet
2382      */
2383     private boolean getSuperscriptFromAttributeSet(AttributeSet as) {
2384         if (as != null) {
2385             return StyleConstants.isSuperscript(as);
2386         } else {
2387             debugString("getSuperscriptFromAttributeSet; as = null");
2388         }
2389         return false;
2390     }
2391 
2392     /**
2393      * return the subscript setting from an AttributeSet
2394      */
2395     private boolean getSubscriptFromAttributeSet(AttributeSet as) {
2396         if (as != null) {
2397             return StyleConstants.isSubscript(as);
2398         } else {
2399             debugString("getSubscriptFromAttributeSet; as = null");
2400         }
2401         return false;
2402     }
2403 
2404     /**
2405      * return the background color from an AttributeSet
2406      */
2407     private String getBackgroundColorFromAttributeSet(AttributeSet as) {
2408         if (as != null) {
2409             String s = StyleConstants.getBackground(as).toString();
2410             if (s != null) {
2411                 references.increment(s);
2412                 return s;
2413             }
2414         } else {
2415             debugString("getBackgroundColorFromAttributeSet; as = null");
2416         }
2417         return null;
2418     }
2419 
2420     /**
2421      * return the foreground color from an AttributeSet
2422      */
2423     private String getForegroundColorFromAttributeSet(AttributeSet as) {
2424         if (as != null) {
2425             String s = StyleConstants.getForeground(as).toString();
2426             if (s != null) {
2427                 references.increment(s);
2428                 return s;
2429             }
2430         } else {
2431             debugString("getForegroundColorFromAttributeSet; as = null");
2432         }
2433         return null;
2434     }
2435 
2436     /**
2437      * return the font family from an AttributeSet
2438      */
2439     private String getFontFamilyFromAttributeSet(AttributeSet as) {
2440         if (as != null) {
2441             String s = StyleConstants.getFontFamily(as).toString();
2442             if (s != null) {
2443                 references.increment(s);
2444                 return s;
2445             }
2446         } else {
2447             debugString("getFontFamilyFromAttributeSet; as = null");
2448         }
2449         return null;
2450     }
2451 
2452     /**
2453      * return the font size from an AttributeSet
2454      */
2455     private int getFontSizeFromAttributeSet(AttributeSet as) {
2456         if (as != null) {
2457             return StyleConstants.getFontSize(as);
2458         } else {
2459             debugString("getFontSizeFromAttributeSet; as = null");
2460         }
2461         return -1;
2462     }
2463 
2464     /**
2465      * return the alignment from an AttributeSet
2466      */
2467     private int getAlignmentFromAttributeSet(AttributeSet as) {
2468         if (as != null) {
2469             return StyleConstants.getAlignment(as);
2470         } else {
2471             debugString("getAlignmentFromAttributeSet; as = null");
2472         }
2473         return -1;
2474     }
2475 
2476     /**
2477      * return the BiDi level from an AttributeSet
2478      */
2479     private int getBidiLevelFromAttributeSet(AttributeSet as) {
2480         if (as != null) {
2481             return StyleConstants.getBidiLevel(as);
2482         } else {
2483             debugString("getBidiLevelFromAttributeSet; as = null");
2484         }
2485         return -1;
2486     }
2487 
2488 
2489     /**
2490      * return the first line indent from an AttributeSet
2491      */
2492     private float getFirstLineIndentFromAttributeSet(AttributeSet as) {
2493         if (as != null) {
2494             return StyleConstants.getFirstLineIndent(as);
2495         } else {
2496             debugString("getFirstLineIndentFromAttributeSet; as = null");
2497         }
2498         return -1;
2499     }
2500 
2501     /**
2502      * return the left indent from an AttributeSet
2503      */
2504     private float getLeftIndentFromAttributeSet(AttributeSet as) {
2505         if (as != null) {
2506             return StyleConstants.getLeftIndent(as);
2507         } else {
2508             debugString("getLeftIndentFromAttributeSet; as = null");
2509         }
2510         return -1;
2511     }
2512 
2513     /**
2514      * return the right indent from an AttributeSet
2515      */
2516     private float getRightIndentFromAttributeSet(AttributeSet as) {
2517         if (as != null) {
2518             return StyleConstants.getRightIndent(as);
2519         } else {
2520             debugString("getRightIndentFromAttributeSet; as = null");
2521         }
2522         return -1;
2523     }
2524 
2525     /**
2526      * return the line spacing from an AttributeSet
2527      */
2528     private float getLineSpacingFromAttributeSet(AttributeSet as) {
2529         if (as != null) {
2530             return StyleConstants.getLineSpacing(as);
2531         } else {
2532             debugString("getLineSpacingFromAttributeSet; as = null");
2533         }
2534         return -1;
2535     }
2536 
2537     /**
2538      * return the space above from an AttributeSet
2539      */
2540     private float getSpaceAboveFromAttributeSet(AttributeSet as) {
2541         if (as != null) {
2542             return StyleConstants.getSpaceAbove(as);
2543         } else {
2544             debugString("getSpaceAboveFromAttributeSet; as = null");
2545         }
2546         return -1;
2547     }
2548 
2549     /**
2550      * return the space below from an AttributeSet
2551      */
2552     private float getSpaceBelowFromAttributeSet(AttributeSet as) {
2553         if (as != null) {
2554             return StyleConstants.getSpaceBelow(as);
2555         } else {
2556             debugString("getSpaceBelowFromAttributeSet; as = null");
2557         }
2558         return -1;
2559     }
2560 
2561     /**
2562      * Enumerate all StyleConstants in the AttributeSet
2563      *
2564      * We need to check explicitly, 'cause of the HTML package conversion
2565      * mechanism (they may not be stored as StyleConstants, just translated
2566      * to them when asked).
2567      *
2568      * (Use convenience methods where they are defined...)
2569      *
2570      * Not checking the following (which the IBM SNS guidelines says
2571      * should be defined):
2572      *    - ComponentElementName
2573      *    - IconElementName
2574      *    - NameAttribute
2575      *    - ResolveAttribute
2576      */


2685      *
2686      */
2687     private String getCurrentAccessibleValueFromContext(final AccessibleContext ac) {
2688         if (ac != null) {
2689             final Number value = InvocationUtils.invokeAndWait(new Callable<Number>() {
2690                 @Override
2691                 public Number call() throws Exception {
2692                     AccessibleValue av = ac.getAccessibleValue();
2693                     if (av == null) return null;
2694                     return av.getCurrentAccessibleValue();
2695                 }
2696             }, ac);
2697             if (value != null) {
2698                 String s = value.toString();
2699                 if (s != null) {
2700                     references.increment(s);
2701                     return s;
2702                 }
2703             }
2704         } else {
2705             debugString("getCurrentAccessibleValueFromContext; ac = null");
2706         }
2707         return null;
2708     }
2709 
2710     /**
2711      * return the AccessibleValue maximum value from an AccessibleContext
2712      * returned using a String 'cause the value is a java Number
2713      *
2714      */
2715     private String getMaximumAccessibleValueFromContext(final AccessibleContext ac) {
2716         if (ac != null) {
2717             final Number value = InvocationUtils.invokeAndWait(new Callable<Number>() {
2718                 @Override
2719                 public Number call() throws Exception {
2720                     AccessibleValue av = ac.getAccessibleValue();
2721                     if (av == null) return null;
2722                     return av.getMaximumAccessibleValue();
2723                 }
2724             }, ac);
2725             if (value != null) {
2726                 String s = value.toString();
2727                 if (s != null) {
2728                     references.increment(s);
2729                     return s;
2730                 }
2731             }
2732         } else {
2733             debugString("getMaximumAccessibleValueFromContext; ac = null");
2734         }
2735         return null;
2736     }
2737 
2738     /**
2739      * return the AccessibleValue minimum value from an AccessibleContext
2740      * returned using a String 'cause the value is a java Number
2741      *
2742      */
2743     private String getMinimumAccessibleValueFromContext(final AccessibleContext ac) {
2744         if (ac != null) {
2745             final Number value = InvocationUtils.invokeAndWait(new Callable<Number>() {
2746                 @Override
2747                 public Number call() throws Exception {
2748                     AccessibleValue av = ac.getAccessibleValue();
2749                     if (av == null) return null;
2750                     return av.getMinimumAccessibleValue();
2751                 }
2752             }, ac);
2753             if (value != null) {
2754                 String s = value.toString();
2755                 if (s != null) {
2756                     references.increment(s);
2757                     return s;
2758                 }
2759             }
2760         } else {
2761             debugString("getMinimumAccessibleValueFromContext; ac = null");
2762         }
2763         return null;
2764     }
2765 
2766 
2767     /* ===== AccessibleSelection methods ===== */
2768 
2769     /**
2770      * add to the AccessibleSelection of an AccessibleContext child i
2771      *
2772      */
2773     private void addAccessibleSelectionFromContext(final AccessibleContext ac, final int i) {
2774         try {
2775             InvocationUtils.invokeAndWait(new Callable<Object>() {
2776                 @Override
2777                 public Object call() throws Exception {
2778                     if (ac != null) {
2779                         AccessibleSelection as = ac.getAccessibleSelection();
2780                         if (as != null) {
2781                             as.addAccessibleSelection(i);


2924                         return at;
2925                     }
2926                 }
2927                 return null;
2928             }
2929         }, ac);
2930     }
2931 
2932 
2933     /*
2934      * returns the AccessibleContext that contains an AccessibleTable
2935      */
2936     private AccessibleContext getContextFromAccessibleTable(AccessibleTable at) {
2937         return hashtab.get(at);
2938     }
2939 
2940     /*
2941      * returns the row count for an AccessibleTable
2942      */
2943     private int getAccessibleTableRowCount(final AccessibleContext ac) {
2944         debugString("##### getAccessibleTableRowCount");
2945         return InvocationUtils.invokeAndWait(new Callable<Integer>() {
2946             @Override
2947             public Integer call() throws Exception {
2948                 if (ac != null) {
2949                     AccessibleTable at = ac.getAccessibleTable();
2950                     if (at != null) {
2951                         return at.getAccessibleRowCount();
2952                     }
2953                 }
2954                 return -1;
2955             }
2956         }, ac);
2957     }
2958 
2959     /*
2960      * returns the column count for an AccessibleTable
2961      */
2962     private int getAccessibleTableColumnCount(final AccessibleContext ac) {
2963         debugString("##### getAccessibleTableColumnCount");
2964         return InvocationUtils.invokeAndWait(new Callable<Integer>() {
2965             @Override
2966             public Integer call() throws Exception {
2967                 if (ac != null) {
2968                     AccessibleTable at = ac.getAccessibleTable();
2969                     if (at != null) {
2970                         return at.getAccessibleColumnCount();
2971                     }
2972                 }
2973                 return -1;
2974             }
2975         }, ac);
2976     }
2977 
2978     /*
2979      * returns the AccessibleContext for an AccessibleTable cell
2980      */
2981     private AccessibleContext getAccessibleTableCellAccessibleContext(final AccessibleTable at,
2982                                                                       final int row, final int column) {
2983         debugString("getAccessibleTableCellAccessibleContext: at = "+at.getClass());
2984         if (at == null) return null;
2985         return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
2986             @Override
2987             public AccessibleContext call() throws Exception {
2988                 if (!(at instanceof AccessibleContext)) {
2989                     Accessible a = at.getAccessibleAt(row, column);
2990                     if (a != null) {
2991                         return a.getAccessibleContext();
2992                     }
2993                 } else {
2994                     // work-around for AccessibleJTable.getCurrentAccessibleContext returning
2995                     // wrong renderer component when cell contains more than one component
2996                     AccessibleContext ac = (AccessibleContext) at;
2997                     Accessible parent = ac.getAccessibleParent();
2998                     if (parent != null) {
2999                         int indexInParent = ac.getAccessibleIndexInParent();
3000                         Accessible child =
3001                                 parent.getAccessibleContext().getAccessibleChild(indexInParent);
3002                         if (child instanceof JTable) {
3003                             JTable table = (JTable) child;


3008                                 renderer = table.getDefaultRenderer(columnClass);
3009                             }
3010                             Component component =
3011                                     renderer.getTableCellRendererComponent(table, table.getValueAt(row, column),
3012                                             false, false, row, column);
3013                             if (component instanceof Accessible) {
3014                                 return component.getAccessibleContext();
3015                             }
3016                         }
3017                     }
3018                 }
3019                 return null;
3020             }
3021         }, getContextFromAccessibleTable(at));
3022     }
3023 
3024     /*
3025      * returns the index of a cell at a given row and column in an AccessibleTable
3026      */
3027     private int getAccessibleTableCellIndex(final AccessibleTable at, int row, int column) {
3028         debugString("##### getAccessibleTableCellIndex: at="+at);
3029         if (at != null) {
3030             int cellIndex = row *
3031                 InvocationUtils.invokeAndWait(new Callable<Integer>() {
3032                     @Override
3033                     public Integer call() throws Exception {
3034                         return at.getAccessibleColumnCount();
3035                     }
3036                 }, getContextFromAccessibleTable(at)) +
3037                 column;
3038             debugString("   ##### getAccessibleTableCellIndex="+cellIndex);
3039             return cellIndex;
3040         }
3041         debugString(" ##### getAccessibleTableCellIndex FAILED");
3042         return -1;
3043     }
3044 
3045     /*
3046      * returns the row extent of a cell at a given row and column in an AccessibleTable
3047      */
3048     private int getAccessibleTableCellRowExtent(final AccessibleTable at, final int row, final int column) {
3049         debugString("##### getAccessibleTableCellRowExtent");
3050         if (at != null) {
3051             int rowExtent = InvocationUtils.invokeAndWait(new Callable<Integer>() {
3052                                                               @Override
3053                                                               public Integer call() throws Exception {
3054                                                                   return at.getAccessibleRowExtentAt(row, column);
3055                                                               }
3056                                                           },
3057                     getContextFromAccessibleTable(at));
3058             debugString("   ##### getAccessibleTableCellRowExtent="+rowExtent);
3059             return rowExtent;
3060         }
3061         debugString(" ##### getAccessibleTableCellRowExtent FAILED");
3062         return -1;
3063     }
3064 
3065     /*
3066      * returns the column extent of a cell at a given row and column in an AccessibleTable
3067      */
3068     private int getAccessibleTableCellColumnExtent(final AccessibleTable at, final int row, final int column) {
3069         debugString("##### getAccessibleTableCellColumnExtent");
3070         if (at != null) {
3071             int columnExtent = InvocationUtils.invokeAndWait(new Callable<Integer>() {
3072                                                                  @Override
3073                                                                  public Integer call() throws Exception {
3074                                                                      return at.getAccessibleColumnExtentAt(row, column);
3075                                                                  }
3076                                                              },
3077                     getContextFromAccessibleTable(at));
3078             debugString("   ##### getAccessibleTableCellColumnExtent="+columnExtent);
3079             return columnExtent;
3080         }
3081         debugString(" ##### getAccessibleTableCellColumnExtent FAILED");
3082         return -1;
3083     }
3084 
3085     /*
3086      * returns whether a cell is selected at a given row and column in an AccessibleTable
3087      */
3088     private boolean isAccessibleTableCellSelected(final AccessibleTable at, final int row,
3089                          final int column) {
3090         debugString("##### isAccessibleTableCellSelected: ["+row+"]["+column+"]");
3091         if (at == null)
3092             return false;
3093         return InvocationUtils.invokeAndWait(new Callable<Boolean>() {
3094             @Override
3095             public Boolean call() throws Exception {
3096                 boolean isSelected = false;
3097                 Accessible a = at.getAccessibleAt(row, column);
3098                 if (a != null) {
3099                     AccessibleContext ac = a.getAccessibleContext();
3100                     if (ac == null)
3101                         return false;
3102                     AccessibleStateSet as = ac.getAccessibleStateSet();
3103                     if (as != null) {
3104                         isSelected = as.contains(AccessibleState.SELECTED);
3105                     }
3106                 }
3107                 return isSelected;
3108             }
3109         }, getContextFromAccessibleTable(at));
3110     }
3111 
3112     /*
3113      * returns an AccessibleTable that represents the row header in an
3114      * AccessibleTable
3115      */
3116     private AccessibleTable getAccessibleTableRowHeader(final AccessibleContext ac) {
3117         debugString(" #####  getAccessibleTableRowHeader called");
3118         AccessibleTable at = InvocationUtils.invokeAndWait(new Callable<AccessibleTable>() {
3119             @Override
3120             public AccessibleTable call() throws Exception {
3121                 if (ac != null) {
3122                     AccessibleTable at = ac.getAccessibleTable();
3123                     if (at != null) {
3124                         return at.getAccessibleRowHeader();
3125                     }
3126                 }
3127                 return null;
3128             }
3129         }, ac);
3130         if (at != null) {
3131             hashtab.put(at, ac);
3132         }
3133         return at;
3134     }
3135 
3136     /*
3137      * returns an AccessibleTable that represents the column header in an
3138      * AccessibleTable
3139      */
3140     private AccessibleTable getAccessibleTableColumnHeader(final AccessibleContext ac) {
3141     debugString("##### getAccessibleTableColumnHeader");
3142         if (ac == null)
3143             return null;
3144         AccessibleTable at = InvocationUtils.invokeAndWait(new Callable<AccessibleTable>() {
3145             @Override
3146             public AccessibleTable call() throws Exception {
3147                 // workaround for getAccessibleColumnHeader NPE
3148                 // when the table header is null
3149                 Accessible parent = ac.getAccessibleParent();
3150                 if (parent != null) {
3151                     int indexInParent = ac.getAccessibleIndexInParent();
3152                     Accessible child =
3153                             parent.getAccessibleContext().getAccessibleChild(indexInParent);
3154                     if (child instanceof JTable) {
3155                         JTable table = (JTable) child;
3156                         if (table.getTableHeader() == null) {
3157                             return null;
3158                         }
3159                     }
3160                 }
3161                 AccessibleTable at = ac.getAccessibleTable();
3162                 if (at != null) {
3163                     return at.getAccessibleColumnHeader();
3164                 }
3165                 return null;
3166             }
3167         }, ac);
3168         if (at != null) {
3169             hashtab.put(at, ac);
3170         }
3171         return at;
3172     }
3173 
3174     /*
3175      * returns the number of row headers in an AccessibleTable that represents
3176      * the row header in an AccessibleTable
3177      */
3178     private int getAccessibleTableRowHeaderRowCount(AccessibleContext ac) {
3179 
3180     debugString(" #####  getAccessibleTableRowHeaderRowCount called");
3181         if (ac != null) {
3182             final AccessibleTable atRowHeader = getAccessibleTableRowHeader(ac);
3183             if (atRowHeader != null) {
3184                 return InvocationUtils.invokeAndWait(new Callable<Integer>() {
3185                     @Override
3186                     public Integer call() throws Exception {
3187                         if (atRowHeader != null) {
3188                             return atRowHeader.getAccessibleRowCount();
3189                         }
3190                         return -1;
3191                     }
3192                 }, ac);
3193             }
3194         }
3195         return -1;
3196     }
3197 
3198     /*
3199      * returns the number of column headers in an AccessibleTable that represents
3200      * the row header in an AccessibleTable
3201      */
3202     private int getAccessibleTableRowHeaderColumnCount(AccessibleContext ac) {
3203         debugString(" #####  getAccessibleTableRowHeaderColumnCount called");
3204         if (ac != null) {
3205             final AccessibleTable atRowHeader = getAccessibleTableRowHeader(ac);
3206             if (atRowHeader != null) {
3207                 return InvocationUtils.invokeAndWait(new Callable<Integer>() {
3208                     @Override
3209                     public Integer call() throws Exception {
3210                         if (atRowHeader != null) {
3211                             return atRowHeader.getAccessibleColumnCount();
3212                         }
3213                         return -1;
3214                     }
3215                 }, ac);
3216             }
3217         }
3218         debugString(" ##### getAccessibleTableRowHeaderColumnCount FAILED");
3219         return -1;
3220     }
3221 
3222     /*
3223      * returns the number of row headers in an AccessibleTable that represents
3224      * the column header in an AccessibleTable
3225      */
3226     private int getAccessibleTableColumnHeaderRowCount(AccessibleContext ac) {
3227 
3228     debugString("##### getAccessibleTableColumnHeaderRowCount");
3229         if (ac != null) {
3230             final AccessibleTable atColumnHeader = getAccessibleTableColumnHeader(ac);
3231             if (atColumnHeader != null) {
3232                 return InvocationUtils.invokeAndWait(new Callable<Integer>() {
3233                     @Override
3234                     public Integer call() throws Exception {
3235                         if (atColumnHeader != null) {
3236                             return atColumnHeader.getAccessibleRowCount();
3237                         }
3238                         return -1;
3239                     }
3240                 }, ac);
3241             }
3242         }
3243         debugString(" ##### getAccessibleTableColumnHeaderRowCount FAILED");
3244         return -1;
3245     }
3246 
3247     /*
3248      * returns the number of column headers in an AccessibleTable that represents
3249      * the column header in an AccessibleTable
3250      */
3251     private int getAccessibleTableColumnHeaderColumnCount(AccessibleContext ac) {
3252 
3253     debugString("#####  getAccessibleTableColumnHeaderColumnCount");
3254         if (ac != null) {
3255             final AccessibleTable atColumnHeader = getAccessibleTableColumnHeader(ac);
3256             if (atColumnHeader != null) {
3257                 return InvocationUtils.invokeAndWait(new Callable<Integer>() {
3258                     @Override
3259                     public Integer call() throws Exception {
3260                         if (atColumnHeader != null) {
3261                             return atColumnHeader.getAccessibleColumnCount();
3262                         }
3263                         return -1;
3264                     }
3265                 }, ac);
3266             }
3267         }
3268         debugString(" ##### getAccessibleTableColumnHeaderColumnCount FAILED");
3269         return -1;
3270     }
3271 
3272     /*
3273      * returns the description of a row header in an AccessibleTable
3274      */
3275     private AccessibleContext getAccessibleTableRowDescription(final AccessibleTable table,
3276                                                               final int row) {
3277         return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
3278             @Override
3279             public AccessibleContext call() throws Exception {
3280                 if (table != null) {
3281                     Accessible a = table.getAccessibleRowDescription(row);
3282                     if (a != null) {
3283                         return a.getAccessibleContext();
3284                     }
3285                 }
3286                 return null;
3287             }
3288         }, getContextFromAccessibleTable(table));


3515                     AccessibleRelationSet ars = ac.getAccessibleRelationSet();
3516                     if (ars != null) {
3517                         AccessibleRelation[] relations = ars.toArray();
3518                         if (relations != null && i >= 0 && i < relations.length) {
3519                             Object[] targets = relations[i].getTarget();
3520                             return targets.length;
3521                         }
3522                     }
3523                 }
3524                 return -1;
3525             }
3526         }, ac);
3527     }
3528 
3529     /*
3530      * returns the jth target in the ith relation in the AccessibleContext's
3531      * AccessibleRelationSet
3532      */
3533     private AccessibleContext getAccessibleRelationTarget(final AccessibleContext ac,
3534                                                          final int i, final int j) {
3535         debugString("***** getAccessibleRelationTarget");
3536         return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
3537             @Override
3538             public AccessibleContext call() throws Exception {
3539                 if (ac != null) {
3540                     AccessibleRelationSet ars = ac.getAccessibleRelationSet();
3541                     if (ars != null) {
3542                         AccessibleRelation[] relations = ars.toArray();
3543                         if (relations != null && i >= 0 && i < relations.length) {
3544                             Object[] targets = relations[i].getTarget();
3545                             if (targets != null && j >= 0 & j < targets.length) {
3546                                 Object o = targets[j];
3547                                 if (o instanceof Accessible) {
3548                                     return ((Accessible) o).getAccessibleContext();
3549                                 }
3550                             }
3551                         }
3552                     }
3553                 }
3554                 return null;
3555             }
3556         }, ac);
3557     }
3558 
3559     // ========= AccessibleHypertext =========
3560 
3561     private Map<AccessibleHypertext, AccessibleContext> hyperTextContextMap = new WeakHashMap<>();
3562     private Map<AccessibleHyperlink, AccessibleContext> hyperLinkContextMap = new WeakHashMap<>();
3563 
3564     /*
3565      * Returns the AccessibleHypertext
3566      */
3567     private AccessibleHypertext getAccessibleHypertext(final AccessibleContext ac) {
3568         debugString("getAccessibleHyperlink");
3569         if (ac==null)
3570             return null;
3571         AccessibleHypertext hypertext = InvocationUtils.invokeAndWait(new Callable<AccessibleHypertext>() {
3572             @Override
3573             public AccessibleHypertext call() throws Exception {
3574                 AccessibleText at = ac.getAccessibleText();
3575                 if (!(at instanceof AccessibleHypertext)) {
3576                     return null;
3577                 }
3578                 return ((AccessibleHypertext) at);
3579             }
3580         }, ac);
3581         hyperTextContextMap.put(hypertext, ac);
3582         return hypertext;
3583     }
3584 
3585     /*
3586      * Returns the number of AccessibleHyperlinks
3587      */
3588     private int getAccessibleHyperlinkCount(AccessibleContext ac) {
3589         debugString("getAccessibleHyperlinkCount");
3590         if (ac == null) {
3591             return 0;
3592         }
3593         final AccessibleHypertext hypertext = getAccessibleHypertext(ac);
3594         if (hypertext == null) {
3595             return 0;
3596         }
3597         //return hypertext.getLinkCount();
3598         return InvocationUtils.invokeAndWait(new Callable<Integer>() {
3599             @Override
3600             public Integer call() throws Exception {
3601                 return hypertext.getLinkCount();
3602             }
3603         }, ac);
3604     }
3605 
3606     /*
3607      * Returns the hyperlink at the specified index
3608      */
3609     private AccessibleHyperlink getAccessibleHyperlink(final AccessibleHypertext hypertext, final int i) {
3610         debugString("getAccessibleHyperlink");
3611         if (hypertext == null) {
3612             return null;
3613         }
3614         AccessibleContext ac = hyperTextContextMap.get(hypertext);
3615         if ( i < 0 || i >=
3616              InvocationUtils.invokeAndWait(new Callable<Integer>() {
3617                  @Override
3618                  public Integer call() throws Exception {
3619                      return hypertext.getLinkCount();
3620                  }
3621              }, ac) ) {
3622             return null;
3623         }
3624         AccessibleHyperlink acLink = InvocationUtils.invokeAndWait(new Callable<AccessibleHyperlink>() {
3625             @Override
3626             public AccessibleHyperlink call() throws Exception {
3627                 AccessibleHyperlink link = hypertext.getLink(i);
3628                 if (link == null || (!link.isValid())) {
3629                     return null;
3630                 }
3631                 return link;
3632             }
3633         }, ac);
3634         hyperLinkContextMap.put(acLink, ac);
3635         return acLink;
3636     }
3637 
3638     /*
3639      * Returns the hyperlink object description
3640      */
3641     private String getAccessibleHyperlinkText(final AccessibleHyperlink link) {
3642         debugString("getAccessibleHyperlinkText");
3643         if (link == null) {
3644             return null;
3645         }
3646         return InvocationUtils.invokeAndWait(new Callable<String>() {
3647             @Override
3648             public String call() throws Exception {
3649                 Object o = link.getAccessibleActionDescription(0);
3650                 if (o != null) {
3651                     return o.toString();
3652                 }
3653                 return null;
3654             }
3655         }, hyperLinkContextMap.get(link));
3656     }
3657 
3658     /*
3659      * Returns the hyperlink URL
3660      */
3661     private String getAccessibleHyperlinkURL(final AccessibleHyperlink link) {
3662         debugString("getAccessibleHyperlinkURL");
3663         if (link == null) {
3664             return null;
3665         }
3666         return InvocationUtils.invokeAndWait(new Callable<String>() {
3667             @Override
3668             public String call() throws Exception {
3669                 Object o = link.getAccessibleActionObject(0);
3670                 if (o != null) {
3671                     return o.toString();
3672                 } else {
3673                     return null;
3674                 }
3675             }
3676         }, hyperLinkContextMap.get(link));
3677     }
3678 
3679     /*
3680      * Returns the start index of the hyperlink text
3681      */
3682     private int getAccessibleHyperlinkStartIndex(final AccessibleHyperlink link) {
3683         debugString("getAccessibleHyperlinkStartIndex");
3684         if (link == null) {
3685             return -1;
3686         }
3687         return  InvocationUtils.invokeAndWait(new Callable<Integer>() {
3688             @Override
3689             public Integer call() throws Exception {
3690                 return link.getStartIndex();
3691             }
3692         }, hyperLinkContextMap.get(link));
3693     }
3694 
3695     /*
3696      * Returns the end index of the hyperlink text
3697      */
3698     private int getAccessibleHyperlinkEndIndex(final AccessibleHyperlink link) {
3699         debugString("getAccessibleHyperlinkEndIndex");
3700         if (link == null) {
3701             return -1;
3702         }
3703         return  InvocationUtils.invokeAndWait(new Callable<Integer>() {
3704             @Override
3705             public Integer call() throws Exception {
3706                 return link.getEndIndex();
3707             }
3708         }, hyperLinkContextMap.get(link));
3709     }
3710 
3711     /*
3712      * Returns the index into an array of hyperlinks that
3713      * is associated with this character index, or -1 if there
3714      * is no hyperlink associated with this index.
3715      */
3716     private int getAccessibleHypertextLinkIndex(final AccessibleHypertext hypertext, final int charIndex) {
3717         debugString("getAccessibleHypertextLinkIndex: charIndex = "+charIndex);
3718         if (hypertext == null) {
3719             return -1;
3720         }
3721         int linkIndex = InvocationUtils.invokeAndWait(new Callable<Integer>() {
3722             @Override
3723             public Integer call() throws Exception {
3724                 return hypertext.getLinkIndex(charIndex);
3725             }
3726         }, hyperTextContextMap.get(hypertext));
3727         debugString("getAccessibleHypertextLinkIndex returning "+linkIndex);
3728         return linkIndex;
3729     }
3730 
3731     /*
3732      * Actives the hyperlink
3733      */
3734     private boolean activateAccessibleHyperlink(final AccessibleContext ac,
3735                                                 final AccessibleHyperlink link) {
3736         //debugString("activateAccessibleHyperlink: link = "+link.getClass());
3737         if (link == null) {
3738             return false;
3739         }
3740         boolean retval = InvocationUtils.invokeAndWait(new Callable<Boolean>() {
3741             @Override
3742             public Boolean call() throws Exception {
3743                 return link.doAccessibleAction(0);
3744             }
3745         }, ac);
3746         debugString("activateAccessibleHyperlink: returning = "+retval);
3747         return retval;
3748     }
3749 
3750 
3751     // ============ AccessibleKeyBinding =============
3752 
3753     /*
3754      * returns the component mnemonic
3755      */
3756     private KeyStroke getMnemonic(final AccessibleContext ac) {
3757         if (ac == null)
3758             return null;
3759         return InvocationUtils.invokeAndWait(new Callable<KeyStroke>() {
3760             @Override
3761             public KeyStroke call() throws Exception {
3762                 AccessibleComponent comp = ac.getAccessibleComponent();
3763                 if (!(comp instanceof AccessibleExtendedComponent)) {
3764                     return null;
3765                 }
3766                 AccessibleExtendedComponent aec = (AccessibleExtendedComponent) comp;


3854             case KeyEvent.VK_RIGHT:
3855             case KeyEvent.VK_UP:
3856                 break;
3857             default:
3858                 code = 0;
3859                 break;
3860         }
3861         return code;
3862     }
3863 
3864     /*
3865      * returns the KeyStoke character
3866      */
3867     private char getKeyChar(KeyStroke keyStroke) {
3868         // If the shortcut is an FKey return 1-24
3869         if (keyStroke == null)
3870             return 0;
3871         int fKey = fKeyNumber(keyStroke);
3872         if (fKey != 0) {
3873             // return 0x00000001 through 0x00000018
3874             debugString("   Shortcut is: F" + fKey);
3875             return (char)fKey;
3876         }
3877         // If the accelerator is a control character, return it
3878         int keyCode = controlCode(keyStroke);
3879         if (keyCode != 0) {
3880             debugString("   Shortcut is control character: " + Integer.toHexString(keyCode));
3881             return (char)keyCode;
3882         }
3883         String keyText = KeyEvent.getKeyText(keyStroke.getKeyCode());
3884         debugString("   Shortcut is: " + keyText);
3885         if (keyText != null || keyText.length() > 0) {
3886             CharSequence seq = keyText.subSequence(0, 1);
3887             if (seq != null || seq.length() > 0) {
3888                 return seq.charAt(0);
3889             }
3890         }
3891         return 0;
3892     }
3893 
3894     /*
3895      * returns the KeyStroke modifiers as an int
3896      */
3897     private int getModifiers(KeyStroke keyStroke) {
3898         if (keyStroke == null)
3899             return 0;
3900         debugString("In AccessBridge.getModifiers");
3901         // modifiers is a bit strip where bits 0-7 indicate a traditional modifier
3902         // such as Ctrl/Alt/Shift, bit 8 indicates an F key shortcut, and bit 9 indicates
3903         // a control code shortcut such as the delete key.
3904 
3905         int modifiers = 0;
3906         // Is the shortcut an FKey?
3907         if (fKeyNumber(keyStroke) != 0) {
3908             modifiers |= 1 << 8;
3909         }
3910         // Is the shortcut a control code?
3911         if (controlCode(keyStroke) != 0) {
3912             modifiers |= 1 << 9;
3913         }
3914         // The following is needed in order to handle translated modifiers.
3915         // getKeyModifiersText doesn't work because for example in German Strg is
3916         // returned for Ctrl.
3917 
3918         // There can be more than one modifier, e.g. if the modifier is ctrl + shift + B
3919         // the toString text is "shift ctrl pressed B". Need to parse through that.
3920         StringTokenizer st = new StringTokenizer(keyStroke.toString());
3921         while (st.hasMoreTokens()) {
3922             String text = st.nextToken();
3923             // Meta+Ctrl+Alt+Shift
3924             // 0-3 are shift, ctrl, meta, alt
3925             // 4-7 are for Solaris workstations (though not being used)
3926             if (text.startsWith("met")) {
3927                 debugString("   found meta");
3928                 modifiers |= ActionEvent.META_MASK;
3929             }
3930             if (text.startsWith("ctr")) {
3931                 debugString("   found ctrl");
3932                 modifiers |= ActionEvent.CTRL_MASK;
3933             }
3934             if (text.startsWith("alt")) {
3935                 debugString("   found alt");
3936                 modifiers |= ActionEvent.ALT_MASK;
3937             }
3938             if (text.startsWith("shi")) {
3939                 debugString("   found shift");
3940                 modifiers |= ActionEvent.SHIFT_MASK;
3941             }
3942         }
3943         debugString("   returning modifiers: 0x" + Integer.toHexString(modifiers));
3944         return modifiers;
3945     }
3946 
3947     /*
3948      * returns the number of key bindings associated with this context
3949      */
3950     private int getAccessibleKeyBindingsCount(AccessibleContext ac) {
3951         if (ac == null)
3952             return 0;
3953         int count = 0;
3954 
3955         if (getMnemonic(ac) != null) {
3956             count++;
3957         }
3958         if (getAccelerator(ac) != null) {
3959             count++;
3960         }
3961         return count;
3962     }
3963 


4002         if (index == 0) {   // mnemonic
4003             KeyStroke keyStroke = getMnemonic(ac);
4004             if (keyStroke != null) {
4005                 return getModifiers(keyStroke);
4006             }
4007         } else if (index == 1) { // accelerator
4008             KeyStroke keyStroke = getAccelerator(ac);
4009             if (keyStroke != null) {
4010                 return getModifiers(keyStroke);
4011             }
4012         }
4013         return 0;
4014     }
4015 
4016     // ========== AccessibleIcon ============
4017 
4018     /*
4019      * return the number of icons associated with this context
4020      */
4021     private int getAccessibleIconsCount(final AccessibleContext ac) {
4022         debugString("getAccessibleIconsCount");
4023         if (ac == null) {
4024             return 0;
4025         }
4026         return InvocationUtils.invokeAndWait(new Callable<Integer>() {
4027             @Override
4028             public Integer call() throws Exception {
4029                 AccessibleIcon[] ai = ac.getAccessibleIcon();
4030                 if (ai == null) {
4031                     return 0;
4032                 }
4033                 return ai.length;
4034             }
4035         }, ac);
4036     }
4037 
4038     /*
4039      * return icon description at the specified index
4040      */
4041     private String getAccessibleIconDescription(final AccessibleContext ac, final int index) {
4042         debugString("getAccessibleIconDescription: index = "+index);
4043         if (ac == null) {
4044             return null;
4045         }
4046         return InvocationUtils.invokeAndWait(new Callable<String>() {
4047             @Override
4048             public String call() throws Exception {
4049                 AccessibleIcon[] ai = ac.getAccessibleIcon();
4050                 if (ai == null || index < 0 || index >= ai.length) {
4051                     return null;
4052                 }
4053                 return ai[index].getAccessibleIconDescription();
4054             }
4055         }, ac);
4056     }
4057 
4058     /*
4059      * return icon height at the specified index
4060      */
4061     private int getAccessibleIconHeight(final AccessibleContext ac, final int index) {
4062         debugString("getAccessibleIconHeight: index = "+index);
4063         if (ac == null) {
4064             return 0;
4065         }
4066         return InvocationUtils.invokeAndWait(new Callable<Integer>() {
4067             @Override
4068             public Integer call() throws Exception {
4069                 AccessibleIcon[] ai = ac.getAccessibleIcon();
4070                 if (ai == null || index < 0 || index >= ai.length) {
4071                     return 0;
4072                 }
4073                 return ai[index].getAccessibleIconHeight();
4074             }
4075         }, ac);
4076     }
4077 
4078     /*
4079      * return icon width at the specified index
4080      */
4081     private int getAccessibleIconWidth(final AccessibleContext ac, final int index) {
4082         debugString("getAccessibleIconWidth: index = "+index);
4083         if (ac == null) {
4084             return 0;
4085         }
4086         return InvocationUtils.invokeAndWait(new Callable<Integer>() {
4087             @Override
4088             public Integer call() throws Exception {
4089                 AccessibleIcon[] ai = ac.getAccessibleIcon();
4090                 if (ai == null || index < 0 || index >= ai.length) {
4091                     return 0;
4092                 }
4093                 return ai[index].getAccessibleIconWidth();
4094             }
4095         }, ac);
4096     }
4097 
4098     // ========= AccessibleAction ===========
4099 
4100     /*
4101      * return the number of icons associated with this context
4102      */
4103     private int getAccessibleActionsCount(final AccessibleContext ac) {
4104         debugString("getAccessibleActionsCount");
4105         if (ac == null) {
4106             return 0;
4107         }
4108         return InvocationUtils.invokeAndWait(new Callable<Integer>() {
4109             @Override
4110             public Integer call() throws Exception {
4111                 AccessibleAction aa = ac.getAccessibleAction();
4112                 if (aa == null)
4113                     return 0;
4114                 return aa.getAccessibleActionCount();
4115             }
4116         }, ac);
4117     }
4118 
4119     /*
4120      * return icon description at the specified index
4121      */
4122     private String getAccessibleActionName(final AccessibleContext ac, final int index) {
4123         debugString("getAccessibleActionName: index = "+index);
4124         if (ac == null) {
4125             return null;
4126         }
4127         return InvocationUtils.invokeAndWait(new Callable<String>() {
4128             @Override
4129             public String call() throws Exception {
4130                 AccessibleAction aa = ac.getAccessibleAction();
4131                 if (aa == null) {
4132                     return null;
4133                 }
4134                 return aa.getAccessibleActionDescription(index);
4135             }
4136         }, ac);
4137     }
4138     /*
4139      * return icon description at the specified index
4140      */
4141     private boolean doAccessibleActions(final AccessibleContext ac, final String name) {
4142         debugString("doAccessibleActions: action name = "+name);
4143         if (ac == null || name == null) {
4144             return false;
4145         }
4146         return InvocationUtils.invokeAndWait(new Callable<Boolean>() {
4147             @Override
4148             public Boolean call() throws Exception {
4149                 AccessibleAction aa = ac.getAccessibleAction();
4150                 if (aa == null) {
4151                     return false;
4152                 }
4153                 int index = -1;
4154                 int numActions = aa.getAccessibleActionCount();
4155                 for (int i = 0; i < numActions; i++) {
4156                     String actionName = aa.getAccessibleActionDescription(i);
4157                     if (name.equals(actionName)) {
4158                         index = i;
4159                         break;
4160                     }
4161                 }
4162                 if (index == -1) {
4163                     return false;
4164                 }
4165                 boolean retval = aa.doAccessibleAction(index);
4166                 return retval;
4167             }
4168         }, ac);
4169     }
4170 
4171     /* ===== AT utility methods ===== */
4172 
4173     /**
4174      * Sets the contents of an AccessibleContext that
4175      * implements AccessibleEditableText with the
4176      * specified text string.
4177      * Returns whether successful.
4178      */
4179     private boolean setTextContents(final AccessibleContext ac, final String text) {
4180         debugString("setTextContents: ac = "+ac+"; text = "+text);
4181 
4182         if (! (ac instanceof AccessibleEditableText)) {
4183             debugString("   ac not instanceof AccessibleEditableText: "+ac);
4184             return false;
4185         }
4186         if (text == null) {
4187             debugString("   text is null");
4188             return false;
4189         }
4190 
4191         return InvocationUtils.invokeAndWait(new Callable<Boolean>() {
4192             @Override
4193             public Boolean call() throws Exception {
4194                 // check whether the text field is editable
4195                 AccessibleStateSet ass = ac.getAccessibleStateSet();
4196                 if (!ass.contains(AccessibleState.ENABLED)) {
4197                     return false;
4198                 }
4199                 ((AccessibleEditableText) ac).setTextContents(text);
4200                 return true;
4201             }
4202         }, ac);
4203     }
4204 
4205     /**
4206      * Returns the Accessible Context of an Internal Frame object that is
4207      * the ancestor of a given object.  If the object is an Internal Frame
4208      * object or an Internal Frame ancestor object was found, returns the
4209      * object's AccessibleContext.
4210      * If there is no ancestor object that has an Accessible Role of
4211      * Internal Frame, returns (AccessibleContext)0.
4212      */
4213     private AccessibleContext getInternalFrame (AccessibleContext ac) {
4214         return getParentWithRole(ac, AccessibleRole.INTERNAL_FRAME.toString());
4215     }
4216 
4217     /**
4218      * Returns the Accessible Context for the top level object in
4219      * a Java Window.  This is same Accessible Context that is obtained
4220      * from GetAccessibleContextFromHWND for that window.  Returns
4221      * (AccessibleContext)0 on error.
4222      */
4223     private AccessibleContext getTopLevelObject (final AccessibleContext ac) {
4224         debugString("getTopLevelObject; ac = "+ac);
4225         if (ac == null) {
4226             return null;
4227         }
4228         return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
4229             @Override
4230             public AccessibleContext call() throws Exception {
4231                 if (ac.getAccessibleRole() == AccessibleRole.DIALOG) {
4232                     // return the dialog, not the parent window
4233                     return ac;
4234                 }
4235 
4236                 Accessible parent = ac.getAccessibleParent();
4237                 if (parent == null) {
4238                     return ac;
4239                 }
4240                 Accessible tmp = parent;
4241                 while (tmp != null && tmp.getAccessibleContext() != null) {
4242                     AccessibleContext ac2 = tmp.getAccessibleContext();
4243                     if (ac2 != null && ac2.getAccessibleRole() == AccessibleRole.DIALOG) {
4244                         // return the dialog, not the parent window
4245                         return ac2;
4246                     }
4247                     parent = tmp;
4248                     tmp = parent.getAccessibleContext().getAccessibleParent();
4249                 }
4250                 return parent.getAccessibleContext();
4251             }
4252         }, ac);
4253     }
4254 
4255     /**
4256      * Returns the parent AccessibleContext that has the specified AccessibleRole.
4257      * Returns null on error or if the AccessibleContext does not exist.
4258      */
4259     private AccessibleContext getParentWithRole (final AccessibleContext ac,
4260                                                  final String roleName) {
4261         debugString("getParentWithRole; ac = "+ac);
4262         debugString("role = "+roleName);
4263         if (ac == null || roleName == null) {
4264             return null;
4265         }
4266 
4267         return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
4268             @Override
4269             public AccessibleContext call() throws Exception {
4270                 AccessibleRole role = AccessBridge.this.accessibleRoleMap.get(roleName);
4271                 if (role == null) {
4272                     return ac;
4273                 }
4274 
4275                 Accessible parent = ac.getAccessibleParent();
4276                 if (parent == null && ac.getAccessibleRole() == role) {
4277                     return ac;
4278                 }
4279 
4280                 Accessible tmp = parent;
4281                 AccessibleContext tmp_ac = null;
4282 


4298     /**
4299      * Returns the parent AccessibleContext that has the specified AccessibleRole.
4300      * Otherwise, returns the top level object for the Java Window.
4301      * Returns (AccessibleContext)0 on error.
4302      */
4303     private AccessibleContext getParentWithRoleElseRoot (AccessibleContext ac,
4304                                                          String roleName) {
4305         AccessibleContext retval = getParentWithRole(ac, roleName);
4306         if (retval == null) {
4307             retval = getTopLevelObject(ac);
4308         }
4309         return retval;
4310     }
4311 
4312     /**
4313      * Returns how deep in the object hierarchy a given object is.
4314      * The top most object in the object hierarchy has an object depth of 0.
4315      * Returns -1 on error.
4316      */
4317     private int getObjectDepth(final AccessibleContext ac) {
4318         debugString("getObjectDepth: ac = "+ac);
4319 
4320         if (ac == null) {
4321             return -1;
4322         }
4323         return InvocationUtils.invokeAndWait(new Callable<Integer>() {
4324             @Override
4325             public Integer call() throws Exception {
4326                 int count = 0;
4327                 Accessible parent = ac.getAccessibleParent();
4328                 if (parent == null) {
4329                     return count;
4330                 }
4331                 Accessible tmp = parent;
4332                 while (tmp != null && tmp.getAccessibleContext() != null) {
4333                     parent = tmp;
4334                     tmp = parent.getAccessibleContext().getAccessibleParent();
4335                     count++;
4336                 }
4337                 return count;
4338             }
4339         }, ac);
4340     }
4341 
4342     /**
4343      * Returns the Accessible Context of the current ActiveDescendent of an object.
4344      * Returns (AccessibleContext)0 on error.
4345      */
4346     private AccessibleContext getActiveDescendent (final AccessibleContext ac) {
4347         debugString("getActiveDescendent: ac = "+ac);
4348         if (ac == null) {
4349             return null;
4350         }
4351         // workaround for JTree bug where the only possible active
4352         // descendent is the JTree root
4353         final Accessible parent = InvocationUtils.invokeAndWait(new Callable<Accessible>() {
4354             @Override
4355             public Accessible call() throws Exception {
4356                 return ac.getAccessibleParent();
4357             }
4358         }, ac);
4359 
4360         if (parent != null) {
4361             Accessible child = InvocationUtils.invokeAndWait(new Callable<Accessible>() {
4362                 @Override
4363                 public Accessible call() throws Exception {
4364                     int indexInParent = ac.getAccessibleIndexInParent();
4365                     return parent.getAccessibleContext().getAccessibleChild(indexInParent);
4366                 }
4367             }, ac);


4395                 if (a == null) {
4396                     return null;
4397                 }
4398                 return a.getAccessibleContext();
4399             }
4400         }, ac);
4401     }
4402 
4403 
4404     /**
4405      * Additional methods for Teton
4406      */
4407 
4408     /**
4409      * Gets the AccessibleName for a component based upon the JAWS algorithm.
4410      * Returns whether successful.
4411      *
4412      * Bug ID 4916682 - Implement JAWS AccessibleName policy
4413      */
4414     private String getJAWSAccessibleName(final AccessibleContext ac) {
4415         debugString("getJAWSAccessibleName");
4416         if (ac == null) {
4417             return null;
4418         }
4419         // placeholder
4420         return InvocationUtils.invokeAndWait(new Callable<String>() {
4421             @Override
4422             public String call() throws Exception {
4423                 return ac.getAccessibleName();
4424             }
4425         }, ac);
4426     }
4427 
4428     /**
4429      * Request focus for a component. Returns whether successful;
4430      *
4431      * Bug ID 4944757 - requestFocus method needed
4432      */
4433     private boolean requestFocus(final AccessibleContext ac) {
4434         debugString("requestFocus");
4435         if (ac == null) {
4436             return false;
4437         }
4438         return InvocationUtils.invokeAndWait(new Callable<Boolean>() {
4439             @Override
4440             public Boolean call() throws Exception {
4441                 AccessibleComponent acomp = ac.getAccessibleComponent();
4442                 if (acomp == null) {
4443                     return false;
4444                 }
4445                 acomp.requestFocus();
4446                 return ac.getAccessibleStateSet().contains(AccessibleState.FOCUSED);
4447             }
4448         }, ac);
4449     }
4450 
4451     /**
4452      * Selects text between two indices.  Selection includes the
4453      * text at the start index and the text at the end index. Returns
4454      * whether successful;
4455      *
4456      * Bug ID 4944758 - selectTextRange method needed
4457      */
4458     private boolean selectTextRange(final AccessibleContext ac, final int startIndex, final int endIndex) {
4459         debugString("selectTextRange: start = "+startIndex+"; end = "+endIndex);
4460         if (ac == null) {
4461             return false;
4462         }
4463         return InvocationUtils.invokeAndWait(new Callable<Boolean>() {
4464             @Override
4465             public Boolean call() throws Exception {
4466                 AccessibleText at = ac.getAccessibleText();
4467                 if (!(at instanceof AccessibleEditableText)) {
4468                     return false;
4469                 }
4470                 ((AccessibleEditableText) at).selectText(startIndex, endIndex);
4471 
4472                 boolean result = at.getSelectionStart() == startIndex &&
4473                         at.getSelectionEnd() == endIndex;
4474                 return result;
4475             }
4476         }, ac);
4477     }
4478 
4479     /**
4480      * Set the caret to a text position. Returns whether successful;
4481      *
4482      * Bug ID 4944770 - setCaretPosition method needed
4483      */
4484     private boolean setCaretPosition(final AccessibleContext ac, final int position) {
4485         debugString("setCaretPosition: position = "+position);
4486         if (ac == null) {
4487             return false;
4488         }
4489         return InvocationUtils.invokeAndWait(new Callable<Boolean>() {
4490             @Override
4491             public Boolean call() throws Exception {
4492                 AccessibleText at = ac.getAccessibleText();
4493                 if (!(at instanceof AccessibleEditableText)) {
4494                     return false;
4495                 }
4496                 ((AccessibleEditableText) at).selectText(position, position);
4497                 return at.getCaretPosition() == position;
4498             }
4499         }, ac);
4500     }
4501 
4502     /**
4503      * Gets the number of visible children of an AccessibleContext.
4504      *
4505      * Bug ID 4944762- getVisibleChildren for list-like components needed
4506      */
4507     private int _visibleChildrenCount;
4508     private AccessibleContext _visibleChild;
4509     private int _currentVisibleIndex;
4510     private boolean _foundVisibleChild;
4511 
4512     private int getVisibleChildrenCount(AccessibleContext ac) {
4513         debugString("getVisibleChildrenCount");
4514         if (ac == null) {
4515             return -1;
4516         }
4517         _visibleChildrenCount = 0;
4518         _getVisibleChildrenCount(ac);
4519         debugString("  _visibleChildrenCount = "+_visibleChildrenCount);
4520         return _visibleChildrenCount;
4521     }
4522 
4523     /*
4524      * Recursively descends AccessibleContext and gets the number
4525      * of visible children
4526      */
4527     private void _getVisibleChildrenCount(final AccessibleContext ac) {
4528         if (ac == null)
4529             return;
4530         if(ac instanceof AccessibleExtendedTable) {
4531             _getVisibleChildrenCount((AccessibleExtendedTable)ac);
4532             return;
4533         }
4534         int numChildren = InvocationUtils.invokeAndWait(new Callable<Integer>() {
4535             @Override
4536             public Integer call() throws Exception {
4537                 return ac.getAccessibleChildrenCount();
4538             }
4539         }, ac);


4639 
4640                 if (InvocationUtils.invokeAndWait(new Callable<Integer>() {
4641                     @Override
4642                     public Integer call() throws Exception {
4643                         return ac2.getAccessibleChildrenCount();
4644                     }
4645                 }, acTable) > 0) {
4646                     _getVisibleChildrenCount(ac2);
4647                 }
4648             }
4649         }
4650     }
4651 
4652     /**
4653      * Gets the visible child of an AccessibleContext at the
4654      * specified index
4655      *
4656      * Bug ID 4944762- getVisibleChildren for list-like components needed
4657      */
4658     private AccessibleContext getVisibleChild(AccessibleContext ac, int index) {
4659         debugString("getVisibleChild: index = "+index);
4660         if (ac == null) {
4661             return null;
4662         }
4663         _visibleChild = null;
4664         _currentVisibleIndex = 0;
4665         _foundVisibleChild = false;
4666         _getVisibleChild(ac, index);
4667 
4668         if (_visibleChild != null) {
4669             debugString( "    getVisibleChild: found child = " +
4670                          InvocationUtils.invokeAndWait(new Callable<String>() {
4671                              @Override
4672                              public String call() throws Exception {
4673                                  return AccessBridge.this._visibleChild.getAccessibleName();
4674                              }
4675                          }, ac) );
4676         }
4677         return _visibleChild;
4678     }
4679 
4680     /*
4681      * Recursively searchs AccessibleContext and finds the visible component
4682      * at the specified index
4683      */
4684     private void _getVisibleChild(final AccessibleContext ac, final int index) {
4685         if (_visibleChild != null) {
4686             return;
4687         }
4688         if(ac instanceof AccessibleExtendedTable) {
4689             _getVisibleChild((AccessibleExtendedTable)ac, index);


4838 
4839         /**
4840         * Constructor
4841         */
4842         ObjectReferences() {
4843             refs = new ConcurrentHashMap<>(4);
4844         }
4845 
4846         /**
4847         * Debugging: dump the contents of ObjectReferences' refs Hashtable
4848         */
4849         String dump() {
4850             return refs.toString();
4851         }
4852 
4853         /**
4854         * Increment ref count; set to 1 if we have no references for it
4855         */
4856         void increment(Object o) {
4857             if (o == null){
4858                 debugString("ObjectReferences::increment - Passed in object is null");
4859                 return;
4860             }
4861 
4862             if (refs.containsKey(o)) {
4863                 (refs.get(o)).value++;
4864             } else {
4865                 refs.put(o, new Reference(1));
4866             }
4867         }
4868 
4869         /**
4870         * Decrement ref count; remove if count drops to 0
4871         */
4872         void decrement(Object o) {
4873             Reference aRef = refs.get(o);
4874             if (aRef != null) {
4875                 aRef.value--;
4876                 if (aRef.value == 0) {
4877                     refs.remove(o);
4878                 } else if (aRef.value < 0) {
4879                     debugString("ERROR: decrementing reference count below 0");
4880                 }
4881             } else {
4882                 debugString("ERROR: object to decrement not in ObjectReferences table");
4883             }
4884         }
4885 
4886     }
4887 
4888     /* ===== event handling code ===== */
4889 
4890    /**
4891      * native method for handling property change events
4892      */
4893     private native void propertyCaretChange(PropertyChangeEvent e,
4894                         AccessibleContext src,
4895                         int oldValue, int newValue);
4896     private native void propertyDescriptionChange(PropertyChangeEvent e,
4897                         AccessibleContext src,
4898                         String oldValue, String newValue);
4899     private native void propertyNameChange(PropertyChangeEvent e,
4900                         AccessibleContext src,
4901                         String oldValue, String newValue);
4902     private native void propertySelectionChange(PropertyChangeEvent e,


5197         /**
5198          * Turn off event monitoring for the event type passed in
5199          * If necessary, remove the appropriate event listener (if
5200          * no other event of that type is being listened for)
5201          */
5202         void removeAccessibilityEventNotification(long type) {
5203             long newEventMask = accessibilityEventMask & (~type);
5204             if ( ((accessibilityEventMask & PROPERTY_EVENTS) != 0) &&
5205                  ((newEventMask & PROPERTY_EVENTS) == 0) ) {
5206                 AccessibilityEventMonitor.removePropertyChangeListener(this);
5207             }
5208             accessibilityEventMask = newEventMask;
5209         }
5210 
5211         /**
5212          *  ------- property change event glue
5213          */
5214         // This is invoked on the EDT , as
5215         public void propertyChange(PropertyChangeEvent e) {
5216 
5217             accessBridge.debugString("propertyChange(" + e.toString() + ") called");
5218 
5219             if (e != null && (accessibilityEventMask & PROPERTY_EVENTS) != 0) {
5220                 Object o = e.getSource();
5221                 AccessibleContext ac;
5222 
5223                 if (o instanceof AccessibleContext) {
5224                     ac = (AccessibleContext) o;
5225                 } else {
5226                     Accessible a = Translator.getAccessible(e.getSource());
5227                     if (a == null)
5228                         return;
5229                     else
5230                         ac = a.getAccessibleContext();
5231                 }
5232                 if (ac != null) {
5233                     InvocationUtils.registerAccessibleContext(ac, AppContext.getAppContext());
5234 
5235                     accessBridge.debugString("AccessibleContext: " + ac);
5236                     String propertyName = e.getPropertyName();
5237 
5238                     if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_CARET_PROPERTY) == 0) {
5239                         int oldValue = 0;
5240                         int newValue = 0;
5241 
5242                         if (e.getOldValue() instanceof Integer) {
5243                             oldValue = ((Integer) e.getOldValue()).intValue();
5244                         }
5245                         if (e.getNewValue() instanceof Integer) {
5246                             newValue = ((Integer) e.getNewValue()).intValue();
5247                         }
5248                         accessBridge.debugString(" - about to call propertyCaretChange()");
5249                         accessBridge.debugString("   old value: " + oldValue + "new value: " + newValue);
5250                         accessBridge.propertyCaretChange(e, ac, oldValue, newValue);
5251 
5252                     } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_DESCRIPTION_PROPERTY) == 0) {
5253                         String oldValue = null;
5254                         String newValue = null;
5255 
5256                         if (e.getOldValue() != null) {
5257                             oldValue = e.getOldValue().toString();
5258                         }
5259                         if (e.getNewValue() != null) {
5260                             newValue = e.getNewValue().toString();
5261                         }
5262                         accessBridge.debugString(" - about to call propertyDescriptionChange()");
5263                         accessBridge.debugString("   old value: " + oldValue + "new value: " + newValue);
5264                         accessBridge.propertyDescriptionChange(e, ac, oldValue, newValue);
5265 
5266                     } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_NAME_PROPERTY) == 0) {
5267                         String oldValue = null;
5268                         String newValue = null;
5269 
5270                         if (e.getOldValue() != null) {
5271                             oldValue = e.getOldValue().toString();
5272                         }
5273                         if (e.getNewValue() != null) {
5274                             newValue = e.getNewValue().toString();
5275                         }
5276                         accessBridge.debugString(" - about to call propertyNameChange()");
5277                         accessBridge.debugString("   old value: " + oldValue + " new value: " + newValue);
5278                         accessBridge.propertyNameChange(e, ac, oldValue, newValue);
5279 
5280                     } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY) == 0) {
5281                         accessBridge.debugString(" - about to call propertySelectionChange() " + ac +  "   " + Thread.currentThread() + "   " + e.getSource());
5282 
5283                         accessBridge.propertySelectionChange(e, ac);
5284 
5285                     } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_STATE_PROPERTY) == 0) {
5286                         String oldValue = null;
5287                         String newValue = null;
5288 
5289                         // Localization fix requested by Oliver for EA-1
5290                         if (e.getOldValue() != null) {
5291                             AccessibleState oldState = (AccessibleState) e.getOldValue();
5292                             oldValue = oldState.toDisplayString(Locale.US);
5293                         }
5294                         if (e.getNewValue() != null) {
5295                             AccessibleState newState = (AccessibleState) e.getNewValue();
5296                             newValue = newState.toDisplayString(Locale.US);
5297                         }
5298 
5299                         accessBridge.debugString(" - about to call propertyStateChange()");
5300                         accessBridge.propertyStateChange(e, ac, oldValue, newValue);
5301 
5302                     } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_TEXT_PROPERTY) == 0) {
5303                         accessBridge.debugString(" - about to call propertyTextChange()");
5304                         accessBridge.propertyTextChange(e, ac);
5305 
5306                     } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_VALUE_PROPERTY) == 0) {  // strings 'cause of floating point, etc.
5307                         String oldValue = null;
5308                         String newValue = null;
5309 
5310                         if (e.getOldValue() != null) {
5311                             oldValue = e.getOldValue().toString();
5312                         }
5313                         if (e.getNewValue() != null) {
5314                             newValue = e.getNewValue().toString();
5315                         }
5316                         accessBridge.debugString(" - about to call propertyDescriptionChange()");
5317                         accessBridge.propertyValueChange(e, ac, oldValue, newValue);
5318 
5319                     } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY) == 0) {
5320                         accessBridge.propertyVisibleDataChange(e, ac);
5321 
5322                     } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_CHILD_PROPERTY) == 0) {
5323                         AccessibleContext oldAC = null;
5324                         AccessibleContext newAC = null;
5325                         Accessible a;
5326 
5327                         if (e.getOldValue() instanceof AccessibleContext) {
5328                             oldAC = (AccessibleContext) e.getOldValue();
5329                             InvocationUtils.registerAccessibleContext(oldAC, AppContext.getAppContext());
5330                         }
5331                         if (e.getNewValue() instanceof AccessibleContext) {
5332                             newAC = (AccessibleContext) e.getNewValue();
5333                             InvocationUtils.registerAccessibleContext(newAC, AppContext.getAppContext());
5334                         }
5335                         accessBridge.debugString(" - about to call propertyChildChange()");
5336                         accessBridge.debugString("   old AC: " + oldAC + "new AC: " + newAC);
5337                         accessBridge.propertyChildChange(e, ac, oldAC, newAC);
5338 
5339                     } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY) == 0) {
5340                         handleActiveDescendentEvent(e, ac);
5341                     }
5342                 }
5343             }
5344         }
5345 
5346         /*
5347         * Handle an ActiveDescendent PropertyChangeEvent.  This
5348         * method works around a JTree bug where ActiveDescendent
5349         * PropertyChangeEvents have the wrong parent.
5350         */
5351         private AccessibleContext prevAC = null; // previous AccessibleContext
5352 
5353         private void handleActiveDescendentEvent(PropertyChangeEvent e,
5354                                                  AccessibleContext ac) {
5355             if (e == null || ac == null)
5356                 return;


5379             if (e.getNewValue() instanceof Accessible) {
5380                 newAC = ((Accessible) e.getNewValue()).getAccessibleContext();
5381             } else if (e.getNewValue() instanceof Component) {
5382                 a = Translator.getAccessible(e.getNewValue());
5383                 if (a != null) {
5384                     newAC = a.getAccessibleContext();
5385                 }
5386             }
5387             if (newAC != null) {
5388                 Accessible parent = newAC.getAccessibleParent();
5389                 if (parent instanceof JTree) {
5390                     // use a new AccessibleJTreeNode with the right parent
5391                     JTree tree = (JTree)parent;
5392                     newAC = new AccessibleJTreeNode(tree,
5393                                                     tree.getSelectionPath(),
5394                                                     null);
5395                 }
5396             }
5397             prevAC = newAC;
5398 
5399             accessBridge.debugString("  - about to call propertyActiveDescendentChange()");
5400             accessBridge.debugString("   AC: " + ac);
5401             accessBridge.debugString("   old AC: " + oldAC + "new AC: " + newAC);
5402 
5403             InvocationUtils.registerAccessibleContext(oldAC, AppContext.getAppContext());
5404             InvocationUtils.registerAccessibleContext(newAC, AppContext.getAppContext());
5405             accessBridge.propertyActiveDescendentChange(e, ac, oldAC, newAC);
5406         }
5407 
5408         /**
5409         *  ------- focus event glue
5410         */
5411         private boolean stateChangeListenerAdded = false;
5412 
5413         public void focusGained(FocusEvent e) {
5414             processFocusGained();
5415         }
5416 
5417         public void stateChanged(ChangeEvent e) {
5418             processFocusGained();
5419         }
5420 
5421         private void processFocusGained() {
5422             Component focusOwner = KeyboardFocusManager.


5427 
5428             // Only menus and popup selections are handled by the JRootPane.
5429             if (focusOwner instanceof JRootPane) {
5430                 MenuElement [] path =
5431                 MenuSelectionManager.defaultManager().getSelectedPath();
5432                 if (path.length > 1) {
5433                     Component penult = path[path.length-2].getComponent();
5434                     Component last = path[path.length-1].getComponent();
5435 
5436                     if (last instanceof JPopupMenu) {
5437                         // This is a popup with nothing in the popup
5438                         // selected. The menu itself is selected.
5439                         FocusEvent e = new FocusEvent(penult, FocusEvent.FOCUS_GAINED);
5440                         AccessibleContext context = penult.getAccessibleContext();
5441                         InvocationUtils.registerAccessibleContext(context, SunToolkit.targetToAppContext(penult));
5442                         accessBridge.focusGained(e, context);
5443                     } else if (penult instanceof JPopupMenu) {
5444                         // This is a popup with an item selected
5445                         FocusEvent e =
5446                         new FocusEvent(last, FocusEvent.FOCUS_GAINED);
5447                         accessBridge.debugString(" - about to call focusGained()");
5448                         AccessibleContext focusedAC = last.getAccessibleContext();
5449                         InvocationUtils.registerAccessibleContext(focusedAC, SunToolkit.targetToAppContext(last));
5450                         accessBridge.debugString("   AC: " + focusedAC);
5451                         accessBridge.focusGained(e, focusedAC);
5452                     }
5453                 }
5454             } else {
5455                 // The focus owner has the selection.
5456                 if (focusOwner instanceof Accessible) {
5457                     FocusEvent e = new FocusEvent(focusOwner,
5458                                                   FocusEvent.FOCUS_GAINED);
5459                     accessBridge.debugString(" - about to call focusGained()");
5460                     AccessibleContext focusedAC = focusOwner.getAccessibleContext();
5461                     InvocationUtils.registerAccessibleContext(focusedAC, SunToolkit.targetToAppContext(focusOwner));
5462                     accessBridge.debugString("   AC: " + focusedAC);
5463                     accessBridge.focusGained(e, focusedAC);
5464                 }
5465             }
5466         }
5467 
5468         public void focusLost(FocusEvent e) {
5469             if (e != null && (javaEventMask & FOCUS_LOST_EVENTS) != 0) {
5470                 Accessible a = Translator.getAccessible(e.getSource());
5471                 if (a != null) {
5472                     accessBridge.debugString(" - about to call focusLost()");
5473                     accessBridge.debugString("   AC: " + a.getAccessibleContext());
5474                     AccessibleContext context = a.getAccessibleContext();
5475                     InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());
5476                     accessBridge.focusLost(e, context);
5477                 }
5478             }
5479         }
5480 
5481         /**
5482          *  ------- caret event glue
5483          */
5484         public void caretUpdate(CaretEvent e) {
5485             if (e != null && (javaEventMask & CARET_UPATE_EVENTS) != 0) {
5486                 Accessible a = Translator.getAccessible(e.getSource());
5487                 if (a != null) {
5488                     AccessibleContext context = a.getAccessibleContext();
5489                     InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());
5490                     accessBridge.caretUpdate(e, context);
5491                 }
5492             }
5493         }


6156         private TreePath path = null;
6157         private Accessible accessibleParent = null;
6158         private int index = 0;
6159         private boolean isLeaf = false;
6160 
6161         /**
6162          *  Constructs an AccessibleJTreeNode
6163          */
6164         AccessibleJTreeNode(JTree t, TreePath p, Accessible ap) {
6165             tree = t;
6166             path = p;
6167             accessibleParent = ap;
6168             if (t != null)
6169                 treeModel = t.getModel();
6170             if (p != null) {
6171                 obj = p.getLastPathComponent();
6172                 if (treeModel != null && obj != null) {
6173                     isLeaf = treeModel.isLeaf(obj);
6174                 }
6175             }
6176             debugString("AccessibleJTreeNode: name = "+getAccessibleName()+"; TreePath = "+p+"; parent = "+ap);
6177         }
6178 
6179         private TreePath getChildTreePath(int i) {
6180             // Tree nodes can't be so complex that they have
6181             // two sets of children -> we're ignoring that case
6182             if (i < 0 || i >= getAccessibleChildrenCount() || path == null || treeModel == null) {
6183                 return null;
6184             } else {
6185                 Object childObj = treeModel.getChild(obj, i);
6186                 Object[] objPath = path.getPath();
6187                 Object[] objChildPath = new Object[objPath.length+1];
6188                 java.lang.System.arraycopy(objPath, 0, objChildPath, 0, objPath.length);
6189                 objChildPath[objChildPath.length-1] = childObj;
6190                 return new TreePath(objChildPath);
6191             }
6192         }
6193 
6194         /**
6195          * Get the AccessibleContext associated with this tree node.
6196          * In the implementation of the Java Accessibility API for
6197          * this class, return this object, which is its own
6198          * AccessibleContext.
6199          *
6200          * @return this object
6201         */
6202         public AccessibleContext getAccessibleContext() {
6203             return this;
6204         }
6205 
6206         private AccessibleContext getCurrentAccessibleContext() {
6207             Component c = getCurrentComponent();
6208             if (c instanceof Accessible) {
6209                return (c.getAccessibleContext());
6210             } else {
6211                 return null;
6212             }
6213         }
6214 
6215         private Component getCurrentComponent() {
6216             debugString("AccessibleJTreeNode: getCurrentComponent");
6217             // is the object visible?
6218             // if so, get row, selected, focus & leaf state,
6219             // and then get the renderer component and return it
6220             if (tree != null && tree.isVisible(path)) {
6221                 TreeCellRenderer r = tree.getCellRenderer();
6222                 if (r == null) {
6223                     debugString("  returning null 1");
6224                     return null;
6225                 }
6226                 TreeUI ui = tree.getUI();
6227                 if (ui != null) {
6228                     int row = ui.getRowForPath(tree, path);
6229                     boolean selected = tree.isPathSelected(path);
6230                     boolean expanded = tree.isExpanded(path);
6231                     boolean hasFocus = false; // how to tell?? -PK
6232                     Component retval = r.getTreeCellRendererComponent(tree, obj,
6233                                                                       selected, expanded,
6234                                                                       isLeaf, row, hasFocus);
6235                     debugString("  returning = "+retval.getClass());
6236                     return retval;
6237                 }
6238             }
6239             debugString("  returning null 2");
6240             return null;
6241         }
6242 
6243         // AccessibleContext methods
6244 
6245         /**
6246          * Get the accessible name of this object.
6247          *
6248          * @return the localized name of the object; null if this
6249          * object does not have a name
6250          */
6251         public String getAccessibleName() {
6252             debugString("AccessibleJTreeNode: getAccessibleName");
6253             AccessibleContext ac = getCurrentAccessibleContext();
6254             if (ac != null) {
6255                 String name = ac.getAccessibleName();
6256                 if ((name != null) && (!name.isEmpty())) {
6257                     String retval = ac.getAccessibleName();
6258                     debugString("    returning "+retval);
6259                     return retval;
6260                 } else {
6261                     return null;
6262                 }
6263             }
6264             if ((accessibleName != null) && (accessibleName.isEmpty())) {
6265                 return accessibleName;
6266             } else {
6267                 return null;
6268             }
6269         }
6270 
6271         /**
6272          * Set the localized accessible name of this object.
6273          *
6274          * @param s the new localized name of the object.
6275          */
6276         public void setAccessibleName(String s) {
6277             AccessibleContext ac = getCurrentAccessibleContext();
6278             if (ac != null) {




 143         // windows
 144         initHWNDcalls();
 145 
 146         // is this a JVM we can use?
 147         // install JDK 1.2 and later Swing ToolKit listener
 148         EventQueueMonitor.isGUIInitialized();
 149 
 150         // start the Java event handler
 151         eventHandler = new EventHandler(this);
 152 
 153         // register for menu selection events
 154         MenuSelectionManager.defaultManager().addChangeListener(eventHandler);
 155 
 156         // register as a NativeWindowHandler
 157         addNativeWindowHandler(new DefaultNativeWindowHandler());
 158 
 159         // start in a new thread
 160         Thread abthread = new Thread(new dllRunner());
 161         abthread.setDaemon(true);
 162         abthread.start();
 163         debugString("[INFO]:AccessBridge started");
 164     }
 165 
 166     /*
 167      * adaptor to run the AccessBridge DLL
 168      */
 169     private class dllRunner implements Runnable {
 170         public void run() {
 171             runDLL();
 172         }
 173     }
 174 
 175     /*
 176      * shutdown hook
 177      */
 178     private class shutdownHook implements Runnable {
 179 
 180         public void run() {
 181             debugString("[INFO]:***** shutdownHook: shutting down...");
 182             javaShutdown();
 183         }
 184     }
 185 
 186 
 187     /*
 188      * Initialize the hashtable that maps Strings to AccessibleRoles.
 189      */
 190     private void initAccessibleRoleMap() {
 191         /*
 192          * Initialize the AccessibleRoles map. This code uses methods in
 193          * java.lang.reflect.* to build the map.
 194          */
 195         try {
 196             Class<?> clAccessibleRole = Class.forName ("javax.accessibility.AccessibleRole");
 197             if (null != clAccessibleRole) {
 198                 AccessibleRole roleUnknown = AccessibleRole.UNKNOWN;
 199                 Field [] fields = clAccessibleRole.getFields ();
 200                 int i = 0;
 201                 for (i = 0; i < fields.length; i ++) {


 280     private Method javaGetComponentFromNativeWindowHandleMethod;
 281     private Method javaGetNativeWindowHandleFromComponentMethod;
 282 
 283     // native jawt methods for mapping HWNDs to Java components
 284     private native int jawtGetNativeWindowHandleFromComponent(Component comp);
 285 
 286     private native Component jawtGetComponentFromNativeWindowHandle(int handle);
 287 
 288     Toolkit toolkit;
 289 
 290     /**
 291      * map an HWND to an AWT Component
 292      */
 293     private void initHWNDcalls() {
 294         Class<?>[] integerParemter = new Class<?>[1];
 295         integerParemter[0] = Integer.TYPE;
 296         Class<?>[] componentParemter = new Class<?>[1];
 297         try {
 298             componentParemter[0] = Class.forName("java.awt.Component");
 299         } catch (ClassNotFoundException e) {
 300             debugString("[ERROR]:Exception: " + e.toString());
 301         }
 302         toolkit = Toolkit.getDefaultToolkit();
 303         return;
 304     }
 305 
 306     // native window handler interface
 307     private interface NativeWindowHandler {
 308         public Accessible getAccessibleFromNativeWindowHandle(int nativeHandle);
 309     }
 310 
 311     // hash table of native window handle to AccessibleContext mappings
 312     static private ConcurrentHashMap<Integer,AccessibleContext> windowHandleToContextMap = new ConcurrentHashMap<>();
 313 
 314     // hash table of AccessibleContext to native window handle mappings
 315     static private ConcurrentHashMap<AccessibleContext,Integer> contextToWindowHandleMap = new ConcurrentHashMap<>();
 316 
 317     /*
 318      * adds a virtual window handler to our hash tables
 319      */
 320     static private void registerVirtualFrame(final Accessible a,


 369         return nativeWindowHandlers.removeElement(handler);
 370     }
 371 
 372     /**
 373      * verifies that a native window handle is a Java window
 374      */
 375     private boolean isJavaWindow(int nativeHandle) {
 376         AccessibleContext ac = getContextFromNativeWindowHandle(nativeHandle);
 377         if (ac != null) {
 378             saveContextToWindowHandleMapping(ac, nativeHandle);
 379             return true;
 380         }
 381         return false;
 382     }
 383 
 384     /*
 385      * saves the mapping between an AccessibleContext and a window handle
 386      */
 387     private void saveContextToWindowHandleMapping(AccessibleContext ac,
 388                                                   int nativeHandle) {
 389         debugString("[INFO]:saveContextToWindowHandleMapping...");
 390         if (ac == null) {
 391             return;
 392         }
 393         if (! contextToWindowHandleMap.containsKey(ac)) {
 394             debugString("[INFO]: saveContextToWindowHandleMapping: ac = "+ac+"; handle = "+nativeHandle);
 395             contextToWindowHandleMap.put(ac, nativeHandle);
 396         }
 397     }
 398 
 399     /**
 400      * maps a native window handle to an Accessible Context
 401      */
 402     private AccessibleContext getContextFromNativeWindowHandle(int nativeHandle) {
 403         // First, look for the Accessible in our hash table of
 404         // virtual window handles.
 405         AccessibleContext ac = windowHandleToContextMap.get(nativeHandle);
 406         if(ac!=null) {
 407             saveContextToWindowHandleMapping(ac, nativeHandle);
 408             return ac;
 409         }
 410 
 411         // Next, look for the native window handle in our vector
 412         // of native window handles.
 413         int numHandlers = nativeWindowHandlers.size();
 414         for (int i = 0; i < numHandlers; i++) {


 417             if (a != null) {
 418                 ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
 419                     @Override
 420                     public AccessibleContext call() throws Exception {
 421                         return a.getAccessibleContext();
 422                     }
 423                 }, a);
 424                 saveContextToWindowHandleMapping(ac, nativeHandle);
 425                 return ac;
 426             }
 427         }
 428         // Not found.
 429         return null;
 430     }
 431 
 432     /**
 433      * maps an AccessibleContext to a native window handle
 434      *     returns 0 on error
 435      */
 436     private int getNativeWindowHandleFromContext(AccessibleContext ac) {
 437     debugString("[INFO]: getNativeWindowHandleFromContext: ac = "+ac);
 438         try {
 439             return contextToWindowHandleMap.get(ac);
 440         } catch (Exception ex) {
 441             return 0;
 442         }
 443     }
 444 
 445     private class DefaultNativeWindowHandler implements NativeWindowHandler {
 446         /*
 447         * returns the Accessible associated with a native window
 448         */
 449         public Accessible getAccessibleFromNativeWindowHandle(int nativeHandle) {
 450             final Component c = jawtGetComponentFromNativeWindowHandle(nativeHandle);
 451             if (c instanceof Accessible) {
 452                 AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
 453                     @Override
 454                     public AccessibleContext call() throws Exception {
 455                         return c.getAccessibleContext();
 456                     }
 457                 }, c);


 498             public AccessibleContext call() throws Exception {
 499                 Accessible parent = ac.getAccessibleParent();
 500                 if (parent == null) {
 501                     return ac;
 502                 }
 503                 Accessible tmp = parent.getAccessibleContext().getAccessibleParent();
 504                 while (tmp != null) {
 505                     parent = tmp;
 506                     tmp = parent.getAccessibleContext().getAccessibleParent();
 507                 }
 508                 return parent.getAccessibleContext();
 509             }
 510         }, ac);
 511     }
 512 
 513     /*
 514      * StarOffice version that does not use the EventQueueMonitor
 515      */
 516     private AccessibleContext getAccessibleContextAt_1(final int x, final int y,
 517                                                       final AccessibleContext parent) {
 518         debugString("[INFO]: getAccessibleContextAt_1 called");
 519         debugString("   -> x = " + x + " y = " + y + " parent = " + parent);
 520 
 521         if (parent == null) return null;
 522             final AccessibleComponent acmp = InvocationUtils.invokeAndWait(new Callable<AccessibleComponent>() {
 523                 @Override
 524                 public AccessibleComponent call() throws Exception {
 525                     return parent.getAccessibleComponent();
 526                 }
 527             }, parent);
 528         if (acmp!=null) {
 529             final Point loc = InvocationUtils.invokeAndWait(new Callable<Point>() {
 530                 @Override
 531                 public Point call() throws Exception {
 532                     return acmp.getLocation();
 533                 }
 534             }, parent);
 535             final Accessible a = InvocationUtils.invokeAndWait(new Callable<Accessible>() {
 536                 @Override
 537                 public Accessible call() throws Exception {
 538                     return acmp.getAccessibleAt(new Point(x - loc.x, y - loc.y));


 546                     }
 547                 }, parent);
 548                 if (foundAC != null) {
 549                     if (foundAC != parent) {
 550                         // recurse down into the child
 551                         return getAccessibleContextAt_1(x - loc.x, y - loc.y,
 552                                                         foundAC);
 553                     } else
 554                         return foundAC;
 555                 }
 556             }
 557         }
 558         return parent;
 559     }
 560 
 561     /*
 562      * AWT/Swing version
 563      */
 564     private AccessibleContext getAccessibleContextAt_2(final int x, final int y,
 565                                                       AccessibleContext parent) {
 566         debugString("[INFO]: getAccessibleContextAt_2 called");
 567         debugString("   -> x = " + x + " y = " + y + " parent = " + parent);
 568 
 569         return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
 570             @Override
 571             public AccessibleContext call() throws Exception {
 572                 Accessible a = EventQueueMonitor.getAccessibleAt(new Point(x, y));
 573                 if (a != null) {
 574                     AccessibleContext childAC = a.getAccessibleContext();
 575                     if (childAC != null) {
 576                         debugString("[INFO]:   returning childAC = " + childAC);
 577                         return childAC;
 578                     }
 579                 }
 580                 return null;
 581             }
 582         }, parent);
 583     }
 584 
 585     /**
 586      * returns the Accessible that has focus
 587      */
 588     private AccessibleContext getAccessibleContextWithFocus() {
 589         Component c = AWTEventMonitor.getComponentWithFocus();
 590         if (c != null) {
 591             final Accessible a = Translator.getAccessible(c);
 592             if (a != null) {
 593                 AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
 594                     @Override
 595                     public AccessibleContext call() throws Exception {
 596                         return a.getAccessibleContext();
 597                     }
 598                 }, c);
 599                 if (ac != null) {
 600                     return ac;
 601                 }
 602             }
 603         }
 604         return null;
 605     }
 606 
 607     /**
 608      * returns the AccessibleName from an AccessibleContext
 609      */
 610     private String getAccessibleNameFromContext(final AccessibleContext ac) {
 611         debugString("[INFO]: ***** ac = "+ac.getClass());
 612         if (ac != null) {
 613             String s = InvocationUtils.invokeAndWait(new Callable<String>() {
 614                 @Override
 615                 public String call() throws Exception {
 616                     return ac.getAccessibleName();
 617                 }
 618             }, ac);
 619             if (s != null) {
 620                 references.increment(s);
 621                 debugString("[INFO]: Returning AccessibleName from Context: " + s);
 622                 return s;
 623             } else {
 624                 return null;
 625             }
 626         } else {
 627             debugString("[INFO]: getAccessibleNameFromContext; ac = null!");
 628             return null;
 629         }
 630     }
 631 
 632     /**
 633      * Returns an AccessibleName for a component using an algorithm optimized
 634      * for the JAWS screen reader.  This method is only intended for JAWS. All
 635      * other uses are entirely optional.
 636      */
 637     private String getVirtualAccessibleNameFromContext(final AccessibleContext ac) {
 638         if (null != ac) {
 639             /*
 640             Step 1:
 641             =======
 642             Determine if we can obtain the Virtual Accessible Name from the
 643             Accessible Name or Accessible Description of the object.
 644             */
 645             String nameString = InvocationUtils.invokeAndWait(new Callable<String>() {
 646                 @Override
 647                 public String call() throws Exception {
 648                     return ac.getAccessibleName();
 649                 }
 650             }, ac);
 651             if ( ( null != nameString ) && ( 0 != nameString.length () ) ) {
 652                 debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from AccessibleContext::getAccessibleName.");
 653                 references.increment (nameString);
 654                 return nameString;
 655             }
 656             String descriptionString = InvocationUtils.invokeAndWait(new Callable<String>() {
 657                 @Override
 658                 public String call() throws Exception {
 659                     return ac.getAccessibleDescription();
 660                 }
 661             }, ac);
 662             if ( ( null != descriptionString ) && ( 0 != descriptionString.length () ) ) {
 663                 debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from AccessibleContext::getAccessibleDescription.");
 664                 references.increment (descriptionString);
 665                 return descriptionString;
 666             }
 667 
 668             debugString ("[WARN]: The Virtual Accessible Name was not found using AccessibleContext::getAccessibleDescription. or getAccessibleName");
 669             /*
 670             Step 2:
 671             =======
 672             Decide whether the extended name search algorithm should be
 673             used for this object.
 674             */
 675             boolean bExtendedSearch = false;
 676             AccessibleRole role = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {
 677                 @Override
 678                 public AccessibleRole call() throws Exception {
 679                     return ac.getAccessibleRole();
 680                 }
 681             }, ac);
 682             AccessibleContext parentContext = null;
 683             AccessibleRole parentRole = AccessibleRole.UNKNOWN;
 684 
 685             if ( extendedVirtualNameSearchRoles.contains (role) ) {
 686                 parentContext = getAccessibleParentFromContext (ac);
 687                 if ( null != parentContext ) {
 688                     final AccessibleContext parentContextInnerTemp = parentContext;
 689                     parentRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {
 690                         @Override
 691                         public AccessibleRole call() throws Exception {
 692                             return parentContextInnerTemp.getAccessibleRole();
 693                         }
 694                     }, ac);
 695                     if ( AccessibleRole.UNKNOWN != parentRole ) {
 696                         bExtendedSearch = true;
 697                         if ( noExtendedVirtualNameSearchParentRoles.contains (parentRole) ) {
 698                             bExtendedSearch = false;
 699                         }
 700                     }
 701                 }
 702             }
 703 
 704             if (false == bExtendedSearch) {
 705                 debugString ("[INFO]: bk -- getVirtualAccessibleNameFromContext will not use the extended name search algorithm.  role = " + ( role != null ? role.toDisplayString(Locale.US) : "null") );
 706                 /*
 707                 Step 3:
 708                 =======
 709                 We have determined that we should not use the extended name
 710                 search algorithm for this object (we must obtain the name of
 711                 the object from the object itself and not from neighboring
 712                 objects).  However the object name cannot be obtained from
 713                 the Accessible Name or Accessible Description of the object.
 714 
 715                 Handle several special cases here that might yield a value for
 716                 the Virtual Accessible Name.  Return null if the object does
 717                 not match the criteria for any of these special cases.
 718                 */
 719                 if (AccessibleRole.LABEL == role) {
 720                     /*
 721                     Does the label support the Accessible Text Interface?
 722                     */
 723                     final AccessibleText at = InvocationUtils.invokeAndWait(new Callable<AccessibleText>() {
 724                         @Override
 725                         public AccessibleText call() throws Exception {
 726                             return ac.getAccessibleText();
 727                         }
 728                     }, ac);
 729                     if (null != at) {
 730                         int charCount = InvocationUtils.invokeAndWait(new Callable<Integer>() {
 731                             @Override
 732                             public Integer call() throws Exception {
 733                                 return at.getCharCount();
 734                             }
 735                         }, ac);
 736                         String text = getAccessibleTextRangeFromContext (ac, 0, charCount);
 737                         if (null != text) {
 738                             debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from the Accessible Text of the LABEL object.");
 739                             references.increment (text);
 740                             return text;
 741                         }
 742                     }
 743                     /*
 744                     Does the label support the Accessible Icon Interface?
 745                     */
 746                     debugString ("[INFO]: bk -- Attempting to obtain the Virtual Accessible Name from the Accessible Icon information.");
 747                     final AccessibleIcon [] ai = InvocationUtils.invokeAndWait(new Callable<AccessibleIcon[]>() {
 748                         @Override
 749                         public AccessibleIcon[] call() throws Exception {
 750                             return ac.getAccessibleIcon();
 751                         }
 752                     }, ac);
 753                     if ( (null != ai) && (ai.length > 0) ) {
 754                         String iconDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
 755                             @Override
 756                             public String call() throws Exception {
 757                                 return ai[0].getAccessibleIconDescription();
 758                             }
 759                         }, ac);
 760                         if (iconDescription != null){
 761                             debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from the description of the first Accessible Icon found in the LABEL object.");
 762                             references.increment (iconDescription);
 763                             return iconDescription;
 764                         }
 765                     } else {
 766                         parentContext = getAccessibleParentFromContext (ac);
 767                         if ( null != parentContext ) {
 768                             final AccessibleContext parentContextInnerTemp = parentContext;
 769                             parentRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {
 770                                 @Override
 771                                 public AccessibleRole call() throws Exception {
 772                                     return parentContextInnerTemp.getAccessibleRole();
 773                                 }
 774                             }, ac);
 775                             if ( AccessibleRole.TABLE == parentRole ) {
 776                                 int indexInParent = InvocationUtils.invokeAndWait(new Callable<Integer>() {
 777                                     @Override
 778                                     public Integer call() throws Exception {
 779                                         return ac.getAccessibleIndexInParent();
 780                                     }
 781                                 }, ac);
 782                                 final AccessibleContext acTableCell = getAccessibleChildFromContext (parentContext, indexInParent);
 783                                 debugString ("[INFO]: bk -- Making a second attempt to obtain the Virtual Accessible Name from the Accessible Icon information for the Table Cell.");
 784                                 if (acTableCell != null) {
 785                                     final AccessibleIcon [] aiRet =InvocationUtils.invokeAndWait(new Callable<AccessibleIcon[]>() {
 786                                         @Override
 787                                         public AccessibleIcon[] call() throws Exception {
 788                                             return acTableCell.getAccessibleIcon();
 789                                         }
 790                                     }, ac);
 791                                     if ( (null != aiRet) && (aiRet.length > 0) ) {
 792                                         String iconDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
 793                                             @Override
 794                                             public String call() throws Exception {
 795                                                 return aiRet[0].getAccessibleIconDescription();
 796                                             }
 797                                         }, ac);
 798                                         if (iconDescription != null){
 799                                             debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from the description of the first Accessible Icon found in the Table Cell object.");
 800                                             references.increment (iconDescription);
 801                                             return iconDescription;
 802                                         }
 803                                     }
 804                                 }
 805                             }
 806                         }
 807                     }
 808                 } else if ( (AccessibleRole.TOGGLE_BUTTON == role) ||
 809                             (AccessibleRole.PUSH_BUTTON == role) ) {
 810                     /*
 811                     Does the button support the Accessible Icon Interface?
 812                     */
 813                     debugString ("[INFO]: bk -- Attempting to obtain the Virtual Accessible Name from the Accessible Icon information.");
 814                     final AccessibleIcon [] ai = InvocationUtils.invokeAndWait(new Callable<AccessibleIcon[]>() {
 815                         @Override
 816                         public AccessibleIcon[] call() throws Exception {
 817                             return ac.getAccessibleIcon();
 818                         }
 819                     }, ac);
 820                     if ( (null != ai) && (ai.length > 0) ) {
 821                         String iconDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
 822                             @Override
 823                             public String call() throws Exception {
 824                                 return ai[0].getAccessibleIconDescription();
 825                             }
 826                         }, ac);
 827                         if (iconDescription != null){
 828                             debugString ("[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.");
 829                             references.increment (iconDescription);
 830                             return iconDescription;
 831                         }
 832                     }
 833                 } else if ( AccessibleRole.CHECK_BOX == role ) {
 834                     /*
 835                     NOTE: The only case I know of in which a check box does not
 836                     have a name is when that check box is contained in a table.
 837 
 838                     In this case it would be appropriate to use the display string
 839                     of the check box object as the name (in US English the display
 840                     string is typically either "true" or "false").
 841 
 842                     I am using the AccessibleValue interface to obtain the display
 843                     string of the check box.  If the Accessible Value is 1, I am
 844                     returning Boolean.TRUE.toString (),  If the Accessible Value is
 845                     0, I am returning Boolean.FALSE.toString ().  If the Accessible
 846                     Value is some other number, I will return the display string of
 847                     the current numerical value of the check box.
 848                     */


 888                 @Override
 889                 public String call() throws Exception {
 890                     return parentContextOuterTemp.getAccessibleName();
 891                 }
 892             }, ac);
 893             String parentDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
 894                 @Override
 895                 public String call() throws Exception {
 896                     return parentContextOuterTemp.getAccessibleDescription();
 897                 }
 898             }, ac);
 899 
 900             /*
 901             Step 4:
 902             =======
 903             Special case for Slider Bar objects.
 904             */
 905             if ( (AccessibleRole.SLIDER == role) &&
 906                  (AccessibleRole.PANEL == parentRole) &&
 907                  (null != parentName) ) {
 908                 debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from the Accessible Name of the SLIDER object's parent object.");
 909                 references.increment (parentName);
 910                 return parentName;
 911             }
 912 
 913             boolean bIsEditCombo = false;
 914 
 915             AccessibleContext testContext = ac;
 916             /*
 917             Step 5:
 918             =======
 919             Special case for Edit Combo Boxes
 920             */
 921             if ( (AccessibleRole.TEXT == role) &&
 922                  (AccessibleRole.COMBO_BOX == parentRole) ) {
 923                 bIsEditCombo = true;
 924                 if (null != parentName) {
 925                     debugString ("[INFO]: bk -- The Virtual Accessible Name for this Edit Combo box was obtained from the Accessible Name of the object's parent object.");
 926                     references.increment (parentName);
 927                     return parentName;
 928                 } else if (null != parentDescription) {
 929                     debugString ("[INFO]: bk -- The Virtual Accessible Name for this Edit Combo box was obtained from the Accessible Description of the object's parent object.");
 930                     references.increment (parentDescription);
 931                     return parentDescription;
 932                 }
 933                 testContext = parentContext;
 934                 parentRole = AccessibleRole.UNKNOWN;
 935                 parentContext = getAccessibleParentFromContext (testContext);
 936                 if ( null != parentContext ) {
 937                     final AccessibleContext parentContextInnerTemp = parentContext;
 938                     parentRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {
 939                         @Override
 940                         public AccessibleRole call() throws Exception {
 941                             return parentContextInnerTemp.getAccessibleRole();
 942                         }
 943                     }, ac);
 944                 }
 945             }
 946 
 947             /*
 948             Step 6:
 949             =======


 952             */
 953             {
 954                 final AccessibleContext parentContextTempInner = parentContext;
 955                 AccessibleRelationSet ars = InvocationUtils.invokeAndWait(new Callable<AccessibleRelationSet>() {
 956                     @Override
 957                     public AccessibleRelationSet call() throws Exception {
 958                         return parentContextTempInner.getAccessibleRelationSet();
 959                     }
 960                 }, ac);
 961                 if ( ars != null && (ars.size () > 0) && (ars.contains (AccessibleRelation.LABELED_BY)) ) {
 962                     AccessibleRelation labeledByRelation = ars.get (AccessibleRelation.LABELED_BY);
 963                     if (labeledByRelation != null) {
 964                         Object [] targets = labeledByRelation.getTarget ();
 965                         Object o = targets [0];
 966                         if (o instanceof Accessible) {
 967                             AccessibleContext labelContext = ((Accessible)o).getAccessibleContext ();
 968                             if (labelContext != null) {
 969                                 String labelName = labelContext.getAccessibleName ();
 970                                 String labelDescription = labelContext.getAccessibleDescription ();
 971                                 if (null != labelName) {
 972                                     debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained using the LABELED_BY AccessibleRelation -- Name Case.");
 973                                     references.increment (labelName);
 974                                     return labelName;
 975                                 } else if (null != labelDescription) {
 976                                     debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained using the LABELED_BY AccessibleRelation -- Description Case.");
 977                                     references.increment (labelDescription);
 978                                     return labelDescription;
 979                                 }
 980                             }
 981                         }
 982                     }
 983                 }
 984             }
 985 
 986             //Note: add AccessibleContext to use InvocationUtils.invokeAndWait
 987             /*
 988             Step 7:
 989             =======
 990             Search for a label object that is positioned either just to the left
 991             or just above the object and get the Accessible Name of the Label
 992             object.
 993             */
 994             int testIndexMax = 0;
 995             int testX = 0;
 996             int testY = 0;


1051                         AccessibleRole childRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {
1052                             @Override
1053                             public AccessibleRole call() throws Exception {
1054                                 return childContext.getAccessibleRole();
1055                             }
1056                         }, ac);
1057                         if ( AccessibleRole.LABEL == childRole ) {
1058                             childX = getAccessibleXcoordFromContext (childContext);
1059                             childY = getAccessibleYcoordFromContext (childContext);
1060                             childWidth = getAccessibleWidthFromContext (childContext);
1061                             childHeight = getAccessibleHeightFromContext (childContext);
1062                             if ( (childX < testX) &&
1063                                  ((childY <= targetY) && (targetY <= (childY + childHeight))) ) {
1064                                 childName = InvocationUtils.invokeAndWait(new Callable<String>() {
1065                                     @Override
1066                                     public String call() throws Exception {
1067                                         return childContext.getAccessibleName();
1068                                     }
1069                                 }, ac);
1070                                 if ( null != childName ) {
1071                                     debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from Accessible Name of a LABEL object positioned to the left of the object.");
1072                                     references.increment (childName);
1073                                     return childName;
1074                                 }
1075                                 childDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
1076                                     @Override
1077                                     public String call() throws Exception {
1078                                         return childContext.getAccessibleDescription();
1079                                     }
1080                                 }, ac);
1081                                 if ( null != childDescription ) {
1082                                     debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from Accessible Description of a LABEL object positioned to the left of the object.");
1083                                     references.increment (childDescription);
1084                                     return childDescription;
1085                                 }
1086                             } else if ( (childY < targetY) &&
1087                                         ((childX <= targetX) && (targetX <= (childX + childWidth))) ) {
1088                                 childName = InvocationUtils.invokeAndWait(new Callable<String>() {
1089                                     @Override
1090                                     public String call() throws Exception {
1091                                         return childContext.getAccessibleName();
1092                                     }
1093                                 }, ac);
1094                                 if ( null != childName ) {
1095                                     debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from Accessible Name of a LABEL object positioned above the object.");
1096                                     references.increment (childName);
1097                                     return childName;
1098                                 }
1099                                 childDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
1100                                     @Override
1101                                     public String call() throws Exception {
1102                                         return childContext.getAccessibleDescription();
1103                                     }
1104                                 }, ac);
1105                                 if ( null != childDescription ) {
1106                                     debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from Accessible Description of a LABEL object positioned above the object.");
1107                                     references.increment (childDescription);
1108                                     return childDescription;
1109                                 }
1110                             }
1111                         }
1112                     }
1113                 }
1114                 childIndex --;
1115             }
1116             childIndex = testIndex + 1;
1117             while (childIndex <= testIndexMax) {
1118                 final int childIndexTemp = childIndex;
1119                 final AccessibleContext parentContextInnerTemp = parentContext;
1120                 final Accessible child  =  InvocationUtils.invokeAndWait(new Callable<Accessible>() {
1121                     @Override
1122                     public Accessible call() throws Exception {
1123                         return parentContextInnerTemp.getAccessibleChild(childIndexTemp);
1124                     }
1125                 }, ac);
1126                 if ( null != child ) {


1134                         AccessibleRole childRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {
1135                             @Override
1136                             public AccessibleRole call() throws Exception {
1137                                 return childContext.getAccessibleRole();
1138                             }
1139                         }, ac);
1140                         if ( AccessibleRole.LABEL == childRole ) {
1141                             childX = getAccessibleXcoordFromContext (childContext);
1142                             childY = getAccessibleYcoordFromContext (childContext);
1143                             childWidth = getAccessibleWidthFromContext (childContext);
1144                             childHeight = getAccessibleHeightFromContext (childContext);
1145                             if ( (childX < testX) &&
1146                                  ((childY <= targetY) && (targetY <= (childY + childHeight))) ) {
1147                                 childName = InvocationUtils.invokeAndWait(new Callable<String>() {
1148                                     @Override
1149                                     public String call() throws Exception {
1150                                         return childContext.getAccessibleName();
1151                                     }
1152                                 }, ac);
1153                                 if ( null != childName ) {
1154                                     debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from Accessible Name of a LABEL object positioned to the left of the object.");
1155                                     references.increment (childName);
1156                                     return childName;
1157                                 }
1158                                 childDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
1159                                     @Override
1160                                     public String call() throws Exception {
1161                                         return childContext.getAccessibleDescription();
1162                                     }
1163                                 }, ac);
1164                                 if ( null != childDescription ) {
1165                                     debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from Accessible Description of a LABEL object positioned to the left of the object.");
1166                                     references.increment (childDescription);
1167                                     return childDescription;
1168                                 }
1169                             } else if ( (childY < targetY) &&
1170                                         ((childX <= targetX) && (targetX <= (childX + childWidth))) ) {
1171                                 childName = InvocationUtils.invokeAndWait(new Callable<String>() {
1172                                     @Override
1173                                     public String call() throws Exception {
1174                                         return childContext.getAccessibleName();
1175                                     }
1176                                 }, ac);
1177                                 if ( null != childName ) {
1178                                     debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from Accessible Name of a LABEL object positioned above the object.");
1179                                     references.increment (childName);
1180                                     return childName;
1181                                 }
1182                                 childDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
1183                                     @Override
1184                                     public String call() throws Exception {
1185                                         return childContext.getAccessibleDescription();
1186                                     }
1187                                 }, ac);
1188                                 if ( null != childDescription ) {
1189                                     debugString ("[INFO]: bk -- The Virtual Accessible Name was obtained from Accessible Description of a LABEL object positioned above the object.");
1190                                     references.increment (childDescription);
1191                                     return childDescription;
1192                                 }
1193                             }
1194                         }
1195                     }
1196                 }
1197                 childIndex ++;
1198             }
1199             /*
1200             Step 8:
1201             =======
1202             Special case for combo boxes and text objects, based on a
1203             similar special case I found in some of our internal JAWS code.
1204 
1205             Search for a button object that is positioned either just to the left
1206             or just above the object and get the Accessible Name of the button
1207             object.
1208             */
1209             if ( (AccessibleRole.TEXT == role) ||


1231                                 @Override
1232                                 public AccessibleRole call() throws Exception {
1233                                     return childContext.getAccessibleRole();
1234                                 }
1235                             }, ac);
1236                             if ( ( AccessibleRole.PUSH_BUTTON == childRole ) ||
1237                                  ( AccessibleRole.TOGGLE_BUTTON == childRole )) {
1238                                 childX = getAccessibleXcoordFromContext (childContext);
1239                                 childY = getAccessibleYcoordFromContext (childContext);
1240                                 childWidth = getAccessibleWidthFromContext (childContext);
1241                                 childHeight = getAccessibleHeightFromContext (childContext);
1242                                 if ( (childX < testX) &&
1243                                      ((childY <= targetY) && (targetY <= (childY + childHeight))) ) {
1244                                     childName = InvocationUtils.invokeAndWait(new Callable<String>() {
1245                                         @Override
1246                                         public String call() throws Exception {
1247                                             return childContext.getAccessibleName();
1248                                         }
1249                                     }, ac);
1250                                     if ( null != childName ) {
1251                                         debugString ("[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.");
1252                                         references.increment (childName);
1253                                         return childName;
1254                                     }
1255                                     childDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
1256                                         @Override
1257                                         public String call() throws Exception {
1258                                             return childContext.getAccessibleDescription();
1259                                         }
1260                                     }, ac);
1261                                     if ( null != childDescription ) {
1262                                         debugString ("[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.");
1263                                         references.increment (childDescription);
1264                                         return childDescription;
1265                                     }
1266                                 }
1267                             }
1268                         }
1269                     }
1270                     childIndex --;
1271                 }
1272                 childIndex = testIndex + 1;
1273                 while (childIndex <= testIndexMax) {
1274                     final int childIndexTemp = childIndex;
1275                     final AccessibleContext parentContextInnerTemp = parentContext;
1276                     final Accessible child  =  InvocationUtils.invokeAndWait(new Callable<Accessible>() {
1277                         @Override
1278                         public Accessible call() throws Exception {
1279                             return parentContextInnerTemp.getAccessibleChild(childIndexTemp);
1280                         }
1281                     }, ac);
1282                     if ( null != child ) {


1291                                 @Override
1292                                 public AccessibleRole call() throws Exception {
1293                                     return childContext.getAccessibleRole();
1294                                 }
1295                             }, ac);
1296                             if ( ( AccessibleRole.PUSH_BUTTON == childRole ) ||
1297                                     ( AccessibleRole.TOGGLE_BUTTON == childRole ) ) {
1298                                 childX = getAccessibleXcoordFromContext (childContext);
1299                                 childY = getAccessibleYcoordFromContext (childContext);
1300                                 childWidth = getAccessibleWidthFromContext (childContext);
1301                                 childHeight = getAccessibleHeightFromContext (childContext);
1302                                 if ( (childX < testX) &&
1303                                      ((childY <= targetY) && (targetY <= (childY + childHeight))) ) {
1304                                     childName = InvocationUtils.invokeAndWait(new Callable<String>() {
1305                                         @Override
1306                                         public String call() throws Exception {
1307                                             return childContext.getAccessibleName();
1308                                         }
1309                                     }, ac);
1310                                     if ( null != childName ) {
1311                                         debugString ("[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.");
1312                                         references.increment (childName);
1313                                         return childName;
1314                                     }
1315                                     childDescription = InvocationUtils.invokeAndWait(new Callable<String>() {
1316                                         @Override
1317                                         public String call() throws Exception {
1318                                             return childContext.getAccessibleDescription();
1319                                         }
1320                                     }, ac);
1321                                     if ( null != childDescription ) {
1322                                         debugString ("[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.");
1323                                         references.increment (childDescription);
1324                                         return childDescription;
1325                                     }
1326                                 }
1327                             }
1328                         }
1329                     }
1330                     childIndex ++;
1331                 }
1332             }
1333             return null;
1334         } else {
1335             debugString ("[ERROR]: AccessBridge::getVirtualAccessibleNameFromContext error - ac == null.");
1336             return null;
1337         }
1338     }
1339 
1340     /**
1341      * returns the AccessibleDescription from an AccessibleContext
1342      */
1343     private String getAccessibleDescriptionFromContext(final AccessibleContext ac) {
1344         if (ac != null) {
1345             String s = InvocationUtils.invokeAndWait(new Callable<String>() {
1346                 @Override
1347                 public String call() throws Exception {
1348                     return ac.getAccessibleDescription();
1349                 }
1350             }, ac);
1351             if (s != null) {
1352                 references.increment(s);
1353                 debugString("[INFO]: Returning AccessibleDescription from Context: " + s);
1354                 return s;
1355             }
1356         } else {
1357             debugString("[ERROR]: getAccessibleDescriptionFromContext; ac = null");
1358         }
1359         return null;
1360     }
1361 
1362     /**
1363      * returns the AccessibleRole from an AccessibleContext
1364      */
1365     private String getAccessibleRoleStringFromContext(final AccessibleContext ac) {
1366         if (ac != null) {
1367             AccessibleRole role = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() {
1368                 @Override
1369                 public AccessibleRole call() throws Exception {
1370                     return ac.getAccessibleRole();
1371                 }
1372             }, ac);
1373             if (role != null) {
1374                 String s = role.toDisplayString(Locale.US);
1375                 if (s != null) {
1376                     references.increment(s);
1377                     debugString("[INFO]: Returning AccessibleRole from Context: " + s);
1378                     return s;
1379                 }
1380             }
1381         } else {
1382             debugString("[ERROR]: getAccessibleRoleStringFromContext; ac = null");
1383         }
1384         return null;
1385     }
1386 
1387     /**
1388      * return the AccessibleRole from an AccessibleContext in the en_US locale
1389      */
1390     private String getAccessibleRoleStringFromContext_en_US(final AccessibleContext ac) {
1391         return getAccessibleRoleStringFromContext(ac);
1392     }
1393 
1394     /**
1395      * return the AccessibleStates from an AccessibleContext
1396      */
1397     private String getAccessibleStatesStringFromContext(final AccessibleContext ac) {
1398         if (ac != null) {
1399             AccessibleStateSet stateSet = InvocationUtils.invokeAndWait(new Callable<AccessibleStateSet>() {
1400                 @Override
1401                 public AccessibleStateSet call() throws Exception {
1402                     return ac.getAccessibleStateSet();
1403                 }
1404             }, ac);
1405             if (stateSet != null) {
1406                 String s = stateSet.toString();
1407                 if (s != null &&
1408                     s.indexOf(AccessibleState.MANAGES_DESCENDANTS.toDisplayString(Locale.US)) == -1) {
1409                     // Indicate whether this component manages its own
1410                     // children
1411                     AccessibleRole role = InvocationUtils.invokeAndWait(() -> {
1412                             return ac.getAccessibleRole();
1413                         }, ac);
1414                     if (role == AccessibleRole.LIST ||
1415                         role == AccessibleRole.TABLE ||
1416                         role == AccessibleRole.TREE) {
1417                         s += ",";
1418                         s += AccessibleState.MANAGES_DESCENDANTS.toDisplayString(Locale.US);
1419                     }
1420                     references.increment(s);
1421                     debugString("[INFO]: Returning AccessibleStateSet from Context: " + s);
1422                     return s;
1423                 }
1424             }
1425         } else {
1426             debugString("[ERROR]: getAccessibleStatesStringFromContext; ac = null");
1427         }
1428         return null;
1429     }
1430 
1431     /**
1432      * returns the AccessibleStates from an AccessibleContext in the en_US locale
1433      */
1434     private String getAccessibleStatesStringFromContext_en_US(final AccessibleContext ac) {
1435         if (ac != null) {
1436             AccessibleStateSet stateSet = InvocationUtils.invokeAndWait(new Callable<AccessibleStateSet>() {
1437                 @Override
1438                 public AccessibleStateSet call() throws Exception {
1439                     return ac.getAccessibleStateSet();
1440                 }
1441             }, ac);
1442             if (stateSet != null) {
1443                 String s = "";
1444                 AccessibleState[] states = stateSet.toArray();
1445                 if (states != null && states.length > 0) {
1446                     s = states[0].toDisplayString(Locale.US);
1447                     for (int i = 1; i < states.length; i++) {
1448                         s = s + "," + states[i].toDisplayString(Locale.US);
1449                     }
1450                 }
1451                 references.increment(s);
1452                 debugString("[INFO]: Returning AccessibleStateSet en_US from Context: " + s);
1453                 return s;
1454             }
1455         }
1456         debugString("[ERROR]: getAccessibleStatesStringFromContext; ac = null");
1457         return null;
1458     }
1459 
1460     /**
1461      * returns the AccessibleParent from an AccessibleContext
1462      */
1463     private AccessibleContext getAccessibleParentFromContext(final AccessibleContext ac) {
1464         if (ac==null)
1465             return null;
1466         return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
1467             @Override
1468             public AccessibleContext call() throws Exception {
1469                 Accessible a = ac.getAccessibleParent();
1470                 if (a != null) {
1471                     AccessibleContext apc = a.getAccessibleContext();
1472                     if (apc != null) {
1473                         return apc;
1474                     }
1475                 }
1476                 return null;


1590                                 r.y = p.y;
1591                                 return r;
1592                             }
1593                         } catch (Exception e) {
1594                             return null;
1595                         }
1596                     }
1597                 }
1598                 return null;
1599             }
1600         }, ac);
1601     }
1602 
1603     /**
1604      * returns the AccessibleComponent x-coord from an AccessibleContext
1605      */
1606     private int getAccessibleXcoordFromContext(AccessibleContext ac) {
1607         if (ac != null) {
1608             Rectangle r = getAccessibleBoundsOnScreenFromContext(ac);
1609             if (r != null) {
1610                 debugString("[INFO]: Returning Accessible x coord from Context: " + r.x);
1611                 return r.x;
1612             }
1613         } else {
1614             debugString("[ERROR]: getAccessibleXcoordFromContext ac = null");
1615         }
1616         return -1;
1617     }
1618 
1619     /**
1620      * returns the AccessibleComponent y-coord from an AccessibleContext
1621      */
1622     private int getAccessibleYcoordFromContext(AccessibleContext ac) {
1623         debugString("[INFO]: getAccessibleYcoordFromContext() called");
1624         if (ac != null) {
1625             Rectangle r = getAccessibleBoundsOnScreenFromContext(ac);
1626             if (r != null) {
1627                 return r.y;
1628             }
1629         } else {
1630         debugString("[ERROR]: getAccessibleYcoordFromContext; ac = null");
1631         }
1632         return -1;
1633     }
1634 
1635     /**
1636      * returns the AccessibleComponent height from an AccessibleContext
1637      */
1638     private int getAccessibleHeightFromContext(AccessibleContext ac) {
1639         if (ac != null) {
1640             Rectangle r = getAccessibleBoundsOnScreenFromContext(ac);
1641             if (r != null) {
1642                 return r.height;
1643             }
1644         } else {
1645             debugString("[ERROR]: getAccessibleHeightFromContext; ac = null");
1646         }
1647         return -1;
1648     }
1649 
1650     /**
1651      * returns the AccessibleComponent width from an AccessibleContext
1652      */
1653     private int getAccessibleWidthFromContext(AccessibleContext ac) {
1654         if (ac != null) {
1655             Rectangle r = getAccessibleBoundsOnScreenFromContext(ac);
1656             if (r != null) {
1657                 return r.width;
1658             }
1659         } else {
1660             debugString("[ERROR]: getAccessibleWidthFromContext; ac = null");
1661         }
1662         return -1;
1663     }
1664 
1665 
1666     /**
1667      * returns the AccessibleComponent from an AccessibleContext
1668      */
1669     private AccessibleComponent getAccessibleComponentFromContext(AccessibleContext ac) {
1670         if (ac != null) {
1671             AccessibleComponent acmp = InvocationUtils.invokeAndWait(() -> {
1672                     return ac.getAccessibleComponent();
1673                 }, ac);
1674             if (acmp != null) {
1675                 debugString("[INFO]: Returning AccessibleComponent Context");
1676                 return acmp;
1677             }
1678         } else {
1679             debugString("[ERROR]: getAccessibleComponentFromContext; ac = null");
1680         }
1681         return null;
1682     }
1683 
1684     /**
1685      * returns the AccessibleAction from an AccessibleContext
1686      */
1687     private AccessibleAction getAccessibleActionFromContext(final AccessibleContext ac) {
1688         debugString("[INFO]: Returning AccessibleAction Context");
1689         return ac == null ? null : InvocationUtils.invokeAndWait(new Callable<AccessibleAction>() {
1690             @Override
1691             public AccessibleAction call() throws Exception {
1692                 return ac.getAccessibleAction();
1693             }
1694         }, ac);
1695     }
1696 
1697     /**
1698      * returns the AccessibleSelection from an AccessibleContext
1699      */
1700     private AccessibleSelection getAccessibleSelectionFromContext(final AccessibleContext ac) {
1701         return ac == null ? null : InvocationUtils.invokeAndWait(new Callable<AccessibleSelection>() {
1702             @Override
1703             public AccessibleSelection call() throws Exception {
1704                 return ac.getAccessibleSelection();
1705             }
1706         }, ac);
1707     }
1708 


1720 
1721     /**
1722      * return the AccessibleComponent from an AccessibleContext
1723      */
1724     private AccessibleValue getAccessibleValueFromContext(final AccessibleContext ac) {
1725         return ac == null ? null : InvocationUtils.invokeAndWait(new Callable<AccessibleValue>() {
1726             @Override
1727             public AccessibleValue call() throws Exception {
1728                 return ac.getAccessibleValue();
1729             }
1730         }, ac);
1731     }
1732 
1733     /* ===== AccessibleText methods ===== */
1734 
1735     /**
1736      * returns the bounding rectangle for the text cursor
1737      * XXX
1738      */
1739     private Rectangle getCaretLocation(final AccessibleContext ac) {
1740     debugString("[INFO]: getCaretLocation");
1741         if (ac==null)
1742             return null;
1743         return InvocationUtils.invokeAndWait(new Callable<Rectangle>() {
1744             @Override
1745             public Rectangle call() throws Exception {
1746                 // workaround for JAAPI not returning cursor bounding rectangle
1747                 Rectangle r = null;
1748                 Accessible parent = ac.getAccessibleParent();
1749                 if (parent instanceof Accessible) {
1750                     int indexInParent = ac.getAccessibleIndexInParent();
1751                     Accessible child =
1752                             parent.getAccessibleContext().getAccessibleChild(indexInParent);
1753 
1754                     if (child instanceof JTextComponent) {
1755                         JTextComponent text = (JTextComponent) child;
1756                         try {
1757                             r = text.modelToView2D(text.getCaretPosition()).getBounds();
1758                             if (r != null) {
1759                                 Point p = text.getLocationOnScreen();
1760                                 r.translate(p.x, p.y);


1841         if (ac==null)
1842             return -1;
1843         return InvocationUtils.invokeAndWait(new Callable<Integer>() {
1844             @Override
1845             public Integer call() throws Exception {
1846                 AccessibleText at = ac.getAccessibleText();
1847                 if (at != null) {
1848                     return at.getCaretPosition();
1849                 }
1850                 return -1;
1851             }
1852         }, ac);
1853     }
1854 
1855     /**
1856      * Return the index at a specific point from an AccessibleContext
1857      * Point(x, y) is in screen coordinates.
1858      */
1859     private int getAccessibleIndexAtPointFromContext(final AccessibleContext ac,
1860                                                     final int x, final int y) {
1861         debugString("[INFO]: getAccessibleIndexAtPointFromContext: x = "+x+"; y = "+y);
1862         if (ac==null)
1863             return -1;
1864         return InvocationUtils.invokeAndWait(new Callable<Integer>() {
1865             @Override
1866             public Integer call() throws Exception {
1867                 AccessibleText at = ac.getAccessibleText();
1868                 AccessibleComponent acomp = ac.getAccessibleComponent();
1869                 if (at != null && acomp != null) {
1870                     // Convert x and y from screen coordinates to
1871                     // local coordinates.
1872                     try {
1873                         Point p = acomp.getLocationOnScreen();
1874                         int x1, y1;
1875                         if (p != null) {
1876                             x1 = x - p.x;
1877                             if (x1 < 0) {
1878                                 x1 = 0;
1879                             }
1880                             y1 = y - p.y;
1881                             if (y1 < 0) {


1895     }
1896 
1897     /**
1898      * return the letter at a specific point from an AccessibleContext
1899      */
1900     private String getAccessibleLetterAtIndexFromContext(final AccessibleContext ac, final int index) {
1901         if (ac != null) {
1902             String s = InvocationUtils.invokeAndWait(new Callable<String>() {
1903                 @Override
1904                 public String call() throws Exception {
1905                     AccessibleText at = ac.getAccessibleText();
1906                     if (at == null) return null;
1907                     return at.getAtIndex(AccessibleText.CHARACTER, index);
1908                 }
1909             }, ac);
1910             if (s != null) {
1911                 references.increment(s);
1912                 return s;
1913             }
1914         } else {
1915             debugString("[ERROR]: getAccessibleLetterAtIndexFromContext; ac = null");
1916         }
1917         return null;
1918     }
1919 
1920     /**
1921      * return the word at a specific point from an AccessibleContext
1922      */
1923     private String getAccessibleWordAtIndexFromContext(final AccessibleContext ac, final int index) {
1924         if (ac != null) {
1925             String s = InvocationUtils.invokeAndWait(new Callable<String>() {
1926                 @Override
1927                 public String call() throws Exception {
1928                     AccessibleText at = ac.getAccessibleText();
1929                     if (at == null) return null;
1930                     return at.getAtIndex(AccessibleText.WORD, index);
1931                 }
1932             }, ac);
1933             if (s != null) {
1934                 references.increment(s);
1935                 return s;
1936             }
1937         } else {
1938             debugString("[ERROR]: getAccessibleWordAtIndexFromContext; ac = null");
1939         }
1940         return null;
1941     }
1942 
1943     /**
1944      * return the sentence at a specific point from an AccessibleContext
1945      */
1946     private String getAccessibleSentenceAtIndexFromContext(final AccessibleContext ac, final int index) {
1947         if (ac != null) {
1948             String s = InvocationUtils.invokeAndWait(new Callable<String>() {
1949                 @Override
1950                 public String call() throws Exception {
1951                     AccessibleText at = ac.getAccessibleText();
1952                     if (at == null) return null;
1953                     return at.getAtIndex(AccessibleText.SENTENCE, index);
1954                 }
1955             }, ac);
1956             if (s != null) {
1957                 references.increment(s);
1958                 return s;
1959             }
1960         } else {
1961             debugString("[ERROR]: getAccessibleSentenceAtIndexFromContext; ac = null");
1962         }
1963         return null;
1964     }
1965 
1966     /**
1967      * return the text selection start from an AccessibleContext
1968      */
1969     private int getAccessibleTextSelectionStartFromContext(final AccessibleContext ac) {
1970         if (ac == null) return -1;
1971         return InvocationUtils.invokeAndWait(new Callable<Integer>() {
1972             @Override
1973             public Integer call() throws Exception {
1974                 AccessibleText at = ac.getAccessibleText();
1975                 if (at != null) {
1976                     return at.getSelectionStart();
1977                 }
1978                 return -1;
1979             }
1980         }, ac);
1981     }


1999     }
2000 
2001     /**
2002      * return the selected text from an AccessibleContext
2003      */
2004     private String getAccessibleTextSelectedTextFromContext(final AccessibleContext ac) {
2005         if (ac != null) {
2006             String s = InvocationUtils.invokeAndWait(new Callable<String>() {
2007                 @Override
2008                 public String call() throws Exception {
2009                     AccessibleText at = ac.getAccessibleText();
2010                     if (at == null) return null;
2011                     return at.getSelectedText();
2012                 }
2013             }, ac);
2014             if (s != null) {
2015                 references.increment(s);
2016                 return s;
2017             }
2018         } else {
2019             debugString("[ERROR]: getAccessibleTextSelectedTextFromContext; ac = null");
2020         }
2021         return null;
2022     }
2023 
2024     /**
2025      * return the attribute string at a given index from an AccessibleContext
2026      */
2027     private String getAccessibleAttributesAtIndexFromContext(final AccessibleContext ac,
2028                                                              final int index) {
2029         if (ac == null)
2030             return null;
2031         AttributeSet as = InvocationUtils.invokeAndWait(new Callable<AttributeSet>() {
2032             @Override
2033             public AttributeSet call() throws Exception {
2034                 AccessibleText at = ac.getAccessibleText();
2035                 if (at != null) {
2036                     return at.getCharacterAttribute(index);
2037                 }
2038                 return null;
2039             }


2260             }
2261         }, ac);
2262         Rectangle acRect = getAccessibleBoundsOnScreenFromContext(ac);
2263         if (r != null && acRect != null) {
2264             r.translate(acRect.x, acRect.y);
2265             return r;
2266         }
2267         return null;
2268     }
2269 
2270     /**
2271      * return the AccessibleText character x-coord at index from an AccessibleContext
2272      */
2273     private int getAccessibleXcoordTextRectAtIndexFromContext(AccessibleContext ac, int index) {
2274         if (ac != null) {
2275             Rectangle r = getAccessibleTextRectAtIndexFromContext(ac, index);
2276             if (r != null) {
2277                 return r.x;
2278             }
2279         } else {
2280             debugString("[ERROR]: getAccessibleXcoordTextRectAtIndexFromContext; ac = null");
2281         }
2282         return -1;
2283     }
2284 
2285     /**
2286      * return the AccessibleText character y-coord at index from an AccessibleContext
2287      */
2288     private int getAccessibleYcoordTextRectAtIndexFromContext(AccessibleContext ac, int index) {
2289         if (ac != null) {
2290             Rectangle r = getAccessibleTextRectAtIndexFromContext(ac, index);
2291             if (r != null) {
2292                 return r.y;
2293             }
2294         } else {
2295             debugString("[ERROR]: getAccessibleYcoordTextRectAtIndexFromContext; ac = null");
2296         }
2297         return -1;
2298     }
2299 
2300     /**
2301      * return the AccessibleText character height at index from an AccessibleContext
2302      */
2303     private int getAccessibleHeightTextRectAtIndexFromContext(AccessibleContext ac, int index) {
2304         if (ac != null) {
2305             Rectangle r = getAccessibleTextRectAtIndexFromContext(ac, index);
2306             if (r != null) {
2307                 return r.height;
2308             }
2309         } else {
2310             debugString("[ERROR]: getAccessibleHeightTextRectAtIndexFromContext; ac = null");
2311         }
2312         return -1;
2313     }
2314 
2315     /**
2316      * return the AccessibleText character width at index from an AccessibleContext
2317      */
2318     private int getAccessibleWidthTextRectAtIndexFromContext(AccessibleContext ac, int index) {
2319         if (ac != null) {
2320             Rectangle r = getAccessibleTextRectAtIndexFromContext(ac, index);
2321             if (r != null) {
2322                 return r.width;
2323             }
2324         } else {
2325             debugString("[ERROR]: getAccessibleWidthTextRectAtIndexFromContext; ac = null");
2326         }
2327         return -1;
2328     }
2329 
2330     /* ===== AttributeSet methods for AccessibleText ===== */
2331 
2332     /**
2333      * return the bold setting from an AttributeSet
2334      */
2335     private boolean getBoldFromAttributeSet(AttributeSet as) {
2336         if (as != null) {
2337             return StyleConstants.isBold(as);
2338         } else {
2339             debugString("[ERROR]: getBoldFromAttributeSet; as = null");
2340         }
2341         return false;
2342     }
2343 
2344     /**
2345      * return the italic setting from an AttributeSet
2346      */
2347     private boolean getItalicFromAttributeSet(AttributeSet as) {
2348         if (as != null) {
2349             return StyleConstants.isItalic(as);
2350         } else {
2351             debugString("[ERROR]: getItalicFromAttributeSet; as = null");
2352         }
2353         return false;
2354     }
2355 
2356     /**
2357      * return the underline setting from an AttributeSet
2358      */
2359     private boolean getUnderlineFromAttributeSet(AttributeSet as) {
2360         if (as != null) {
2361             return StyleConstants.isUnderline(as);
2362         } else {
2363             debugString("[ERROR]: getUnderlineFromAttributeSet; as = null");
2364         }
2365         return false;
2366     }
2367 
2368     /**
2369      * return the strikethrough setting from an AttributeSet
2370      */
2371     private boolean getStrikethroughFromAttributeSet(AttributeSet as) {
2372         if (as != null) {
2373             return StyleConstants.isStrikeThrough(as);
2374         } else {
2375             debugString("[ERROR]: getStrikethroughFromAttributeSet; as = null");
2376         }
2377         return false;
2378     }
2379 
2380     /**
2381      * return the superscript setting from an AttributeSet
2382      */
2383     private boolean getSuperscriptFromAttributeSet(AttributeSet as) {
2384         if (as != null) {
2385             return StyleConstants.isSuperscript(as);
2386         } else {
2387             debugString("[ERROR]: getSuperscriptFromAttributeSet; as = null");
2388         }
2389         return false;
2390     }
2391 
2392     /**
2393      * return the subscript setting from an AttributeSet
2394      */
2395     private boolean getSubscriptFromAttributeSet(AttributeSet as) {
2396         if (as != null) {
2397             return StyleConstants.isSubscript(as);
2398         } else {
2399             debugString("[ERROR]: getSubscriptFromAttributeSet; as = null");
2400         }
2401         return false;
2402     }
2403 
2404     /**
2405      * return the background color from an AttributeSet
2406      */
2407     private String getBackgroundColorFromAttributeSet(AttributeSet as) {
2408         if (as != null) {
2409             String s = StyleConstants.getBackground(as).toString();
2410             if (s != null) {
2411                 references.increment(s);
2412                 return s;
2413             }
2414         } else {
2415             debugString("[ERROR]: getBackgroundColorFromAttributeSet; as = null");
2416         }
2417         return null;
2418     }
2419 
2420     /**
2421      * return the foreground color from an AttributeSet
2422      */
2423     private String getForegroundColorFromAttributeSet(AttributeSet as) {
2424         if (as != null) {
2425             String s = StyleConstants.getForeground(as).toString();
2426             if (s != null) {
2427                 references.increment(s);
2428                 return s;
2429             }
2430         } else {
2431             debugString("[ERROR]: getForegroundColorFromAttributeSet; as = null");
2432         }
2433         return null;
2434     }
2435 
2436     /**
2437      * return the font family from an AttributeSet
2438      */
2439     private String getFontFamilyFromAttributeSet(AttributeSet as) {
2440         if (as != null) {
2441             String s = StyleConstants.getFontFamily(as).toString();
2442             if (s != null) {
2443                 references.increment(s);
2444                 return s;
2445             }
2446         } else {
2447             debugString("[ERROR]: getFontFamilyFromAttributeSet; as = null");
2448         }
2449         return null;
2450     }
2451 
2452     /**
2453      * return the font size from an AttributeSet
2454      */
2455     private int getFontSizeFromAttributeSet(AttributeSet as) {
2456         if (as != null) {
2457             return StyleConstants.getFontSize(as);
2458         } else {
2459             debugString("[ERROR]: getFontSizeFromAttributeSet; as = null");
2460         }
2461         return -1;
2462     }
2463 
2464     /**
2465      * return the alignment from an AttributeSet
2466      */
2467     private int getAlignmentFromAttributeSet(AttributeSet as) {
2468         if (as != null) {
2469             return StyleConstants.getAlignment(as);
2470         } else {
2471             debugString("[ERROR]: getAlignmentFromAttributeSet; as = null");
2472         }
2473         return -1;
2474     }
2475 
2476     /**
2477      * return the BiDi level from an AttributeSet
2478      */
2479     private int getBidiLevelFromAttributeSet(AttributeSet as) {
2480         if (as != null) {
2481             return StyleConstants.getBidiLevel(as);
2482         } else {
2483             debugString("[ERROR]: getBidiLevelFromAttributeSet; as = null");
2484         }
2485         return -1;
2486     }
2487 
2488 
2489     /**
2490      * return the first line indent from an AttributeSet
2491      */
2492     private float getFirstLineIndentFromAttributeSet(AttributeSet as) {
2493         if (as != null) {
2494             return StyleConstants.getFirstLineIndent(as);
2495         } else {
2496             debugString("[ERROR]: getFirstLineIndentFromAttributeSet; as = null");
2497         }
2498         return -1;
2499     }
2500 
2501     /**
2502      * return the left indent from an AttributeSet
2503      */
2504     private float getLeftIndentFromAttributeSet(AttributeSet as) {
2505         if (as != null) {
2506             return StyleConstants.getLeftIndent(as);
2507         } else {
2508             debugString("[ERROR]: getLeftIndentFromAttributeSet; as = null");
2509         }
2510         return -1;
2511     }
2512 
2513     /**
2514      * return the right indent from an AttributeSet
2515      */
2516     private float getRightIndentFromAttributeSet(AttributeSet as) {
2517         if (as != null) {
2518             return StyleConstants.getRightIndent(as);
2519         } else {
2520             debugString("[ERROR]: getRightIndentFromAttributeSet; as = null");
2521         }
2522         return -1;
2523     }
2524 
2525     /**
2526      * return the line spacing from an AttributeSet
2527      */
2528     private float getLineSpacingFromAttributeSet(AttributeSet as) {
2529         if (as != null) {
2530             return StyleConstants.getLineSpacing(as);
2531         } else {
2532             debugString("[ERROR]: getLineSpacingFromAttributeSet; as = null");
2533         }
2534         return -1;
2535     }
2536 
2537     /**
2538      * return the space above from an AttributeSet
2539      */
2540     private float getSpaceAboveFromAttributeSet(AttributeSet as) {
2541         if (as != null) {
2542             return StyleConstants.getSpaceAbove(as);
2543         } else {
2544             debugString("[ERROR]: getSpaceAboveFromAttributeSet; as = null");
2545         }
2546         return -1;
2547     }
2548 
2549     /**
2550      * return the space below from an AttributeSet
2551      */
2552     private float getSpaceBelowFromAttributeSet(AttributeSet as) {
2553         if (as != null) {
2554             return StyleConstants.getSpaceBelow(as);
2555         } else {
2556             debugString("[ERROR]: getSpaceBelowFromAttributeSet; as = null");
2557         }
2558         return -1;
2559     }
2560 
2561     /**
2562      * Enumerate all StyleConstants in the AttributeSet
2563      *
2564      * We need to check explicitly, 'cause of the HTML package conversion
2565      * mechanism (they may not be stored as StyleConstants, just translated
2566      * to them when asked).
2567      *
2568      * (Use convenience methods where they are defined...)
2569      *
2570      * Not checking the following (which the IBM SNS guidelines says
2571      * should be defined):
2572      *    - ComponentElementName
2573      *    - IconElementName
2574      *    - NameAttribute
2575      *    - ResolveAttribute
2576      */


2685      *
2686      */
2687     private String getCurrentAccessibleValueFromContext(final AccessibleContext ac) {
2688         if (ac != null) {
2689             final Number value = InvocationUtils.invokeAndWait(new Callable<Number>() {
2690                 @Override
2691                 public Number call() throws Exception {
2692                     AccessibleValue av = ac.getAccessibleValue();
2693                     if (av == null) return null;
2694                     return av.getCurrentAccessibleValue();
2695                 }
2696             }, ac);
2697             if (value != null) {
2698                 String s = value.toString();
2699                 if (s != null) {
2700                     references.increment(s);
2701                     return s;
2702                 }
2703             }
2704         } else {
2705             debugString("[ERROR]: getCurrentAccessibleValueFromContext; ac = null");
2706         }
2707         return null;
2708     }
2709 
2710     /**
2711      * return the AccessibleValue maximum value from an AccessibleContext
2712      * returned using a String 'cause the value is a java Number
2713      *
2714      */
2715     private String getMaximumAccessibleValueFromContext(final AccessibleContext ac) {
2716         if (ac != null) {
2717             final Number value = InvocationUtils.invokeAndWait(new Callable<Number>() {
2718                 @Override
2719                 public Number call() throws Exception {
2720                     AccessibleValue av = ac.getAccessibleValue();
2721                     if (av == null) return null;
2722                     return av.getMaximumAccessibleValue();
2723                 }
2724             }, ac);
2725             if (value != null) {
2726                 String s = value.toString();
2727                 if (s != null) {
2728                     references.increment(s);
2729                     return s;
2730                 }
2731             }
2732         } else {
2733             debugString("[ERROR]: getMaximumAccessibleValueFromContext; ac = null");
2734         }
2735         return null;
2736     }
2737 
2738     /**
2739      * return the AccessibleValue minimum value from an AccessibleContext
2740      * returned using a String 'cause the value is a java Number
2741      *
2742      */
2743     private String getMinimumAccessibleValueFromContext(final AccessibleContext ac) {
2744         if (ac != null) {
2745             final Number value = InvocationUtils.invokeAndWait(new Callable<Number>() {
2746                 @Override
2747                 public Number call() throws Exception {
2748                     AccessibleValue av = ac.getAccessibleValue();
2749                     if (av == null) return null;
2750                     return av.getMinimumAccessibleValue();
2751                 }
2752             }, ac);
2753             if (value != null) {
2754                 String s = value.toString();
2755                 if (s != null) {
2756                     references.increment(s);
2757                     return s;
2758                 }
2759             }
2760         } else {
2761             debugString("[ERROR]: getMinimumAccessibleValueFromContext; ac = null");
2762         }
2763         return null;
2764     }
2765 
2766 
2767     /* ===== AccessibleSelection methods ===== */
2768 
2769     /**
2770      * add to the AccessibleSelection of an AccessibleContext child i
2771      *
2772      */
2773     private void addAccessibleSelectionFromContext(final AccessibleContext ac, final int i) {
2774         try {
2775             InvocationUtils.invokeAndWait(new Callable<Object>() {
2776                 @Override
2777                 public Object call() throws Exception {
2778                     if (ac != null) {
2779                         AccessibleSelection as = ac.getAccessibleSelection();
2780                         if (as != null) {
2781                             as.addAccessibleSelection(i);


2924                         return at;
2925                     }
2926                 }
2927                 return null;
2928             }
2929         }, ac);
2930     }
2931 
2932 
2933     /*
2934      * returns the AccessibleContext that contains an AccessibleTable
2935      */
2936     private AccessibleContext getContextFromAccessibleTable(AccessibleTable at) {
2937         return hashtab.get(at);
2938     }
2939 
2940     /*
2941      * returns the row count for an AccessibleTable
2942      */
2943     private int getAccessibleTableRowCount(final AccessibleContext ac) {
2944         debugString("[INFO]: ##### getAccessibleTableRowCount");
2945         return InvocationUtils.invokeAndWait(new Callable<Integer>() {
2946             @Override
2947             public Integer call() throws Exception {
2948                 if (ac != null) {
2949                     AccessibleTable at = ac.getAccessibleTable();
2950                     if (at != null) {
2951                         return at.getAccessibleRowCount();
2952                     }
2953                 }
2954                 return -1;
2955             }
2956         }, ac);
2957     }
2958 
2959     /*
2960      * returns the column count for an AccessibleTable
2961      */
2962     private int getAccessibleTableColumnCount(final AccessibleContext ac) {
2963         debugString("[INFO]: ##### getAccessibleTableColumnCount");
2964         return InvocationUtils.invokeAndWait(new Callable<Integer>() {
2965             @Override
2966             public Integer call() throws Exception {
2967                 if (ac != null) {
2968                     AccessibleTable at = ac.getAccessibleTable();
2969                     if (at != null) {
2970                         return at.getAccessibleColumnCount();
2971                     }
2972                 }
2973                 return -1;
2974             }
2975         }, ac);
2976     }
2977 
2978     /*
2979      * returns the AccessibleContext for an AccessibleTable cell
2980      */
2981     private AccessibleContext getAccessibleTableCellAccessibleContext(final AccessibleTable at,
2982                                                                       final int row, final int column) {
2983         debugString("[INFO]: getAccessibleTableCellAccessibleContext: at = "+at.getClass());
2984         if (at == null) return null;
2985         return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
2986             @Override
2987             public AccessibleContext call() throws Exception {
2988                 if (!(at instanceof AccessibleContext)) {
2989                     Accessible a = at.getAccessibleAt(row, column);
2990                     if (a != null) {
2991                         return a.getAccessibleContext();
2992                     }
2993                 } else {
2994                     // work-around for AccessibleJTable.getCurrentAccessibleContext returning
2995                     // wrong renderer component when cell contains more than one component
2996                     AccessibleContext ac = (AccessibleContext) at;
2997                     Accessible parent = ac.getAccessibleParent();
2998                     if (parent != null) {
2999                         int indexInParent = ac.getAccessibleIndexInParent();
3000                         Accessible child =
3001                                 parent.getAccessibleContext().getAccessibleChild(indexInParent);
3002                         if (child instanceof JTable) {
3003                             JTable table = (JTable) child;


3008                                 renderer = table.getDefaultRenderer(columnClass);
3009                             }
3010                             Component component =
3011                                     renderer.getTableCellRendererComponent(table, table.getValueAt(row, column),
3012                                             false, false, row, column);
3013                             if (component instanceof Accessible) {
3014                                 return component.getAccessibleContext();
3015                             }
3016                         }
3017                     }
3018                 }
3019                 return null;
3020             }
3021         }, getContextFromAccessibleTable(at));
3022     }
3023 
3024     /*
3025      * returns the index of a cell at a given row and column in an AccessibleTable
3026      */
3027     private int getAccessibleTableCellIndex(final AccessibleTable at, int row, int column) {
3028         debugString("[INFO]: ##### getAccessibleTableCellIndex: at="+at);
3029         if (at != null) {
3030             int cellIndex = row *
3031                 InvocationUtils.invokeAndWait(new Callable<Integer>() {
3032                     @Override
3033                     public Integer call() throws Exception {
3034                         return at.getAccessibleColumnCount();
3035                     }
3036                 }, getContextFromAccessibleTable(at)) +
3037                 column;
3038             debugString("[INFO]:    ##### getAccessibleTableCellIndex="+cellIndex);
3039             return cellIndex;
3040         }
3041         debugString("[ERROR]: ##### getAccessibleTableCellIndex FAILED");
3042         return -1;
3043     }
3044 
3045     /*
3046      * returns the row extent of a cell at a given row and column in an AccessibleTable
3047      */
3048     private int getAccessibleTableCellRowExtent(final AccessibleTable at, final int row, final int column) {
3049         debugString("[INFO]: ##### getAccessibleTableCellRowExtent");
3050         if (at != null) {
3051             int rowExtent = InvocationUtils.invokeAndWait(new Callable<Integer>() {
3052                                                               @Override
3053                                                               public Integer call() throws Exception {
3054                                                                   return at.getAccessibleRowExtentAt(row, column);
3055                                                               }
3056                                                           },
3057                     getContextFromAccessibleTable(at));
3058             debugString("[INFO]:   ##### getAccessibleTableCellRowExtent="+rowExtent);
3059             return rowExtent;
3060         }
3061         debugString("[ERROR]: ##### getAccessibleTableCellRowExtent FAILED");
3062         return -1;
3063     }
3064 
3065     /*
3066      * returns the column extent of a cell at a given row and column in an AccessibleTable
3067      */
3068     private int getAccessibleTableCellColumnExtent(final AccessibleTable at, final int row, final int column) {
3069         debugString("[INFO]: ##### getAccessibleTableCellColumnExtent");
3070         if (at != null) {
3071             int columnExtent = InvocationUtils.invokeAndWait(new Callable<Integer>() {
3072                                                                  @Override
3073                                                                  public Integer call() throws Exception {
3074                                                                      return at.getAccessibleColumnExtentAt(row, column);
3075                                                                  }
3076                                                              },
3077                     getContextFromAccessibleTable(at));
3078             debugString("[INFO]:   ##### getAccessibleTableCellColumnExtent="+columnExtent);
3079             return columnExtent;
3080         }
3081         debugString("[ERROR]: ##### getAccessibleTableCellColumnExtent FAILED");
3082         return -1;
3083     }
3084 
3085     /*
3086      * returns whether a cell is selected at a given row and column in an AccessibleTable
3087      */
3088     private boolean isAccessibleTableCellSelected(final AccessibleTable at, final int row,
3089                          final int column) {
3090         debugString("[INFO]: ##### isAccessibleTableCellSelected: ["+row+"]["+column+"]");
3091         if (at == null)
3092             return false;
3093         return InvocationUtils.invokeAndWait(new Callable<Boolean>() {
3094             @Override
3095             public Boolean call() throws Exception {
3096                 boolean isSelected = false;
3097                 Accessible a = at.getAccessibleAt(row, column);
3098                 if (a != null) {
3099                     AccessibleContext ac = a.getAccessibleContext();
3100                     if (ac == null)
3101                         return false;
3102                     AccessibleStateSet as = ac.getAccessibleStateSet();
3103                     if (as != null) {
3104                         isSelected = as.contains(AccessibleState.SELECTED);
3105                     }
3106                 }
3107                 return isSelected;
3108             }
3109         }, getContextFromAccessibleTable(at));
3110     }
3111 
3112     /*
3113      * returns an AccessibleTable that represents the row header in an
3114      * AccessibleTable
3115      */
3116     private AccessibleTable getAccessibleTableRowHeader(final AccessibleContext ac) {
3117         debugString("[INFO]: #####  getAccessibleTableRowHeader called");
3118         AccessibleTable at = InvocationUtils.invokeAndWait(new Callable<AccessibleTable>() {
3119             @Override
3120             public AccessibleTable call() throws Exception {
3121                 if (ac != null) {
3122                     AccessibleTable at = ac.getAccessibleTable();
3123                     if (at != null) {
3124                         return at.getAccessibleRowHeader();
3125                     }
3126                 }
3127                 return null;
3128             }
3129         }, ac);
3130         if (at != null) {
3131             hashtab.put(at, ac);
3132         }
3133         return at;
3134     }
3135 
3136     /*
3137      * returns an AccessibleTable that represents the column header in an
3138      * AccessibleTable
3139      */
3140     private AccessibleTable getAccessibleTableColumnHeader(final AccessibleContext ac) {
3141     debugString("[INFO]: ##### getAccessibleTableColumnHeader");
3142         if (ac == null)
3143             return null;
3144         AccessibleTable at = InvocationUtils.invokeAndWait(new Callable<AccessibleTable>() {
3145             @Override
3146             public AccessibleTable call() throws Exception {
3147                 // workaround for getAccessibleColumnHeader NPE
3148                 // when the table header is null
3149                 Accessible parent = ac.getAccessibleParent();
3150                 if (parent != null) {
3151                     int indexInParent = ac.getAccessibleIndexInParent();
3152                     Accessible child =
3153                             parent.getAccessibleContext().getAccessibleChild(indexInParent);
3154                     if (child instanceof JTable) {
3155                         JTable table = (JTable) child;
3156                         if (table.getTableHeader() == null) {
3157                             return null;
3158                         }
3159                     }
3160                 }
3161                 AccessibleTable at = ac.getAccessibleTable();
3162                 if (at != null) {
3163                     return at.getAccessibleColumnHeader();
3164                 }
3165                 return null;
3166             }
3167         }, ac);
3168         if (at != null) {
3169             hashtab.put(at, ac);
3170         }
3171         return at;
3172     }
3173 
3174     /*
3175      * returns the number of row headers in an AccessibleTable that represents
3176      * the row header in an AccessibleTable
3177      */
3178     private int getAccessibleTableRowHeaderRowCount(AccessibleContext ac) {
3179 
3180     debugString("[INFO]: #####  getAccessibleTableRowHeaderRowCount called");
3181         if (ac != null) {
3182             final AccessibleTable atRowHeader = getAccessibleTableRowHeader(ac);
3183             if (atRowHeader != null) {
3184                 return InvocationUtils.invokeAndWait(new Callable<Integer>() {
3185                     @Override
3186                     public Integer call() throws Exception {
3187                         if (atRowHeader != null) {
3188                             return atRowHeader.getAccessibleRowCount();
3189                         }
3190                         return -1;
3191                     }
3192                 }, ac);
3193             }
3194         }
3195         return -1;
3196     }
3197 
3198     /*
3199      * returns the number of column headers in an AccessibleTable that represents
3200      * the row header in an AccessibleTable
3201      */
3202     private int getAccessibleTableRowHeaderColumnCount(AccessibleContext ac) {
3203         debugString("[INFO]: #####  getAccessibleTableRowHeaderColumnCount called");
3204         if (ac != null) {
3205             final AccessibleTable atRowHeader = getAccessibleTableRowHeader(ac);
3206             if (atRowHeader != null) {
3207                 return InvocationUtils.invokeAndWait(new Callable<Integer>() {
3208                     @Override
3209                     public Integer call() throws Exception {
3210                         if (atRowHeader != null) {
3211                             return atRowHeader.getAccessibleColumnCount();
3212                         }
3213                         return -1;
3214                     }
3215                 }, ac);
3216             }
3217         }
3218         debugString("[ERROR]: ##### getAccessibleTableRowHeaderColumnCount FAILED");
3219         return -1;
3220     }
3221 
3222     /*
3223      * returns the number of row headers in an AccessibleTable that represents
3224      * the column header in an AccessibleTable
3225      */
3226     private int getAccessibleTableColumnHeaderRowCount(AccessibleContext ac) {
3227 
3228     debugString("[INFO]: ##### getAccessibleTableColumnHeaderRowCount");
3229         if (ac != null) {
3230             final AccessibleTable atColumnHeader = getAccessibleTableColumnHeader(ac);
3231             if (atColumnHeader != null) {
3232                 return InvocationUtils.invokeAndWait(new Callable<Integer>() {
3233                     @Override
3234                     public Integer call() throws Exception {
3235                         if (atColumnHeader != null) {
3236                             return atColumnHeader.getAccessibleRowCount();
3237                         }
3238                         return -1;
3239                     }
3240                 }, ac);
3241             }
3242         }
3243         debugString("[ERROR]: ##### getAccessibleTableColumnHeaderRowCount FAILED");
3244         return -1;
3245     }
3246 
3247     /*
3248      * returns the number of column headers in an AccessibleTable that represents
3249      * the column header in an AccessibleTable
3250      */
3251     private int getAccessibleTableColumnHeaderColumnCount(AccessibleContext ac) {
3252 
3253     debugString("[ERROR]: #####  getAccessibleTableColumnHeaderColumnCount");
3254         if (ac != null) {
3255             final AccessibleTable atColumnHeader = getAccessibleTableColumnHeader(ac);
3256             if (atColumnHeader != null) {
3257                 return InvocationUtils.invokeAndWait(new Callable<Integer>() {
3258                     @Override
3259                     public Integer call() throws Exception {
3260                         if (atColumnHeader != null) {
3261                             return atColumnHeader.getAccessibleColumnCount();
3262                         }
3263                         return -1;
3264                     }
3265                 }, ac);
3266             }
3267         }
3268         debugString("[ERROR]: ##### getAccessibleTableColumnHeaderColumnCount FAILED");
3269         return -1;
3270     }
3271 
3272     /*
3273      * returns the description of a row header in an AccessibleTable
3274      */
3275     private AccessibleContext getAccessibleTableRowDescription(final AccessibleTable table,
3276                                                               final int row) {
3277         return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
3278             @Override
3279             public AccessibleContext call() throws Exception {
3280                 if (table != null) {
3281                     Accessible a = table.getAccessibleRowDescription(row);
3282                     if (a != null) {
3283                         return a.getAccessibleContext();
3284                     }
3285                 }
3286                 return null;
3287             }
3288         }, getContextFromAccessibleTable(table));


3515                     AccessibleRelationSet ars = ac.getAccessibleRelationSet();
3516                     if (ars != null) {
3517                         AccessibleRelation[] relations = ars.toArray();
3518                         if (relations != null && i >= 0 && i < relations.length) {
3519                             Object[] targets = relations[i].getTarget();
3520                             return targets.length;
3521                         }
3522                     }
3523                 }
3524                 return -1;
3525             }
3526         }, ac);
3527     }
3528 
3529     /*
3530      * returns the jth target in the ith relation in the AccessibleContext's
3531      * AccessibleRelationSet
3532      */
3533     private AccessibleContext getAccessibleRelationTarget(final AccessibleContext ac,
3534                                                          final int i, final int j) {
3535         debugString("[INFO]: ***** getAccessibleRelationTarget");
3536         return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
3537             @Override
3538             public AccessibleContext call() throws Exception {
3539                 if (ac != null) {
3540                     AccessibleRelationSet ars = ac.getAccessibleRelationSet();
3541                     if (ars != null) {
3542                         AccessibleRelation[] relations = ars.toArray();
3543                         if (relations != null && i >= 0 && i < relations.length) {
3544                             Object[] targets = relations[i].getTarget();
3545                             if (targets != null && j >= 0 & j < targets.length) {
3546                                 Object o = targets[j];
3547                                 if (o instanceof Accessible) {
3548                                     return ((Accessible) o).getAccessibleContext();
3549                                 }
3550                             }
3551                         }
3552                     }
3553                 }
3554                 return null;
3555             }
3556         }, ac);
3557     }
3558 
3559     // ========= AccessibleHypertext =========
3560 
3561     private Map<AccessibleHypertext, AccessibleContext> hyperTextContextMap = new WeakHashMap<>();
3562     private Map<AccessibleHyperlink, AccessibleContext> hyperLinkContextMap = new WeakHashMap<>();
3563 
3564     /*
3565      * Returns the AccessibleHypertext
3566      */
3567     private AccessibleHypertext getAccessibleHypertext(final AccessibleContext ac) {
3568         debugString("[INFO]: getAccessibleHyperlink");
3569         if (ac==null)
3570             return null;
3571         AccessibleHypertext hypertext = InvocationUtils.invokeAndWait(new Callable<AccessibleHypertext>() {
3572             @Override
3573             public AccessibleHypertext call() throws Exception {
3574                 AccessibleText at = ac.getAccessibleText();
3575                 if (!(at instanceof AccessibleHypertext)) {
3576                     return null;
3577                 }
3578                 return ((AccessibleHypertext) at);
3579             }
3580         }, ac);
3581         hyperTextContextMap.put(hypertext, ac);
3582         return hypertext;
3583     }
3584 
3585     /*
3586      * Returns the number of AccessibleHyperlinks
3587      */
3588     private int getAccessibleHyperlinkCount(AccessibleContext ac) {
3589         debugString("[INFO]: getAccessibleHyperlinkCount");
3590         if (ac == null) {
3591             return 0;
3592         }
3593         final AccessibleHypertext hypertext = getAccessibleHypertext(ac);
3594         if (hypertext == null) {
3595             return 0;
3596         }
3597         //return hypertext.getLinkCount();
3598         return InvocationUtils.invokeAndWait(new Callable<Integer>() {
3599             @Override
3600             public Integer call() throws Exception {
3601                 return hypertext.getLinkCount();
3602             }
3603         }, ac);
3604     }
3605 
3606     /*
3607      * Returns the hyperlink at the specified index
3608      */
3609     private AccessibleHyperlink getAccessibleHyperlink(final AccessibleHypertext hypertext, final int i) {
3610         debugString("[INFO]: getAccessibleHyperlink");
3611         if (hypertext == null) {
3612             return null;
3613         }
3614         AccessibleContext ac = hyperTextContextMap.get(hypertext);
3615         if ( i < 0 || i >=
3616              InvocationUtils.invokeAndWait(new Callable<Integer>() {
3617                  @Override
3618                  public Integer call() throws Exception {
3619                      return hypertext.getLinkCount();
3620                  }
3621              }, ac) ) {
3622             return null;
3623         }
3624         AccessibleHyperlink acLink = InvocationUtils.invokeAndWait(new Callable<AccessibleHyperlink>() {
3625             @Override
3626             public AccessibleHyperlink call() throws Exception {
3627                 AccessibleHyperlink link = hypertext.getLink(i);
3628                 if (link == null || (!link.isValid())) {
3629                     return null;
3630                 }
3631                 return link;
3632             }
3633         }, ac);
3634         hyperLinkContextMap.put(acLink, ac);
3635         return acLink;
3636     }
3637 
3638     /*
3639      * Returns the hyperlink object description
3640      */
3641     private String getAccessibleHyperlinkText(final AccessibleHyperlink link) {
3642         debugString("[INFO]: getAccessibleHyperlinkText");
3643         if (link == null) {
3644             return null;
3645         }
3646         return InvocationUtils.invokeAndWait(new Callable<String>() {
3647             @Override
3648             public String call() throws Exception {
3649                 Object o = link.getAccessibleActionDescription(0);
3650                 if (o != null) {
3651                     return o.toString();
3652                 }
3653                 return null;
3654             }
3655         }, hyperLinkContextMap.get(link));
3656     }
3657 
3658     /*
3659      * Returns the hyperlink URL
3660      */
3661     private String getAccessibleHyperlinkURL(final AccessibleHyperlink link) {
3662         debugString("[INFO]: getAccessibleHyperlinkURL");
3663         if (link == null) {
3664             return null;
3665         }
3666         return InvocationUtils.invokeAndWait(new Callable<String>() {
3667             @Override
3668             public String call() throws Exception {
3669                 Object o = link.getAccessibleActionObject(0);
3670                 if (o != null) {
3671                     return o.toString();
3672                 } else {
3673                     return null;
3674                 }
3675             }
3676         }, hyperLinkContextMap.get(link));
3677     }
3678 
3679     /*
3680      * Returns the start index of the hyperlink text
3681      */
3682     private int getAccessibleHyperlinkStartIndex(final AccessibleHyperlink link) {
3683         debugString("[INFO]: getAccessibleHyperlinkStartIndex");
3684         if (link == null) {
3685             return -1;
3686         }
3687         return  InvocationUtils.invokeAndWait(new Callable<Integer>() {
3688             @Override
3689             public Integer call() throws Exception {
3690                 return link.getStartIndex();
3691             }
3692         }, hyperLinkContextMap.get(link));
3693     }
3694 
3695     /*
3696      * Returns the end index of the hyperlink text
3697      */
3698     private int getAccessibleHyperlinkEndIndex(final AccessibleHyperlink link) {
3699         debugString("[INFO]: getAccessibleHyperlinkEndIndex");
3700         if (link == null) {
3701             return -1;
3702         }
3703         return  InvocationUtils.invokeAndWait(new Callable<Integer>() {
3704             @Override
3705             public Integer call() throws Exception {
3706                 return link.getEndIndex();
3707             }
3708         }, hyperLinkContextMap.get(link));
3709     }
3710 
3711     /*
3712      * Returns the index into an array of hyperlinks that
3713      * is associated with this character index, or -1 if there
3714      * is no hyperlink associated with this index.
3715      */
3716     private int getAccessibleHypertextLinkIndex(final AccessibleHypertext hypertext, final int charIndex) {
3717         debugString("[INFO]: getAccessibleHypertextLinkIndex: charIndex = "+charIndex);
3718         if (hypertext == null) {
3719             return -1;
3720         }
3721         int linkIndex = InvocationUtils.invokeAndWait(new Callable<Integer>() {
3722             @Override
3723             public Integer call() throws Exception {
3724                 return hypertext.getLinkIndex(charIndex);
3725             }
3726         }, hyperTextContextMap.get(hypertext));
3727         debugString("[INFO]: getAccessibleHypertextLinkIndex returning "+linkIndex);
3728         return linkIndex;
3729     }
3730 
3731     /*
3732      * Actives the hyperlink
3733      */
3734     private boolean activateAccessibleHyperlink(final AccessibleContext ac,
3735                                                 final AccessibleHyperlink link) {
3736         //debugString("activateAccessibleHyperlink: link = "+link.getClass());
3737         if (link == null) {
3738             return false;
3739         }
3740         boolean retval = InvocationUtils.invokeAndWait(new Callable<Boolean>() {
3741             @Override
3742             public Boolean call() throws Exception {
3743                 return link.doAccessibleAction(0);
3744             }
3745         }, ac);
3746         debugString("[INFO]: activateAccessibleHyperlink: returning = "+retval);
3747         return retval;
3748     }
3749 
3750 
3751     // ============ AccessibleKeyBinding =============
3752 
3753     /*
3754      * returns the component mnemonic
3755      */
3756     private KeyStroke getMnemonic(final AccessibleContext ac) {
3757         if (ac == null)
3758             return null;
3759         return InvocationUtils.invokeAndWait(new Callable<KeyStroke>() {
3760             @Override
3761             public KeyStroke call() throws Exception {
3762                 AccessibleComponent comp = ac.getAccessibleComponent();
3763                 if (!(comp instanceof AccessibleExtendedComponent)) {
3764                     return null;
3765                 }
3766                 AccessibleExtendedComponent aec = (AccessibleExtendedComponent) comp;


3854             case KeyEvent.VK_RIGHT:
3855             case KeyEvent.VK_UP:
3856                 break;
3857             default:
3858                 code = 0;
3859                 break;
3860         }
3861         return code;
3862     }
3863 
3864     /*
3865      * returns the KeyStoke character
3866      */
3867     private char getKeyChar(KeyStroke keyStroke) {
3868         // If the shortcut is an FKey return 1-24
3869         if (keyStroke == null)
3870             return 0;
3871         int fKey = fKeyNumber(keyStroke);
3872         if (fKey != 0) {
3873             // return 0x00000001 through 0x00000018
3874             debugString("[INFO]:   Shortcut is: F" + fKey);
3875             return (char)fKey;
3876         }
3877         // If the accelerator is a control character, return it
3878         int keyCode = controlCode(keyStroke);
3879         if (keyCode != 0) {
3880             debugString("[INFO]:   Shortcut is control character: " + Integer.toHexString(keyCode));
3881             return (char)keyCode;
3882         }
3883         String keyText = KeyEvent.getKeyText(keyStroke.getKeyCode());
3884         debugString("[INFO]:   Shortcut is: " + keyText);
3885         if (keyText != null || keyText.length() > 0) {
3886             CharSequence seq = keyText.subSequence(0, 1);
3887             if (seq != null || seq.length() > 0) {
3888                 return seq.charAt(0);
3889             }
3890         }
3891         return 0;
3892     }
3893 
3894     /*
3895      * returns the KeyStroke modifiers as an int
3896      */
3897     private int getModifiers(KeyStroke keyStroke) {
3898         if (keyStroke == null)
3899             return 0;
3900         debugString("[INFO]: In AccessBridge.getModifiers");
3901         // modifiers is a bit strip where bits 0-7 indicate a traditional modifier
3902         // such as Ctrl/Alt/Shift, bit 8 indicates an F key shortcut, and bit 9 indicates
3903         // a control code shortcut such as the delete key.
3904 
3905         int modifiers = 0;
3906         // Is the shortcut an FKey?
3907         if (fKeyNumber(keyStroke) != 0) {
3908             modifiers |= 1 << 8;
3909         }
3910         // Is the shortcut a control code?
3911         if (controlCode(keyStroke) != 0) {
3912             modifiers |= 1 << 9;
3913         }
3914         // The following is needed in order to handle translated modifiers.
3915         // getKeyModifiersText doesn't work because for example in German Strg is
3916         // returned for Ctrl.
3917 
3918         // There can be more than one modifier, e.g. if the modifier is ctrl + shift + B
3919         // the toString text is "shift ctrl pressed B". Need to parse through that.
3920         StringTokenizer st = new StringTokenizer(keyStroke.toString());
3921         while (st.hasMoreTokens()) {
3922             String text = st.nextToken();
3923             // Meta+Ctrl+Alt+Shift
3924             // 0-3 are shift, ctrl, meta, alt
3925             // 4-7 are for Solaris workstations (though not being used)
3926             if (text.startsWith("met")) {
3927                 debugString("[INFO]:   found meta");
3928                 modifiers |= ActionEvent.META_MASK;
3929             }
3930             if (text.startsWith("ctr")) {
3931                 debugString("[INFO]:   found ctrl");
3932                 modifiers |= ActionEvent.CTRL_MASK;
3933             }
3934             if (text.startsWith("alt")) {
3935                 debugString("[INFO]:   found alt");
3936                 modifiers |= ActionEvent.ALT_MASK;
3937             }
3938             if (text.startsWith("shi")) {
3939                 debugString("   found shift");
3940                 modifiers |= ActionEvent.SHIFT_MASK;
3941             }
3942         }
3943         debugString("[INFO]:   returning modifiers: 0x" + Integer.toHexString(modifiers));
3944         return modifiers;
3945     }
3946 
3947     /*
3948      * returns the number of key bindings associated with this context
3949      */
3950     private int getAccessibleKeyBindingsCount(AccessibleContext ac) {
3951         if (ac == null)
3952             return 0;
3953         int count = 0;
3954 
3955         if (getMnemonic(ac) != null) {
3956             count++;
3957         }
3958         if (getAccelerator(ac) != null) {
3959             count++;
3960         }
3961         return count;
3962     }
3963 


4002         if (index == 0) {   // mnemonic
4003             KeyStroke keyStroke = getMnemonic(ac);
4004             if (keyStroke != null) {
4005                 return getModifiers(keyStroke);
4006             }
4007         } else if (index == 1) { // accelerator
4008             KeyStroke keyStroke = getAccelerator(ac);
4009             if (keyStroke != null) {
4010                 return getModifiers(keyStroke);
4011             }
4012         }
4013         return 0;
4014     }
4015 
4016     // ========== AccessibleIcon ============
4017 
4018     /*
4019      * return the number of icons associated with this context
4020      */
4021     private int getAccessibleIconsCount(final AccessibleContext ac) {
4022         debugString("[INFO]: getAccessibleIconsCount");
4023         if (ac == null) {
4024             return 0;
4025         }
4026         return InvocationUtils.invokeAndWait(new Callable<Integer>() {
4027             @Override
4028             public Integer call() throws Exception {
4029                 AccessibleIcon[] ai = ac.getAccessibleIcon();
4030                 if (ai == null) {
4031                     return 0;
4032                 }
4033                 return ai.length;
4034             }
4035         }, ac);
4036     }
4037 
4038     /*
4039      * return icon description at the specified index
4040      */
4041     private String getAccessibleIconDescription(final AccessibleContext ac, final int index) {
4042         debugString("[INFO]: getAccessibleIconDescription: index = "+index);
4043         if (ac == null) {
4044             return null;
4045         }
4046         return InvocationUtils.invokeAndWait(new Callable<String>() {
4047             @Override
4048             public String call() throws Exception {
4049                 AccessibleIcon[] ai = ac.getAccessibleIcon();
4050                 if (ai == null || index < 0 || index >= ai.length) {
4051                     return null;
4052                 }
4053                 return ai[index].getAccessibleIconDescription();
4054             }
4055         }, ac);
4056     }
4057 
4058     /*
4059      * return icon height at the specified index
4060      */
4061     private int getAccessibleIconHeight(final AccessibleContext ac, final int index) {
4062         debugString("[INFO]: getAccessibleIconHeight: index = "+index);
4063         if (ac == null) {
4064             return 0;
4065         }
4066         return InvocationUtils.invokeAndWait(new Callable<Integer>() {
4067             @Override
4068             public Integer call() throws Exception {
4069                 AccessibleIcon[] ai = ac.getAccessibleIcon();
4070                 if (ai == null || index < 0 || index >= ai.length) {
4071                     return 0;
4072                 }
4073                 return ai[index].getAccessibleIconHeight();
4074             }
4075         }, ac);
4076     }
4077 
4078     /*
4079      * return icon width at the specified index
4080      */
4081     private int getAccessibleIconWidth(final AccessibleContext ac, final int index) {
4082         debugString("[INFO]: getAccessibleIconWidth: index = "+index);
4083         if (ac == null) {
4084             return 0;
4085         }
4086         return InvocationUtils.invokeAndWait(new Callable<Integer>() {
4087             @Override
4088             public Integer call() throws Exception {
4089                 AccessibleIcon[] ai = ac.getAccessibleIcon();
4090                 if (ai == null || index < 0 || index >= ai.length) {
4091                     return 0;
4092                 }
4093                 return ai[index].getAccessibleIconWidth();
4094             }
4095         }, ac);
4096     }
4097 
4098     // ========= AccessibleAction ===========
4099 
4100     /*
4101      * return the number of icons associated with this context
4102      */
4103     private int getAccessibleActionsCount(final AccessibleContext ac) {
4104         debugString("[INFO]: getAccessibleActionsCount");
4105         if (ac == null) {
4106             return 0;
4107         }
4108         return InvocationUtils.invokeAndWait(new Callable<Integer>() {
4109             @Override
4110             public Integer call() throws Exception {
4111                 AccessibleAction aa = ac.getAccessibleAction();
4112                 if (aa == null)
4113                     return 0;
4114                 return aa.getAccessibleActionCount();
4115             }
4116         }, ac);
4117     }
4118 
4119     /*
4120      * return icon description at the specified index
4121      */
4122     private String getAccessibleActionName(final AccessibleContext ac, final int index) {
4123         debugString("[INFO]: getAccessibleActionName: index = "+index);
4124         if (ac == null) {
4125             return null;
4126         }
4127         return InvocationUtils.invokeAndWait(new Callable<String>() {
4128             @Override
4129             public String call() throws Exception {
4130                 AccessibleAction aa = ac.getAccessibleAction();
4131                 if (aa == null) {
4132                     return null;
4133                 }
4134                 return aa.getAccessibleActionDescription(index);
4135             }
4136         }, ac);
4137     }
4138     /*
4139      * return icon description at the specified index
4140      */
4141     private boolean doAccessibleActions(final AccessibleContext ac, final String name) {
4142         debugString("[INFO]: doAccessibleActions: action name = "+name);
4143         if (ac == null || name == null) {
4144             return false;
4145         }
4146         return InvocationUtils.invokeAndWait(new Callable<Boolean>() {
4147             @Override
4148             public Boolean call() throws Exception {
4149                 AccessibleAction aa = ac.getAccessibleAction();
4150                 if (aa == null) {
4151                     return false;
4152                 }
4153                 int index = -1;
4154                 int numActions = aa.getAccessibleActionCount();
4155                 for (int i = 0; i < numActions; i++) {
4156                     String actionName = aa.getAccessibleActionDescription(i);
4157                     if (name.equals(actionName)) {
4158                         index = i;
4159                         break;
4160                     }
4161                 }
4162                 if (index == -1) {
4163                     return false;
4164                 }
4165                 boolean retval = aa.doAccessibleAction(index);
4166                 return retval;
4167             }
4168         }, ac);
4169     }
4170 
4171     /* ===== AT utility methods ===== */
4172 
4173     /**
4174      * Sets the contents of an AccessibleContext that
4175      * implements AccessibleEditableText with the
4176      * specified text string.
4177      * Returns whether successful.
4178      */
4179     private boolean setTextContents(final AccessibleContext ac, final String text) {
4180         debugString("[INFO]: setTextContents: ac = "+ac+"; text = "+text);
4181 
4182         if (! (ac instanceof AccessibleEditableText)) {
4183             debugString("[WARN]:   ac not instanceof AccessibleEditableText: "+ac);
4184             return false;
4185         }
4186         if (text == null) {
4187             debugString("[WARN]:   text is null");
4188             return false;
4189         }
4190 
4191         return InvocationUtils.invokeAndWait(new Callable<Boolean>() {
4192             @Override
4193             public Boolean call() throws Exception {
4194                 // check whether the text field is editable
4195                 AccessibleStateSet ass = ac.getAccessibleStateSet();
4196                 if (!ass.contains(AccessibleState.ENABLED)) {
4197                     return false;
4198                 }
4199                 ((AccessibleEditableText) ac).setTextContents(text);
4200                 return true;
4201             }
4202         }, ac);
4203     }
4204 
4205     /**
4206      * Returns the Accessible Context of an Internal Frame object that is
4207      * the ancestor of a given object.  If the object is an Internal Frame
4208      * object or an Internal Frame ancestor object was found, returns the
4209      * object's AccessibleContext.
4210      * If there is no ancestor object that has an Accessible Role of
4211      * Internal Frame, returns (AccessibleContext)0.
4212      */
4213     private AccessibleContext getInternalFrame (AccessibleContext ac) {
4214         return getParentWithRole(ac, AccessibleRole.INTERNAL_FRAME.toString());
4215     }
4216 
4217     /**
4218      * Returns the Accessible Context for the top level object in
4219      * a Java Window.  This is same Accessible Context that is obtained
4220      * from GetAccessibleContextFromHWND for that window.  Returns
4221      * (AccessibleContext)0 on error.
4222      */
4223     private AccessibleContext getTopLevelObject (final AccessibleContext ac) {
4224         debugString("[INFO]: getTopLevelObject; ac = "+ac);
4225         if (ac == null) {
4226             return null;
4227         }
4228         return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
4229             @Override
4230             public AccessibleContext call() throws Exception {
4231                 if (ac.getAccessibleRole() == AccessibleRole.DIALOG) {
4232                     // return the dialog, not the parent window
4233                     return ac;
4234                 }
4235 
4236                 Accessible parent = ac.getAccessibleParent();
4237                 if (parent == null) {
4238                     return ac;
4239                 }
4240                 Accessible tmp = parent;
4241                 while (tmp != null && tmp.getAccessibleContext() != null) {
4242                     AccessibleContext ac2 = tmp.getAccessibleContext();
4243                     if (ac2 != null && ac2.getAccessibleRole() == AccessibleRole.DIALOG) {
4244                         // return the dialog, not the parent window
4245                         return ac2;
4246                     }
4247                     parent = tmp;
4248                     tmp = parent.getAccessibleContext().getAccessibleParent();
4249                 }
4250                 return parent.getAccessibleContext();
4251             }
4252         }, ac);
4253     }
4254 
4255     /**
4256      * Returns the parent AccessibleContext that has the specified AccessibleRole.
4257      * Returns null on error or if the AccessibleContext does not exist.
4258      */
4259     private AccessibleContext getParentWithRole (final AccessibleContext ac,
4260                                                  final String roleName) {
4261         debugString("[INFO]: getParentWithRole; ac = "+ac + "\n role = "+roleName);

4262         if (ac == null || roleName == null) {
4263             return null;
4264         }
4265 
4266         return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() {
4267             @Override
4268             public AccessibleContext call() throws Exception {
4269                 AccessibleRole role = AccessBridge.this.accessibleRoleMap.get(roleName);
4270                 if (role == null) {
4271                     return ac;
4272                 }
4273 
4274                 Accessible parent = ac.getAccessibleParent();
4275                 if (parent == null && ac.getAccessibleRole() == role) {
4276                     return ac;
4277                 }
4278 
4279                 Accessible tmp = parent;
4280                 AccessibleContext tmp_ac = null;
4281 


4297     /**
4298      * Returns the parent AccessibleContext that has the specified AccessibleRole.
4299      * Otherwise, returns the top level object for the Java Window.
4300      * Returns (AccessibleContext)0 on error.
4301      */
4302     private AccessibleContext getParentWithRoleElseRoot (AccessibleContext ac,
4303                                                          String roleName) {
4304         AccessibleContext retval = getParentWithRole(ac, roleName);
4305         if (retval == null) {
4306             retval = getTopLevelObject(ac);
4307         }
4308         return retval;
4309     }
4310 
4311     /**
4312      * Returns how deep in the object hierarchy a given object is.
4313      * The top most object in the object hierarchy has an object depth of 0.
4314      * Returns -1 on error.
4315      */
4316     private int getObjectDepth(final AccessibleContext ac) {
4317         debugString("[INFO]: getObjectDepth: ac = "+ac);
4318 
4319         if (ac == null) {
4320             return -1;
4321         }
4322         return InvocationUtils.invokeAndWait(new Callable<Integer>() {
4323             @Override
4324             public Integer call() throws Exception {
4325                 int count = 0;
4326                 Accessible parent = ac.getAccessibleParent();
4327                 if (parent == null) {
4328                     return count;
4329                 }
4330                 Accessible tmp = parent;
4331                 while (tmp != null && tmp.getAccessibleContext() != null) {
4332                     parent = tmp;
4333                     tmp = parent.getAccessibleContext().getAccessibleParent();
4334                     count++;
4335                 }
4336                 return count;
4337             }
4338         }, ac);
4339     }
4340 
4341     /**
4342      * Returns the Accessible Context of the current ActiveDescendent of an object.
4343      * Returns (AccessibleContext)0 on error.
4344      */
4345     private AccessibleContext getActiveDescendent (final AccessibleContext ac) {
4346         debugString("[INFO]: getActiveDescendent: ac = "+ac);
4347         if (ac == null) {
4348             return null;
4349         }
4350         // workaround for JTree bug where the only possible active
4351         // descendent is the JTree root
4352         final Accessible parent = InvocationUtils.invokeAndWait(new Callable<Accessible>() {
4353             @Override
4354             public Accessible call() throws Exception {
4355                 return ac.getAccessibleParent();
4356             }
4357         }, ac);
4358 
4359         if (parent != null) {
4360             Accessible child = InvocationUtils.invokeAndWait(new Callable<Accessible>() {
4361                 @Override
4362                 public Accessible call() throws Exception {
4363                     int indexInParent = ac.getAccessibleIndexInParent();
4364                     return parent.getAccessibleContext().getAccessibleChild(indexInParent);
4365                 }
4366             }, ac);


4394                 if (a == null) {
4395                     return null;
4396                 }
4397                 return a.getAccessibleContext();
4398             }
4399         }, ac);
4400     }
4401 
4402 
4403     /**
4404      * Additional methods for Teton
4405      */
4406 
4407     /**
4408      * Gets the AccessibleName for a component based upon the JAWS algorithm.
4409      * Returns whether successful.
4410      *
4411      * Bug ID 4916682 - Implement JAWS AccessibleName policy
4412      */
4413     private String getJAWSAccessibleName(final AccessibleContext ac) {
4414         debugString("[INFO]:  getJAWSAccessibleName");
4415         if (ac == null) {
4416             return null;
4417         }
4418         // placeholder
4419         return InvocationUtils.invokeAndWait(new Callable<String>() {
4420             @Override
4421             public String call() throws Exception {
4422                 return ac.getAccessibleName();
4423             }
4424         }, ac);
4425     }
4426 
4427     /**
4428      * Request focus for a component. Returns whether successful;
4429      *
4430      * Bug ID 4944757 - requestFocus method needed
4431      */
4432     private boolean requestFocus(final AccessibleContext ac) {
4433         debugString("[INFO]:  requestFocus");
4434         if (ac == null) {
4435             return false;
4436         }
4437         return InvocationUtils.invokeAndWait(new Callable<Boolean>() {
4438             @Override
4439             public Boolean call() throws Exception {
4440                 AccessibleComponent acomp = ac.getAccessibleComponent();
4441                 if (acomp == null) {
4442                     return false;
4443                 }
4444                 acomp.requestFocus();
4445                 return ac.getAccessibleStateSet().contains(AccessibleState.FOCUSED);
4446             }
4447         }, ac);
4448     }
4449 
4450     /**
4451      * Selects text between two indices.  Selection includes the
4452      * text at the start index and the text at the end index. Returns
4453      * whether successful;
4454      *
4455      * Bug ID 4944758 - selectTextRange method needed
4456      */
4457     private boolean selectTextRange(final AccessibleContext ac, final int startIndex, final int endIndex) {
4458         debugString("[INFO]:  selectTextRange: start = "+startIndex+"; end = "+endIndex);
4459         if (ac == null) {
4460             return false;
4461         }
4462         return InvocationUtils.invokeAndWait(new Callable<Boolean>() {
4463             @Override
4464             public Boolean call() throws Exception {
4465                 AccessibleText at = ac.getAccessibleText();
4466                 if (!(at instanceof AccessibleEditableText)) {
4467                     return false;
4468                 }
4469                 ((AccessibleEditableText) at).selectText(startIndex, endIndex);
4470 
4471                 boolean result = at.getSelectionStart() == startIndex &&
4472                         at.getSelectionEnd() == endIndex;
4473                 return result;
4474             }
4475         }, ac);
4476     }
4477 
4478     /**
4479      * Set the caret to a text position. Returns whether successful;
4480      *
4481      * Bug ID 4944770 - setCaretPosition method needed
4482      */
4483     private boolean setCaretPosition(final AccessibleContext ac, final int position) {
4484         debugString("[INFO]: setCaretPosition: position = "+position);
4485         if (ac == null) {
4486             return false;
4487         }
4488         return InvocationUtils.invokeAndWait(new Callable<Boolean>() {
4489             @Override
4490             public Boolean call() throws Exception {
4491                 AccessibleText at = ac.getAccessibleText();
4492                 if (!(at instanceof AccessibleEditableText)) {
4493                     return false;
4494                 }
4495                 ((AccessibleEditableText) at).selectText(position, position);
4496                 return at.getCaretPosition() == position;
4497             }
4498         }, ac);
4499     }
4500 
4501     /**
4502      * Gets the number of visible children of an AccessibleContext.
4503      *
4504      * Bug ID 4944762- getVisibleChildren for list-like components needed
4505      */
4506     private int _visibleChildrenCount;
4507     private AccessibleContext _visibleChild;
4508     private int _currentVisibleIndex;
4509     private boolean _foundVisibleChild;
4510 
4511     private int getVisibleChildrenCount(AccessibleContext ac) {
4512         debugString("[INFO]: getVisibleChildrenCount");
4513         if (ac == null) {
4514             return -1;
4515         }
4516         _visibleChildrenCount = 0;
4517         _getVisibleChildrenCount(ac);
4518         debugString("[INFO]:   _visibleChildrenCount = "+_visibleChildrenCount);
4519         return _visibleChildrenCount;
4520     }
4521 
4522     /*
4523      * Recursively descends AccessibleContext and gets the number
4524      * of visible children
4525      */
4526     private void _getVisibleChildrenCount(final AccessibleContext ac) {
4527         if (ac == null)
4528             return;
4529         if(ac instanceof AccessibleExtendedTable) {
4530             _getVisibleChildrenCount((AccessibleExtendedTable)ac);
4531             return;
4532         }
4533         int numChildren = InvocationUtils.invokeAndWait(new Callable<Integer>() {
4534             @Override
4535             public Integer call() throws Exception {
4536                 return ac.getAccessibleChildrenCount();
4537             }
4538         }, ac);


4638 
4639                 if (InvocationUtils.invokeAndWait(new Callable<Integer>() {
4640                     @Override
4641                     public Integer call() throws Exception {
4642                         return ac2.getAccessibleChildrenCount();
4643                     }
4644                 }, acTable) > 0) {
4645                     _getVisibleChildrenCount(ac2);
4646                 }
4647             }
4648         }
4649     }
4650 
4651     /**
4652      * Gets the visible child of an AccessibleContext at the
4653      * specified index
4654      *
4655      * Bug ID 4944762- getVisibleChildren for list-like components needed
4656      */
4657     private AccessibleContext getVisibleChild(AccessibleContext ac, int index) {
4658         debugString("[INFO]: getVisibleChild: index = "+index);
4659         if (ac == null) {
4660             return null;
4661         }
4662         _visibleChild = null;
4663         _currentVisibleIndex = 0;
4664         _foundVisibleChild = false;
4665         _getVisibleChild(ac, index);
4666 
4667         if (_visibleChild != null) {
4668             debugString( "[INFO]:     getVisibleChild: found child = " +
4669                          InvocationUtils.invokeAndWait(new Callable<String>() {
4670                              @Override
4671                              public String call() throws Exception {
4672                                  return AccessBridge.this._visibleChild.getAccessibleName();
4673                              }
4674                          }, ac) );
4675         }
4676         return _visibleChild;
4677     }
4678 
4679     /*
4680      * Recursively searchs AccessibleContext and finds the visible component
4681      * at the specified index
4682      */
4683     private void _getVisibleChild(final AccessibleContext ac, final int index) {
4684         if (_visibleChild != null) {
4685             return;
4686         }
4687         if(ac instanceof AccessibleExtendedTable) {
4688             _getVisibleChild((AccessibleExtendedTable)ac, index);


4837 
4838         /**
4839         * Constructor
4840         */
4841         ObjectReferences() {
4842             refs = new ConcurrentHashMap<>(4);
4843         }
4844 
4845         /**
4846         * Debugging: dump the contents of ObjectReferences' refs Hashtable
4847         */
4848         String dump() {
4849             return refs.toString();
4850         }
4851 
4852         /**
4853         * Increment ref count; set to 1 if we have no references for it
4854         */
4855         void increment(Object o) {
4856             if (o == null){
4857                 debugString("[WARN]: ObjectReferences::increment - Passed in object is null");
4858                 return;
4859             }
4860 
4861             if (refs.containsKey(o)) {
4862                 (refs.get(o)).value++;
4863             } else {
4864                 refs.put(o, new Reference(1));
4865             }
4866         }
4867 
4868         /**
4869         * Decrement ref count; remove if count drops to 0
4870         */
4871         void decrement(Object o) {
4872             Reference aRef = refs.get(o);
4873             if (aRef != null) {
4874                 aRef.value--;
4875                 if (aRef.value == 0) {
4876                     refs.remove(o);
4877                 } else if (aRef.value < 0) {
4878                     debugString("[ERROR]: decrementing reference count below 0");
4879                 }
4880             } else {
4881                 debugString("[ERROR]: object to decrement not in ObjectReferences table");
4882             }
4883         }
4884 
4885     }
4886 
4887     /* ===== event handling code ===== */
4888 
4889    /**
4890      * native method for handling property change events
4891      */
4892     private native void propertyCaretChange(PropertyChangeEvent e,
4893                         AccessibleContext src,
4894                         int oldValue, int newValue);
4895     private native void propertyDescriptionChange(PropertyChangeEvent e,
4896                         AccessibleContext src,
4897                         String oldValue, String newValue);
4898     private native void propertyNameChange(PropertyChangeEvent e,
4899                         AccessibleContext src,
4900                         String oldValue, String newValue);
4901     private native void propertySelectionChange(PropertyChangeEvent e,


5196         /**
5197          * Turn off event monitoring for the event type passed in
5198          * If necessary, remove the appropriate event listener (if
5199          * no other event of that type is being listened for)
5200          */
5201         void removeAccessibilityEventNotification(long type) {
5202             long newEventMask = accessibilityEventMask & (~type);
5203             if ( ((accessibilityEventMask & PROPERTY_EVENTS) != 0) &&
5204                  ((newEventMask & PROPERTY_EVENTS) == 0) ) {
5205                 AccessibilityEventMonitor.removePropertyChangeListener(this);
5206             }
5207             accessibilityEventMask = newEventMask;
5208         }
5209 
5210         /**
5211          *  ------- property change event glue
5212          */
5213         // This is invoked on the EDT , as
5214         public void propertyChange(PropertyChangeEvent e) {
5215 
5216             accessBridge.debugString("[INFO]: propertyChange(" + e.toString() + ") called");
5217 
5218             if (e != null && (accessibilityEventMask & PROPERTY_EVENTS) != 0) {
5219                 Object o = e.getSource();
5220                 AccessibleContext ac;
5221 
5222                 if (o instanceof AccessibleContext) {
5223                     ac = (AccessibleContext) o;
5224                 } else {
5225                     Accessible a = Translator.getAccessible(e.getSource());
5226                     if (a == null)
5227                         return;
5228                     else
5229                         ac = a.getAccessibleContext();
5230                 }
5231                 if (ac != null) {
5232                     InvocationUtils.registerAccessibleContext(ac, AppContext.getAppContext());
5233 
5234                     accessBridge.debugString("[INFO]: AccessibleContext: " + ac);
5235                     String propertyName = e.getPropertyName();
5236 
5237                     if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_CARET_PROPERTY) == 0) {
5238                         int oldValue = 0;
5239                         int newValue = 0;
5240 
5241                         if (e.getOldValue() instanceof Integer) {
5242                             oldValue = ((Integer) e.getOldValue()).intValue();
5243                         }
5244                         if (e.getNewValue() instanceof Integer) {
5245                             newValue = ((Integer) e.getNewValue()).intValue();
5246                         }
5247                         accessBridge.debugString("[INFO]:  - about to call propertyCaretChange()   old value: " + oldValue + "new value: " + newValue);

5248                         accessBridge.propertyCaretChange(e, ac, oldValue, newValue);
5249 
5250                     } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_DESCRIPTION_PROPERTY) == 0) {
5251                         String oldValue = null;
5252                         String newValue = null;
5253 
5254                         if (e.getOldValue() != null) {
5255                             oldValue = e.getOldValue().toString();
5256                         }
5257                         if (e.getNewValue() != null) {
5258                             newValue = e.getNewValue().toString();
5259                         }
5260                         accessBridge.debugString("[INFO]:  - about to call propertyDescriptionChange()   old value: " + oldValue + "new value: " + newValue);

5261                         accessBridge.propertyDescriptionChange(e, ac, oldValue, newValue);
5262 
5263                     } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_NAME_PROPERTY) == 0) {
5264                         String oldValue = null;
5265                         String newValue = null;
5266 
5267                         if (e.getOldValue() != null) {
5268                             oldValue = e.getOldValue().toString();
5269                         }
5270                         if (e.getNewValue() != null) {
5271                             newValue = e.getNewValue().toString();
5272                         }
5273                         accessBridge.debugString("[INFO]:  - about to call propertyNameChange()   old value: " + oldValue + " new value: " + newValue);

5274                         accessBridge.propertyNameChange(e, ac, oldValue, newValue);
5275 
5276                     } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY) == 0) {
5277                         accessBridge.debugString("[INFO]:  - about to call propertySelectionChange() " + ac +  "   " + Thread.currentThread() + "   " + e.getSource());
5278 
5279                         accessBridge.propertySelectionChange(e, ac);
5280 
5281                     } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_STATE_PROPERTY) == 0) {
5282                         String oldValue = null;
5283                         String newValue = null;
5284 
5285                         // Localization fix requested by Oliver for EA-1
5286                         if (e.getOldValue() != null) {
5287                             AccessibleState oldState = (AccessibleState) e.getOldValue();
5288                             oldValue = oldState.toDisplayString(Locale.US);
5289                         }
5290                         if (e.getNewValue() != null) {
5291                             AccessibleState newState = (AccessibleState) e.getNewValue();
5292                             newValue = newState.toDisplayString(Locale.US);
5293                         }
5294 
5295                         accessBridge.debugString("[INFO]:  - about to call propertyStateChange()");
5296                         accessBridge.propertyStateChange(e, ac, oldValue, newValue);
5297 
5298                     } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_TEXT_PROPERTY) == 0) {
5299                         accessBridge.debugString("[INFO]:  - about to call propertyTextChange()");
5300                         accessBridge.propertyTextChange(e, ac);
5301 
5302                     } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_VALUE_PROPERTY) == 0) {  // strings 'cause of floating point, etc.
5303                         String oldValue = null;
5304                         String newValue = null;
5305 
5306                         if (e.getOldValue() != null) {
5307                             oldValue = e.getOldValue().toString();
5308                         }
5309                         if (e.getNewValue() != null) {
5310                             newValue = e.getNewValue().toString();
5311                         }
5312                         accessBridge.debugString("[INFO]:  - about to call propertyDescriptionChange()");
5313                         accessBridge.propertyValueChange(e, ac, oldValue, newValue);
5314 
5315                     } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY) == 0) {
5316                         accessBridge.propertyVisibleDataChange(e, ac);
5317 
5318                     } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_CHILD_PROPERTY) == 0) {
5319                         AccessibleContext oldAC = null;
5320                         AccessibleContext newAC = null;
5321                         Accessible a;
5322 
5323                         if (e.getOldValue() instanceof AccessibleContext) {
5324                             oldAC = (AccessibleContext) e.getOldValue();
5325                             InvocationUtils.registerAccessibleContext(oldAC, AppContext.getAppContext());
5326                         }
5327                         if (e.getNewValue() instanceof AccessibleContext) {
5328                             newAC = (AccessibleContext) e.getNewValue();
5329                             InvocationUtils.registerAccessibleContext(newAC, AppContext.getAppContext());
5330                         }
5331                         accessBridge.debugString("[INFO]:  - about to call propertyChildChange()   old AC: " + oldAC + "new AC: " + newAC);

5332                         accessBridge.propertyChildChange(e, ac, oldAC, newAC);
5333 
5334                     } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY) == 0) {
5335                         handleActiveDescendentEvent(e, ac);
5336                     }
5337                 }
5338             }
5339         }
5340 
5341         /*
5342         * Handle an ActiveDescendent PropertyChangeEvent.  This
5343         * method works around a JTree bug where ActiveDescendent
5344         * PropertyChangeEvents have the wrong parent.
5345         */
5346         private AccessibleContext prevAC = null; // previous AccessibleContext
5347 
5348         private void handleActiveDescendentEvent(PropertyChangeEvent e,
5349                                                  AccessibleContext ac) {
5350             if (e == null || ac == null)
5351                 return;


5374             if (e.getNewValue() instanceof Accessible) {
5375                 newAC = ((Accessible) e.getNewValue()).getAccessibleContext();
5376             } else if (e.getNewValue() instanceof Component) {
5377                 a = Translator.getAccessible(e.getNewValue());
5378                 if (a != null) {
5379                     newAC = a.getAccessibleContext();
5380                 }
5381             }
5382             if (newAC != null) {
5383                 Accessible parent = newAC.getAccessibleParent();
5384                 if (parent instanceof JTree) {
5385                     // use a new AccessibleJTreeNode with the right parent
5386                     JTree tree = (JTree)parent;
5387                     newAC = new AccessibleJTreeNode(tree,
5388                                                     tree.getSelectionPath(),
5389                                                     null);
5390                 }
5391             }
5392             prevAC = newAC;
5393 
5394             accessBridge.debugString("[INFO]:   - about to call propertyActiveDescendentChange()   AC: " + ac + "   old AC: " + oldAC + "new AC: " + newAC);



5395             InvocationUtils.registerAccessibleContext(oldAC, AppContext.getAppContext());
5396             InvocationUtils.registerAccessibleContext(newAC, AppContext.getAppContext());
5397             accessBridge.propertyActiveDescendentChange(e, ac, oldAC, newAC);
5398         }
5399 
5400         /**
5401         *  ------- focus event glue
5402         */
5403         private boolean stateChangeListenerAdded = false;
5404 
5405         public void focusGained(FocusEvent e) {
5406             processFocusGained();
5407         }
5408 
5409         public void stateChanged(ChangeEvent e) {
5410             processFocusGained();
5411         }
5412 
5413         private void processFocusGained() {
5414             Component focusOwner = KeyboardFocusManager.


5419 
5420             // Only menus and popup selections are handled by the JRootPane.
5421             if (focusOwner instanceof JRootPane) {
5422                 MenuElement [] path =
5423                 MenuSelectionManager.defaultManager().getSelectedPath();
5424                 if (path.length > 1) {
5425                     Component penult = path[path.length-2].getComponent();
5426                     Component last = path[path.length-1].getComponent();
5427 
5428                     if (last instanceof JPopupMenu) {
5429                         // This is a popup with nothing in the popup
5430                         // selected. The menu itself is selected.
5431                         FocusEvent e = new FocusEvent(penult, FocusEvent.FOCUS_GAINED);
5432                         AccessibleContext context = penult.getAccessibleContext();
5433                         InvocationUtils.registerAccessibleContext(context, SunToolkit.targetToAppContext(penult));
5434                         accessBridge.focusGained(e, context);
5435                     } else if (penult instanceof JPopupMenu) {
5436                         // This is a popup with an item selected
5437                         FocusEvent e =
5438                         new FocusEvent(last, FocusEvent.FOCUS_GAINED);

5439                         AccessibleContext focusedAC = last.getAccessibleContext();
5440                         InvocationUtils.registerAccessibleContext(focusedAC, SunToolkit.targetToAppContext(last));
5441                         accessBridge.debugString("[INFO]:  - about to call focusGained()   AC: " + focusedAC);
5442                         accessBridge.focusGained(e, focusedAC);
5443                     }
5444                 }
5445             } else {
5446                 // The focus owner has the selection.
5447                 if (focusOwner instanceof Accessible) {
5448                     FocusEvent e = new FocusEvent(focusOwner,
5449                                                   FocusEvent.FOCUS_GAINED);

5450                     AccessibleContext focusedAC = focusOwner.getAccessibleContext();
5451                     InvocationUtils.registerAccessibleContext(focusedAC, SunToolkit.targetToAppContext(focusOwner));
5452                     accessBridge.debugString("[INFO]:  - about to call focusGained()   AC: " + focusedAC);
5453                     accessBridge.focusGained(e, focusedAC);
5454                 }
5455             }
5456         }
5457 
5458         public void focusLost(FocusEvent e) {
5459             if (e != null && (javaEventMask & FOCUS_LOST_EVENTS) != 0) {
5460                 Accessible a = Translator.getAccessible(e.getSource());
5461                 if (a != null) {
5462                     accessBridge.debugString("[INFO]:  - about to call focusLost()   AC: " + a.getAccessibleContext());

5463                     AccessibleContext context = a.getAccessibleContext();
5464                     InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());
5465                     accessBridge.focusLost(e, context);
5466                 }
5467             }
5468         }
5469 
5470         /**
5471          *  ------- caret event glue
5472          */
5473         public void caretUpdate(CaretEvent e) {
5474             if (e != null && (javaEventMask & CARET_UPATE_EVENTS) != 0) {
5475                 Accessible a = Translator.getAccessible(e.getSource());
5476                 if (a != null) {
5477                     AccessibleContext context = a.getAccessibleContext();
5478                     InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext());
5479                     accessBridge.caretUpdate(e, context);
5480                 }
5481             }
5482         }


6145         private TreePath path = null;
6146         private Accessible accessibleParent = null;
6147         private int index = 0;
6148         private boolean isLeaf = false;
6149 
6150         /**
6151          *  Constructs an AccessibleJTreeNode
6152          */
6153         AccessibleJTreeNode(JTree t, TreePath p, Accessible ap) {
6154             tree = t;
6155             path = p;
6156             accessibleParent = ap;
6157             if (t != null)
6158                 treeModel = t.getModel();
6159             if (p != null) {
6160                 obj = p.getLastPathComponent();
6161                 if (treeModel != null && obj != null) {
6162                     isLeaf = treeModel.isLeaf(obj);
6163                 }
6164             }
6165             debugString("[INFO]: AccessibleJTreeNode: name = "+getAccessibleName()+"; TreePath = "+p+"; parent = "+ap);
6166         }
6167 
6168         private TreePath getChildTreePath(int i) {
6169             // Tree nodes can't be so complex that they have
6170             // two sets of children -> we're ignoring that case
6171             if (i < 0 || i >= getAccessibleChildrenCount() || path == null || treeModel == null) {
6172                 return null;
6173             } else {
6174                 Object childObj = treeModel.getChild(obj, i);
6175                 Object[] objPath = path.getPath();
6176                 Object[] objChildPath = new Object[objPath.length+1];
6177                 java.lang.System.arraycopy(objPath, 0, objChildPath, 0, objPath.length);
6178                 objChildPath[objChildPath.length-1] = childObj;
6179                 return new TreePath(objChildPath);
6180             }
6181         }
6182 
6183         /**
6184          * Get the AccessibleContext associated with this tree node.
6185          * In the implementation of the Java Accessibility API for
6186          * this class, return this object, which is its own
6187          * AccessibleContext.
6188          *
6189          * @return this object
6190         */
6191         public AccessibleContext getAccessibleContext() {
6192             return this;
6193         }
6194 
6195         private AccessibleContext getCurrentAccessibleContext() {
6196             Component c = getCurrentComponent();
6197             if (c instanceof Accessible) {
6198                return (c.getAccessibleContext());
6199             } else {
6200                 return null;
6201             }
6202         }
6203 
6204         private Component getCurrentComponent() {
6205             debugString("[INFO]: AccessibleJTreeNode: getCurrentComponent");
6206             // is the object visible?
6207             // if so, get row, selected, focus & leaf state,
6208             // and then get the renderer component and return it
6209             if (tree != null && tree.isVisible(path)) {
6210                 TreeCellRenderer r = tree.getCellRenderer();
6211                 if (r == null) {
6212                     debugString("[WARN]:  returning null 1");
6213                     return null;
6214                 }
6215                 TreeUI ui = tree.getUI();
6216                 if (ui != null) {
6217                     int row = ui.getRowForPath(tree, path);
6218                     boolean selected = tree.isPathSelected(path);
6219                     boolean expanded = tree.isExpanded(path);
6220                     boolean hasFocus = false; // how to tell?? -PK
6221                     Component retval = r.getTreeCellRendererComponent(tree, obj,
6222                                                                       selected, expanded,
6223                                                                       isLeaf, row, hasFocus);
6224                     debugString("[INFO]:   returning = "+retval.getClass());
6225                     return retval;
6226                 }
6227             }
6228             debugString("[WARN]:  returning null 2");
6229             return null;
6230         }
6231 
6232         // AccessibleContext methods
6233 
6234         /**
6235          * Get the accessible name of this object.
6236          *
6237          * @return the localized name of the object; null if this
6238          * object does not have a name
6239          */
6240         public String getAccessibleName() {
6241             debugString("[INFO]: AccessibleJTreeNode: getAccessibleName");
6242             AccessibleContext ac = getCurrentAccessibleContext();
6243             if (ac != null) {
6244                 String name = ac.getAccessibleName();
6245                 if ((name != null) && (!name.isEmpty())) {
6246                     String retval = ac.getAccessibleName();
6247                     debugString("[INFO]:     returning "+retval);
6248                     return retval;
6249                 } else {
6250                     return null;
6251                 }
6252             }
6253             if ((accessibleName != null) && (accessibleName.isEmpty())) {
6254                 return accessibleName;
6255             } else {
6256                 return null;
6257             }
6258         }
6259 
6260         /**
6261          * Set the localized accessible name of this object.
6262          *
6263          * @param s the new localized name of the object.
6264          */
6265         public void setAccessibleName(String s) {
6266             AccessibleContext ac = getCurrentAccessibleContext();
6267             if (ac != null) {


< prev index next >