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