1 /* 2 * Copyright (c) 2011, 2016, 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 sun.lwawt.macosx; 27 28 import sun.lwawt.LWWindowPeer; 29 30 import java.awt.*; 31 import java.beans.*; 32 import java.lang.reflect.Field; 33 import java.lang.reflect.InvocationTargetException; 34 import java.util.*; 35 import java.util.concurrent.Callable; 36 37 import javax.accessibility.*; 38 import javax.swing.*; 39 40 class CAccessibility implements PropertyChangeListener { 41 private static Set<String> ignoredRoles; 42 43 static { 44 // Need to load the native library for this code. 45 java.security.AccessController.doPrivileged( 46 new java.security.PrivilegedAction<Void>() { 47 public Void run() { 48 System.loadLibrary("awt"); 49 return null; 50 } 51 }); 52 } 53 54 static CAccessibility sAccessibility; 55 static synchronized CAccessibility getAccessibility(final String[] roles) { 56 if (sAccessibility != null) return sAccessibility; 57 sAccessibility = new CAccessibility(); 58 59 if (roles != null) { 60 ignoredRoles = new HashSet<String>(roles.length); 61 for (final String role : roles) ignoredRoles.add(role); 62 } else { 63 ignoredRoles = new HashSet<String>(); 64 } 65 66 return sAccessibility; 67 } 68 69 private CAccessibility() { 70 KeyboardFocusManager.getCurrentKeyboardFocusManager().addPropertyChangeListener("focusOwner", this); 71 } 72 73 public void propertyChange(final PropertyChangeEvent evt) { 74 if (evt.getNewValue() == null) return; 75 focusChanged(); 76 } 77 78 private native void focusChanged(); 79 80 static <T> T invokeAndWait(final Callable<T> callable, final Component c) { 81 try { 82 return LWCToolkit.invokeAndWait(callable, c); 83 } catch (final Exception e) { e.printStackTrace(); } 84 return null; 85 } 86 87 static <T> T invokeAndWait(final Callable<T> callable, final Component c, final T defValue) { 88 T value = null; 89 try { 90 value = LWCToolkit.invokeAndWait(callable, c); 91 } catch (final Exception e) { e.printStackTrace(); } 92 93 return value != null ? value : defValue; 94 } 95 96 static void invokeLater(final Runnable runnable, final Component c) { 97 try { 98 LWCToolkit.invokeLater(runnable, c); 99 } catch (InvocationTargetException e) { e.printStackTrace(); } 100 } 101 102 public static String getAccessibleActionDescription(final AccessibleAction aa, final int index, final Component c) { 103 if (aa == null) return null; 104 105 return invokeAndWait(new Callable<String>() { 106 public String call() throws Exception { 107 return aa.getAccessibleActionDescription(index); 108 } 109 }, c); 110 } 111 112 public static void doAccessibleAction(final AccessibleAction aa, final int index, final Component c) { 113 // We make this an invokeLater because we don't need a reply. 114 if (aa == null) return; 115 116 invokeLater(new Runnable() { 117 public void run() { 118 aa.doAccessibleAction(index); 119 } 120 }, c); 121 } 122 123 public static Dimension getSize(final AccessibleComponent ac, final Component c) { 124 if (ac == null) return null; 125 126 return invokeAndWait(new Callable<Dimension>() { 127 public Dimension call() throws Exception { 128 return ac.getSize(); 129 } 130 }, c); 131 } 132 133 public static AccessibleSelection getAccessibleSelection(final AccessibleContext ac, final Component c) { 134 if (ac == null) return null; 135 136 return invokeAndWait(new Callable<AccessibleSelection>() { 137 public AccessibleSelection call() throws Exception { 138 return ac.getAccessibleSelection(); 139 } 140 }, c); 141 } 142 143 public static Accessible ax_getAccessibleSelection(final AccessibleContext ac, final int index, final Component c) { 144 if (ac == null) return null; 145 146 return invokeAndWait(new Callable<Accessible>() { 147 public Accessible call() throws Exception { 148 final AccessibleSelection as = ac.getAccessibleSelection(); 149 if (as == null) return null; 150 return as.getAccessibleSelection(index); 151 } 152 }, c); 153 } 154 155 // KCH - can we make this a postEvent? 156 public static void addAccessibleSelection(final AccessibleContext ac, final int index, final Component c) { 157 if (ac == null) return; 158 159 invokeLater(new Runnable() { 160 public void run() { 161 final AccessibleSelection as = ac.getAccessibleSelection(); 162 if (as == null) return; 163 as.addAccessibleSelection(index); 164 } 165 }, c); 166 } 167 168 public static AccessibleContext getAccessibleContext(final Accessible a, final Component c) { 169 if (a == null) return null; 170 171 return invokeAndWait(new Callable<AccessibleContext>() { 172 public AccessibleContext call() throws Exception { 173 return a.getAccessibleContext(); 174 } 175 }, c); 176 } 177 178 public static boolean isAccessibleChildSelected(final Accessible a, final int index, final Component c) { 179 if (a == null) return false; 180 181 return invokeAndWait(new Callable<Boolean>() { 182 public Boolean call() throws Exception { 183 final AccessibleContext ac = a.getAccessibleContext(); 184 if (ac == null) return Boolean.FALSE; 185 186 final AccessibleSelection as = ac.getAccessibleSelection(); 187 if (as == null) return Boolean.FALSE; 188 189 return new Boolean(as.isAccessibleChildSelected(index)); 190 } 191 }, c, false); 192 } 193 194 public static AccessibleStateSet getAccessibleStateSet(final AccessibleContext ac, final Component c) { 195 if (ac == null) return null; 196 197 return invokeAndWait(new Callable<AccessibleStateSet>() { 198 public AccessibleStateSet call() throws Exception { 199 return ac.getAccessibleStateSet(); 200 } 201 }, c); 202 } 203 204 public static boolean contains(final AccessibleContext ac, final AccessibleState as, final Component c) { 205 if (ac == null || as == null) return false; 206 207 return invokeAndWait(new Callable<Boolean>() { 208 public Boolean call() throws Exception { 209 final AccessibleStateSet ass = ac.getAccessibleStateSet(); 210 if (ass == null) return null; 211 return ass.contains(as); 212 } 213 }, c, false); 214 } 215 216 static Field getAccessibleBundleKeyFieldWithReflection() { 217 try { 218 final Field fieldKey = AccessibleBundle.class.getDeclaredField("key"); 219 fieldKey.setAccessible(true); 220 return fieldKey; 221 } catch (final SecurityException e) { 222 e.printStackTrace(); 223 } catch (final NoSuchFieldException e) { 224 e.printStackTrace(); 225 } 226 return null; 227 } 228 private static final Field FIELD_KEY = getAccessibleBundleKeyFieldWithReflection(); 229 230 static String getAccessibleRoleFor(final Accessible a) { 231 final AccessibleContext ac = a.getAccessibleContext(); 232 if (ac == null) return null; 233 234 final AccessibleRole role = ac.getAccessibleRole(); 235 try { 236 return (String)FIELD_KEY.get(role); 237 } catch (final IllegalArgumentException e) { 238 e.printStackTrace(); 239 } catch (final IllegalAccessException e) { 240 e.printStackTrace(); 241 } 242 return null; 243 } 244 245 public static String getAccessibleRole(final Accessible a, final Component c) { 246 if (a == null) return null; 247 248 return invokeAndWait(new Callable<String>() { 249 public String call() throws Exception { 250 final Accessible sa = CAccessible.getSwingAccessible(a); 251 final String role = getAccessibleRoleFor(a); 252 253 if (!"text".equals(role)) return role; 254 if (sa instanceof JTextArea || sa instanceof JEditorPane) { 255 return "textarea"; 256 } 257 return role; 258 } 259 }, c); 260 } 261 262 public static Point getLocationOnScreen(final AccessibleComponent ac, final Component c) { 263 if (ac == null) return null; 264 265 return invokeAndWait(new Callable<Point>() { 266 public Point call() throws Exception { 267 return ac.getLocationOnScreen(); 268 } 269 }, c); 270 } 271 272 public static int getCharCount(final AccessibleText at, final Component c) { 273 if (at == null) return 0; 274 275 return invokeAndWait(new Callable<Integer>() { 276 public Integer call() throws Exception { 277 return at.getCharCount(); 278 } 279 }, c, 0); 280 } 281 282 // Accessibility Threadsafety for JavaComponentAccessibility.m 283 public static Accessible getAccessibleParent(final Accessible a, final Component c) { 284 if (a == null) return null; 285 286 return invokeAndWait(new Callable<Accessible>() { 287 public Accessible call() throws Exception { 288 final AccessibleContext ac = a.getAccessibleContext(); 289 if (ac == null) return null; 290 return ac.getAccessibleParent(); 291 } 292 }, c); 293 } 294 295 public static int getAccessibleIndexInParent(final Accessible a, final Component c) { 296 if (a == null) return -1; 297 298 return invokeAndWait(new Callable<Integer>() { 299 public Integer call() throws Exception { 300 final AccessibleContext ac = a.getAccessibleContext(); 301 if (ac == null) return null; 302 return ac.getAccessibleIndexInParent(); 303 } 304 }, c, -1); 305 } 306 307 public static AccessibleComponent getAccessibleComponent(final Accessible a, final Component c) { 308 if (a == null) return null; 309 310 return invokeAndWait(new Callable<AccessibleComponent>() { 311 public AccessibleComponent call() throws Exception { 312 final AccessibleContext ac = a.getAccessibleContext(); 313 if (ac == null) return null; 314 return ac.getAccessibleComponent(); 315 } 316 }, c); 317 } 318 319 public static AccessibleValue getAccessibleValue(final Accessible a, final Component c) { 320 if (a == null) return null; 321 322 return invokeAndWait(new Callable<AccessibleValue>() { 323 public AccessibleValue call() throws Exception { 324 final AccessibleContext ac = a.getAccessibleContext(); 325 if (ac == null) return null; 326 327 AccessibleValue accessibleValue = ac.getAccessibleValue(); 328 return accessibleValue; 329 } 330 }, c); 331 } 332 333 public static String getAccessibleName(final Accessible a, final Component c) { 334 if (a == null) return null; 335 336 return invokeAndWait(new Callable<String>() { 337 public String call() throws Exception { 338 final AccessibleContext ac = a.getAccessibleContext(); 339 if (ac == null) return null; 340 341 final String accessibleName = ac.getAccessibleName(); 342 if (accessibleName == null) { 343 return ac.getAccessibleDescription(); 344 } 345 return accessibleName; 346 } 347 }, c); 348 } 349 350 public static AccessibleText getAccessibleText(final Accessible a, final Component c) { 351 if (a == null) return null; 352 353 return invokeAndWait(new Callable<AccessibleText>() { 354 public AccessibleText call() throws Exception { 355 final AccessibleContext ac = a.getAccessibleContext(); 356 if (ac == null) return null; 357 358 AccessibleText accessibleText = ac.getAccessibleText(); 359 return accessibleText; 360 } 361 }, c); 362 } 363 364 public static String getAccessibleDescription(final Accessible a, final Component c) { 365 if (a == null) return null; 366 367 return invokeAndWait(new Callable<String>() { 368 public String call() throws Exception { 369 final AccessibleContext ac = a.getAccessibleContext(); 370 if (ac == null) return null; 371 372 final String accessibleDescription = ac.getAccessibleDescription(); 373 if (accessibleDescription == null) { 374 if (c instanceof JComponent) { 375 String toolTipText = ((JComponent)c).getToolTipText(); 376 if (toolTipText != null) { 377 return toolTipText; 378 } 379 } 380 } 381 382 return accessibleDescription; 383 } 384 }, c); 385 } 386 387 public static boolean isFocusTraversable(final Accessible a, final Component c) { 388 if (a == null) return false; 389 390 return invokeAndWait(new Callable<Boolean>() { 391 public Boolean call() throws Exception { 392 final AccessibleContext ac = a.getAccessibleContext(); 393 if (ac == null) return null; 394 395 final AccessibleComponent aComp = ac.getAccessibleComponent(); 396 if (aComp == null) return null; 397 398 return aComp.isFocusTraversable(); 399 } 400 }, c, false); 401 } 402 403 public static Accessible accessibilityHitTest(final Container parent, final float hitPointX, final float hitPointY) { 404 return invokeAndWait(new Callable<Accessible>() { 405 public Accessible call() throws Exception { 406 final Point p = parent.getLocationOnScreen(); 407 408 // Make it into local coords 409 final Point localPoint = new Point((int)(hitPointX - p.getX()), (int)(hitPointY - p.getY())); 410 411 final Component component = parent.findComponentAt(localPoint); 412 if (component == null) return null; 413 414 final AccessibleContext axContext = component.getAccessibleContext(); 415 if (axContext == null) return null; 416 417 final AccessibleComponent axComponent = axContext.getAccessibleComponent(); 418 if (axComponent == null) return null; 419 420 final int numChildren = axContext.getAccessibleChildrenCount(); 421 if (numChildren > 0) { 422 // It has children, check to see which one is hit. 423 final Point p2 = axComponent.getLocationOnScreen(); 424 final Point localP2 = new Point((int)(hitPointX - p2.getX()), (int)(hitPointY - p2.getY())); 425 return CAccessible.getCAccessible(axComponent.getAccessibleAt(localP2)); 426 } 427 428 if (!(component instanceof Accessible)) return null; 429 return CAccessible.getCAccessible((Accessible)component); 430 } 431 }, parent); 432 } 433 434 public static AccessibleAction getAccessibleAction(final Accessible a, final Component c) { 435 if (a == null) return null; 436 437 return invokeAndWait(new Callable<AccessibleAction>() { 438 public AccessibleAction call() throws Exception { 439 final AccessibleContext ac = a.getAccessibleContext(); 440 if (ac == null) return null; 441 return ac.getAccessibleAction(); 442 } 443 }, c); 444 } 445 446 public static boolean isEnabled(final Accessible a, final Component c) { 447 if (a == null) return false; 448 449 return invokeAndWait(new Callable<Boolean>() { 450 public Boolean call() throws Exception { 451 final AccessibleContext ac = a.getAccessibleContext(); 452 if (ac == null) return null; 453 454 final AccessibleComponent aComp = ac.getAccessibleComponent(); 455 if (aComp == null) return null; 456 457 return aComp.isEnabled(); 458 } 459 }, c, false); 460 } 461 462 // KCH - can we make this a postEvent instead? 463 public static void requestFocus(final Accessible a, final Component c) { 464 if (a == null) return; 465 466 invokeLater(new Runnable() { 467 public void run() { 468 final AccessibleContext ac = a.getAccessibleContext(); 469 if (ac == null) return; 470 471 final AccessibleComponent aComp = ac.getAccessibleComponent(); 472 if (aComp == null) return; 473 474 aComp.requestFocus(); 475 } 476 }, c); 477 } 478 479 public static void requestSelection(final Accessible a, final Component c) { 480 if (a == null) return; 481 invokeLater(new Runnable() { 482 public void run() { 483 AccessibleContext ac = a.getAccessibleContext(); 484 if (ac == null) return; 485 int i = ac.getAccessibleIndexInParent(); 486 if (i == -1) return; 487 Accessible parent = ac.getAccessibleParent(); 488 AccessibleContext pac = parent.getAccessibleContext(); 489 if (pac == null) return; 490 AccessibleSelection as = pac.getAccessibleSelection(); 491 if (as == null) return; 492 as.addAccessibleSelection(i); 493 } 494 }, c); 495 } 496 497 public static Number getMaximumAccessibleValue(final Accessible a, final Component c) { 498 if (a == null) return null; 499 500 return invokeAndWait(new Callable<Number>() { 501 public Number call() throws Exception { 502 final AccessibleContext ac = a.getAccessibleContext(); 503 if (ac == null) return null; 504 505 final AccessibleValue av = ac.getAccessibleValue(); 506 if (av == null) return null; 507 508 return av.getMaximumAccessibleValue(); 509 } 510 }, c); 511 } 512 513 public static Number getMinimumAccessibleValue(final Accessible a, final Component c) { 514 if (a == null) return null; 515 516 return invokeAndWait(new Callable<Number>() { 517 public Number call() throws Exception { 518 final AccessibleContext ac = a.getAccessibleContext(); 519 if (ac == null) return null; 520 521 final AccessibleValue av = ac.getAccessibleValue(); 522 if (av == null) return null; 523 524 return av.getMinimumAccessibleValue(); 525 } 526 }, c); 527 } 528 529 public static String getAccessibleRoleDisplayString(final Accessible a, final Component c) { 530 if (a == null) return null; 531 532 return invokeAndWait(new Callable<String>() { 533 public String call() throws Exception { 534 final AccessibleContext ac = a.getAccessibleContext(); 535 if (ac == null) return null; 536 537 final AccessibleRole ar = ac.getAccessibleRole(); 538 if (ar == null) return null; 539 540 return ar.toDisplayString(); 541 } 542 }, c); 543 } 544 545 public static Number getCurrentAccessibleValue(final AccessibleValue av, final Component c) { 546 if (av == null) return null; 547 548 return invokeAndWait(new Callable<Number>() { 549 public Number call() throws Exception { 550 Number currentAccessibleValue = av.getCurrentAccessibleValue(); 551 return currentAccessibleValue; 552 } 553 }, c); 554 } 555 556 public static Accessible getFocusOwner(final Component c) { 557 return invokeAndWait(new Callable<Accessible>() { 558 public Accessible call() throws Exception { 559 Component c = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner(); 560 if (c == null || !(c instanceof Accessible)) return null; 561 return CAccessible.getCAccessible((Accessible)c); 562 } 563 }, c); 564 } 565 566 public static boolean[] getInitialAttributeStates(final Accessible a, final Component c) { 567 final boolean[] ret = new boolean[7]; 568 if (a == null) return ret; 569 570 return invokeAndWait(new Callable<boolean[]>() { 571 public boolean[] call() throws Exception { 572 final AccessibleContext aContext = a.getAccessibleContext(); 573 if (aContext == null) return ret; 574 575 final AccessibleComponent aComponent = aContext.getAccessibleComponent(); 576 ret[0] = (aComponent != null); 577 ret[1] = ((aComponent != null) && (aComponent.isFocusTraversable())); 578 ret[2] = (aContext.getAccessibleValue() != null); 579 ret[3] = (aContext.getAccessibleText() != null); 580 581 final AccessibleStateSet aStateSet = aContext.getAccessibleStateSet(); 582 ret[4] = (aStateSet.contains(AccessibleState.HORIZONTAL) || aStateSet.contains(AccessibleState.VERTICAL)); 583 ret[5] = (aContext.getAccessibleName() != null); 584 ret[6] = (aContext.getAccessibleChildrenCount() > 0); 585 return ret; 586 } 587 }, c); 588 } 589 590 // Duplicated from JavaComponentAccessibility 591 // Note that values >=0 are indexes into the child array 592 final static int JAVA_AX_ALL_CHILDREN = -1; 593 final static int JAVA_AX_SELECTED_CHILDREN = -2; 594 final static int JAVA_AX_VISIBLE_CHILDREN = -3; 595 596 // Each child takes up two entries in the array: one for itself and one for its role 597 public static Object[] getChildrenAndRoles(final Accessible a, final Component c, final int whichChildren, final boolean allowIgnored) { 598 if (a == null) return null; 599 return invokeAndWait(new Callable<Object[]>() { 600 public Object[] call() throws Exception { 601 ArrayList<Object> childrenAndRoles = new ArrayList<Object>(); 602 _addChildren(a, whichChildren, allowIgnored, childrenAndRoles); 603 604 /* In the case of fetching a selection, need to check to see if 605 * the active descendant is at the beginning of the list. If it 606 * is not it needs to be moved to the beginning of the list so 607 * VoiceOver will annouce it correctly. The list returned 608 * from Java is always in order from top to bottom, but when shift 609 * selecting downward (extending the list) or multi-selecting using 610 * the VO keys control+option+command+return the active descendant 611 * is not at the top of the list in the shift select down case and 612 * may not be in the multi select case. 613 */ 614 if (whichChildren == JAVA_AX_SELECTED_CHILDREN) { 615 if (!childrenAndRoles.isEmpty()) { 616 AccessibleContext activeDescendantAC = 617 CAccessible.getActiveDescendant(a); 618 if (activeDescendantAC != null) { 619 String activeDescendantName = 620 activeDescendantAC.getAccessibleName(); 621 AccessibleRole activeDescendantRole = 622 activeDescendantAC.getAccessibleRole(); 623 // Move active descendant to front of list. 624 // List contains pairs of each selected item's 625 // Accessible and AccessibleRole. 626 ArrayList<Object> newArray = new ArrayList<Object>(); 627 int count = childrenAndRoles.size(); 628 Accessible currentAccessible = null; 629 AccessibleContext currentAC = null; 630 String currentName = null; 631 AccessibleRole currentRole = null; 632 for (int i = 0; i < count; i+=2) { 633 // Is this the active descendant? 634 currentAccessible = (Accessible)childrenAndRoles.get(i); 635 currentAC = currentAccessible.getAccessibleContext(); 636 currentName = currentAC.getAccessibleName(); 637 currentRole = (AccessibleRole)childrenAndRoles.get(i+1); 638 if ( currentName.equals(activeDescendantName) && 639 currentRole.equals(activeDescendantRole) ) { 640 newArray.add(0, currentAccessible); 641 newArray.add(1, currentRole); 642 } else { 643 newArray.add(currentAccessible); 644 newArray.add(currentRole); 645 } 646 } 647 childrenAndRoles = newArray; 648 } 649 } 650 } 651 652 if ((whichChildren < 0) || (whichChildren * 2 >= childrenAndRoles.size())) { 653 return childrenAndRoles.toArray(); 654 } 655 656 return new Object[] { childrenAndRoles.get(whichChildren * 2), childrenAndRoles.get((whichChildren * 2) + 1) }; 657 } 658 }, c); 659 } 660 661 private static AccessibleRole getAccessibleRoleForLabel(JLabel l, AccessibleRole fallback) { 662 String text = l.getText(); 663 if (text != null && text.length() > 0) { 664 return fallback; 665 } 666 Icon icon = l.getIcon(); 667 if (icon != null) { 668 return AccessibleRole.ICON; 669 } 670 return fallback; 671 } 672 673 private static AccessibleRole getAccessibleRole(Accessible a) { 674 AccessibleContext ac = a.getAccessibleContext(); 675 AccessibleRole role = ac.getAccessibleRole(); 676 Object component = CAccessible.getSwingAccessible(a); 677 if (role == null) return null; 678 String roleString = role.toString(); 679 if ("label".equals(roleString) && component instanceof JLabel) { 680 return getAccessibleRoleForLabel((JLabel) component, role); 681 } 682 return role; 683 } 684 685 686 // Either gets the immediate children of a, or recursively gets all unignored children of a 687 private static void _addChildren(final Accessible a, final int whichChildren, final boolean allowIgnored, final ArrayList<Object> childrenAndRoles) { 688 if (a == null) return; 689 690 final AccessibleContext ac = a.getAccessibleContext(); 691 if (ac == null) return; 692 693 final int numChildren = ac.getAccessibleChildrenCount(); 694 695 // each child takes up two entries in the array: itself, and its role 696 // so the array holds alternating Accessible and AccessibleRole objects 697 for (int i = 0; i < numChildren; i++) { 698 final Accessible child = ac.getAccessibleChild(i); 699 if (child == null) continue; 700 701 final AccessibleContext context = child.getAccessibleContext(); 702 if (context == null) continue; 703 704 if (whichChildren == JAVA_AX_VISIBLE_CHILDREN) { 705 if (!context.getAccessibleComponent().isVisible()) continue; 706 } else if (whichChildren == JAVA_AX_SELECTED_CHILDREN) { 707 if (!ac.getAccessibleSelection().isAccessibleChildSelected(i)) continue; 708 } 709 710 if (!allowIgnored) { 711 final AccessibleRole role = context.getAccessibleRole(); 712 if (role != null && ignoredRoles != null && ignoredRoles.contains(roleKey(role))) { 713 // Get the child's unignored children. 714 _addChildren(child, whichChildren, false, childrenAndRoles); 715 } else { 716 childrenAndRoles.add(child); 717 childrenAndRoles.add(getAccessibleRole(child)); 718 } 719 } else { 720 childrenAndRoles.add(child); 721 childrenAndRoles.add(getAccessibleRole(child)); 722 } 723 724 // If there is an index, and we are beyond it, time to finish up 725 if ((whichChildren >= 0) && (childrenAndRoles.size() / 2) >= (whichChildren + 1)) { 726 return; 727 } 728 } 729 } 730 731 private static native String roleKey(AccessibleRole aRole); 732 733 public static Object[] getChildren(final Accessible a, final Component c) { 734 if (a == null) return null; 735 return invokeAndWait(new Callable<Object[]>() { 736 public Object[] call() throws Exception { 737 final AccessibleContext ac = a.getAccessibleContext(); 738 if (ac == null) return null; 739 740 final int numChildren = ac.getAccessibleChildrenCount(); 741 final Object[] children = new Object[numChildren]; 742 for (int i = 0; i < numChildren; i++) { 743 children[i] = ac.getAccessibleChild(i); 744 } 745 return children; 746 } 747 }, c); 748 } 749 750 /** 751 * @return AWTView ptr, a peer of the CPlatformView associated with the toplevel container of the Accessible, if any 752 */ 753 private static long getAWTView(Accessible a) { 754 Accessible ax = CAccessible.getSwingAccessible(a); 755 if (!(ax instanceof Component)) return 0; 756 757 return invokeAndWait(new Callable<Long>() { 758 public Long call() throws Exception { 759 Component cont = (Component) ax; 760 while (cont != null && !(cont instanceof Window)) { 761 cont = cont.getParent(); 762 } 763 if (cont != null) { 764 LWWindowPeer peer = (LWWindowPeer) cont.getPeer(); 765 if (peer != null) { 766 return ((CPlatformWindow) peer.getPlatformWindow()).getContentView().getAWTView(); 767 } 768 } 769 return 0L; 770 } 771 }, (Component)ax); 772 } 773 }