8329667: [macos] Issue with JTree related fix for JDK-8317771

Reviewed-by: asemenov, abhiscxk, psadhukhan
This commit is contained in:
Alexander Zuev 2024-05-25 00:35:56 +00:00
parent 7bf1989f59
commit 05f13e75ee
3 changed files with 104 additions and 72 deletions
src/java.desktop/macosx
classes/sun/lwawt/macosx
native/libawt_lwawt/awt/a11y

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2024, 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
@ -36,10 +36,11 @@ import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.annotation.Native;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.Arrays;
@ -64,7 +65,6 @@ import javax.swing.JTextArea;
import javax.swing.JList;
import javax.swing.JTree;
import javax.swing.KeyStroke;
import javax.swing.tree.TreePath;
import sun.awt.AWTAccessor;
import sun.lwawt.LWWindowPeer;
@ -759,21 +759,6 @@ class CAccessibility implements PropertyChangeListener {
return new Object[]{childrenAndRoles.get(whichChildren * 2), childrenAndRoles.get((whichChildren * 2) + 1)};
}
private static Accessible createAccessibleTreeNode(JTree t, TreePath p) {
Accessible a = null;
try {
Class<?> accessibleJTreeNodeClass = Class.forName("javax.swing.JTree$AccessibleJTree$AccessibleJTreeNode");
Constructor<?> constructor = accessibleJTreeNodeClass.getConstructor(t.getAccessibleContext().getClass(), JTree.class, TreePath.class, Accessible.class);
constructor.setAccessible(true);
a = ((Accessible) constructor.newInstance(t.getAccessibleContext(), t, p, null));
} catch (Exception e) {
e.printStackTrace();
}
return a;
}
// 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) {
@ -781,62 +766,21 @@ class CAccessibility implements PropertyChangeListener {
return invokeAndWait(new Callable<Object[]>() {
public Object[] call() throws Exception {
ArrayList<Object> allChildren = new ArrayList<Object>();
Accessible at = null;
if (a instanceof CAccessible) {
at = CAccessible.getSwingAccessible(a);
} else {
at = a;
}
if (at instanceof JTree) {
JTree tree = ((JTree) at);
if (whichChildren == JAVA_AX_ALL_CHILDREN) {
int count = tree.getRowCount();
for (int i = 0; i < count; i++) {
TreePath path = tree.getPathForRow(i);
Accessible an = createAccessibleTreeNode(tree, path);
if (an != null) {
AccessibleContext ac = an.getAccessibleContext();
if (ac != null) {
allChildren.add(an);
allChildren.add(ac.getAccessibleRole());;
allChildren.add(String.valueOf((tree.isRootVisible() ? path.getPathCount() : path.getPathCount() - 1)));
}
}
}
}
if (whichChildren == JAVA_AX_SELECTED_CHILDREN) {
int count = tree.getSelectionCount();
for (int i = 0; i < count; i++) {
TreePath path = tree.getSelectionPaths()[i];
Accessible an = createAccessibleTreeNode(tree, path);
if (an != null) {
AccessibleContext ac = an.getAccessibleContext();
if (ac != null) {
allChildren.add(an);
allChildren.add(ac.getAccessibleRole());
allChildren.add(String.valueOf((tree.isRootVisible() ? path.getPathCount() : path.getPathCount() - 1)));
}
}
}
}
return allChildren.toArray();
}
ArrayList<Object> currentLevelChildren = new ArrayList<Object>();
ArrayList<Accessible> parentStack = new ArrayList<Accessible>();
HashMap<Accessible, List<Object>> childrenOfParent = new HashMap<>();
parentStack.add(a);
ArrayList<Integer> indexses = new ArrayList<Integer>();
Integer index = 0;
int currentLevel = level;
while (!parentStack.isEmpty()) {
Accessible p = parentStack.get(parentStack.size() - 1);
currentLevelChildren.addAll(Arrays.asList(getChildrenAndRolesImpl(p, c, JAVA_AX_ALL_CHILDREN, allowIgnored, ChildrenOperations.COMMON)));
if (!childrenOfParent.containsKey(p)) {
childrenOfParent.put(p, Arrays.asList(getChildrenAndRolesImpl(p,
c, JAVA_AX_ALL_CHILDREN, allowIgnored,
ChildrenOperations.COMMON)));
}
currentLevelChildren.addAll(childrenOfParent.get(p));
if ((currentLevelChildren.size() == 0) || (index >= currentLevelChildren.size())) {
if (!parentStack.isEmpty()) parentStack.remove(parentStack.size() - 1);
if (!indexses.isEmpty()) index = indexses.remove(indexses.size() - 1);
@ -879,7 +823,6 @@ class CAccessibility implements PropertyChangeListener {
currentLevel += 1;
continue;
}
}
return allChildren.toArray();

@ -1,6 +1,6 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2024, JetBrains s.r.o.. 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
@ -29,7 +29,12 @@
// This is a tree representation. See: https://developer.apple.com/documentation/appkit/nsoutlineview
@interface OutlineAccessibility : ListAccessibility <NSAccessibilityOutline>
{
NSMutableArray<id<NSAccessibilityRow>> *rowCache;
BOOL rowCacheValid;
NSMutableArray<id<NSAccessibilityRow>> *selectedRowCache;
BOOL selectedRowCacheValid;
}
@property(readonly) BOOL isTreeRootVisible;
@end

@ -1,6 +1,6 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2024, JetBrains s.r.o.. 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,4 +55,88 @@ static jmethodID sjm_isTreeRootVisible = NULL;
return [[super accessibilityLabel] isEqualToString:@"list"] ? @"tree" : [super accessibilityLabel];
}
- (nullable NSArray<id<NSAccessibilityRow>> *)accessibilityRows
{
return [self accessibilityChildren];
}
- (nullable NSArray<id<NSAccessibilityRow>> *)accessibilitySelectedRows
{
return [self accessibilitySelectedChildren];
}
- (nullable NSArray<id<NSAccessibilityRow>> *)accessibilityChildren
{
if (![self isCacheValid]) {
NSArray *t = [super accessibilityChildren];
if (t != nil) {
rowCache = [[NSMutableArray arrayWithArray:t] retain];
} else {
rowCache = nil;
}
rowCacheValid = YES;
}
return rowCache;
}
- (nullable NSArray<id<NSAccessibilityRow>> *)accessibilitySelectedChildren
{
if (!selectedRowCacheValid) {
NSArray *t = [super accessibilitySelectedChildren];
if (t != nil) {
selectedRowCache = [[NSMutableArray arrayWithArray:t] retain];
} else {
selectedRowCache = nil;
}
selectedRowCacheValid = YES;
}
return selectedRowCache;
}
- (BOOL)isCacheValid
{
if (rowCacheValid && [[self parent] respondsToSelector:NSSelectorFromString(@"isCacheValid")]) {
return [[self parent] isCacheValid];
}
return rowCacheValid;
}
- (void)invalidateCache
{
rowCacheValid = NO;
}
- (void)invalidateSelectionCache
{
selectedRowCacheValid = NO;
}
- (void)postSelectionChanged
{
AWT_ASSERT_APPKIT_THREAD;
[self invalidateSelectionCache];
[super postSelectionChanged];
}
- (void)postTreeNodeCollapsed
{
AWT_ASSERT_APPKIT_THREAD;
[self invalidateCache];
[super postTreeNodeCollapsed];
}
- (void)postTreeNodeExpanded
{
AWT_ASSERT_APPKIT_THREAD;
[self invalidateCache];
[super postTreeNodeExpanded];
}
- (void)postSelectedCellsChanged
{
AWT_ASSERT_APPKIT_THREAD;
[self invalidateSelectionCache];
[super postSelectedCellsChanged];
}
@end