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