IDEA-349563 Improve accessible name handling for EditorTextField

* Set the name for the internal editor component instead of EditorTextField, because the focus goes to the editor and screen readers announce its information, not EditorTextField's.
* Because the editor is initialized lazily, the accessible name is stored in a field.
* If EditorTextField has a label, use it as the accessible name for the internal editor component.

GitOrigin-RevId: 30ac07d3d924b48f6b1c8342f18064af6171d6a3
This commit is contained in:
Dmitry Drobotov
2024-03-20 21:12:19 +00:00
committed by intellij-monorepo-bot
parent c501ffbdbc
commit 23d6b88926
@@ -64,6 +64,8 @@ import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.accessibility.Accessible;
import javax.accessibility.AccessibleContext;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
@@ -112,6 +114,7 @@ public class EditorTextField extends NonOpaquePanel implements EditorTextCompone
private Disposable myDisposable;
private Disposable myManualDisposable;
private boolean myInHierarchy;
private @Nls String myAccessibleName;
public EditorTextField() {
this("");
@@ -731,6 +734,21 @@ public class EditorTextField extends NonOpaquePanel implements EditorTextCompone
editor.setPlaceholder(myHintText);
editor.setShowPlaceholderWhenFocused(myShowPlaceholderWhenFocused);
String accessibleName = myAccessibleName;
// Fallback to using the label as accessible name, similar to AccessibleJComponent.getAccessibleName.
if (accessibleName == null) {
Object label = getClientProperty("labeledBy");
if (label instanceof Accessible a) {
AccessibleContext ac = a.getAccessibleContext();
if (ac != null) {
accessibleName = ac.getAccessibleName();
}
}
}
if (accessibleName != null) {
editor.getContentComponent().getAccessibleContext().setAccessibleName(accessibleName);
}
initOneLineMode(editor);
if (myIsRendererWithSelection) {
@@ -1174,4 +1192,27 @@ public class EditorTextField extends NonOpaquePanel implements EditorTextCompone
return aContainer;
}
}
@Override
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleJPanel() {
@Override
public String getAccessibleName() {
// Accessible name is not needed on the wrapper, only on the editor component itself. Otherwise, it may be read twice.
return null;
}
@Override
public void setAccessibleName(@Nls String s) {
myAccessibleName = s;
EditorEx editor = getEditor(false);
if (editor != null) {
editor.getContentComponent().getAccessibleContext().setAccessibleName(s);
}
}
};
}
return accessibleContext;
}
}