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