New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
8267385: Create NSAccessibilityElement implementation for JavaComponentAccessibility #4412
Changes from 7 commits
c05c814
66ce693
f7979c6
e8b284f
dd219ab
d74af05
280ee5f
e9b966b
ba09569
fbe3443
76cba14
b4ef57a
a07c86d
6505334
a13d6a6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,13 +32,15 @@ | |
import java.awt.Point; | ||
import java.awt.Window; | ||
import java.awt.event.KeyEvent; | ||
import java.awt.EventQueue; | ||
import java.beans.PropertyChangeEvent; | ||
import java.beans.PropertyChangeListener; | ||
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.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; | ||
|
@@ -116,19 +120,14 @@ public void propertyChange(final PropertyChangeEvent evt) { | |
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) { | ||
T value = null; | ||
if (c != null) { | ||
try { | ||
value = LWCToolkit.invokeAndWait(callable, c); | ||
value = EventQueue.isDispatchThread() ? callable.call() : LWCToolkit.invokeAndWait(callable, c); | ||
} catch (final Exception e) { e.printStackTrace(); } | ||
} | ||
|
||
|
@@ -551,6 +550,10 @@ public void run() { | |
if (pac == null) return; | ||
AccessibleSelection as = pac.getAccessibleSelection(); | ||
if (as == null) return; | ||
if (parent instanceof JList) { | ||
((JList) parent).setSelectedIndex(i); | ||
return; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like the a11y interface miss "setSelectedIndex" method? The code above will not work for the custom component which uses the "AccessibleJListChild" a11y object? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unfortunately, the current a11y interface does not allow this action. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the example, you use a JList class, and the checks in the code above works, but if some other "AccessibleJList" class will be used then it will not work, right? This is the reason why implementations of a11y classes usually use specific interfaces like "AccessibleJList". There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, this will not work with a custom list not inherited from JList. Unfortunately AccessibleJList is not perfect and the functionality you need is not there. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is what I meant in the first message, "a11y interface miss setSelectedIndex method". I suggest filing a separate issue to accumulate such use cases and then fix them by adding additional methods to a11y interfaces. Probably something similar will be found in the Table/etc. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. JDK-8271846 |
||
as.addAccessibleSelection(i); | ||
} | ||
}, c); | ||
|
@@ -720,6 +723,32 @@ public Object[] call() throws Exception { | |
}, c); | ||
} | ||
|
||
// 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>(); | ||
currentLevelChildren.addAll(Arrays.asList(getChildrenAndRoles(a, c, JAVA_AX_ALL_CHILDREN, allowIgnored))); | ||
ArrayList<Object> allChildren = new ArrayList<Object>(); | ||
for (int i = 0; i < currentLevelChildren.size(); i += 2) { | ||
if ((((Accessible) currentLevelChildren.get(i)).getAccessibleContext().getAccessibleStateSet().contains(AccessibleState.SELECTED) && (whichChildren == JAVA_AX_SELECTED_CHILDREN)) || | ||
(((Accessible) currentLevelChildren.get(i)).getAccessibleContext().getAccessibleStateSet().contains(AccessibleState.VISIBLE) && (whichChildren == JAVA_AX_VISIBLE_CHILDREN)) || | ||
(whichChildren == JAVA_AX_ALL_CHILDREN)) { | ||
allChildren.add(currentLevelChildren.get(i)); | ||
allChildren.add(currentLevelChildren.get(i + 1)); | ||
allChildren.add(String.valueOf(level)); | ||
} | ||
if (getAccessibleStateSet(((Accessible) currentLevelChildren.get(i)).getAccessibleContext(), c).contains(AccessibleState.EXPANDED)) { | ||
allChildren.addAll(Arrays.asList(getChildrenAndRolesRecursive(((Accessible) currentLevelChildren.get(i)), c, whichChildren, allowIgnored, level + 1))); | ||
} | ||
} | ||
return allChildren.toArray(); | ||
} | ||
}, c); | ||
} | ||
|
||
private static final int JAVA_AX_ROWS = 1; | ||
private static final int JAVA_AX_COLS = 2; | ||
|
||
|
@@ -858,4 +887,18 @@ public Long call() throws Exception { | |
} | ||
}, (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); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When this method is called on EDT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the same class there is a getChildrenAndRolesRecursive () method that calls invokeAndWait (), inside it it calls itself and getChildrenAndRoles (), which also call invokeAndWait ().
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, so this is in the new code, how hard it will be to reimplement these methods to call invokeAndWait only once per callback from the native, as it usually was done before?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done