From 60c411eff22b84ed63f12311e57dcf82520701d9 Mon Sep 17 00:00:00 2001 From: Maximilian Wittmer Date: Wed, 29 May 2024 21:39:00 +0200 Subject: [PATCH] Make the ToolBar in the Find/Replace Overlay accessible #1910 Makes the Find/Replace Overlay options accessible by tabbing through the different option buttons. Implements a new "AccessibleToolBar" class which wraps the ToolBar and allows for being natively accessible by using the normal traversal mechanism provided by SWT. fixes #1910 --- .../META-INF/MANIFEST.MF | 2 +- .../ui/texteditor/AccessibleToolBar.java | 77 +++++++++++++++++++ .../ui/texteditor/FindReplaceAction.java | 3 - .../ui/texteditor/FindReplaceOverlay.java | 31 ++++---- 4 files changed, 94 insertions(+), 19 deletions(-) create mode 100644 bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AccessibleToolBar.java diff --git a/bundles/org.eclipse.ui.workbench.texteditor/META-INF/MANIFEST.MF b/bundles/org.eclipse.ui.workbench.texteditor/META-INF/MANIFEST.MF index 1b0e61771ba..c405735b80b 100644 --- a/bundles/org.eclipse.ui.workbench.texteditor/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.ui.workbench.texteditor/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.ui.workbench.texteditor; singleton:=true -Bundle-Version: 3.17.400.qualifier +Bundle-Version: 3.18.0.qualifier Bundle-Activator: org.eclipse.ui.internal.texteditor.TextEditorPlugin Bundle-ActivationPolicy: lazy Bundle-Vendor: %providerName diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AccessibleToolBar.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AccessibleToolBar.java new file mode 100644 index 00000000000..a27e6f02ba7 --- /dev/null +++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/AccessibleToolBar.java @@ -0,0 +1,77 @@ +package org.eclipse.ui.texteditor; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.TraverseEvent; +import org.eclipse.swt.events.TraverseListener; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.ToolBar; +import org.eclipse.swt.widgets.ToolItem; + +import org.eclipse.jface.layout.GridLayoutFactory; + +/** + * This class wraps the ToolBar to make it possible to use tabulator-keys to + * navigate between the buttons of a ToolBar. For this, we simulate a singular + * ToolBar by putting each ToolItem into it's own ToolBar and composing them + * into a Composite. Since the "Enter" keypress could not previously trigger + * activation behavior, we listen for it manually and send according events if + * necessary. + * + * @since 3.18 + */ +class AccessibleToolBar extends Composite { + + private List toolBars = new ArrayList<>(); + + public AccessibleToolBar(Composite parent) { + super(parent, SWT.NONE); + GridLayoutFactory.fillDefaults().numColumns(0).spacing(0, 0).margins(0, 0).applyTo(this); + } + + /** + * Creates a ToolItem handled by this ToolBar and returns it. Will add a + * KeyListener which will catch all "Enter"-Keypresses. + * + * @param styleBits the StyleBits to apply to the created ToolItem + * @return a newly created ToolItem + */ + public ToolItem createToolItem(int styleBits) { + ToolBar parent = new ToolBar(this, SWT.FLAT | SWT.HORIZONTAL); + ToolItem result = new ToolItem(parent, styleBits); + + addToolItemTraverseListener(parent, result); + + ((GridLayout) getLayout()).numColumns++; + + toolBars.add(parent); + return result; + } + + private void addToolItemTraverseListener(ToolBar parent, ToolItem result) { + parent.addTraverseListener(new TraverseListener() { + + @Override + public void keyTraversed(TraverseEvent e) { + if (e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) { + result.setSelection(!result.getSelection()); + e.doit = false; + } + } + + }); + } + + @Override + public void setBackground(Color color) { + super.setBackground(color); + for (ToolBar bar : toolBars) { // we need to color each toolbar separately + bar.setBackground(color); + } + } + +} diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceAction.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceAction.java index 2b848bdf8f0..e253c0902b4 100644 --- a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceAction.java +++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceAction.java @@ -376,9 +376,6 @@ public void run() { } } - /** - * @since 3.17 - */ private void showDialog() { final FindReplaceDialog dialog; final boolean isEditable; diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceOverlay.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceOverlay.java index 2471b514a68..9cda73c5f3e 100644 --- a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceOverlay.java +++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceOverlay.java @@ -44,7 +44,6 @@ import org.eclipse.swt.widgets.Scrollable; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; -import org.eclipse.swt.widgets.ToolBar; import org.eclipse.swt.widgets.ToolItem; import org.eclipse.swt.widgets.Widget; @@ -91,7 +90,7 @@ class FindReplaceOverlay extends Dialog { private Composite searchContainer; private Composite searchBarContainer; private Text searchBar; - private ToolBar searchTools; + private AccessibleToolBar searchTools; private ToolItem searchInSelectionButton; private ToolItem wholeWordSearchButton; @@ -104,7 +103,7 @@ class FindReplaceOverlay extends Dialog { private Composite replaceContainer; private Composite replaceBarContainer; private Text replaceBar; - private ToolBar replaceTools; + private AccessibleToolBar replaceTools; private ToolItem replaceButton; private ToolItem replaceAllButton; @@ -193,6 +192,7 @@ private void performSearchOnEnter(boolean isShiftPressed) { @Override public void keyPressed(KeyEvent e) { e.doit = false; + System.out.println(e.keyCode); if ((e.stateMask & SWT.CTRL) != 0 && (e.keyCode == 'F' || e.keyCode == 'f')) { close(); } else if ((e.stateMask & SWT.CTRL) != 0 && (e.keyCode == 'R' || e.keyCode == 'r')) { @@ -450,7 +450,7 @@ private void retrieveBackgroundColor() { } private void createSearchTools() { - searchTools = new ToolBar(searchContainer, SWT.HORIZONTAL); + searchTools = new AccessibleToolBar(searchContainer); GridDataFactory.fillDefaults().grab(false, true).align(GridData.CENTER, GridData.END).applyTo(searchTools); createWholeWordsButton(); @@ -459,9 +459,9 @@ private void createSearchTools() { createAreaSearchButton(); @SuppressWarnings("unused") - ToolItem separator = new ToolItem(searchTools, SWT.SEPARATOR); + ToolItem separator = searchTools.createToolItem(SWT.SEPARATOR); - searchUpButton = new ToolItem(searchTools, SWT.PUSH); + searchUpButton = searchTools.createToolItem(SWT.PUSH); searchUpButton.setImage(FindReplaceOverlayImages.get(FindReplaceOverlayImages.OBJ_FIND_PREV)); searchUpButton.setToolTipText(FindReplaceMessages.FindReplaceOverlay_upSearchButton_toolTip); searchUpButton.addSelectionListener(new SelectionListener() { @@ -476,7 +476,7 @@ public void widgetDefaultSelected(SelectionEvent e) { // Do Nothing } }); - searchDownButton = new ToolItem(searchTools, SWT.PUSH); + searchDownButton = searchTools.createToolItem(SWT.PUSH); searchDownButton.setSelection(true); // by default, search down searchDownButton.setImage(FindReplaceOverlayImages.get(FindReplaceOverlayImages.OBJ_FIND_NEXT)); searchDownButton.setToolTipText(FindReplaceMessages.FindReplaceOverlay_downSearchButton_toolTip); @@ -493,7 +493,7 @@ public void widgetDefaultSelected(SelectionEvent e) { // Do nothing } }); - searchAllButton = new ToolItem(searchTools, SWT.PUSH); + searchAllButton = searchTools.createToolItem(SWT.PUSH); searchAllButton.setImage(FindReplaceOverlayImages.get(FindReplaceOverlayImages.OBJ_SEARCH_ALL)); searchAllButton.setToolTipText(FindReplaceMessages.FindReplaceOverlay_searchAllButton_toolTip); searchAllButton.addSelectionListener(new SelectionListener() { @@ -513,7 +513,7 @@ public void widgetDefaultSelected(SelectionEvent e) { } private void createAreaSearchButton() { - searchInSelectionButton = new ToolItem(searchTools, SWT.CHECK); + searchInSelectionButton = searchTools.createToolItem(SWT.CHECK); searchInSelectionButton.setImage(FindReplaceOverlayImages.get(FindReplaceOverlayImages.OBJ_SEARCH_IN_AREA)); searchInSelectionButton.setToolTipText(FindReplaceMessages.FindReplaceOverlay_searchInSelectionButton_toolTip); searchInSelectionButton.setSelection(findReplaceLogic.isActive(SearchOptions.WHOLE_WORD)); @@ -533,7 +533,7 @@ public void widgetDefaultSelected(SelectionEvent e) { } private void createRegexSearchButton() { - regexSearchButton = new ToolItem(searchTools, SWT.CHECK); + regexSearchButton = searchTools.createToolItem(SWT.CHECK); regexSearchButton.setImage(FindReplaceOverlayImages.get(FindReplaceOverlayImages.OBJ_FIND_REGEX)); regexSearchButton.setToolTipText(FindReplaceMessages.FindReplaceOverlay_regexSearchButton_toolTip); regexSearchButton.setSelection(findReplaceLogic.isActive(SearchOptions.REGEX)); @@ -554,7 +554,7 @@ public void widgetDefaultSelected(SelectionEvent e) { } private void createCaseSensitiveButton() { - caseSensitiveSearchButton = new ToolItem(searchTools, SWT.CHECK); + caseSensitiveSearchButton = searchTools.createToolItem(SWT.CHECK); caseSensitiveSearchButton.setImage(FindReplaceOverlayImages.get(FindReplaceOverlayImages.OBJ_CASE_SENSITIVE)); caseSensitiveSearchButton.setToolTipText(FindReplaceMessages.FindReplaceOverlay_caseSensitiveButton_toolTip); caseSensitiveSearchButton.setSelection(findReplaceLogic.isActive(SearchOptions.CASE_SENSITIVE)); @@ -574,7 +574,7 @@ public void widgetDefaultSelected(SelectionEvent e) { } private void createWholeWordsButton() { - wholeWordSearchButton = new ToolItem(searchTools, SWT.CHECK); + wholeWordSearchButton = searchTools.createToolItem(SWT.CHECK); wholeWordSearchButton.setImage(FindReplaceOverlayImages.get(FindReplaceOverlayImages.OBJ_WHOLE_WORD)); wholeWordSearchButton.setToolTipText(FindReplaceMessages.FindReplaceOverlay_wholeWordsButton_toolTip); wholeWordSearchButton.setSelection(findReplaceLogic.isActive(SearchOptions.WHOLE_WORD)); @@ -596,9 +596,10 @@ public void widgetDefaultSelected(SelectionEvent e) { private void createReplaceTools() { Color warningColor = JFaceColors.getErrorText(getShell().getDisplay()); - replaceTools = new ToolBar(replaceContainer, SWT.HORIZONTAL); + replaceTools = new AccessibleToolBar(replaceContainer); GridDataFactory.fillDefaults().grab(false, true).align(GridData.CENTER, GridData.END).applyTo(replaceTools); - replaceButton = new ToolItem(replaceTools, SWT.PUSH); + + replaceButton = replaceTools.createToolItem(SWT.PUSH); replaceButton.setImage(FindReplaceOverlayImages.get(FindReplaceOverlayImages.OBJ_REPLACE)); replaceButton.setToolTipText(FindReplaceMessages.FindReplaceOverlay_replaceButton_toolTip); replaceButton.addSelectionListener(new SelectionListener() { @@ -617,7 +618,7 @@ public void widgetDefaultSelected(SelectionEvent e) { // Do nothing } }); - replaceAllButton = new ToolItem(replaceTools, SWT.PUSH); + replaceAllButton = replaceTools.createToolItem(SWT.PUSH); replaceAllButton.setImage(FindReplaceOverlayImages.get(FindReplaceOverlayImages.OBJ_REPLACE_ALL)); replaceAllButton.setToolTipText(FindReplaceMessages.FindReplaceOverlay_replaceAllButton_toolTip); replaceAllButton.addSelectionListener(new SelectionListener() {