1 /* 2 * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.java.accessibility; 27 28 import java.awt.*; 29 import java.awt.event.*; 30 import java.util.*; 31 import java.lang.*; 32 import java.lang.reflect.*; 33 34 import java.beans.*; 35 import javax.swing.*; 36 import javax.swing.event.*; 37 import javax.swing.text.*; 38 import javax.swing.tree.*; 39 import javax.swing.table.*; 40 import javax.swing.plaf.TreeUI; 41 42 import javax.accessibility.*; 43 import com.sun.java.accessibility.util.*; 44 import sun.awt.AWTAccessor; 45 import sun.awt.AppContext; 46 import sun.awt.SunToolkit; 47 48 import java.util.concurrent.Callable; 49 import java.util.concurrent.ConcurrentHashMap; 50 import java.util.concurrent.CountDownLatch; 51 52 /* 53 * Note: This class has to be public. It's loaded from the VM like this: 54 * Class.forName(atName).newInstance(); 55 */ 56 @jdk.Exported(false) 57 final public class AccessBridge extends AccessBridgeLoader { 58 59 private final String AccessBridgeVersion = 60 "AccessBridge 2.0.4"; 61 62 private static AccessBridge theAccessBridge; 63 private ObjectReferences references; 64 private EventHandler eventHandler; 65 private boolean runningOnJDK1_4 = false; 66 private boolean runningOnJDK1_5 = false; 67 68 // Maps AccessibleRoles strings to AccessibleRoles. 69 private ConcurrentHashMap<String,AccessibleRole> accessibleRoleMap = new ConcurrentHashMap<>(); 70 71 /** 72 If the object's role is in the following array getVirtualAccessibleName 73 will use the extended search algorithm. 74 */ 75 private ArrayList<AccessibleRole> extendedVirtualNameSearchRoles = new ArrayList<>(); 76 /** 77 If the role of the object's parent is in the following array 78 getVirtualAccessibleName will NOT use the extended search 79 algorithm even if the object's role is in the 80 extendedVirtualNameSearchRoles array. 81 */ 82 private ArrayList<AccessibleRole> noExtendedVirtualNameSearchParentRoles = new ArrayList<>(); 83 84 /** 85 * AccessBridge constructor 86 * 87 * Note: This constructor has to be public. It's called from the VM like this: 88 * Class.forName(atName).newInstance(); 89 */ 90 public AccessBridge() { 91 super(); 92 theAccessBridge = this; 93 references = new ObjectReferences(); 94 95 // initialize shutdown hook 96 Runtime runTime = Runtime.getRuntime(); 97 shutdownHook hook = new shutdownHook(); 98 runTime.addShutdownHook(new Thread(hook)); 99 100 // initialize AccessibleRole map 101 initAccessibleRoleMap(); 102 103 // determine which version of the JDK is running 104 String version = getJavaVersionProperty(); 105 debugString("JDK version = "+version); 106 runningOnJDK1_4 = (version.compareTo("1.4") >= 0); 107 runningOnJDK1_5 = (version.compareTo("1.5") >= 0); 108 109 // initialize the methods that map HWNDs and Java top-level 110 // windows 111 if (initHWNDcalls() == true) { 112 113 // is this a JVM we can use? 114 // install JDK 1.2 and later Swing ToolKit listener 115 EventQueueMonitor.isGUIInitialized(); 116 117 // start the Java event handler 118 eventHandler = new EventHandler(this); 119 120 // register for menu selection events 121 if (runningOnJDK1_4) { 122 MenuSelectionManager.defaultManager().addChangeListener(eventHandler); 123 } 124 125 // register as a NativeWindowHandler 126 addNativeWindowHandler(new DefaultNativeWindowHandler()); 127 128 // start in a new thread 129 Thread abthread = new Thread(new dllRunner()); 130 abthread.setDaemon(true); 131 abthread.start(); 132 debugString("AccessBridge started"); 133 } 134 } 135 136 /* 137 * adaptor to run the AccessBridge DLL 138 */ 139 private class dllRunner implements Runnable { 140 public void run() { 141 runDLL(); 142 } 143 } 144 145 /* 146 * shutdown hook 147 */ 148 private class shutdownHook implements Runnable { 149 150 public void run() { 151 debugString("***** shutdownHook: shutting down..."); 152 javaShutdown(); 153 } 154 } 155 156 157 /* 158 * Initialize the hashtable that maps Strings to AccessibleRoles. 159 */ 160 private void initAccessibleRoleMap() { 161 /* 162 * Initialize the AccessibleRoles map. This code uses methods in 163 * java.lang.reflect.* to build the map. 164 */ 165 try { 166 Class<?> clAccessibleRole = Class.forName ("javax.accessibility.AccessibleRole"); 167 if (null != clAccessibleRole) { 168 AccessibleRole roleUnknown = AccessibleRole.UNKNOWN; 169 Field [] fields = clAccessibleRole.getFields (); 170 int i = 0; 171 for (i = 0; i < fields.length; i ++) { 172 Field f = fields [i]; 173 if (javax.accessibility.AccessibleRole.class == f.getType ()) { 174 AccessibleRole nextRole = (AccessibleRole) (f.get (roleUnknown)); 175 String nextRoleString = nextRole.toDisplayString (Locale.US); 176 accessibleRoleMap.put (nextRoleString, nextRole); 177 } 178 } 179 } 180 } catch (Exception e) {} 181 182 /* 183 Build the extendedVirtualNameSearchRoles array list. I chose this method 184 because some of the Accessible Roles that need to be added to it are not 185 available in all versions of the J2SE that we want to support. 186 */ 187 extendedVirtualNameSearchRoles.add (AccessibleRole.COMBO_BOX); 188 try { 189 /* 190 Added in J2SE 1.4 191 */ 192 extendedVirtualNameSearchRoles.add (AccessibleRole.DATE_EDITOR); 193 } catch (NoSuchFieldError e) {} 194 extendedVirtualNameSearchRoles.add (AccessibleRole.LIST); 195 extendedVirtualNameSearchRoles.add (AccessibleRole.PASSWORD_TEXT); 196 extendedVirtualNameSearchRoles.add (AccessibleRole.SLIDER); 197 try { 198 /* 199 Added in J2SE 1.3 200 */ 201 extendedVirtualNameSearchRoles.add (AccessibleRole.SPIN_BOX); 202 } catch (NoSuchFieldError e) {} 203 extendedVirtualNameSearchRoles.add (AccessibleRole.TABLE); 204 extendedVirtualNameSearchRoles.add (AccessibleRole.TEXT); 205 extendedVirtualNameSearchRoles.add (AccessibleRole.UNKNOWN); 206 207 noExtendedVirtualNameSearchParentRoles.add (AccessibleRole.TABLE); 208 noExtendedVirtualNameSearchParentRoles.add (AccessibleRole.TOOL_BAR); 209 } 210 211 /** 212 * start the AccessBridge DLL running in its own thread 213 */ 214 private native void runDLL(); 215 216 /** 217 * debugging output (goes to OutputDebugStr()) 218 */ 219 private native void sendDebugString(String debugStr); 220 221 /** 222 * debugging output (goes to OutputDebugStr()) 223 */ 224 private void debugString(String debugStr) { 225 sendDebugString(debugStr); 226 } 227 228 /* ===== utility methods ===== */ 229 230 /** 231 * decrement the reference to the object (called by native code) 232 */ 233 private void decrementReference(Object o) { 234 references.decrement(o); 235 } 236 237 /** 238 * get the java.version property from the JVM 239 */ 240 private String getJavaVersionProperty() { 241 String s = System.getProperty("java.version"); 242 if (s != null) { 243 references.increment(s); 244 return s; 245 } 246 return null; 247 } 248 249 /** 250 * get the java.version property from the JVM 251 */ 252 private String getAccessBridgeVersion() { 253 String s = new String(AccessBridgeVersion); 254 references.increment(s); 255 return s; 256 } 257 258 /* ===== HWND/Java window mapping methods ===== */ 259 260 // Java toolkit methods for mapping HWNDs to Java components 261 private Method javaGetComponentFromNativeWindowHandleMethod; 262 private Method javaGetNativeWindowHandleFromComponentMethod; 263 264 // native jawt methods for mapping HWNDs to Java components 265 private native int isJAWTInstalled(); 266 267 private native int jawtGetNativeWindowHandleFromComponent(Component comp); 268 269 private native Component jawtGetComponentFromNativeWindowHandle(int handle); 270 271 Toolkit toolkit; 272 273 /** 274 * map an HWND to an AWT Component 275 */ 276 private boolean initHWNDcalls() { 277 Class<?> integerParemter[] = new Class<?>[1]; 278 integerParemter[0] = Integer.TYPE; 279 Class<?> componentParemter[] = new Class<?>[1]; 280 try { 281 componentParemter[0] = Class.forName("java.awt.Component"); 282 } catch (ClassNotFoundException e) { 283 debugString("Exception: " + e.toString()); 284 } 285 Object[] args = new Object[1]; 286 Component c; 287 boolean returnVal = false; 288 289 toolkit = Toolkit.getDefaultToolkit(); 290 291 if (useJAWT_DLL) { 292 returnVal = true; 293 } else { 294 // verify javaGetComponentFromNativeWindowHandle() method 295 // is present if JAWT.DLL is not installed 296 try { 297 javaGetComponentFromNativeWindowHandleMethod = 298 toolkit.getClass().getMethod( 299 "getComponentFromNativeWindowHandle", integerParemter); 300 if (javaGetComponentFromNativeWindowHandleMethod != null) { 301 try { 302 args[0] = new Integer(1); 303 c = (Component) javaGetComponentFromNativeWindowHandleMethod.invoke(toolkit, args); 304 returnVal = true; 305 } catch (InvocationTargetException e) { 306 debugString("Exception: " + e.toString()); 307 } catch (IllegalAccessException e) { 308 debugString("Exception: " + e.toString()); 309 } 310 } 311 } catch (NoSuchMethodException e) { 312 debugString("Exception: " + e.toString()); 313 } catch (SecurityException e) { 314 debugString("Exception: " + e.toString()); 315 } 316 317 // verify getComponentFromNativeWindowHandle() method 318 // is present if JAWT.DLL is not installed 319 try { 320 javaGetNativeWindowHandleFromComponentMethod = 321 toolkit.getClass().getMethod( 322 "getNativeWindowHandleFromComponent", componentParemter); 323 if (javaGetNativeWindowHandleFromComponentMethod != null) { 324 try { 325 args[0] = new Button("OK"); // need some Component... 326 Integer i = (Integer) javaGetNativeWindowHandleFromComponentMethod.invoke(toolkit, args); 327 returnVal = true; 328 } catch (InvocationTargetException e) { 329 debugString("Exception: " + e.toString()); 330 } catch (IllegalAccessException e) { 331 debugString("Exception: " + e.toString()); 332 } catch (Exception e) { 333 debugString("Exception: " + e.toString()); 334 } 335 } 336 } catch (NoSuchMethodException e) { 337 debugString("Exception: " + e.toString()); 338 } catch (SecurityException e) { 339 debugString("Exception: " + e.toString()); 340 } 341 } 342 return returnVal; 343 } 344 345 // native window handler interface 346 private interface NativeWindowHandler { 347 public Accessible getAccessibleFromNativeWindowHandle(int nativeHandle); 348 } 349 350 // hash table of native window handle to AccessibleContext mappings 351 static private ConcurrentHashMap<Integer,AccessibleContext> windowHandleToContextMap = new ConcurrentHashMap<>(); 352 353 // hash table of AccessibleContext to native window handle mappings 354 static private ConcurrentHashMap<AccessibleContext,Integer> contextToWindowHandleMap = new ConcurrentHashMap<>(); 355 356 /* 357 * adds a virtual window handler to our hash tables 358 */ 359 static private void registerVirtualFrame(final Accessible a, 360 Integer nativeWindowHandle ) { 361 if (a != null) { 362 AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() { 363 @Override 364 public AccessibleContext call() throws Exception { 365 return a.getAccessibleContext(); 366 } 367 }, a); 368 windowHandleToContextMap.put(nativeWindowHandle, ac); 369 contextToWindowHandleMap.put(ac, nativeWindowHandle); 370 } 371 } 372 373 /* 374 * removes a virtual window handler to our hash tables 375 */ 376 static private void revokeVirtualFrame(final Accessible a, 377 Integer nativeWindowHandle ) { 378 AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() { 379 @Override 380 public AccessibleContext call() throws Exception { 381 return a.getAccessibleContext(); 382 } 383 }, a); 384 windowHandleToContextMap.remove(nativeWindowHandle); 385 contextToWindowHandleMap.remove(ac); 386 } 387 388 // vector of native window handlers 389 private static Vector<NativeWindowHandler> nativeWindowHandlers = new Vector<>(); 390 391 /* 392 * adds a native window handler to our list 393 */ 394 private static void addNativeWindowHandler(NativeWindowHandler handler) { 395 if (handler == null) { 396 throw new IllegalArgumentException(); 397 } 398 nativeWindowHandlers.addElement(handler); 399 } 400 401 /* 402 * removes a native window handler to our list 403 */ 404 private static boolean removeNativeWindowHandler(NativeWindowHandler handler) { 405 if (handler == null) { 406 throw new IllegalArgumentException(); 407 } 408 return nativeWindowHandlers.removeElement(handler); 409 } 410 411 /** 412 * verifies that a native window handle is a Java window 413 */ 414 private boolean isJavaWindow(int nativeHandle) { 415 AccessibleContext ac = getContextFromNativeWindowHandle(nativeHandle); 416 if (ac != null) { 417 saveContextToWindowHandleMapping(ac, nativeHandle); 418 return true; 419 } 420 return false; 421 } 422 423 /* 424 * saves the mapping between an AccessibleContext and a window handle 425 */ 426 private void saveContextToWindowHandleMapping(AccessibleContext ac, 427 int nativeHandle) { 428 debugString("saveContextToWindowHandleMapping..."); 429 if (ac == null) { 430 return; 431 } 432 if (! contextToWindowHandleMap.containsKey(ac)) { 433 debugString("saveContextToWindowHandleMapping: ac = "+ac+"; handle = "+nativeHandle); 434 contextToWindowHandleMap.put(ac, nativeHandle); 435 } 436 } 437 438 /** 439 * maps a native window handle to an Accessible Context 440 */ 441 private AccessibleContext getContextFromNativeWindowHandle(int nativeHandle) { 442 // First, look for the Accessible in our hash table of 443 // virtual window handles. 444 AccessibleContext ac = windowHandleToContextMap.get(nativeHandle); 445 if(ac!=null) { 446 saveContextToWindowHandleMapping(ac, nativeHandle); 447 return ac; 448 } 449 450 // Next, look for the native window handle in our vector 451 // of native window handles. 452 int numHandlers = nativeWindowHandlers.size(); 453 for (int i = 0; i < numHandlers; i++) { 454 NativeWindowHandler nextHandler = nativeWindowHandlers.elementAt(i); 455 final Accessible a = nextHandler.getAccessibleFromNativeWindowHandle(nativeHandle); 456 if (a != null) { 457 ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() { 458 @Override 459 public AccessibleContext call() throws Exception { 460 return a.getAccessibleContext(); 461 } 462 }, a); 463 saveContextToWindowHandleMapping(ac, nativeHandle); 464 return ac; 465 } 466 } 467 // Not found. 468 return null; 469 } 470 471 /** 472 * maps an AccessibleContext to a native window handle 473 * returns 0 on error 474 */ 475 private int getNativeWindowHandleFromContext(AccessibleContext ac) { 476 debugString("getNativeWindowHandleFromContext: ac = "+ac); 477 try { 478 return contextToWindowHandleMap.get(ac); 479 } catch (Exception ex) { 480 return 0; 481 } 482 } 483 484 private class DefaultNativeWindowHandler implements NativeWindowHandler { 485 /* 486 * returns the Accessible associated with a native window 487 */ 488 public Accessible getAccessibleFromNativeWindowHandle(int nativeHandle) { 489 final Component c = getComponentFromNativeWindowHandle(nativeHandle); 490 if (c instanceof Accessible) { 491 AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() { 492 @Override 493 public AccessibleContext call() throws Exception { 494 return c.getAccessibleContext(); 495 } 496 }, c); 497 saveContextToWindowHandleMapping(ac, nativeHandle); 498 return (Accessible)c; 499 } else { 500 return null; 501 } 502 } 503 504 /** 505 * map an HWND to an AWT Component 506 */ 507 private Component getComponentFromNativeWindowHandle(int nativeHandle) { 508 if (useJAWT_DLL) { 509 debugString("*** calling jawtGetComponentFromNativeWindowHandle"); 510 return jawtGetComponentFromNativeWindowHandle(nativeHandle); 511 } else { 512 debugString("*** calling javaGetComponentFromNativeWindowHandle"); 513 Object[] args = new Object[1]; 514 if (javaGetComponentFromNativeWindowHandleMethod != null) { 515 try { 516 args[0] = nativeHandle; 517 Object o = javaGetComponentFromNativeWindowHandleMethod.invoke(toolkit, args); 518 if (o instanceof Accessible) { 519 final Accessible acc=(Accessible)o; 520 AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() { 521 @Override 522 public AccessibleContext call() throws Exception { 523 return acc.getAccessibleContext(); 524 } 525 }, (Component)o); 526 saveContextToWindowHandleMapping(ac,nativeHandle); 527 } 528 return (Component)o; 529 } catch (InvocationTargetException | IllegalAccessException e) { 530 debugString("Exception: " + e.toString()); 531 } 532 } 533 } 534 return null; 535 } 536 } 537 538 /** 539 * map an AWT Component to an HWND 540 */ 541 private int getNativeWindowHandleFromComponent(final Component target) { 542 if (useJAWT_DLL) { 543 debugString("*** calling jawtGetNativeWindowHandleFromComponent"); 544 return jawtGetNativeWindowHandleFromComponent(target); 545 } else { 546 Object[] args = new Object[1]; 547 debugString("*** calling javaGetNativeWindowHandleFromComponent"); 548 if (javaGetNativeWindowHandleFromComponentMethod != null) { 549 try { 550 args[0] = target; 551 Integer i = (Integer) javaGetNativeWindowHandleFromComponentMethod.invoke(toolkit, args); 552 // cache the mapping 553 AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() { 554 @Override 555 public AccessibleContext call() throws Exception { 556 return target.getAccessibleContext(); 557 } 558 }, target); 559 contextToWindowHandleMap.put(ac, i); 560 return i.intValue(); 561 } catch (InvocationTargetException e) { 562 debugString("Exception: " + e.toString()); 563 } catch (IllegalAccessException e) { 564 debugString("Exception: " + e.toString()); 565 } 566 } 567 } 568 return -1; 569 } 570 571 /* ===== AccessibleContext methods =====*/ 572 573 /* 574 * returns the inner-most AccessibleContext in parent at Point(x, y) 575 */ 576 private AccessibleContext getAccessibleContextAt(int x, int y, 577 AccessibleContext parent) { 578 if (parent == null) { 579 return null; 580 } 581 if (windowHandleToContextMap != null && 582 windowHandleToContextMap.containsValue(getRootAccessibleContext(parent))) { 583 // Path for applications that register their top-level 584 // windows with the AccessBridge (e.g., StarOffice 6.1) 585 return getAccessibleContextAt_1(x, y, parent); 586 } else { 587 // Path for applications that do not register 588 // their top-level windows with the AccessBridge 589 // (e.g., Swing/AWT applications) 590 return getAccessibleContextAt_2(x, y, parent); 591 } 592 } 593 594 /* 595 * returns the root accessible context 596 */ 597 private AccessibleContext getRootAccessibleContext(final AccessibleContext ac) { 598 if (ac == null) { 599 return null; 600 } 601 return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() { 602 @Override 603 public AccessibleContext call() throws Exception { 604 Accessible parent = ac.getAccessibleParent(); 605 if (parent == null) { 606 return ac; 607 } 608 Accessible tmp = parent.getAccessibleContext().getAccessibleParent(); 609 while (tmp != null) { 610 parent = tmp; 611 tmp = parent.getAccessibleContext().getAccessibleParent(); 612 } 613 return parent.getAccessibleContext(); 614 } 615 }, ac); 616 } 617 618 /* 619 * StarOffice version that does not use the EventQueueMonitor 620 */ 621 private AccessibleContext getAccessibleContextAt_1(final int x, final int y, 622 final AccessibleContext parent) { 623 debugString(" : getAccessibleContextAt_1 called"); 624 debugString(" -> x = " + x + " y = " + y + " parent = " + parent); 625 626 if (parent == null) return null; 627 final AccessibleComponent acmp = InvocationUtils.invokeAndWait(new Callable<AccessibleComponent>() { 628 @Override 629 public AccessibleComponent call() throws Exception { 630 return parent.getAccessibleComponent(); 631 } 632 }, parent); 633 if (acmp!=null) { 634 final Point loc = InvocationUtils.invokeAndWait(new Callable<Point>() { 635 @Override 636 public Point call() throws Exception { 637 return acmp.getLocation(); 638 } 639 }, parent); 640 final Accessible a = InvocationUtils.invokeAndWait(new Callable<Accessible>() { 641 @Override 642 public Accessible call() throws Exception { 643 return acmp.getAccessibleAt(new Point(x - loc.x, y - loc.y)); 644 } 645 }, parent); 646 if (a != null) { 647 AccessibleContext foundAC = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() { 648 @Override 649 public AccessibleContext call() throws Exception { 650 return a.getAccessibleContext(); 651 } 652 }, parent); 653 if (foundAC != null) { 654 if (foundAC != parent) { 655 // recurse down into the child 656 return getAccessibleContextAt_1(x - loc.x, y - loc.y, 657 foundAC); 658 } else 659 return foundAC; 660 } 661 } 662 } 663 return parent; 664 } 665 666 /* 667 * AWT/Swing version 668 */ 669 private AccessibleContext getAccessibleContextAt_2(final int x, final int y, 670 AccessibleContext parent) { 671 debugString("getAccessibleContextAt_2 called"); 672 debugString(" -> x = " + x + " y = " + y + " parent = " + parent); 673 674 return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() { 675 @Override 676 public AccessibleContext call() throws Exception { 677 Accessible a = EventQueueMonitor.getAccessibleAt(new Point(x, y)); 678 if (a != null) { 679 AccessibleContext childAC = a.getAccessibleContext(); 680 if (childAC != null) { 681 debugString(" returning childAC = " + childAC); 682 return childAC; 683 } 684 } 685 return null; 686 } 687 }, parent); 688 } 689 690 /** 691 * returns the Accessible that has focus 692 */ 693 private AccessibleContext getAccessibleContextWithFocus() { 694 Component c = AWTEventMonitor.getComponentWithFocus(); 695 if (c != null) { 696 final Accessible a = Translator.getAccessible(c); 697 if (a != null) { 698 AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() { 699 @Override 700 public AccessibleContext call() throws Exception { 701 return a.getAccessibleContext(); 702 } 703 }, c); 704 if (ac != null) { 705 return ac; 706 } 707 } 708 } 709 return null; 710 } 711 712 /** 713 * returns the AccessibleName from an AccessibleContext 714 */ 715 private String getAccessibleNameFromContext(final AccessibleContext ac) { 716 debugString("***** ac = "+ac.getClass()); 717 if (ac != null) { 718 String s = InvocationUtils.invokeAndWait(new Callable<String>() { 719 @Override 720 public String call() throws Exception { 721 return ac.getAccessibleName(); 722 } 723 }, ac); 724 if (s != null) { 725 references.increment(s); 726 debugString("Returning AccessibleName from Context: " + s); 727 return s; 728 } else { 729 return null; 730 } 731 } else { 732 debugString("getAccessibleNameFromContext; ac = null!"); 733 return null; 734 } 735 } 736 737 /** 738 * Returns an AccessibleName for a component using an algorithm optimized 739 * for the JAWS screen reader. This method is only intended for JAWS. All 740 * other uses are entirely optional. 741 */ 742 private String getVirtualAccessibleNameFromContext(final AccessibleContext ac) { 743 if (null != ac) { 744 /* 745 Step 1: 746 ======= 747 Determine if we can obtain the Virtual Accessible Name from the 748 Accessible Name or Accessible Description of the object. 749 */ 750 String nameString = InvocationUtils.invokeAndWait(new Callable<String>() { 751 @Override 752 public String call() throws Exception { 753 return ac.getAccessibleName(); 754 } 755 }, ac); 756 if ( ( null != nameString ) && ( 0 != nameString.length () ) ) { 757 debugString ("bk -- The Virtual Accessible Name was obtained from AccessibleContext::getAccessibleName."); 758 references.increment (nameString); 759 return nameString; 760 } 761 String descriptionString = InvocationUtils.invokeAndWait(new Callable<String>() { 762 @Override 763 public String call() throws Exception { 764 return ac.getAccessibleDescription(); 765 } 766 }, ac); 767 if ( ( null != descriptionString ) && ( 0 != descriptionString.length () ) ) { 768 debugString ("bk -- The Virtual Accessible Name was obtained from AccessibleContext::getAccessibleDescription."); 769 references.increment (descriptionString); 770 return descriptionString; 771 } 772 773 debugString ("The Virtual Accessible Name was not found using AccessibleContext::getAccessibleDescription. or getAccessibleName"); 774 /* 775 Step 2: 776 ======= 777 Decide whether the extended name search algorithm should be 778 used for this object. 779 */ 780 boolean bExtendedSearch = false; 781 AccessibleRole role = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() { 782 @Override 783 public AccessibleRole call() throws Exception { 784 return ac.getAccessibleRole(); 785 } 786 }, ac); 787 AccessibleContext parentContext = null; 788 AccessibleRole parentRole = AccessibleRole.UNKNOWN; 789 790 if ( extendedVirtualNameSearchRoles.contains (role) ) { 791 parentContext = getAccessibleParentFromContext (ac); 792 if ( null != parentContext ) { 793 final AccessibleContext parentContextInnerTemp = parentContext; 794 parentRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() { 795 @Override 796 public AccessibleRole call() throws Exception { 797 return parentContextInnerTemp.getAccessibleRole(); 798 } 799 }, ac); 800 if ( AccessibleRole.UNKNOWN != parentRole ) { 801 bExtendedSearch = true; 802 if ( noExtendedVirtualNameSearchParentRoles.contains (parentRole) ) { 803 bExtendedSearch = false; 804 } 805 } 806 } 807 } 808 809 if (false == bExtendedSearch) { 810 debugString ("bk -- getVirtualAccessibleNameFromContext will not use the extended name search algorithm. role = " + role.toDisplayString (Locale.US) ); 811 /* 812 Step 3: 813 ======= 814 We have determined that we should not use the extended name 815 search algorithm for this object (we must obtain the name of 816 the object from the object itself and not from neighboring 817 objects). However the object name cannot be obtained from 818 the Accessible Name or Accessible Description of the object. 819 820 Handle several special cases here that might yield a value for 821 the Virtual Accessible Name. Return null if the object does 822 not match the criteria for any of these special cases. 823 */ 824 if (AccessibleRole.LABEL == role) { 825 /* 826 Does the label support the Accessible Text Interface? 827 */ 828 final AccessibleText at = InvocationUtils.invokeAndWait(new Callable<AccessibleText>() { 829 @Override 830 public AccessibleText call() throws Exception { 831 return ac.getAccessibleText(); 832 } 833 }, ac); 834 if (null != at) { 835 int charCount = InvocationUtils.invokeAndWait(new Callable<Integer>() { 836 @Override 837 public Integer call() throws Exception { 838 return at.getCharCount(); 839 } 840 }, ac); 841 String text = getAccessibleTextRangeFromContext (ac, 0, charCount); 842 if (null != text) { 843 debugString ("bk -- The Virtual Accessible Name was obtained from the Accessible Text of the LABEL object."); 844 references.increment (text); 845 return text; 846 } 847 } 848 /* 849 Does the label support the Accessible Icon Interface? 850 */ 851 debugString ("bk -- Attempting to obtain the Virtual Accessible Name from the Accessible Icon information."); 852 final AccessibleIcon [] ai = InvocationUtils.invokeAndWait(new Callable<AccessibleIcon[]>() { 853 @Override 854 public AccessibleIcon[] call() throws Exception { 855 return ac.getAccessibleIcon(); 856 } 857 }, ac); 858 if ( (null != ai) && (ai.length > 0) ) { 859 String iconDescription = InvocationUtils.invokeAndWait(new Callable<String>() { 860 @Override 861 public String call() throws Exception { 862 return ai[0].getAccessibleIconDescription(); 863 } 864 }, ac); 865 if (iconDescription != null){ 866 debugString ("bk -- The Virtual Accessible Name was obtained from the description of the first Accessible Icon found in the LABEL object."); 867 references.increment (iconDescription); 868 return iconDescription; 869 } 870 } else { 871 parentContext = getAccessibleParentFromContext (ac); 872 if ( null != parentContext ) { 873 final AccessibleContext parentContextInnerTemp = parentContext; 874 parentRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() { 875 @Override 876 public AccessibleRole call() throws Exception { 877 return parentContextInnerTemp.getAccessibleRole(); 878 } 879 }, ac); 880 if ( AccessibleRole.TABLE == parentRole ) { 881 int indexInParent = InvocationUtils.invokeAndWait(new Callable<Integer>() { 882 @Override 883 public Integer call() throws Exception { 884 return ac.getAccessibleIndexInParent(); 885 } 886 }, ac); 887 final AccessibleContext acTableCell = getAccessibleChildFromContext (parentContext, indexInParent); 888 debugString ("bk -- Making a second attempt to obtain the Virtual Accessible Name from the Accessible Icon information for the Table Cell."); 889 if (acTableCell != null) { 890 final AccessibleIcon [] aiRet =InvocationUtils.invokeAndWait(new Callable<AccessibleIcon[]>() { 891 @Override 892 public AccessibleIcon[] call() throws Exception { 893 return acTableCell.getAccessibleIcon(); 894 } 895 }, ac); 896 if ( (null != aiRet) && (aiRet.length > 0) ) { 897 String iconDescription = InvocationUtils.invokeAndWait(new Callable<String>() { 898 public String call() { 899 return aiRet[0].getAccessibleIconDescription (); 900 } 901 }, ac); 902 if (iconDescription != null){ 903 debugString ("bk -- The Virtual Accessible Name was obtained from the description of the first Accessible Icon found in the Table Cell object."); 904 references.increment (iconDescription); 905 return iconDescription; 906 } 907 } 908 } 909 } 910 } 911 } 912 } else if ( (AccessibleRole.TOGGLE_BUTTON == role) || 913 (AccessibleRole.PUSH_BUTTON == role) ) { 914 /* 915 Does the button support the Accessible Icon Interface? 916 */ 917 debugString ("bk -- Attempting to obtain the Virtual Accessible Name from the Accessible Icon information."); 918 final AccessibleIcon [] ai = InvocationUtils.invokeAndWait(new Callable<AccessibleIcon []>() { 919 public AccessibleIcon [] call() { 920 return ac.getAccessibleIcon (); 921 } 922 }, ac); 923 if ( (null != ai) && (ai.length > 0) ) { 924 String iconDescription = InvocationUtils.invokeAndWait(new Callable<String>() { 925 public String call() { 926 return ai[0].getAccessibleIconDescription (); 927 } 928 }, ac); 929 if (iconDescription != null){ 930 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."); 931 references.increment (iconDescription); 932 return iconDescription; 933 } 934 } 935 } else if ( AccessibleRole.CHECK_BOX == role ) { 936 /* 937 NOTE: The only case I know of in which a check box does not 938 have a name is when that check box is contained in a table. 939 940 In this case it would be appropriate to use the display string 941 of the check box object as the name (in US English the display 942 string is typically either "true" or "false"). 943 944 I am using the AccessibleValue interface to obtain the display 945 string of the check box. If the Accessible Value is 1, I am 946 returning Boolean.TRUE.toString (), If the Accessible Value is 947 0, I am returning Boolean.FALSE.toString (). If the Accessible 948 Value is some other number, I will return the display string of 949 the current numerical value of the check box. 950 */ 951 final AccessibleValue av = InvocationUtils.invokeAndWait(new Callable<AccessibleValue>() { 952 @Override 953 public AccessibleValue call() throws Exception { 954 return ac.getAccessibleValue(); 955 } 956 }, ac); 957 if ( null != av ) { 958 nameString = null; 959 Number value = InvocationUtils.invokeAndWait(new Callable<Number>() { 960 @Override 961 public Number call() throws Exception { 962 return av.getCurrentAccessibleValue(); 963 } 964 }, ac); 965 if ( null != value ) { 966 if ( 1 == value.intValue () ) { 967 nameString = Boolean.TRUE.toString (); 968 } else if ( 0 == value.intValue () ) { 969 nameString = Boolean.FALSE.toString (); 970 } else { 971 nameString = value.toString (); 972 } 973 if ( null != nameString ) { 974 references.increment (nameString); 975 return nameString; 976 } 977 } 978 } 979 } 980 return null; 981 } 982 983 /* 984 + 985 Beginning of the extended name search 986 + 987 */ 988 final AccessibleContext parentContextOuterTemp = parentContext; 989 String parentName = InvocationUtils.invokeAndWait(new Callable<String>() { 990 @Override 991 public String call() throws Exception { 992 return parentContextOuterTemp.getAccessibleName(); 993 } 994 }, ac); 995 String parentDescription = InvocationUtils.invokeAndWait(new Callable<String>() { 996 @Override 997 public String call() throws Exception { 998 return parentContextOuterTemp.getAccessibleDescription(); 999 } 1000 }, ac); 1001 1002 /* 1003 Step 4: 1004 ======= 1005 Special case for Slider Bar objects. 1006 */ 1007 if ( (AccessibleRole.SLIDER == role) && 1008 (AccessibleRole.PANEL == parentRole) && 1009 (null != parentName) ) { 1010 debugString ("bk -- The Virtual Accessible Name was obtained from the Accessible Name of the SLIDER object's parent object."); 1011 references.increment (parentName); 1012 return parentName; 1013 } 1014 1015 boolean bIsEditCombo = false; 1016 1017 AccessibleContext testContext = ac; 1018 /* 1019 Step 5: 1020 ======= 1021 Special case for Edit Combo Boxes 1022 */ 1023 if ( (AccessibleRole.TEXT == role) && 1024 (AccessibleRole.COMBO_BOX == parentRole) ) { 1025 bIsEditCombo = true; 1026 if (null != parentName) { 1027 debugString ("bk -- The Virtual Accessible Name for this Edit Combo box was obtained from the Accessible Name of the object's parent object."); 1028 references.increment (parentName); 1029 return parentName; 1030 } else if (null != parentDescription) { 1031 debugString ("bk -- The Virtual Accessible Name for this Edit Combo box was obtained from the Accessible Description of the object's parent object."); 1032 references.increment (parentDescription); 1033 return parentDescription; 1034 } 1035 testContext = parentContext; 1036 parentRole = AccessibleRole.UNKNOWN; 1037 parentContext = getAccessibleParentFromContext (testContext); 1038 if ( null != parentContext ) { 1039 final AccessibleContext parentContextInnerTemp = parentContext; 1040 parentRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() { 1041 @Override 1042 public AccessibleRole call() throws Exception { 1043 return parentContextInnerTemp.getAccessibleRole(); 1044 } 1045 }, ac); 1046 } 1047 } 1048 1049 /* 1050 Step 6: 1051 ======= 1052 Attempt to get the Virtual Accessible Name of the object using the 1053 Accessible Relation Set Info (the LABELED_BY Accessible Relation). 1054 */ 1055 String version = getJavaVersionProperty (); 1056 if ( (null != version) && (version.compareTo ("1.3") >= 0) ) { 1057 final AccessibleContext parentContextTempInner = parentContext; 1058 AccessibleRelationSet ars = InvocationUtils.invokeAndWait(new Callable<AccessibleRelationSet>() { 1059 @Override 1060 public AccessibleRelationSet call() throws Exception { 1061 return parentContextTempInner.getAccessibleRelationSet(); 1062 } 1063 }, ac); 1064 if ( ars != null && (ars.size () > 0) && (ars.contains (AccessibleRelation.LABELED_BY)) ) { 1065 AccessibleRelation labeledByRelation = ars.get (AccessibleRelation.LABELED_BY); 1066 if (labeledByRelation != null) { 1067 Object [] targets = labeledByRelation.getTarget (); 1068 Object o = targets [0]; 1069 if (o instanceof Accessible) { 1070 AccessibleContext labelContext = ((Accessible)o).getAccessibleContext (); 1071 if (labelContext != null) { 1072 String labelName = labelContext.getAccessibleName (); 1073 String labelDescription = labelContext.getAccessibleDescription (); 1074 if (null != labelName) { 1075 debugString ("bk -- The Virtual Accessible Name was obtained using the LABELED_BY AccessibleRelation -- Name Case."); 1076 references.increment (labelName); 1077 return labelName; 1078 } else if (null != labelDescription) { 1079 debugString ("bk -- The Virtual Accessible Name was obtained using the LABELED_BY AccessibleRelation -- Description Case."); 1080 references.increment (labelDescription); 1081 return labelDescription; 1082 } 1083 } 1084 } 1085 } 1086 } 1087 } else { 1088 debugString ("bk -- This version of Java does not support AccessibleContext::getAccessibleRelationSet."); 1089 } 1090 1091 //Note: add AccessibleContext to use InvocationUtils.invokeAndWait 1092 /* 1093 Step 7: 1094 ======= 1095 Search for a label object that is positioned either just to the left 1096 or just above the object and get the Accessible Name of the Label 1097 object. 1098 */ 1099 int testIndexMax = 0; 1100 int testX = 0; 1101 int testY = 0; 1102 int testWidth = 0; 1103 int testHeight = 0; 1104 int targetX = 0; 1105 int targetY = 0; 1106 final AccessibleContext tempContext = testContext; 1107 int testIndex = InvocationUtils.invokeAndWait(new Callable<Integer>() { 1108 @Override 1109 public Integer call() throws Exception { 1110 return tempContext.getAccessibleIndexInParent(); 1111 } 1112 }, ac); 1113 if ( null != parentContext ) { 1114 final AccessibleContext parentContextInnerTemp = parentContext; 1115 testIndexMax = InvocationUtils.invokeAndWait(new Callable<Integer>() { 1116 @Override 1117 public Integer call() throws Exception { 1118 return parentContextInnerTemp.getAccessibleChildrenCount() - 1; 1119 } 1120 }, ac); 1121 } 1122 testX = getAccessibleXcoordFromContext (testContext); 1123 testY = getAccessibleYcoordFromContext (testContext); 1124 testWidth = getAccessibleWidthFromContext (testContext); 1125 testHeight = getAccessibleHeightFromContext (testContext); 1126 targetX = testX + 2; 1127 targetY = testY + 2; 1128 1129 int childIndex = testIndex - 1; 1130 /*Accessible child = null; 1131 AccessibleContext childContext = null; 1132 AccessibleRole childRole = AccessibleRole.UNKNOWN;*/ 1133 int childX = 0; 1134 int childY = 0; 1135 int childWidth = 0; 1136 int childHeight = 0; 1137 String childName = null; 1138 String childDescription = null; 1139 while (childIndex >= 0) { 1140 final int childIndexTemp = childIndex; 1141 final AccessibleContext parentContextInnerTemp = parentContext; 1142 final Accessible child = InvocationUtils.invokeAndWait(new Callable<Accessible>() { 1143 @Override 1144 public Accessible call() throws Exception { 1145 return parentContextInnerTemp.getAccessibleChild(childIndexTemp); 1146 } 1147 }, ac); 1148 if ( null != child ) { 1149 final AccessibleContext childContext = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() { 1150 @Override 1151 public AccessibleContext call() throws Exception { 1152 return child.getAccessibleContext(); 1153 } 1154 }, ac); 1155 if ( null != childContext ) { 1156 AccessibleRole childRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() { 1157 @Override 1158 public AccessibleRole call() throws Exception { 1159 return childContext.getAccessibleRole(); 1160 } 1161 }, ac); 1162 if ( AccessibleRole.LABEL == childRole ) { 1163 childX = getAccessibleXcoordFromContext (childContext); 1164 childY = getAccessibleYcoordFromContext (childContext); 1165 childWidth = getAccessibleWidthFromContext (childContext); 1166 childHeight = getAccessibleHeightFromContext (childContext); 1167 if ( (childX < testX) && 1168 ((childY <= targetY) && (targetY <= (childY + childHeight))) ) { 1169 childName = InvocationUtils.invokeAndWait(new Callable<String>() { 1170 public String call() { 1171 return childContext.getAccessibleName (); 1172 } 1173 }, ac); 1174 if ( null != childName ) { 1175 debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Name of a LABEL object positioned to the left of the object."); 1176 references.increment (childName); 1177 return childName; 1178 } 1179 childDescription = InvocationUtils.invokeAndWait(new Callable<String>() { 1180 public String call() { 1181 return childContext.getAccessibleDescription (); 1182 } 1183 }, ac); 1184 if ( null != childDescription ) { 1185 debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Description of a LABEL object positioned to the left of the object."); 1186 references.increment (childDescription); 1187 return childDescription; 1188 } 1189 } else if ( (childY < targetY) && 1190 ((childX <= targetX) && (targetX <= (childX + childWidth))) ) { 1191 childName = InvocationUtils.invokeAndWait(new Callable<String>() { 1192 public String call() { 1193 return childContext.getAccessibleName (); 1194 } 1195 }, ac); 1196 if ( null != childName ) { 1197 debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Name of a LABEL object positioned above the object."); 1198 references.increment (childName); 1199 return childName; 1200 } 1201 childDescription = InvocationUtils.invokeAndWait(new Callable<String>() { 1202 public String call() { 1203 return childContext.getAccessibleDescription (); 1204 } 1205 }, ac); 1206 if ( null != childDescription ) { 1207 debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Description of a LABEL object positioned above the object."); 1208 references.increment (childDescription); 1209 return childDescription; 1210 } 1211 } 1212 } 1213 } 1214 } 1215 childIndex --; 1216 } 1217 childIndex = testIndex + 1; 1218 while (childIndex <= testIndexMax) { 1219 final int childIndexTemp = childIndex; 1220 final AccessibleContext parentContextInnerTemp = parentContext; 1221 final Accessible child = InvocationUtils.invokeAndWait(new Callable<Accessible>() { 1222 @Override 1223 public Accessible call() throws Exception { 1224 return parentContextInnerTemp.getAccessibleChild(childIndexTemp); 1225 } 1226 }, ac); 1227 if ( null != child ) { 1228 final AccessibleContext childContext = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() { 1229 @Override 1230 public AccessibleContext call() throws Exception { 1231 return child.getAccessibleContext(); 1232 } 1233 }, ac); 1234 if ( null != childContext ) { 1235 AccessibleRole childRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() { 1236 @Override 1237 public AccessibleRole call() throws Exception { 1238 return childContext.getAccessibleRole(); 1239 } 1240 }, ac); 1241 if ( AccessibleRole.LABEL == childRole ) { 1242 childX = getAccessibleXcoordFromContext (childContext); 1243 childY = getAccessibleYcoordFromContext (childContext); 1244 childWidth = getAccessibleWidthFromContext (childContext); 1245 childHeight = getAccessibleHeightFromContext (childContext); 1246 if ( (childX < testX) && 1247 ((childY <= targetY) && (targetY <= (childY + childHeight))) ) { 1248 childName = InvocationUtils.invokeAndWait(new Callable<String>() { 1249 public String call() { 1250 return childContext.getAccessibleName (); 1251 } 1252 }, ac); 1253 if ( null != childName ) { 1254 debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Name of a LABEL object positioned to the left of the object."); 1255 references.increment (childName); 1256 return childName; 1257 } 1258 childDescription = InvocationUtils.invokeAndWait(new Callable<String>() { 1259 public String call() { 1260 return childContext.getAccessibleDescription (); 1261 } 1262 }, ac); 1263 if ( null != childDescription ) { 1264 debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Description of a LABEL object positioned to the left of the object."); 1265 references.increment (childDescription); 1266 return childDescription; 1267 } 1268 } else if ( (childY < targetY) && 1269 ((childX <= targetX) && (targetX <= (childX + childWidth))) ) { 1270 childName = InvocationUtils.invokeAndWait(new Callable<String>() { 1271 public String call() { 1272 return childContext.getAccessibleName (); 1273 } 1274 }, ac); 1275 if ( null != childName ) { 1276 debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Name of a LABEL object positioned above the object."); 1277 references.increment (childName); 1278 return childName; 1279 } 1280 childDescription = InvocationUtils.invokeAndWait(new Callable<String>() { 1281 public String call() { 1282 return childContext.getAccessibleDescription (); 1283 } 1284 }, ac); 1285 if ( null != childDescription ) { 1286 debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Description of a LABEL object positioned above the object."); 1287 references.increment (childDescription); 1288 return childDescription; 1289 } 1290 } 1291 } 1292 } 1293 } 1294 childIndex ++; 1295 } 1296 /* 1297 Step 8: 1298 ======= 1299 Special case for combo boxes and text objects, based on a 1300 similar special case I found in some of our internal JAWS code. 1301 1302 Search for a button object that is positioned either just to the left 1303 or just above the object and get the Accessible Name of the button 1304 object. 1305 */ 1306 if ( (AccessibleRole.TEXT == role) || 1307 (AccessibleRole.COMBO_BOX == role) || 1308 (bIsEditCombo) ) { 1309 childIndex = testIndex - 1; 1310 while (childIndex >= 0) { 1311 final int childIndexTemp = childIndex; 1312 final AccessibleContext parentContextInnerTemp = parentContext; 1313 final Accessible child = InvocationUtils.invokeAndWait(new Callable<Accessible>() { 1314 @Override 1315 public Accessible call() throws Exception { 1316 return parentContextInnerTemp.getAccessibleChild(childIndexTemp); 1317 } 1318 }, ac); 1319 if ( null != child ) { 1320 final AccessibleContext childContext = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() { 1321 @Override 1322 public AccessibleContext call() throws Exception { 1323 return child.getAccessibleContext(); 1324 } 1325 }, ac); 1326 if ( null != childContext ) { 1327 AccessibleRole childRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() { 1328 @Override 1329 public AccessibleRole call() throws Exception { 1330 return childContext.getAccessibleRole(); 1331 } 1332 }, ac); 1333 if ( ( AccessibleRole.PUSH_BUTTON == childRole ) || 1334 ( AccessibleRole.TOGGLE_BUTTON == childRole )) { 1335 childX = getAccessibleXcoordFromContext (childContext); 1336 childY = getAccessibleYcoordFromContext (childContext); 1337 childWidth = getAccessibleWidthFromContext (childContext); 1338 childHeight = getAccessibleHeightFromContext (childContext); 1339 if ( (childX < testX) && 1340 ((childY <= targetY) && (targetY <= (childY + childHeight))) ) { 1341 childName = InvocationUtils.invokeAndWait(new Callable<String>() { 1342 public String call() { 1343 return childContext.getAccessibleName (); 1344 } 1345 }, ac); 1346 if ( null != childName ) { 1347 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."); 1348 references.increment (childName); 1349 return childName; 1350 } 1351 childDescription = InvocationUtils.invokeAndWait(new Callable<String>() { 1352 public String call() { 1353 return childContext.getAccessibleDescription (); 1354 } 1355 }, ac); 1356 if ( null != childDescription ) { 1357 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."); 1358 references.increment (childDescription); 1359 return childDescription; 1360 } 1361 } 1362 } 1363 } 1364 } 1365 childIndex --; 1366 } 1367 childIndex = testIndex + 1; 1368 while (childIndex <= testIndexMax) { 1369 final int childIndexTemp = childIndex; 1370 final AccessibleContext parentContextInnerTemp = parentContext; 1371 final Accessible child = InvocationUtils.invokeAndWait(new Callable<Accessible>() { 1372 @Override 1373 public Accessible call() throws Exception { 1374 return parentContextInnerTemp.getAccessibleChild(childIndexTemp); 1375 } 1376 }, ac); 1377 if ( null != child ) { 1378 final AccessibleContext childContext = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() { 1379 @Override 1380 public AccessibleContext call() throws Exception { 1381 return child.getAccessibleContext(); 1382 } 1383 }, ac); 1384 if ( null != childContext ) { 1385 AccessibleRole childRole = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() { 1386 @Override 1387 public AccessibleRole call() throws Exception { 1388 return childContext.getAccessibleRole(); 1389 } 1390 }, ac); 1391 if ( ( AccessibleRole.PUSH_BUTTON == childRole ) || 1392 ( AccessibleRole.TOGGLE_BUTTON == childRole ) ) { 1393 childX = getAccessibleXcoordFromContext (childContext); 1394 childY = getAccessibleYcoordFromContext (childContext); 1395 childWidth = getAccessibleWidthFromContext (childContext); 1396 childHeight = getAccessibleHeightFromContext (childContext); 1397 if ( (childX < testX) && 1398 ((childY <= targetY) && (targetY <= (childY + childHeight))) ) { 1399 childName = InvocationUtils.invokeAndWait(new Callable<String>() { 1400 public String call() { 1401 return childContext.getAccessibleName(); 1402 } 1403 }, ac); 1404 if ( null != childName ) { 1405 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."); 1406 references.increment (childName); 1407 return childName; 1408 } 1409 childDescription = InvocationUtils.invokeAndWait(new Callable<String>() { 1410 public String call() { 1411 return childContext.getAccessibleDescription (); 1412 } 1413 }, ac); 1414 if ( null != childDescription ) { 1415 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."); 1416 references.increment (childDescription); 1417 return childDescription; 1418 } 1419 } 1420 } 1421 } 1422 } 1423 childIndex ++; 1424 } 1425 } 1426 return null; 1427 } else { 1428 debugString ("AccessBridge::getVirtualAccessibleNameFromContext error - ac == null."); 1429 return null; 1430 } 1431 } 1432 1433 /** 1434 * returns the AccessibleDescription from an AccessibleContext 1435 */ 1436 private String getAccessibleDescriptionFromContext(final AccessibleContext ac) { 1437 if (ac != null) { 1438 String s = InvocationUtils.invokeAndWait(new Callable<String>() { 1439 @Override 1440 public String call() throws Exception { 1441 return ac.getAccessibleDescription(); 1442 } 1443 }, ac); 1444 if (s != null) { 1445 references.increment(s); 1446 debugString("Returning AccessibleDescription from Context: " + s); 1447 return s; 1448 } 1449 } else { 1450 debugString("getAccessibleDescriptionFromContext; ac = null"); 1451 } 1452 return null; 1453 } 1454 1455 /** 1456 * returns the AccessibleRole from an AccessibleContext 1457 */ 1458 private String getAccessibleRoleStringFromContext(final AccessibleContext ac) { 1459 if (ac != null) { 1460 AccessibleRole role = InvocationUtils.invokeAndWait(new Callable<AccessibleRole>() { 1461 @Override 1462 public AccessibleRole call() throws Exception { 1463 return ac.getAccessibleRole(); 1464 } 1465 }, ac); 1466 if (role != null) { 1467 String s = role.toDisplayString(Locale.US); 1468 if (s != null) { 1469 references.increment(s); 1470 debugString("Returning AccessibleRole from Context: " + s); 1471 return s; 1472 } 1473 } 1474 } else { 1475 debugString("getAccessibleRoleStringFromContext; ac = null"); 1476 } 1477 return null; 1478 } 1479 1480 /** 1481 * return the AccessibleRole from an AccessibleContext in the en_US locale 1482 */ 1483 private String getAccessibleRoleStringFromContext_en_US(final AccessibleContext ac) { 1484 return getAccessibleRoleStringFromContext(ac); 1485 } 1486 1487 /** 1488 * return the AccessibleStates from an AccessibleContext 1489 */ 1490 private String getAccessibleStatesStringFromContext(final AccessibleContext ac) { 1491 if (ac != null) { 1492 AccessibleStateSet stateSet = InvocationUtils.invokeAndWait(new Callable<AccessibleStateSet>() { 1493 @Override 1494 public AccessibleStateSet call() throws Exception { 1495 return ac.getAccessibleStateSet(); 1496 } 1497 }, ac); 1498 if (stateSet != null) { 1499 String s = stateSet.toString(); 1500 if (s != null && 1501 s.indexOf(AccessibleState.MANAGES_DESCENDANTS.toDisplayString(Locale.US)) == -1) { 1502 // Indicate whether this component manages its own 1503 // children 1504 AccessibleRole role = ac.getAccessibleRole(); 1505 if (role == AccessibleRole.LIST || 1506 role == AccessibleRole.TABLE || 1507 role == AccessibleRole.TREE) { 1508 s += ","; 1509 s += AccessibleState.MANAGES_DESCENDANTS.toDisplayString(Locale.US); 1510 } 1511 references.increment(s); 1512 debugString("Returning AccessibleStateSet from Context: " + s); 1513 return s; 1514 } 1515 } 1516 } else { 1517 debugString("getAccessibleStatesStringFromContext; ac = null"); 1518 } 1519 return null; 1520 } 1521 1522 /** 1523 * returns the AccessibleStates from an AccessibleContext in the en_US locale 1524 */ 1525 private String getAccessibleStatesStringFromContext_en_US(final AccessibleContext ac) { 1526 if (ac != null) { 1527 AccessibleStateSet stateSet = InvocationUtils.invokeAndWait(new Callable<AccessibleStateSet>() { 1528 @Override 1529 public AccessibleStateSet call() throws Exception { 1530 return ac.getAccessibleStateSet(); 1531 } 1532 }, ac); 1533 if (stateSet != null) { 1534 String s = ""; 1535 AccessibleState[] states = stateSet.toArray(); 1536 if (states != null && states.length > 0) { 1537 s = states[0].toDisplayString(Locale.US); 1538 for (int i = 1; i < states.length; i++) { 1539 s = s + "," + states[i].toDisplayString(Locale.US); 1540 } 1541 } 1542 references.increment(s); 1543 debugString("Returning AccessibleStateSet en_US from Context: " + s); 1544 return s; 1545 } 1546 } 1547 debugString("getAccessibleStatesStringFromContext; ac = null"); 1548 return null; 1549 } 1550 1551 /** 1552 * returns the AccessibleParent from an AccessibleContext 1553 */ 1554 private AccessibleContext getAccessibleParentFromContext(final AccessibleContext ac) { 1555 if (ac==null) 1556 return null; 1557 return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() { 1558 @Override 1559 public AccessibleContext call() throws Exception { 1560 Accessible a = ac.getAccessibleParent(); 1561 if (a != null) { 1562 AccessibleContext apc = a.getAccessibleContext(); 1563 if (apc != null) { 1564 return apc; 1565 } 1566 } 1567 return null; 1568 } 1569 }, ac); 1570 } 1571 1572 /** 1573 * returns the AccessibleIndexInParent from an AccessibleContext 1574 */ 1575 private int getAccessibleIndexInParentFromContext(final AccessibleContext ac) { 1576 if (ac==null) 1577 return -1; 1578 return InvocationUtils.invokeAndWait(new Callable<Integer>() { 1579 @Override 1580 public Integer call() throws Exception { 1581 return ac.getAccessibleIndexInParent(); 1582 } 1583 }, ac); 1584 } 1585 1586 /** 1587 * returns the AccessibleChild count from an AccessibleContext 1588 */ 1589 private int getAccessibleChildrenCountFromContext(final AccessibleContext ac) { 1590 if (ac==null) 1591 return -1; 1592 return InvocationUtils.invokeAndWait(new Callable<Integer>() { 1593 @Override 1594 public Integer call() throws Exception { 1595 return ac.getAccessibleChildrenCount(); 1596 } 1597 }, ac); 1598 } 1599 1600 /** 1601 * returns the AccessibleChild Context from an AccessibleContext 1602 */ 1603 private AccessibleContext getAccessibleChildFromContext(final AccessibleContext ac, final int index) { 1604 1605 if (ac == null) { 1606 return null; 1607 } 1608 1609 final JTable table = InvocationUtils.invokeAndWait(new Callable<JTable>() { 1610 @Override 1611 public JTable call() throws Exception { 1612 // work-around for AccessibleJTable.getCurrentAccessibleContext returning 1613 // wrong renderer component when cell contains more than one component 1614 Accessible parent = ac.getAccessibleParent(); 1615 if (parent != null) { 1616 int indexInParent = ac.getAccessibleIndexInParent(); 1617 Accessible child = 1618 parent.getAccessibleContext().getAccessibleChild(indexInParent); 1619 if (child instanceof JTable) { 1620 return (JTable) child; 1621 } 1622 } 1623 return null; 1624 } 1625 }, ac); 1626 1627 if (table == null) { 1628 return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() { 1629 @Override 1630 public AccessibleContext call() throws Exception { 1631 Accessible a = ac.getAccessibleChild(index); 1632 if (a != null) { 1633 return a.getAccessibleContext(); 1634 } 1635 return null; 1636 } 1637 }, ac); 1638 } 1639 1640 final AccessibleTable at = getAccessibleTableFromContext(ac); 1641 1642 final int row = getAccessibleTableRow(at, index); 1643 final int column = getAccessibleTableColumn(at, index); 1644 1645 return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() { 1646 @Override 1647 public AccessibleContext call() throws Exception { 1648 TableCellRenderer renderer = table.getCellRenderer(row, column); 1649 if (renderer == null) { 1650 Class<?> columnClass = table.getColumnClass(column); 1651 renderer = table.getDefaultRenderer(columnClass); 1652 } 1653 Component component = 1654 renderer.getTableCellRendererComponent(table, table.getValueAt(row, column), 1655 false, false, row, column); 1656 if (component instanceof Accessible) { 1657 return component.getAccessibleContext(); 1658 } 1659 return null; 1660 } 1661 }, ac); 1662 } 1663 1664 /** 1665 * returns the AccessibleComponent bounds on screen from an AccessibleContext 1666 */ 1667 private Rectangle getAccessibleBoundsOnScreenFromContext(final AccessibleContext ac) { 1668 if(ac==null) 1669 return null; 1670 return InvocationUtils.invokeAndWait(new Callable<Rectangle>() { 1671 @Override 1672 public Rectangle call() throws Exception { 1673 AccessibleComponent acmp = ac.getAccessibleComponent(); 1674 if (acmp != null) { 1675 Rectangle r = acmp.getBounds(); 1676 if (r != null) { 1677 try { 1678 Point p = acmp.getLocationOnScreen(); 1679 if (p != null) { 1680 r.x = p.x; 1681 r.y = p.y; 1682 return r; 1683 } 1684 } catch (Exception e) { 1685 return null; 1686 } 1687 } 1688 } 1689 return null; 1690 } 1691 }, ac); 1692 } 1693 1694 /** 1695 * returns the AccessibleComponent x-coord from an AccessibleContext 1696 */ 1697 private int getAccessibleXcoordFromContext(AccessibleContext ac) { 1698 if (ac != null) { 1699 Rectangle r = getAccessibleBoundsOnScreenFromContext(ac); 1700 if (r != null) { 1701 debugString(" - Returning Accessible x coord from Context: " + r.x); 1702 return r.x; 1703 } 1704 } else { 1705 debugString("getAccessibleXcoordFromContext ac = null"); 1706 } 1707 return -1; 1708 } 1709 1710 /** 1711 * returns the AccessibleComponent y-coord from an AccessibleContext 1712 */ 1713 private int getAccessibleYcoordFromContext(AccessibleContext ac) { 1714 debugString("getAccessibleYcoordFromContext() called"); 1715 if (ac != null) { 1716 Rectangle r = getAccessibleBoundsOnScreenFromContext(ac); 1717 if (r != null) { 1718 return r.y; 1719 } 1720 } else { 1721 debugString("getAccessibleYcoordFromContext; ac = null"); 1722 } 1723 return -1; 1724 } 1725 1726 /** 1727 * returns the AccessibleComponent height from an AccessibleContext 1728 */ 1729 private int getAccessibleHeightFromContext(AccessibleContext ac) { 1730 if (ac != null) { 1731 Rectangle r = getAccessibleBoundsOnScreenFromContext(ac); 1732 if (r != null) { 1733 return r.height; 1734 } 1735 } else { 1736 debugString("getAccessibleHeightFromContext; ac = null"); 1737 } 1738 return -1; 1739 } 1740 1741 /** 1742 * returns the AccessibleComponent width from an AccessibleContext 1743 */ 1744 private int getAccessibleWidthFromContext(AccessibleContext ac) { 1745 if (ac != null) { 1746 Rectangle r = getAccessibleBoundsOnScreenFromContext(ac); 1747 if (r != null) { 1748 return r.width; 1749 } 1750 } else { 1751 debugString("getAccessibleWidthFromContext; ac = null"); 1752 } 1753 return -1; 1754 } 1755 1756 1757 /** 1758 * returns the AccessibleComponent from an AccessibleContext 1759 */ 1760 private AccessibleComponent getAccessibleComponentFromContext(AccessibleContext ac) { 1761 if (ac != null) { 1762 AccessibleComponent acmp = ac.getAccessibleComponent(); 1763 if (acmp != null) { 1764 debugString("Returning AccessibleComponent Context"); 1765 return acmp; 1766 } 1767 } else { 1768 debugString("getAccessibleComponentFromContext; ac = null"); 1769 } 1770 return null; 1771 } 1772 1773 /** 1774 * returns the AccessibleAction from an AccessibleContext 1775 */ 1776 private AccessibleAction getAccessibleActionFromContext(final AccessibleContext ac) { 1777 debugString("Returning AccessibleAction Context"); 1778 return ac == null ? null : InvocationUtils.invokeAndWait(new Callable<AccessibleAction>() { 1779 @Override 1780 public AccessibleAction call() throws Exception { 1781 return ac.getAccessibleAction(); 1782 } 1783 }, ac); 1784 } 1785 1786 /** 1787 * returns the AccessibleSelection from an AccessibleContext 1788 */ 1789 private AccessibleSelection getAccessibleSelectionFromContext(final AccessibleContext ac) { 1790 return ac == null ? null : InvocationUtils.invokeAndWait(new Callable<AccessibleSelection>() { 1791 @Override 1792 public AccessibleSelection call() throws Exception { 1793 return ac.getAccessibleSelection(); 1794 } 1795 }, ac); 1796 } 1797 1798 /** 1799 * return the AccessibleText from an AccessibleContext 1800 */ 1801 private AccessibleText getAccessibleTextFromContext(final AccessibleContext ac) { 1802 return ac == null ? null : InvocationUtils.invokeAndWait(new Callable<AccessibleText>() { 1803 @Override 1804 public AccessibleText call() throws Exception { 1805 return ac.getAccessibleText(); 1806 } 1807 }, ac); 1808 } 1809 1810 /** 1811 * return the AccessibleComponent from an AccessibleContext 1812 */ 1813 private AccessibleValue getAccessibleValueFromContext(final AccessibleContext ac) { 1814 return ac == null ? null : InvocationUtils.invokeAndWait(new Callable<AccessibleValue>() { 1815 @Override 1816 public AccessibleValue call() throws Exception { 1817 return ac.getAccessibleValue(); 1818 } 1819 }, ac); 1820 } 1821 1822 /* ===== AccessibleText methods ===== */ 1823 1824 /** 1825 * returns the bounding rectangle for the text cursor 1826 * XXX 1827 */ 1828 private Rectangle getCaretLocation(final AccessibleContext ac) { 1829 debugString("getCaretLocation"); 1830 if (ac==null) 1831 return null; 1832 return InvocationUtils.invokeAndWait(new Callable<Rectangle>() { 1833 @Override 1834 public Rectangle call() throws Exception { 1835 // workaround for JAAPI not returning cursor bounding rectangle 1836 Rectangle r = null; 1837 Accessible parent = ac.getAccessibleParent(); 1838 if (parent instanceof Accessible) { 1839 int indexInParent = ac.getAccessibleIndexInParent(); 1840 Accessible child = 1841 parent.getAccessibleContext().getAccessibleChild(indexInParent); 1842 1843 if (child instanceof JTextComponent) { 1844 JTextComponent text = (JTextComponent) child; 1845 try { 1846 r = text.modelToView(text.getCaretPosition()); 1847 if (r != null) { 1848 Point p = text.getLocationOnScreen(); 1849 r.translate(p.x, p.y); 1850 } 1851 } catch (BadLocationException ble) { 1852 } 1853 } 1854 } 1855 return r; 1856 } 1857 }, ac); 1858 } 1859 1860 /** 1861 * returns the x-coordinate for the text cursor rectangle 1862 */ 1863 private int getCaretLocationX(AccessibleContext ac) { 1864 Rectangle r = getCaretLocation(ac); 1865 if (r != null) { 1866 return r.x; 1867 } else { 1868 return -1; 1869 } 1870 } 1871 1872 /** 1873 * returns the y-coordinate for the text cursor rectangle 1874 */ 1875 private int getCaretLocationY(AccessibleContext ac) { 1876 Rectangle r = getCaretLocation(ac); 1877 if (r != null) { 1878 return r.y; 1879 } else { 1880 return -1; 1881 } 1882 } 1883 1884 /** 1885 * returns the height for the text cursor rectangle 1886 */ 1887 private int getCaretLocationHeight(AccessibleContext ac) { 1888 Rectangle r = getCaretLocation(ac); 1889 if (r != null) { 1890 return r.height; 1891 } else { 1892 return -1; 1893 } 1894 } 1895 1896 /** 1897 * returns the width for the text cursor rectangle 1898 */ 1899 private int getCaretLocationWidth(AccessibleContext ac) { 1900 Rectangle r = getCaretLocation(ac); 1901 if (r != null) { 1902 return r.width; 1903 } else { 1904 return -1; 1905 } 1906 } 1907 1908 /** 1909 * returns the character count from an AccessibleContext 1910 */ 1911 private int getAccessibleCharCountFromContext(final AccessibleContext ac) { 1912 if (ac==null) 1913 return -1; 1914 return InvocationUtils.invokeAndWait(new Callable<Integer>() { 1915 @Override 1916 public Integer call() throws Exception { 1917 AccessibleText at = ac.getAccessibleText(); 1918 if (at != null) { 1919 return at.getCharCount(); 1920 } 1921 return -1; 1922 } 1923 }, ac); 1924 } 1925 1926 /** 1927 * returns the caret position from an AccessibleContext 1928 */ 1929 private int getAccessibleCaretPositionFromContext(final AccessibleContext ac) { 1930 if (ac==null) 1931 return -1; 1932 return InvocationUtils.invokeAndWait(new Callable<Integer>() { 1933 @Override 1934 public Integer call() throws Exception { 1935 AccessibleText at = ac.getAccessibleText(); 1936 if (at != null) { 1937 return at.getCaretPosition(); 1938 } 1939 return -1; 1940 } 1941 }, ac); 1942 } 1943 1944 /** 1945 * Return the index at a specific point from an AccessibleContext 1946 * Point(x, y) is in screen coordinates. 1947 */ 1948 private int getAccessibleIndexAtPointFromContext(final AccessibleContext ac, 1949 final int x, final int y) { 1950 debugString("getAccessibleIndexAtPointFromContext: x = "+x+"; y = "+y); 1951 if (ac==null) 1952 return -1; 1953 return InvocationUtils.invokeAndWait(new Callable<Integer>() { 1954 @Override 1955 public Integer call() throws Exception { 1956 AccessibleText at = ac.getAccessibleText(); 1957 AccessibleComponent acomp = ac.getAccessibleComponent(); 1958 if (at != null && acomp != null) { 1959 // Convert x and y from screen coordinates to 1960 // local coordinates. 1961 try { 1962 Point p = acomp.getLocationOnScreen(); 1963 int x1, y1; 1964 if (p != null) { 1965 x1 = x - p.x; 1966 if (x1 < 0) { 1967 x1 = 0; 1968 } 1969 y1 = y - p.y; 1970 if (y1 < 0) { 1971 y1 = 0; 1972 } 1973 1974 Point newPoint = new Point(x1, y1); 1975 int indexAtPoint = at.getIndexAtPoint(new Point(x1, y1)); 1976 return indexAtPoint; 1977 } 1978 } catch (Exception e) { 1979 } 1980 } 1981 return -1; 1982 } 1983 }, ac); 1984 } 1985 1986 /** 1987 * return the letter at a specific point from an AccessibleContext 1988 */ 1989 private String getAccessibleLetterAtIndexFromContext(final AccessibleContext ac, final int index) { 1990 if (ac != null) { 1991 String s = InvocationUtils.invokeAndWait(new Callable<String>() { 1992 @Override 1993 public String call() throws Exception { 1994 AccessibleText at = ac.getAccessibleText(); 1995 if (at == null) return null; 1996 return at.getAtIndex(AccessibleText.CHARACTER, index); 1997 } 1998 }, ac); 1999 if (s != null) { 2000 references.increment(s); 2001 return s; 2002 } 2003 } else { 2004 debugString("getAccessibleLetterAtIndexFromContext; ac = null"); 2005 } 2006 return null; 2007 } 2008 2009 /** 2010 * return the word at a specific point from an AccessibleContext 2011 */ 2012 private String getAccessibleWordAtIndexFromContext(final AccessibleContext ac, final int index) { 2013 if (ac != null) { 2014 String s = InvocationUtils.invokeAndWait(new Callable<String>() { 2015 @Override 2016 public String call() throws Exception { 2017 AccessibleText at = ac.getAccessibleText(); 2018 if (at == null) return null; 2019 return at.getAtIndex(AccessibleText.WORD, index); 2020 } 2021 }, ac); 2022 if (s != null) { 2023 references.increment(s); 2024 return s; 2025 } 2026 } else { 2027 debugString("getAccessibleWordAtIndexFromContext; ac = null"); 2028 } 2029 return null; 2030 } 2031 2032 /** 2033 * return the sentence at a specific point from an AccessibleContext 2034 */ 2035 private String getAccessibleSentenceAtIndexFromContext(final AccessibleContext ac, final int index) { 2036 if (ac != null) { 2037 String s = InvocationUtils.invokeAndWait(new Callable<String>() { 2038 @Override 2039 public String call() throws Exception { 2040 AccessibleText at = ac.getAccessibleText(); 2041 if (at == null) return null; 2042 return at.getAtIndex(AccessibleText.SENTENCE, index); 2043 } 2044 }, ac); 2045 if (s != null) { 2046 references.increment(s); 2047 return s; 2048 } 2049 } else { 2050 debugString("getAccessibleSentenceAtIndexFromContext; ac = null"); 2051 } 2052 return null; 2053 } 2054 2055 /** 2056 * return the text selection start from an AccessibleContext 2057 */ 2058 private int getAccessibleTextSelectionStartFromContext(final AccessibleContext ac) { 2059 if (ac == null) return -1; 2060 return InvocationUtils.invokeAndWait(new Callable<Integer>() { 2061 @Override 2062 public Integer call() throws Exception { 2063 AccessibleText at = ac.getAccessibleText(); 2064 if (at != null) { 2065 return at.getSelectionStart(); 2066 } 2067 return -1; 2068 } 2069 }, ac); 2070 } 2071 2072 /** 2073 * return the text selection end from an AccessibleContext 2074 */ 2075 private int getAccessibleTextSelectionEndFromContext(final AccessibleContext ac) { 2076 if (ac == null) 2077 return -1; 2078 return InvocationUtils.invokeAndWait(new Callable<Integer>() { 2079 @Override 2080 public Integer call() throws Exception { 2081 AccessibleText at = ac.getAccessibleText(); 2082 if (at != null) { 2083 return at.getSelectionEnd(); 2084 } 2085 return -1; 2086 } 2087 }, ac); 2088 } 2089 2090 /** 2091 * return the selected text from an AccessibleContext 2092 */ 2093 private String getAccessibleTextSelectedTextFromContext(final AccessibleContext ac) { 2094 if (ac != null) { 2095 String s = InvocationUtils.invokeAndWait(new Callable<String>() { 2096 @Override 2097 public String call() throws Exception { 2098 AccessibleText at = ac.getAccessibleText(); 2099 if (at == null) return null; 2100 return at.getSelectedText(); 2101 } 2102 }, ac); 2103 if (s != null) { 2104 references.increment(s); 2105 return s; 2106 } 2107 } else { 2108 debugString("getAccessibleTextSelectedTextFromContext; ac = null"); 2109 } 2110 return null; 2111 } 2112 2113 /** 2114 * return the attribute string at a given index from an AccessibleContext 2115 */ 2116 private String getAccessibleAttributesAtIndexFromContext(final AccessibleContext ac, 2117 final int index) { 2118 if (ac == null) 2119 return null; 2120 AttributeSet as = InvocationUtils.invokeAndWait(new Callable<AttributeSet>() { 2121 @Override 2122 public AttributeSet call() throws Exception { 2123 AccessibleText at = ac.getAccessibleText(); 2124 if (at != null) { 2125 return at.getCharacterAttribute(index); 2126 } 2127 return null; 2128 } 2129 }, ac); 2130 String s = expandStyleConstants(as); 2131 if (s != null) { 2132 references.increment(s); 2133 return s; 2134 } 2135 return null; 2136 } 2137 2138 /** 2139 * Get line info: left index of line 2140 * 2141 * algorithm: cast back, doubling each time, 2142 * 'till find line boundaries 2143 * 2144 * return -1 if we can't get the info (e.g. index or at passed in 2145 * is bogus; etc.) 2146 */ 2147 private int getAccessibleTextLineLeftBoundsFromContext(final AccessibleContext ac, 2148 final int index) { 2149 if (ac == null) 2150 return -1; 2151 return InvocationUtils.invokeAndWait(new Callable<Integer>() { 2152 @Override 2153 public Integer call() throws Exception { 2154 AccessibleText at = ac.getAccessibleText(); 2155 if (at != null) { 2156 int lineStart; 2157 int offset; 2158 Rectangle charRect; 2159 Rectangle indexRect = at.getCharacterBounds(index); 2160 int textLen = at.getCharCount(); 2161 if (indexRect == null) { 2162 return -1; 2163 } 2164 // find the start of the line 2165 // 2166 offset = 1; 2167 lineStart = index - offset < 0 ? 0 : index - offset; 2168 charRect = at.getCharacterBounds(lineStart); 2169 // slouch behind beginning of line 2170 while (charRect != null 2171 && charRect.y >= indexRect.y 2172 && lineStart > 0) { 2173 offset = offset << 1; 2174 lineStart = index - offset < 0 ? 0 : index - offset; 2175 charRect = at.getCharacterBounds(lineStart); 2176 } 2177 if (lineStart == 0) { // special case: we're on the first line! 2178 // we found it! 2179 } else { 2180 offset = offset >> 1; // know boundary within last expansion 2181 // ground forward to beginning of line 2182 while (offset > 0) { 2183 charRect = at.getCharacterBounds(lineStart + offset); 2184 if (charRect.y < indexRect.y) { // still before line 2185 lineStart += offset; 2186 } else { 2187 // leave lineStart alone, it's close! 2188 } 2189 offset = offset >> 1; 2190 } 2191 // subtract one 'cause we're already too far... 2192 lineStart += 1; 2193 } 2194 return lineStart; 2195 } 2196 return -1; 2197 } 2198 }, ac); 2199 } 2200 2201 /** 2202 * Get line info: right index of line 2203 * 2204 * algorithm: cast back, doubling each time, 2205 * 'till find line boundaries 2206 * 2207 * return -1 if we can't get the info (e.g. index or at passed in 2208 * is bogus; etc.) 2209 */ 2210 private int getAccessibleTextLineRightBoundsFromContext(final AccessibleContext ac, final int index) { 2211 if(ac == null) 2212 return -1; 2213 return InvocationUtils.invokeAndWait(new Callable<Integer>() { 2214 @Override 2215 public Integer call() throws Exception { 2216 AccessibleText at = ac.getAccessibleText(); 2217 if (at != null) { 2218 int lineEnd; 2219 int offset; 2220 Rectangle charRect; 2221 Rectangle indexRect = at.getCharacterBounds(index); 2222 int textLen = at.getCharCount(); 2223 if (indexRect == null) { 2224 return -1; 2225 } 2226 // find the end of the line 2227 // 2228 offset = 1; 2229 lineEnd = index + offset > textLen - 1 2230 ? textLen - 1 : index + offset; 2231 charRect = at.getCharacterBounds(lineEnd); 2232 // push past end of line 2233 while (charRect != null && 2234 charRect.y <= indexRect.y && 2235 lineEnd < textLen - 1) { 2236 offset = offset << 1; 2237 lineEnd = index + offset > textLen - 1 2238 ? textLen - 1 : index + offset; 2239 charRect = at.getCharacterBounds(lineEnd); 2240 } 2241 if (lineEnd == textLen - 1) { // special case: on the last line! 2242 // we found it! 2243 } else { 2244 offset = offset >> 1; // know boundary within last expansion 2245 // pull back to end of line 2246 while (offset > 0) { 2247 charRect = at.getCharacterBounds(lineEnd - offset); 2248 if (charRect.y > indexRect.y) { // still beyond line 2249 lineEnd -= offset; 2250 } else { 2251 // leave lineEnd alone, it's close! 2252 } 2253 offset = offset >> 1; 2254 } 2255 // subtract one 'cause we're already too far... 2256 lineEnd -= 1; 2257 } 2258 return lineEnd; 2259 } 2260 return -1; 2261 } 2262 }, ac); 2263 } 2264 2265 /** 2266 * Get a range of text; null if indicies are bogus 2267 */ 2268 private String getAccessibleTextRangeFromContext(final AccessibleContext ac, 2269 final int start, final int end) { 2270 String s = InvocationUtils.invokeAndWait(new Callable<String>() { 2271 @Override 2272 public String call() throws Exception { 2273 if (ac != null) { 2274 AccessibleText at = ac.getAccessibleText(); 2275 if (at != null) { 2276 // start - end is inclusive 2277 if (start > end) { 2278 return null; 2279 } 2280 if (end >= at.getCharCount()) { 2281 return null; 2282 } 2283 StringBuffer buf = new StringBuffer(end - start + 1); 2284 for (int i = start; i <= end; i++) { 2285 buf.append(at.getAtIndex(AccessibleText.CHARACTER, i)); 2286 } 2287 return buf.toString(); 2288 } 2289 } 2290 return null; 2291 } 2292 }, ac); 2293 if (s != null) { 2294 references.increment(s); 2295 return s; 2296 } else { 2297 return null; 2298 } 2299 } 2300 2301 /** 2302 * return the AttributeSet object at a given index from an AccessibleContext 2303 */ 2304 private AttributeSet getAccessibleAttributeSetAtIndexFromContext(final AccessibleContext ac, 2305 final int index) { 2306 return InvocationUtils.invokeAndWait(new Callable<AttributeSet>() { 2307 @Override 2308 public AttributeSet call() throws Exception { 2309 if (ac != null) { 2310 AccessibleText at = ac.getAccessibleText(); 2311 if (at != null) { 2312 AttributeSet as = at.getCharacterAttribute(index); 2313 if (as != null) { 2314 AccessBridge.this.references.increment(as); 2315 return as; 2316 } 2317 } 2318 } 2319 return null; 2320 } 2321 }, ac); 2322 } 2323 2324 2325 /** 2326 * return the bounding rectangle at index from an AccessibleContext 2327 */ 2328 private Rectangle getAccessibleTextRectAtIndexFromContext(final AccessibleContext ac, 2329 final int index) { 2330 // want to do this in global coords, so need to combine w/ac global coords 2331 Rectangle r = InvocationUtils.invokeAndWait(new Callable<Rectangle>() { 2332 @Override 2333 public Rectangle call() throws Exception { 2334 // want to do this in global coords, so need to combine w/ac global coords 2335 if (ac != null) { 2336 AccessibleText at = ac.getAccessibleText(); 2337 if (at != null) { 2338 Rectangle rect = at.getCharacterBounds(index); 2339 if (rect != null) { 2340 String s = at.getAtIndex(AccessibleText.CHARACTER, index); 2341 if (s != null && s.equals("\n")) { 2342 rect.width = 0; 2343 } 2344 return rect; 2345 } 2346 } 2347 } 2348 return null; 2349 } 2350 }, ac); 2351 Rectangle acRect = getAccessibleBoundsOnScreenFromContext(ac); 2352 if (r != null && acRect != null) { 2353 r.translate(acRect.x, acRect.y); 2354 return r; 2355 } 2356 return null; 2357 } 2358 2359 /** 2360 * return the AccessibleText character x-coord at index from an AccessibleContext 2361 */ 2362 private int getAccessibleXcoordTextRectAtIndexFromContext(AccessibleContext ac, int index) { 2363 if (ac != null) { 2364 Rectangle r = getAccessibleTextRectAtIndexFromContext(ac, index); 2365 if (r != null) { 2366 return r.x; 2367 } 2368 } else { 2369 debugString("getAccessibleXcoordTextRectAtIndexFromContext; ac = null"); 2370 } 2371 return -1; 2372 } 2373 2374 /** 2375 * return the AccessibleText character y-coord at index from an AccessibleContext 2376 */ 2377 private int getAccessibleYcoordTextRectAtIndexFromContext(AccessibleContext ac, int index) { 2378 if (ac != null) { 2379 Rectangle r = getAccessibleTextRectAtIndexFromContext(ac, index); 2380 if (r != null) { 2381 return r.y; 2382 } 2383 } else { 2384 debugString("getAccessibleYcoordTextRectAtIndexFromContext; ac = null"); 2385 } 2386 return -1; 2387 } 2388 2389 /** 2390 * return the AccessibleText character height at index from an AccessibleContext 2391 */ 2392 private int getAccessibleHeightTextRectAtIndexFromContext(AccessibleContext ac, int index) { 2393 if (ac != null) { 2394 Rectangle r = getAccessibleTextRectAtIndexFromContext(ac, index); 2395 if (r != null) { 2396 return r.height; 2397 } 2398 } else { 2399 debugString("getAccessibleHeightTextRectAtIndexFromContext; ac = null"); 2400 } 2401 return -1; 2402 } 2403 2404 /** 2405 * return the AccessibleText character width at index from an AccessibleContext 2406 */ 2407 private int getAccessibleWidthTextRectAtIndexFromContext(AccessibleContext ac, int index) { 2408 if (ac != null) { 2409 Rectangle r = getAccessibleTextRectAtIndexFromContext(ac, index); 2410 if (r != null) { 2411 return r.width; 2412 } 2413 } else { 2414 debugString("getAccessibleWidthTextRectAtIndexFromContext; ac = null"); 2415 } 2416 return -1; 2417 } 2418 2419 /* ===== AttributeSet methods for AccessibleText ===== */ 2420 2421 /** 2422 * return the bold setting from an AttributeSet 2423 */ 2424 private boolean getBoldFromAttributeSet(AttributeSet as) { 2425 if (as != null) { 2426 return StyleConstants.isBold(as); 2427 } else { 2428 debugString("getBoldFromAttributeSet; as = null"); 2429 } 2430 return false; 2431 } 2432 2433 /** 2434 * return the italic setting from an AttributeSet 2435 */ 2436 private boolean getItalicFromAttributeSet(AttributeSet as) { 2437 if (as != null) { 2438 return StyleConstants.isItalic(as); 2439 } else { 2440 debugString("getItalicFromAttributeSet; as = null"); 2441 } 2442 return false; 2443 } 2444 2445 /** 2446 * return the underline setting from an AttributeSet 2447 */ 2448 private boolean getUnderlineFromAttributeSet(AttributeSet as) { 2449 if (as != null) { 2450 return StyleConstants.isUnderline(as); 2451 } else { 2452 debugString("getUnderlineFromAttributeSet; as = null"); 2453 } 2454 return false; 2455 } 2456 2457 /** 2458 * return the strikethrough setting from an AttributeSet 2459 */ 2460 private boolean getStrikethroughFromAttributeSet(AttributeSet as) { 2461 if (as != null) { 2462 return StyleConstants.isStrikeThrough(as); 2463 } else { 2464 debugString("getStrikethroughFromAttributeSet; as = null"); 2465 } 2466 return false; 2467 } 2468 2469 /** 2470 * return the superscript setting from an AttributeSet 2471 */ 2472 private boolean getSuperscriptFromAttributeSet(AttributeSet as) { 2473 if (as != null) { 2474 return StyleConstants.isSuperscript(as); 2475 } else { 2476 debugString("getSuperscriptFromAttributeSet; as = null"); 2477 } 2478 return false; 2479 } 2480 2481 /** 2482 * return the subscript setting from an AttributeSet 2483 */ 2484 private boolean getSubscriptFromAttributeSet(AttributeSet as) { 2485 if (as != null) { 2486 return StyleConstants.isSubscript(as); 2487 } else { 2488 debugString("getSubscriptFromAttributeSet; as = null"); 2489 } 2490 return false; 2491 } 2492 2493 /** 2494 * return the background color from an AttributeSet 2495 */ 2496 private String getBackgroundColorFromAttributeSet(AttributeSet as) { 2497 if (as != null) { 2498 String s = StyleConstants.getBackground(as).toString(); 2499 if (s != null) { 2500 references.increment(s); 2501 return s; 2502 } 2503 } else { 2504 debugString("getBackgroundColorFromAttributeSet; as = null"); 2505 } 2506 return null; 2507 } 2508 2509 /** 2510 * return the foreground color from an AttributeSet 2511 */ 2512 private String getForegroundColorFromAttributeSet(AttributeSet as) { 2513 if (as != null) { 2514 String s = StyleConstants.getForeground(as).toString(); 2515 if (s != null) { 2516 references.increment(s); 2517 return s; 2518 } 2519 } else { 2520 debugString("getForegroundColorFromAttributeSet; as = null"); 2521 } 2522 return null; 2523 } 2524 2525 /** 2526 * return the font family from an AttributeSet 2527 */ 2528 private String getFontFamilyFromAttributeSet(AttributeSet as) { 2529 if (as != null) { 2530 String s = StyleConstants.getFontFamily(as).toString(); 2531 if (s != null) { 2532 references.increment(s); 2533 return s; 2534 } 2535 } else { 2536 debugString("getFontFamilyFromAttributeSet; as = null"); 2537 } 2538 return null; 2539 } 2540 2541 /** 2542 * return the font size from an AttributeSet 2543 */ 2544 private int getFontSizeFromAttributeSet(AttributeSet as) { 2545 if (as != null) { 2546 return StyleConstants.getFontSize(as); 2547 } else { 2548 debugString("getFontSizeFromAttributeSet; as = null"); 2549 } 2550 return -1; 2551 } 2552 2553 /** 2554 * return the alignment from an AttributeSet 2555 */ 2556 private int getAlignmentFromAttributeSet(AttributeSet as) { 2557 if (as != null) { 2558 return StyleConstants.getAlignment(as); 2559 } else { 2560 debugString("getAlignmentFromAttributeSet; as = null"); 2561 } 2562 return -1; 2563 } 2564 2565 /** 2566 * return the BiDi level from an AttributeSet 2567 */ 2568 private int getBidiLevelFromAttributeSet(AttributeSet as) { 2569 if (as != null) { 2570 return StyleConstants.getBidiLevel(as); 2571 } else { 2572 debugString("getBidiLevelFromAttributeSet; as = null"); 2573 } 2574 return -1; 2575 } 2576 2577 2578 /** 2579 * return the first line indent from an AttributeSet 2580 */ 2581 private float getFirstLineIndentFromAttributeSet(AttributeSet as) { 2582 if (as != null) { 2583 return StyleConstants.getFirstLineIndent(as); 2584 } else { 2585 debugString("getFirstLineIndentFromAttributeSet; as = null"); 2586 } 2587 return -1; 2588 } 2589 2590 /** 2591 * return the left indent from an AttributeSet 2592 */ 2593 private float getLeftIndentFromAttributeSet(AttributeSet as) { 2594 if (as != null) { 2595 return StyleConstants.getLeftIndent(as); 2596 } else { 2597 debugString("getLeftIndentFromAttributeSet; as = null"); 2598 } 2599 return -1; 2600 } 2601 2602 /** 2603 * return the right indent from an AttributeSet 2604 */ 2605 private float getRightIndentFromAttributeSet(AttributeSet as) { 2606 if (as != null) { 2607 return StyleConstants.getRightIndent(as); 2608 } else { 2609 debugString("getRightIndentFromAttributeSet; as = null"); 2610 } 2611 return -1; 2612 } 2613 2614 /** 2615 * return the line spacing from an AttributeSet 2616 */ 2617 private float getLineSpacingFromAttributeSet(AttributeSet as) { 2618 if (as != null) { 2619 return StyleConstants.getLineSpacing(as); 2620 } else { 2621 debugString("getLineSpacingFromAttributeSet; as = null"); 2622 } 2623 return -1; 2624 } 2625 2626 /** 2627 * return the space above from an AttributeSet 2628 */ 2629 private float getSpaceAboveFromAttributeSet(AttributeSet as) { 2630 if (as != null) { 2631 return StyleConstants.getSpaceAbove(as); 2632 } else { 2633 debugString("getSpaceAboveFromAttributeSet; as = null"); 2634 } 2635 return -1; 2636 } 2637 2638 /** 2639 * return the space below from an AttributeSet 2640 */ 2641 private float getSpaceBelowFromAttributeSet(AttributeSet as) { 2642 if (as != null) { 2643 return StyleConstants.getSpaceBelow(as); 2644 } else { 2645 debugString("getSpaceBelowFromAttributeSet; as = null"); 2646 } 2647 return -1; 2648 } 2649 2650 /** 2651 * Enumerate all StyleConstants in the AttributeSet 2652 * 2653 * We need to check explicitly, 'cause of the HTML package conversion 2654 * mechanism (they may not be stored as StyleConstants, just translated 2655 * to them when asked). 2656 * 2657 * (Use convenience methods where they are defined...) 2658 * 2659 * Not checking the following (which the IBM SNS guidelines says 2660 * should be defined): 2661 * - ComponentElementName 2662 * - IconElementName 2663 * - NameAttribute 2664 * - ResolveAttribute 2665 */ 2666 private String expandStyleConstants(AttributeSet as) { 2667 Color c; 2668 Object o; 2669 String attrString = ""; 2670 2671 // ---------- check for various Character Constants 2672 2673 attrString += "BidiLevel = " + StyleConstants.getBidiLevel(as); 2674 2675 final Component comp = StyleConstants.getComponent(as); 2676 if (comp != null) { 2677 if (comp instanceof Accessible) { 2678 final AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() { 2679 @Override 2680 public AccessibleContext call() throws Exception { 2681 return comp.getAccessibleContext(); 2682 } 2683 }, comp); 2684 if (ac != null) { 2685 attrString += "; Accessible Component = " + InvocationUtils.invokeAndWait(new Callable<String>() { 2686 @Override 2687 public String call() throws Exception { 2688 return ac.getAccessibleName(); 2689 } 2690 }, ac); 2691 } else { 2692 attrString += "; Innaccessible Component = " + comp; 2693 } 2694 } else { 2695 attrString += "; Innaccessible Component = " + comp; 2696 } 2697 } 2698 2699 Icon i = StyleConstants.getIcon(as); 2700 if (i != null) { 2701 if (i instanceof ImageIcon) { 2702 attrString += "; ImageIcon = " + ((ImageIcon) i).getDescription(); 2703 } else { 2704 attrString += "; Icon = " + i; 2705 } 2706 } 2707 2708 attrString += "; FontFamily = " + StyleConstants.getFontFamily(as); 2709 2710 attrString += "; FontSize = " + StyleConstants.getFontSize(as); 2711 2712 if (StyleConstants.isBold(as)) { 2713 attrString += "; bold"; 2714 } 2715 2716 if (StyleConstants.isItalic(as)) { 2717 attrString += "; italic"; 2718 } 2719 2720 if (StyleConstants.isUnderline(as)) { 2721 attrString += "; underline"; 2722 } 2723 2724 if (StyleConstants.isStrikeThrough(as)) { 2725 attrString += "; strikethrough"; 2726 } 2727 2728 if (StyleConstants.isSuperscript(as)) { 2729 attrString += "; superscript"; 2730 } 2731 2732 if (StyleConstants.isSubscript(as)) { 2733 attrString += "; subscript"; 2734 } 2735 2736 c = StyleConstants.getForeground(as); 2737 if (c != null) { 2738 attrString += "; Foreground = " + c; 2739 } 2740 2741 c = StyleConstants.getBackground(as); 2742 if (c != null) { 2743 attrString += "; Background = " + c; 2744 } 2745 2746 attrString += "; FirstLineIndent = " + StyleConstants.getFirstLineIndent(as); 2747 2748 attrString += "; RightIndent = " + StyleConstants.getRightIndent(as); 2749 2750 attrString += "; LeftIndent = " + StyleConstants.getLeftIndent(as); 2751 2752 attrString += "; LineSpacing = " + StyleConstants.getLineSpacing(as); 2753 2754 attrString += "; SpaceAbove = " + StyleConstants.getSpaceAbove(as); 2755 2756 attrString += "; SpaceBelow = " + StyleConstants.getSpaceBelow(as); 2757 2758 attrString += "; Alignment = " + StyleConstants.getAlignment(as); 2759 2760 TabSet ts = StyleConstants.getTabSet(as); 2761 if (ts != null) { 2762 attrString += "; TabSet = " + ts; 2763 } 2764 2765 return attrString; 2766 } 2767 2768 2769 /* ===== AccessibleValue methods ===== */ 2770 2771 /** 2772 * return the AccessibleValue current value from an AccessibleContext 2773 * returned using a String 'cause the value is a java Number 2774 * 2775 */ 2776 private String getCurrentAccessibleValueFromContext(final AccessibleContext ac) { 2777 if (ac != null) { 2778 final Number value = InvocationUtils.invokeAndWait(new Callable<Number>() { 2779 @Override 2780 public Number call() throws Exception { 2781 AccessibleValue av = ac.getAccessibleValue(); 2782 if (av == null) return null; 2783 return av.getCurrentAccessibleValue(); 2784 } 2785 }, ac); 2786 if (value != null) { 2787 String s = value.toString(); 2788 if (s != null) { 2789 references.increment(s); 2790 return s; 2791 } 2792 } 2793 } else { 2794 debugString("getCurrentAccessibleValueFromContext; ac = null"); 2795 } 2796 return null; 2797 } 2798 2799 /** 2800 * return the AccessibleValue maximum value from an AccessibleContext 2801 * returned using a String 'cause the value is a java Number 2802 * 2803 */ 2804 private String getMaximumAccessibleValueFromContext(final AccessibleContext ac) { 2805 if (ac != null) { 2806 final Number value = InvocationUtils.invokeAndWait(new Callable<Number>() { 2807 @Override 2808 public Number call() throws Exception { 2809 AccessibleValue av = ac.getAccessibleValue(); 2810 if (av == null) return null; 2811 return av.getMaximumAccessibleValue(); 2812 } 2813 }, ac); 2814 if (value != null) { 2815 String s = value.toString(); 2816 if (s != null) { 2817 references.increment(s); 2818 return s; 2819 } 2820 } 2821 } else { 2822 debugString("getMaximumAccessibleValueFromContext; ac = null"); 2823 } 2824 return null; 2825 } 2826 2827 /** 2828 * return the AccessibleValue minimum value from an AccessibleContext 2829 * returned using a String 'cause the value is a java Number 2830 * 2831 */ 2832 private String getMinimumAccessibleValueFromContext(final AccessibleContext ac) { 2833 if (ac != null) { 2834 final Number value = InvocationUtils.invokeAndWait(new Callable<Number>() { 2835 @Override 2836 public Number call() throws Exception { 2837 AccessibleValue av = ac.getAccessibleValue(); 2838 if (av == null) return null; 2839 return av.getMinimumAccessibleValue(); 2840 } 2841 }, ac); 2842 if (value != null) { 2843 String s = value.toString(); 2844 if (s != null) { 2845 references.increment(s); 2846 return s; 2847 } 2848 } 2849 } else { 2850 debugString("getMinimumAccessibleValueFromContext; ac = null"); 2851 } 2852 return null; 2853 } 2854 2855 2856 /* ===== AccessibleSelection methods ===== */ 2857 2858 /** 2859 * add to the AccessibleSelection of an AccessibleContext child i 2860 * 2861 */ 2862 private void addAccessibleSelectionFromContext(final AccessibleContext ac, final int i) { 2863 try { 2864 InvocationUtils.invokeAndWait(new Callable<Object>() { 2865 @Override 2866 public Object call() throws Exception { 2867 if (ac != null) { 2868 AccessibleSelection as = ac.getAccessibleSelection(); 2869 if (as != null) { 2870 as.addAccessibleSelection(i); 2871 } 2872 } 2873 return null; 2874 } 2875 }, ac); 2876 } catch(Exception e){} 2877 } 2878 2879 /** 2880 * clear all of the AccessibleSelection of an AccessibleContex 2881 * 2882 */ 2883 private void clearAccessibleSelectionFromContext(final AccessibleContext ac) { 2884 try { 2885 InvocationUtils.invokeAndWait(new Callable<Object>() { 2886 @Override 2887 public Object call() throws Exception { 2888 AccessibleSelection as = ac.getAccessibleSelection(); 2889 if (as != null) { 2890 as.clearAccessibleSelection(); 2891 } 2892 return null; 2893 } 2894 }, ac); 2895 } catch(Exception e){} 2896 2897 } 2898 2899 /** 2900 * get the AccessibleContext of the i-th AccessibleSelection of an AccessibleContext 2901 * 2902 */ 2903 private AccessibleContext getAccessibleSelectionFromContext(final AccessibleContext ac, final int i) { 2904 return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() { 2905 @Override 2906 public AccessibleContext call() throws Exception { 2907 if (ac != null) { 2908 AccessibleSelection as = ac.getAccessibleSelection(); 2909 if (as != null) { 2910 Accessible a = as.getAccessibleSelection(i); 2911 if (a == null) 2912 return null; 2913 else 2914 return a.getAccessibleContext(); 2915 } 2916 } 2917 return null; 2918 } 2919 }, ac); 2920 } 2921 2922 /** 2923 * get number of things selected in the AccessibleSelection of an AccessibleContext 2924 * 2925 */ 2926 private int getAccessibleSelectionCountFromContext(final AccessibleContext ac) { 2927 return InvocationUtils.invokeAndWait(new Callable<Integer>() { 2928 @Override 2929 public Integer call() throws Exception { 2930 if (ac != null) { 2931 AccessibleSelection as = ac.getAccessibleSelection(); 2932 if (as != null) { 2933 return as.getAccessibleSelectionCount(); 2934 } 2935 } 2936 return -1; 2937 } 2938 }, ac); 2939 } 2940 2941 /** 2942 * return true if the i-th child of the AccessibleSelection of an AccessibleContext is selected 2943 * 2944 */ 2945 private boolean isAccessibleChildSelectedFromContext(final AccessibleContext ac, final int i) { 2946 return InvocationUtils.invokeAndWait(new Callable<Boolean>() { 2947 @Override 2948 public Boolean call() throws Exception { 2949 if (ac != null) { 2950 AccessibleSelection as = ac.getAccessibleSelection(); 2951 if (as != null) { 2952 return as.isAccessibleChildSelected(i); 2953 } 2954 } 2955 return false; 2956 } 2957 }, ac); 2958 } 2959 2960 /** 2961 * remove the i-th child from the AccessibleSelection of an AccessibleContext 2962 * 2963 */ 2964 private void removeAccessibleSelectionFromContext(final AccessibleContext ac, final int i) { 2965 InvocationUtils.invokeAndWait(new Callable<Object>() { 2966 @Override 2967 public Object call() throws Exception { 2968 if (ac != null) { 2969 AccessibleSelection as = ac.getAccessibleSelection(); 2970 if (as != null) { 2971 as.removeAccessibleSelection(i); 2972 } 2973 } 2974 return null; 2975 } 2976 }, ac); 2977 } 2978 2979 /** 2980 * select all (if possible) of the children of the AccessibleSelection of an AccessibleContext 2981 * 2982 */ 2983 private void selectAllAccessibleSelectionFromContext(final AccessibleContext ac) { 2984 InvocationUtils.invokeAndWait(new Callable<Object>() { 2985 @Override 2986 public Object call() throws Exception { 2987 if (ac != null) { 2988 AccessibleSelection as = ac.getAccessibleSelection(); 2989 if (as != null) { 2990 as.selectAllAccessibleSelection(); 2991 } 2992 } 2993 return null; 2994 } 2995 }, ac); 2996 } 2997 2998 // ======== AccessibleTable ======== 2999 3000 ConcurrentHashMap<AccessibleTable,AccessibleContext> hashtab = new ConcurrentHashMap<>(); 3001 3002 /** 3003 * returns the AccessibleTable for an AccessibleContext 3004 */ 3005 private AccessibleTable getAccessibleTableFromContext(final AccessibleContext ac) { 3006 String version = getJavaVersionProperty(); 3007 if ((version != null && version.compareTo("1.3") >= 0)) { 3008 return InvocationUtils.invokeAndWait(new Callable<AccessibleTable>() { 3009 @Override 3010 public AccessibleTable call() throws Exception { 3011 if (ac != null) { 3012 AccessibleTable at = ac.getAccessibleTable(); 3013 if (at != null) { 3014 AccessBridge.this.hashtab.put(at, ac); 3015 return at; 3016 } 3017 } 3018 return null; 3019 } 3020 }, ac); 3021 } 3022 return null; 3023 } 3024 3025 3026 /* 3027 * returns the AccessibleContext that contains an AccessibleTable 3028 */ 3029 private AccessibleContext getContextFromAccessibleTable(AccessibleTable at) { 3030 return hashtab.get(at); 3031 } 3032 3033 /* 3034 * returns the row count for an AccessibleTable 3035 */ 3036 private int getAccessibleTableRowCount(final AccessibleContext ac) { 3037 debugString("##### getAccessibleTableRowCount"); 3038 return InvocationUtils.invokeAndWait(new Callable<Integer>() { 3039 @Override 3040 public Integer call() throws Exception { 3041 if (ac != null) { 3042 AccessibleTable at = ac.getAccessibleTable(); 3043 if (at != null) { 3044 return at.getAccessibleRowCount(); 3045 } 3046 } 3047 return -1; 3048 } 3049 }, ac); 3050 } 3051 3052 /* 3053 * returns the column count for an AccessibleTable 3054 */ 3055 private int getAccessibleTableColumnCount(final AccessibleContext ac) { 3056 debugString("##### getAccessibleTableColumnCount"); 3057 return InvocationUtils.invokeAndWait(new Callable<Integer>() { 3058 @Override 3059 public Integer call() throws Exception { 3060 if (ac != null) { 3061 AccessibleTable at = ac.getAccessibleTable(); 3062 if (at != null) { 3063 return at.getAccessibleColumnCount(); 3064 } 3065 } 3066 return -1; 3067 } 3068 }, ac); 3069 } 3070 3071 /* 3072 * returns the AccessibleContext for an AccessibleTable cell 3073 */ 3074 private AccessibleContext getAccessibleTableCellAccessibleContext(final AccessibleTable at, 3075 final int row, final int column) { 3076 debugString("getAccessibleTableCellAccessibleContext: at = "+at.getClass()); 3077 if (at == null) return null; 3078 return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() { 3079 @Override 3080 public AccessibleContext call() throws Exception { 3081 if (!(at instanceof AccessibleContext)) { 3082 Accessible a = at.getAccessibleAt(row, column); 3083 if (a != null) { 3084 return a.getAccessibleContext(); 3085 } 3086 } else { 3087 // work-around for AccessibleJTable.getCurrentAccessibleContext returning 3088 // wrong renderer component when cell contains more than one component 3089 AccessibleContext ac = (AccessibleContext) at; 3090 Accessible parent = ac.getAccessibleParent(); 3091 if (parent != null) { 3092 int indexInParent = ac.getAccessibleIndexInParent(); 3093 Accessible child = 3094 parent.getAccessibleContext().getAccessibleChild(indexInParent); 3095 if (child instanceof JTable) { 3096 JTable table = (JTable) child; 3097 3098 TableCellRenderer renderer = table.getCellRenderer(row, column); 3099 if (renderer == null) { 3100 Class<?> columnClass = table.getColumnClass(column); 3101 renderer = table.getDefaultRenderer(columnClass); 3102 } 3103 Component component = 3104 renderer.getTableCellRendererComponent(table, table.getValueAt(row, column), 3105 false, false, row, column); 3106 if (component instanceof Accessible) { 3107 return component.getAccessibleContext(); 3108 } 3109 } 3110 } 3111 } 3112 return null; 3113 } 3114 }, getContextFromAccessibleTable(at)); 3115 } 3116 3117 /* 3118 * returns the index of a cell at a given row and column in an AccessibleTable 3119 */ 3120 private int getAccessibleTableCellIndex(final AccessibleTable at, int row, int column) { 3121 debugString("##### getAccessibleTableCellIndex: at="+at); 3122 if (at != null) { 3123 int cellIndex = row * 3124 InvocationUtils.invokeAndWait(new Callable<Integer>() { 3125 @Override 3126 public Integer call() throws Exception { 3127 return at.getAccessibleColumnCount(); 3128 } 3129 }, getContextFromAccessibleTable(at)) + 3130 column; 3131 debugString(" ##### getAccessibleTableCellIndex="+cellIndex); 3132 return cellIndex; 3133 } 3134 debugString(" ##### getAccessibleTableCellIndex FAILED"); 3135 return -1; 3136 } 3137 3138 /* 3139 * returns the row extent of a cell at a given row and column in an AccessibleTable 3140 */ 3141 private int getAccessibleTableCellRowExtent(final AccessibleTable at, final int row, final int column) { 3142 debugString("##### getAccessibleTableCellRowExtent"); 3143 if (at != null) { 3144 int rowExtent = InvocationUtils.invokeAndWait(new Callable<Integer>() { 3145 @Override 3146 public Integer call() throws Exception { 3147 return at.getAccessibleRowExtentAt(row, column); 3148 } 3149 }, 3150 getContextFromAccessibleTable(at)); 3151 debugString(" ##### getAccessibleTableCellRowExtent="+rowExtent); 3152 return rowExtent; 3153 } 3154 debugString(" ##### getAccessibleTableCellRowExtent FAILED"); 3155 return -1; 3156 } 3157 3158 /* 3159 * returns the column extent of a cell at a given row and column in an AccessibleTable 3160 */ 3161 private int getAccessibleTableCellColumnExtent(final AccessibleTable at, final int row, final int column) { 3162 debugString("##### getAccessibleTableCellColumnExtent"); 3163 if (at != null) { 3164 int columnExtent = InvocationUtils.invokeAndWait(new Callable<Integer>() { 3165 @Override 3166 public Integer call() throws Exception { 3167 return at.getAccessibleColumnExtentAt(row, column); 3168 } 3169 }, 3170 getContextFromAccessibleTable(at)); 3171 debugString(" ##### getAccessibleTableCellColumnExtent="+columnExtent); 3172 return columnExtent; 3173 } 3174 debugString(" ##### getAccessibleTableCellColumnExtent FAILED"); 3175 return -1; 3176 } 3177 3178 /* 3179 * returns whether a cell is selected at a given row and column in an AccessibleTable 3180 */ 3181 private boolean isAccessibleTableCellSelected(final AccessibleTable at, final int row, 3182 final int column) { 3183 debugString("##### isAccessibleTableCellSelected: ["+row+"]["+column+"]"); 3184 if (at == null) 3185 return false; 3186 return InvocationUtils.invokeAndWait(new Callable<Boolean>() { 3187 @Override 3188 public Boolean call() throws Exception { 3189 boolean isSelected = false; 3190 Accessible a = at.getAccessibleAt(row, column); 3191 if (a != null) { 3192 AccessibleContext ac = a.getAccessibleContext(); 3193 if (ac == null) 3194 return false; 3195 AccessibleStateSet as = ac.getAccessibleStateSet(); 3196 if (as != null) { 3197 isSelected = as.contains(AccessibleState.SELECTED); 3198 } 3199 } 3200 return isSelected; 3201 } 3202 }, getContextFromAccessibleTable(at)); 3203 } 3204 3205 /* 3206 * returns an AccessibleTable that represents the row header in an 3207 * AccessibleTable 3208 */ 3209 private AccessibleTable getAccessibleTableRowHeader(final AccessibleContext ac) { 3210 debugString(" ##### getAccessibleTableRowHeader called"); 3211 AccessibleTable at = InvocationUtils.invokeAndWait(new Callable<AccessibleTable>() { 3212 @Override 3213 public AccessibleTable call() throws Exception { 3214 if (ac != null) { 3215 AccessibleTable at = ac.getAccessibleTable(); 3216 if (at != null) { 3217 return at.getAccessibleRowHeader(); 3218 } 3219 } 3220 return null; 3221 } 3222 }, ac); 3223 if (at != null) { 3224 hashtab.put(at, ac); 3225 } 3226 return at; 3227 } 3228 3229 /* 3230 * returns an AccessibleTable that represents the column header in an 3231 * AccessibleTable 3232 */ 3233 private AccessibleTable getAccessibleTableColumnHeader(final AccessibleContext ac) { 3234 debugString("##### getAccessibleTableColumnHeader"); 3235 if (ac == null) 3236 return null; 3237 AccessibleTable at = InvocationUtils.invokeAndWait(new Callable<AccessibleTable>() { 3238 @Override 3239 public AccessibleTable call() throws Exception { 3240 // workaround for getAccessibleColumnHeader NPE 3241 // when the table header is null 3242 Accessible parent = ac.getAccessibleParent(); 3243 if (parent != null) { 3244 int indexInParent = ac.getAccessibleIndexInParent(); 3245 Accessible child = 3246 parent.getAccessibleContext().getAccessibleChild(indexInParent); 3247 if (child instanceof JTable) { 3248 JTable table = (JTable) child; 3249 if (table.getTableHeader() == null) { 3250 return null; 3251 } 3252 } 3253 } 3254 AccessibleTable at = ac.getAccessibleTable(); 3255 if (at != null) { 3256 return at.getAccessibleColumnHeader(); 3257 } 3258 return null; 3259 } 3260 }, ac); 3261 if (at != null) { 3262 hashtab.put(at, ac); 3263 } 3264 return at; 3265 } 3266 3267 /* 3268 * returns the number of row headers in an AccessibleTable that represents 3269 * the row header in an AccessibleTable 3270 */ 3271 private int getAccessibleTableRowHeaderRowCount(AccessibleContext ac) { 3272 3273 debugString(" ##### getAccessibleTableRowHeaderRowCount called"); 3274 if (ac != null) { 3275 final AccessibleTable atRowHeader = getAccessibleTableRowHeader(ac); 3276 if (atRowHeader != null) { 3277 return InvocationUtils.invokeAndWait(new Callable<Integer>() { 3278 @Override 3279 public Integer call() throws Exception { 3280 if (atRowHeader != null) { 3281 return atRowHeader.getAccessibleRowCount(); 3282 } 3283 return -1; 3284 } 3285 }, ac); 3286 } 3287 } 3288 return -1; 3289 } 3290 3291 /* 3292 * returns the number of column headers in an AccessibleTable that represents 3293 * the row header in an AccessibleTable 3294 */ 3295 private int getAccessibleTableRowHeaderColumnCount(AccessibleContext ac) { 3296 debugString(" ##### getAccessibleTableRowHeaderColumnCount called"); 3297 if (ac != null) { 3298 final AccessibleTable atRowHeader = getAccessibleTableRowHeader(ac); 3299 if (atRowHeader != null) { 3300 return InvocationUtils.invokeAndWait(new Callable<Integer>() { 3301 @Override 3302 public Integer call() throws Exception { 3303 if (atRowHeader != null) { 3304 return atRowHeader.getAccessibleColumnCount(); 3305 } 3306 return -1; 3307 } 3308 }, ac); 3309 } 3310 } 3311 debugString(" ##### getAccessibleTableRowHeaderColumnCount FAILED"); 3312 return -1; 3313 } 3314 3315 /* 3316 * returns the number of row headers in an AccessibleTable that represents 3317 * the column header in an AccessibleTable 3318 */ 3319 private int getAccessibleTableColumnHeaderRowCount(AccessibleContext ac) { 3320 3321 debugString("##### getAccessibleTableColumnHeaderRowCount"); 3322 if (ac != null) { 3323 final AccessibleTable atColumnHeader = getAccessibleTableColumnHeader(ac); 3324 if (atColumnHeader != null) { 3325 return InvocationUtils.invokeAndWait(new Callable<Integer>() { 3326 @Override 3327 public Integer call() throws Exception { 3328 if (atColumnHeader != null) { 3329 return atColumnHeader.getAccessibleRowCount(); 3330 } 3331 return -1; 3332 } 3333 }, ac); 3334 } 3335 } 3336 debugString(" ##### getAccessibleTableColumnHeaderRowCount FAILED"); 3337 return -1; 3338 } 3339 3340 /* 3341 * returns the number of column headers in an AccessibleTable that represents 3342 * the column header in an AccessibleTable 3343 */ 3344 private int getAccessibleTableColumnHeaderColumnCount(AccessibleContext ac) { 3345 3346 debugString("##### getAccessibleTableColumnHeaderColumnCount"); 3347 if (ac != null) { 3348 final AccessibleTable atColumnHeader = getAccessibleTableColumnHeader(ac); 3349 if (atColumnHeader != null) { 3350 return InvocationUtils.invokeAndWait(new Callable<Integer>() { 3351 @Override 3352 public Integer call() throws Exception { 3353 if (atColumnHeader != null) { 3354 return atColumnHeader.getAccessibleColumnCount(); 3355 } 3356 return -1; 3357 } 3358 }, ac); 3359 } 3360 } 3361 debugString(" ##### getAccessibleTableColumnHeaderColumnCount FAILED"); 3362 return -1; 3363 } 3364 3365 /* 3366 * returns the description of a row header in an AccessibleTable 3367 */ 3368 private AccessibleContext getAccessibleTableRowDescription(final AccessibleTable table, 3369 final int row) { 3370 return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() { 3371 @Override 3372 public AccessibleContext call() throws Exception { 3373 if (table != null) { 3374 Accessible a = table.getAccessibleRowDescription(row); 3375 if (a != null) { 3376 return a.getAccessibleContext(); 3377 } 3378 } 3379 return null; 3380 } 3381 }, getContextFromAccessibleTable(table)); 3382 } 3383 3384 /* 3385 * returns the description of a column header in an AccessibleTable 3386 */ 3387 private AccessibleContext getAccessibleTableColumnDescription(final AccessibleTable at, 3388 final int column) { 3389 if (at == null) 3390 return null; 3391 return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() { 3392 @Override 3393 public AccessibleContext call() throws Exception { 3394 Accessible a = at.getAccessibleColumnDescription(column); 3395 if (a != null) { 3396 return a.getAccessibleContext(); 3397 } 3398 return null; 3399 } 3400 }, getContextFromAccessibleTable(at)); 3401 } 3402 3403 /* 3404 * returns the number of rows selected in an AccessibleTable 3405 */ 3406 private int getAccessibleTableRowSelectionCount(final AccessibleTable at) { 3407 if (at != null) { 3408 return InvocationUtils.invokeAndWait(new Callable<Integer>() { 3409 @Override 3410 public Integer call() throws Exception { 3411 int[] selections = at.getSelectedAccessibleRows(); 3412 if (selections != null) 3413 return selections.length; 3414 else 3415 return -1; 3416 } 3417 }, getContextFromAccessibleTable(at)); 3418 } 3419 return -1; 3420 } 3421 3422 /* 3423 * returns the row number of the i-th selected row in an AccessibleTable 3424 */ 3425 private int getAccessibleTableRowSelections(final AccessibleTable at, final int i) { 3426 if (at != null) { 3427 return InvocationUtils.invokeAndWait(new Callable<Integer>() { 3428 @Override 3429 public Integer call() throws Exception { 3430 int[] selections = at.getSelectedAccessibleRows(); 3431 if (selections.length > i) { 3432 return selections[i]; 3433 } 3434 return -1; 3435 } 3436 }, getContextFromAccessibleTable(at)); 3437 } 3438 return -1; 3439 } 3440 3441 /* 3442 * returns whether a row is selected in an AccessibleTable 3443 */ 3444 private boolean isAccessibleTableRowSelected(final AccessibleTable at, 3445 final int row) { 3446 if (at == null) 3447 return false; 3448 return InvocationUtils.invokeAndWait(new Callable<Boolean>() { 3449 @Override 3450 public Boolean call() throws Exception { 3451 return at.isAccessibleRowSelected(row); 3452 } 3453 }, getContextFromAccessibleTable(at)); 3454 } 3455 3456 /* 3457 * returns whether a column is selected in an AccessibleTable 3458 */ 3459 private boolean isAccessibleTableColumnSelected(final AccessibleTable at, 3460 final int column) { 3461 if (at == null) 3462 return false; 3463 return InvocationUtils.invokeAndWait(new Callable<Boolean>() { 3464 @Override 3465 public Boolean call() throws Exception { 3466 return at.isAccessibleColumnSelected(column); 3467 } 3468 }, getContextFromAccessibleTable(at)); 3469 } 3470 3471 /* 3472 * returns the number of columns selected in an AccessibleTable 3473 */ 3474 private int getAccessibleTableColumnSelectionCount(final AccessibleTable at) { 3475 if (at == null) 3476 return -1; 3477 return InvocationUtils.invokeAndWait(new Callable<Integer>() { 3478 @Override 3479 public Integer call() throws Exception { 3480 int[] selections = at.getSelectedAccessibleColumns(); 3481 if (selections != null) 3482 return selections.length; 3483 else 3484 return -1; 3485 } 3486 }, getContextFromAccessibleTable(at)); 3487 } 3488 3489 /* 3490 * returns the row number of the i-th selected row in an AccessibleTable 3491 */ 3492 private int getAccessibleTableColumnSelections(final AccessibleTable at, final int i) { 3493 if (at == null) 3494 return -1; 3495 return InvocationUtils.invokeAndWait(new Callable<Integer>() { 3496 @Override 3497 public Integer call() throws Exception { 3498 int[] selections = at.getSelectedAccessibleColumns(); 3499 if (selections != null && selections.length > i) { 3500 return selections[i]; 3501 } 3502 return -1; 3503 } 3504 }, getContextFromAccessibleTable(at)); 3505 } 3506 3507 /* ===== AccessibleExtendedTable (since 1.4) ===== */ 3508 3509 /* 3510 * returns the row number for a cell at a given index in an AccessibleTable 3511 */ 3512 private int getAccessibleTableRow(final AccessibleTable at, int index) { 3513 if (at == null) 3514 return -1; 3515 int colCount=InvocationUtils.invokeAndWait(new Callable<Integer>() { 3516 @Override 3517 public Integer call() throws Exception { 3518 return at.getAccessibleColumnCount(); 3519 } 3520 }, getContextFromAccessibleTable(at)); 3521 return index / colCount; 3522 } 3523 3524 /* 3525 * returns the column number for a cell at a given index in an AccessibleTable 3526 */ 3527 private int getAccessibleTableColumn(final AccessibleTable at, int index) { 3528 if (at == null) 3529 return -1; 3530 int colCount=InvocationUtils.invokeAndWait(new Callable<Integer>() { 3531 @Override 3532 public Integer call() throws Exception { 3533 return at.getAccessibleColumnCount(); 3534 } 3535 }, getContextFromAccessibleTable(at)); 3536 return index % colCount; 3537 } 3538 3539 /* 3540 * returns the index for a cell at a given row and column in an 3541 * AccessibleTable 3542 */ 3543 private int getAccessibleTableIndex(final AccessibleTable at, int row, int column) { 3544 if (at == null) 3545 return -1; 3546 int colCount = InvocationUtils.invokeAndWait(new Callable<Integer>() { 3547 @Override 3548 public Integer call() throws Exception { 3549 return at.getAccessibleColumnCount(); 3550 } 3551 }, getContextFromAccessibleTable(at)); 3552 return row * colCount + column; 3553 } 3554 3555 // ===== AccessibleRelationSet ===== 3556 3557 /* 3558 * returns the number of relations in the AccessibleContext's 3559 * AccessibleRelationSet 3560 */ 3561 private int getAccessibleRelationCount(final AccessibleContext ac) { 3562 String version = getJavaVersionProperty(); 3563 if ((version != null && version.compareTo("1.3") >= 0)) { 3564 if (ac != null) { 3565 AccessibleRelationSet ars = InvocationUtils.invokeAndWait(new Callable<AccessibleRelationSet>() { 3566 @Override 3567 public AccessibleRelationSet call() throws Exception { 3568 return ac.getAccessibleRelationSet(); 3569 } 3570 }, ac); 3571 if (ars != null) 3572 return ars.size(); 3573 } 3574 } 3575 return 0; 3576 } 3577 3578 /* 3579 * returns the ith relation key in the AccessibleContext's 3580 * AccessibleRelationSet 3581 */ 3582 private String getAccessibleRelationKey(final AccessibleContext ac, final int i) { 3583 return InvocationUtils.invokeAndWait(new Callable<String>() { 3584 @Override 3585 public String call() throws Exception { 3586 if (ac != null) { 3587 AccessibleRelationSet ars = ac.getAccessibleRelationSet(); 3588 if (ars != null) { 3589 AccessibleRelation[] relations = ars.toArray(); 3590 if (relations != null && i >= 0 && i < relations.length) { 3591 return relations[i].getKey(); 3592 } 3593 } 3594 } 3595 return null; 3596 } 3597 }, ac); 3598 } 3599 3600 /* 3601 * returns the number of targets in a relation in the AccessibleContext's 3602 * AccessibleRelationSet 3603 */ 3604 private int getAccessibleRelationTargetCount(final AccessibleContext ac, final int i) { 3605 return InvocationUtils.invokeAndWait(new Callable<Integer>() { 3606 @Override 3607 public Integer call() throws Exception { 3608 if (ac != null) { 3609 AccessibleRelationSet ars = ac.getAccessibleRelationSet(); 3610 if (ars != null) { 3611 AccessibleRelation[] relations = ars.toArray(); 3612 if (relations != null && i >= 0 && i < relations.length) { 3613 Object[] targets = relations[i].getTarget(); 3614 return targets.length; 3615 } 3616 } 3617 } 3618 return -1; 3619 } 3620 }, ac); 3621 } 3622 3623 /* 3624 * returns the jth target in the ith relation in the AccessibleContext's 3625 * AccessibleRelationSet 3626 */ 3627 private AccessibleContext getAccessibleRelationTarget(final AccessibleContext ac, 3628 final int i, final int j) { 3629 debugString("***** getAccessibleRelationTarget"); 3630 return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() { 3631 @Override 3632 public AccessibleContext call() throws Exception { 3633 if (ac != null) { 3634 AccessibleRelationSet ars = ac.getAccessibleRelationSet(); 3635 if (ars != null) { 3636 AccessibleRelation[] relations = ars.toArray(); 3637 if (relations != null && i >= 0 && i < relations.length) { 3638 Object[] targets = relations[i].getTarget(); 3639 if (targets != null && j >= 0 & j < targets.length) { 3640 Object o = targets[j]; 3641 if (o instanceof Accessible) { 3642 return ((Accessible) o).getAccessibleContext(); 3643 } 3644 } 3645 } 3646 } 3647 } 3648 return null; 3649 } 3650 }, ac); 3651 } 3652 3653 // ========= AccessibleHypertext ========= 3654 3655 private Map<AccessibleHypertext, AccessibleContext> hyperTextContextMap = new WeakHashMap<>(); 3656 private Map<AccessibleHyperlink, AccessibleContext> hyperLinkContextMap = new WeakHashMap<>(); 3657 3658 /* 3659 * Returns the AccessibleHypertext 3660 */ 3661 private AccessibleHypertext getAccessibleHypertext(final AccessibleContext ac) { 3662 debugString("getAccessibleHyperlink"); 3663 if (ac==null) 3664 return null; 3665 AccessibleHypertext hypertext = InvocationUtils.invokeAndWait(new Callable<AccessibleHypertext>() { 3666 @Override 3667 public AccessibleHypertext call() throws Exception { 3668 AccessibleText at = ac.getAccessibleText(); 3669 if (!(at instanceof AccessibleHypertext)) { 3670 return null; 3671 } 3672 return ((AccessibleHypertext) at); 3673 } 3674 }, ac); 3675 hyperTextContextMap.put(hypertext, ac); 3676 return hypertext; 3677 } 3678 3679 /* 3680 * Returns the number of AccessibleHyperlinks 3681 */ 3682 private int getAccessibleHyperlinkCount(AccessibleContext ac) { 3683 debugString("getAccessibleHyperlinkCount"); 3684 if (ac == null) { 3685 return 0; 3686 } 3687 final AccessibleHypertext hypertext = getAccessibleHypertext(ac); 3688 if (hypertext == null) { 3689 return 0; 3690 } 3691 //return hypertext.getLinkCount(); 3692 return InvocationUtils.invokeAndWait(new Callable<Integer>() { 3693 @Override 3694 public Integer call() throws Exception { 3695 return hypertext.getLinkCount(); 3696 } 3697 }, ac); 3698 } 3699 3700 /* 3701 * Returns the hyperlink at the specified index 3702 */ 3703 private AccessibleHyperlink getAccessibleHyperlink(final AccessibleHypertext hypertext, final int i) { 3704 debugString("getAccessibleHyperlink"); 3705 if (hypertext == null) { 3706 return null; 3707 } 3708 AccessibleContext ac = hyperTextContextMap.get(hypertext); 3709 if ( i < 0 || i >= 3710 InvocationUtils.invokeAndWait(new Callable<Integer>() { 3711 @Override 3712 public Integer call() throws Exception { 3713 return hypertext.getLinkCount(); 3714 } 3715 }, ac) ) { 3716 return null; 3717 } 3718 AccessibleHyperlink acLink = InvocationUtils.invokeAndWait(new Callable<AccessibleHyperlink>() { 3719 @Override 3720 public AccessibleHyperlink call() throws Exception { 3721 AccessibleHyperlink link = hypertext.getLink(i); 3722 if (link == null || (!link.isValid())) { 3723 return null; 3724 } 3725 return link; 3726 } 3727 }, ac); 3728 hyperLinkContextMap.put(acLink, ac); 3729 return acLink; 3730 } 3731 3732 /* 3733 * Returns the hyperlink object description 3734 */ 3735 private String getAccessibleHyperlinkText(final AccessibleHyperlink link) { 3736 debugString("getAccessibleHyperlinkText"); 3737 if (link == null) { 3738 return null; 3739 } 3740 return InvocationUtils.invokeAndWait(new Callable<String>() { 3741 @Override 3742 public String call() throws Exception { 3743 Object o = link.getAccessibleActionDescription(0); 3744 if (o != null) { 3745 return o.toString(); 3746 } 3747 return null; 3748 } 3749 }, hyperLinkContextMap.get(link)); 3750 } 3751 3752 /* 3753 * Returns the hyperlink URL 3754 */ 3755 private String getAccessibleHyperlinkURL(final AccessibleHyperlink link) { 3756 debugString("getAccessibleHyperlinkURL"); 3757 if (link == null) { 3758 return null; 3759 } 3760 return InvocationUtils.invokeAndWait(new Callable<String>() { 3761 @Override 3762 public String call() throws Exception { 3763 Object o = link.getAccessibleActionObject(0); 3764 if (o != null) { 3765 return o.toString(); 3766 } else { 3767 return null; 3768 } 3769 } 3770 }, hyperLinkContextMap.get(link)); 3771 } 3772 3773 /* 3774 * Returns the start index of the hyperlink text 3775 */ 3776 private int getAccessibleHyperlinkStartIndex(final AccessibleHyperlink link) { 3777 debugString("getAccessibleHyperlinkStartIndex"); 3778 if (link == null) { 3779 return -1; 3780 } 3781 return InvocationUtils.invokeAndWait(new Callable<Integer>() { 3782 @Override 3783 public Integer call() throws Exception { 3784 return link.getStartIndex(); 3785 } 3786 }, hyperLinkContextMap.get(link)); 3787 } 3788 3789 /* 3790 * Returns the end index of the hyperlink text 3791 */ 3792 private int getAccessibleHyperlinkEndIndex(final AccessibleHyperlink link) { 3793 debugString("getAccessibleHyperlinkEndIndex"); 3794 if (link == null) { 3795 return -1; 3796 } 3797 return InvocationUtils.invokeAndWait(new Callable<Integer>() { 3798 @Override 3799 public Integer call() throws Exception { 3800 return link.getEndIndex(); 3801 } 3802 }, hyperLinkContextMap.get(link)); 3803 } 3804 3805 /* 3806 * Returns the index into an array of hyperlinks that 3807 * is associated with this character index, or -1 if there 3808 * is no hyperlink associated with this index. 3809 */ 3810 private int getAccessibleHypertextLinkIndex(final AccessibleHypertext hypertext, final int charIndex) { 3811 debugString("getAccessibleHypertextLinkIndex: charIndex = "+charIndex); 3812 if (hypertext == null) { 3813 return -1; 3814 } 3815 int linkIndex = InvocationUtils.invokeAndWait(new Callable<Integer>() { 3816 @Override 3817 public Integer call() throws Exception { 3818 return hypertext.getLinkIndex(charIndex); 3819 } 3820 }, hyperTextContextMap.get(hypertext)); 3821 debugString("getAccessibleHypertextLinkIndex returning "+linkIndex); 3822 return linkIndex; 3823 } 3824 3825 /* 3826 * Actives the hyperlink 3827 */ 3828 private boolean activateAccessibleHyperlink(final AccessibleContext ac, 3829 final AccessibleHyperlink link) { 3830 //debugString("activateAccessibleHyperlink: link = "+link.getClass()); 3831 if (link == null) { 3832 return false; 3833 } 3834 boolean retval = InvocationUtils.invokeAndWait(new Callable<Boolean>() { 3835 @Override 3836 public Boolean call() throws Exception { 3837 return link.doAccessibleAction(0); 3838 } 3839 }, ac); 3840 debugString("activateAccessibleHyperlink: returning = "+retval); 3841 return retval; 3842 } 3843 3844 3845 // ============ AccessibleKeyBinding ============= 3846 3847 /* 3848 * returns the component mnemonic 3849 */ 3850 private KeyStroke getMnemonic(final AccessibleContext ac) { 3851 if (ac == null) 3852 return null; 3853 return InvocationUtils.invokeAndWait(new Callable<KeyStroke>() { 3854 @Override 3855 public KeyStroke call() throws Exception { 3856 AccessibleComponent comp = ac.getAccessibleComponent(); 3857 if (!(comp instanceof AccessibleExtendedComponent)) { 3858 return null; 3859 } 3860 AccessibleExtendedComponent aec = (AccessibleExtendedComponent) comp; 3861 if (aec != null) { 3862 AccessibleKeyBinding akb = aec.getAccessibleKeyBinding(); 3863 if (akb != null) { 3864 Object o = akb.getAccessibleKeyBinding(0); 3865 if (o instanceof KeyStroke) { 3866 return (KeyStroke) o; 3867 } 3868 } 3869 } 3870 return null; 3871 } 3872 }, ac); 3873 } 3874 3875 /* 3876 * returns the JMenuItem accelerator 3877 */ 3878 private KeyStroke getAccelerator(final AccessibleContext ac) { 3879 // workaround for getAccessibleKeyBinding not returning the 3880 // JMenuItem accelerator 3881 if (ac == null) 3882 return null; 3883 return InvocationUtils.invokeAndWait(new Callable<KeyStroke>() { 3884 @Override 3885 public KeyStroke call() throws Exception { 3886 Accessible parent = ac.getAccessibleParent(); 3887 if (parent instanceof Accessible) { 3888 int indexInParent = ac.getAccessibleIndexInParent(); 3889 Accessible child = 3890 parent.getAccessibleContext().getAccessibleChild(indexInParent); 3891 if (child instanceof JMenuItem) { 3892 JMenuItem menuItem = (JMenuItem) child; 3893 if (menuItem == null) 3894 return null; 3895 KeyStroke keyStroke = menuItem.getAccelerator(); 3896 return keyStroke; 3897 } 3898 } 3899 return null; 3900 } 3901 }, ac); 3902 } 3903 3904 /* 3905 * returns 1-24 to indicate which F key is being used for a shortcut or 0 otherwise 3906 */ 3907 private int fKeyNumber(KeyStroke keyStroke) { 3908 if (keyStroke == null) 3909 return 0; 3910 int fKey = 0; 3911 String keyText = KeyEvent.getKeyText(keyStroke.getKeyCode()); 3912 if (keyText != null && (keyText.length() == 2 || keyText.length() == 3)) { 3913 String prefix = keyText.substring(0, 1); 3914 if (prefix.equals("F")) { 3915 try { 3916 int suffix = Integer.parseInt(keyText.substring(1)); 3917 if (suffix >= 1 && suffix <= 24) { 3918 fKey = suffix; 3919 } 3920 } catch (Exception e) { // ignore NumberFormatException 3921 } 3922 } 3923 } 3924 return fKey; 3925 } 3926 3927 /* 3928 * returns one of several important control characters or 0 otherwise 3929 */ 3930 private int controlCode(KeyStroke keyStroke) { 3931 if (keyStroke == null) 3932 return 0; 3933 int code = keyStroke.getKeyCode(); 3934 switch (code) { 3935 case KeyEvent.VK_BACK_SPACE: 3936 case KeyEvent.VK_DELETE: 3937 case KeyEvent.VK_DOWN: 3938 case KeyEvent.VK_END: 3939 case KeyEvent.VK_HOME: 3940 case KeyEvent.VK_INSERT: 3941 case KeyEvent.VK_KP_DOWN: 3942 case KeyEvent.VK_KP_LEFT: 3943 case KeyEvent.VK_KP_RIGHT: 3944 case KeyEvent.VK_KP_UP: 3945 case KeyEvent.VK_LEFT: 3946 case KeyEvent.VK_PAGE_DOWN: 3947 case KeyEvent.VK_PAGE_UP: 3948 case KeyEvent.VK_RIGHT: 3949 case KeyEvent.VK_UP: 3950 break; 3951 default: 3952 code = 0; 3953 break; 3954 } 3955 return code; 3956 } 3957 3958 /* 3959 * returns the KeyStoke character 3960 */ 3961 private char getKeyChar(KeyStroke keyStroke) { 3962 // If the shortcut is an FKey return 1-24 3963 if (keyStroke == null) 3964 return 0; 3965 int fKey = fKeyNumber(keyStroke); 3966 if (fKey != 0) { 3967 // return 0x00000001 through 0x00000018 3968 debugString(" Shortcut is: F" + fKey); 3969 return (char)fKey; 3970 } 3971 // If the accelerator is a control character, return it 3972 int keyCode = controlCode(keyStroke); 3973 if (keyCode != 0) { 3974 debugString(" Shortcut is control character: " + Integer.toHexString(keyCode)); 3975 return (char)keyCode; 3976 } 3977 String keyText = KeyEvent.getKeyText(keyStroke.getKeyCode()); 3978 debugString(" Shortcut is: " + keyText); 3979 if (keyText != null || keyText.length() > 0) { 3980 CharSequence seq = keyText.subSequence(0, 1); 3981 if (seq != null || seq.length() > 0) { 3982 return seq.charAt(0); 3983 } 3984 } 3985 return 0; 3986 } 3987 3988 /* 3989 * returns the KeyStroke modifiers as an int 3990 */ 3991 private int getModifiers(KeyStroke keyStroke) { 3992 if (keyStroke == null) 3993 return 0; 3994 debugString("In AccessBridge.getModifiers"); 3995 // modifiers is a bit strip where bits 0-7 indicate a traditional modifier 3996 // such as Ctrl/Alt/Shift, bit 8 indicates an F key shortcut, and bit 9 indicates 3997 // a control code shortcut such as the delete key. 3998 3999 int modifiers = 0; 4000 // Is the shortcut an FKey? 4001 if (fKeyNumber(keyStroke) != 0) { 4002 modifiers |= 1 << 8; 4003 } 4004 // Is the shortcut a control code? 4005 if (controlCode(keyStroke) != 0) { 4006 modifiers |= 1 << 9; 4007 } 4008 // The following is needed in order to handle translated modifiers. 4009 // getKeyModifiersText doesn't work because for example in German Strg is 4010 // returned for Ctrl. 4011 4012 // There can be more than one modifier, e.g. if the modifier is ctrl + shift + B 4013 // the toString text is "shift ctrl pressed B". Need to parse through that. 4014 StringTokenizer st = new StringTokenizer(keyStroke.toString()); 4015 while (st.hasMoreTokens()) { 4016 String text = st.nextToken(); 4017 // Meta+Ctrl+Alt+Shift 4018 // 0-3 are shift, ctrl, meta, alt 4019 // 4-7 are for Solaris workstations (though not being used) 4020 if (text.startsWith("met")) { 4021 debugString(" found meta"); 4022 modifiers |= ActionEvent.META_MASK; 4023 } 4024 if (text.startsWith("ctr")) { 4025 debugString(" found ctrl"); 4026 modifiers |= ActionEvent.CTRL_MASK; 4027 } 4028 if (text.startsWith("alt")) { 4029 debugString(" found alt"); 4030 modifiers |= ActionEvent.ALT_MASK; 4031 } 4032 if (text.startsWith("shi")) { 4033 debugString(" found shift"); 4034 modifiers |= ActionEvent.SHIFT_MASK; 4035 } 4036 } 4037 debugString(" returning modifiers: 0x" + Integer.toHexString(modifiers)); 4038 return modifiers; 4039 } 4040 4041 /* 4042 * returns the number of key bindings associated with this context 4043 */ 4044 private int getAccessibleKeyBindingsCount(AccessibleContext ac) { 4045 if (ac == null || (! runningOnJDK1_4) ) 4046 return 0; 4047 int count = 0; 4048 4049 if (getMnemonic(ac) != null) { 4050 count++; 4051 } 4052 if (getAccelerator(ac) != null) { 4053 count++; 4054 } 4055 return count; 4056 } 4057 4058 /* 4059 * returns the key binding character at the specified index 4060 */ 4061 private char getAccessibleKeyBindingChar(AccessibleContext ac, int index) { 4062 if (ac == null || (! runningOnJDK1_4) ) 4063 return 0; 4064 if((index == 0) && getMnemonic(ac)==null) {// special case when there is no mnemonic 4065 KeyStroke keyStroke = getAccelerator(ac); 4066 if (keyStroke != null) { 4067 return getKeyChar(keyStroke); 4068 } 4069 } 4070 if (index == 0) { // mnemonic 4071 KeyStroke keyStroke = getMnemonic(ac); 4072 if (keyStroke != null) { 4073 return getKeyChar(keyStroke); 4074 } 4075 } else if (index == 1) { // accelerator 4076 KeyStroke keyStroke = getAccelerator(ac); 4077 if (keyStroke != null) { 4078 return getKeyChar(keyStroke); 4079 } 4080 } 4081 return 0; 4082 } 4083 4084 /* 4085 * returns the key binding modifiers at the specified index 4086 */ 4087 private int getAccessibleKeyBindingModifiers(AccessibleContext ac, int index) { 4088 if (ac == null || (! runningOnJDK1_4) ) 4089 return 0; 4090 if((index == 0) && getMnemonic(ac)==null) {// special case when there is no mnemonic 4091 KeyStroke keyStroke = getAccelerator(ac); 4092 if (keyStroke != null) { 4093 return getModifiers(keyStroke); 4094 } 4095 } 4096 if (index == 0) { // mnemonic 4097 KeyStroke keyStroke = getMnemonic(ac); 4098 if (keyStroke != null) { 4099 return getModifiers(keyStroke); 4100 } 4101 } else if (index == 1) { // accelerator 4102 KeyStroke keyStroke = getAccelerator(ac); 4103 if (keyStroke != null) { 4104 return getModifiers(keyStroke); 4105 } 4106 } 4107 return 0; 4108 } 4109 4110 // ========== AccessibleIcon ============ 4111 4112 /* 4113 * return the number of icons associated with this context 4114 */ 4115 private int getAccessibleIconsCount(final AccessibleContext ac) { 4116 debugString("getAccessibleIconsCount"); 4117 if (ac == null) { 4118 return 0; 4119 } 4120 return InvocationUtils.invokeAndWait(new Callable<Integer>() { 4121 @Override 4122 public Integer call() throws Exception { 4123 AccessibleIcon[] ai = ac.getAccessibleIcon(); 4124 if (ai == null) { 4125 return 0; 4126 } 4127 return ai.length; 4128 } 4129 }, ac); 4130 } 4131 4132 /* 4133 * return icon description at the specified index 4134 */ 4135 private String getAccessibleIconDescription(final AccessibleContext ac, final int index) { 4136 debugString("getAccessibleIconDescription: index = "+index); 4137 if (ac == null) { 4138 return null; 4139 } 4140 return InvocationUtils.invokeAndWait(new Callable<String>() { 4141 @Override 4142 public String call() throws Exception { 4143 AccessibleIcon[] ai = ac.getAccessibleIcon(); 4144 if (ai == null || index < 0 || index >= ai.length) { 4145 return null; 4146 } 4147 return ai[index].getAccessibleIconDescription(); 4148 } 4149 }, ac); 4150 } 4151 4152 /* 4153 * return icon height at the specified index 4154 */ 4155 private int getAccessibleIconHeight(final AccessibleContext ac, final int index) { 4156 debugString("getAccessibleIconHeight: index = "+index); 4157 if (ac == null) { 4158 return 0; 4159 } 4160 return InvocationUtils.invokeAndWait(new Callable<Integer>() { 4161 @Override 4162 public Integer call() throws Exception { 4163 AccessibleIcon[] ai = ac.getAccessibleIcon(); 4164 if (ai == null || index < 0 || index >= ai.length) { 4165 return 0; 4166 } 4167 return ai[index].getAccessibleIconHeight(); 4168 } 4169 }, ac); 4170 } 4171 4172 /* 4173 * return icon width at the specified index 4174 */ 4175 private int getAccessibleIconWidth(final AccessibleContext ac, final int index) { 4176 debugString("getAccessibleIconWidth: index = "+index); 4177 if (ac == null) { 4178 return 0; 4179 } 4180 return InvocationUtils.invokeAndWait(new Callable<Integer>() { 4181 @Override 4182 public Integer call() throws Exception { 4183 AccessibleIcon[] ai = ac.getAccessibleIcon(); 4184 if (ai == null || index < 0 || index >= ai.length) { 4185 return 0; 4186 } 4187 return ai[index].getAccessibleIconWidth(); 4188 } 4189 }, ac); 4190 } 4191 4192 // ========= AccessibleAction =========== 4193 4194 /* 4195 * return the number of icons associated with this context 4196 */ 4197 private int getAccessibleActionsCount(final AccessibleContext ac) { 4198 debugString("getAccessibleActionsCount"); 4199 if (ac == null) { 4200 return 0; 4201 } 4202 return InvocationUtils.invokeAndWait(new Callable<Integer>() { 4203 @Override 4204 public Integer call() throws Exception { 4205 AccessibleAction aa = ac.getAccessibleAction(); 4206 if (aa == null) 4207 return 0; 4208 return aa.getAccessibleActionCount(); 4209 } 4210 }, ac); 4211 } 4212 4213 /* 4214 * return icon description at the specified index 4215 */ 4216 private String getAccessibleActionName(final AccessibleContext ac, final int index) { 4217 debugString("getAccessibleActionName: index = "+index); 4218 if (ac == null) { 4219 return null; 4220 } 4221 return InvocationUtils.invokeAndWait(new Callable<String>() { 4222 @Override 4223 public String call() throws Exception { 4224 AccessibleAction aa = ac.getAccessibleAction(); 4225 if (aa == null) { 4226 return null; 4227 } 4228 return aa.getAccessibleActionDescription(index); 4229 } 4230 }, ac); 4231 } 4232 /* 4233 * return icon description at the specified index 4234 */ 4235 private boolean doAccessibleActions(final AccessibleContext ac, final String name) { 4236 debugString("doAccessibleActions: action name = "+name); 4237 if (ac == null || name == null) { 4238 return false; 4239 } 4240 return InvocationUtils.invokeAndWait(new Callable<Boolean>() { 4241 @Override 4242 public Boolean call() throws Exception { 4243 AccessibleAction aa = ac.getAccessibleAction(); 4244 if (aa == null) { 4245 return false; 4246 } 4247 int index = -1; 4248 int numActions = aa.getAccessibleActionCount(); 4249 for (int i = 0; i < numActions; i++) { 4250 String actionName = aa.getAccessibleActionDescription(i); 4251 if (name.equals(actionName)) { 4252 index = i; 4253 break; 4254 } 4255 } 4256 if (index == -1) { 4257 return false; 4258 } 4259 boolean retval = aa.doAccessibleAction(index); 4260 return retval; 4261 } 4262 }, ac); 4263 } 4264 4265 /* ===== AT utility methods ===== */ 4266 4267 /** 4268 * Sets the contents of an AccessibleContext that 4269 * implements AccessibleEditableText with the 4270 * specified text string. 4271 * Returns whether successful. 4272 */ 4273 private boolean setTextContents(final AccessibleContext ac, final String text) { 4274 debugString("setTextContents: ac = "+ac+"; text = "+text); 4275 4276 if (! (ac instanceof AccessibleEditableText)) { 4277 debugString(" ac not instanceof AccessibleEditableText: "+ac); 4278 return false; 4279 } 4280 if (text == null) { 4281 debugString(" text is null"); 4282 return false; 4283 } 4284 4285 return InvocationUtils.invokeAndWait(new Callable<Boolean>() { 4286 @Override 4287 public Boolean call() throws Exception { 4288 // check whether the text field is editable 4289 AccessibleStateSet ass = ac.getAccessibleStateSet(); 4290 if (!ass.contains(AccessibleState.ENABLED)) { 4291 return false; 4292 } 4293 ((AccessibleEditableText) ac).setTextContents(text); 4294 return true; 4295 } 4296 }, ac); 4297 } 4298 4299 /** 4300 * Returns the Accessible Context of an Internal Frame object that is 4301 * the ancestor of a given object. If the object is an Internal Frame 4302 * object or an Internal Frame ancestor object was found, returns the 4303 * object's AccessibleContext. 4304 * If there is no ancestor object that has an Accessible Role of 4305 * Internal Frame, returns (AccessibleContext)0. 4306 */ 4307 private AccessibleContext getInternalFrame (AccessibleContext ac) { 4308 return getParentWithRole(ac, AccessibleRole.INTERNAL_FRAME.toString()); 4309 } 4310 4311 /** 4312 * Returns the Accessible Context for the top level object in 4313 * a Java Window. This is same Accessible Context that is obtained 4314 * from GetAccessibleContextFromHWND for that window. Returns 4315 * (AccessibleContext)0 on error. 4316 */ 4317 private AccessibleContext getTopLevelObject (final AccessibleContext ac) { 4318 debugString("getTopLevelObject; ac = "+ac); 4319 if (ac == null) { 4320 return null; 4321 } 4322 return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() { 4323 @Override 4324 public AccessibleContext call() throws Exception { 4325 if (ac.getAccessibleRole() == AccessibleRole.DIALOG) { 4326 // return the dialog, not the parent window 4327 return ac; 4328 } 4329 4330 Accessible parent = ac.getAccessibleParent(); 4331 if (parent == null) { 4332 return ac; 4333 } 4334 Accessible tmp = parent; 4335 while (tmp != null && tmp.getAccessibleContext() != null) { 4336 AccessibleContext ac2 = tmp.getAccessibleContext(); 4337 if (ac2 != null && ac2.getAccessibleRole() == AccessibleRole.DIALOG) { 4338 // return the dialog, not the parent window 4339 return ac2; 4340 } 4341 parent = tmp; 4342 tmp = parent.getAccessibleContext().getAccessibleParent(); 4343 } 4344 return parent.getAccessibleContext(); 4345 } 4346 }, ac); 4347 } 4348 4349 /** 4350 * Returns the parent AccessibleContext that has the specified AccessibleRole. 4351 * Returns null on error or if the AccessibleContext does not exist. 4352 */ 4353 private AccessibleContext getParentWithRole (final AccessibleContext ac, 4354 final String roleName) { 4355 debugString("getParentWithRole; ac = "+ac); 4356 debugString("role = "+roleName); 4357 if (ac == null || roleName == null) { 4358 return null; 4359 } 4360 4361 return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() { 4362 @Override 4363 public AccessibleContext call() throws Exception { 4364 AccessibleRole role = AccessBridge.this.accessibleRoleMap.get(roleName); 4365 if (role == null) { 4366 return ac; 4367 } 4368 4369 Accessible parent = ac.getAccessibleParent(); 4370 if (parent == null && ac.getAccessibleRole() == role) { 4371 return ac; 4372 } 4373 4374 Accessible tmp = parent; 4375 AccessibleContext tmp_ac = null; 4376 4377 while (tmp != null && (tmp_ac = tmp.getAccessibleContext()) != null) { 4378 AccessibleRole ar = tmp_ac.getAccessibleRole(); 4379 if (ar == role) { 4380 // found 4381 return tmp_ac; 4382 } 4383 parent = tmp; 4384 tmp = parent.getAccessibleContext().getAccessibleParent(); 4385 } 4386 // not found 4387 return null; 4388 } 4389 }, ac); 4390 } 4391 4392 /** 4393 * Returns the parent AccessibleContext that has the specified AccessibleRole. 4394 * Otherwise, returns the top level object for the Java Window. 4395 * Returns (AccessibleContext)0 on error. 4396 */ 4397 private AccessibleContext getParentWithRoleElseRoot (AccessibleContext ac, 4398 String roleName) { 4399 AccessibleContext retval = getParentWithRole(ac, roleName); 4400 if (retval == null) { 4401 retval = getTopLevelObject(ac); 4402 } 4403 return retval; 4404 } 4405 4406 /** 4407 * Returns how deep in the object hierarchy a given object is. 4408 * The top most object in the object hierarchy has an object depth of 0. 4409 * Returns -1 on error. 4410 */ 4411 private int getObjectDepth(final AccessibleContext ac) { 4412 debugString("getObjectDepth: ac = "+ac); 4413 4414 if (ac == null) { 4415 return -1; 4416 } 4417 return InvocationUtils.invokeAndWait(new Callable<Integer>() { 4418 @Override 4419 public Integer call() throws Exception { 4420 int count = 0; 4421 Accessible parent = ac.getAccessibleParent(); 4422 if (parent == null) { 4423 return count; 4424 } 4425 Accessible tmp = parent; 4426 while (tmp != null && tmp.getAccessibleContext() != null) { 4427 parent = tmp; 4428 tmp = parent.getAccessibleContext().getAccessibleParent(); 4429 count++; 4430 } 4431 return count; 4432 } 4433 }, ac); 4434 } 4435 4436 /** 4437 * Returns the Accessible Context of the current ActiveDescendent of an object. 4438 * Returns (AccessibleContext)0 on error. 4439 */ 4440 private AccessibleContext getActiveDescendent (final AccessibleContext ac) { 4441 debugString("getActiveDescendent: ac = "+ac); 4442 if (ac == null) { 4443 return null; 4444 } 4445 // workaround for JTree bug where the only possible active 4446 // descendent is the JTree root 4447 final Accessible parent = InvocationUtils.invokeAndWait(new Callable<Accessible>() { 4448 @Override 4449 public Accessible call() throws Exception { 4450 return ac.getAccessibleParent(); 4451 } 4452 }, ac); 4453 4454 if (parent != null) { 4455 Accessible child = InvocationUtils.invokeAndWait(new Callable<Accessible>() { 4456 @Override 4457 public Accessible call() throws Exception { 4458 int indexInParent = ac.getAccessibleIndexInParent(); 4459 return parent.getAccessibleContext().getAccessibleChild(indexInParent); 4460 } 4461 }, ac); 4462 4463 if (child instanceof JTree) { 4464 // return the selected node 4465 final JTree tree = (JTree)child; 4466 return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() { 4467 @Override 4468 public AccessibleContext call() throws Exception { 4469 return new AccessibleJTreeNode(tree, 4470 tree.getSelectionPath(), 4471 null); 4472 } 4473 }, child); 4474 } 4475 } 4476 4477 return InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() { 4478 @Override 4479 public AccessibleContext call() throws Exception { 4480 AccessibleSelection as = ac.getAccessibleSelection(); 4481 if (as == null) { 4482 return null; 4483 } 4484 // assume single selection 4485 if (as.getAccessibleSelectionCount() != 1) { 4486 return null; 4487 } 4488 Accessible a = as.getAccessibleSelection(0); 4489 if (a == null) { 4490 return null; 4491 } 4492 return a.getAccessibleContext(); 4493 } 4494 }, ac); 4495 } 4496 4497 4498 /** 4499 * Additional methods for Teton 4500 */ 4501 4502 /** 4503 * Gets the AccessibleName for a component based upon the JAWS algorithm. 4504 * Returns whether successful. 4505 * 4506 * Bug ID 4916682 - Implement JAWS AccessibleName policy 4507 */ 4508 private String getJAWSAccessibleName(final AccessibleContext ac) { 4509 debugString("getJAWSAccessibleName"); 4510 if (ac == null) { 4511 return null; 4512 } 4513 // placeholder 4514 return InvocationUtils.invokeAndWait(new Callable<String>() { 4515 @Override 4516 public String call() throws Exception { 4517 return ac.getAccessibleName(); 4518 } 4519 }, ac); 4520 } 4521 4522 /** 4523 * Request focus for a component. Returns whether successful; 4524 * 4525 * Bug ID 4944757 - requestFocus method needed 4526 */ 4527 private boolean requestFocus(final AccessibleContext ac) { 4528 debugString("requestFocus"); 4529 if (ac == null) { 4530 return false; 4531 } 4532 return InvocationUtils.invokeAndWait(new Callable<Boolean>() { 4533 @Override 4534 public Boolean call() throws Exception { 4535 AccessibleComponent acomp = ac.getAccessibleComponent(); 4536 if (acomp == null) { 4537 return false; 4538 } 4539 acomp.requestFocus(); 4540 return ac.getAccessibleStateSet().contains(AccessibleState.FOCUSED); 4541 } 4542 }, ac); 4543 } 4544 4545 /** 4546 * Selects text between two indices. Selection includes the 4547 * text at the start index and the text at the end index. Returns 4548 * whether successful; 4549 * 4550 * Bug ID 4944758 - selectTextRange method needed 4551 */ 4552 private boolean selectTextRange(final AccessibleContext ac, final int startIndex, final int endIndex) { 4553 debugString("selectTextRange: start = "+startIndex+"; end = "+endIndex); 4554 if (ac == null) { 4555 return false; 4556 } 4557 return InvocationUtils.invokeAndWait(new Callable<Boolean>() { 4558 @Override 4559 public Boolean call() throws Exception { 4560 AccessibleText at = ac.getAccessibleText(); 4561 if (!(at instanceof AccessibleEditableText)) { 4562 return false; 4563 } 4564 ((AccessibleEditableText) at).selectText(startIndex, endIndex); 4565 4566 boolean result = at.getSelectionStart() == startIndex && 4567 at.getSelectionEnd() == endIndex; 4568 return result; 4569 } 4570 }, ac); 4571 } 4572 4573 /** 4574 * Set the caret to a text position. Returns whether successful; 4575 * 4576 * Bug ID 4944770 - setCaretPosition method needed 4577 */ 4578 private boolean setCaretPosition(final AccessibleContext ac, final int position) { 4579 debugString("setCaretPosition: position = "+position); 4580 if (ac == null) { 4581 return false; 4582 } 4583 return InvocationUtils.invokeAndWait(new Callable<Boolean>() { 4584 @Override 4585 public Boolean call() throws Exception { 4586 AccessibleText at = ac.getAccessibleText(); 4587 if (!(at instanceof AccessibleEditableText)) { 4588 return false; 4589 } 4590 ((AccessibleEditableText) at).selectText(position, position); 4591 return at.getCaretPosition() == position; 4592 } 4593 }, ac); 4594 } 4595 4596 /** 4597 * Gets the number of visible children of an AccessibleContext. 4598 * 4599 * Bug ID 4944762- getVisibleChildren for list-like components needed 4600 */ 4601 private int _visibleChildrenCount; 4602 private AccessibleContext _visibleChild; 4603 private int _currentVisibleIndex; 4604 private boolean _foundVisibleChild; 4605 4606 private int getVisibleChildrenCount(AccessibleContext ac) { 4607 debugString("getVisibleChildrenCount"); 4608 if (ac == null) { 4609 return -1; 4610 } 4611 _visibleChildrenCount = 0; 4612 _getVisibleChildrenCount(ac); 4613 debugString(" _visibleChildrenCount = "+_visibleChildrenCount); 4614 return _visibleChildrenCount; 4615 } 4616 4617 /* 4618 * Recursively descends AccessibleContext and gets the number 4619 * of visible children 4620 */ 4621 private void _getVisibleChildrenCount(final AccessibleContext ac) { 4622 if (ac == null) 4623 return; 4624 int numChildren = InvocationUtils.invokeAndWait(new Callable<Integer>() { 4625 @Override 4626 public Integer call() throws Exception { 4627 return ac.getAccessibleChildrenCount(); 4628 } 4629 }, ac); 4630 for (int i = 0; i < numChildren; i++) { 4631 final int idx = i; 4632 final AccessibleContext ac2 = InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() { 4633 @Override 4634 public AccessibleContext call() throws Exception { 4635 Accessible a = ac.getAccessibleChild(idx); 4636 if (a != null) 4637 return a.getAccessibleContext(); 4638 else 4639 return null; 4640 } 4641 }, ac); 4642 if ( ac2 == null || 4643 (!InvocationUtils.invokeAndWait(new Callable<Boolean>() { 4644 @Override 4645 public Boolean call() throws Exception { 4646 return ac2.getAccessibleStateSet().contains(AccessibleState.SHOWING); 4647 } 4648 }, ac)) 4649 ) { 4650 continue; 4651 } 4652 _visibleChildrenCount++; 4653 4654 if (InvocationUtils.invokeAndWait(new Callable<Integer>() { 4655 @Override 4656 public Integer call() throws Exception { 4657 return ac2.getAccessibleChildrenCount(); 4658 } 4659 }, ac) > 0 ) { 4660 _getVisibleChildrenCount(ac2); 4661 } 4662 } 4663 } 4664 4665 /** 4666 * Gets the visible child of an AccessibleContext at the 4667 * specified index 4668 * 4669 * Bug ID 4944762- getVisibleChildren for list-like components needed 4670 */ 4671 private AccessibleContext getVisibleChild(AccessibleContext ac, int index) { 4672 debugString("getVisibleChild: index = "+index); 4673 if (ac == null) { 4674 return null; 4675 } 4676 _visibleChild = null; 4677 _currentVisibleIndex = 0; 4678 _foundVisibleChild = false; 4679 _getVisibleChild(ac, index); 4680 4681 if (_visibleChild != null) { 4682 debugString( " getVisibleChild: found child = " + 4683 InvocationUtils.invokeAndWait(new Callable<String>() { 4684 @Override 4685 public String call() throws Exception { 4686 return AccessBridge.this._visibleChild.getAccessibleName(); 4687 } 4688 }, ac) ); 4689 } 4690 return _visibleChild; 4691 } 4692 4693 /* 4694 * Recursively searchs AccessibleContext and finds the visible component 4695 * at the specified index 4696 */ 4697 private void _getVisibleChild(final AccessibleContext ac, final int index) { 4698 if (_visibleChild != null) { 4699 return; 4700 } 4701 4702 int numChildren = InvocationUtils.invokeAndWait(new Callable<Integer>() { 4703 @Override 4704 public Integer call() throws Exception { 4705 return ac.getAccessibleChildrenCount(); 4706 } 4707 }, ac); 4708 for (int i = 0; i < numChildren; i++) { 4709 final int idx=i; 4710 final AccessibleContext ac2=InvocationUtils.invokeAndWait(new Callable<AccessibleContext>() { 4711 @Override 4712 public AccessibleContext call() throws Exception { 4713 Accessible a = ac.getAccessibleChild(idx); 4714 if (a == null) 4715 return null; 4716 else 4717 return a.getAccessibleContext(); 4718 } 4719 }, ac); 4720 if (ac2 == null || 4721 (!InvocationUtils.invokeAndWait(new Callable<Boolean>() { 4722 @Override 4723 public Boolean call() throws Exception { 4724 return ac2.getAccessibleStateSet().contains(AccessibleState.SHOWING); 4725 } 4726 }, ac))) { 4727 continue; 4728 } 4729 if (!_foundVisibleChild && _currentVisibleIndex == index) { 4730 _visibleChild = ac2; 4731 _foundVisibleChild = true; 4732 return; 4733 } 4734 _currentVisibleIndex++; 4735 4736 if ( InvocationUtils.invokeAndWait(new Callable<Integer>() { 4737 @Override 4738 public Integer call() throws Exception { 4739 return ac2.getAccessibleChildrenCount(); 4740 } 4741 }, ac) > 0 ) { 4742 _getVisibleChild(ac2, index); 4743 } 4744 } 4745 } 4746 4747 4748 /* ===== Java object memory management code ===== */ 4749 4750 /** 4751 * Class to track object references to ensure the 4752 * Java VM doesn't garbage collect them 4753 */ 4754 private class ObjectReferences { 4755 4756 private class Reference { 4757 private int value; 4758 4759 Reference(int i) { 4760 value = i; 4761 } 4762 4763 public String toString() { 4764 return ("refCount: " + value); 4765 } 4766 } 4767 4768 /** 4769 * table object references, to keep 'em from being garbage collected 4770 */ 4771 private ConcurrentHashMap<Object,Reference> refs; 4772 4773 /** 4774 * Constructor 4775 */ 4776 ObjectReferences() { 4777 refs = new ConcurrentHashMap<>(4); 4778 } 4779 4780 /** 4781 * Debugging: dump the contents of ObjectReferences' refs Hashtable 4782 */ 4783 String dump() { 4784 return refs.toString(); 4785 } 4786 4787 /** 4788 * Increment ref count; set to 1 if we have no references for it 4789 */ 4790 void increment(Object o) { 4791 if (o == null){ 4792 debugString("ObjectReferences::increment - Passed in object is null"); 4793 return; 4794 } 4795 4796 if (refs.containsKey(o)) { 4797 (refs.get(o)).value++; 4798 } else { 4799 refs.put(o, new Reference(1)); 4800 } 4801 } 4802 4803 /** 4804 * Decrement ref count; remove if count drops to 0 4805 */ 4806 void decrement(Object o) { 4807 Reference aRef = refs.get(o); 4808 if (aRef != null) { 4809 aRef.value--; 4810 if (aRef.value == 0) { 4811 refs.remove(o); 4812 } else if (aRef.value < 0) { 4813 debugString("ERROR: decrementing reference count below 0"); 4814 } 4815 } else { 4816 debugString("ERROR: object to decrement not in ObjectReferences table"); 4817 } 4818 } 4819 4820 } 4821 4822 /* ===== event handling code ===== */ 4823 4824 /** 4825 * native method for handling property change events 4826 */ 4827 private native void propertyCaretChange(PropertyChangeEvent e, 4828 AccessibleContext src, 4829 int oldValue, int newValue); 4830 private native void propertyDescriptionChange(PropertyChangeEvent e, 4831 AccessibleContext src, 4832 String oldValue, String newValue); 4833 private native void propertyNameChange(PropertyChangeEvent e, 4834 AccessibleContext src, 4835 String oldValue, String newValue); 4836 private native void propertySelectionChange(PropertyChangeEvent e, 4837 AccessibleContext src); 4838 private native void propertyStateChange(PropertyChangeEvent e, 4839 AccessibleContext src, 4840 String oldValue, String newValue); 4841 private native void propertyTextChange(PropertyChangeEvent e, 4842 AccessibleContext src); 4843 private native void propertyValueChange(PropertyChangeEvent e, 4844 AccessibleContext src, 4845 String oldValue, String newValue); 4846 private native void propertyVisibleDataChange(PropertyChangeEvent e, 4847 AccessibleContext src); 4848 private native void propertyChildChange(PropertyChangeEvent e, 4849 AccessibleContext src, 4850 AccessibleContext oldValue, 4851 AccessibleContext newValue); 4852 private native void propertyActiveDescendentChange(PropertyChangeEvent e, 4853 AccessibleContext src, 4854 AccessibleContext oldValue, 4855 AccessibleContext newValue); 4856 4857 private native void javaShutdown(); 4858 4859 /** 4860 * native methods for handling focus events 4861 */ 4862 private native void focusGained(FocusEvent e, AccessibleContext src); 4863 private native void focusLost(FocusEvent e, AccessibleContext src); 4864 4865 /** 4866 * native method for handling caret events 4867 */ 4868 private native void caretUpdate(CaretEvent e, AccessibleContext src); 4869 4870 /** 4871 * native methods for handling mouse events 4872 */ 4873 private native void mouseClicked(MouseEvent e, AccessibleContext src); 4874 private native void mouseEntered(MouseEvent e, AccessibleContext src); 4875 private native void mouseExited(MouseEvent e, AccessibleContext src); 4876 private native void mousePressed(MouseEvent e, AccessibleContext src); 4877 private native void mouseReleased(MouseEvent e, AccessibleContext src); 4878 4879 /** 4880 * native methods for handling menu & popupMenu events 4881 */ 4882 private native void menuCanceled(MenuEvent e, AccessibleContext src); 4883 private native void menuDeselected(MenuEvent e, AccessibleContext src); 4884 private native void menuSelected(MenuEvent e, AccessibleContext src); 4885 private native void popupMenuCanceled(PopupMenuEvent e, AccessibleContext src); 4886 private native void popupMenuWillBecomeInvisible(PopupMenuEvent e, 4887 AccessibleContext src); 4888 private native void popupMenuWillBecomeVisible(PopupMenuEvent e, 4889 AccessibleContext src); 4890 4891 /* ===== event definitions ===== */ 4892 4893 private static final long PROPERTY_CHANGE_EVENTS = 1; 4894 private static final long FOCUS_GAINED_EVENTS = 2; 4895 private static final long FOCUS_LOST_EVENTS = 4; 4896 private static final long FOCUS_EVENTS = (FOCUS_GAINED_EVENTS | FOCUS_LOST_EVENTS); 4897 4898 private static final long CARET_UPATE_EVENTS = 8; 4899 private static final long CARET_EVENTS = CARET_UPATE_EVENTS; 4900 4901 private static final long MOUSE_CLICKED_EVENTS = 16; 4902 private static final long MOUSE_ENTERED_EVENTS = 32; 4903 private static final long MOUSE_EXITED_EVENTS = 64; 4904 private static final long MOUSE_PRESSED_EVENTS = 128; 4905 private static final long MOUSE_RELEASED_EVENTS = 256; 4906 private static final long MOUSE_EVENTS = (MOUSE_CLICKED_EVENTS | MOUSE_ENTERED_EVENTS | 4907 MOUSE_EXITED_EVENTS | MOUSE_PRESSED_EVENTS | 4908 MOUSE_RELEASED_EVENTS); 4909 4910 private static final long MENU_CANCELED_EVENTS = 512; 4911 private static final long MENU_DESELECTED_EVENTS = 1024; 4912 private static final long MENU_SELECTED_EVENTS = 2048; 4913 private static final long MENU_EVENTS = (MENU_CANCELED_EVENTS | MENU_DESELECTED_EVENTS | 4914 MENU_SELECTED_EVENTS); 4915 4916 private static final long POPUPMENU_CANCELED_EVENTS = 4096; 4917 private static final long POPUPMENU_WILL_BECOME_INVISIBLE_EVENTS = 8192; 4918 private static final long POPUPMENU_WILL_BECOME_VISIBLE_EVENTS = 16384; 4919 private static final long POPUPMENU_EVENTS = (POPUPMENU_CANCELED_EVENTS | 4920 POPUPMENU_WILL_BECOME_INVISIBLE_EVENTS | 4921 POPUPMENU_WILL_BECOME_VISIBLE_EVENTS); 4922 4923 /* These use their own numbering scheme, to ensure sufficient expansion room */ 4924 private static final long PROPERTY_NAME_CHANGE_EVENTS = 1; 4925 private static final long PROPERTY_DESCRIPTION_CHANGE_EVENTS = 2; 4926 private static final long PROPERTY_STATE_CHANGE_EVENTS = 4; 4927 private static final long PROPERTY_VALUE_CHANGE_EVENTS = 8; 4928 private static final long PROPERTY_SELECTION_CHANGE_EVENTS = 16; 4929 private static final long PROPERTY_TEXT_CHANGE_EVENTS = 32; 4930 private static final long PROPERTY_CARET_CHANGE_EVENTS = 64; 4931 private static final long PROPERTY_VISIBLEDATA_CHANGE_EVENTS = 128; 4932 private static final long PROPERTY_CHILD_CHANGE_EVENTS = 256; 4933 private static final long PROPERTY_ACTIVEDESCENDENT_CHANGE_EVENTS = 512; 4934 4935 4936 private static final long PROPERTY_EVENTS = (PROPERTY_NAME_CHANGE_EVENTS | 4937 PROPERTY_DESCRIPTION_CHANGE_EVENTS | 4938 PROPERTY_STATE_CHANGE_EVENTS | 4939 PROPERTY_VALUE_CHANGE_EVENTS | 4940 PROPERTY_SELECTION_CHANGE_EVENTS | 4941 PROPERTY_TEXT_CHANGE_EVENTS | 4942 PROPERTY_CARET_CHANGE_EVENTS | 4943 PROPERTY_VISIBLEDATA_CHANGE_EVENTS | 4944 PROPERTY_CHILD_CHANGE_EVENTS | 4945 PROPERTY_ACTIVEDESCENDENT_CHANGE_EVENTS); 4946 4947 /** 4948 * The EventHandler class listens for Java events and 4949 * forwards them to the AT 4950 */ 4951 private class EventHandler implements PropertyChangeListener, 4952 FocusListener, CaretListener, 4953 MenuListener, PopupMenuListener, 4954 MouseListener, WindowListener, 4955 ChangeListener { 4956 4957 private AccessBridge accessBridge; 4958 private long javaEventMask = 0; 4959 private long accessibilityEventMask = 0; 4960 4961 EventHandler(AccessBridge bridge) { 4962 accessBridge = bridge; 4963 4964 // Register to receive WINDOW_OPENED and WINDOW_CLOSED 4965 // events. Add the event source as a native window 4966 // handler is it implements NativeWindowHandler. 4967 // SwingEventMonitor.addWindowListener(this); 4968 } 4969 4970 // --------- Event Notification Registration methods 4971 4972 /** 4973 * Invoked the first time a window is made visible. 4974 */ 4975 public void windowOpened(WindowEvent e) { 4976 // If the window is a NativeWindowHandler, add it. 4977 Object o = null; 4978 if (e != null) 4979 o = e.getSource(); 4980 if (o instanceof NativeWindowHandler) { 4981 addNativeWindowHandler((NativeWindowHandler)o); 4982 } 4983 } 4984 4985 /** 4986 * Invoked when the user attempts to close the window 4987 * from the window's system menu. If the program does not 4988 * explicitly hide or dispose the window while processing 4989 * this event, the window close operation will be canceled. 4990 */ 4991 public void windowClosing(WindowEvent e) {} 4992 4993 /** 4994 * Invoked when a window has been closed as the result 4995 * of calling dispose on the window. 4996 */ 4997 public void windowClosed(WindowEvent e) { 4998 // If the window is a NativeWindowHandler, remove it. 4999 Object o = null; 5000 if (e != null) 5001 o = e.getSource(); 5002 if (o instanceof NativeWindowHandler) { 5003 removeNativeWindowHandler((NativeWindowHandler)o); 5004 } 5005 } 5006 5007 /** 5008 * Invoked when a window is changed from a normal to a 5009 * minimized state. For many platforms, a minimized window 5010 * is displayed as the icon specified in the window's 5011 * iconImage property. 5012 * @see java.awt.Frame#setIconImage 5013 */ 5014 public void windowIconified(WindowEvent e) {} 5015 5016 /** 5017 * Invoked when a window is changed from a minimized 5018 * to a normal state. 5019 */ 5020 public void windowDeiconified(WindowEvent e) {} 5021 5022 /** 5023 * Invoked when the Window is set to be the active Window. Only a Frame or 5024 * a Dialog can be the active Window. The native windowing system may 5025 * denote the active Window or its children with special decorations, such 5026 * as a highlighted title bar. The active Window is always either the 5027 * focused Window, or the first Frame or Dialog that is an owner of the 5028 * focused Window. 5029 */ 5030 public void windowActivated(WindowEvent e) {} 5031 5032 /** 5033 * Invoked when a Window is no longer the active Window. Only a Frame or a 5034 * Dialog can be the active Window. The native windowing system may denote 5035 * the active Window or its children with special decorations, such as a 5036 * highlighted title bar. The active Window is always either the focused 5037 * Window, or the first Frame or Dialog that is an owner of the focused 5038 * Window. 5039 */ 5040 public void windowDeactivated(WindowEvent e) {} 5041 5042 /** 5043 * Turn on event monitoring for the event type passed in 5044 * If necessary, add the appropriate event listener (if 5045 * no other event of that type is being listened for) 5046 */ 5047 void addJavaEventNotification(long type) { 5048 long newEventMask = javaEventMask | type; 5049 /* 5050 if ( ((javaEventMask & PROPERTY_EVENTS) == 0) && 5051 ((newEventMask & PROPERTY_EVENTS) != 0) ) { 5052 AccessibilityEventMonitor.addPropertyChangeListener(this); 5053 } 5054 */ 5055 if ( ((javaEventMask & FOCUS_EVENTS) == 0) && 5056 ((newEventMask & FOCUS_EVENTS) != 0) ) { 5057 SwingEventMonitor.addFocusListener(this); 5058 } 5059 if ( ((javaEventMask & CARET_EVENTS) == 0) && 5060 ((newEventMask & CARET_EVENTS) != 0) ) { 5061 SwingEventMonitor.addCaretListener(this); 5062 } 5063 if ( ((javaEventMask & MOUSE_EVENTS) == 0) && 5064 ((newEventMask & MOUSE_EVENTS) != 0) ) { 5065 SwingEventMonitor.addMouseListener(this); 5066 } 5067 if ( ((javaEventMask & MENU_EVENTS) == 0) && 5068 ((newEventMask & MENU_EVENTS) != 0) ) { 5069 SwingEventMonitor.addMenuListener(this); 5070 SwingEventMonitor.addPopupMenuListener(this); 5071 } 5072 if ( ((javaEventMask & POPUPMENU_EVENTS) == 0) && 5073 ((newEventMask & POPUPMENU_EVENTS) != 0) ) { 5074 SwingEventMonitor.addPopupMenuListener(this); 5075 } 5076 5077 javaEventMask = newEventMask; 5078 } 5079 5080 /** 5081 * Turn off event monitoring for the event type passed in 5082 * If necessary, remove the appropriate event listener (if 5083 * no other event of that type is being listened for) 5084 */ 5085 void removeJavaEventNotification(long type) { 5086 long newEventMask = javaEventMask & (~type); 5087 /* 5088 if ( ((javaEventMask & PROPERTY_EVENTS) != 0) && 5089 ((newEventMask & PROPERTY_EVENTS) == 0) ) { 5090 AccessibilityEventMonitor.removePropertyChangeListener(this); 5091 } 5092 */ 5093 if (((javaEventMask & FOCUS_EVENTS) != 0) && 5094 ((newEventMask & FOCUS_EVENTS) == 0)) { 5095 SwingEventMonitor.removeFocusListener(this); 5096 } 5097 if (((javaEventMask & CARET_EVENTS) != 0) && 5098 ((newEventMask & CARET_EVENTS) == 0)) { 5099 SwingEventMonitor.removeCaretListener(this); 5100 } 5101 if (((javaEventMask & MOUSE_EVENTS) == 0) && 5102 ((newEventMask & MOUSE_EVENTS) != 0)) { 5103 SwingEventMonitor.removeMouseListener(this); 5104 } 5105 if (((javaEventMask & MENU_EVENTS) == 0) && 5106 ((newEventMask & MENU_EVENTS) != 0)) { 5107 SwingEventMonitor.removeMenuListener(this); 5108 } 5109 if (((javaEventMask & POPUPMENU_EVENTS) == 0) && 5110 ((newEventMask & POPUPMENU_EVENTS) != 0)) { 5111 SwingEventMonitor.removePopupMenuListener(this); 5112 } 5113 5114 javaEventMask = newEventMask; 5115 } 5116 5117 /** 5118 * Turn on event monitoring for the event type passed in 5119 * If necessary, add the appropriate event listener (if 5120 * no other event of that type is being listened for) 5121 */ 5122 void addAccessibilityEventNotification(long type) { 5123 long newEventMask = accessibilityEventMask | type; 5124 if ( ((accessibilityEventMask & PROPERTY_EVENTS) == 0) && 5125 ((newEventMask & PROPERTY_EVENTS) != 0) ) { 5126 AccessibilityEventMonitor.addPropertyChangeListener(this); 5127 } 5128 accessibilityEventMask = newEventMask; 5129 } 5130 5131 /** 5132 * Turn off event monitoring for the event type passed in 5133 * If necessary, remove the appropriate event listener (if 5134 * no other event of that type is being listened for) 5135 */ 5136 void removeAccessibilityEventNotification(long type) { 5137 long newEventMask = accessibilityEventMask & (~type); 5138 if ( ((accessibilityEventMask & PROPERTY_EVENTS) != 0) && 5139 ((newEventMask & PROPERTY_EVENTS) == 0) ) { 5140 AccessibilityEventMonitor.removePropertyChangeListener(this); 5141 } 5142 accessibilityEventMask = newEventMask; 5143 } 5144 5145 /** 5146 * ------- property change event glue 5147 */ 5148 // This is invoked on the EDT , as 5149 public void propertyChange(PropertyChangeEvent e) { 5150 5151 accessBridge.debugString("propertyChange(" + e.toString() + ") called"); 5152 5153 if (e != null && (accessibilityEventMask & PROPERTY_EVENTS) != 0) { 5154 Object o = e.getSource(); 5155 AccessibleContext ac; 5156 5157 if (o instanceof AccessibleContext) { 5158 ac = (AccessibleContext) o; 5159 } else { 5160 Accessible a = Translator.getAccessible(e.getSource()); 5161 if (a == null) 5162 return; 5163 else 5164 ac = a.getAccessibleContext(); 5165 } 5166 if (ac != null) { 5167 InvocationUtils.registerAccessibleContext(ac, AppContext.getAppContext()); 5168 5169 accessBridge.debugString("AccessibleContext: " + ac); 5170 String propertyName = e.getPropertyName(); 5171 5172 if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_CARET_PROPERTY) == 0) { 5173 int oldValue = 0; 5174 int newValue = 0; 5175 5176 if (e.getOldValue() instanceof Integer) { 5177 oldValue = ((Integer) e.getOldValue()).intValue(); 5178 } 5179 if (e.getNewValue() instanceof Integer) { 5180 newValue = ((Integer) e.getNewValue()).intValue(); 5181 } 5182 accessBridge.debugString(" - about to call propertyCaretChange()"); 5183 accessBridge.debugString(" old value: " + oldValue + "new value: " + newValue); 5184 accessBridge.propertyCaretChange(e, ac, oldValue, newValue); 5185 5186 } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_DESCRIPTION_PROPERTY) == 0) { 5187 String oldValue = null; 5188 String newValue = null; 5189 5190 if (e.getOldValue() != null) { 5191 oldValue = e.getOldValue().toString(); 5192 } 5193 if (e.getNewValue() != null) { 5194 newValue = e.getNewValue().toString(); 5195 } 5196 accessBridge.debugString(" - about to call propertyDescriptionChange()"); 5197 accessBridge.debugString(" old value: " + oldValue + "new value: " + newValue); 5198 accessBridge.propertyDescriptionChange(e, ac, oldValue, newValue); 5199 5200 } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_NAME_PROPERTY) == 0) { 5201 String oldValue = null; 5202 String newValue = null; 5203 5204 if (e.getOldValue() != null) { 5205 oldValue = e.getOldValue().toString(); 5206 } 5207 if (e.getNewValue() != null) { 5208 newValue = e.getNewValue().toString(); 5209 } 5210 accessBridge.debugString(" - about to call propertyNameChange()"); 5211 accessBridge.debugString(" old value: " + oldValue + " new value: " + newValue); 5212 accessBridge.propertyNameChange(e, ac, oldValue, newValue); 5213 5214 } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY) == 0) { 5215 accessBridge.debugString(" - about to call propertySelectionChange() " + ac + " " + Thread.currentThread() + " " + e.getSource()); 5216 5217 accessBridge.propertySelectionChange(e, ac); 5218 5219 } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_STATE_PROPERTY) == 0) { 5220 String oldValue = null; 5221 String newValue = null; 5222 5223 // Localization fix requested by Oliver for EA-1 5224 if (e.getOldValue() != null) { 5225 AccessibleState oldState = (AccessibleState) e.getOldValue(); 5226 oldValue = oldState.toDisplayString(Locale.US); 5227 } 5228 if (e.getNewValue() != null) { 5229 AccessibleState newState = (AccessibleState) e.getNewValue(); 5230 newValue = newState.toDisplayString(Locale.US); 5231 } 5232 5233 accessBridge.debugString(" - about to call propertyStateChange()"); 5234 accessBridge.propertyStateChange(e, ac, oldValue, newValue); 5235 5236 } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_TEXT_PROPERTY) == 0) { 5237 accessBridge.debugString(" - about to call propertyTextChange()"); 5238 accessBridge.propertyTextChange(e, ac); 5239 5240 } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_VALUE_PROPERTY) == 0) { // strings 'cause of floating point, etc. 5241 String oldValue = null; 5242 String newValue = null; 5243 5244 if (e.getOldValue() != null) { 5245 oldValue = e.getOldValue().toString(); 5246 } 5247 if (e.getNewValue() != null) { 5248 newValue = e.getNewValue().toString(); 5249 } 5250 accessBridge.debugString(" - about to call propertyDescriptionChange()"); 5251 accessBridge.propertyValueChange(e, ac, oldValue, newValue); 5252 5253 } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY) == 0) { 5254 accessBridge.propertyVisibleDataChange(e, ac); 5255 5256 } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_CHILD_PROPERTY) == 0) { 5257 AccessibleContext oldAC = null; 5258 AccessibleContext newAC = null; 5259 Accessible a; 5260 5261 if (e.getOldValue() instanceof AccessibleContext) { 5262 oldAC = (AccessibleContext) e.getOldValue(); 5263 InvocationUtils.registerAccessibleContext(oldAC, AppContext.getAppContext()); 5264 } 5265 if (e.getNewValue() instanceof AccessibleContext) { 5266 newAC = (AccessibleContext) e.getNewValue(); 5267 InvocationUtils.registerAccessibleContext(newAC, AppContext.getAppContext()); 5268 } 5269 accessBridge.debugString(" - about to call propertyChildChange()"); 5270 accessBridge.debugString(" old AC: " + oldAC + "new AC: " + newAC); 5271 accessBridge.propertyChildChange(e, ac, oldAC, newAC); 5272 5273 } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY) == 0) { 5274 handleActiveDescendentEvent(e, ac); 5275 } 5276 } 5277 } 5278 } 5279 5280 /* 5281 * Handle an ActiveDescendent PropertyChangeEvent. This 5282 * method works around a JTree bug where ActiveDescendent 5283 * PropertyChangeEvents have the wrong parent. 5284 */ 5285 private AccessibleContext prevAC = null; // previous AccessibleContext 5286 5287 private void handleActiveDescendentEvent(PropertyChangeEvent e, 5288 AccessibleContext ac) { 5289 if (e == null || ac == null) 5290 return; 5291 AccessibleContext oldAC = null; 5292 AccessibleContext newAC = null; 5293 Accessible a; 5294 5295 // get the old active descendent 5296 if (e.getOldValue() instanceof Accessible) { 5297 oldAC = ((Accessible) e.getOldValue()).getAccessibleContext(); 5298 } else if (e.getOldValue() instanceof Component) { 5299 a = Translator.getAccessible(e.getOldValue()); 5300 if (a != null) { 5301 oldAC = a.getAccessibleContext(); 5302 } 5303 } 5304 if (oldAC != null) { 5305 Accessible parent = oldAC.getAccessibleParent(); 5306 if (parent instanceof JTree) { 5307 // use the previous AccessibleJTreeNode 5308 oldAC = prevAC; 5309 } 5310 } 5311 5312 // get the new active descendent 5313 if (e.getNewValue() instanceof Accessible) { 5314 newAC = ((Accessible) e.getNewValue()).getAccessibleContext(); 5315 } else if (e.getNewValue() instanceof Component) { 5316 a = Translator.getAccessible(e.getNewValue()); 5317 if (a != null) { 5318 newAC = a.getAccessibleContext(); 5319 } 5320 } 5321 if (newAC != null) { 5322 Accessible parent = newAC.getAccessibleParent(); 5323 if (parent instanceof JTree) { 5324 // use a new AccessibleJTreeNode with the right parent 5325 JTree tree = (JTree)parent; 5326 newAC = new AccessibleJTreeNode(tree, 5327 tree.getSelectionPath(), 5328 null); 5329 } 5330 } 5331 prevAC = newAC; 5332 5333 accessBridge.debugString(" - about to call propertyActiveDescendentChange()"); 5334 accessBridge.debugString(" AC: " + ac); 5335 accessBridge.debugString(" old AC: " + oldAC + "new AC: " + newAC); 5336 5337 InvocationUtils.registerAccessibleContext(oldAC, AppContext.getAppContext()); 5338 InvocationUtils.registerAccessibleContext(newAC, AppContext.getAppContext()); 5339 accessBridge.propertyActiveDescendentChange(e, ac, oldAC, newAC); 5340 } 5341 5342 /** 5343 * ------- focus event glue 5344 */ 5345 private boolean stateChangeListenerAdded = false; 5346 5347 public void focusGained(FocusEvent e) { 5348 if (runningOnJDK1_4) { 5349 processFocusGained(); 5350 } else { 5351 if ((javaEventMask & FOCUS_GAINED_EVENTS) != 0) { 5352 Accessible a = Translator.getAccessible(e.getSource()); 5353 if (a != null) { 5354 AccessibleContext context = a.getAccessibleContext(); 5355 InvocationUtils.registerAccessibleContext(context, SunToolkit.targetToAppContext(e.getSource())); 5356 accessBridge.focusGained(e, context); 5357 } 5358 } 5359 } 5360 } 5361 5362 public void stateChanged(ChangeEvent e) { 5363 processFocusGained(); 5364 } 5365 5366 private void processFocusGained() { 5367 Component focusOwner = KeyboardFocusManager. 5368 getCurrentKeyboardFocusManager().getFocusOwner(); 5369 if (focusOwner == null) { 5370 return; 5371 } 5372 5373 // Only menus and popup selections are handled by the JRootPane. 5374 if (focusOwner instanceof JRootPane) { 5375 MenuElement [] path = 5376 MenuSelectionManager.defaultManager().getSelectedPath(); 5377 if (path.length > 1) { 5378 Component penult = path[path.length-2].getComponent(); 5379 Component last = path[path.length-1].getComponent(); 5380 5381 if (last instanceof JPopupMenu) { 5382 // This is a popup with nothing in the popup 5383 // selected. The menu itself is selected. 5384 FocusEvent e = new FocusEvent(penult, FocusEvent.FOCUS_GAINED); 5385 AccessibleContext context = penult.getAccessibleContext(); 5386 InvocationUtils.registerAccessibleContext(context, SunToolkit.targetToAppContext(penult)); 5387 accessBridge.focusGained(e, context); 5388 } else if (penult instanceof JPopupMenu) { 5389 // This is a popup with an item selected 5390 FocusEvent e = 5391 new FocusEvent(last, FocusEvent.FOCUS_GAINED); 5392 accessBridge.debugString(" - about to call focusGained()"); 5393 AccessibleContext focusedAC = last.getAccessibleContext(); 5394 InvocationUtils.registerAccessibleContext(focusedAC, SunToolkit.targetToAppContext(last)); 5395 accessBridge.debugString(" AC: " + focusedAC); 5396 accessBridge.focusGained(e, focusedAC); 5397 } 5398 } 5399 } else { 5400 // The focus owner has the selection. 5401 if (focusOwner instanceof Accessible) { 5402 FocusEvent e = new FocusEvent(focusOwner, 5403 FocusEvent.FOCUS_GAINED); 5404 accessBridge.debugString(" - about to call focusGained()"); 5405 AccessibleContext focusedAC = focusOwner.getAccessibleContext(); 5406 InvocationUtils.registerAccessibleContext(focusedAC, SunToolkit.targetToAppContext(focusOwner)); 5407 accessBridge.debugString(" AC: " + focusedAC); 5408 accessBridge.focusGained(e, focusedAC); 5409 } 5410 } 5411 } 5412 5413 public void focusLost(FocusEvent e) { 5414 if (e != null && (javaEventMask & FOCUS_LOST_EVENTS) != 0) { 5415 Accessible a = Translator.getAccessible(e.getSource()); 5416 if (a != null) { 5417 accessBridge.debugString(" - about to call focusLost()"); 5418 accessBridge.debugString(" AC: " + a.getAccessibleContext()); 5419 AccessibleContext context = a.getAccessibleContext(); 5420 InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); 5421 accessBridge.focusLost(e, context); 5422 } 5423 } 5424 } 5425 5426 /** 5427 * ------- caret event glue 5428 */ 5429 public void caretUpdate(CaretEvent e) { 5430 if (e != null && (javaEventMask & CARET_UPATE_EVENTS) != 0) { 5431 Accessible a = Translator.getAccessible(e.getSource()); 5432 if (a != null) { 5433 AccessibleContext context = a.getAccessibleContext(); 5434 InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); 5435 accessBridge.caretUpdate(e, context); 5436 } 5437 } 5438 } 5439 5440 /** 5441 * ------- mouse event glue 5442 */ 5443 5444 public void mouseClicked(MouseEvent e) { 5445 if (e != null && (javaEventMask & MOUSE_CLICKED_EVENTS) != 0) { 5446 Accessible a = Translator.getAccessible(e.getSource()); 5447 if (a != null) { 5448 AccessibleContext context = a.getAccessibleContext(); 5449 InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); 5450 accessBridge.mouseClicked(e, context); 5451 } 5452 } 5453 } 5454 5455 public void mouseEntered(MouseEvent e) { 5456 if (e != null && (javaEventMask & MOUSE_ENTERED_EVENTS) != 0) { 5457 Accessible a = Translator.getAccessible(e.getSource()); 5458 if (a != null) { 5459 AccessibleContext context = a.getAccessibleContext(); 5460 InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); 5461 accessBridge.mouseEntered(e, context); 5462 } 5463 } 5464 } 5465 5466 public void mouseExited(MouseEvent e) { 5467 if (e != null && (javaEventMask & MOUSE_EXITED_EVENTS) != 0) { 5468 Accessible a = Translator.getAccessible(e.getSource()); 5469 if (a != null) { 5470 AccessibleContext context = a.getAccessibleContext(); 5471 InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); 5472 accessBridge.mouseExited(e, context); 5473 } 5474 } 5475 } 5476 5477 public void mousePressed(MouseEvent e) { 5478 if (e != null && (javaEventMask & MOUSE_PRESSED_EVENTS) != 0) { 5479 Accessible a = Translator.getAccessible(e.getSource()); 5480 if (a != null) { 5481 AccessibleContext context = a.getAccessibleContext(); 5482 InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); 5483 accessBridge.mousePressed(e, context); 5484 } 5485 } 5486 } 5487 5488 public void mouseReleased(MouseEvent e) { 5489 if (e != null && (javaEventMask & MOUSE_RELEASED_EVENTS) != 0) { 5490 Accessible a = Translator.getAccessible(e.getSource()); 5491 if (a != null) { 5492 AccessibleContext context = a.getAccessibleContext(); 5493 InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); 5494 accessBridge.mouseReleased(e, context); 5495 } 5496 } 5497 } 5498 5499 /** 5500 * ------- menu event glue 5501 */ 5502 public void menuCanceled(MenuEvent e) { 5503 if (e != null && (javaEventMask & MENU_CANCELED_EVENTS) != 0) { 5504 Accessible a = Translator.getAccessible(e.getSource()); 5505 if (a != null) { 5506 AccessibleContext context = a.getAccessibleContext(); 5507 InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); 5508 accessBridge.menuCanceled(e, context); 5509 } 5510 } 5511 } 5512 5513 public void menuDeselected(MenuEvent e) { 5514 if (e != null && (javaEventMask & MENU_DESELECTED_EVENTS) != 0) { 5515 Accessible a = Translator.getAccessible(e.getSource()); 5516 if (a != null) { 5517 AccessibleContext context = a.getAccessibleContext(); 5518 InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); 5519 accessBridge.menuDeselected(e, context); 5520 } 5521 } 5522 } 5523 5524 public void menuSelected(MenuEvent e) { 5525 if (e != null && (javaEventMask & MENU_SELECTED_EVENTS) != 0) { 5526 Accessible a = Translator.getAccessible(e.getSource()); 5527 if (a != null) { 5528 AccessibleContext context = a.getAccessibleContext(); 5529 InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); 5530 accessBridge.menuSelected(e, context); 5531 } 5532 } 5533 } 5534 5535 public void popupMenuCanceled(PopupMenuEvent e) { 5536 if (e != null && (javaEventMask & POPUPMENU_CANCELED_EVENTS) != 0) { 5537 Accessible a = Translator.getAccessible(e.getSource()); 5538 if (a != null) { 5539 AccessibleContext context = a.getAccessibleContext(); 5540 InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); 5541 accessBridge.popupMenuCanceled(e, context); 5542 } 5543 } 5544 } 5545 5546 public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { 5547 if (e != null && (javaEventMask & POPUPMENU_WILL_BECOME_INVISIBLE_EVENTS) != 0) { 5548 Accessible a = Translator.getAccessible(e.getSource()); 5549 if (a != null) { 5550 AccessibleContext context = a.getAccessibleContext(); 5551 InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); 5552 accessBridge.popupMenuWillBecomeInvisible(e, context); 5553 } 5554 } 5555 } 5556 5557 public void popupMenuWillBecomeVisible(PopupMenuEvent e) { 5558 if (e != null && (javaEventMask & POPUPMENU_WILL_BECOME_VISIBLE_EVENTS) != 0) { 5559 Accessible a = Translator.getAccessible(e.getSource()); 5560 if (a != null) { 5561 AccessibleContext context = a.getAccessibleContext(); 5562 InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); 5563 accessBridge.popupMenuWillBecomeVisible(e, context); 5564 } 5565 } 5566 } 5567 5568 } // End of EventHandler Class 5569 5570 // --------- Event Notification Registration methods 5571 5572 /** 5573 * Wrapper method around eventHandler.addJavaEventNotification() 5574 */ 5575 private void addJavaEventNotification(final long type) { 5576 EventQueue.invokeLater(new Runnable() { 5577 public void run(){ 5578 eventHandler.addJavaEventNotification(type); 5579 } 5580 }); 5581 } 5582 5583 /** 5584 * Wrapper method around eventHandler.removeJavaEventNotification() 5585 */ 5586 private void removeJavaEventNotification(final long type) { 5587 EventQueue.invokeLater(new Runnable() { 5588 public void run(){ 5589 eventHandler.removeJavaEventNotification(type); 5590 } 5591 }); 5592 } 5593 5594 5595 /** 5596 * Wrapper method around eventHandler.addAccessibilityEventNotification() 5597 */ 5598 private void addAccessibilityEventNotification(final long type) { 5599 EventQueue.invokeLater(new Runnable() { 5600 public void run(){ 5601 eventHandler.addAccessibilityEventNotification(type); 5602 } 5603 }); 5604 } 5605 5606 /** 5607 * Wrapper method around eventHandler.removeAccessibilityEventNotification() 5608 */ 5609 private void removeAccessibilityEventNotification(final long type) { 5610 EventQueue.invokeLater(new Runnable() { 5611 public void run(){ 5612 eventHandler.removeAccessibilityEventNotification(type); 5613 } 5614 }); 5615 } 5616 5617 /** 5618 ****************************************************** 5619 * All AccessibleRoles 5620 * 5621 * We shouldn't have to do this since it requires us 5622 * to synchronize the allAccessibleRoles array when 5623 * the AccessibleRoles class interface changes. However, 5624 * there is no Accessibility API method to get all 5625 * AccessibleRoles 5626 ****************************************************** 5627 */ 5628 private AccessibleRole [] allAccessibleRoles = { 5629 /** 5630 * Object is used to alert the user about something. 5631 */ 5632 AccessibleRole.ALERT, 5633 5634 /** 5635 * The header for a column of data. 5636 */ 5637 AccessibleRole.COLUMN_HEADER, 5638 5639 /** 5640 * Object that can be drawn into and is used to trap 5641 * events. 5642 * @see #FRAME 5643 * @see #GLASS_PANE 5644 * @see #LAYERED_PANE 5645 */ 5646 AccessibleRole.CANVAS, 5647 5648 /** 5649 * A list of choices the user can select from. Also optionally 5650 * allows the user to enter a choice of their own. 5651 */ 5652 AccessibleRole.COMBO_BOX, 5653 5654 /** 5655 * An iconified internal frame in a DESKTOP_PANE. 5656 * @see #DESKTOP_PANE 5657 * @see #INTERNAL_FRAME 5658 */ 5659 AccessibleRole.DESKTOP_ICON, 5660 5661 /** 5662 * A frame-like object that is clipped by a desktop pane. The 5663 * desktop pane, internal frame, and desktop icon objects are 5664 * often used to create multiple document interfaces within an 5665 * application. 5666 * @see #DESKTOP_ICON 5667 * @see #DESKTOP_PANE 5668 * @see #FRAME 5669 */ 5670 AccessibleRole.INTERNAL_FRAME, 5671 5672 /** 5673 * A pane that supports internal frames and 5674 * iconified versions of those internal frames. 5675 * @see #DESKTOP_ICON 5676 * @see #INTERNAL_FRAME 5677 */ 5678 AccessibleRole.DESKTOP_PANE, 5679 5680 /** 5681 * A specialized pane whose primary use is inside a DIALOG 5682 * @see #DIALOG 5683 */ 5684 AccessibleRole.OPTION_PANE, 5685 5686 /** 5687 * A top level window with no title or border. 5688 * @see #FRAME 5689 * @see #DIALOG 5690 */ 5691 AccessibleRole.WINDOW, 5692 5693 /** 5694 * A top level window with a title bar, border, menu bar, etc. It is 5695 * often used as the primary window for an application. 5696 * @see #DIALOG 5697 * @see #CANVAS 5698 * @see #WINDOW 5699 */ 5700 AccessibleRole.FRAME, 5701 5702 /** 5703 * A top level window with title bar and a border. A dialog is similar 5704 * to a frame, but it has fewer properties and is often used as a 5705 * secondary window for an application. 5706 * @see #FRAME 5707 * @see #WINDOW 5708 */ 5709 AccessibleRole.DIALOG, 5710 5711 /** 5712 * A specialized dialog that lets the user choose a color. 5713 */ 5714 AccessibleRole.COLOR_CHOOSER, 5715 5716 5717 /** 5718 * A pane that allows the user to navigate through 5719 * and select the contents of a directory. May be used 5720 * by a file chooser. 5721 * @see #FILE_CHOOSER 5722 */ 5723 AccessibleRole.DIRECTORY_PANE, 5724 5725 /** 5726 * A specialized dialog that displays the files in the directory 5727 * and lets the user select a file, browse a different directory, 5728 * or specify a filename. May use the directory pane to show the 5729 * contents of a directory. 5730 * @see #DIRECTORY_PANE 5731 */ 5732 AccessibleRole.FILE_CHOOSER, 5733 5734 /** 5735 * An object that fills up space in a user interface. It is often 5736 * used in interfaces to tweak the spacing between components, 5737 * but serves no other purpose. 5738 */ 5739 AccessibleRole.FILLER, 5740 5741 /** 5742 * A hypertext anchor 5743 */ 5744 // AccessibleRole.HYPERLINK, 5745 5746 /** 5747 * A small fixed size picture, typically used to decorate components. 5748 */ 5749 AccessibleRole.ICON, 5750 5751 /** 5752 * An object used to present an icon or short string in an interface. 5753 */ 5754 AccessibleRole.LABEL, 5755 5756 /** 5757 * A specialized pane that has a glass pane and a layered pane as its 5758 * children. 5759 * @see #GLASS_PANE 5760 * @see #LAYERED_PANE 5761 */ 5762 AccessibleRole.ROOT_PANE, 5763 5764 /** 5765 * A pane that is guaranteed to be painted on top 5766 * of all panes beneath it. 5767 * @see #ROOT_PANE 5768 * @see #CANVAS 5769 */ 5770 AccessibleRole.GLASS_PANE, 5771 5772 /** 5773 * A specialized pane that allows its children to be drawn in layers, 5774 * providing a form of stacking order. This is usually the pane that 5775 * holds the menu bar as well as the pane that contains most of the 5776 * visual components in a window. 5777 * @see #GLASS_PANE 5778 * @see #ROOT_PANE 5779 */ 5780 AccessibleRole.LAYERED_PANE, 5781 5782 /** 5783 * An object that presents a list of objects to the user and allows the 5784 * user to select one or more of them. A list is usually contained 5785 * within a scroll pane. 5786 * @see #SCROLL_PANE 5787 * @see #LIST_ITEM 5788 */ 5789 AccessibleRole.LIST, 5790 5791 /** 5792 * An object that presents an element in a list. A list is usually 5793 * contained within a scroll pane. 5794 * @see #SCROLL_PANE 5795 * @see #LIST 5796 */ 5797 AccessibleRole.LIST_ITEM, 5798 5799 /** 5800 * An object usually drawn at the top of the primary dialog box of 5801 * an application that contains a list of menus the user can choose 5802 * from. For example, a menu bar might contain menus for "File," 5803 * "Edit," and "Help." 5804 * @see #MENU 5805 * @see #POPUP_MENU 5806 * @see #LAYERED_PANE 5807 */ 5808 AccessibleRole.MENU_BAR, 5809 5810 /** 5811 * A temporary window that is usually used to offer the user a 5812 * list of choices, and then hides when the user selects one of 5813 * those choices. 5814 * @see #MENU 5815 * @see #MENU_ITEM 5816 */ 5817 AccessibleRole.POPUP_MENU, 5818 5819 /** 5820 * An object usually found inside a menu bar that contains a list 5821 * of actions the user can choose from. A menu can have any object 5822 * as its children, but most often they are menu items, other menus, 5823 * or rudimentary objects such as radio buttons, check boxes, or 5824 * separators. For example, an application may have an "Edit" menu 5825 * that contains menu items for "Cut" and "Paste." 5826 * @see #MENU_BAR 5827 * @see #MENU_ITEM 5828 * @see #SEPARATOR 5829 * @see #RADIO_BUTTON 5830 * @see #CHECK_BOX 5831 * @see #POPUP_MENU 5832 */ 5833 AccessibleRole.MENU, 5834 5835 /** 5836 * An object usually contained in a menu that presents an action 5837 * the user can choose. For example, the "Cut" menu item in an 5838 * "Edit" menu would be an action the user can select to cut the 5839 * selected area of text in a document. 5840 * @see #MENU_BAR 5841 * @see #SEPARATOR 5842 * @see #POPUP_MENU 5843 */ 5844 AccessibleRole.MENU_ITEM, 5845 5846 /** 5847 * An object usually contained in a menu to provide a visual 5848 * and logical separation of the contents in a menu. For example, 5849 * the "File" menu of an application might contain menu items for 5850 * "Open," "Close," and "Exit," and will place a separator between 5851 * "Close" and "Exit" menu items. 5852 * @see #MENU 5853 * @see #MENU_ITEM 5854 */ 5855 AccessibleRole.SEPARATOR, 5856 5857 /** 5858 * An object that presents a series of panels (or page tabs), one at a 5859 * time, through some mechanism provided by the object. The most common 5860 * mechanism is a list of tabs at the top of the panel. The children of 5861 * a page tab list are all page tabs. 5862 * @see #PAGE_TAB 5863 */ 5864 AccessibleRole.PAGE_TAB_LIST, 5865 5866 /** 5867 * An object that is a child of a page tab list. Its sole child is 5868 * the panel that is to be presented to the user when the user 5869 * selects the page tab from the list of tabs in the page tab list. 5870 * @see #PAGE_TAB_LIST 5871 */ 5872 AccessibleRole.PAGE_TAB, 5873 5874 /** 5875 * A generic container that is often used to group objects. 5876 */ 5877 AccessibleRole.PANEL, 5878 5879 /** 5880 * An object used to indicate how much of a task has been completed. 5881 */ 5882 AccessibleRole.PROGRESS_BAR, 5883 5884 /** 5885 * A text object used for passwords, or other places where the 5886 * text contents is not shown visibly to the user 5887 */ 5888 AccessibleRole.PASSWORD_TEXT, 5889 5890 /** 5891 * An object the user can manipulate to tell the application to do 5892 * something. 5893 * @see #CHECK_BOX 5894 * @see #TOGGLE_BUTTON 5895 * @see #RADIO_BUTTON 5896 */ 5897 AccessibleRole.PUSH_BUTTON, 5898 5899 /** 5900 * A specialized push button that can be checked or unchecked, but 5901 * does not provide a separate indicator for the current state. 5902 * @see #PUSH_BUTTON 5903 * @see #CHECK_BOX 5904 * @see #RADIO_BUTTON 5905 */ 5906 AccessibleRole.TOGGLE_BUTTON, 5907 5908 /** 5909 * A choice that can be checked or unchecked and provides a 5910 * separate indicator for the current state. 5911 * @see #PUSH_BUTTON 5912 * @see #TOGGLE_BUTTON 5913 * @see #RADIO_BUTTON 5914 */ 5915 AccessibleRole.CHECK_BOX, 5916 5917 /** 5918 * A specialized check box that will cause other radio buttons in the 5919 * same group to become unchecked when this one is checked. 5920 * @see #PUSH_BUTTON 5921 * @see #TOGGLE_BUTTON 5922 * @see #CHECK_BOX 5923 */ 5924 AccessibleRole.RADIO_BUTTON, 5925 5926 /** 5927 * The header for a row of data. 5928 */ 5929 AccessibleRole.ROW_HEADER, 5930 5931 /** 5932 * An object that allows a user to incrementally view a large amount 5933 * of information. Its children can include scroll bars and a viewport. 5934 * @see #SCROLL_BAR 5935 * @see #VIEWPORT 5936 */ 5937 AccessibleRole.SCROLL_PANE, 5938 5939 /** 5940 * An object usually used to allow a user to incrementally view a 5941 * large amount of data. Usually used only by a scroll pane. 5942 * @see #SCROLL_PANE 5943 */ 5944 AccessibleRole.SCROLL_BAR, 5945 5946 /** 5947 * An object usually used in a scroll pane. It represents the portion 5948 * of the entire data that the user can see. As the user manipulates 5949 * the scroll bars, the contents of the viewport can change. 5950 * @see #SCROLL_PANE 5951 */ 5952 AccessibleRole.VIEWPORT, 5953 5954 /** 5955 * An object that allows the user to select from a bounded range. For 5956 * example, a slider might be used to select a number between 0 and 100. 5957 */ 5958 AccessibleRole.SLIDER, 5959 5960 /** 5961 * A specialized panel that presents two other panels at the same time. 5962 * Between the two panels is a divider the user can manipulate to make 5963 * one panel larger and the other panel smaller. 5964 */ 5965 AccessibleRole.SPLIT_PANE, 5966 5967 /** 5968 * An object used to present information in terms of rows and columns. 5969 * An example might include a spreadsheet application. 5970 */ 5971 AccessibleRole.TABLE, 5972 5973 /** 5974 * An object that presents text to the user. The text is usually 5975 * editable by the user as opposed to a label. 5976 * @see #LABEL 5977 */ 5978 AccessibleRole.TEXT, 5979 5980 /** 5981 * An object used to present hierarchical information to the user. 5982 * The individual nodes in the tree can be collapsed and expanded 5983 * to provide selective disclosure of the tree's contents. 5984 */ 5985 AccessibleRole.TREE, 5986 5987 /** 5988 * A bar or palette usually composed of push buttons or toggle buttons. 5989 * It is often used to provide the most frequently used functions for an 5990 * application. 5991 */ 5992 AccessibleRole.TOOL_BAR, 5993 5994 /** 5995 * An object that provides information about another object. The 5996 * accessibleDescription property of the tool tip is often displayed 5997 * to the user in a small "help bubble" when the user causes the 5998 * mouse to hover over the object associated with the tool tip. 5999 */ 6000 AccessibleRole.TOOL_TIP, 6001 6002 /** 6003 * An AWT component, but nothing else is known about it. 6004 * @see #SWING_COMPONENT 6005 * @see #UNKNOWN 6006 */ 6007 AccessibleRole.AWT_COMPONENT, 6008 6009 /** 6010 * A Swing component, but nothing else is known about it. 6011 * @see #AWT_COMPONENT 6012 * @see #UNKNOWN 6013 */ 6014 AccessibleRole.SWING_COMPONENT, 6015 6016 /** 6017 * The object contains some Accessible information, but its role is 6018 * not known. 6019 * @see #AWT_COMPONENT 6020 * @see #SWING_COMPONENT 6021 */ 6022 AccessibleRole.UNKNOWN, 6023 6024 // These roles are only available in JDK 1.4 6025 6026 /** 6027 * A STATUS_BAR is an simple component that can contain 6028 * multiple labels of status information to the user. 6029 AccessibleRole.STATUS_BAR, 6030 6031 /** 6032 * A DATE_EDITOR is a component that allows users to edit 6033 * java.util.Date and java.util.Time objects 6034 AccessibleRole.DATE_EDITOR, 6035 6036 /** 6037 * A SPIN_BOX is a simple spinner component and its main use 6038 * is for simple numbers. 6039 AccessibleRole.SPIN_BOX, 6040 6041 /** 6042 * A FONT_CHOOSER is a component that lets the user pick various 6043 * attributes for fonts. 6044 AccessibleRole.FONT_CHOOSER, 6045 6046 /** 6047 * A GROUP_BOX is a simple container that contains a border 6048 * around it and contains components inside it. 6049 AccessibleRole.GROUP_BOX 6050 6051 /** 6052 * Since JDK 1.5 6053 * 6054 * A text header 6055 6056 AccessibleRole.HEADER, 6057 6058 /** 6059 * A text footer 6060 6061 AccessibleRole.FOOTER, 6062 6063 /** 6064 * A text paragraph 6065 6066 AccessibleRole.PARAGRAPH, 6067 6068 /** 6069 * A ruler is an object used to measure distance 6070 6071 AccessibleRole.RULER, 6072 6073 /** 6074 * A role indicating the object acts as a formula for 6075 * calculating a value. An example is a formula in 6076 * a spreadsheet cell. 6077 AccessibleRole.EDITBAR 6078 */ 6079 }; 6080 6081 /** 6082 * This class implements accessibility support for the 6083 * <code>JTree</code> child. It provides an implementation of the 6084 * Java Accessibility API appropriate to tree nodes. 6085 * 6086 * Copied from JTree.java to work around a JTree bug where 6087 * ActiveDescendent PropertyChangeEvents contain the wrong 6088 * parent. 6089 */ 6090 /** 6091 * This class in invoked on the EDT as its part of ActiveDescendant, 6092 * hence the calls do not need to be specifically made on the EDT 6093 */ 6094 private class AccessibleJTreeNode extends AccessibleContext 6095 implements Accessible, AccessibleComponent, AccessibleSelection, 6096 AccessibleAction { 6097 6098 private JTree tree = null; 6099 private TreeModel treeModel = null; 6100 private Object obj = null; 6101 private TreePath path = null; 6102 private Accessible accessibleParent = null; 6103 private int index = 0; 6104 private boolean isLeaf = false; 6105 6106 /** 6107 * Constructs an AccessibleJTreeNode 6108 */ 6109 AccessibleJTreeNode(JTree t, TreePath p, Accessible ap) { 6110 tree = t; 6111 path = p; 6112 accessibleParent = ap; 6113 if (t != null) 6114 treeModel = t.getModel(); 6115 if (p != null) { 6116 obj = p.getLastPathComponent(); 6117 if (treeModel != null && obj != null) { 6118 isLeaf = treeModel.isLeaf(obj); 6119 } 6120 } 6121 debugString("AccessibleJTreeNode: name = "+getAccessibleName()+"; TreePath = "+p+"; parent = "+ap); 6122 } 6123 6124 private TreePath getChildTreePath(int i) { 6125 // Tree nodes can't be so complex that they have 6126 // two sets of children -> we're ignoring that case 6127 if (i < 0 || i >= getAccessibleChildrenCount() || path == null || treeModel == null) { 6128 return null; 6129 } else { 6130 Object childObj = treeModel.getChild(obj, i); 6131 Object[] objPath = path.getPath(); 6132 Object[] objChildPath = new Object[objPath.length+1]; 6133 java.lang.System.arraycopy(objPath, 0, objChildPath, 0, objPath.length); 6134 objChildPath[objChildPath.length-1] = childObj; 6135 return new TreePath(objChildPath); 6136 } 6137 } 6138 6139 /** 6140 * Get the AccessibleContext associated with this tree node. 6141 * In the implementation of the Java Accessibility API for 6142 * this class, return this object, which is its own 6143 * AccessibleContext. 6144 * 6145 * @return this object 6146 */ 6147 public AccessibleContext getAccessibleContext() { 6148 return this; 6149 } 6150 6151 private AccessibleContext getCurrentAccessibleContext() { 6152 Component c = getCurrentComponent(); 6153 if (c instanceof Accessible) { 6154 return (c.getAccessibleContext()); 6155 } else { 6156 return null; 6157 } 6158 } 6159 6160 private Component getCurrentComponent() { 6161 debugString("AccessibleJTreeNode: getCurrentComponent"); 6162 // is the object visible? 6163 // if so, get row, selected, focus & leaf state, 6164 // and then get the renderer component and return it 6165 if (tree != null && tree.isVisible(path)) { 6166 TreeCellRenderer r = tree.getCellRenderer(); 6167 if (r == null) { 6168 debugString(" returning null 1"); 6169 return null; 6170 } 6171 TreeUI ui = tree.getUI(); 6172 if (ui != null) { 6173 int row = ui.getRowForPath(tree, path); 6174 boolean selected = tree.isPathSelected(path); 6175 boolean expanded = tree.isExpanded(path); 6176 boolean hasFocus = false; // how to tell?? -PK 6177 Component retval = r.getTreeCellRendererComponent(tree, obj, 6178 selected, expanded, 6179 isLeaf, row, hasFocus); 6180 debugString(" returning = "+retval.getClass()); 6181 return retval; 6182 } 6183 } 6184 debugString(" returning null 2"); 6185 return null; 6186 } 6187 6188 // AccessibleContext methods 6189 6190 /** 6191 * Get the accessible name of this object. 6192 * 6193 * @return the localized name of the object; null if this 6194 * object does not have a name 6195 */ 6196 public String getAccessibleName() { 6197 debugString("AccessibleJTreeNode: getAccessibleName"); 6198 AccessibleContext ac = getCurrentAccessibleContext(); 6199 if (ac != null) { 6200 String name = ac.getAccessibleName(); 6201 if ((name != null) && (!name.isEmpty())) { 6202 String retval = ac.getAccessibleName(); 6203 debugString(" returning "+retval); 6204 return retval; 6205 } else { 6206 return null; 6207 } 6208 } 6209 if ((accessibleName != null) && (accessibleName.isEmpty())) { 6210 return accessibleName; 6211 } else { 6212 return null; 6213 } 6214 } 6215 6216 /** 6217 * Set the localized accessible name of this object. 6218 * 6219 * @param s the new localized name of the object. 6220 */ 6221 public void setAccessibleName(String s) { 6222 AccessibleContext ac = getCurrentAccessibleContext(); 6223 if (ac != null) { 6224 ac.setAccessibleName(s); 6225 } else { 6226 super.setAccessibleName(s); 6227 } 6228 } 6229 6230 // 6231 // *** should check tooltip text for desc. (needs MouseEvent) 6232 // 6233 /** 6234 * Get the accessible description of this object. 6235 * 6236 * @return the localized description of the object; null if 6237 * this object does not have a description 6238 */ 6239 public String getAccessibleDescription() { 6240 AccessibleContext ac = getCurrentAccessibleContext(); 6241 if (ac != null) { 6242 return ac.getAccessibleDescription(); 6243 } else { 6244 return super.getAccessibleDescription(); 6245 } 6246 } 6247 6248 /** 6249 * Set the accessible description of this object. 6250 * 6251 * @param s the new localized description of the object 6252 */ 6253 public void setAccessibleDescription(String s) { 6254 AccessibleContext ac = getCurrentAccessibleContext(); 6255 if (ac != null) { 6256 ac.setAccessibleDescription(s); 6257 } else { 6258 super.setAccessibleDescription(s); 6259 } 6260 } 6261 6262 /** 6263 * Get the role of this object. 6264 * 6265 * @return an instance of AccessibleRole describing the role of the object 6266 * @see AccessibleRole 6267 */ 6268 public AccessibleRole getAccessibleRole() { 6269 AccessibleContext ac = getCurrentAccessibleContext(); 6270 if (ac != null) { 6271 return ac.getAccessibleRole(); 6272 } else { 6273 return AccessibleRole.UNKNOWN; 6274 } 6275 } 6276 6277 /** 6278 * Get the state set of this object. 6279 * 6280 * @return an instance of AccessibleStateSet containing the 6281 * current state set of the object 6282 * @see AccessibleState 6283 */ 6284 public AccessibleStateSet getAccessibleStateSet() { 6285 if (tree == null) 6286 return null; 6287 AccessibleContext ac = getCurrentAccessibleContext(); 6288 AccessibleStateSet states; 6289 int row = tree.getUI().getRowForPath(tree,path); 6290 int lsr = tree.getLeadSelectionRow(); 6291 if (ac != null) { 6292 states = ac.getAccessibleStateSet(); 6293 } else { 6294 states = new AccessibleStateSet(); 6295 } 6296 // need to test here, 'cause the underlying component 6297 // is a cellRenderer, which is never showing... 6298 if (isShowing()) { 6299 states.add(AccessibleState.SHOWING); 6300 } else if (states.contains(AccessibleState.SHOWING)) { 6301 states.remove(AccessibleState.SHOWING); 6302 } 6303 if (isVisible()) { 6304 states.add(AccessibleState.VISIBLE); 6305 } else if (states.contains(AccessibleState.VISIBLE)) { 6306 states.remove(AccessibleState.VISIBLE); 6307 } 6308 if (tree.isPathSelected(path)){ 6309 states.add(AccessibleState.SELECTED); 6310 } 6311 if (lsr == row) { 6312 states.add(AccessibleState.ACTIVE); 6313 } 6314 if (!isLeaf) { 6315 states.add(AccessibleState.EXPANDABLE); 6316 } 6317 if (tree.isExpanded(path)) { 6318 states.add(AccessibleState.EXPANDED); 6319 } else { 6320 states.add(AccessibleState.COLLAPSED); 6321 } 6322 if (tree.isEditable()) { 6323 states.add(AccessibleState.EDITABLE); 6324 } 6325 return states; 6326 } 6327 6328 /** 6329 * Get the Accessible parent of this object. 6330 * 6331 * @return the Accessible parent of this object; null if this 6332 * object does not have an Accessible parent 6333 */ 6334 public Accessible getAccessibleParent() { 6335 // someone wants to know, so we need to create our parent 6336 // if we don't have one (hey, we're a talented kid!) 6337 if (accessibleParent == null && path != null) { 6338 Object[] objPath = path.getPath(); 6339 if (objPath.length > 1) { 6340 Object objParent = objPath[objPath.length-2]; 6341 if (treeModel != null) { 6342 index = treeModel.getIndexOfChild(objParent, obj); 6343 } 6344 Object[] objParentPath = new Object[objPath.length-1]; 6345 java.lang.System.arraycopy(objPath, 0, objParentPath, 6346 0, objPath.length-1); 6347 TreePath parentPath = new TreePath(objParentPath); 6348 accessibleParent = new AccessibleJTreeNode(tree, 6349 parentPath, 6350 null); 6351 this.setAccessibleParent(accessibleParent); 6352 } else if (treeModel != null) { 6353 accessibleParent = tree; // we're the top! 6354 index = 0; // we're an only child! 6355 this.setAccessibleParent(accessibleParent); 6356 } 6357 } 6358 return accessibleParent; 6359 } 6360 6361 /** 6362 * Get the index of this object in its accessible parent. 6363 * 6364 * @return the index of this object in its parent; -1 if this 6365 * object does not have an accessible parent. 6366 * @see #getAccessibleParent 6367 */ 6368 public int getAccessibleIndexInParent() { 6369 // index is invalid 'till we have an accessibleParent... 6370 if (accessibleParent == null) { 6371 getAccessibleParent(); 6372 } 6373 if (path != null) { 6374 Object[] objPath = path.getPath(); 6375 if (objPath.length > 1) { 6376 Object objParent = objPath[objPath.length-2]; 6377 if (treeModel != null) { 6378 index = treeModel.getIndexOfChild(objParent, obj); 6379 } 6380 } 6381 } 6382 return index; 6383 } 6384 6385 /** 6386 * Returns the number of accessible children in the object. 6387 * 6388 * @return the number of accessible children in the object. 6389 */ 6390 public int getAccessibleChildrenCount() { 6391 // Tree nodes can't be so complex that they have 6392 // two sets of children -> we're ignoring that case 6393 if (obj != null && treeModel != null) { 6394 return treeModel.getChildCount(obj); 6395 } 6396 return 0; 6397 } 6398 6399 /** 6400 * Return the specified Accessible child of the object. 6401 * 6402 * @param i zero-based index of child 6403 * @return the Accessible child of the object 6404 */ 6405 public Accessible getAccessibleChild(int i) { 6406 // Tree nodes can't be so complex that they have 6407 // two sets of children -> we're ignoring that case 6408 if (i < 0 || i >= getAccessibleChildrenCount() || path == null || treeModel == null) { 6409 return null; 6410 } else { 6411 Object childObj = treeModel.getChild(obj, i); 6412 Object[] objPath = path.getPath(); 6413 Object[] objChildPath = new Object[objPath.length+1]; 6414 java.lang.System.arraycopy(objPath, 0, objChildPath, 0, objPath.length); 6415 objChildPath[objChildPath.length-1] = childObj; 6416 TreePath childPath = new TreePath(objChildPath); 6417 return new AccessibleJTreeNode(tree, childPath, this); 6418 } 6419 } 6420 6421 /** 6422 * Gets the locale of the component. If the component does not have 6423 * a locale, then the locale of its parent is returned. 6424 * 6425 * @return This component's locale. If this component does not have 6426 * a locale, the locale of its parent is returned. 6427 * @exception IllegalComponentStateException 6428 * If the Component does not have its own locale and has not yet 6429 * been added to a containment hierarchy such that the locale can be 6430 * determined from the containing parent. 6431 * @see #setLocale 6432 */ 6433 public Locale getLocale() { 6434 if (tree == null) 6435 return null; 6436 AccessibleContext ac = getCurrentAccessibleContext(); 6437 if (ac != null) { 6438 return ac.getLocale(); 6439 } else { 6440 return tree.getLocale(); 6441 } 6442 } 6443 6444 /** 6445 * Add a PropertyChangeListener to the listener list. 6446 * The listener is registered for all properties. 6447 * 6448 * @param l The PropertyChangeListener to be added 6449 */ 6450 public void addPropertyChangeListener(PropertyChangeListener l) { 6451 AccessibleContext ac = getCurrentAccessibleContext(); 6452 if (ac != null) { 6453 ac.addPropertyChangeListener(l); 6454 } else { 6455 super.addPropertyChangeListener(l); 6456 } 6457 } 6458 6459 /** 6460 * Remove a PropertyChangeListener from the listener list. 6461 * This removes a PropertyChangeListener that was registered 6462 * for all properties. 6463 * 6464 * @param l The PropertyChangeListener to be removed 6465 */ 6466 public void removePropertyChangeListener(PropertyChangeListener l) { 6467 AccessibleContext ac = getCurrentAccessibleContext(); 6468 if (ac != null) { 6469 ac.removePropertyChangeListener(l); 6470 } else { 6471 super.removePropertyChangeListener(l); 6472 } 6473 } 6474 6475 /** 6476 * Get the AccessibleAction associated with this object. In the 6477 * implementation of the Java Accessibility API for this class, 6478 * return this object, which is responsible for implementing the 6479 * AccessibleAction interface on behalf of itself. 6480 * 6481 * @return this object 6482 */ 6483 public AccessibleAction getAccessibleAction() { 6484 return this; 6485 } 6486 6487 /** 6488 * Get the AccessibleComponent associated with this object. In the 6489 * implementation of the Java Accessibility API for this class, 6490 * return this object, which is responsible for implementing the 6491 * AccessibleComponent interface on behalf of itself. 6492 * 6493 * @return this object 6494 */ 6495 public AccessibleComponent getAccessibleComponent() { 6496 return this; // to override getBounds() 6497 } 6498 6499 /** 6500 * Get the AccessibleSelection associated with this object if one 6501 * exists. Otherwise return null. 6502 * 6503 * @return the AccessibleSelection, or null 6504 */ 6505 public AccessibleSelection getAccessibleSelection() { 6506 AccessibleContext ac = getCurrentAccessibleContext(); 6507 if (ac != null && isLeaf) { 6508 return getCurrentAccessibleContext().getAccessibleSelection(); 6509 } else { 6510 return this; 6511 } 6512 } 6513 6514 /** 6515 * Get the AccessibleText associated with this object if one 6516 * exists. Otherwise return null. 6517 * 6518 * @return the AccessibleText, or null 6519 */ 6520 public AccessibleText getAccessibleText() { 6521 AccessibleContext ac = getCurrentAccessibleContext(); 6522 if (ac != null) { 6523 return getCurrentAccessibleContext().getAccessibleText(); 6524 } else { 6525 return null; 6526 } 6527 } 6528 6529 /** 6530 * Get the AccessibleValue associated with this object if one 6531 * exists. Otherwise return null. 6532 * 6533 * @return the AccessibleValue, or null 6534 */ 6535 public AccessibleValue getAccessibleValue() { 6536 AccessibleContext ac = getCurrentAccessibleContext(); 6537 if (ac != null) { 6538 return getCurrentAccessibleContext().getAccessibleValue(); 6539 } else { 6540 return null; 6541 } 6542 } 6543 6544 6545 // AccessibleComponent methods 6546 6547 /** 6548 * Get the background color of this object. 6549 * 6550 * @return the background color, if supported, of the object; 6551 * otherwise, null 6552 */ 6553 public Color getBackground() { 6554 AccessibleContext ac = getCurrentAccessibleContext(); 6555 if (ac instanceof AccessibleComponent) { 6556 return ((AccessibleComponent) ac).getBackground(); 6557 } else { 6558 Component c = getCurrentComponent(); 6559 if (c != null) { 6560 return c.getBackground(); 6561 } else { 6562 return null; 6563 } 6564 } 6565 } 6566 6567 /** 6568 * Set the background color of this object. 6569 * 6570 * @param c the new Color for the background 6571 */ 6572 public void setBackground(Color c) { 6573 AccessibleContext ac = getCurrentAccessibleContext(); 6574 if (ac instanceof AccessibleComponent) { 6575 ((AccessibleComponent) ac).setBackground(c); 6576 } else { 6577 Component cp = getCurrentComponent(); 6578 if ( cp != null) { 6579 cp.setBackground(c); 6580 } 6581 } 6582 } 6583 6584 6585 /** 6586 * Get the foreground color of this object. 6587 * 6588 * @return the foreground color, if supported, of the object; 6589 * otherwise, null 6590 */ 6591 public Color getForeground() { 6592 AccessibleContext ac = getCurrentAccessibleContext(); 6593 if (ac instanceof AccessibleComponent) { 6594 return ((AccessibleComponent) ac).getForeground(); 6595 } else { 6596 Component c = getCurrentComponent(); 6597 if (c != null) { 6598 return c.getForeground(); 6599 } else { 6600 return null; 6601 } 6602 } 6603 } 6604 6605 public void setForeground(Color c) { 6606 AccessibleContext ac = getCurrentAccessibleContext(); 6607 if (ac instanceof AccessibleComponent) { 6608 ((AccessibleComponent) ac).setForeground(c); 6609 } else { 6610 Component cp = getCurrentComponent(); 6611 if (cp != null) { 6612 cp.setForeground(c); 6613 } 6614 } 6615 } 6616 6617 public Cursor getCursor() { 6618 AccessibleContext ac = getCurrentAccessibleContext(); 6619 if (ac instanceof AccessibleComponent) { 6620 return ((AccessibleComponent) ac).getCursor(); 6621 } else { 6622 Component c = getCurrentComponent(); 6623 if (c != null) { 6624 return c.getCursor(); 6625 } else { 6626 Accessible ap = getAccessibleParent(); 6627 if (ap instanceof AccessibleComponent) { 6628 return ((AccessibleComponent) ap).getCursor(); 6629 } else { 6630 return null; 6631 } 6632 } 6633 } 6634 } 6635 6636 public void setCursor(Cursor c) { 6637 AccessibleContext ac = getCurrentAccessibleContext(); 6638 if (ac instanceof AccessibleComponent) { 6639 ((AccessibleComponent) ac).setCursor(c); 6640 } else { 6641 Component cp = getCurrentComponent(); 6642 if (cp != null) { 6643 cp.setCursor(c); 6644 } 6645 } 6646 } 6647 6648 public Font getFont() { 6649 AccessibleContext ac = getCurrentAccessibleContext(); 6650 if (ac instanceof AccessibleComponent) { 6651 return ((AccessibleComponent) ac).getFont(); 6652 } else { 6653 Component c = getCurrentComponent(); 6654 if (c != null) { 6655 return c.getFont(); 6656 } else { 6657 return null; 6658 } 6659 } 6660 } 6661 6662 public void setFont(Font f) { 6663 AccessibleContext ac = getCurrentAccessibleContext(); 6664 if (ac instanceof AccessibleComponent) { 6665 ((AccessibleComponent) ac).setFont(f); 6666 } else { 6667 Component c = getCurrentComponent(); 6668 if (c != null) { 6669 c.setFont(f); 6670 } 6671 } 6672 } 6673 6674 public FontMetrics getFontMetrics(Font f) { 6675 AccessibleContext ac = getCurrentAccessibleContext(); 6676 if (ac instanceof AccessibleComponent) { 6677 return ((AccessibleComponent) ac).getFontMetrics(f); 6678 } else { 6679 Component c = getCurrentComponent(); 6680 if (c != null) { 6681 return c.getFontMetrics(f); 6682 } else { 6683 return null; 6684 } 6685 } 6686 } 6687 6688 public boolean isEnabled() { 6689 AccessibleContext ac = getCurrentAccessibleContext(); 6690 if (ac instanceof AccessibleComponent) { 6691 return ((AccessibleComponent) ac).isEnabled(); 6692 } else { 6693 Component c = getCurrentComponent(); 6694 if (c != null) { 6695 return c.isEnabled(); 6696 } else { 6697 return false; 6698 } 6699 } 6700 } 6701 6702 public void setEnabled(boolean b) { 6703 AccessibleContext ac = getCurrentAccessibleContext(); 6704 if (ac instanceof AccessibleComponent) { 6705 ((AccessibleComponent) ac).setEnabled(b); 6706 } else { 6707 Component c = getCurrentComponent(); 6708 if (c != null) { 6709 c.setEnabled(b); 6710 } 6711 } 6712 } 6713 6714 public boolean isVisible() { 6715 if (tree == null) 6716 return false; 6717 Rectangle pathBounds = tree.getPathBounds(path); 6718 Rectangle parentBounds = tree.getVisibleRect(); 6719 if ( pathBounds != null && parentBounds != null && 6720 parentBounds.intersects(pathBounds) ) { 6721 return true; 6722 } else { 6723 return false; 6724 } 6725 } 6726 6727 public void setVisible(boolean b) { 6728 } 6729 6730 public boolean isShowing() { 6731 return (tree.isShowing() && isVisible()); 6732 } 6733 6734 public boolean contains(Point p) { 6735 AccessibleContext ac = getCurrentAccessibleContext(); 6736 if (ac instanceof AccessibleComponent) { 6737 Rectangle r = ((AccessibleComponent) ac).getBounds(); 6738 return r.contains(p); 6739 } else { 6740 Component c = getCurrentComponent(); 6741 if (c != null) { 6742 Rectangle r = c.getBounds(); 6743 return r.contains(p); 6744 } else { 6745 return getBounds().contains(p); 6746 } 6747 } 6748 } 6749 6750 public Point getLocationOnScreen() { 6751 if (tree != null) { 6752 Point treeLocation = tree.getLocationOnScreen(); 6753 Rectangle pathBounds = tree.getPathBounds(path); 6754 if (treeLocation != null && pathBounds != null) { 6755 Point nodeLocation = new Point(pathBounds.x, 6756 pathBounds.y); 6757 nodeLocation.translate(treeLocation.x, treeLocation.y); 6758 return nodeLocation; 6759 } else { 6760 return null; 6761 } 6762 } else { 6763 return null; 6764 } 6765 } 6766 6767 private Point getLocationInJTree() { 6768 Rectangle r = tree.getPathBounds(path); 6769 if (r != null) { 6770 return r.getLocation(); 6771 } else { 6772 return null; 6773 } 6774 } 6775 6776 public Point getLocation() { 6777 Rectangle r = getBounds(); 6778 if (r != null) { 6779 return r.getLocation(); 6780 } else { 6781 return null; 6782 } 6783 } 6784 6785 public void setLocation(Point p) { 6786 } 6787 6788 public Rectangle getBounds() { 6789 if (tree == null) 6790 return null; 6791 Rectangle r = tree.getPathBounds(path); 6792 Accessible parent = getAccessibleParent(); 6793 if (parent instanceof AccessibleJTreeNode) { 6794 Point parentLoc = ((AccessibleJTreeNode) parent).getLocationInJTree(); 6795 if (parentLoc != null && r != null) { 6796 r.translate(-parentLoc.x, -parentLoc.y); 6797 } else { 6798 return null; // not visible! 6799 } 6800 } 6801 return r; 6802 } 6803 6804 public void setBounds(Rectangle r) { 6805 AccessibleContext ac = getCurrentAccessibleContext(); 6806 if (ac instanceof AccessibleComponent) { 6807 ((AccessibleComponent) ac).setBounds(r); 6808 } else { 6809 Component c = getCurrentComponent(); 6810 if (c != null) { 6811 c.setBounds(r); 6812 } 6813 } 6814 } 6815 6816 public Dimension getSize() { 6817 return getBounds().getSize(); 6818 } 6819 6820 public void setSize (Dimension d) { 6821 AccessibleContext ac = getCurrentAccessibleContext(); 6822 if (ac instanceof AccessibleComponent) { 6823 ((AccessibleComponent) ac).setSize(d); 6824 } else { 6825 Component c = getCurrentComponent(); 6826 if (c != null) { 6827 c.setSize(d); 6828 } 6829 } 6830 } 6831 6832 /** 6833 * Returns the <code>Accessible</code> child, if one exists, 6834 * contained at the local coordinate <code>Point</code>. 6835 * Otherwise returns <code>null</code>. 6836 * 6837 * @param p point in local coordinates of this 6838 * <code>Accessible</code> 6839 * @return the <code>Accessible</code>, if it exists, 6840 * at the specified location; else <code>null</code> 6841 */ 6842 public Accessible getAccessibleAt(Point p) { 6843 AccessibleContext ac = getCurrentAccessibleContext(); 6844 if (ac instanceof AccessibleComponent) { 6845 return ((AccessibleComponent) ac).getAccessibleAt(p); 6846 } else { 6847 return null; 6848 } 6849 } 6850 6851 public boolean isFocusTraversable() { 6852 AccessibleContext ac = getCurrentAccessibleContext(); 6853 if (ac instanceof AccessibleComponent) { 6854 return ((AccessibleComponent) ac).isFocusTraversable(); 6855 } else { 6856 Component c = getCurrentComponent(); 6857 if (c != null) { 6858 return c.isFocusable(); 6859 } else { 6860 return false; 6861 } 6862 } 6863 } 6864 6865 public void requestFocus() { 6866 AccessibleContext ac = getCurrentAccessibleContext(); 6867 if (ac instanceof AccessibleComponent) { 6868 ((AccessibleComponent) ac).requestFocus(); 6869 } else { 6870 Component c = getCurrentComponent(); 6871 if (c != null) { 6872 c.requestFocus(); 6873 } 6874 } 6875 } 6876 6877 public void addFocusListener(FocusListener l) { 6878 AccessibleContext ac = getCurrentAccessibleContext(); 6879 if (ac instanceof AccessibleComponent) { 6880 ((AccessibleComponent) ac).addFocusListener(l); 6881 } else { 6882 Component c = getCurrentComponent(); 6883 if (c != null) { 6884 c.addFocusListener(l); 6885 } 6886 } 6887 } 6888 6889 public void removeFocusListener(FocusListener l) { 6890 AccessibleContext ac = getCurrentAccessibleContext(); 6891 if (ac instanceof AccessibleComponent) { 6892 ((AccessibleComponent) ac).removeFocusListener(l); 6893 } else { 6894 Component c = getCurrentComponent(); 6895 if (c != null) { 6896 c.removeFocusListener(l); 6897 } 6898 } 6899 } 6900 6901 // AccessibleSelection methods 6902 6903 /** 6904 * Returns the number of items currently selected. 6905 * If no items are selected, the return value will be 0. 6906 * 6907 * @return the number of items currently selected. 6908 */ 6909 public int getAccessibleSelectionCount() { 6910 int count = 0; 6911 int childCount = getAccessibleChildrenCount(); 6912 for (int i = 0; i < childCount; i++) { 6913 TreePath childPath = getChildTreePath(i); 6914 if (tree.isPathSelected(childPath)) { 6915 count++; 6916 } 6917 } 6918 return count; 6919 } 6920 6921 /** 6922 * Returns an Accessible representing the specified selected item 6923 * in the object. If there isn't a selection, or there are 6924 * fewer items selected than the integer passed in, the return 6925 * value will be null. 6926 * 6927 * @param i the zero-based index of selected items 6928 * @return an Accessible containing the selected item 6929 */ 6930 public Accessible getAccessibleSelection(int i) { 6931 int childCount = getAccessibleChildrenCount(); 6932 if (i < 0 || i >= childCount) { 6933 return null; // out of range 6934 } 6935 int count = 0; 6936 for (int j = 0; j < childCount && i >= count; j++) { 6937 TreePath childPath = getChildTreePath(j); 6938 if (tree.isPathSelected(childPath)) { 6939 if (count == i) { 6940 return new AccessibleJTreeNode(tree, childPath, this); 6941 } else { 6942 count++; 6943 } 6944 } 6945 } 6946 return null; 6947 } 6948 6949 /** 6950 * Returns true if the current child of this object is selected. 6951 * 6952 * @param i the zero-based index of the child in this Accessible 6953 * object. 6954 * @see AccessibleContext#getAccessibleChild 6955 */ 6956 public boolean isAccessibleChildSelected(int i) { 6957 int childCount = getAccessibleChildrenCount(); 6958 if (i < 0 || i >= childCount) { 6959 return false; // out of range 6960 } else { 6961 TreePath childPath = getChildTreePath(i); 6962 return tree.isPathSelected(childPath); 6963 } 6964 } 6965 6966 /** 6967 * Adds the specified selected item in the object to the object's 6968 * selection. If the object supports multiple selections, 6969 * the specified item is added to any existing selection, otherwise 6970 * it replaces any existing selection in the object. If the 6971 * specified item is already selected, this method has no effect. 6972 * 6973 * @param i the zero-based index of selectable items 6974 */ 6975 public void addAccessibleSelection(int i) { 6976 if (tree == null) 6977 return; 6978 TreeModel model = tree.getModel(); 6979 if (model != null) { 6980 if (i >= 0 && i < getAccessibleChildrenCount()) { 6981 TreePath path = getChildTreePath(i); 6982 tree.addSelectionPath(path); 6983 } 6984 } 6985 } 6986 6987 /** 6988 * Removes the specified selected item in the object from the 6989 * object's 6990 * selection. If the specified item isn't currently selected, this 6991 * method has no effect. 6992 * 6993 * @param i the zero-based index of selectable items 6994 */ 6995 public void removeAccessibleSelection(int i) { 6996 if (tree == null) 6997 return; 6998 TreeModel model = tree.getModel(); 6999 if (model != null) { 7000 if (i >= 0 && i < getAccessibleChildrenCount()) { 7001 TreePath path = getChildTreePath(i); 7002 tree.removeSelectionPath(path); 7003 } 7004 } 7005 } 7006 7007 /** 7008 * Clears the selection in the object, so that nothing in the 7009 * object is selected. 7010 */ 7011 public void clearAccessibleSelection() { 7012 int childCount = getAccessibleChildrenCount(); 7013 for (int i = 0; i < childCount; i++) { 7014 removeAccessibleSelection(i); 7015 } 7016 } 7017 7018 /** 7019 * Causes every selected item in the object to be selected 7020 * if the object supports multiple selections. 7021 */ 7022 public void selectAllAccessibleSelection() { 7023 if (tree == null) 7024 return; 7025 TreeModel model = tree.getModel(); 7026 if (model != null) { 7027 int childCount = getAccessibleChildrenCount(); 7028 TreePath path; 7029 for (int i = 0; i < childCount; i++) { 7030 path = getChildTreePath(i); 7031 tree.addSelectionPath(path); 7032 } 7033 } 7034 } 7035 7036 // AccessibleAction methods 7037 7038 /** 7039 * Returns the number of accessible actions available in this 7040 * tree node. If this node is not a leaf, there is at least 7041 * one action (toggle expand), in addition to any available 7042 * on the object behind the TreeCellRenderer. 7043 * 7044 * @return the number of Actions in this object 7045 */ 7046 public int getAccessibleActionCount() { 7047 AccessibleContext ac = getCurrentAccessibleContext(); 7048 if (ac != null) { 7049 AccessibleAction aa = ac.getAccessibleAction(); 7050 if (aa != null) { 7051 return (aa.getAccessibleActionCount() + (isLeaf ? 0 : 1)); 7052 } 7053 } 7054 return isLeaf ? 0 : 1; 7055 } 7056 7057 /** 7058 * Return a description of the specified action of the tree node. 7059 * If this node is not a leaf, there is at least one action 7060 * description (toggle expand), in addition to any available 7061 * on the object behind the TreeCellRenderer. 7062 * 7063 * @param i zero-based index of the actions 7064 * @return a description of the action 7065 */ 7066 public String getAccessibleActionDescription(int i) { 7067 if (i < 0 || i >= getAccessibleActionCount()) { 7068 return null; 7069 } 7070 AccessibleContext ac = getCurrentAccessibleContext(); 7071 if (i == 0) { 7072 // TIGER - 4766636 7073 // return AccessibleAction.TOGGLE_EXPAND; 7074 return "toggle expand"; 7075 } else if (ac != null) { 7076 AccessibleAction aa = ac.getAccessibleAction(); 7077 if (aa != null) { 7078 return aa.getAccessibleActionDescription(i - 1); 7079 } 7080 } 7081 return null; 7082 } 7083 7084 /** 7085 * Perform the specified Action on the tree node. If this node 7086 * is not a leaf, there is at least one action which can be 7087 * done (toggle expand), in addition to any available on the 7088 * object behind the TreeCellRenderer. 7089 * 7090 * @param i zero-based index of actions 7091 * @return true if the the action was performed; else false. 7092 */ 7093 public boolean doAccessibleAction(int i) { 7094 if (i < 0 || i >= getAccessibleActionCount()) { 7095 return false; 7096 } 7097 AccessibleContext ac = getCurrentAccessibleContext(); 7098 if (i == 0) { 7099 if (tree.isExpanded(path)) { 7100 tree.collapsePath(path); 7101 } else { 7102 tree.expandPath(path); 7103 } 7104 return true; 7105 } else if (ac != null) { 7106 AccessibleAction aa = ac.getAccessibleAction(); 7107 if (aa != null) { 7108 return aa.doAccessibleAction(i - 1); 7109 } 7110 } 7111 return false; 7112 } 7113 7114 } // inner class AccessibleJTreeNode 7115 7116 /** 7117 * A helper class to perform {@code Callable} objects on the event dispatch thread appropriate 7118 * for the provided {@code AccessibleContext}. 7119 */ 7120 private static class InvocationUtils { 7121 7122 /** 7123 * Invokes a {@code Callable} in the {@code AppContext} of the given {@code Accessible} 7124 * and waits for it to finish blocking the caller thread. 7125 * 7126 * @param callable the {@code Callable} to invoke 7127 * @param accessible the {@code Accessible} which would be used to find the right context 7128 * for the task execution 7129 * @param <T> type parameter for the result value 7130 * 7131 * @return the result of the {@code Callable} execution 7132 */ 7133 public static <T> T invokeAndWait(final Callable<T> callable, 7134 final Accessible accessible) { 7135 if (accessible instanceof Component) { 7136 return invokeAndWait(callable, (Component)accessible); 7137 } 7138 if (accessible instanceof AccessibleContext) { 7139 // This case also covers the Translator 7140 return invokeAndWait(callable, (AccessibleContext)accessible); 7141 } 7142 throw new RuntimeException("Unmapped Accessible used to dispatch event: " + accessible); 7143 } 7144 7145 /** 7146 * Invokes a {@code Callable} in the {@code AppContext} of the given {@code Component} 7147 * and waits for it to finish blocking the caller thread. 7148 * 7149 * @param callable the {@code Callable} to invoke 7150 * @param component the {@code Component} which would be used to find the right context 7151 * for the task execution 7152 * @param <T> type parameter for the result value 7153 * 7154 * @return the result of the {@code Callable} execution 7155 */ 7156 public static <T> T invokeAndWait(final Callable<T> callable, 7157 final Component component) { 7158 return invokeAndWait(callable, SunToolkit.targetToAppContext(component)); 7159 } 7160 7161 /** 7162 * Invokes a {@code Callable} in the {@code AppContext} mapped to the given {@code AccessibleContext} 7163 * and waits for it to finish blocking the caller thread. 7164 * 7165 * @param callable the {@code Callable} to invoke 7166 * @param accessibleContext the {@code AccessibleContext} which would be used to determine the right 7167 * context for the task execution. 7168 * @param <T> type parameter for the result value 7169 * 7170 * @return the result of the {@code Callable} execution 7171 */ 7172 public static <T> T invokeAndWait(final Callable<T> callable, 7173 final AccessibleContext accessibleContext) { 7174 AppContext targetContext = AWTAccessor.getAccessibleContextAccessor() 7175 .getAppContext(accessibleContext); 7176 if (targetContext != null) { 7177 return invokeAndWait(callable, targetContext); 7178 } else { 7179 // Normally this should not happen, unmapped context provided and 7180 // the target AppContext is unknown. 7181 7182 // Try to recover in case the context is a translator. 7183 if (accessibleContext instanceof Translator) { 7184 Object source = ((Translator)accessibleContext).getSource(); 7185 if (source instanceof Component) { 7186 return invokeAndWait(callable, (Component)source); 7187 } 7188 } 7189 } 7190 throw new RuntimeException("Unmapped AccessibleContext used to dispatch event: " + accessibleContext); 7191 } 7192 7193 private static <T> T invokeAndWait(final Callable<T> callable, 7194 final AppContext targetAppContext) { 7195 final CallableWrapper<T> wrapper = new CallableWrapper<T>(callable); 7196 try { 7197 invokeAndWait(wrapper, targetAppContext); 7198 T result = wrapper.getResult(); 7199 updateAppContextMap(result, targetAppContext); 7200 return result; 7201 } catch (final Exception e) { 7202 throw new RuntimeException(e); 7203 } 7204 } 7205 7206 private static void invokeAndWait(final Runnable runnable, 7207 final AppContext appContext) 7208 throws InterruptedException, InvocationTargetException { 7209 7210 EventQueue eq = SunToolkit.getSystemEventQueueImplPP(appContext); 7211 Object lock = new Object(); 7212 Toolkit source = Toolkit.getDefaultToolkit(); 7213 InvocationEvent event = 7214 new InvocationEvent(source, runnable, lock, true); 7215 synchronized (lock) { 7216 eq.postEvent(event); 7217 lock.wait(); 7218 } 7219 7220 Throwable eventThrowable = event.getThrowable(); 7221 if (eventThrowable != null) { 7222 throw new InvocationTargetException(eventThrowable); 7223 } 7224 } 7225 7226 /** 7227 * Maps the {@code AccessibleContext} to the {@code AppContext} which should be used 7228 * to dispatch events related to the {@code AccessibleContext} 7229 * @param accessibleContext the {@code AccessibleContext} for the mapping 7230 * @param targetContext the {@code AppContext} for the mapping 7231 */ 7232 public static void registerAccessibleContext(final AccessibleContext accessibleContext, 7233 final AppContext targetContext) { 7234 if (accessibleContext != null) { 7235 AWTAccessor.getAccessibleContextAccessor().setAppContext(accessibleContext, targetContext); 7236 } 7237 } 7238 7239 private static <T> void updateAppContextMap(final T accessibleContext, 7240 final AppContext targetContext) { 7241 if (accessibleContext instanceof AccessibleContext) { 7242 registerAccessibleContext((AccessibleContext)accessibleContext, targetContext); 7243 } 7244 } 7245 7246 private static class CallableWrapper<T> implements Runnable { 7247 private final Callable<T> callable; 7248 private volatile T object; 7249 private Exception e; 7250 7251 CallableWrapper(final Callable<T> callable) { 7252 this.callable = callable; 7253 } 7254 7255 public void run() { 7256 try { 7257 if (callable != null) { 7258 object = callable.call(); 7259 } 7260 } catch (final Exception e) { 7261 this.e = e; 7262 } 7263 } 7264 7265 T getResult() throws Exception { 7266 if (e != null) 7267 throw e; 7268 return object; 7269 } 7270 } 7271 } 7272 }