8160893: [macosx] JMenuItems in JPopupMenu are not accessible
Post events for MenuOpened/Closed/ItemSelected Reviewed-by: ant, alexsch
This commit is contained in:
parent
6e147fc49f
commit
27ca3765bb
@ -29,11 +29,9 @@ import sun.lwawt.LWWindowPeer;
|
||||
|
||||
import java.awt.*;
|
||||
import java.beans.*;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Callable;
|
||||
import sun.awt.AWTAccessor;
|
||||
|
||||
import javax.accessibility.*;
|
||||
import javax.swing.*;
|
||||
@ -73,8 +71,20 @@ class CAccessibility implements PropertyChangeListener {
|
||||
}
|
||||
|
||||
public void propertyChange(final PropertyChangeEvent evt) {
|
||||
if (evt.getNewValue() == null) return;
|
||||
focusChanged();
|
||||
Object newValue = evt.getNewValue();
|
||||
if (newValue == null) return;
|
||||
// Don't post focus on things that don't matter, i.e. alert, colorchooser,
|
||||
// desktoppane, dialog, directorypane, filechooser, filler, fontchoose,
|
||||
// frame, glasspane, layeredpane, optionpane, panel, rootpane, separator,
|
||||
// tooltip, viewport, window.
|
||||
// List taken from initializeRoles() in JavaComponentUtilities.m.
|
||||
if (newValue instanceof Accessible) {
|
||||
AccessibleContext nvAC = ((Accessible) newValue).getAccessibleContext();
|
||||
AccessibleRole nvRole = nvAC.getAccessibleRole();
|
||||
if (!ignoredRoles.contains(roleKey(nvRole))) {
|
||||
focusChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private native void focusChanged();
|
||||
@ -683,9 +693,15 @@ class CAccessibility implements PropertyChangeListener {
|
||||
if (context == null) continue;
|
||||
|
||||
if (whichChildren == JAVA_AX_VISIBLE_CHILDREN) {
|
||||
if (!context.getAccessibleComponent().isVisible()) continue;
|
||||
AccessibleComponent acomp = context.getAccessibleComponent();
|
||||
if (acomp == null || !acomp.isVisible()) {
|
||||
continue;
|
||||
}
|
||||
} else if (whichChildren == JAVA_AX_SELECTED_CHILDREN) {
|
||||
if (!ac.getAccessibleSelection().isAccessibleChildSelected(i)) continue;
|
||||
AccessibleSelection sel = ac.getAccessibleSelection();
|
||||
if (sel == null || !sel.isAccessibleChildSelected(i)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!allowIgnored) {
|
||||
|
@ -39,7 +39,10 @@ import javax.swing.event.ChangeListener;
|
||||
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_STATE_PROPERTY;
|
||||
import static javax.accessibility.AccessibleContext.ACCESSIBLE_TEXT_PROPERTY;
|
||||
import javax.accessibility.AccessibleRole;
|
||||
import javax.accessibility.AccessibleState;
|
||||
import sun.awt.AWTAccessor;
|
||||
|
||||
|
||||
@ -63,6 +66,9 @@ class CAccessible extends CFRetainedResource implements Accessible {
|
||||
private static native void valueChanged(long ptr);
|
||||
private static native void selectedTextChanged(long ptr);
|
||||
private static native void selectionChanged(long ptr);
|
||||
private static native void menuOpened(long ptr);
|
||||
private static native void menuClosed(long ptr);
|
||||
private static native void menuItemSelected(long ptr);
|
||||
|
||||
private Accessible accessible;
|
||||
|
||||
@ -111,16 +117,45 @@ class CAccessible extends CFRetainedResource implements Accessible {
|
||||
public void propertyChange(PropertyChangeEvent e) {
|
||||
String name = e.getPropertyName();
|
||||
if ( ptr != 0 ) {
|
||||
Object newValue = e.getNewValue();
|
||||
Object oldValue = e.getOldValue();
|
||||
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;
|
||||
} else if (name.compareTo(ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY) == 0 ) {
|
||||
if (newValue instanceof AccessibleContext) {
|
||||
activeDescendant = (AccessibleContext)newValue;
|
||||
}
|
||||
} else if (name.compareTo(ACCESSIBLE_STATE_PROPERTY) == 0) {
|
||||
AccessibleContext thisAC = accessible.getAccessibleContext();
|
||||
AccessibleRole thisRole = thisAC.getAccessibleRole();
|
||||
Accessible parentAccessible = thisAC.getAccessibleParent();
|
||||
AccessibleRole parentRole = null;
|
||||
if (parentAccessible != null) {
|
||||
parentRole = parentAccessible.getAccessibleContext().getAccessibleRole();
|
||||
}
|
||||
// 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
|
||||
// for JPopupMenus, not for combobox menus.
|
||||
if (parentRole != AccessibleRole.COMBO_BOX) {
|
||||
if (thisRole == AccessibleRole.POPUP_MENU) {
|
||||
if ( newValue != null &&
|
||||
((AccessibleState)newValue) == AccessibleState.VISIBLE ) {
|
||||
menuOpened(ptr);
|
||||
} else if ( oldValue != null &&
|
||||
((AccessibleState)oldValue) == AccessibleState.VISIBLE ) {
|
||||
menuClosed(ptr);
|
||||
}
|
||||
} else if (thisRole == AccessibleRole.MENU_ITEM) {
|
||||
if ( newValue != null &&
|
||||
((AccessibleState)newValue) == AccessibleState.FOCUSED ) {
|
||||
menuItemSelected(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -66,7 +66,6 @@ static JNF_CLASS_CACHE(sjc_CAccessible, "sun/lwawt/macosx/CAccessible");
|
||||
static JNF_MEMBER_CACHE(jf_ptr, sjc_CAccessible, "ptr", "J");
|
||||
static JNF_STATIC_MEMBER_CACHE(sjm_getCAccessible, sjc_CAccessible, "getCAccessible", "(Ljavax/accessibility/Accessible;)Lsun/lwawt/macosx/CAccessible;");
|
||||
|
||||
|
||||
static jobject sAccessibilityClass = NULL;
|
||||
|
||||
// sAttributeNamesForRoleCache holds the names of the attributes to which each java
|
||||
@ -213,6 +212,24 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
NSAccessibilityPostNotification(self, NSAccessibilitySelectedChildrenChangedNotification);
|
||||
}
|
||||
|
||||
- (void)postMenuOpened
|
||||
{
|
||||
AWT_ASSERT_APPKIT_THREAD;
|
||||
NSAccessibilityPostNotification(self, (NSString *)kAXMenuOpenedNotification);
|
||||
}
|
||||
|
||||
- (void)postMenuClosed
|
||||
{
|
||||
AWT_ASSERT_APPKIT_THREAD;
|
||||
NSAccessibilityPostNotification(self, (NSString *)kAXMenuClosedNotification);
|
||||
}
|
||||
|
||||
- (void)postMenuItemSelected
|
||||
{
|
||||
AWT_ASSERT_APPKIT_THREAD;
|
||||
NSAccessibilityPostNotification(self, (NSString *)kAXMenuItemSelectedNotification);
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)anObject
|
||||
{
|
||||
if (![anObject isKindOfClass:[self class]]) return NO;
|
||||
@ -278,8 +295,7 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
+ (jobject) getCAccessible:(jobject)jaccessible withEnv:(JNIEnv *)env {
|
||||
if (JNFIsInstanceOf(env, jaccessible, &sjc_CAccessible)) {
|
||||
return jaccessible;
|
||||
}
|
||||
else if (JNFIsInstanceOf(env, jaccessible, &sjc_Accessible)) {
|
||||
} else if (JNFIsInstanceOf(env, jaccessible, &sjc_Accessible)) {
|
||||
return JNFCallStaticObjectMethod(env, sjm_getCAccessible, jaccessible);
|
||||
}
|
||||
return NULL;
|
||||
@ -368,6 +384,14 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
// must init freshly -alloc'd object
|
||||
[newChild initWithParent:parent withEnv:env withAccessible:jCAX withIndex:index withView:view withJavaRole:javaRole]; // must init new instance
|
||||
|
||||
// If creating a JPopupMenu (not a combobox popup list) need to fire menuOpened.
|
||||
// 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"] ) {
|
||||
[newChild postMenuOpened];
|
||||
}
|
||||
|
||||
// must hard retain pointer poked into Java object
|
||||
[newChild retain];
|
||||
JNFSetLongField(env, jCAX, jf_ptr, ptr_to_jlong(newChild));
|
||||
@ -634,6 +658,15 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
return moreNames;
|
||||
}
|
||||
}
|
||||
// popupmenu's return values not selected children
|
||||
if ( [javaRole isEqualToString:@"popupmenu"] &&
|
||||
![[[self parent] javaRole] isEqualToString:@"combobox"] ) {
|
||||
NSMutableArray *moreNames =
|
||||
[[NSMutableArray alloc] initWithCapacity: [names count] + 1];
|
||||
[moreNames addObjectsFromArray: names];
|
||||
[moreNames addObject:NSAccessibilityValueAttribute];
|
||||
return moreNames;
|
||||
}
|
||||
return names;
|
||||
|
||||
} // end @synchronized
|
||||
@ -707,6 +740,7 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
- (BOOL)accessibilityIsChildrenAttributeSettable
|
||||
{
|
||||
return NO;
|
||||
@ -939,6 +973,13 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
if (fNSRole == nil) {
|
||||
NSString *javaRole = [self javaRole];
|
||||
fNSRole = [sRoles objectForKey:javaRole];
|
||||
// The sRoles NSMutableDictionary maps popupmenu to Mac's popup button.
|
||||
// JComboBox behavior currently relies on this. However this is not the
|
||||
// proper mapping for a JPopupMenu so fix that.
|
||||
if ( [javaRole isEqualToString:@"popupmenu"] &&
|
||||
![[[self parent] javaRole] isEqualToString:@"combobox"] ) {
|
||||
fNSRole = NSAccessibilityMenuRole;
|
||||
}
|
||||
if (fNSRole == nil) {
|
||||
// this component has assigned itself a custom AccessibleRole not in the sRoles array
|
||||
fNSRole = javaRole;
|
||||
@ -947,6 +988,7 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
}
|
||||
return fNSRole;
|
||||
}
|
||||
|
||||
- (BOOL)accessibilityIsRoleAttributeSettable
|
||||
{
|
||||
return NO;
|
||||
@ -1046,8 +1088,7 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
- (NSString *)accessibilitySubroleAttribute
|
||||
{
|
||||
NSString *value = nil;
|
||||
if ([[self javaRole] isEqualToString:@"passwordtext"])
|
||||
{
|
||||
if ([[self javaRole] isEqualToString:@"passwordtext"]) {
|
||||
value = NSAccessibilitySecureTextFieldSubrole;
|
||||
}
|
||||
/*
|
||||
@ -1123,6 +1164,45 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
|
||||
JNIEnv* env = [ThreadUtilities getJNIEnv];
|
||||
|
||||
// Need to handle popupmenus differently.
|
||||
//
|
||||
// At least for now don't handle combo box menus.
|
||||
// This may change when later fixing issues which currently
|
||||
// exist for combo boxes, but for now the following is only
|
||||
// for JPopupMenus, not for combobox menus.
|
||||
id parent = [self parent];
|
||||
if ( [[self javaRole] isEqualToString:@"popupmenu"] &&
|
||||
![[parent javaRole] isEqualToString:@"combobox"] ) {
|
||||
NSArray *children =
|
||||
[JavaComponentAccessibility childrenOfParent:self
|
||||
withEnv:env
|
||||
withChildrenCode:JAVA_AX_ALL_CHILDREN
|
||||
allowIgnored:YES];
|
||||
if ([children count] > 0) {
|
||||
// handle case of AXMenuItem
|
||||
// need to ask menu what is selected
|
||||
NSArray *selectedChildrenOfMenu =
|
||||
[self accessibilitySelectedChildrenAttribute];
|
||||
JavaComponentAccessibility *selectedMenuItem =
|
||||
[selectedChildrenOfMenu objectAtIndex:0];
|
||||
if (selectedMenuItem != nil) {
|
||||
jobject itemValue =
|
||||
JNFCallStaticObjectMethod( env,
|
||||
sjm_getAccessibleName,
|
||||
selectedMenuItem->fAccessible,
|
||||
selectedMenuItem->fComponent ); // AWT_THREADING Safe (AWTRunLoop)
|
||||
if (itemValue == NULL) {
|
||||
return nil;
|
||||
}
|
||||
NSString* itemString = JNFJavaToNSString(env, itemValue);
|
||||
(*env)->DeleteLocalRef(env, itemValue);
|
||||
return itemString;
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ask Java for the component's accessibleValue. In java, the "accessibleValue" just means a numerical value
|
||||
// a text value is taken care of in JavaTextAccessibility
|
||||
|
||||
@ -1343,6 +1423,54 @@ JNF_COCOA_ENTER(env);
|
||||
JNF_COCOA_EXIT(env);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_lwawt_macosx_CAccessible
|
||||
* Method: menuOpened
|
||||
* Signature: (I)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_menuOpened
|
||||
(JNIEnv *env, jclass jklass, jlong element)
|
||||
{
|
||||
JNF_COCOA_ENTER(env);
|
||||
[ThreadUtilities performOnMainThread:@selector(postMenuOpened)
|
||||
on:(JavaComponentAccessibility *)jlong_to_ptr(element)
|
||||
withObject:nil
|
||||
waitUntilDone:NO];
|
||||
JNF_COCOA_EXIT(env);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_lwawt_macosx_CAccessible
|
||||
* Method: menuClosed
|
||||
* Signature: (I)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_menuClosed
|
||||
(JNIEnv *env, jclass jklass, jlong element)
|
||||
{
|
||||
JNF_COCOA_ENTER(env);
|
||||
[ThreadUtilities performOnMainThread:@selector(postMenuClosed)
|
||||
on:(JavaComponentAccessibility *)jlong_to_ptr(element)
|
||||
withObject:nil
|
||||
waitUntilDone:NO];
|
||||
JNF_COCOA_EXIT(env);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_lwawt_macosx_CAccessible
|
||||
* Method: menuItemSelected
|
||||
* Signature: (I)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_menuItemSelected
|
||||
(JNIEnv *env, jclass jklass, jlong element)
|
||||
{
|
||||
JNF_COCOA_ENTER(env);
|
||||
[ThreadUtilities performOnMainThread:@selector(postMenuItemSelected)
|
||||
on:(JavaComponentAccessibility *)jlong_to_ptr(element)
|
||||
withObject:nil
|
||||
waitUntilDone:NO];
|
||||
JNF_COCOA_EXIT(env);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_lwawt_macosx_CAccessible
|
||||
* Method: unregisterFromCocoaAXSystem
|
||||
|
Loading…
Reference in New Issue
Block a user