PageRenderTime 44ms CodeModel.GetById 35ms RepoModel.GetById 1ms app.codeStats 1ms

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

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