8133713: [macosx] Accessible JTables always reported as empty
authorserb
Tue, 16 Oct 2018 16:49:50 -0700
changeset 52260 1cfc72a40bb8
parent 52259 22517c8020d3
child 52261 bd20f7a84e3e
8133713: [macosx] Accessible JTables always reported as empty Reviewed-by: prr
src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java
src/java.desktop/macosx/native/libawt_lwawt/awt/JavaAccessibilityUtilities.m
src/java.desktop/macosx/native/libawt_lwawt/awt/JavaComponentAccessibility.m
--- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java	Tue Oct 16 15:47:53 2018 -0700
+++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java	Tue Oct 16 16:49:50 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2018, 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
@@ -25,17 +25,39 @@
 
 package sun.lwawt.macosx;
 
-import sun.lwawt.LWWindowPeer;
-
-import java.awt.*;
-import java.beans.*;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.KeyboardFocusManager;
+import java.awt.Point;
+import java.awt.Window;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
 import java.lang.reflect.InvocationTargetException;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
 import java.util.concurrent.Callable;
 
-import javax.accessibility.*;
-import javax.swing.*;
+import javax.accessibility.Accessible;
+import javax.accessibility.AccessibleAction;
+import javax.accessibility.AccessibleComponent;
+import javax.accessibility.AccessibleContext;
+import javax.accessibility.AccessibleRole;
+import javax.accessibility.AccessibleSelection;
+import javax.accessibility.AccessibleState;
+import javax.accessibility.AccessibleStateSet;
+import javax.accessibility.AccessibleTable;
+import javax.accessibility.AccessibleText;
+import javax.accessibility.AccessibleValue;
+import javax.swing.Icon;
+import javax.swing.JComponent;
+import javax.swing.JEditorPane;
+import javax.swing.JLabel;
+import javax.swing.JTextArea;
+
 import sun.awt.AWTAccessor;
+import sun.lwawt.LWWindowPeer;
 
 class CAccessibility implements PropertyChangeListener {
     private static Set<String> ignoredRoles;
@@ -626,7 +648,7 @@
                                 currentAC = currentAccessible.getAccessibleContext();
                                 currentName = currentAC.getAccessibleName();
                                 currentRole = (AccessibleRole)childrenAndRoles.get(i+1);
-                                if ( currentName.equals(activeDescendantName) &&
+                                if (currentName != null && currentName.equals(activeDescendantName) &&
                                      currentRole.equals(activeDescendantRole) ) {
                                     newArray.add(0, currentAccessible);
                                     newArray.add(1, currentRole);
@@ -649,6 +671,26 @@
         }, c);
     }
 
+    private static final int JAVA_AX_ROWS = 1;
+    private static final int JAVA_AX_COLS = 2;
+
+    public static int getTableInfo(final Accessible a, final Component c,
+                                   final int info) {
+        if (a == null) return 0;
+        return invokeAndWait(() -> {
+            AccessibleContext ac = a.getAccessibleContext();
+            AccessibleTable table = ac.getAccessibleTable();
+            if (table != null) {
+                if (info == JAVA_AX_COLS) {
+                    return table.getAccessibleColumnCount();
+                } else if (info == JAVA_AX_ROWS) {
+                    return table.getAccessibleRowCount();
+                }
+            }
+            return 0;
+        }, c);
+    }
+
     private static AccessibleRole getAccessibleRoleForLabel(JLabel l, AccessibleRole fallback) {
         String text = l.getText();
         if (text != null && text.length() > 0) {
--- a/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaAccessibilityUtilities.m	Tue Oct 16 15:47:53 2018 -0700
+++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaAccessibilityUtilities.m	Tue Oct 16 16:49:50 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2018, 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
@@ -368,7 +368,7 @@
     [sRoles setObject:NSAccessibilitySplitGroupRole forKey:@"splitpane"];
     [sRoles setObject:NSAccessibilityValueIndicatorRole forKey:@"statusbar"];
     [sRoles setObject:NSAccessibilityGroupRole forKey:@"swingcomponent"];
-    [sRoles setObject:NSAccessibilityTableRole forKey:@"table"];
+    [sRoles setObject:NSAccessibilityGridRole 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"];
--- a/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaComponentAccessibility.m	Tue Oct 16 15:47:53 2018 -0700
+++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaComponentAccessibility.m	Tue Oct 16 16:49:50 2018 -0700
@@ -54,6 +54,7 @@
 // If the value is >=0, it's an index
 
 static JNF_STATIC_MEMBER_CACHE(jm_getChildrenAndRoles, sjc_CAccessibility, "getChildrenAndRoles", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;IZ)[Ljava/lang/Object;");
+static JNF_STATIC_MEMBER_CACHE(jm_getTableInfo, sjc_CAccessibility, "getTableInfo", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;I)I");
 static JNF_STATIC_MEMBER_CACHE(sjm_getAccessibleComponent, sjc_CAccessibility, "getAccessibleComponent", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/AccessibleComponent;");
 static JNF_STATIC_MEMBER_CACHE(sjm_getAccessibleValue, sjc_CAccessibility, "getAccessibleValue", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/AccessibleValue;");
 static JNF_STATIC_MEMBER_CACHE(sjm_getAccessibleName, sjc_CAccessibility, "getAccessibleName", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;");
@@ -117,6 +118,14 @@
 - (BOOL)accessibilityIsHorizontalScrollBarAttributeSettable;
 @end
 
+@interface TableAccessibility : JavaComponentAccessibility {
+
+}
+- (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env;
+- (NSArray *)accessibilityRowsAttribute;
+- (NSArray *)accessibilityColumnsAttribute;
+@end
+
 
 @implementation JavaComponentAccessibility
 
@@ -370,6 +379,8 @@
     JavaComponentAccessibility *newChild = nil;
     if ([javaRole isEqualToString:@"pagetablist"]) {
         newChild = [TabGroupAccessibility alloc];
+    } else if ([javaRole isEqualToString:@"table"]) {
+        newChild = [TableAccessibility alloc];
     } else if ([javaRole isEqualToString:@"scrollpane"]) {
         newChild = [ScrollAreaAccessibility alloc];
     } else {
@@ -484,7 +495,8 @@
     // children
     if (attributeStatesArray[6]) {
         [attributeNames addObject:NSAccessibilityChildrenAttribute];
-        if ([javaRole isEqualToString:@"list"]) {
+        if ([javaRole isEqualToString:@"list"]
+                || [javaRole isEqualToString:@"table"]) {
             [attributeNames addObject:NSAccessibilitySelectedChildrenAttribute];
             [attributeNames addObject:NSAccessibilityVisibleChildrenAttribute];
         }
@@ -652,7 +664,9 @@
         id myParent = [self accessibilityParentAttribute];
         if ([myParent isKindOfClass:[JavaComponentAccessibility class]]) {
             NSString *parentRole = [(JavaComponentAccessibility *)myParent javaRole];
-            if ([parentRole isEqualToString:@"list"]) {
+
+            if ([parentRole isEqualToString:@"list"]
+                    || [parentRole isEqualToString:@"table"]) {
                 NSMutableArray *moreNames =
                     [[NSMutableArray alloc] initWithCapacity: [names count] + 2];
                 [moreNames addObjectsFromArray: names];
@@ -1847,6 +1861,41 @@
 
 @end
 
+// these constants are duplicated in CAccessibility.java
+#define JAVA_AX_ROWS (1)
+#define JAVA_AX_COLS (2)
+
+@implementation TableAccessibility
+
+- (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env
+{
+    NSMutableArray *names = (NSMutableArray *)[super initializeAttributeNamesWithEnv:env];
+
+    [names addObject:NSAccessibilityRowCountAttribute];
+    [names addObject:NSAccessibilityColumnCountAttribute];
+    return names;
+}
+
+- (id)getTableInfo:(jint)info {
+    if (fAccessible == NULL) return 0;
+
+    JNIEnv* env = [ThreadUtilities getJNIEnv];
+    jint count = JNFCallStaticIntMethod(env, jm_getTableInfo, fAccessible,
+                                        fComponent, info);
+    NSNumber *index = [NSNumber numberWithInt:count];
+    return index;
+}
+
+
+- (id)accessibilityRowCountAttribute {
+    return [self getTableInfo:JAVA_AX_ROWS];
+}
+
+- (id)accessibilityColumnCountAttribute {
+    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