提交 b5248c0c 编写于 作者: M mcherkas

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
上级 7e79ca83
/*
* Copyright (c) 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());
}
}
}
}
}
......@@ -293,7 +293,7 @@ class CAccessibility implements PropertyChangeListener {
}
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 {
......@@ -476,6 +476,24 @@ class CAccessibility implements PropertyChangeListener {
}, 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;
......@@ -580,9 +598,57 @@ class CAccessibility implements PropertyChangeListener {
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();
}
......
......@@ -37,7 +37,11 @@ import javax.swing.JSlider;
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 @@ class CAccessible extends CFRetainedResource implements Accessible {
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 @@ class CAccessible extends CFRetainedResource implements Accessible {
}
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 @@ class CAccessible extends CFRetainedResource implements Accessible {
}
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) {
selectionChanged(ptr);
} else if (name.compareTo(AccessibleContext.ACCESSIBLE_TEXT_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(ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY) == 0 ) {
Object nv = e.getNewValue();
if (nv instanceof AccessibleContext) {
activeDescendant = (AccessibleContext)nv;
}
}
}
}
......@@ -137,4 +151,9 @@ class CAccessible extends CFRetainedResource implements Accessible {
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;
}
}
......@@ -64,16 +64,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
......
/*
* 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 containsAxState(JNIEnv *env, jobject axContext, jobject axState, jobject co
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);
......
......@@ -151,6 +151,18 @@ BOOL isShowing(JNIEnv *env, jobject axContext, jobject component)
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;");
......
/*
* 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
......@@ -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;
......
......@@ -201,12 +201,18 @@ static NSObject *sAttributeNamesLOCK = nil;
NSAccessibilityPostNotification(self, NSAccessibilityValueChangedNotification);
}
- (void)postSelectionChanged
- (void)postSelectedTextChanged
{
AWT_ASSERT_APPKIT_THREAD;
NSAccessibilityPostNotification(self, NSAccessibilitySelectedTextChangedNotification);
}
- (void)postSelectionChanged
{
AWT_ASSERT_APPKIT_THREAD;
NSAccessibilityPostNotification(self, NSAccessibilitySelectedChildrenChangedNotification);
}
- (BOOL)isEqual:(id)anObject
{
if (![anObject isKindOfClass:[self class]]) return NO;
......@@ -225,7 +231,7 @@ static NSObject *sAttributeNamesLOCK = nil;
{
if (sAttributeNamesForRoleCache == nil) {
sAttributeNamesLOCK = [[NSObject alloc] init];
sAttributeNamesForRoleCache = [[NSMutableDictionary alloc] initWithCapacity:10];
sAttributeNamesForRoleCache = [[NSMutableDictionary alloc] initWithCapacity:60];
}
if (sRoles == nil) {
......@@ -281,6 +287,7 @@ static NSObject *sAttributeNamesLOCK = nil;
+ (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;
......@@ -374,7 +381,7 @@ static NSObject *sAttributeNamesLOCK = nil;
{
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
......@@ -453,6 +460,12 @@ static NSObject *sAttributeNamesLOCK = nil;
// 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:
......@@ -571,6 +584,14 @@ static NSObject *sAttributeNamesLOCK = nil;
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) {
......@@ -590,18 +611,32 @@ static NSObject *sAttributeNamesLOCK = nil;
@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]);
......@@ -660,7 +695,10 @@ static NSObject *sAttributeNamesLOCK = nil;
- (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) {
......@@ -684,7 +722,12 @@ static NSObject *sAttributeNamesLOCK = nil;
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.
......@@ -758,7 +801,7 @@ static NSObject *sAttributeNamesLOCK = nil;
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);
......@@ -770,6 +813,18 @@ static NSObject *sAttributeNamesLOCK = nil;
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
{
......@@ -943,6 +998,33 @@ static NSObject *sAttributeNamesLOCK = nil;
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];
......@@ -1009,7 +1091,7 @@ static NSObject *sAttributeNamesLOCK = nil;
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);
......@@ -1214,14 +1296,11 @@ static NSObject *sAttributeNamesLOCK = nil;
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
......@@ -1235,6 +1314,22 @@ JNF_COCOA_ENTER(env);
JNF_COCOA_EXIT(env);
}
/*
* 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
......@@ -1248,7 +1343,6 @@ JNF_COCOA_ENTER(env);
JNF_COCOA_EXIT(env);
}
/*
* Class: sun_lwawt_macosx_CAccessible
* Method: unregisterFromCocoaAXSystem
......
/*
* 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
......@@ -427,13 +427,15 @@ NSValue *javaIntArrayToNSRangeValue(JNIEnv* env, jintArray array) {
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
......@@ -3052,7 +3052,7 @@ public class JList<E> extends JComponent implements Scrollable, Accessible
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;
}
......@@ -3079,7 +3079,7 @@ public class JList<E> extends JComponent implements Scrollable, Accessible
if (i >= getModel().getSize()) {
return null;
} else {
return new AccessibleJListChild(JList.this, i);
return new ActionableAccessibleJListChild(JList.this, i);
}
}
......@@ -3184,7 +3184,7 @@ public class JList<E> extends JComponent implements Scrollable, Accessible
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;
......@@ -3204,7 +3204,7 @@ public class JList<E> extends JComponent implements Scrollable, Accessible
return getComponentAtIndex(indexInParent);
}
private AccessibleContext getCurrentAccessibleContext() {
AccessibleContext getCurrentAccessibleContext() {
Component c = getComponentAtIndex(indexInParent);
if (c instanceof Accessible) {
return c.getAccessibleContext();
......@@ -3370,10 +3370,6 @@ public class JList<E> extends JComponent implements Scrollable, Accessible
}
}
public AccessibleAction getAccessibleAction() {
return getCurrentAccessibleContext().getAccessibleAction();
}
/**
* Get the AccessibleComponent associated with this object. In the
* implementation of the Java Accessibility API for this class,
......@@ -3591,7 +3587,13 @@ public class JList<E> extends JComponent implements Scrollable, Accessible
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);
......@@ -3731,6 +3733,57 @@ public class JList<E> extends JComponent implements Scrollable, Accessible
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
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册