8267385: Create NSAccessibilityElement implementation for JavaComponentAccessibility

8262031: Create implementation for NSAccessibilityNavigableStaticText protocol
8264287: Create implementation for NSAccessibilityComboBox protocol peer
8264303: Create implementation for NSAccessibilityTabGroup protocol peer
8264292: Create implementation for NSAccessibilityList protocol peer
8267387: Create implementation for NSAccessibilityOutline protocol
8267388: Create implementation for NSAccessibilityTable protocol
8264286: Create implementation for NSAccessibilityColumn protocol peer
8264298: Create implementation for NSAccessibilityRow protocol peer
8264291: Create implementation for NSAccessibilityCell protocol peer

Reviewed-by: kizune, pbansal, serb
This commit is contained in:
Artem Semenov 2021-08-09 16:21:35 +00:00 committed by Anton Tarasov
parent 0ac2be9b35
commit 9c6457f222
52 changed files with 4782 additions and 236 deletions

@ -34,11 +34,13 @@ import java.awt.Window;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.annotation.Native;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.Arrays;
import javax.accessibility.Accessible;
import javax.accessibility.AccessibleAction;
@ -57,6 +59,8 @@ import javax.swing.JEditorPane;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JTextArea;
import javax.swing.JList;
import javax.swing.JTree;
import javax.swing.KeyStroke;
import sun.awt.AWTAccessor;
@ -120,12 +124,7 @@ class CAccessibility implements PropertyChangeListener {
private native void focusChanged();
static <T> T invokeAndWait(final Callable<T> callable, final Component c) {
if (c != null) {
try {
return LWCToolkit.invokeAndWait(callable, c);
} catch (final Exception e) { e.printStackTrace(); }
}
return null;
return invokeAndWait(callable, c, null);
}
static <T> T invokeAndWait(final Callable<T> callable, final Component c, final T defValue) {
@ -555,6 +554,10 @@ class CAccessibility implements PropertyChangeListener {
if (pac == null) return;
AccessibleSelection as = pac.getAccessibleSelection();
if (as == null) return;
if (parent instanceof JList) {
((JList) parent).setSelectedIndex(i);
return;
}
as.addAccessibleSelection(i);
}
}, c);
@ -655,77 +658,148 @@ class CAccessibility implements PropertyChangeListener {
// Duplicated from JavaComponentAccessibility
// Note that values >=0 are indexes into the child array
static final int JAVA_AX_ALL_CHILDREN = -1;
static final int JAVA_AX_SELECTED_CHILDREN = -2;
static final int JAVA_AX_VISIBLE_CHILDREN = -3;
@Native static final int JAVA_AX_ALL_CHILDREN = -1;
@Native static final int JAVA_AX_SELECTED_CHILDREN = -2;
@Native static final int JAVA_AX_VISIBLE_CHILDREN = -3;
// Each child takes up two entries in the array: one for itself and one for its role
public static Object[] getChildrenAndRoles(final Accessible a, final Component c, final int whichChildren, final boolean allowIgnored) {
if (a == null) return null;
return invokeAndWait(new Callable<Object[]>() {
public Object[] call() throws Exception {
ArrayList<Object> childrenAndRoles = new ArrayList<Object>();
_addChildren(a, whichChildren, allowIgnored, childrenAndRoles);
/* In the case of fetching a selection, need to check to see if
* the active descendant is at the beginning of the list. If it
* is not it needs to be moved to the beginning of the list so
* VoiceOver will annouce it correctly. The list returned
* from Java is always in order from top to bottom, but when shift
* selecting downward (extending the list) or multi-selecting using
* the VO keys control+option+command+return the active descendant
* is not at the top of the list in the shift select down case and
* may not be in the multi select case.
*/
if (whichChildren == JAVA_AX_SELECTED_CHILDREN) {
if (!childrenAndRoles.isEmpty()) {
AccessibleContext activeDescendantAC =
CAccessible.getActiveDescendant(a);
if (activeDescendantAC != null) {
String activeDescendantName =
activeDescendantAC.getAccessibleName();
AccessibleRole activeDescendantRole =
activeDescendantAC.getAccessibleRole();
// Move active descendant to front of list.
// List contains pairs of each selected item's
// Accessible and AccessibleRole.
ArrayList<Object> newArray = new ArrayList<Object>();
int count = childrenAndRoles.size();
Accessible currentAccessible = null;
AccessibleContext currentAC = null;
String currentName = null;
AccessibleRole currentRole = null;
for (int i = 0; i < count; i+=2) {
// Is this the active descendant?
currentAccessible = (Accessible)childrenAndRoles.get(i);
currentAC = currentAccessible.getAccessibleContext();
currentName = currentAC.getAccessibleName();
currentRole = (AccessibleRole)childrenAndRoles.get(i+1);
if (currentName != null && currentName.equals(activeDescendantName) &&
currentRole.equals(activeDescendantRole) ) {
newArray.add(0, currentAccessible);
newArray.add(1, currentRole);
} else {
newArray.add(currentAccessible);
newArray.add(currentRole);
}
}
childrenAndRoles = newArray;
}
}
}
if ((whichChildren < 0) || (whichChildren * 2 >= childrenAndRoles.size())) {
return childrenAndRoles.toArray();
}
return new Object[] { childrenAndRoles.get(whichChildren * 2), childrenAndRoles.get((whichChildren * 2) + 1) };
return getChildrenAndRolesImpl(a, c, whichChildren, allowIgnored);
}
}, c);
}
private static final int JAVA_AX_ROWS = 1;
private static final int JAVA_AX_COLS = 2;
private static Object[] getChildrenAndRolesImpl(final Accessible a, final Component c, final int whichChildren, final boolean allowIgnored) {
if (a == null) return null;
ArrayList<Object> childrenAndRoles = new ArrayList<Object>();
_addChildren(a, whichChildren, allowIgnored, childrenAndRoles);
/* In case of fetching a selection, we need to check if
* the active descendant is at the beginning of the list, or
* otherwise move it, so that VoiceOver announces it correctly.
* The java list is always in order from top to bottom, but when
* (1) shift-selecting downward (extending the list) or (2) multi-selecting with
* the VO keys (CTRL+ALT+CMD+RETURN) the active descendant
* is not at the top of the list in the 1st case and may not be in the 2nd.
*/
if (whichChildren == JAVA_AX_SELECTED_CHILDREN) {
if (!childrenAndRoles.isEmpty()) {
AccessibleContext activeDescendantAC =
CAccessible.getActiveDescendant(a);
if (activeDescendantAC != null) {
String activeDescendantName =
activeDescendantAC.getAccessibleName();
AccessibleRole activeDescendantRole =
activeDescendantAC.getAccessibleRole();
// Move active descendant to front of list.
// List contains pairs of each selected item's
// Accessible and AccessibleRole.
ArrayList<Object> newArray = new ArrayList<Object>();
int count = childrenAndRoles.size();
Accessible currentAccessible = null;
AccessibleContext currentAC = null;
String currentName = null;
AccessibleRole currentRole = null;
for (int i = 0; i < count; i += 2) {
// Is this the active descendant?
currentAccessible = (Accessible) childrenAndRoles.get(i);
currentAC = currentAccessible.getAccessibleContext();
currentName = currentAC.getAccessibleName();
currentRole = (AccessibleRole) childrenAndRoles.get(i + 1);
if (currentName != null && currentName.equals(activeDescendantName) &&
currentRole.equals(activeDescendantRole)) {
newArray.add(0, currentAccessible);
newArray.add(1, currentRole);
} else {
newArray.add(currentAccessible);
newArray.add(currentRole);
}
}
childrenAndRoles = newArray;
}
}
}
if ((whichChildren < 0) || (whichChildren * 2 >= childrenAndRoles.size())) {
return childrenAndRoles.toArray();
}
return new Object[]{childrenAndRoles.get(whichChildren * 2), childrenAndRoles.get((whichChildren * 2) + 1)};
}
// This method is called from the native
// Each child takes up three entries in the array: one for itself, one for its role, and one for the recursion level
private static Object[] getChildrenAndRolesRecursive(final Accessible a, final Component c, final int whichChildren, final boolean allowIgnored, final int level) {
if (a == null) return null;
return invokeAndWait(new Callable<Object[]>() {
public Object[] call() throws Exception {
ArrayList<Object> currentLevelChildren = new ArrayList<Object>();
ArrayList<Object> allChildren = new ArrayList<Object>();
ArrayList<Accessible> parentStack = new ArrayList<Accessible>();
parentStack.add(a);
ArrayList<Integer> indexses = new ArrayList<Integer>();
Integer index = 0;
int currentLevel = level;
while (!parentStack.isEmpty()) {
Accessible p = parentStack.get(parentStack.size() - 1);
currentLevelChildren.addAll(Arrays.asList(getChildrenAndRolesImpl(p, c, JAVA_AX_ALL_CHILDREN, allowIgnored)));
if ((currentLevelChildren.size() == 0) || (index >= currentLevelChildren.size())) {
if (!parentStack.isEmpty()) parentStack.remove(parentStack.size() - 1);
if (!indexses.isEmpty()) index = indexses.remove(indexses.size() - 1);
currentLevel -= 1;
currentLevelChildren.clear();
continue;
}
Accessible ca = null;
Object obj = currentLevelChildren.get(index);
if (!(obj instanceof Accessible)) {
index += 2;
currentLevelChildren.clear();
continue;
}
ca = (Accessible) obj;
Object role = currentLevelChildren.get(index + 1);
currentLevelChildren.clear();
AccessibleContext cac = ca.getAccessibleContext();
if (cac == null) {
index += 2;
continue;
}
if ((cac.getAccessibleStateSet().contains(AccessibleState.SELECTED) && (whichChildren == JAVA_AX_SELECTED_CHILDREN)) ||
(cac.getAccessibleStateSet().contains(AccessibleState.VISIBLE) && (whichChildren == JAVA_AX_VISIBLE_CHILDREN)) ||
(whichChildren == JAVA_AX_ALL_CHILDREN)) {
allChildren.add(ca);
allChildren.add(role);
allChildren.add(String.valueOf(currentLevel));
}
index += 2;
if (cac.getAccessibleStateSet().contains(AccessibleState.EXPANDED)) {
parentStack.add(ca);
indexses.add(index);
index = 0;
currentLevel += 1;
continue;
}
}
return allChildren.toArray();
}
}, c);
}
@Native private static final int JAVA_AX_ROWS = 1;
@Native private static final int JAVA_AX_COLS = 2;
public static int getTableInfo(final Accessible a, final Component c,
final int info) {
@ -744,6 +818,23 @@ class CAccessibility implements PropertyChangeListener {
}, c);
}
private static int[] getTableSelectedInfo(final Accessible a, final Component c,
final int info) {
if (a == null) return null;
return invokeAndWait(() -> {
AccessibleContext ac = a.getAccessibleContext();
AccessibleTable table = ac.getAccessibleTable();
if (table != null) {
if (info == JAVA_AX_COLS) {
return table.getSelectedAccessibleColumns();
} else if (info == JAVA_AX_ROWS) {
return table.getSelectedAccessibleRows();
}
}
return null;
}, c);
}
private static AccessibleRole getAccessibleRoleForLabel(JLabel l, AccessibleRole fallback) {
String text = l.getText();
if (text != null && text.length() > 0) {
@ -862,4 +953,18 @@ class CAccessibility implements PropertyChangeListener {
}
}, (Component)ax);
}
private static boolean isTreeRootVisible(Accessible a, Component c) {
if (a == null) return false;
return invokeAndWait(new Callable<Boolean>() {
public Boolean call() throws Exception {
Accessible sa = CAccessible.getSwingAccessible(a);
if (sa instanceof JTree) {
return ((JTree) sa).isRootVisible();
}
return false;
}
}, c);
}
}

@ -31,11 +31,7 @@ import java.beans.PropertyChangeListener;
import javax.accessibility.Accessible;
import javax.accessibility.AccessibleContext;
import javax.swing.JProgressBar;
import javax.swing.JTabbedPane;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import static javax.accessibility.AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY;
import static javax.accessibility.AccessibleContext.ACCESSIBLE_CARET_PROPERTY;
@ -75,6 +71,8 @@ class CAccessible extends CFRetainedResource implements Accessible {
private static native void menuOpened(long ptr);
private static native void menuClosed(long ptr);
private static native void menuItemSelected(long ptr);
private static native void treeNodeExpanded(long ptr);
private static native void treeNodeCollapsed(long ptr);
private Accessible accessible;
@ -137,6 +135,13 @@ class CAccessible extends CFRetainedResource implements Accessible {
if (parentAccessible != null) {
parentRole = parentAccessible.getAccessibleContext().getAccessibleRole();
}
if (newValue == AccessibleState.EXPANDED) {
treeNodeExpanded(ptr);
} else if (newValue == AccessibleState.COLLAPSED) {
treeNodeCollapsed(ptr);
}
// At least for now don't handle combo box menu state changes.
// This may change when later fixing issues which currently
// exist for combo boxes, but for now the following is only

@ -27,8 +27,7 @@
#import "CGLGraphicsConfig.h"
#import "AWTView.h"
#import "AWTWindow.h"
#import "JavaComponentAccessibility.h"
#import "JavaTextAccessibility.h"
#import "a11y/CommonComponentAccessibility.h"
#import "JavaAccessibilityUtilities.h"
#import "GeomUtilities.h"
#import "ThreadUtilities.h"
@ -611,42 +610,29 @@ static BOOL shouldUsePressAndHold() {
- (id)getAxData:(JNIEnv*)env
{
jobject jcomponent = [self awtComponent:env];
id ax = [[[JavaComponentAccessibility alloc] initWithParent:self withEnv:env withAccessible:jcomponent withIndex:-1 withView:self withJavaRole:nil] autorelease];
id ax = [[[CommonComponentAccessibility alloc] initWithParent:self withEnv:env withAccessible:jcomponent withIndex:-1 withView:self withJavaRole:nil] autorelease];
(*env)->DeleteLocalRef(env, jcomponent);
return ax;
}
- (NSArray *)accessibilityAttributeNames
{
return [[super accessibilityAttributeNames] arrayByAddingObject:NSAccessibilityChildrenAttribute];
}
// NSAccessibility messages
// attribute methods
- (id)accessibilityAttributeValue:(NSString *)attribute
- (id)accessibilityChildren
{
AWT_ASSERT_APPKIT_THREAD;
JNIEnv *env = [ThreadUtilities getJNIEnv];
if ([attribute isEqualToString:NSAccessibilityChildrenAttribute])
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
(*env)->PushLocalFrame(env, 4);
(*env)->PushLocalFrame(env, 4);
id result = NSAccessibilityUnignoredChildrenForOnlyChild([self getAxData:env]);
id result = NSAccessibilityUnignoredChildrenForOnlyChild([self getAxData:env]);
(*env)->PopLocalFrame(env, NULL);
(*env)->PopLocalFrame(env, NULL);
return result;
}
else
{
return [super accessibilityAttributeValue:attribute];
}
return result;
}
- (BOOL)accessibilityIsIgnored
- (BOOL)isAccessibilityElement
{
return YES;
return NO;
}
- (id)accessibilityHitTest:(NSPoint)point
@ -656,7 +642,7 @@ static BOOL shouldUsePressAndHold() {
(*env)->PushLocalFrame(env, 4);
id result = [[self getAxData:env] accessibilityHitTest:point withEnv:env];
id result = [[self getAxData:env] accessibilityHitTest:point];
(*env)->PopLocalFrame(env, NULL);
@ -681,17 +667,24 @@ static BOOL shouldUsePressAndHold() {
// --- Services menu support for lightweights ---
// finds the focused accessible element, and if it is a text element, obtains the text from it
- (NSString *)accessibleSelectedText
- (NSString *)accessibilitySelectedText
{
id focused = [self accessibilityFocusedUIElement];
if (![focused isKindOfClass:[JavaTextAccessibility class]]) return nil;
return [(JavaTextAccessibility *)focused accessibilitySelectedTextAttribute];
if (![focused respondsToSelector:@selector(accessibilitySelectedText)]) return nil;
return [focused accessibilitySelectedText];
}
- (void)setAccessibilitySelectedText:(NSString *)accessibilitySelectedText {
id focused = [self accessibilityFocusedUIElement];
if ([focused respondsToSelector:@selector(setAccessibilitySelectedText:)]) {
[focused setAccessibilitySelectedText:accessibilitySelectedText];
}
}
// same as above, but converts to RTFD
- (NSData *)accessibleSelectedTextAsRTFD
{
NSString *selectedText = [self accessibleSelectedText];
NSString *selectedText = [self accessibilitySelectedText];
NSAttributedString *styledText = [[NSAttributedString alloc] initWithString:selectedText];
NSData *rtfdData = [styledText RTFDFromRange:NSMakeRange(0, [styledText length])
documentAttributes:
@ -704,8 +697,8 @@ static BOOL shouldUsePressAndHold() {
- (BOOL)replaceAccessibleTextSelection:(NSString *)text
{
id focused = [self accessibilityFocusedUIElement];
if (![focused isKindOfClass:[JavaTextAccessibility class]]) return NO;
[(JavaTextAccessibility *)focused accessibilitySetSelectedTextAttribute:text];
if (![focused respondsToSelector:@selector(setAccessibilitySelectedText)]) return NO;
[focused setAccessibilitySelectedText:text];
return YES;
}
@ -715,7 +708,7 @@ static BOOL shouldUsePressAndHold() {
if ([[self window] firstResponder] != self) return nil; // let AWT components handle themselves
if ([sendType isEqual:NSStringPboardType] || [returnType isEqual:NSStringPboardType]) {
NSString *selectedText = [self accessibleSelectedText];
NSString *selectedText = [self accessibilitySelectedText];
if (selectedText) return self;
}
@ -728,7 +721,7 @@ static BOOL shouldUsePressAndHold() {
if ([types containsObject:NSStringPboardType])
{
[pboard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil];
return [pboard setString:[self accessibleSelectedText] forType:NSStringPboardType];
return [pboard setString:[self accessibilitySelectedText] forType:NSStringPboardType];
}
if ([types containsObject:NSRTFDPboardType])

@ -26,6 +26,10 @@
#import <AppKit/AppKit.h>
#import <jni.h>
extern NSMutableDictionary *sActions;
extern NSMutableDictionary *sActionSelectors;
extern NSMutableArray *sAllActionSelectors;
void initializeActions();
@protocol JavaAccessibilityAction

@ -29,6 +29,10 @@
#import "ThreadUtilities.h"
#import "JNIUtilities.h"
NSMutableDictionary *sActions = nil;
NSMutableDictionary *sActionSelectors = nil;
NSMutableArray *sAllActionSelectors = nil;
void initializeActions();
@implementation JavaAxAction
@ -148,3 +152,31 @@
}
@end
void initializeActions() {
int actionsCount = 5;
sActions = [[NSMutableDictionary alloc] initWithCapacity:actionsCount];
[sActions setObject:NSAccessibilityPressAction forKey:@"click"];
[sActions setObject:NSAccessibilityIncrementAction forKey:@"increment"];
[sActions setObject:NSAccessibilityDecrementAction forKey:@"decrement"];
[sActions setObject:NSAccessibilityShowMenuAction forKey:@"togglePopup"];
[sActions setObject:NSAccessibilityPressAction forKey:@"toggleExpand"];
sActionSelectors = [[NSMutableDictionary alloc] initWithCapacity:actionsCount];
[sActionSelectors setObject:NSStringFromSelector(@selector(accessibilityPerformPress)) forKey:NSAccessibilityPressAction];
[sActionSelectors setObject:NSStringFromSelector(@selector(accessibilityPerformShowMenu)) forKey:NSAccessibilityShowMenuAction];
[sActionSelectors setObject:NSStringFromSelector(@selector(accessibilityPerformDecrement)) forKey:NSAccessibilityDecrementAction];
[sActionSelectors setObject:NSStringFromSelector(@selector(accessibilityPerformIncrement)) forKey:NSAccessibilityIncrementAction];
[sActionSelectors setObject:NSStringFromSelector(@selector(accessibilityPerformPick)) forKey:NSAccessibilityPickAction];
sAllActionSelectors = [[NSMutableArray alloc] initWithCapacity:actionsCount];
[sAllActionSelectors addObject:NSStringFromSelector(@selector(accessibilityPerformPick))];
[sAllActionSelectors addObject:NSStringFromSelector(@selector(accessibilityPerformIncrement))];
[sAllActionSelectors addObject:NSStringFromSelector(@selector(accessibilityPerformDecrement))];
[sAllActionSelectors addObject:NSStringFromSelector(@selector(accessibilityPerformShowMenu))];
[sAllActionSelectors addObject:NSStringFromSelector(@selector(accessibilityPerformPress))];
}

@ -48,6 +48,7 @@ BOOL isVertical(JNIEnv *env, jobject axContext, jobject component);
BOOL isHorizontal(JNIEnv *env, jobject axContext, jobject component);
BOOL isShowing(JNIEnv *env, jobject axContext, jobject component);
BOOL isSelectable(JNIEnv *env, jobject axContext, jobject component);
BOOL isExpanded(JNIEnv *env, jobject axContext, jobject component);
NSPoint getAxComponentLocationOnScreen(JNIEnv *env, jobject axComponent, jobject component);
jint getAxTextCharCount(JNIEnv *env, jobject axText, jobject component);
@ -60,3 +61,6 @@ void JavaAccessibilitySetAttributeValue(id element, NSString *attribute, id valu
void JavaAccessibilityRaiseSetAttributeToIllegalTypeException(const char *functionName, id element, NSString *attribute, id value);
void JavaAccessibilityRaiseUnimplementedAttributeException(const char *functionName, id element, NSString *attribute);
void JavaAccessibilityRaiseIllegalParameterTypeException(const char *functionName, id element, NSString *attribute, id parameter);
BOOL ObjectEquals(JNIEnv *env, jobject a, jobject b, jobject component);
NSNumber* JavaNumberToNSNumber(JNIEnv *env, jobject jnumber);
NSValue *javaIntArrayToNSRangeValue(JNIEnv* env, jintArray array);

@ -27,6 +27,7 @@
#import "JNIUtilities.h"
#import <AppKit/AppKit.h>
#import "ThreadUtilities.h"
static BOOL JavaAccessibilityIsSupportedAttribute(id element, NSString *attribute);
static void JavaAccessibilityLogError(NSString *message);
@ -199,6 +200,20 @@ BOOL isSelectable(JNIEnv *env, jobject axContext, jobject component)
return selectable;
}
BOOL isExpanded(JNIEnv *env, jobject axContext, jobject component)
{
GET_ACCESSIBLESTATE_CLASS_RETURN(NO);
DECLARE_STATIC_FIELD_RETURN(jm_EXPANDED,
sjc_AccessibleState,
"EXPANDED",
"Ljavax/accessibility/AccessibleState;", NO );
jobject axExpandedState = (*env)->GetStaticObjectField(env, sjc_AccessibleState, jm_EXPANDED);
CHECK_EXCEPTION_NULL_RETURN(axExpandedState, NO);
BOOL expanded = containsAxState(env, axContext, axExpandedState, component);
(*env)->DeleteLocalRef(env, axExpandedState);
return expanded;
}
NSPoint getAxComponentLocationOnScreen(JNIEnv *env, jobject axComponent, jobject component)
{
GET_CACCESSIBILITY_CLASS_RETURN(NSZeroPoint);
@ -348,6 +363,75 @@ static void JavaAccessibilityLogError(NSString *message)
NSLog(@"!!! %@", message);
}
/*
* Returns Object.equals for the two items
* This may use LWCToolkit.invokeAndWait(); don't call while holding fLock
* and try to pass a component so the event happens on the correct thread.
*/
BOOL ObjectEquals(JNIEnv *env, jobject a, jobject b, jobject component)
{
DECLARE_CLASS_RETURN(sjc_Object, "java/lang/Object", NO);
DECLARE_METHOD_RETURN(jm_equals, sjc_Object, "equals", "(Ljava/lang/Object;)Z", NO);
if ((a == NULL) && (b == NULL)) return YES;
if ((a == NULL) || (b == NULL)) return NO;
if (pthread_main_np() != 0) {
// If we are on the AppKit thread
DECLARE_CLASS_RETURN(sjc_LWCToolkit, "sun/lwawt/macosx/LWCToolkit", NO);
DECLARE_STATIC_METHOD_RETURN(jm_doEquals, sjc_LWCToolkit, "doEquals",
"(Ljava/lang/Object;Ljava/lang/Object;Ljava/awt/Component;)Z", NO);
return (*env)->CallStaticBooleanMethod(env, sjc_LWCToolkit, jm_doEquals, a, b, component);
CHECK_EXCEPTION();
}
jboolean jb = (*env)->CallBooleanMethod(env, a, jm_equals, b);
CHECK_EXCEPTION();
return jb;
}
/*
* The java/lang/Number concrete class could be for any of the Java primitive
* numerical types or some other subclass.
* All existing A11Y code uses Integer so that is what we look for first
* But all must be able to return a double and NSNumber accepts a double,
* so that's the fall back.
*/
NSNumber* JavaNumberToNSNumber(JNIEnv *env, jobject jnumber) {
if (jnumber == NULL) {
return nil;
}
DECLARE_CLASS_RETURN(jnumber_Class, "java/lang/Number", nil);
DECLARE_CLASS_RETURN(jinteger_Class, "java/lang/Integer", nil);
DECLARE_METHOD_RETURN(jm_intValue, jnumber_Class, "intValue", "()I", nil);
DECLARE_METHOD_RETURN(jm_doubleValue, jnumber_Class, "doubleValue", "()D", nil);
if ((*env)->IsInstanceOf(env, jnumber, jinteger_Class)) {
jint i = (*env)->CallIntMethod(env, jnumber, jm_intValue);
CHECK_EXCEPTION();
return [NSNumber numberWithInteger:i];
} else {
jdouble d = (*env)->CallDoubleMethod(env, jnumber, jm_doubleValue);
CHECK_EXCEPTION();
return [NSNumber numberWithDouble:d];
}
}
/*
* Converts an int array to an NSRange wrapped inside an NSValue
* takes [start, end] values and returns [start, end - start]
*/
NSValue *javaIntArrayToNSRangeValue(JNIEnv* env, jintArray array) {
jint *values = (*env)->GetIntArrayElements(env, array, 0);
if (values == NULL) {
// Note: Java will not be on the stack here so a java exception can't happen and no need to call ExceptionCheck.
NSLog(@"%s failed calling GetIntArrayElements", __FUNCTION__);
return nil;
};
NSValue *value = [NSValue valueWithRange:NSMakeRange(values[0], values[1] - values[0])];
(*env)->ReleaseIntArrayElements(env, array, values, 0);
return value;
}
// end appKit copies
/*
@ -417,13 +501,13 @@ void initializeRoles()
[sRoles setObject:NSAccessibilitySplitGroupRole forKey:@"splitpane"];
[sRoles setObject:NSAccessibilityValueIndicatorRole forKey:@"statusbar"];
[sRoles setObject:NSAccessibilityGroupRole forKey:@"swingcomponent"];
[sRoles setObject:NSAccessibilityGridRole forKey:@"table"];
[sRoles setObject:NSAccessibilityTableRole forKey:@"table"];
[sRoles setObject:NSAccessibilityTextFieldRole forKey:@"text"];
[sRoles setObject:NSAccessibilityTextAreaRole forKey:@"textarea"]; // supports top/bottom of document notifications: CAccessability.getAccessibleRole()
[sRoles setObject:NSAccessibilityCheckBoxRole forKey:@"togglebutton"];
[sRoles setObject:NSAccessibilityToolbarRole forKey:@"toolbar"];
[sRoles setObject:JavaAccessibilityIgnore forKey:@"tooltip"];
[sRoles setObject:NSAccessibilityBrowserRole forKey:@"tree"];
[sRoles setObject:NSAccessibilityOutlineRole forKey:@"tree"];
[sRoles setObject:NSAccessibilityUnknownRole forKey:@"unknown"];
[sRoles setObject:JavaAccessibilityIgnore forKey:@"viewport"];
[sRoles setObject:JavaAccessibilityIgnore forKey:@"window"];

@ -29,7 +29,6 @@
// <https://www.ibm.com/able/guidelines/java/snsjavagjfc.html>
#import "JavaComponentAccessibility.h"
#import "a11y/CommonComponentAccessibility.h"
#import "sun_lwawt_macosx_CAccessibility.h"
#import <AppKit/AppKit.h>
@ -45,6 +44,12 @@
#import "JNIUtilities.h"
#import "AWTView.h"
// these constants are duplicated in CAccessibility.java
#define JAVA_AX_ALL_CHILDREN (-1)
#define JAVA_AX_SELECTED_CHILDREN (-2)
#define JAVA_AX_VISIBLE_CHILDREN (-3)
// If the value is >=0, it's an index
// GET* macros defined in JavaAccessibilityUtilities.h, so they can be shared.
static jclass sjc_CAccessibility = NULL;
@ -82,7 +87,7 @@ static jclass sjc_CAccessible = NULL;
static NSMutableDictionary *sAttributeNamesForRoleCache = nil;
static NSObject *sAttributeNamesLOCK = nil;
@interface TabGroupAccessibility : JavaComponentAccessibility {
@interface TabGroupLegacyAccessibility : JavaComponentAccessibility {
NSInteger _numTabs;
}
@ -112,7 +117,7 @@ static NSObject *sAttributeNamesLOCK = nil;
- (id)accessibilityValueAttribute;
@end
@interface TableAccessibility : JavaComponentAccessibility {
@interface TableLegacyAccessibility : JavaComponentAccessibility {
}
- (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env;
@ -362,21 +367,18 @@ static NSObject *sAttributeNamesLOCK = nil;
// otherwise, create a new instance
JavaComponentAccessibility *newChild = nil;
newChild = [CommonComponentAccessibility getComponentAccessibility:javaRole];
if (newChild == nil) {
if ([javaRole isEqualToString:@"pagetablist"]) {
newChild = [TabGroupAccessibility alloc];
} else if ([javaRole isEqualToString:@"table"]) {
newChild = [TableAccessibility alloc];
if ([javaRole isEqualToString:@"pagetablist"]) {
newChild = [TabGroupLegacyAccessibility alloc];
} else if ([javaRole isEqualToString:@"table"]) {
newChild = [TableLegacyAccessibility alloc];
} else {
NSString *nsRole = [sRoles objectForKey:javaRole];
if ([nsRole isEqualToString:NSAccessibilityStaticTextRole] ||
[nsRole isEqualToString:NSAccessibilityTextAreaRole] ||
[nsRole isEqualToString:NSAccessibilityTextFieldRole]) {
newChild = [JavaTextAccessibility alloc];
} else {
NSString *nsRole = [sRoles objectForKey:javaRole];
if ([nsRole isEqualToString:NSAccessibilityStaticTextRole] ||
[nsRole isEqualToString:NSAccessibilityTextAreaRole] ||
[nsRole isEqualToString:NSAccessibilityTextFieldRole]) {
newChild = [JavaTextAccessibility alloc];
} else {
newChild = [JavaComponentAccessibility alloc];
}
newChild = [JavaComponentAccessibility alloc];
}
}
@ -387,7 +389,7 @@ static NSObject *sAttributeNamesLOCK = nil;
// This is the only way to know if the menu is opening; visible state change
// can't be caught because the listeners are not set up in time.
if ( [javaRole isEqualToString:@"popupmenu"] &&
![[parent javaRole] isEqualToString:@"combobox"] ) {
![[parent javaRole] isEqualToString:@"combobox"] ) {
[newChild postMenuOpened];
}
@ -904,32 +906,6 @@ static NSObject *sAttributeNamesLOCK = nil;
return index;
}
/*
* The java/lang/Number concrete class could be for any of the Java primitive
* numerical types or some other subclass.
* All existing A11Y code uses Integer so that is what we look for first
* But all must be able to return a double and NSNumber accepts a double,
* so that's the fall back.
*/
static NSNumber* JavaNumberToNSNumber(JNIEnv *env, jobject jnumber) {
if (jnumber == NULL) {
return nil;
}
DECLARE_CLASS_RETURN(jnumber_Class, "java/lang/Number", nil);
DECLARE_CLASS_RETURN(jinteger_Class, "java/lang/Integer", nil);
DECLARE_METHOD_RETURN(jm_intValue, jnumber_Class, "intValue", "()I", nil);
DECLARE_METHOD_RETURN(jm_doubleValue, jnumber_Class, "doubleValue", "()D", nil);
if ((*env)->IsInstanceOf(env, jnumber, jinteger_Class)) {
jint i = (*env)->CallIntMethod(env, jnumber, jm_intValue);
CHECK_EXCEPTION();
return [NSNumber numberWithInteger:i];
} else {
jdouble d = (*env)->CallDoubleMethod(env, jnumber, jm_doubleValue);
CHECK_EXCEPTION();
return [NSNumber numberWithDouble:d];
}
}
// Element's maximum value (id)
- (id)accessibilityMaxValueAttribute
{
@ -1600,7 +1576,7 @@ JNI_COCOA_ENTER(env);
JNI_COCOA_EXIT(env);
}
@implementation TabGroupAccessibility
@implementation TabGroupLegacyAccessibility
- (id)initWithParent:(NSObject *)parent withEnv:(JNIEnv *)env withAccessible:(jobject)accessible withIndex:(jint)index withView:(NSView *)view withJavaRole:(NSString *)javaRole
{
@ -1802,9 +1778,6 @@ JNI_COCOA_EXIT(env);
@end
static BOOL ObjectEquals(JNIEnv *env, jobject a, jobject b, jobject component);
@implementation TabGroupControlAccessibility
- (id)initWithParent:(NSObject *)parent withEnv:(JNIEnv *)env withAccessible:(jobject)accessible withIndex:(jint)index withTabGroup:(jobject)tabGroup withView:(NSView *)view withJavaRole:(NSString *)javaRole
@ -1873,7 +1846,7 @@ static BOOL ObjectEquals(JNIEnv *env, jobject a, jobject b, jobject component);
#define JAVA_AX_ROWS (1)
#define JAVA_AX_COLS (2)
@implementation TableAccessibility
@implementation TableLegacyAccessibility
- (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env
{
@ -1907,30 +1880,3 @@ static BOOL ObjectEquals(JNIEnv *env, jobject a, jobject b, jobject component);
return [self getTableInfo:JAVA_AX_COLS];
}
@end
/*
* Returns Object.equals for the two items
* This may use LWCToolkit.invokeAndWait(); don't call while holding fLock
* and try to pass a component so the event happens on the correct thread.
*/
static BOOL ObjectEquals(JNIEnv *env, jobject a, jobject b, jobject component)
{
DECLARE_CLASS_RETURN(sjc_Object, "java/lang/Object", NO);
DECLARE_METHOD_RETURN(jm_equals, sjc_Object, "equals", "(Ljava/lang/Object;)Z", NO);
if ((a == NULL) && (b == NULL)) return YES;
if ((a == NULL) || (b == NULL)) return NO;
if (pthread_main_np() != 0) {
// If we are on the AppKit thread
DECLARE_CLASS_RETURN(sjc_LWCToolkit, "sun/lwawt/macosx/LWCToolkit", NO);
DECLARE_STATIC_METHOD_RETURN(jm_doEquals, sjc_LWCToolkit, "doEquals",
"(Ljava/lang/Object;Ljava/lang/Object;Ljava/awt/Component;)Z", NO);
return (*env)->CallStaticBooleanMethod(env, sjc_LWCToolkit, jm_doEquals, a, b, component);
CHECK_EXCEPTION();
}
jboolean jb = (*env)->CallBooleanMethod(env, a, jm_equals, b);
CHECK_EXCEPTION();
return jb;
}

@ -53,23 +53,6 @@ static jmethodID sjm_getAccessibleEditableText = NULL;
GET_STATIC_METHOD_RETURN(sjm_getAccessibleEditableText, sjc_CAccessibleText, "getAccessibleEditableText", \
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/AccessibleEditableText;", ret);
/*
* Converts an int array to an NSRange wrapped inside an NSValue
* takes [start, end] values and returns [start, end - start]
*/
NSValue *javaIntArrayToNSRangeValue(JNIEnv* env, jintArray array) {
jint *values = (*env)->GetIntArrayElements(env, array, 0);
if (values == NULL) {
// Note: Java will not be on the stack here so a java exception can't happen and no need to call ExceptionCheck.
NSLog(@"%s failed calling GetIntArrayElements", __FUNCTION__);
return nil;
};
NSValue *value = [NSValue valueWithRange:NSMakeRange(values[0], values[1] - values[0])];
(*env)->ReleaseIntArrayElements(env, array, values, 0);
return value;
}
@implementation JavaTextAccessibility
// based strongly upon NSTextViewAccessibility:accessibilityAttributeNames

@ -36,7 +36,7 @@
- (NSString * _Nullable)accessibilityLabel
{
return [self accessibilityTitleAttribute];
return [super accessibilityLabel];
}
- (BOOL)accessibilityPerformPress
@ -44,4 +44,14 @@
return [self performAccessibleAction:0];
}
- (NSRect)accessibilityFrame
{
return [super accessibilityFrame];
}
- (id)accessibilityParent
{
return [super accessibilityParent];
}
@end

@ -0,0 +1,28 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "CommonComponentAccessibility.h"
@interface CellAccessibility : CommonComponentAccessibility
@end

@ -0,0 +1,86 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "CellAccessibility.h"
#import "ThreadUtilities.h"
#import "TableAccessibility.h"
@implementation CellAccessibility
// NSAccessibilityElement protocol methods
- (NSAccessibilityRole)accessibilityRole
{
return NSAccessibilityCellRole;;
}
- (NSArray *)accessibilityChildren
{
NSArray *children = [super accessibilityChildren];
if (children == NULL) {
NSString *javaRole = [self javaRole];
CommonComponentAccessibility *newChild = [CommonComponentAccessibility createWithParent:self
accessible:self->fAccessible
role:javaRole
index:self->fIndex
withEnv:[ThreadUtilities getJNIEnv]
withView:self->fView
isWrapped:NO];
return [NSArray arrayWithObject:newChild];
} else {
return children;
}
}
- (NSRect)accessibilityFrame
{
return [super accessibilityFrame];
}
- (id)accessibilityParent
{
return [super accessibilityParent];
}
- (NSRange)accessibilityRowIndexRange {
NSInteger location = -1;
if ([[(CommonComponentAccessibility *)fParent accessibilityParent] isKindOfClass:[TableAccessibility class]]) {
TableAccessibility *table = [(CommonComponentAccessibility *)fParent accessibilityParent];
location = [table accessibleRowAtIndex:fIndex];
}
return NSMakeRange(location, 1);
}
- (NSRange)accessibilityColumnIndexRange {
NSInteger location = -1;
if ([[(CommonComponentAccessibility *)fParent accessibilityParent] isKindOfClass:[TableAccessibility class]]) {
TableAccessibility *table = [(CommonComponentAccessibility *)fParent accessibilityParent];
location = [table accessibleColumnAtIndex:fIndex];
}
return NSMakeRange(location, 1);
}
@end

@ -39,7 +39,7 @@
- (id _Nonnull) accessibilityValue
{
AWT_ASSERT_APPKIT_THREAD;
return [self accessibilityValueAttribute];
return [super accessibilityValue];
}
@end

@ -0,0 +1,31 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "CommonComponentAccessibility.h"
@interface ColumnAccessibility : CommonComponentAccessibility
@property(readonly) NSUInteger columnNumberInTable;
@end

@ -0,0 +1,112 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include "jni.h"
#import "JavaAccessibilityAction.h"
#import "JavaAccessibilityUtilities.h"
#import "CellAccessibility.h"
#import "ColumnAccessibility.h"
#import "TableAccessibility.h"
#import "ThreadUtilities.h"
#import "JNIUtilities.h"
#import "sun_lwawt_macosx_CAccessibility.h"
static jclass sjc_CAccessibility = NULL;
static jmethodID jm_getChildrenAndRoles = NULL;
#define GET_CHILDRENANDROLES_METHOD_RETURN(ret) \
GET_CACCESSIBILITY_CLASS_RETURN(ret); \
GET_STATIC_METHOD_RETURN(jm_getChildrenAndRoles, sjc_CAccessibility, "getChildrenAndRoles",\
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;IZ)[Ljava/lang/Object;", ret);
@implementation ColumnAccessibility
// NSAccessibilityElement protocol methods
- (NSAccessibilityRole)accessibilityRole
{
return NSAccessibilityColumnRole;
}
- (NSArray *)accessibilityChildren
{
NSArray *children = [super accessibilityChildren];
if (children == NULL) {
JNIEnv *env = [ThreadUtilities getJNIEnv];
CommonComponentAccessibility *parent = [self accessibilityParent];
if (parent->fAccessible == NULL) return nil;
GET_CHILDRENANDROLES_METHOD_RETURN(nil);
jobjectArray jchildrenAndRoles = (jobjectArray)(*env)->CallStaticObjectMethod(env, sjc_CAccessibility, jm_getChildrenAndRoles,
parent->fAccessible, parent->fComponent, sun_lwawt_macosx_CAccessibility_JAVA_AX_ALL_CHILDREN, NO);
CHECK_EXCEPTION();
if (jchildrenAndRoles == NULL) return nil;
jsize arrayLen = (*env)->GetArrayLength(env, jchildrenAndRoles);
NSMutableArray *childrenCells = [NSMutableArray arrayWithCapacity:arrayLen/2];
NSUInteger childIndex = fIndex;
int inc = [(TableAccessibility *)[self accessibilityParent] accessibilityRowCount] * 2;
NSInteger i = childIndex * 2;
for(i; i < arrayLen; i += inc)
{
jobject /* Accessible */ jchild = (*env)->GetObjectArrayElement(env, jchildrenAndRoles, i);
jobject /* String */ jchildJavaRole = (*env)->GetObjectArrayElement(env, jchildrenAndRoles, i+1);
NSString *childJavaRole = nil;
if (jchildJavaRole != NULL) {
DECLARE_CLASS_RETURN(sjc_AccessibleRole, "javax/accessibility/AccessibleRole", nil);
DECLARE_FIELD_RETURN(sjf_key, sjc_AccessibleRole, "key", "Ljava/lang/String;", nil);
jobject jkey = (*env)->GetObjectField(env, jchildJavaRole, sjf_key);
CHECK_EXCEPTION();
childJavaRole = JavaStringToNSString(env, jkey);
(*env)->DeleteLocalRef(env, jkey);
}
CellAccessibility *child = [[CellAccessibility alloc] initWithParent:self
withEnv:env
withAccessible:jchild
withIndex:childIndex
withView:self->fView
withJavaRole:childJavaRole];
[childrenCells addObject:[[child retain] autorelease]];
(*env)->DeleteLocalRef(env, jchild);
(*env)->DeleteLocalRef(env, jchildJavaRole);
childIndex += (inc / 2);
}
(*env)->DeleteLocalRef(env, jchildrenAndRoles);
return childrenCells;
} else {
return children;
}
}
- (NSInteger)accessibilityIndex
{
return fIndex;
}
@end

@ -0,0 +1,28 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "CommonComponentAccessibility.h"
@interface ComboBoxAccessibility : CommonComponentAccessibility
@end

@ -0,0 +1,68 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "ComboBoxAccessibility.h"
#import "../JavaAccessibilityUtilities.h"
#import "ThreadUtilities.h"
#import "JNIUtilities.h"
static jclass sjc_CAccessibility = NULL;
static jmethodID sjm_getAccessibleName = NULL;
#define GET_ACCESSIBLENAME_METHOD_RETURN(ret) \
GET_CACCESSIBILITY_CLASS_RETURN(ret); \
GET_STATIC_METHOD_RETURN(sjm_getAccessibleName, sjc_CAccessibility, "getAccessibleName", \
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;", ret);
@implementation ComboBoxAccessibility
// NSAccessibilityElement protocol methods
- (id)accessibilityValue {
JNIEnv *env = [ThreadUtilities getJNIEnv];
jobject axContext = [self axContextWithEnv:env];
if (axContext == NULL) return nil;
jclass axContextClass = (*env)->GetObjectClass(env, axContext);
DECLARE_METHOD_RETURN(jm_getAccessibleSelection, axContextClass, "getAccessibleSelection", "(I)Ljavax/accessibility/Accessible;", nil);
jobject axSelectedChild = (*env)->CallObjectMethod(env, axContext, jm_getAccessibleSelection, 0);
CHECK_EXCEPTION();
(*env)->DeleteLocalRef(env, axContext);
if (axSelectedChild == NULL) {
return nil;
}
GET_CACCESSIBILITY_CLASS_RETURN(nil);
GET_ACCESSIBLENAME_METHOD_RETURN(nil);
jobject childName = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility, sjm_getAccessibleName, axSelectedChild, fComponent);
CHECK_EXCEPTION();
if (childName == NULL) {
(*env)->DeleteLocalRef(env, axSelectedChild);
return nil;
}
NSString *selectedText = JavaStringToNSString(env, childName);
(*env)->DeleteLocalRef(env, axSelectedChild);
(*env)->DeleteLocalRef(env, childName);
return selectedText;
}
@end

@ -26,23 +26,83 @@
#ifndef JAVA_COMPONENT_ACCESSIBILITY
#define JAVA_COMPONENT_ACCESSIBILITY
#import "JavaComponentAccessibility.h"
#include "jni.h"
#import <AppKit/AppKit.h>
#import "JavaAccessibilityUtilities.h"
// these constants are duplicated in CAccessibility.java
#define JAVA_AX_ALL_CHILDREN (-1)
#define JAVA_AX_SELECTED_CHILDREN (-2)
#define JAVA_AX_VISIBLE_CHILDREN (-3)
// If the value is >=0, it's an index
@interface CommonComponentAccessibility : NSAccessibilityElement {
NSView *fView;
NSObject *fParent;
@interface CommonComponentAccessibility : JavaComponentAccessibility <NSAccessibilityElement> {
NSString *fNSRole;
NSString *fJavaRole;
jint fIndex;
jobject fAccessible;
jobject fComponent;
NSMutableDictionary *fActions;
NSMutableArray *fActionSelectors;
NSObject *fActionsLOCK;
}
@property(nonnull, readonly) NSArray *actionSelectors;
- (id _Nonnull)initWithParent:(NSObject* _Nonnull)parent withEnv:(JNIEnv _Nonnull * _Nonnull)env withAccessible:(jobject _Nullable)accessible withIndex:(jint)index withView:(NSView* _Nonnull)view withJavaRole:(NSString* _Nullable)javaRole;
- (void)unregisterFromCocoaAXSystem;
- (void)postValueChanged;
- (void)postSelectedTextChanged;
- (void)postSelectionChanged;
- (void)postTitleChanged;
- (void)postTreeNodeExpanded;
- (void)postTreeNodeCollapsed;
- (BOOL)isEqual:(nonnull id)anObject;
- (BOOL)isAccessibleWithEnv:(JNIEnv _Nonnull * _Nonnull)env forAccessible:(nonnull jobject)accessible;
+ (void)postFocusChanged:(nullable id)message;
+ (void) initializeRolesMap;
+ (JavaComponentAccessibility * _Nullable) getComponentAccessibility:(NSString * _Nonnull)role;
+ (CommonComponentAccessibility* _Nullable) getComponentAccessibility:(NSString* _Nonnull)role;
+ (CommonComponentAccessibility * _Nullable) getComponentAccessibility:(NSString * _Nonnull)role andParent:(CommonComponentAccessibility * _Nonnull)parent;
+ (NSArray* _Nullable)childrenOfParent:(CommonComponentAccessibility* _Nonnull)parent withEnv:(JNIEnv _Nonnull * _Nonnull)env withChildrenCode:(NSInteger)whichChildren allowIgnored:(BOOL)allowIgnored;
+ (NSArray* _Nullable)childrenOfParent:(CommonComponentAccessibility* _Nonnull)parent withEnv:(JNIEnv _Nonnull * _Nonnull)env withChildrenCode:(NSInteger)whichChildren allowIgnored:(BOOL)allowIgnored recursive:(BOOL)recursive;
+ (CommonComponentAccessibility* _Nullable) createWithParent:(CommonComponentAccessibility* _Nullable)parent accessible:(jobject _Nonnull)jaccessible role:(NSString* _Nonnull)javaRole index:(jint)index withEnv:(JNIEnv _Nonnull * _Nonnull)env withView:(NSView* _Nonnull)view;
+ (CommonComponentAccessibility* _Nullable) createWithAccessible:(jobject _Nonnull)jaccessible role:(NSString* _Nonnull)role index:(jint)index withEnv:(JNIEnv _Nonnull * _Nonnull)env withView:(NSView* _Nonnull)view;
+ (CommonComponentAccessibility* _Nullable) createWithAccessible:(jobject _Nonnull)jaccessible withEnv:(JNIEnv _Nonnull * _Nonnull)env withView:(NSView* _Nonnull)view;
// If the isWraped parameter is true, then the object passed as a parent was created based on the same java component,
// but performs a different NSAccessibilityRole of a table cell, or a list row, or tree row,
// and we need to create an element whose role corresponds to the role in Java.
+ (CommonComponentAccessibility* _Nullable) createWithParent:(CommonComponentAccessibility* _Nullable)parent accessible:(jobject _Nonnull)jaccessible role:(NSString* _Nonnull)javaRole index:(jint)index withEnv:(JNIEnv _Nonnull * _Nonnull)env withView:(NSView* _Nonnull)view isWrapped:(BOOL)wrapped;
// The current parameter is used to bypass the check for an item's index on the parent so that the item is created. This is necessary,
// for example, for AccessibleJTreeNode, whose currentComponent has index -1
+ (CommonComponentAccessibility* _Nullable) createWithAccessible:(jobject _Nonnull)jaccessible withEnv:(JNIEnv _Nonnull * _Nonnull)env withView:(NSView* _Nonnull)view isCurrent:(BOOL)current;
- (jobject _Nullable)axContextWithEnv:(JNIEnv _Nonnull * _Nonnull)env;
- (NSView* _Nonnull)view;
- (NSWindow* _Nonnull)window;
- (id _Nonnull)parent;
- (NSString* _Nonnull)javaRole;
- (BOOL)isMenu;
- (BOOL)isSelected:(JNIEnv _Nonnull * _Nonnull)env;
- (BOOL)isSelectable:(JNIEnv _Nonnull * _Nonnull)env;
- (BOOL)isVisible:(JNIEnv _Nonnull * _Nonnull)env;
- (NSArray* _Nullable)accessibleChildrenWithChildCode:(NSInteger)childCode;
- (NSDictionary* _Nullable)getActions:(JNIEnv _Nonnull * _Nonnull)env;
- (void)getActionsWithEnv:(JNIEnv _Nonnull * _Nonnull)env;
- (BOOL)accessiblePerformAction:(NSAccessibilityActionName _Nonnull)actionName;
- (BOOL)performAccessibleAction:(int)index;
- (NSRect)accessibilityFrame;
- (id _Nullable)accessibilityParent;
- (BOOL)performAccessibleAction:(int)index;
- (BOOL)isAccessibilityElement;
@end

@ -70,7 +70,7 @@ static NSRange javaIntArrayToNSRange(JNIEnv* env, jintArray array) {
GET_CACCESSIBILITY_CLASS_RETURN(nil);
DECLARE_STATIC_METHOD_RETURN(sjm_getAccessibleName, sjc_CAccessibility, "getAccessibleName",
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;", nil);
if ([[self accessibilityRoleAttribute] isEqualToString:NSAccessibilityStaticTextRole]) {
if ([[self accessibilityRole] isEqualToString:NSAccessibilityStaticTextRole]) {
jobject axName = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility,
sjm_getAccessibleName, fAccessible, fComponent);
CHECK_EXCEPTION();

@ -26,6 +26,7 @@
#import "GroupAccessibility.h"
#import "JNIUtilities.h"
#import "ThreadUtilities.h"
#import "sun_lwawt_macosx_CAccessibility.h"
/*
* This is the protocol for the components that contain children.
* Basic logic of accessibilityChildren might be overridden in the specific implementing
@ -43,9 +44,9 @@
- (NSArray *)accessibilityChildren {
JNIEnv *env = [ThreadUtilities getJNIEnv];
NSArray *children = [JavaComponentAccessibility childrenOfParent:self
NSArray *children = [CommonComponentAccessibility childrenOfParent:self
withEnv:env
withChildrenCode:JAVA_AX_ALL_CHILDREN
withChildrenCode:sun_lwawt_macosx_CAccessibility_JAVA_AX_ALL_CHILDREN
allowIgnored:NO];
if ([children count] == 0) {
@ -55,4 +56,14 @@
}
}
- (NSRect)accessibilityFrame
{
return [super accessibilityFrame];
}
- (id)accessibilityParent
{
return [super accessibilityParent];
}
@end

@ -36,7 +36,17 @@
- (NSString * _Nullable)accessibilityLabel
{
return [self accessibilityTitleAttribute];
return [super accessibilityLabel];
}
- (NSRect)accessibilityFrame
{
return [super accessibilityFrame];
}
- (id)accessibilityParent
{
return [super accessibilityParent];
}
@end

@ -0,0 +1,28 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "CommonComponentAccessibility.h"
@interface ListAccessibility : CommonComponentAccessibility <NSAccessibilityList>
@end

@ -0,0 +1,63 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "ListAccessibility.h"
#import "JavaAccessibilityUtilities.h"
#import "ThreadUtilities.h"
@implementation ListAccessibility
// NSAccessibilityElement protocol methods
- (nullable NSArray<id<NSAccessibilityRow>> *)accessibilityRows
{
return [self accessibilityChildren];
}
- (nullable NSArray<id<NSAccessibilityRow>> *)accessibilitySelectedRows
{
return [self accessibilitySelectedChildren];
}
- (NSString *)accessibilityLabel
{
return [super accessibilityLabel] == NULL ? @"list" : [super accessibilityLabel];
}
// to avoid warning (why?): method in protocol 'NSAccessibilityElement' not implemented
- (NSRect)accessibilityFrame
{
return [super accessibilityFrame];
}
// to avoid warning (why?): method in protocol 'NSAccessibilityElement' not implemented
- (id)accessibilityParent
{
return [super accessibilityParent];
}
@end

@ -0,0 +1,28 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "CommonComponentAccessibility.h"
@interface ListRowAccessibility : CommonComponentAccessibility <NSAccessibilityRow>
@end

@ -0,0 +1,75 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include "jni.h"
#import "ListRowAccessibility.h"
#import "JavaAccessibilityAction.h"
#import "JavaAccessibilityUtilities.h"
#import "ListAccessibility.h"
#import "ThreadUtilities.h"
@implementation ListRowAccessibility
// NSAccessibilityElement protocol methods
- (NSAccessibilityRole)accessibilityRole
{
return NSAccessibilityRowRole;
}
- (NSArray *)accessibilityChildren
{
NSArray *children = [super accessibilityChildren];
if (children == NULL) {
// Since the row element has already been created, we should no create it again, but just retrieve it by a pointer, that's why isWrapped is set to YES.
CommonComponentAccessibility *newChild = [CommonComponentAccessibility createWithParent:self
accessible:self->fAccessible
role:self->fJavaRole
index:self->fIndex
withEnv:[ThreadUtilities getJNIEnv]
withView:self->fView
isWrapped:YES];
return [NSArray arrayWithObject:newChild];
} else {
return children;
}
}
- (NSInteger)accessibilityIndex
{
return [[self accessibilityParent] accessibilityIndexOfChild:self];
}
- (id)accessibilityParent
{
return [super accessibilityParent];
}
- (NSRect)accessibilityFrame
{
return [super accessibilityFrame];
}
@end

@ -0,0 +1,31 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "CommonComponentAccessibility.h"
@interface NavigableTextAccessibility : CommonComponentAccessibility <NSAccessibilityNavigableStaticText>
@property(readonly) BOOL accessibleIsPasswordText;
@end

@ -0,0 +1,316 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "NavigableTextAccessibility.h"
#import "JavaAccessibilityUtilities.h"
#import "ThreadUtilities.h"
#import "JNIUtilities.h"
static jclass sjc_CAccessibility = NULL;
#define GET_CACCESSIBLITY_CLASS() \
GET_CLASS(sjc_CAccessibility, "sun/lwawt/macosx/CAccessibility");
#define GET_CACCESSIBLITY_CLASS_RETURN(ret) \
GET_CLASS_RETURN(sjc_CAccessibility, "sun/lwawt/macosx/CAccessibility", ret);
static jmethodID sjm_getAccessibleText = NULL;
#define GET_ACCESSIBLETEXT_METHOD_RETURN(ret) \
GET_CACCESSIBLITY_CLASS_RETURN(ret); \
GET_STATIC_METHOD_RETURN(sjm_getAccessibleText, sjc_CAccessibility, "getAccessibleText", \
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/AccessibleText;", ret);
static jclass sjc_CAccessibleText = NULL;
#define GET_CACCESSIBLETEXT_CLASS() \
GET_CLASS(sjc_CAccessibleText, "sun/lwawt/macosx/CAccessibleText");
#define GET_CACCESSIBLETEXT_CLASS_RETURN(ret) \
GET_CLASS_RETURN(sjc_CAccessibleText, "sun/lwawt/macosx/CAccessibleText", ret);
static jmethodID sjm_getAccessibleEditableText = NULL;
#define GET_ACCESSIBLEEDITABLETEXT_METHOD_RETURN(ret) \
GET_CACCESSIBLETEXT_CLASS_RETURN(ret); \
GET_STATIC_METHOD_RETURN(sjm_getAccessibleEditableText, sjc_CAccessibleText, "getAccessibleEditableText", \
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/AccessibleEditableText;", ret);
@implementation NavigableTextAccessibility
- (BOOL)accessibleIsPasswordText {
return [fJavaRole isEqualToString:@"passwordtext"];
}
// NSAccessibilityElement protocol methods
- (NSRect)accessibilityFrameForRange:(NSRange)range
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
GET_CACCESSIBLETEXT_CLASS_RETURN(NSMakeRect(0, 0, 0, 0));
DECLARE_STATIC_METHOD_RETURN(jm_getBoundsForRange, sjc_CAccessibleText, "getBoundsForRange",
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;II)[D", NSMakeRect(0, 0, 0, 0));
jdoubleArray axBounds = (jdoubleArray)(*env)->CallStaticObjectMethod(env, sjc_CAccessibleText, jm_getBoundsForRange,
fAccessible, fComponent, range.location, range.length);
CHECK_EXCEPTION();
if (axBounds == NULL) return NSMakeRect(0, 0, 0, 0);
// We cheat because we know that the array is 4 elements long (x, y, width, height)
jdouble *values = (*env)->GetDoubleArrayElements(env, axBounds, 0);
CHECK_EXCEPTION();
NSRect bounds;
bounds.origin.x = values[0];
bounds.origin.y = [[[[self view] window] screen] frame].size.height - values[1] - values[3]; //values[1] is y-coord from top-left of screen. Flip. Account for the height (values[3]) when flipping
bounds.size.width = values[2];
bounds.size.height = values[3];
(*env)->ReleaseDoubleArrayElements(env, axBounds, values, 0);
return bounds;
}
- (NSInteger)accessibilityLineForIndex:(NSInteger)index
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
GET_CACCESSIBLETEXT_CLASS_RETURN(-1);
DECLARE_STATIC_METHOD_RETURN(jm_getLineNumberForIndex, sjc_CAccessibleText, "getLineNumberForIndex",
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;I)I", -1);
jint row = (*env)->CallStaticIntMethod(env, sjc_CAccessibleText, jm_getLineNumberForIndex,
fAccessible, fComponent, index);
CHECK_EXCEPTION();
if (row < 0) return -1;
return row;
}
- (NSRange)accessibilityRangeForLine:(NSInteger)line
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
GET_CACCESSIBLETEXT_CLASS_RETURN(NSRangeFromString(@""));
DECLARE_STATIC_METHOD_RETURN(jm_getRangeForLine, sjc_CAccessibleText, "getRangeForLine",
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;I)[I", NSRangeFromString(@""));
jintArray axTextRange = (jintArray)(*env)->CallStaticObjectMethod(env, sjc_CAccessibleText,
jm_getRangeForLine, fAccessible, fComponent, line);
CHECK_EXCEPTION();
if (axTextRange == NULL) return NSRangeFromString(@"");
NSRange range = [javaIntArrayToNSRangeValue(env,axTextRange) rangeValue];
(*env)->DeleteLocalRef(env, axTextRange);
return range;
}
- (NSString *)accessibilityStringForRange:(NSRange)range
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
GET_CACCESSIBLETEXT_CLASS_RETURN(nil);
DECLARE_STATIC_METHOD_RETURN(jm_getStringForRange, sjc_CAccessibleText, "getStringForRange",
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;II)Ljava/lang/String;", nil);
jstring jstringForRange = (jstring)(*env)->CallStaticObjectMethod(env, sjc_CAccessibleText, jm_getStringForRange,
fAccessible, fComponent, range.location, range.length);
CHECK_EXCEPTION();
if (jstringForRange == NULL) return @"";
NSString* str = JavaStringToNSString(env, jstringForRange);
(*env)->DeleteLocalRef(env, jstringForRange);
return str;
}
- (id)accessibilityValue
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
GET_CACCESSIBLITY_CLASS_RETURN(nil);
DECLARE_STATIC_METHOD_RETURN(sjm_getAccessibleName, sjc_CAccessibility, "getAccessibleName",
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;", nil);
// cmcnote: inefficient to make three distinct JNI calls. Coalesce. radr://3951923
GET_ACCESSIBLETEXT_METHOD_RETURN(@"");
jobject axText = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility,
sjm_getAccessibleText, fAccessible, fComponent);
CHECK_EXCEPTION();
if (axText == NULL) return nil;
(*env)->DeleteLocalRef(env, axText);
GET_ACCESSIBLEEDITABLETEXT_METHOD_RETURN(nil);
jobject axEditableText = (*env)->CallStaticObjectMethod(env, sjc_CAccessibleText,
sjm_getAccessibleEditableText, fAccessible, fComponent);
CHECK_EXCEPTION();
if (axEditableText == NULL) return nil;
DECLARE_STATIC_METHOD_RETURN(jm_getTextRange, sjc_CAccessibleText, "getTextRange",
"(Ljavax/accessibility/AccessibleEditableText;IILjava/awt/Component;)Ljava/lang/String;", nil);
jobject jrange = (*env)->CallStaticObjectMethod(env, sjc_CAccessibleText, jm_getTextRange,
axEditableText, 0, getAxTextCharCount(env, axEditableText, fComponent), fComponent);
CHECK_EXCEPTION();
NSString *string = JavaStringToNSString(env, jrange);
(*env)->DeleteLocalRef(env, jrange);
(*env)->DeleteLocalRef(env, axEditableText);
if (string == nil) string = @"";
return string;
}
- (NSAccessibilitySubrole)accessibilitySubrole {
if ([self accessibleIsPasswordText]) {
return NSAccessibilitySecureTextFieldSubrole;
}
return nil;
}
- (NSRange)accessibilityRangeForIndex:(NSInteger)index
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
GET_CACCESSIBLETEXT_CLASS_RETURN(NSRangeFromString(@""));
DECLARE_STATIC_METHOD_RETURN(jm_getRangeForIndex, sjc_CAccessibleText, "getRangeForIndex",
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;I)[I", NSRangeFromString(@""));
jintArray axTextRange = (jintArray)(*env)->CallStaticObjectMethod(env, sjc_CAccessibleText, jm_getRangeForIndex,
fAccessible, fComponent, index);
CHECK_EXCEPTION();
if (axTextRange == NULL) return NSRangeFromString(@"");
return [javaIntArrayToNSRangeValue(env, axTextRange) rangeValue];
}
- (NSAccessibilityRole)accessibilityRole {
return [sRoles objectForKey:self.javaRole];
}
- (NSRange)accessibilityRangeForPosition:(NSPoint)point
{
point.y = [[[[self view] window] screen] frame].size.height - point.y; // flip into java screen coords (0 is at upper-left corner of screen)
JNIEnv *env = [ThreadUtilities getJNIEnv];
GET_CACCESSIBLETEXT_CLASS_RETURN(NSRangeFromString(@""));
DECLARE_STATIC_METHOD_RETURN(jm_getCharacterIndexAtPosition, sjc_CAccessibleText, "getCharacterIndexAtPosition",
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;II)I", NSRangeFromString(@""));
jint charIndex = (*env)->CallStaticIntMethod(env, sjc_CAccessibleText, jm_getCharacterIndexAtPosition,
fAccessible, fComponent, point.x, point.y);
CHECK_EXCEPTION();
if (charIndex == -1) return NSRangeFromString(@"");
// AccessibleText.getIndexAtPoint returns -1 for an invalid point
NSRange range = NSMakeRange(charIndex, 1); //range's length is 1 - one-character range
return range;
}
- (NSString *)accessibilitySelectedText
{
JNIEnv* env = [ThreadUtilities getJNIEnv];
GET_CACCESSIBLETEXT_CLASS_RETURN(nil);
DECLARE_STATIC_METHOD_RETURN(jm_getSelectedText, sjc_CAccessibleText, "getSelectedText",
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;", nil);
jobject axText = (*env)->CallStaticObjectMethod(env, sjc_CAccessibleText, jm_getSelectedText,
fAccessible, fComponent);
CHECK_EXCEPTION();
if (axText == NULL) return @"";
NSString* str = JavaStringToNSString(env, axText);
(*env)->DeleteLocalRef(env, axText);
return str;
}
- (NSRange)accessibilitySelectedTextRange
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
GET_CACCESSIBLETEXT_CLASS_RETURN(NSRangeFromString(@""));
DECLARE_STATIC_METHOD_RETURN(jm_getSelectedTextRange, sjc_CAccessibleText, "getSelectedTextRange",
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;)[I", NSRangeFromString(@""));
jintArray axTextRange = (*env)->CallStaticObjectMethod(env, sjc_CAccessibleText,
jm_getSelectedTextRange, fAccessible, fComponent);
CHECK_EXCEPTION();
if (axTextRange == NULL) return NSRangeFromString(@"");
return [javaIntArrayToNSRangeValue(env, axTextRange) rangeValue];
}
- (NSInteger)accessibilityNumberOfCharacters
{
// cmcnote: should coalesce these two calls - radr://3951923
// also, static text doesn't always have accessibleText. if axText is null, should get the charcount of the accessibleName instead
JNIEnv *env = [ThreadUtilities getJNIEnv];
GET_ACCESSIBLETEXT_METHOD_RETURN(0);
jobject axText = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility,
sjm_getAccessibleText, fAccessible, fComponent);
CHECK_EXCEPTION();
NSInteger num = getAxTextCharCount(env, axText, fComponent);
(*env)->DeleteLocalRef(env, axText);
return num;
}
- (NSInteger)accessibilityInsertionPointLineNumber
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
GET_CACCESSIBLETEXT_CLASS_RETURN(0);
DECLARE_STATIC_METHOD_RETURN(jm_getLineNumberForInsertionPoint, sjc_CAccessibleText,
"getLineNumberForInsertionPoint", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)I", 0);
jint row = (*env)->CallStaticIntMethod(env, sjc_CAccessibleText,
jm_getLineNumberForInsertionPoint, fAccessible, fComponent);
CHECK_EXCEPTION();
return row >= 0 ? row : 0;
}
- (void)setAccessibilitySelectedText:(NSString *)accessibilitySelectedText
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
jstring jstringValue = NSStringToJavaString(env, accessibilitySelectedText);
GET_CACCESSIBLETEXT_CLASS();
DECLARE_STATIC_METHOD(jm_setSelectedText, sjc_CAccessibleText, "setSelectedText",
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;Ljava/lang/String;)V");
(*env)->CallStaticVoidMethod(env, sjc_CAccessibleText, jm_setSelectedText,
fAccessible, fComponent, jstringValue);
CHECK_EXCEPTION();
}
- (void)setAccessibilitySelectedTextRange:(NSRange)accessibilitySelectedTextRange
{
jint startIndex = accessibilitySelectedTextRange.location;
jint endIndex = startIndex + accessibilitySelectedTextRange.length;
JNIEnv *env = [ThreadUtilities getJNIEnv];
GET_CACCESSIBLETEXT_CLASS();
DECLARE_STATIC_METHOD(jm_setSelectedTextRange, sjc_CAccessibleText, "setSelectedTextRange",
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;II)V");
(*env)->CallStaticVoidMethod(env, sjc_CAccessibleText, jm_setSelectedTextRange,
fAccessible, fComponent, startIndex, endIndex);
CHECK_EXCEPTION();
}
- (BOOL)isAccessibilityEdited {
return YES;
}
- (BOOL)isAccessibilityEnabled {
return YES;
}
- (NSRect)accessibilityFrame
{
return [super accessibilityFrame];
}
- (id)accessibilityParent
{
return [super accessibilityParent];
}
/*
* Other text methods
- (NSRange)accessibilitySharedCharacterRange;
- (NSArray *)accessibilitySharedTextUIElements;
- (NSData *)accessibilityRTFForRange:(NSRange)range;
- (NSRange)accessibilityStyleRangeForIndex:(NSInteger)index;
*/
@end

@ -0,0 +1,33 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "ListAccessibility.h"
// This is a tree representation. See: https://developer.apple.com/documentation/appkit/nsoutlineview
@interface OutlineAccessibility : ListAccessibility <NSAccessibilityOutline>
@property(readonly) BOOL isTreeRootVisible;
@end

@ -0,0 +1,56 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "OutlineAccessibility.h"
#import "JavaAccessibilityUtilities.h"
#import "ThreadUtilities.h"
#import "JNIUtilities.h"
static jclass sjc_CAccessibility = NULL;
static jmethodID sjm_isTreeRootVisible = NULL;
#define GET_ISTREEROOTVISIBLE_METHOD_RETURN(ret) \
GET_CACCESSIBILITY_CLASS_RETURN(ret); \
GET_STATIC_METHOD_RETURN(sjm_isTreeRootVisible, sjc_CAccessibility, "isTreeRootVisible", \
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Z", ret);
@implementation OutlineAccessibility
- (BOOL)isTreeRootVisible
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
GET_ISTREEROOTVISIBLE_METHOD_RETURN(NO);
bool isTreeRootVisible = (*env)->CallStaticBooleanMethod(env, sjc_CAccessibility, sjm_isTreeRootVisible, fAccessible, fComponent);
CHECK_EXCEPTION();
return isTreeRootVisible;
}
// NSAccessibilityElement protocol methods
- (NSString *)accessibilityLabel
{
return [[super accessibilityLabel] isEqualToString:@"list"] ? @"tree" : [super accessibilityLabel];
}
@end

@ -0,0 +1,33 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "ListRowAccessibility.h"
@interface OutlineRowAccessibility : ListRowAccessibility
@property(readwrite) int accessibleLevel;
- (jobject)currentAccessibleWithENV:(JNIEnv *)env;
@end

@ -0,0 +1,111 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include "jni.h"
#import "OutlineRowAccessibility.h"
#import "JavaAccessibilityUtilities.h"
#import "ThreadUtilities.h"
#import "JNIUtilities.h"
#import "OutlineAccessibility.h"
#import "sun_lwawt_macosx_CAccessibility.h"
static jclass sjc_CAccessible = NULL;
#define GET_CACCESSIBLE_CLASS_RETURN(ret) \
GET_CLASS_RETURN(sjc_CAccessible, "sun/lwawt/macosx/CAccessible", ret);
@implementation OutlineRowAccessibility
@synthesize accessibleLevel;
- (jobject)currentAccessibleWithENV:(JNIEnv *)env
{
jobject jAxContext = getAxContext(env, fAccessible, fComponent);
if (jAxContext == NULL) return NULL;
jclass axContextClass = (*env)->GetObjectClass(env, jAxContext);
DECLARE_METHOD_RETURN(jm_getCurrentComponent, axContextClass, "getCurrentComponent", "()Ljava/awt/Component;", NULL);
jobject newComponent = (*env)->CallObjectMethod(env, jAxContext, jm_getCurrentComponent);
CHECK_EXCEPTION();
(*env)->DeleteLocalRef(env, jAxContext);
if (newComponent != NULL) {
GET_CACCESSIBLE_CLASS_RETURN(NULL);
DECLARE_STATIC_METHOD_RETURN(sjm_getCAccessible, sjc_CAccessible, "getCAccessible", "(Ljavax/accessibility/Accessible;)Lsun/lwawt/macosx/CAccessible;", NULL);
jobject currentAccessible = (*env)->CallStaticObjectMethod(env, sjc_CAccessible, sjm_getCAccessible, newComponent);
CHECK_EXCEPTION();
(*env)->DeleteLocalRef(env, newComponent);
return currentAccessible;
} else {
return NULL;
}
}
// NSAccessibilityElement protocol methods
- (NSArray *)accessibilityChildren
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
jobject currentAccessible = [self currentAccessibleWithENV:env];
if (currentAccessible != NULL) {
CommonComponentAccessibility *currentElement = [CommonComponentAccessibility createWithAccessible:currentAccessible withEnv:env withView:self->fView isCurrent:YES];
NSArray *children = [CommonComponentAccessibility childrenOfParent:currentElement withEnv:env withChildrenCode:sun_lwawt_macosx_CAccessibility_JAVA_AX_ALL_CHILDREN allowIgnored:YES];
if ([children count] != 0) {
return children;
}
}
return [NSArray arrayWithObject:[CommonComponentAccessibility createWithParent:self
accessible:self->fAccessible
role:self->fJavaRole
index:self->fIndex
withEnv:env
withView:self->fView
isWrapped:YES]];
}
- (NSInteger)accessibilityDisclosureLevel
{
int level = [self accessibleLevel];
return [(OutlineAccessibility *)[self accessibilityParent] isTreeRootVisible] ? level - 1 : level;
}
- (BOOL)isAccessibilityDisclosed
{
return isExpanded([ThreadUtilities getJNIEnv], [self axContextWithEnv:[ThreadUtilities getJNIEnv]], self->fComponent);
}
- (NSAccessibilitySubrole)accessibilitySubrole
{
return NSAccessibilityOutlineRowSubrole;;
}
- (NSAccessibilityRole)accessibilityRole
{
return NSAccessibilityRowRole;;
}
- (BOOL)isAccessibilitySelected
{
return YES;
}
@end

@ -39,7 +39,7 @@
- (id _Nonnull) accessibilityValue
{
AWT_ASSERT_APPKIT_THREAD;
return [self accessibilityValueAttribute];
return [super accessibilityValue];
}
@end

@ -26,6 +26,7 @@
#import "ScrollAreaAccessibility.h"
#import "ThreadUtilities.h"
#import "JNIUtilities.h"
#import "sun_lwawt_macosx_CAccessibility.h"
/*
* Implementation of the accessibility peer for the ScrollArea role
@ -35,16 +36,16 @@
- (NSArray * _Nullable)accessibilityContentsAttribute
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
NSArray *children = [JavaComponentAccessibility childrenOfParent:self withEnv:env withChildrenCode:JAVA_AX_ALL_CHILDREN allowIgnored:YES];
NSArray *children = [CommonComponentAccessibility childrenOfParent:self withEnv:env withChildrenCode:sun_lwawt_macosx_CAccessibility_JAVA_AX_ALL_CHILDREN allowIgnored:YES];
if ([children count] <= 0) return nil;
NSArray *contents = [NSMutableArray arrayWithCapacity:[children count]];
// The scroll bars are in the children. children less the scroll bars is the contents
NSEnumerator *enumerator = [children objectEnumerator];
JavaComponentAccessibility *aElement;
while ((aElement = (JavaComponentAccessibility *)[enumerator nextObject])) {
if (![[aElement accessibilityRoleAttribute] isEqualToString:NSAccessibilityScrollBarRole]) {
CommonComponentAccessibility *aElement;
while ((aElement = (CommonComponentAccessibility *)[enumerator nextObject])) {
if (![[aElement accessibilityRole] isEqualToString:NSAccessibilityScrollBarRole]) {
// no scroll bars in contents
[(NSMutableArray *)contents addObject:aElement];
}
@ -56,14 +57,14 @@
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
NSArray *children = [JavaComponentAccessibility childrenOfParent:self withEnv:env withChildrenCode:JAVA_AX_ALL_CHILDREN allowIgnored:YES];
NSArray *children = [CommonComponentAccessibility childrenOfParent:self withEnv:env withChildrenCode:sun_lwawt_macosx_CAccessibility_JAVA_AX_ALL_CHILDREN allowIgnored:YES];
if ([children count] <= 0) return nil;
// The scroll bars are in the children.
JavaComponentAccessibility *aElement;
CommonComponentAccessibility *aElement;
NSEnumerator *enumerator = [children objectEnumerator];
while ((aElement = (JavaComponentAccessibility *)[enumerator nextObject])) {
if ([[aElement accessibilityRoleAttribute] isEqualToString:NSAccessibilityScrollBarRole]) {
while ((aElement = (CommonComponentAccessibility *)[enumerator nextObject])) {
if ([[aElement accessibilityRole] isEqualToString:NSAccessibilityScrollBarRole]) {
jobject elementAxContext = [aElement axContextWithEnv:env];
if (orientation == NSAccessibilityOrientationHorizontal) {
if (isHorizontal(env, elementAxContext, fComponent)) {

@ -39,12 +39,12 @@
- (NSString * _Nullable)accessibilityLabel
{
return [self accessibilityTitleAttribute];
return [super accessibilityLabel];
}
- (id _Nullable)accessibilityValue
{
return [self accessibilityValueAttribute];
return [super accessibilityValue];
}
- (BOOL)accessibilityPerformIncrement
@ -57,4 +57,14 @@
return [self performAccessibleAction:DECREMENT];
}
- (NSRect)accessibilityFrame
{
return [super accessibilityFrame];
}
- (id)accessibilityParent
{
return [super accessibilityParent];
}
@end

@ -39,12 +39,12 @@
- (NSString * _Nullable)accessibilityLabel
{
return [self accessibilityTitleAttribute];
return [super accessibilityLabel];
}
- (id _Nullable)accessibilityValue
{
return [self accessibilityValueAttribute];
return [super accessibilityValue];
}
- (BOOL)accessibilityPerformIncrement
@ -58,4 +58,14 @@
return [self performAccessibleAction:DECREMENT];
}
- (NSRect)accessibilityFrame
{
return [super accessibilityFrame];
}
- (id)accessibilityParent
{
return [super accessibilityParent];
}
@end

@ -47,4 +47,14 @@
return [self accessibilityVisibleCharacterRangeAttribute];
}
- (NSRect)accessibilityFrame
{
return [super accessibilityFrame];
}
- (id)accessibilityParent
{
return [super accessibilityParent];
}
@end

@ -0,0 +1,37 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "CommonComponentAccessibility.h"
@interface TabButtonAccessibility : CommonComponentAccessibility {
jobject fTabGroupAxContext;
}
@property(readonly) jobject tabGroup;
// from TabGroup controller
- (id)initWithParent:(NSObject *)parent withEnv:(JNIEnv *)env withAccessible:(jobject)accessible withIndex:(jint)index withTabGroup:(jobject)tabGroup withView:(NSView *)view withJavaRole:(NSString *)javaRole;
- (void)performPressAction;
@end

@ -0,0 +1,107 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "TabButtonAccessibility.h"
#import "JavaAccessibilityAction.h"
#import "JavaAccessibilityUtilities.h"
#import "ThreadUtilities.h"
#import "JNIUtilities.h"
@implementation TabButtonAccessibility
- (id)initWithParent:(NSObject *)parent withEnv:(JNIEnv *)env withAccessible:(jobject)accessible withIndex:(jint)index withTabGroup:(jobject)tabGroup withView:(NSView *)view withJavaRole:(NSString *)javaRole
{
self = [super initWithParent:parent withEnv:env withAccessible:accessible withIndex:index withView:view withJavaRole:javaRole];
if (self) {
if (tabGroup != NULL) {
fTabGroupAxContext = (*env)->NewWeakGlobalRef(env, tabGroup);
CHECK_EXCEPTION();
} else {
fTabGroupAxContext = NULL;
}
}
return self;
}
- (void)dealloc
{
JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
if (fTabGroupAxContext != NULL) {
(*env)->DeleteWeakGlobalRef(env, fTabGroupAxContext);
fTabGroupAxContext = NULL;
}
[super dealloc];
}
- (jobject)tabGroup
{
if (fTabGroupAxContext == NULL) {
JNIEnv* env = [ThreadUtilities getJNIEnv];
jobject tabGroupAxContext = [(CommonComponentAccessibility *)[self parent] axContextWithEnv:env];
fTabGroupAxContext = (*env)->NewWeakGlobalRef(env, tabGroupAxContext);
CHECK_EXCEPTION();
(*env)->DeleteLocalRef(env, tabGroupAxContext);
}
return fTabGroupAxContext;
}
- (void)performPressAction {
JNIEnv *env = [ThreadUtilities getJNIEnv];
TabGroupAction *action = [[TabGroupAction alloc] initWithEnv:env withTabGroup:[self tabGroup] withIndex:fIndex withComponent:fComponent];
[action perform];
[action release];
}
// NSAccessibilityElement protocol methods
- (NSAccessibilitySubrole)accessibilitySubrole
{
if (@available(macOS 10.13, *)) {
return NSAccessibilityTabButtonSubrole;
}
return NSAccessibilityUnknownSubrole;
}
- (id)accessibilityValue
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
jobject axContext = [self axContextWithEnv:env];
jobject selAccessible = getAxContextSelection(env, [self tabGroup], fIndex, fComponent);
// Returns the current selection of the page tab list
id val = [NSNumber numberWithBool:ObjectEquals(env, axContext, selAccessible, fComponent)];
(*env)->DeleteLocalRef(env, selAccessible);
(*env)->DeleteLocalRef(env, axContext);
return val;
}
- (BOOL)accessibilityPerformPress {
[self performPressAction];
return YES;
}
@end

@ -0,0 +1,37 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "CommonComponentAccessibility.h"
@interface TabGroupAccessibility : CommonComponentAccessibility {
NSInteger _numTabs;
}
@property(readonly) NSInteger numTabs;
- (id)currentTabWithEnv:(JNIEnv *)env withAxContext:(jobject)axContext;
- (NSArray *)tabButtonsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored;
- (NSArray *)contentsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored;
@end

@ -0,0 +1,204 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "TabGroupAccessibility.h"
#import "TabButtonAccessibility.h"
#import "../JavaAccessibilityUtilities.h"
#import "ThreadUtilities.h"
#import "JNIUtilities.h"
#import "sun_lwawt_macosx_CAccessibility.h"
static jclass sjc_CAccessibility = NULL;
static jmethodID jm_getChildrenAndRoles = NULL;
#define GET_CHILDRENANDROLES_METHOD_RETURN(ret) \
GET_CACCESSIBILITY_CLASS_RETURN(ret); \
GET_STATIC_METHOD_RETURN(jm_getChildrenAndRoles, sjc_CAccessibility, "getChildrenAndRoles",\
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;IZ)[Ljava/lang/Object;", ret);
@implementation TabGroupAccessibility
- (id)currentTabWithEnv:(JNIEnv *)env withAxContext:(jobject)axContext
{
NSArray *tabs = [self tabButtonsWithEnv:env withTabGroupAxContext:axContext withTabCode:sun_lwawt_macosx_CAccessibility_JAVA_AX_ALL_CHILDREN allowIgnored:NO];
// Looking at the JTabbedPane sources, there is always one AccessibleSelection.
jobject selAccessible = getAxContextSelection(env, axContext, 0, fComponent);
if (selAccessible == NULL) return nil;
// Go through the tabs and find selAccessible
_numTabs = [tabs count];
CommonComponentAccessibility *aTab;
NSInteger i;
for (i = 0; i < _numTabs; i++) {
aTab = (CommonComponentAccessibility *)[tabs objectAtIndex:i];
if ([aTab isAccessibleWithEnv:env forAccessible:selAccessible]) {
(*env)->DeleteLocalRef(env, selAccessible);
return aTab;
}
}
(*env)->DeleteLocalRef(env, selAccessible);
return nil;
}
- (NSArray *)tabButtonsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored
{
GET_CHILDRENANDROLES_METHOD_RETURN(nil);
jobjectArray jtabsAndRoles = (jobjectArray)(*env)->CallStaticObjectMethod(env, sjc_CAccessibility, jm_getChildrenAndRoles,
fAccessible, fComponent, whichTabs, allowIgnored);
CHECK_EXCEPTION();
if(jtabsAndRoles == NULL) return nil;
jsize arrayLen = (*env)->GetArrayLength(env, jtabsAndRoles);
if (arrayLen == 0) {
(*env)->DeleteLocalRef(env, jtabsAndRoles);
return nil;
}
NSMutableArray *tabs = [NSMutableArray arrayWithCapacity:(arrayLen/2)];
// all of the tabs have the same role, so we can just find out what that is here and use it for all the tabs
jobject jtabJavaRole = (*env)->GetObjectArrayElement(env, jtabsAndRoles, 1); // the array entries alternate between tab/role, starting with tab. so the first role is entry 1.
if (jtabJavaRole == NULL) {
(*env)->DeleteLocalRef(env, jtabsAndRoles);
return nil;
}
DECLARE_CLASS_RETURN(sjc_AccessibleRole, "javax/accessibility/AccessibleRole", nil);
DECLARE_FIELD_RETURN(sjf_key, sjc_AccessibleRole, "key", "Ljava/lang/String;", nil);
jobject jkey = (*env)->GetObjectField(env, jtabJavaRole, sjf_key);
CHECK_EXCEPTION();
NSString *tabJavaRole = JavaStringToNSString(env, jkey);
(*env)->DeleteLocalRef(env, jkey);
NSInteger i;
NSUInteger tabIndex = (whichTabs >= 0) ? whichTabs : 0; // if we're getting one particular child, make sure to set its index correctly
for(i = 0; i < arrayLen; i+=2) {
jobject jtab = (*env)->GetObjectArrayElement(env, jtabsAndRoles, i);
CommonComponentAccessibility *tab = [[[TabButtonAccessibility alloc] initWithParent:self withEnv:env withAccessible:jtab withIndex:tabIndex withTabGroup:axContext withView:[self view] withJavaRole:tabJavaRole] autorelease];
(*env)->DeleteLocalRef(env, jtab);
[tabs addObject:tab];
tabIndex++;
}
(*env)->DeleteLocalRef(env, jtabsAndRoles);
return tabs;
}
- (NSArray *)contentsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored
{
// Contents are the children of the selected tab.
id currentTab = [self currentTabWithEnv:env withAxContext:axContext];
if (currentTab == nil) return nil;
NSArray *contents = [CommonComponentAccessibility childrenOfParent:currentTab withEnv:env withChildrenCode:whichTabs allowIgnored:allowIgnored];
if ([contents count] <= 0) return nil;
return contents;
}
- (NSInteger)numTabs
{
if (_numTabs == -1) {
_numTabs = [[self accessibilityTabsAttribute] count];
}
return _numTabs;
}
// NSAccessibilityElement protocol methods
- (NSArray *)accessibilityTabs
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
jobject axContext = [self axContextWithEnv:env];
id tabs = [self tabButtonsWithEnv:env withTabGroupAxContext:axContext withTabCode:sun_lwawt_macosx_CAccessibility_JAVA_AX_ALL_CHILDREN allowIgnored:NO];
(*env)->DeleteLocalRef(env, axContext);
return tabs;
}
- (NSArray *)accessibilityContents
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
jobject axContext = [self axContextWithEnv:env];
NSArray* cont = [self contentsWithEnv:env withTabGroupAxContext:axContext withTabCode:sun_lwawt_macosx_CAccessibility_JAVA_AX_ALL_CHILDREN allowIgnored:NO];
(*env)->DeleteLocalRef(env, axContext);
return cont;
}
- (id)accessibilityValue
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
jobject axContext = [self axContextWithEnv:env];
id val = [self currentTabWithEnv:env withAxContext:axContext];
(*env)->DeleteLocalRef(env, axContext);
return val;
}
- (NSArray *)accessibilityChildren
{
//children = AXTabs + AXContents
NSArray *tabs = [self accessibilityTabs];
NSArray *contents = [self accessibilityContents];
NSMutableArray *children = [NSMutableArray arrayWithCapacity:[tabs count] + [contents count]];
[children addObjectsFromArray:tabs];
[children addObjectsFromArray:contents];
return (NSArray *)children;
}
- (NSArray *)accessibilityArrayAttributeValues:(NSAccessibilityAttributeName)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount
{
NSArray *result = nil;
if ( (maxCount == 1) && [attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
// Children codes for ALL, SELECTED, VISIBLE are <0. If the code is >=0, we treat it as an index to a single child
JNIEnv *env = [ThreadUtilities getJNIEnv];
jobject axContext = [self axContextWithEnv:env];
//children = AXTabs + AXContents
NSArray *children = [self tabButtonsWithEnv:env withTabGroupAxContext:axContext withTabCode:index allowIgnored:NO]; // first look at the tabs
if ([children count] > 0) {
result = children;
} else {
children= [self contentsWithEnv:env withTabGroupAxContext:axContext withTabCode:(index-[self numTabs]) allowIgnored:NO];
if ([children count] > 0) {
result = children;
}
}
(*env)->DeleteLocalRef(env, axContext);
} else {
result = [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount];
}
return result;
}
- (void)setAccessibilityValue:(id)accessibilityValue
{
// set the current tab
NSNumber *number = (NSNumber *)accessibilityValue;
if (![number boolValue]) return;
JNIEnv *env = [ThreadUtilities getJNIEnv];
jobject axContext = [self axContextWithEnv:env];
setAxContextSelection(env, axContext, fIndex, fComponent);
(*env)->DeleteLocalRef(env, axContext);
}
@end

@ -0,0 +1,33 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "CommonComponentAccessibility.h"
@interface TableAccessibility : CommonComponentAccessibility <NSAccessibilityTable>
- (BOOL)isAccessibleChildSelectedFromIndex:(int)index;
- (int) accessibleRowAtIndex:(int)index;
- (int) accessibleColumnAtIndex:(int)index;
@end

@ -0,0 +1,241 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include "jni.h"
#import "TableRowAccessibility.h"
#import "JavaAccessibilityAction.h"
#import "JavaAccessibilityUtilities.h"
#import "TableAccessibility.h"
#import "CellAccessibility.h"
#import "ColumnAccessibility.h"
#import "ThreadUtilities.h"
#import "JNIUtilities.h"
#import "CellAccessibility.h"
#import "sun_lwawt_macosx_CAccessibility.h"
static jclass sjc_CAccessibility = NULL;
static jmethodID sjm_getAccessibleName = NULL;
#define GET_ACCESSIBLENAME_METHOD_RETURN(ret) \
GET_CACCESSIBILITY_CLASS_RETURN(ret); \
GET_STATIC_METHOD_RETURN(sjm_getAccessibleName, sjc_CAccessibility, "getAccessibleName", \
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;", ret);
@implementation TableAccessibility
- (id)getTableInfo:(jint)info
{
if (fAccessible == NULL) return 0;
JNIEnv* env = [ThreadUtilities getJNIEnv];
GET_CACCESSIBILITY_CLASS_RETURN(nil);
DECLARE_STATIC_METHOD_RETURN(jm_getTableInfo, sjc_CAccessibility, "getTableInfo",
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;I)I", nil);
jint count = (*env)->CallStaticIntMethod(env, sjc_CAccessibility, jm_getTableInfo, fAccessible,
fComponent, info);
CHECK_EXCEPTION();
NSNumber *index = [NSNumber numberWithInt:count];
return index;
}
- (NSArray<NSNumber *> *)getTableSelectedInfo:(jint)info
{
if (fAccessible == NULL) return 0;
JNIEnv* env = [ThreadUtilities getJNIEnv];
GET_CACCESSIBILITY_CLASS_RETURN(nil);
DECLARE_STATIC_METHOD_RETURN(jm_getTableSelectedInfo, sjc_CAccessibility, "getTableSelectedInfo",
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;I)[I", nil);
jintArray selected = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility, jm_getTableSelectedInfo, fAccessible,
fComponent, info);
CHECK_EXCEPTION();
if (selected == NULL) {
return nil;
}
jsize arrayLen = (*env)->GetArrayLength(env, selected);
jint *indexsis = (*env)->GetIntArrayElements(env, selected, 0);
NSMutableArray<NSNumber *> *nsArraySelected = [NSMutableArray<NSNumber *> arrayWithCapacity:arrayLen];
for (int i = 0; i < arrayLen; i++) {
[nsArraySelected addObject:[NSNumber numberWithInt:indexsis[i]]];
}
(*env)->DeleteLocalRef(env, selected);
return [NSArray<NSNumber *> arrayWithArray:nsArraySelected];
}
- (int)accessibleRowAtIndex:(int)index
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
jobject axContext = [self axContextWithEnv:env];
if (axContext == NULL) return 0;
jclass clsInfo = (*env)->GetObjectClass(env, axContext);
DECLARE_METHOD_RETURN(jm_getAccessibleRowAtIndex, clsInfo, "getAccessibleRowAtIndex", "(I)I", -1);
jint rowAtIndex = (*env)->CallIntMethod(env, axContext, jm_getAccessibleRowAtIndex, (jint)index);
CHECK_EXCEPTION();
(*env)->DeleteLocalRef(env, axContext);
return (int)rowAtIndex;
}
- (int)accessibleColumnAtIndex:(int)index
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
jobject axContext = [self axContextWithEnv:env];
if (axContext == NULL) return 0;
jclass clsInfo = (*env)->GetObjectClass(env, axContext);
DECLARE_METHOD_RETURN(jm_getAccessibleColumnAtIndex, clsInfo, "getAccessibleColumnAtIndex", "(I)I", -1);
jint columnAtIndex = (*env)->CallIntMethod(env, axContext, jm_getAccessibleColumnAtIndex, (jint)index);
CHECK_EXCEPTION();
(*env)->DeleteLocalRef(env, axContext);
return (int)columnAtIndex;
}
- (BOOL) isAccessibleChildSelectedFromIndex:(int)index
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
jobject axContext = [self axContextWithEnv:env];
if (axContext == NULL) return NO;
jclass clsInfo = (*env)->GetObjectClass(env, axContext);
DECLARE_METHOD_RETURN(jm_isAccessibleChildSelected, clsInfo, "isAccessibleChildSelected", "(I)Z", NO);
jboolean isAccessibleChildSelected = (*env)->CallIntMethod(env, axContext, jm_isAccessibleChildSelected, (jint)index);
CHECK_EXCEPTION();
(*env)->DeleteLocalRef(env, axContext);
return isAccessibleChildSelected;
}
// NSAccessibilityElement protocol methods
- (NSArray *)accessibilityChildren
{
return [self accessibilityRows];
}
- (NSArray *)accessibilitySelectedChildren
{
return [self accessibilitySelectedRows];
}
- (NSArray *)accessibilityRows
{
int rowCount = [self accessibilityRowCount];
NSMutableArray *children = [NSMutableArray arrayWithCapacity:rowCount];
for (int i = 0; i < rowCount; i++) {
[children addObject:[[TableRowAccessibility alloc] initWithParent:self
withEnv:[ThreadUtilities getJNIEnv]
withAccessible:NULL
withIndex:i
withView:[self view]
withJavaRole:JavaAccessibilityIgnore]];
}
return [NSArray arrayWithArray:children];
}
- (nullable NSArray<id<NSAccessibilityRow>> *)accessibilitySelectedRows
{
NSArray<NSNumber *> *selectedRowIndexses = [self getTableSelectedInfo:sun_lwawt_macosx_CAccessibility_JAVA_AX_ROWS];
NSMutableArray *children = [NSMutableArray arrayWithCapacity:[selectedRowIndexses count]];
for (NSNumber *index in selectedRowIndexses) {
[children addObject:[[TableRowAccessibility alloc] initWithParent:self
withEnv:[ThreadUtilities getJNIEnv]
withAccessible:NULL
withIndex:index.unsignedIntValue
withView:[self view]
withJavaRole:JavaAccessibilityIgnore]];
}
return [NSArray arrayWithArray:children];
}
- (NSString *)accessibilityLabel
{
return [super accessibilityLabel] == NULL ? @"table" : [super accessibilityLabel];
}
- (NSRect)accessibilityFrame
{
return [super accessibilityFrame];
}
- (id)accessibilityParent
{
return [super accessibilityParent];
}
- (nullable NSArray *)accessibilityColumns
{
int colCount = [self accessibilityColumnCount];
NSMutableArray *columns = [NSMutableArray arrayWithCapacity:colCount];
for (int i = 0; i < colCount; i++) {
[columns addObject:[[ColumnAccessibility alloc] initWithParent:self
withEnv:[ThreadUtilities getJNIEnv]
withAccessible:NULL
withIndex:i
withView:self->fView
withJavaRole:JavaAccessibilityIgnore]];
}
return [NSArray arrayWithArray:columns];
}
- (nullable NSArray *)accessibilitySelectedColumns
{
NSArray<NSNumber *> *indexes = [self getTableSelectedInfo:sun_lwawt_macosx_CAccessibility_JAVA_AX_COLS];
NSMutableArray *columns = [NSMutableArray arrayWithCapacity:[indexes count]];
for (NSNumber *i in indexes) {
[columns addObject:[[ColumnAccessibility alloc] initWithParent:self
withEnv:[ThreadUtilities getJNIEnv]
withAccessible:NULL
withIndex:i.unsignedIntValue
withView:self->fView
withJavaRole:JavaAccessibilityIgnore]];
}
return [NSArray arrayWithArray:columns];
}
- (NSInteger)accessibilityRowCount
{
return [[self getTableInfo:sun_lwawt_macosx_CAccessibility_JAVA_AX_ROWS] integerValue];
}
- (NSInteger)accessibilityColumnCount
{
return [[self getTableInfo:sun_lwawt_macosx_CAccessibility_JAVA_AX_COLS] integerValue];
}
- (nullable NSArray *)accessibilitySelectedCells
{
NSArray *children = [super accessibilitySelectedChildren];
NSMutableArray *cells = [NSMutableArray arrayWithCapacity:[children count]];
for (CommonComponentAccessibility *child in children) {
[cells addObject:[[CellAccessibility alloc] initWithParent:self
withEnv:[ThreadUtilities getJNIEnv]
withAccessible:child->fAccessible
withIndex:child->fIndex
withView:fView
withJavaRole:child->fJavaRole]];
}
return [NSArray arrayWithArray:cells];
}
- (id)accessibilityCellForColumn:(NSInteger)column row:(NSInteger)row {
return [[(TableRowAccessibility *)[[self accessibilityRows] objectAtIndex:row] accessibilityChildren] objectAtIndex:column];
}
@end

@ -0,0 +1,31 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "CommonComponentAccessibility.h"
@interface TableRowAccessibility : CommonComponentAccessibility <NSAccessibilityRow>
@property(readonly) NSUInteger rowNumberInTable;
@end

@ -0,0 +1,145 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "TableRowAccessibility.h"
#import "JavaAccessibilityAction.h"
#import "JavaAccessibilityUtilities.h"
#import "TableAccessibility.h"
#import "CellAccessibility.h"
#import "ThreadUtilities.h"
#import "JNIUtilities.h"
#import "sun_lwawt_macosx_CAccessibility.h"
static jclass sjc_CAccessibility = NULL;
static jmethodID jm_getChildrenAndRoles = NULL;
#define GET_CHILDRENANDROLES_METHOD_RETURN(ret) \
GET_CACCESSIBILITY_CLASS_RETURN(ret); \
GET_STATIC_METHOD_RETURN(jm_getChildrenAndRoles, sjc_CAccessibility, "getChildrenAndRoles",\
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;IZ)[Ljava/lang/Object;", ret);
@implementation TableRowAccessibility
// NSAccessibilityElement protocol methods
- (NSAccessibilityRole)accessibilityRole
{
return NSAccessibilityRowRole;
}
- (NSAccessibilitySubrole)accessibilitySubrole
{
return NSAccessibilityTableRowSubrole;
}
- (NSArray *)accessibilityChildren
{
NSArray *children = [super accessibilityChildren];
if (children == nil) {
JNIEnv *env = [ThreadUtilities getJNIEnv];
CommonComponentAccessibility *parent = [self accessibilityParent];
if (parent->fAccessible == NULL) return nil;
GET_CHILDRENANDROLES_METHOD_RETURN(nil);
jobjectArray jchildrenAndRoles = (jobjectArray)(*env)->CallStaticObjectMethod(env, sjc_CAccessibility, jm_getChildrenAndRoles,
parent->fAccessible, parent->fComponent, sun_lwawt_macosx_CAccessibility_JAVA_AX_ALL_CHILDREN, NO);
CHECK_EXCEPTION();
if (jchildrenAndRoles == NULL) return nil;
jsize arrayLen = (*env)->GetArrayLength(env, jchildrenAndRoles);
NSMutableArray *childrenCells = [NSMutableArray arrayWithCapacity:arrayLen/2];
NSUInteger childIndex = fIndex * [(TableAccessibility *)parent accessibilityColumnCount];
NSInteger i = childIndex * 2;
NSInteger n = (fIndex + 1) * [(TableAccessibility *)parent accessibilityColumnCount] * 2;
for(i; i < n; i+=2)
{
jobject /* Accessible */ jchild = (*env)->GetObjectArrayElement(env, jchildrenAndRoles, i);
jobject /* String */ jchildJavaRole = (*env)->GetObjectArrayElement(env, jchildrenAndRoles, i+1);
NSString *childJavaRole = nil;
if (jchildJavaRole != NULL) {
DECLARE_CLASS_RETURN(sjc_AccessibleRole, "javax/accessibility/AccessibleRole", nil);
DECLARE_FIELD_RETURN(sjf_key, sjc_AccessibleRole, "key", "Ljava/lang/String;", nil);
jobject jkey = (*env)->GetObjectField(env, jchildJavaRole, sjf_key);
CHECK_EXCEPTION();
childJavaRole = JavaStringToNSString(env, jkey);
(*env)->DeleteLocalRef(env, jkey);
}
CellAccessibility *child = [[CellAccessibility alloc] initWithParent:self
withEnv:env
withAccessible:jchild
withIndex:childIndex
withView:self->fView
withJavaRole:childJavaRole];
[childrenCells addObject:[[child retain] autorelease]];
(*env)->DeleteLocalRef(env, jchild);
(*env)->DeleteLocalRef(env, jchildJavaRole);
childIndex++;
}
(*env)->DeleteLocalRef(env, jchildrenAndRoles);
return childrenCells;
} else {
return children;
}
}
- (NSInteger)accessibilityIndex
{
return self->fIndex;
}
- (NSString *)accessibilityLabel
{
NSString *accessibilityName = @"";
NSArray *children = [self accessibilityChildren];
for (id cell in children) {
if ([accessibilityName isEqualToString:@""]) {
accessibilityName = [cell accessibilityLabel];
} else {
accessibilityName = [accessibilityName stringByAppendingFormat:@", %@", [cell accessibilityLabel]];
}
}
return accessibilityName;
}
- (id)accessibilityParent
{
return [super accessibilityParent];
}
- (NSRect)accessibilityFrame
{
int height = [[[self accessibilityChildren] objectAtIndex:0] accessibilityFrame].size.height;
int width = 0;
NSPoint point = [[[self accessibilityChildren] objectAtIndex:0] accessibilityFrame].origin;
for (id cell in [self accessibilityChildren]) {
width += [cell accessibilityFrame].size.width;
}
return NSMakeRect(point.x, point.y, width, height);
}
@end

@ -0,0 +1,119 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.awt.*;
import java.security.PublicKey;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.CountDownLatch;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.GridBagLayout;
import javax.swing.JPanel;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.JButton;
public abstract class AccessibleComponentTest {
protected static volatile boolean testResult = true;
protected static volatile CountDownLatch countDownLatch;
protected static String INSTRUCTIONS;
protected static String exceptionString;
protected JFrame mainFrame;
protected static AccessibleComponentTest a11yTest;
public abstract CountDownLatch createCountDownLatch();
public void createUI(JPanel component, String testName) {
mainFrame = new JFrame(testName);
GridBagLayout layout = new GridBagLayout();
JPanel mainControlPanel = new JPanel(layout);
JPanel resultButtonPanel = new JPanel(layout);
GridBagConstraints gbc = new GridBagConstraints();
JTextArea instructionTextArea = new JTextArea();
instructionTextArea.setText(INSTRUCTIONS);
instructionTextArea.setEditable(false);
instructionTextArea.setBackground(Color.white);
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
mainControlPanel.add(instructionTextArea, gbc);
gbc.gridx = 0;
gbc.gridy = 1;
mainControlPanel.add(component);
JButton passButton = new JButton("Pass");
passButton.setActionCommand("Pass");
passButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
mainFrame.dispose();
countDownLatch.countDown();
}
});
JButton failButton = new JButton("Fail");
failButton.setActionCommand("Fail");
failButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
testResult = false;
mainFrame.dispose();
countDownLatch.countDown();
}
});
gbc.gridx = 0;
gbc.gridy = 0;
resultButtonPanel.add(passButton, gbc);
gbc.gridx = 1;
gbc.gridy = 0;
resultButtonPanel.add(failButton, gbc);
gbc.gridx = 0;
gbc.gridy = 2;
mainControlPanel.add(resultButtonPanel, gbc);
mainFrame.add(mainControlPanel);
mainFrame.pack();
mainFrame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
mainFrame.dispose();
countDownLatch.countDown();
}
});
mainFrame.setVisible(true);
}
}

@ -0,0 +1,80 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8264287
* @summary Test implementation of NSAccessibilityComboBox protocol peer
* @author Artem.Semenov@jetbrains.com
* @run main/manual AccessibleJComboboxTest
* @requires (os.family == "windows" | os.family == "mac")
*/
import javax.swing.JComboBox;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import java.awt.FlowLayout;
import java.util.concurrent.CountDownLatch;
public class AccessibleJComboboxTest extends AccessibleComponentTest {
@java.lang.Override
public CountDownLatch createCountDownLatch() {
return new CountDownLatch(1);
}
void createCombobox() {
INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of JCombobox.\n\n"
+ "Turn screen reader on, and Tab to the combobox.\n\n"
+ "If you can hear combobox selected item tab further and press PASS, otherwise press FAIL.";
JPanel frame = new JPanel();
String[] NAMES = {"One", "Two", "Three", "Four", "Five"};
JComboBox<String> combo = new JComboBox<>(NAMES);
JLabel label = new JLabel("This is combobox:");
label.setLabelFor(combo);
frame.setLayout(new FlowLayout());
frame.add(label);
frame.add(combo);
exceptionString = "AccessibleJCombobox test failed!";
super.createUI(frame, "AccessibleJComboboxTest");
}
public static void main(String[] args) throws Exception {
AccessibleJComboboxTest test = new AccessibleJComboboxTest();
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeLater(test::createCombobox);
countDownLatch.await();
if (!testResult) {
throw new RuntimeException(a11yTest.exceptionString);
}
}
}

@ -0,0 +1,330 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8264292
* @summary Test implementation of NSAccessibilityList protocol peer
* @author Artem.Semenov@jetbrains.com
* @run main/manual AccessibleJListTest
* @requires (os.family == "windows" | os.family == "mac")
*/
import javax.swing.JList;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JWindow;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.ListCellRenderer;
import javax.swing.SwingUtilities;
import javax.swing.Popup;
import javax.swing.PopupFactory;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.Rectangle;
import java.awt.Dimension;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class AccessibleJListTest extends AccessibleComponentTest {
private static final String[] NAMES = {"One", "Two", "Three", "Four", "Five"};
static JWindow window;
public static void main(String[] args) throws Exception {
a11yTest = new AccessibleJListTest();
countDownLatch = a11yTest.createCountDownLatch();
SwingUtilities.invokeLater(((AccessibleJListTest) a11yTest)::createSimpleList);
countDownLatch.await();
if (!testResult) {
throw new RuntimeException(a11yTest.exceptionString);
}
countDownLatch = a11yTest.createCountDownLatch();
SwingUtilities.invokeLater(((AccessibleJListTest) a11yTest)::createSimpleListRenderer);
countDownLatch.await();
if (!testResult) {
throw new RuntimeException(a11yTest.exceptionString);
}
countDownLatch = a11yTest.createCountDownLatch();
SwingUtilities.invokeLater(((AccessibleJListTest) a11yTest)::createSimpleListNamed);
countDownLatch.await();
if (!testResult) {
throw new RuntimeException(a11yTest.exceptionString);
}
countDownLatch = a11yTest.createCountDownLatch();
SwingUtilities.invokeLater(((AccessibleJListTest) a11yTest)::createCombobox);
countDownLatch.await();
if (!testResult) {
throw new RuntimeException(a11yTest.exceptionString);
}
countDownLatch = a11yTest.createCountDownLatch();
SwingUtilities.invokeLater(((AccessibleJListTest) a11yTest)::createPushButton);
countDownLatch.await();
if (!testResult) {
throw new RuntimeException(a11yTest.exceptionString);
}
countDownLatch = a11yTest.createCountDownLatch();
SwingUtilities.invokeLater(((AccessibleJListTest) a11yTest)::createPushButtonHeavyWeight);
countDownLatch.await();
if (!testResult) {
throw new RuntimeException(a11yTest.exceptionString);
}
}
@java.lang.Override
public CountDownLatch createCountDownLatch() {
return new CountDownLatch(1);
}
public void createSimpleList() {
INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of JList.\n\n"
+ "Turn screen reader on, and Tab to the list.\n"
+ "Press the up and down arrow buttons to move through the list.\n\n"
+ "If you can hear menu items tab further and press PASS, otherwise press FAIL.\n";
JPanel frame = new JPanel();
JList<String> list = new JList<>(NAMES);
frame.setLayout(new FlowLayout());
frame.add(list);
exceptionString = "Accessible JList simple list test failed!";
super.createUI(frame, "Accessible JList test");
}
public void createSimpleListRenderer() {
INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of JList with renderer.\n\n"
+ "Turn screen reader on, and Tab to the list.\n"
+ "Press the up and down arrow buttons to move through the list.\n\n"
+ "If you can hear menu items tab further and press PASS, otherwise press FAIL.\n";
JPanel frame = new JPanel();
JList<String> list = new JList<>(NAMES);
list.setCellRenderer(new AccessibleJListTestRenderer());
frame.setLayout(new FlowLayout());
frame.add(list);
exceptionString = "Accessible JList with renderer simple list test failed!";
super.createUI(frame, "Accessible JList test");
}
public void createSimpleListNamed() {
INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of named JList.\n\n"
+ "Turn screen reader on, and Tab to the list.\n"
+ "Press the tab button to move to second list.\n\n"
+ "If you can hear second list name: \"second list\" - tab further and press PASS, otherwise press FAIL.\n";
JPanel frame = new JPanel();
JList<String> list = new JList<>(NAMES);
JList<String> secondList = new JList<>(NAMES);
secondList.getAccessibleContext().setAccessibleName("Second list");
frame.setLayout(new FlowLayout());
frame.add(list);
frame.add(secondList);
exceptionString = "Accessible JList simple list named test failed!";
super.createUI(frame, "Accessible JList test");
}
public void createCombobox() {
INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of JList in a combobox.\n\n"
+ "Turn screen reader on, and Tab to the combobox.\n"
+ "Press the up and down arrow buttons to move through the list.\n\n"
+ "If you can hear combobox items tab further and press PASS, otherwise press FAIL.\n";
JPanel frame = new JPanel();
JComboBox<String> combo = new JComboBox<>(NAMES);
frame.setLayout(new FlowLayout());
frame.add(combo);
exceptionString = "Accessible JList combobox test failed!";
super.createUI(frame, "Accessible JList test");
}
public void createPushButton() {
INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of JList in a popup in a simple window.\n\n"
+ "Turn screen reader on, and Tab to the show button and press space.\n"
+ "Press the up and down arrow buttons to move through the list.\n\n"
+ "If you can hear popup menu items tab further and press PASS, otherwise press FAIL.\n";
JPanel frame = new JPanel();
JButton button = new JButton("show");
button.setPreferredSize(new Dimension(100, 35));
button.addActionListener(new ActionListener() {
final Runnable dispose = () -> {
window.dispose();
window = null;
button.setText("show");
};
@Override
public void actionPerformed(ActionEvent e) {
if (window == null) {
Rectangle bounds = frame.getBounds();
window = new JWindow(mainFrame);
JList<String> winList = new JList<>(NAMES);
winList.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
dispose.run();
}
}
});
window.add(winList);
window.setLocation(bounds.x + bounds.width + 20, bounds.y);
window.pack();
window.setVisible(true);
button.setText("hide (ESC)");
} else {
dispose.run();
}
}
});
frame.setLayout(new FlowLayout());
frame.add(button);
exceptionString = "Accessible JList push button with simple window test failed!";
super.createUI(frame, "Accessible JList test");
}
public void createPushButtonHeavyWeight() {
INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of JList in a popup in a heavy weight window.\n\n"
+ "Turn screen reader on, and Tab to the show button and press space.\n"
+ "Press the up and down arrow buttons to move through the list.\n\n"
+ "If you can hear popup menu items tab further and press PASS, otherwise press FAIL.\n";
JPanel frame = new JPanel();
JButton button = new JButton("show");
button.setPreferredSize(new Dimension(100, 35));
button.addActionListener(new ActionListener() {
private Popup popup = null;
final Runnable dispose = () -> {
popup.hide();
popup = null;
button.requestFocus();
button.setText("show");
};
@Override
public void actionPerformed(ActionEvent e) {
if (popup == null) {
Rectangle bounds = frame.getBounds();
PopupFactory factory = PopupFactory.getSharedInstance();
JList<String> winList = new JList<>(NAMES);
winList.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
dispose.run();
}
}
});
popup = factory.getPopup(frame, winList, bounds.x + bounds.width + 20, bounds.y);
Window c = SwingUtilities.getWindowAncestor(winList);
if (c != null) {
c.setAutoRequestFocus(true);
c.setFocusableWindowState(true);
}
popup.show();
button.setText("hide (ESC)");
} else {
dispose.run();
}
}
});
frame.setLayout(new FlowLayout());
frame.add(button);
exceptionString = "Accessible JList push button with heavy weight window test failed!";
super.createUI(frame, "Accessible JList test");
}
public static class AccessibleJListTestRenderer extends JPanel implements ListCellRenderer {
private JLabel labelAJT = new JLabel("AJL");
private JLabel itemName = new JLabel();
AccessibleJListTestRenderer() {
super(new FlowLayout());
setFocusable(false);
layoutComponents();
}
private void layoutComponents() {
add(labelAJT);
add(itemName);
}
@Override
public Dimension getPreferredSize() {
Dimension size = super.getPreferredSize();
return new Dimension(Math.min(size.width, 245), size.height);
}
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
itemName.setText(((String) value));
getAccessibleContext().setAccessibleName(labelAJT.getText() + ", " + itemName.getText());
return this;
}
}
}

@ -0,0 +1,93 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8264303
* @summary Test implementation of NSAccessibilityTabPanel protocol peer
* @author Artem.Semenov@jetbrains.com
* @run main/manual AccessibleJTabbedPaneTest
* @requires (os.family == "windows" | os.family == "mac")
*/
import javax.swing.JTabbedPane;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JTextField;
import javax.swing.JCheckBox;
import javax.swing.SwingUtilities;
import java.util.concurrent.CountDownLatch;
public class AccessibleJTabbedPaneTest extends AccessibleComponentTest {
@Override
public CountDownLatch createCountDownLatch() {
return new CountDownLatch(1);
}
void createTabPane() {
INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of JTabbedPane.\n\n"
+ "Turn screen reader on, and tab to the JTabbedPane.\n"
+ "Use page up and page down arrow buttons to move through the tabs.\n\n"
+ "If you can hear selected tab names tab further and press PASS, otherwise press FAIL.\n";
JTabbedPane tabbedPane = new JTabbedPane();
JPanel panel1 = new JPanel();
String[] names = {"One", "Two", "Three", "Four", "Five"};
JList list = new JList(names);
JLabel fieldName = new JLabel("Text field:");
JTextField textField = new JTextField("some text");
fieldName.setLabelFor(textField);
panel1.add(fieldName);
panel1.add(textField);
panel1.add(list);
tabbedPane.addTab("Tab 1", panel1);
JPanel panel2 = new JPanel();
for (int i = 0; i < 5; i++) {
panel2.add(new JCheckBox("CheckBox " + String.valueOf(i + 1)));
}
tabbedPane.addTab("tab 2", panel2);
JPanel panel = new JPanel();
panel.add(tabbedPane);
exceptionString = "AccessibleJTabbedPane test failed!";
createUI(panel, "AccessibleJTabbedPaneTest");
}
public static void main(String[] args) throws Exception {
AccessibleJTabbedPaneTest test = new AccessibleJTabbedPaneTest();
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeLater(test::createTabPane);
countDownLatch.await();
if (!testResult) {
throw new RuntimeException(a11yTest.exceptionString);
}
}
}

@ -0,0 +1,114 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8267388
* @summary Test implementation of NSAccessibilityTable protocol peer
* @author Artem.Semenov@jetbrains.com
* @run main/manual AccessibleJTableTest
* @requires (os.family == "windows" | os.family == "mac")
*/
import javax.swing.JTable;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import java.awt.FlowLayout;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class AccessibleJTableTest extends AccessibleComponentTest {
private static final String[] columnNames = {"One", "Two", "Three"};
private static final String[][] data = {
{"One1", "Two1", "Three1"},
{"One2", "Two2", "Three2"},
{"One3", "Two3", "Three3"},
{"One4", "Two4", "Three4"},
{"One5", "Two5", "Three5"}
};
@Override
public CountDownLatch createCountDownLatch() {
return new CountDownLatch(1);
}
public void createUI() {
INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of JTable.\n\n"
+ "Turn screen reader on, and Tab to the table.\n"
+ "On Windows press the arrow buttons to move through the table.\n\n"
+ "On MacOS, use the up and down arrow buttons to move through rows, and VoiceOver fast navigation to move through columns.\n\n"
+ "If you can hear table cells ctrl+tab further and press PASS, otherwise press FAIL.\n";
JTable table = new JTable(data, columnNames);
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
JScrollPane scrollPane = new JScrollPane(table);
panel.add(scrollPane);
panel.setFocusable(false);
exceptionString = "AccessibleJTable test failed!";
super.createUI(panel, "AccessibleJTableTest");
}
public void createUINamed() {
INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of named JTable.\n\n"
+ "Turn screen reader on, and Tab to the table.\n"
+ "Press the ctrl+tab button to move to second table.\n\n"
+ "If you can hear second table name: \"second table\" - ctrl+tab further and press PASS, otherwise press FAIL.\n";
JTable table = new JTable(data, columnNames);
JTable secondTable = new JTable(data, columnNames);
secondTable.getAccessibleContext().setAccessibleName("Second table");
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
JScrollPane scrollPane = new JScrollPane(table);
JScrollPane secondScrollPane = new JScrollPane(secondTable);
panel.add(scrollPane);
panel.add(secondScrollPane);
panel.setFocusable(false);
exceptionString = "AccessibleJTable test failed!";
super.createUI(panel, "AccessibleJTableTest");
}
public static void main(String[] args) throws Exception {
AccessibleJTableTest test = new AccessibleJTableTest();
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeAndWait(test::createUI);
countDownLatch.await(15, TimeUnit.MINUTES);
if (!testResult) {
throw new RuntimeException(exceptionString);
}
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeAndWait(test::createUINamed);
countDownLatch.await(15, TimeUnit.MINUTES);
if (!testResult) {
throw new RuntimeException(exceptionString);
}
}
}

@ -0,0 +1,239 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8267387
* @summary Test implementation of NSAccessibilityOutLine protocol peer
* @author Artem.Semenov@jetbrains.com
* @run main/manual AccessibleJTreeTest
* @requires (os.family == "windows" | os.family == "mac")
*/
import javax.swing.JTree;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.SwingUtilities;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.util.Hashtable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class AccessibleJTreeTest extends AccessibleComponentTest {
@Override
public CountDownLatch createCountDownLatch() {
return new CountDownLatch(1);
}
public void createSampleTree() {
INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of JTree.\n\n"
+ "Turn screen reader on, and Tab to the tree.\n"
+ "Press the arrow buttons to move through the tree.\n\n"
+ "If you can hear tree components tab further and press PASS, otherwise press FAIL.\n";
String root = "Root";
String[] nodes = new String[] {"One node", "Two node"};
String[][] leafs = new String[][]{{"leaf 1.1", "leaf 1.2", "leaf 1.3", "leaf 1.4"},
{"leaf 2.1", "leaf 2.2", "leaf 2.3", "leaf 2.4"}};
Hashtable<String, String[]> data = new Hashtable<String, String[]>();
for (int i = 0; i < nodes.length; i++) {
data.put(nodes[i], leafs[i]);
}
JTree tree = new JTree(data);
tree.setRootVisible(true);
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
JScrollPane scrollPane = new JScrollPane(tree);
panel.add(scrollPane);
panel.setFocusable(false);
exceptionString = "AccessibleJTree sample item test failed!";
super.createUI(panel, "AccessibleJTreeTest");
}
public void createSampleTreeUnvisableRoot() {
INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of JTree with invisible root.\n\n"
+ "Turn screen reader on, and Tab to the tree.\n"
+ "Press the arrow buttons to move through the tree.\n\n"
+ "If you can hear tree components tab further and press PASS, otherwise press FAIL.\n";
String root = "Root";
String[] nodes = new String[] {"One node", "Two node"};
String[][] leafs = new String[][]{{"leaf 1.1", "leaf 1.2", "leaf 1.3", "leaf 1.4"},
{"leaf 2.1", "leaf 2.2", "leaf 2.3", "leaf 2.4"}};
Hashtable<String, String[]> data = new Hashtable<String, String[]>();
for (int i = 0; i < nodes.length; i++) {
data.put(nodes[i], leafs[i]);
}
JTree tree = new JTree(data);
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
JScrollPane scrollPane = new JScrollPane(tree);
panel.add(scrollPane);
panel.setFocusable(false);
exceptionString = "AccessibleJTree sample item invisible root test failed!";
super.createUI(panel, "AccessibleJTreeTest");
}
public void createSampleTreeNamed() {
INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of named JTree.\n\n"
+ "Turn screen reader on, and Tab to the tree.\n"
+ "Press the tab button to move to second tree.\\n\n"
+ "If you can hear second tree name: \"second tree\" - tab further and press PASS, otherwise press FAIL.\n";
String root = "Root";
String[] nodes = new String[] {"One node", "Two node"};
String[][] leafs = new String[][]{{"leaf 1.1", "leaf 1.2", "leaf 1.3", "leaf 1.4"},
{"leaf 2.1", "leaf 2.2", "leaf 2.3", "leaf 2.4"}};
Hashtable<String, String[]> data = new Hashtable<String, String[]>();
for (int i = 0; i < nodes.length; i++) {
data.put(nodes[i], leafs[i]);
}
JTree tree = new JTree(data);
JTree secondTree = new JTree(data);
secondTree.getAccessibleContext().setAccessibleName("Second tree");
tree.setRootVisible(true);
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
JScrollPane scrollPane = new JScrollPane(tree);
JScrollPane secondScrollPane = new JScrollPane(secondTree);
panel.add(scrollPane);
panel.add(secondScrollPane);
panel.setFocusable(false);
exceptionString = "AccessibleJTree named test failed!";
super.createUI(panel, "AccessibleJTreeTest");
}
public void createRendererTree() {
INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of JTree using renderer.\n\n"
+ "Turn screen reader on, and Tab to the tree.\n"
+ "Press the arrow buttons to move through the tree.\n\n"
+ "If you can hear tree components tab further and press PASS, otherwise press FAIL.\n";
String root = "Root";
String[] nodes = new String[] {"One node", "Two node"};
String[][] leafs = new String[][]{{"leaf 1.1", "leaf 1.2", "leaf 1.3", "leaf 1.4"},
{"leaf 2.1", "leaf 2.2", "leaf 2.3", "leaf 2.4"}};
Hashtable<String, String[]> data = new Hashtable<String, String[]>();
for (int i = 0; i < nodes.length; i++) {
data.put(nodes[i], leafs[i]);
}
JTree tree = new JTree(data);
tree.setRootVisible(true);
tree.setCellRenderer(new AccessibleJTreeTestRenderer());
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
JScrollPane scrollPane = new JScrollPane(tree);
panel.add(scrollPane);
panel.setFocusable(false);
exceptionString = "AccessibleJTree renderer item test failed!";
super.createUI(panel, "AccessibleJTreeTest");
}
public static void main(String[] args) throws Exception {
AccessibleJTreeTest test = new AccessibleJTreeTest();
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeAndWait(test::createSampleTree);
AccessibleComponentTest.countDownLatch.await(15, TimeUnit.MINUTES);
if (!testResult) {
throw new RuntimeException(exceptionString);
}
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeAndWait(test::createSampleTreeNamed);
AccessibleComponentTest.countDownLatch.await(15, TimeUnit.MINUTES);
if (!testResult) {
throw new RuntimeException(exceptionString);
}
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeAndWait(test::createSampleTreeUnvisableRoot);
AccessibleComponentTest.countDownLatch.await(15, TimeUnit.MINUTES);
if (!testResult) {
throw new RuntimeException(exceptionString);
}
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeAndWait(test::createRendererTree);
countDownLatch.await(15, TimeUnit.MINUTES);
if (!testResult) {
throw new RuntimeException(AccessibleComponentTest.exceptionString);
}
}
public static class AccessibleJTreeTestRenderer extends JPanel implements TreeCellRenderer {
private JLabel labelAJT = new JLabel("AJT");
private JLabel itemName = new JLabel();
AccessibleJTreeTestRenderer() {
super(new FlowLayout());
setFocusable(false);
layoutComponents();
}
private void layoutComponents() {
add(labelAJT);
add(itemName);
}
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
itemName.setText((String) (((DefaultMutableTreeNode) value).getUserObject()));
getAccessibleContext().setAccessibleName(labelAJT.getText() + ", " + itemName.getText());
return this;
}
@Override
public Dimension getPreferredSize() {
Dimension size = super.getPreferredSize();
return new Dimension(Math.min(size.width, 245), size.height);
}
}
}

@ -0,0 +1,293 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8262031
* @summary Test implementation of NSAccessibilityNavigableStaticTest and NSAccessibilityStaticText protocols peer
* @author Artem.Semenov@jetbrains.com
* @run main/manual AccessibleTextTest
* @requires (os.family == "windows" | os.family == "mac")
*/
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import java.awt.FlowLayout;
import java.awt.event.KeyEvent;
import java.awt.event.KeyAdapter;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class AccessibleTextTest extends AccessibleComponentTest {
@Override
public CountDownLatch createCountDownLatch() {
return new CountDownLatch(1);
}
private void createSimpleLabel() {
AccessibleComponentTest.INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of JLabel.\n\n"
+ "Turn screen reader on.\n"
+ "On MacOS, use the VO navigation keys to read the label text;\n"
+ "ON Windows with JAWS, use window virtualization (insert+alt+w and arrows) to read the label text;\n"
+ "ON Windows with NVDA, use the browse cursor (insert+num4 or insert+num6) to read the label text;\n\n"
+ "If you can hear text from label tab further and press PASS, otherwise press FAIL.";
JLabel label = new JLabel("this is a label");
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
panel.add(label);
exceptionString = "Simple label test failed!";
super.createUI(panel, "AccessibleTextTest");
}
private void createOneLineTexField() {
AccessibleComponentTest.INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of JTextField.\n\n"
+ "Turn screen reader on and press Tab to move to the text field and type some characters.\n\n"
+ "If you can hear input results according to your screen reader settings, tab further and press PASS, otherwise press FAIL.";
JTextField textField = new JTextField("some text to edit");
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
panel.add(textField);
exceptionString = "Simple text field test failed!";
super.createUI(panel, "AccessibleTextTest");
}
private void createPassField() {
AccessibleComponentTest.INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of JPasswordField.\n\n"
+ "Turn screen reader on and press Tab to move to the password field and type some characters.\n\n"
+ "If you can hear sounds specific to your screen reader when interacting with password fields, tab further and press PASS, otherwise press FAIL.";
JPasswordField passwordField = new JPasswordField("12345678");
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
panel.add(passwordField);
exceptionString = "Simple passfield field test failed!";
super.createUI(panel, "AccessibleTextTest");
}
private void createNamedTextField() {
AccessibleComponentTest.INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of named JTextField.\n\n"
+ "Turn screen reader on and press Tab to move to the text field.\n\n"
+ "If you can hear in addition to the fact that this text field is also the names of these fields, tab further and press PASS, otherwise press FAIL.";
JTextField textField = new JTextField("some text 1");
textField.getAccessibleContext().setAccessibleName("This is the first text field:");
JLabel label = new JLabel("This is the second text field:");
JTextField secondTextField = new JTextField("some text 2");
label.setLabelFor(secondTextField);
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
panel.add(textField);
panel.add(label);
panel.add(secondTextField);
exceptionString = "Named text field test failed!";
super.createUI(panel, "AccessibleTextTest");
}
private void createTextArea() {
AccessibleComponentTest.INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of JTextArea.\n\n"
+ "Turn screen reader on and press the arrow keys.\n\n"
+ "If you can hear this instructions, tab further and press PASS, otherwise press FAIL.";
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
exceptionString = "Simple text area test failed!";
super.createUI(panel, "AccessibleTextTest");
}
private void createEditableTextArea() {
AccessibleComponentTest.INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of editable JTextArea.\n\n"
+ "Turn screen reader on and press Tab to move to the text area and type some characters.\n\n"
+ "If you can hear input results according to your screen reader settings, tab further and press PASS, otherwise press FAIL.";
JTextArea textArea = new JTextArea("some text to edit");
JLabel label = new JLabel(textArea.getText().length() + " chars");
label.setLabelFor(textArea);
textArea.setEditable(true);
textArea.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e) {
label.setText(String.valueOf(textArea.getText().length()) + " chars");
}
});
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
panel.add(textArea);
panel.add(label);
exceptionString = "Editable text area test failed!";
super.createUI(panel, "AccessibleTextTest");
}
private void createTextPane() {
AccessibleComponentTest.INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of text in JTextPane.\n\n"
+ "Turn screen reader on and press Tab to move to the text pane and press the arrow keys.\n\n"
+ "If you can hear text, tab further and press PASS, otherwise press FAIL.";
String str = "Line 1\nLine 2\nLine 3";
JTextPane textPane = new JTextPane();
textPane.setEditable(false);
textPane.setText(str);
JTextArea textArea = new JTextArea();
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
panel.add(textPane);
exceptionString = "Simple text pane test failed!";
super.createUI(panel, "AccessibleTextTest");
}
private void createHTMLTextPane() {
AccessibleComponentTest.INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of html text in JTextPane.\n\n"
+ "Turn screen reader on and press Tab to move to the text pane and press the arrow keys.\n\n"
+ "If you can hear text, tab further and press PASS, otherwise press FAIL.";
String str = "<html><h1>Header</h1><ul><li>Item 1</li><li>Item 2</li><li>Item 3</li></ul></html>";
JTextPane textPane = new JTextPane();
textPane.setEditable(false);
textPane.setContentType("text/html");
textPane.setText(str);
JTextArea textArea = new JTextArea();
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
panel.add(textPane);
exceptionString = "HTML text pane test failed!";
super.createUI(panel, "AccessibleTextTest");
}
private void createEditableTextPane() {
AccessibleComponentTest.INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of editable JTextPane.\n\n"
+ "Turn screen reader on and press Tab to move to the text pane and type some characters.\n\n"
+ "If you can hear input results according to your screen reader settings, tab further and press PASS, otherwise press FAIL.";
JTextPane textPane = new JTextPane();
textPane.setText("some text to edit");
JLabel label = new JLabel(textPane.getText().length() + " chars");
label.setLabelFor(textPane);
textPane.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e) {
label.setText(String.valueOf(textPane.getText().length()) + " chars");
}
});
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
panel.add(textPane);
panel.add(label);
exceptionString = "Editable text pane test failed!";
super.createUI(panel, "AccessibleTextTest");
}
public static void main(String[] args) throws Exception {
AccessibleTextTest test = new AccessibleTextTest();
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeAndWait(test::createSimpleLabel);
AccessibleComponentTest.countDownLatch.await(15, TimeUnit.MINUTES);
if (!testResult) {
throw new RuntimeException(exceptionString);
}
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeAndWait(test::createOneLineTexField);
AccessibleComponentTest.countDownLatch.await(15, TimeUnit.MINUTES);
if (!testResult) {
throw new RuntimeException(exceptionString);
}
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeAndWait(test::createPassField);
AccessibleComponentTest.countDownLatch.await(15, TimeUnit.MINUTES);
if (!testResult) {
throw new RuntimeException(exceptionString);
}
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeAndWait(test::createNamedTextField);
AccessibleComponentTest.countDownLatch.await(15, TimeUnit.MINUTES);
if (!testResult) {
throw new RuntimeException(exceptionString);
}
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeAndWait(test::createTextArea);
AccessibleComponentTest.countDownLatch.await(15, TimeUnit.MINUTES);
if (!testResult) {
throw new RuntimeException(exceptionString);
}
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeAndWait(test::createEditableTextArea);
AccessibleComponentTest.countDownLatch.await(15, TimeUnit.MINUTES);
if (!testResult) {
throw new RuntimeException(exceptionString);
}
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeAndWait(test::createTextPane);
AccessibleComponentTest.countDownLatch.await(15, TimeUnit.MINUTES);
if (!testResult) {
throw new RuntimeException(exceptionString);
}
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeAndWait(test::createHTMLTextPane);
AccessibleComponentTest.countDownLatch.await(15, TimeUnit.MINUTES);
if (!testResult) {
throw new RuntimeException(exceptionString);
}
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeAndWait(test::createEditableTextPane);
AccessibleComponentTest.countDownLatch.await(15, TimeUnit.MINUTES);
if (!testResult) {
throw new RuntimeException(exceptionString);
}
}
}