8145207: [macosx] JList, VO can't access non-visible list items
Summary: add support for single/multi select following focus and following VO cursor
Reviewed-by: alexsch, ant
--- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/AccessibilityEventMonitor.java Mon Jul 18 12:52:44 2016 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,253 +0,0 @@
-/*
- * Copyright (c) 2002, 2016, Oracle and/or its affiliates. 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. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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.
- */
-
-package sun.lwawt.macosx;
-
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import javax.accessibility.Accessible;
-import javax.accessibility.AccessibleContext;
-import javax.accessibility.AccessibleRole;
-import javax.accessibility.AccessibleState;
-import javax.accessibility.AccessibleStateSet;
-import javax.swing.event.EventListenerList;
-
-/**
- * <P>{@code AccessibilityEventMonitor} implements a PropertyChange listener
- * on every UI object that implements interface {@code Accessible} in the Java
- * Virtual Machine. The events captured by these listeners are made available
- * through listeners supported by {@code AccessibilityEventMonitor}.
- * With this, all the individual events on each of the UI object
- * instances are funneled into one set of PropertyChange listeners.
- *
- * This code is a subset of com.sun.java.accessibility.util.AccessibilityEventMonitor
- * which resides in module jdk.accessibility. Due to modularization the code in
- * this package, java.desktop, can not be dependent on code in jdk.accessibility.
- */
-
-class AccessibilityEventMonitor {
-
- /**
- * The current list of registered {@link java.beans.PropertyChangeListener
- * PropertyChangeListener} classes.
- *
- * @see #addPropertyChangeListener
- */
- private static final EventListenerList listenerList =
- new EventListenerList();
-
-
- /**
- * The actual listener that is installed on the component instances.
- * This listener calls the other registered listeners when an event
- * occurs. By doing things this way, the actual number of listeners
- * installed on a component instance is drastically reduced.
- */
- private static final AccessibilityEventListener accessibilityListener =
- new AccessibilityEventListener();
-
- /**
- * Adds the specified listener to receive all PropertyChange events on
- * each UI object instance in the Java Virtual Machine as they occur.
- * <P>Note: This listener is automatically added to all component
- * instances created after this method is called. In addition, it
- * is only added to UI object instances that support this listener type.
- *
- * @param l the listener to add
- * @param a the Accessible object to add the PropertyChangeListener to
- */
-
- static void addPropertyChangeListener(PropertyChangeListener l, Accessible a) {
- if (listenerList.getListenerCount(PropertyChangeListener.class) == 0) {
- accessibilityListener.installListeners(a);
- }
- listenerList.add(PropertyChangeListener.class, l);
- }
-
- /**
- * AccessibilityEventListener is the class that does all the work for
- * AccessibilityEventMonitor. It is not intended for use by any other
- * class except AccessibilityEventMonitor.
- */
-
- private static class AccessibilityEventListener implements PropertyChangeListener {
-
- /**
- * Installs PropertyChange listeners to the Accessible object, and its
- * children (so long as the object isn't of TRANSIENT state).
- *
- * @param a the Accessible object to add listeners to
- */
- private void installListeners(Accessible a) {
- installListeners(a.getAccessibleContext());
- }
-
- /**
- * Installs PropertyChange listeners to the AccessibleContext object,
- * and its * children (so long as the object isn't of TRANSIENT state).
- *
- * @param ac the AccessibleContext to add listeners to
- */
- private void installListeners(AccessibleContext ac) {
-
- if (ac != null) {
- AccessibleStateSet states = ac.getAccessibleStateSet();
- if (!states.contains(AccessibleState.TRANSIENT)) {
- ac.addPropertyChangeListener(this);
- /*
- * Don't add listeners to transient children. Components
- * with transient children should return an AccessibleStateSet
- * containing AccessibleState.MANAGES_DESCENDANTS. Components
- * may not explicitly return the MANAGES_DESCENDANTS state.
- * In this case, don't add listeners to the children of
- * lists, tables and trees.
- */
- AccessibleStateSet set = ac.getAccessibleStateSet();
- if (set.contains(AccessibleState.MANAGES_DESCENDANTS)) {
- return;
- }
- AccessibleRole role = ac.getAccessibleRole();
- if ( role == AccessibleRole.LIST ||
- role == AccessibleRole.TREE ) {
- return;
- }
- if (role == AccessibleRole.TABLE) {
- // handle Oracle tables containing tables
- Accessible child = ac.getAccessibleChild(0);
- if (child != null) {
- AccessibleContext ac2 = child.getAccessibleContext();
- if (ac2 != null) {
- role = ac2.getAccessibleRole();
- if (role != null && role != AccessibleRole.TABLE) {
- return;
- }
- }
- }
- }
- int count = ac.getAccessibleChildrenCount();
- for (int i = 0; i < count; i++) {
- Accessible child = ac.getAccessibleChild(i);
- if (child != null) {
- installListeners(child);
- }
- }
- }
- }
- }
-
- /**
- * Removes PropertyChange listeners for the given Accessible object,
- * its children (so long as the object isn't of TRANSIENT state).
- *
- * @param a the Accessible object to remove listeners from
- */
- private void removeListeners(Accessible a) {
- removeListeners(a.getAccessibleContext());
- }
-
- /**
- * Removes PropertyChange listeners for the given AccessibleContext
- * object, its children (so long as the object isn't of TRANSIENT
- * state).
- *
- * @param a the Accessible object to remove listeners from
- */
- private void removeListeners(AccessibleContext ac) {
-
- if (ac != null) {
- // Listeners are not added to transient components.
- AccessibleStateSet states = ac.getAccessibleStateSet();
- if (!states.contains(AccessibleState.TRANSIENT)) {
- ac.removePropertyChangeListener(this);
- /*
- * Listeners are not added to transient children. Components
- * with transient children should return an AccessibleStateSet
- * containing AccessibleState.MANAGES_DESCENDANTS. Components
- * may not explicitly return the MANAGES_DESCENDANTS state.
- * In this case, don't remove listeners from the children of
- * lists, tables and trees.
- */
- if (states.contains(AccessibleState.MANAGES_DESCENDANTS)) {
- return;
- }
- AccessibleRole role = ac.getAccessibleRole();
- if ( role == AccessibleRole.LIST ||
- role == AccessibleRole.TABLE ||
- role == AccessibleRole.TREE ) {
- return;
- }
- int count = ac.getAccessibleChildrenCount();
- for (int i = 0; i < count; i++) {
- Accessible child = ac.getAccessibleChild(i);
- if (child != null) {
- removeListeners(child);
- }
- }
- }
- }
- }
-
- @Override
- public void propertyChange(PropertyChangeEvent e) {
- // propogate the event
- Object[] listeners =
- AccessibilityEventMonitor.listenerList.getListenerList();
- for (int i = listeners.length-2; i>=0; i-=2) {
- if (listeners[i]==PropertyChangeListener.class) {
- ((PropertyChangeListener)listeners[i+1]).propertyChange(e);
- }
- }
-
- // handle childbirth/death
- String name = e.getPropertyName();
- if (name.compareTo(AccessibleContext.ACCESSIBLE_CHILD_PROPERTY) == 0) {
- Object oldValue = e.getOldValue();
- Object newValue = e.getNewValue();
-
- if ((oldValue == null) ^ (newValue == null)) { // one null, not both
- if (oldValue != null) {
- // this Accessible is a child that's going away
- if (oldValue instanceof Accessible) {
- Accessible a = (Accessible) oldValue;
- removeListeners(a.getAccessibleContext());
- } else if (oldValue instanceof AccessibleContext) {
- removeListeners((AccessibleContext) oldValue);
- }
- } else if (newValue != null) {
- // this Accessible is a child was just born
- if (newValue instanceof Accessible) {
- Accessible a = (Accessible) newValue;
- installListeners(a.getAccessibleContext());
- } else if (newValue instanceof AccessibleContext) {
- installListeners((AccessibleContext) newValue);
- }
- }
- } else {
- System.out.println("ERROR in usage of PropertyChangeEvents for: " + e.toString());
- }
- }
- }
- }
-}
--- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java Mon Jul 18 12:52:44 2016 -0700
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java Mon Jul 18 15:43:30 2016 -0500
@@ -285,7 +285,7 @@
}
public static int getAccessibleIndexInParent(final Accessible a, final Component c) {
- if (a == null) return 0;
+ if (a == null) return -1;
return invokeAndWait(new Callable<Integer>() {
public Integer call() throws Exception {
@@ -468,6 +468,24 @@
}, c);
}
+ public static void requestSelection(final Accessible a, final Component c) {
+ if (a == null) return;
+ invokeLater(new Runnable() {
+ public void run() {
+ AccessibleContext ac = a.getAccessibleContext();
+ if (ac == null) return;
+ int i = ac.getAccessibleIndexInParent();
+ if (i == -1) return;
+ Accessible parent = ac.getAccessibleParent();
+ AccessibleContext pac = parent.getAccessibleContext();
+ if (pac == null) return;
+ AccessibleSelection as = pac.getAccessibleSelection();
+ if (as == null) return;
+ as.addAccessibleSelection(i);
+ }
+ }, c);
+ }
+
public static Number getMaximumAccessibleValue(final Accessible a, final Component c) {
if (a == null) return null;
@@ -572,9 +590,57 @@
if (a == null) return null;
return invokeAndWait(new Callable<Object[]>() {
public Object[] call() throws Exception {
- final ArrayList<Object> childrenAndRoles = new ArrayList<Object>();
+ 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.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();
}
--- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java Mon Jul 18 12:52:44 2016 -0700
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java Mon Jul 18 15:43:30 2016 -0500
@@ -37,7 +37,11 @@
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
-import sun.lwawt.macosx.CFRetainedResource;
+import static javax.accessibility.AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY;
+import static javax.accessibility.AccessibleContext.ACCESSIBLE_CARET_PROPERTY;
+import static javax.accessibility.AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY;
+import static javax.accessibility.AccessibleContext.ACCESSIBLE_TEXT_PROPERTY;
+
class CAccessible extends CFRetainedResource implements Accessible {
static Field getNativeAXResourceField() {
@@ -71,10 +75,13 @@
private static native void unregisterFromCocoaAXSystem(long ptr);
private static native void valueChanged(long ptr);
+ private static native void selectedTextChanged(long ptr);
private static native void selectionChanged(long ptr);
private Accessible accessible;
+ private AccessibleContext activeDescendant;
+
private CAccessible(final Accessible accessible) {
super(0L, true); // real pointer will be poked in by native
@@ -98,9 +105,9 @@
}
public void addNotificationListeners(Component c) {
- AXTextChangeNotifier listener = new AXTextChangeNotifier();
if (c instanceof Accessible) {
- AccessibilityEventMonitor.addPropertyChangeListener(listener, (Accessible)c);
+ AccessibleContext ac = ((Accessible)c).getAccessibleContext();
+ ac.addPropertyChangeListener(new AXChangeNotifier());
}
if (c instanceof JProgressBar) {
JProgressBar pb = (JProgressBar) c;
@@ -112,16 +119,23 @@
}
- private class AXTextChangeNotifier implements PropertyChangeListener {
+ private class AXChangeNotifier implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent e) {
String name = e.getPropertyName();
if ( ptr != 0 ) {
- if (name.compareTo(AccessibleContext.ACCESSIBLE_CARET_PROPERTY) == 0) {
+ if (name.compareTo(ACCESSIBLE_CARET_PROPERTY) == 0) {
+ selectedTextChanged(ptr);
+ } else if (name.compareTo(ACCESSIBLE_TEXT_PROPERTY) == 0 ) {
+ valueChanged(ptr);
+ } else if (name.compareTo(ACCESSIBLE_SELECTION_PROPERTY) == 0 ) {
selectionChanged(ptr);
- } else if (name.compareTo(AccessibleContext.ACCESSIBLE_TEXT_PROPERTY) == 0 ) {
- valueChanged(ptr);
+ } else if (name.compareTo(ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY) == 0 ) {
+ Object nv = e.getNewValue();
+ if (nv instanceof AccessibleContext) {
+ activeDescendant = (AccessibleContext)nv;
+ }
}
}
}
@@ -137,4 +151,9 @@
static Accessible getSwingAccessible(final Accessible a) {
return (a instanceof CAccessible) ? ((CAccessible)a).accessible : a;
}
+
+ static AccessibleContext getActiveDescendant(final Accessible a) {
+ return (a instanceof CAccessible) ? ((CAccessible)a).activeDescendant : null;
+ }
+
}
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaAccessibilityAction.m Mon Jul 18 12:52:44 2016 -0700
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaAccessibilityAction.m Mon Jul 18 15:43:30 2016 -0500
@@ -63,16 +63,20 @@
jobject fCompLocal = (*env)->NewLocalRef(env, fComponent);
if ((*env)->IsSameObject(env, fCompLocal, NULL)) {
- return @"unknown";
+ return nil;
}
NSString *str = nil;
- jobject jstr = JNFCallStaticObjectMethod(env, jm_getAccessibleActionDescription, fAccessibleAction, fIndex, fCompLocal);
+ jstring jstr = JNFCallStaticObjectMethod( env,
+ jm_getAccessibleActionDescription,
+ fAccessibleAction,
+ fIndex,
+ fCompLocal );
if (jstr != NULL) {
- NSString *str = JNFJavaToNSString(env, jstr); // AWT_THREADING Safe (AWTRunLoopMode)
+ str = JNFJavaToNSString(env, jstr); // AWT_THREADING Safe (AWTRunLoopMode)
(*env)->DeleteLocalRef(env, jstr);
}
(*env)->DeleteLocalRef(env, fCompLocal);
- return str == nil ? @"unknown" : str;
+ return str;
}
- (void)perform
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaAccessibilityUtilities.h Mon Jul 18 12:52:44 2016 -0700
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaAccessibilityUtilities.h Mon Jul 18 15:43:30 2016 -0500
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. 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
@@ -55,6 +55,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);
NSPoint getAxComponentLocationOnScreen(JNIEnv *env, jobject axComponent, jobject component);
jint getAxTextCharCount(JNIEnv *env, jobject axText, jobject component);
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaAccessibilityUtilities.m Mon Jul 18 12:52:44 2016 -0700
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaAccessibilityUtilities.m Mon Jul 18 15:43:30 2016 -0500
@@ -151,6 +151,18 @@
return showing;
}
+BOOL isSelectable(JNIEnv *env, jobject axContext, jobject component)
+{
+ static JNF_STATIC_MEMBER_CACHE( jm_SELECTABLE,
+ sjc_AccessibleState,
+ "SELECTABLE",
+ "Ljavax/accessibility/AccessibleState;" );
+ jobject axSelectableState = JNFGetStaticObjectField(env, jm_SELECTABLE);
+ BOOL selectable = containsAxState(env, axContext, axSelectableState, component);
+ (*env)->DeleteLocalRef(env, axSelectableState);
+ return selectable;
+}
+
NSPoint getAxComponentLocationOnScreen(JNIEnv *env, jobject axComponent, jobject component)
{
static JNF_STATIC_MEMBER_CACHE(jm_getLocationOnScreen, sjc_CAccessibility, "getLocationOnScreen", "(Ljavax/accessibility/AccessibleComponent;Ljava/awt/Component;)Ljava/awt/Point;");
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaComponentAccessibility.h Mon Jul 18 12:52:44 2016 -0700
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaComponentAccessibility.h Mon Jul 18 15:43:30 2016 -0500
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. 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
@@ -50,6 +50,7 @@
- (id)initWithParent:(NSObject*)parent withEnv:(JNIEnv *)env withAccessible:(jobject)accessible withIndex:(jint)index withView:(NSView *)view withJavaRole:(NSString *)javaRole;
- (void)unregisterFromCocoaAXSystem;
- (void)postValueChanged;
+- (void)postSelectedTextChanged;
- (void)postSelectionChanged;
- (BOOL)isEqual:(id)anObject;
- (BOOL)isAccessibleWithEnv:(JNIEnv *)env forAccessible:(jobject)accessible;
@@ -71,6 +72,7 @@
- (NSString *)javaRole;
- (BOOL)isMenu;
- (BOOL)isSelected:(JNIEnv *)env;
+- (BOOL)isSelectable:(JNIEnv *)env;
- (BOOL)isVisible:(JNIEnv *)env;
// attribute names
@@ -85,6 +87,8 @@
- (NSArray *)accessibilityChildrenAttribute;
- (BOOL)accessibilityIsChildrenAttributeSettable;
- (NSUInteger)accessibilityIndexOfChild:(id)child;
+- (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute
+ index:(NSUInteger)index maxCount:(NSUInteger)maxCount;
- (NSNumber *)accessibilityEnabledAttribute;
- (BOOL)accessibilityIsEnabledAttributeSettable;
- (NSNumber *)accessibilityFocusedAttribute;
@@ -92,6 +96,8 @@
- (void)accessibilitySetFocusedAttribute:(id)value;
- (NSString *)accessibilityHelpAttribute;
- (BOOL)accessibilityIsHelpAttributeSettable;
+- (NSValue *)accessibilityIndexAttribute;
+- (BOOL)accessibilityIsIndexAttributeSettable;
- (id)accessibilityMaxValueAttribute;
- (BOOL)accessibilityIsMaxValueAttributeSettable;
- (id)accessibilityMinValueAttribute;
@@ -108,6 +114,9 @@
- (BOOL)accessibilityIsRoleDescriptionAttributeSettable;
- (NSArray *)accessibilitySelectedChildrenAttribute;
- (BOOL)accessibilityIsSelectedChildrenAttributeSettable;
+- (NSNumber *)accessibilitySelectedAttribute;
+- (BOOL)accessibilityIsSelectedAttributeSettable;
+- (void)accessibilitySetSelectedAttribute:(id)value;
- (NSValue *)accessibilitySizeAttribute;
- (BOOL)accessibilityIsSizeAttributeSettable;
- (NSString *)accessibilitySubroleAttribute;
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaComponentAccessibility.m Mon Jul 18 12:52:44 2016 -0700
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaComponentAccessibility.m Mon Jul 18 15:43:30 2016 -0500
@@ -201,10 +201,16 @@
NSAccessibilityPostNotification(self, NSAccessibilityValueChangedNotification);
}
+- (void)postSelectedTextChanged
+{
+ AWT_ASSERT_APPKIT_THREAD;
+ NSAccessibilityPostNotification(self, NSAccessibilitySelectedTextChangedNotification);
+}
+
- (void)postSelectionChanged
{
AWT_ASSERT_APPKIT_THREAD;
- NSAccessibilityPostNotification(self, NSAccessibilitySelectedTextChangedNotification);
+ NSAccessibilityPostNotification(self, NSAccessibilitySelectedChildrenChangedNotification);
}
- (BOOL)isEqual:(id)anObject
@@ -225,7 +231,7 @@
{
if (sAttributeNamesForRoleCache == nil) {
sAttributeNamesLOCK = [[NSObject alloc] init];
- sAttributeNamesForRoleCache = [[NSMutableDictionary alloc] initWithCapacity:10];
+ sAttributeNamesForRoleCache = [[NSMutableDictionary alloc] initWithCapacity:60];
}
if (sRoles == nil) {
@@ -281,6 +287,7 @@
+ (NSArray *)childrenOfParent:(JavaComponentAccessibility *)parent withEnv:(JNIEnv *)env withChildrenCode:(NSInteger)whichChildren allowIgnored:(BOOL)allowIgnored
{
+ if (parent->fAccessible == NULL) return nil;
jobjectArray jchildrenAndRoles = (jobjectArray)JNFCallStaticObjectMethod(env, jm_getChildrenAndRoles, parent->fAccessible, parent->fComponent, whichChildren, allowIgnored); // AWT_THREADING Safe (AWTRunLoop)
if (jchildrenAndRoles == NULL) return nil;
@@ -370,7 +377,7 @@
{
static JNF_STATIC_MEMBER_CACHE(jm_getInitialAttributeStates, sjc_CAccessibility, "getInitialAttributeStates", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)[Z");
- NSMutableArray *attributeNames = [NSMutableArray arrayWithCapacity:10];
+ NSMutableArray *attributeNames = [NSMutableArray arrayWithCapacity:20];
[attributeNames retain];
// all elements respond to parent, role, role description, window, topLevelUIElement, help
@@ -449,6 +456,12 @@
// children
if (attributeStatesArray[6]) {
[attributeNames addObject:NSAccessibilityChildrenAttribute];
+ if ([javaRole isEqualToString:@"list"]) {
+ [attributeNames addObject:NSAccessibilitySelectedChildrenAttribute];
+ [attributeNames addObject:NSAccessibilityVisibleChildrenAttribute];
+ }
+ // Just above, the below mentioned support has been added back in for lists.
+ // However, the following comments may still be useful for future fixes.
// [attributeNames addObject:NSAccessibilitySelectedChildrenAttribute];
// [attributeNames addObject:NSAccessibilityVisibleChildrenAttribute];
//According to AXRoles.txt:
@@ -567,6 +580,14 @@
return isChildSelected(env, ((JavaComponentAccessibility *)[self parent])->fAccessible, fIndex, fComponent);
}
+- (BOOL)isSelectable:(JNIEnv *)env
+{
+ jobject axContext = [self axContextWithEnv:env];
+ BOOL selectable = isSelectable(env, axContext, fComponent);
+ (*env)->DeleteLocalRef(env, axContext);
+ return selectable;
+}
+
- (BOOL)isVisible:(JNIEnv *)env
{
if (fIndex == -1) {
@@ -586,18 +607,32 @@
@synchronized(sAttributeNamesLOCK) {
NSString *javaRole = [self javaRole];
- NSArray *names = (NSArray *)[sAttributeNamesForRoleCache objectForKey:javaRole];
- if (names != nil) return names;
-
- names = [self initializeAttributeNamesWithEnv:env];
- if (names != nil) {
+ NSArray *names =
+ (NSArray *)[sAttributeNamesForRoleCache objectForKey:javaRole];
+ if (names == nil) {
+ names = [self initializeAttributeNamesWithEnv:env];
#ifdef JAVA_AX_DEBUG
NSLog(@"Initializing: %s for %@: %@", __FUNCTION__, javaRole, names);
#endif
[sAttributeNamesForRoleCache setObject:names forKey:javaRole];
- return names;
}
- }
+ // The above set of attributes is immutable per role, but some objects, if
+ // they are the child of a list, need to add the selected and index attributes.
+ id myParent = [self accessibilityParentAttribute];
+ if ([myParent isKindOfClass:[JavaComponentAccessibility class]]) {
+ NSString *parentRole = [(JavaComponentAccessibility *)myParent javaRole];
+ if ([parentRole isEqualToString:@"list"]) {
+ NSMutableArray *moreNames =
+ [[NSMutableArray alloc] initWithCapacity: [names count] + 2];
+ [moreNames addObjectsFromArray: names];
+ [moreNames addObject:NSAccessibilitySelectedAttribute];
+ [moreNames addObject:NSAccessibilityIndexAttribute];
+ return moreNames;
+ }
+ }
+ return names;
+
+ } // end @synchronized
#ifdef JAVA_AX_DEBUG
NSLog(@"Warning in %s: could not find attribute names for role: %@", __FUNCTION__, [self javaRole]);
@@ -656,7 +691,10 @@
- (NSArray *)accessibilityChildrenAttribute
{
JNIEnv* env = [ThreadUtilities getJNIEnv];
- NSArray *children = [JavaComponentAccessibility childrenOfParent:self withEnv:env withChildrenCode:JAVA_AX_VISIBLE_CHILDREN allowIgnored:NO];
+ NSArray *children = [JavaComponentAccessibility childrenOfParent:self
+ withEnv:env
+ withChildrenCode:JAVA_AX_ALL_CHILDREN
+ allowIgnored:NO];
NSArray *value = nil;
if ([children count] > 0) {
@@ -680,7 +718,12 @@
return [super accessibilityIndexOfChild:child];
}
- return JNFCallStaticIntMethod([ThreadUtilities getJNIEnv], sjm_getAccessibleIndexInParent, ((JavaComponentAccessibility *)child)->fAccessible, ((JavaComponentAccessibility *)child)->fComponent);
+ jint returnValue =
+ JNFCallStaticIntMethod( [ThreadUtilities getJNIEnv],
+ sjm_getAccessibleIndexInParent,
+ ((JavaComponentAccessibility *)child)->fAccessible,
+ ((JavaComponentAccessibility *)child)->fComponent );
+ return (returnValue == -1) ? NSNotFound : returnValue;
}
// Without this optimization accessibilityChildrenAttribute is called in order to get the entire array of children.
@@ -754,7 +797,7 @@
jobject val = JNFCallStaticObjectMethod(env, sjm_getAccessibleDescription, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
if (val == NULL) {
- return @"unknown";
+ return nil;
}
NSString* str = JNFJavaToNSString(env, val);
(*env)->DeleteLocalRef(env, val);
@@ -766,6 +809,18 @@
return NO;
}
+- (NSValue *)accessibilityIndexAttribute
+{
+ NSInteger index = fIndex;
+ NSValue *returnValue = [NSValue value:&index withObjCType:@encode(NSInteger)];
+ return returnValue;
+}
+
+- (BOOL)accessibilityIsIndexAttributeSettable
+{
+ return NO;
+}
+
// Element's maximum value (id)
- (id)accessibilityMaxValueAttribute
{
@@ -939,6 +994,33 @@
return NO; // cmcnote: actually it should be. so need to write accessibilitySetSelectedChildrenAttribute also
}
+- (NSNumber *)accessibilitySelectedAttribute
+{
+ return [NSNumber numberWithBool:[self isSelected:[ThreadUtilities getJNIEnv]]];
+}
+
+- (BOOL)accessibilityIsSelectedAttributeSettable
+{
+ if ([self isSelectable:[ThreadUtilities getJNIEnv]]) {
+ return YES;
+ } else {
+ return NO;
+ }
+}
+
+- (void)accessibilitySetSelectedAttribute:(id)value
+{
+ static JNF_STATIC_MEMBER_CACHE( jm_requestSelection,
+ sjc_CAccessibility,
+ "requestSelection",
+ "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)V" );
+
+ if ([(NSNumber*)value boolValue]) {
+ JNIEnv* env = [ThreadUtilities getJNIEnv];
+ JNFCallStaticVoidMethod(env, jm_requestSelection, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
+ }
+}
+
// Element size (NSValue)
- (NSValue *)accessibilitySizeAttribute {
JNIEnv* env = [ThreadUtilities getJNIEnv];
@@ -1005,7 +1087,7 @@
jobject val = JNFCallStaticObjectMethod(env, sjm_getAccessibleName, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
if (val == NULL) {
- return @"unknown";
+ return nil;
}
NSString* str = JNFJavaToNSString(env, val);
(*env)->DeleteLocalRef(env, val);
@@ -1210,14 +1292,11 @@
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessibility_focusChanged
(JNIEnv *env, jobject jthis)
{
-
JNF_COCOA_ENTER(env);
[ThreadUtilities performOnMainThread:@selector(postFocusChanged:) on:[JavaComponentAccessibility class] withObject:nil waitUntilDone:NO];
JNF_COCOA_EXIT(env);
}
-
-
/*
* Class: sun_lwawt_macosx_CAccessible
* Method: valueChanged
@@ -1233,6 +1312,22 @@
/*
* Class: sun_lwawt_macosx_CAccessible
+ * Method: selectedTextChanged
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_selectedTextChanged
+(JNIEnv *env, jclass jklass, jlong element)
+{
+JNF_COCOA_ENTER(env);
+ [ThreadUtilities performOnMainThread:@selector(postSelectedTextChanged)
+ on:(JavaComponentAccessibility *)jlong_to_ptr(element)
+ withObject:nil
+ waitUntilDone:NO];
+JNF_COCOA_EXIT(env);
+}
+
+/*
+ * Class: sun_lwawt_macosx_CAccessible
* Method: selectionChanged
* Signature: (I)V
*/
@@ -1244,7 +1339,6 @@
JNF_COCOA_EXIT(env);
}
-
/*
* Class: sun_lwawt_macosx_CAccessible
* Method: unregisterFromCocoaAXSystem
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaTextAccessibility.h Mon Jul 18 12:52:44 2016 -0700
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaTextAccessibility.h Mon Jul 18 15:43:30 2016 -0500
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. 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
@@ -60,6 +60,4 @@
- (NSValue *)accessibilityRangeForPositionAttributeForParameter:(id)parameter;
- (NSValue *)accessibilityRangeForIndexAttributeForParameter:(id)parameter;
-// actions
-- (NSDictionary *)getActions:(JNIEnv *)env;
@end
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaTextAccessibility.m Mon Jul 18 12:52:44 2016 -0700
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaTextAccessibility.m Mon Jul 18 15:43:30 2016 -0500
@@ -427,13 +427,15 @@
return javaIntArrayToNSRangeValue(env, axTextRange);
}
-- (NSDictionary *)getActions:(JNIEnv *)env {
- // cmcnote: this isn't correct; text can have actions. Not yet implemented. radr://3941691
- // Editable text has AXShowMenu. Textfields have AXConfirm. Static text has no actions.
-#ifdef JAVA_AX_DEBUG
- NSLog(@"Not yet implemented: %s\n", __FUNCTION__);
-#endif
- return nil;
-}
+/*
+ * - (NSDictionary *)getActions:(JNIEnv *)env { ... }
+ *
+ * In the future, possibly add support: Editable text has AXShowMenu.
+ * Textfields have AXConfirm.
+ *
+ * Note: JLabels (static text) in JLists have a press/click selection action
+ * which is currently handled in superclass JavaComponentAccessibility.
+ * If function is added here be sure to use [super getActions:env] for JLabels.
+ */
@end
--- a/jdk/src/java.desktop/share/classes/javax/swing/JList.java Mon Jul 18 12:52:44 2016 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/JList.java Mon Jul 18 15:43:30 2016 -0500
@@ -3058,7 +3058,7 @@
public Accessible getAccessibleAt(Point p) {
int i = locationToIndex(p);
if (i >= 0) {
- return new AccessibleJListChild(JList.this, i);
+ return new ActionableAccessibleJListChild(JList.this, i);
} else {
return null;
}
@@ -3085,7 +3085,7 @@
if (i >= getModel().getSize()) {
return null;
} else {
- return new AccessibleJListChild(JList.this, i);
+ return new ActionableAccessibleJListChild(JList.this, i);
}
}
@@ -3190,7 +3190,7 @@
protected class AccessibleJListChild extends AccessibleContext
implements Accessible, AccessibleComponent {
private JList<E> parent = null;
- private int indexInParent;
+ int indexInParent;
private Component component = null;
private AccessibleContext accessibleContext = null;
private ListModel<E> listModel;
@@ -3215,7 +3215,7 @@
return getComponentAtIndex(indexInParent);
}
- private AccessibleContext getCurrentAccessibleContext() {
+ AccessibleContext getCurrentAccessibleContext() {
Component c = getComponentAtIndex(indexInParent);
if (c instanceof Accessible) {
return c.getAccessibleContext();
@@ -3381,10 +3381,6 @@
}
}
- public AccessibleAction getAccessibleAction() {
- return getCurrentAccessibleContext().getAccessibleAction();
- }
-
/**
* Get the AccessibleComponent associated with this object. In the
* implementation of the Java Accessibility API for this class,
@@ -3599,7 +3595,13 @@
public Point getLocationOnScreen() {
if (parent != null) {
- Point listLocation = parent.getLocationOnScreen();
+ Point listLocation;
+ try {
+ listLocation = parent.getLocationOnScreen();
+ } catch (IllegalComponentStateException e) {
+ // This can happen if the component isn't visisble
+ return null;
+ }
Point componentLocation = parent.indexToLocation(indexInParent);
if (componentLocation != null) {
componentLocation.translate(listLocation.x, listLocation.y);
@@ -3740,6 +3742,57 @@
return null;
}
}
+
} // inner class AccessibleJListChild
+
+ private class ActionableAccessibleJListChild
+ extends AccessibleJListChild
+ implements AccessibleAction {
+
+ ActionableAccessibleJListChild(JList<E> parent, int indexInParent) {
+ super(parent, indexInParent);
+ }
+
+ @Override
+ public AccessibleAction getAccessibleAction() {
+ AccessibleContext ac = getCurrentAccessibleContext();
+ if (ac == null) {
+ return null;
+ } else {
+ AccessibleAction aa = ac.getAccessibleAction();
+ if (aa != null) {
+ return aa;
+ } else {
+ return this;
+ }
+ }
+ }
+
+ @Override
+ public boolean doAccessibleAction(int i) {
+ if (i == 0) {
+ JList.this.setSelectedIndex(indexInParent);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public String getAccessibleActionDescription(int i) {
+ if (i == 0) {
+ return UIManager.getString("AbstractButton.clickText");
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public int getAccessibleActionCount() {
+ return 1;
+ }
+
+ } // inner class ActionableAccessibleJListChild
+
} // inner class AccessibleJList
}