From 6e1a503bc9b535c96d3ad0edde8e33c00bc08790 Mon Sep 17 00:00:00 2001 From: Kyle Berezin Date: Wed, 28 Feb 2024 15:49:40 -0800 Subject: [PATCH] Added basic accessibility (#1240) Adds basic accessibility support Co-authored-by: Tres Finocchiaro --- src/qz/build/JLink.java | 30 +++++++---- src/qz/ui/DetailsDialog.java | 6 +++ src/qz/ui/component/EmLabel.java | 16 +++--- src/qz/ui/component/LinkLabel.java | 81 +++++++++++------------------- 4 files changed, 62 insertions(+), 71 deletions(-) diff --git a/src/qz/build/JLink.java b/src/qz/build/JLink.java index 5e6cc10d8..d95317ead 100644 --- a/src/qz/build/JLink.java +++ b/src/qz/build/JLink.java @@ -26,9 +26,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.nio.file.*; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.Properties; +import java.util.*; public class JLink { private static final Logger log = LogManager.getLogger(JLink.class); @@ -233,10 +231,16 @@ private JLink calculateDepList() throws IOException { depList.add(item); } } - // "jar:" URLs create transient zipfs dependency, see https://stackoverflow.com/a/57846672/3196753 - depList.add("jdk.zipfs"); - // fix for https://github.com/qzind/tray/issues/894 solution from https://github.com/adoptium/adoptium-support/issues/397 - depList.add("jdk.crypto.ec"); + switch(targetPlatform) { + case WINDOWS: + // Java accessibility bridge dependency, see https://github.com/qzind/tray/issues/1234 + depList.add("jdk.accessibility"); + default: + // "jar:" URLs create transient zipfs dependency, see https://stackoverflow.com/a/57846672/3196753 + depList.add("jdk.zipfs"); + // fix for https://github.com/qzind/tray/issues/894 solution from https://github.com/adoptium/adoptium-support/issues/397 + depList.add("jdk.crypto.ec"); + } return this; } @@ -279,16 +283,22 @@ private JLink deployJre() throws IOException { log.info("Successfully deployed a jre to {}", outPath); // Remove all but java/javaw - String[] keepFiles; + List keepFiles = new ArrayList<>(); + //String[] keepFiles; String keepExt; switch(targetPlatform) { case WINDOWS: - keepFiles = new String[]{ "java.exe", "javaw.exe" }; + keepFiles.add("java.exe"); + keepFiles.add("javaw.exe"); + if(depList.contains("jdk.accessibility")) { + // Java accessibility bridge switching tool + keepFiles.add("jabswitch.exe"); + } // Windows stores ".dll" files in bin keepExt = ".dll"; break; default: - keepFiles = new String[]{ "java" }; + keepFiles.add("java"); keepExt = null; } diff --git a/src/qz/ui/DetailsDialog.java b/src/qz/ui/DetailsDialog.java index 9856ba88f..869f76697 100644 --- a/src/qz/ui/DetailsDialog.java +++ b/src/qz/ui/DetailsDialog.java @@ -31,12 +31,18 @@ private void initComponents(IconCache iconCache) { requestTable = new RequestTable(iconCache); reqScrollPane = new JScrollPane(requestTable); + requestTable.getAccessibleContext().setAccessibleName(requestLabel.getText() + " Details"); + requestTable.getAccessibleContext().setAccessibleDescription("Signing details about this request."); + requestLabel.setLabelFor(requestTable); certLabel = new JLabel("Certificate"); certLabel.setAlignmentX(CENTER_ALIGNMENT); certTable = new CertificateTable(iconCache); certScrollPane = new JScrollPane(certTable); + certTable.getAccessibleContext().setAccessibleName(certLabel.getText() + " Details"); + certTable.getAccessibleContext().setAccessibleDescription("Certificate details about this request."); + certLabel.setLabelFor(certTable); add(requestLabel); add(reqScrollPane); diff --git a/src/qz/ui/component/EmLabel.java b/src/qz/ui/component/EmLabel.java index 0bc23c719..d22929fbb 100644 --- a/src/qz/ui/component/EmLabel.java +++ b/src/qz/ui/component/EmLabel.java @@ -7,25 +7,25 @@ import java.util.Map; /** - * Create a label at the multiplier of it's normal size, similar to CSS's "em" tag + * Create a label at the multiplier of its normal size, similar to CSS's "em" tag */ public class EmLabel extends JLabel { - public EmLabel() {} - public EmLabel(String text) { - super(text); - } public EmLabel(String text, float multiplier) { this(text, multiplier, true); } public EmLabel(String text, float multiplier, boolean underline) { super(text); - Font template = getFont().deriveFont(multiplier * getFont().getSize()); + stylizeComponent(this, multiplier, underline); + } + + public static void stylizeComponent(Component j, float multiplier, boolean underline) { + Font template = j.getFont().deriveFont(multiplier * j.getFont().getSize()); if (!underline) { Map attributes = new HashMap<>(template.getAttributes()); attributes.remove(TextAttribute.UNDERLINE); - setFont(template.deriveFont(attributes)); + j.setFont(template.deriveFont(attributes)); } else { - setFont(template); + j.setFont(template); } } } diff --git a/src/qz/ui/component/LinkLabel.java b/src/qz/ui/component/LinkLabel.java index 139f8af50..67d3c6cbf 100644 --- a/src/qz/ui/component/LinkLabel.java +++ b/src/qz/ui/component/LinkLabel.java @@ -6,28 +6,28 @@ import qz.ui.Themeable; import qz.utils.ShellUtilities; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.swing.*; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; import java.awt.font.TextAttribute; import java.io.File; import java.net.MalformedURLException; import java.net.URL; -import java.util.ArrayList; import java.util.HashMap; import java.util.Map; /** + * Creates a JButton which visually appears as a clickable link + * + * TODO: Rename this class. Since switching from JLabel to a JButton, this class now has a misleading name. + * * Created by Tres on 2/19/2015. */ -public class LinkLabel extends EmLabel implements Themeable { +public class LinkLabel extends JButton implements Themeable { private static final Logger log = LogManager.getLogger(LinkLabel.class); - private ArrayList actionListeners; - public LinkLabel() { super(); initialize(); @@ -39,7 +39,8 @@ public LinkLabel(String text) { } public LinkLabel(String text, float multiplier, boolean underline) { - super(text, multiplier, underline); + super(text); + EmLabel.stylizeComponent(this, multiplier, underline); initialize(); } @@ -53,15 +54,12 @@ public void setLinkLocation(final String url) { } public void setLinkLocation(final URL location) { - addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent ae) { - try { - Desktop.getDesktop().browse(location.toURI()); - } - catch(Exception e) { - log.error("", e); - } + addActionListener(ae -> { + try { + Desktop.getDesktop().browse(location.toURI()); + } + catch(Exception e) { + log.error("", e); } }); } @@ -70,55 +68,32 @@ public void setLinkLocation(final File filePath) { addActionListener(ae -> ShellUtilities.browseDirectory(filePath.isDirectory()? filePath.getPath():filePath.getParent())); } - private void initialize() { Map attributes = new HashMap<>(getFont().getAttributes()); attributes.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON); setFont(getFont().deriveFont(attributes)); - - actionListeners = new ArrayList<>(); - - addMouseListener(new MouseListener() { - @Override - public void mouseClicked(MouseEvent e) { - for(ActionListener actionListener : actionListeners) { - actionListener.actionPerformed(new ActionEvent(e.getSource(), e.getID(), "mouseClicked")); - } - } - - @Override - public void mousePressed(MouseEvent e) {} - - @Override - public void mouseReleased(MouseEvent e) {} - - @Override - public void mouseEntered(MouseEvent e) { - setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); - } - - @Override - public void mouseExited(MouseEvent e) { - setCursor(Cursor.getDefaultCursor()); - } - }); - refresh(); } @Override public void refresh() { setForeground(Constants.TRUSTED_COLOR); + setBorderPainted(false); + setBorder(null); + setOpaque(false); + setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); } - public void addActionListener(ActionListener action) { - if (!actionListeners.contains(action)) { - actionListeners.add(action); + public AccessibleContext getAccessibleContext() { + if (accessibleContext == null) { + accessibleContext = new AccessibleLinkLabel(); } + return accessibleContext; } - public void removeActionListener(ActionListener action) { - actionListeners.remove(action); + protected class AccessibleLinkLabel extends AccessibleJButton { + public AccessibleRole getAccessibleRole() { + return AccessibleRole.HYPERLINK; + } } - }