From 5cf19b8be25d0470e1b19d98ce50db051a8e227f Mon Sep 17 00:00:00 2001 From: xinyi-gong Date: Wed, 27 May 2026 10:13:09 +0800 Subject: [PATCH 1/4] fix two accessibility issues --- .../eclipse/ui/chat/AddContextButton.java | 1 + .../ui/chat/CurrentReferencedFile.java | 6 ++ .../eclipse/ui/chat/ReferencedFile.java | 20 +++++ .../ui/chat/SourceViewerComposite.java | 81 ++++++++++++++++--- 4 files changed, 95 insertions(+), 13 deletions(-) diff --git a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/AddContextButton.java b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/AddContextButton.java index a9091824..1f31441a 100644 --- a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/AddContextButton.java +++ b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/AddContextButton.java @@ -54,6 +54,7 @@ public AddContextButton(Composite parent) { btnAttachIcon.setImage(attachImage); String attachTooltip = Messages.chat_addContext_tooltip; btnAttachIcon.setToolTipText(attachTooltip); + AccessibilityUtils.addAccessibilityNameForUiComponent(this, attachTooltip); AccessibilityUtils.addAccessibilityNameForUiComponent(btnAttachIcon, attachTooltip); btnAttachIcon.addSelectionListener(new SelectionAdapter() { @Override diff --git a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/CurrentReferencedFile.java b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/CurrentReferencedFile.java index 46f22d4d..19a9dde2 100644 --- a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/CurrentReferencedFile.java +++ b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/CurrentReferencedFile.java @@ -92,6 +92,12 @@ public void setFile(IResource file) { super.setFile(file); } + @Override + protected @Nullable String getAccessibilityName() { + IResource file = getFile(); + return file == null ? null : Messages.chat_currentReferencedFile_description + " " + file.getName(); + } + /** * Set the current selection to display. */ diff --git a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/ReferencedFile.java b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/ReferencedFile.java index 8c9faf9d..db63a981 100644 --- a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/ReferencedFile.java +++ b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/ReferencedFile.java @@ -9,6 +9,8 @@ import org.eclipse.e4.ui.css.swt.CSSSWTConstants; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.swt.SWT; +import org.eclipse.swt.accessibility.AccessibleAdapter; +import org.eclipse.swt.accessibility.AccessibleEvent; import org.eclipse.swt.events.KeyAdapter; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.MouseAdapter; @@ -19,6 +21,7 @@ import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.layout.RowData; import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.ui.ISharedImages; import org.eclipse.ui.PlatformUI; @@ -100,6 +103,7 @@ public void keyPressed(KeyEvent e) { }); AccessibilityUtils.addFocusBorderToComposite(this); + addAccessibilityName(this); } /** @@ -170,6 +174,22 @@ protected void setFile(@Nullable IResource file) { } } + /** + * Returns the accessible name for this referenced file widget. + */ + protected @Nullable String getAccessibilityName() { + return file == null ? null : file.getName(); + } + + private void addAccessibilityName(Control control) { + control.getAccessible().addAccessibleListener(new AccessibleAdapter() { + @Override + public void getName(AccessibleEvent event) { + event.result = getAccessibilityName(); + } + }); + } + /** * Setup display for unsupported files (e.g., images without vision support). */ diff --git a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/SourceViewerComposite.java b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/SourceViewerComposite.java index b661f77b..ac1e83a1 100644 --- a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/SourceViewerComposite.java +++ b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/SourceViewerComposite.java @@ -17,6 +17,8 @@ import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.events.ControlAdapter; import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.FocusAdapter; +import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseTrackAdapter; import org.eclipse.swt.graphics.Image; @@ -25,6 +27,7 @@ import org.eclipse.swt.layout.RowLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.ScrollBar; import org.eclipse.ui.IEditorPart; @@ -117,6 +120,17 @@ private SourceViewer createSourceViewer() { StyledText styledText = viewer.getTextWidget(); styledText.setAlwaysShowScrollBars(false); + styledText.addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent e) { + showActionButtons(); + } + + @Override + public void focusLost(FocusEvent e) { + hideActionButtons(null); + } + }); // TODO: Add VerifyKeyListener to listen for copy events // See: https://github.com/microsoft/copilot-eclipse/issues/372 @@ -125,23 +139,12 @@ private SourceViewer createSourceViewer() { styledText.addMouseTrackListener(new MouseTrackAdapter() { @Override public void mouseEnter(MouseEvent e) { - Rectangle textBounds = styledText.getBounds(); - Rectangle actionsBounds = actionsComposite.getBounds(); - actionsComposite.setLocation(textBounds.width - ACTIONS_PADDING_RIGHT - actionsBounds.width, - ACTIONS_PADDING_TOP); - actionsComposite.moveAbove(styledText); - actionsComposite.setVisible(true); + showActionButtons(); } @Override public void mouseExit(MouseEvent e) { - // if mouse move to copy button, it will also trigger mouse exit, check this case here - Rectangle buttonBounds = actionsComposite.getBounds(); - Point cursorLocation = new Point(e.x, e.y); - if (!buttonBounds.contains(cursorLocation)) { - actionsComposite.moveBelow(styledText); - actionsComposite.setVisible(false); - } + hideActionButtons(new Point(e.x, e.y)); } }); @@ -198,6 +201,7 @@ private Composite createActionsComposite() { private Button createActionButton(Composite parent, int style, Image image, String text, String tooltip) { Button result = new Button(parent, style); result.setToolTipText(tooltip); + AccessibilityUtils.addAccessibilityNameForUiComponent(result, tooltip); result.setVisible(true); if (image == null) { result.setText(text); @@ -213,6 +217,57 @@ private Button createActionButton(Composite parent, int style, Image image, Stri return result; } + private void showActionButtons() { + if (this.actionsComposite == null || this.actionsComposite.isDisposed()) { + return; + } + StyledText styledText = this.sourceViewer.getTextWidget(); + Rectangle textBounds = styledText.getBounds(); + Rectangle actionsBounds = actionsComposite.getBounds(); + actionsComposite.setLocation(textBounds.width - ACTIONS_PADDING_RIGHT - actionsBounds.width, ACTIONS_PADDING_TOP); + actionsComposite.moveAbove(styledText); + actionsComposite.setVisible(true); + } + + private void hideActionButtons(Point cursorLocation) { + if (this.actionsComposite == null || this.actionsComposite.isDisposed()) { + return; + } + SwtUtils.invokeOnDisplayThreadAsync(() -> { + if (actionsComposite == null || actionsComposite.isDisposed()) { + return; + } + if (!isCursorWithinCodeBlockActions(cursorLocation) && !isFocusWithinCodeBlockActions()) { + actionsComposite.moveBelow(sourceViewer.getTextWidget()); + actionsComposite.setVisible(false); + } + }, this); + } + + private boolean isCursorWithinCodeBlockActions(Point cursorLocation) { + return cursorLocation != null && actionsComposite.getBounds().contains(cursorLocation); + } + + private boolean isFocusWithinCodeBlockActions() { + if (this.actionsComposite == null || this.actionsComposite.isDisposed()) { + return false; + } + Control focusControl = getDisplay().getFocusControl(); + if (focusControl == null || focusControl.isDisposed()) { + return false; + } + if (this.sourceViewer != null && focusControl == this.sourceViewer.getTextWidget()) { + return true; + } + while (focusControl != null) { + if (focusControl == this.actionsComposite) { + return true; + } + focusControl = focusControl.getParent(); + } + return false; + } + private void refreshScrollerLayout() { if (this.sourceViewer == null) { return; From c706653fe2f2ae78a68f7b423be3e66c8f0266f6 Mon Sep 17 00:00:00 2001 From: xinyi-gong Date: Wed, 27 May 2026 10:51:42 +0800 Subject: [PATCH 2/4] resolve comment --- .../eclipse/ui/chat/SourceViewerComposite.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/SourceViewerComposite.java b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/SourceViewerComposite.java index ac1e83a1..ec1d919d 100644 --- a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/SourceViewerComposite.java +++ b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/SourceViewerComposite.java @@ -128,7 +128,7 @@ public void focusGained(FocusEvent e) { @Override public void focusLost(FocusEvent e) { - hideActionButtons(null); + hideActionButtons(); } }); @@ -144,7 +144,7 @@ public void mouseEnter(MouseEvent e) { @Override public void mouseExit(MouseEvent e) { - hideActionButtons(new Point(e.x, e.y)); + hideActionButtons(); } }); @@ -229,7 +229,7 @@ private void showActionButtons() { actionsComposite.setVisible(true); } - private void hideActionButtons(Point cursorLocation) { + private void hideActionButtons() { if (this.actionsComposite == null || this.actionsComposite.isDisposed()) { return; } @@ -237,15 +237,19 @@ private void hideActionButtons(Point cursorLocation) { if (actionsComposite == null || actionsComposite.isDisposed()) { return; } - if (!isCursorWithinCodeBlockActions(cursorLocation) && !isFocusWithinCodeBlockActions()) { + if (!isCursorWithinCodeBlockActions() && !isFocusWithinCodeBlockActions()) { actionsComposite.moveBelow(sourceViewer.getTextWidget()); actionsComposite.setVisible(false); } }, this); } - private boolean isCursorWithinCodeBlockActions(Point cursorLocation) { - return cursorLocation != null && actionsComposite.getBounds().contains(cursorLocation); + private boolean isCursorWithinCodeBlockActions() { + Point cursorLocation = actionsComposite.getDisplay().getCursorLocation(); + Point actionsLocation = actionsComposite.toDisplay(0, 0); + Point actionsSize = actionsComposite.getSize(); + Rectangle actionsBounds = new Rectangle(actionsLocation.x, actionsLocation.y, actionsSize.x, actionsSize.y); + return actionsBounds.contains(cursorLocation); } private boolean isFocusWithinCodeBlockActions() { From 78584d1bc1613de3b8b456b9d43c4bed60f067b1 Mon Sep 17 00:00:00 2001 From: xinyi-gong Date: Wed, 27 May 2026 17:10:41 +0800 Subject: [PATCH 3/4] revert codeblock fix --- .../ui/chat/SourceViewerComposite.java | 85 +++---------------- 1 file changed, 13 insertions(+), 72 deletions(-) diff --git a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/SourceViewerComposite.java b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/SourceViewerComposite.java index ec1d919d..b661f77b 100644 --- a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/SourceViewerComposite.java +++ b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/SourceViewerComposite.java @@ -17,8 +17,6 @@ import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.events.ControlAdapter; import org.eclipse.swt.events.ControlEvent; -import org.eclipse.swt.events.FocusAdapter; -import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseTrackAdapter; import org.eclipse.swt.graphics.Image; @@ -27,7 +25,6 @@ import org.eclipse.swt.layout.RowLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.ScrollBar; import org.eclipse.ui.IEditorPart; @@ -120,17 +117,6 @@ private SourceViewer createSourceViewer() { StyledText styledText = viewer.getTextWidget(); styledText.setAlwaysShowScrollBars(false); - styledText.addFocusListener(new FocusAdapter() { - @Override - public void focusGained(FocusEvent e) { - showActionButtons(); - } - - @Override - public void focusLost(FocusEvent e) { - hideActionButtons(); - } - }); // TODO: Add VerifyKeyListener to listen for copy events // See: https://github.com/microsoft/copilot-eclipse/issues/372 @@ -139,12 +125,23 @@ public void focusLost(FocusEvent e) { styledText.addMouseTrackListener(new MouseTrackAdapter() { @Override public void mouseEnter(MouseEvent e) { - showActionButtons(); + Rectangle textBounds = styledText.getBounds(); + Rectangle actionsBounds = actionsComposite.getBounds(); + actionsComposite.setLocation(textBounds.width - ACTIONS_PADDING_RIGHT - actionsBounds.width, + ACTIONS_PADDING_TOP); + actionsComposite.moveAbove(styledText); + actionsComposite.setVisible(true); } @Override public void mouseExit(MouseEvent e) { - hideActionButtons(); + // if mouse move to copy button, it will also trigger mouse exit, check this case here + Rectangle buttonBounds = actionsComposite.getBounds(); + Point cursorLocation = new Point(e.x, e.y); + if (!buttonBounds.contains(cursorLocation)) { + actionsComposite.moveBelow(styledText); + actionsComposite.setVisible(false); + } } }); @@ -201,7 +198,6 @@ private Composite createActionsComposite() { private Button createActionButton(Composite parent, int style, Image image, String text, String tooltip) { Button result = new Button(parent, style); result.setToolTipText(tooltip); - AccessibilityUtils.addAccessibilityNameForUiComponent(result, tooltip); result.setVisible(true); if (image == null) { result.setText(text); @@ -217,61 +213,6 @@ private Button createActionButton(Composite parent, int style, Image image, Stri return result; } - private void showActionButtons() { - if (this.actionsComposite == null || this.actionsComposite.isDisposed()) { - return; - } - StyledText styledText = this.sourceViewer.getTextWidget(); - Rectangle textBounds = styledText.getBounds(); - Rectangle actionsBounds = actionsComposite.getBounds(); - actionsComposite.setLocation(textBounds.width - ACTIONS_PADDING_RIGHT - actionsBounds.width, ACTIONS_PADDING_TOP); - actionsComposite.moveAbove(styledText); - actionsComposite.setVisible(true); - } - - private void hideActionButtons() { - if (this.actionsComposite == null || this.actionsComposite.isDisposed()) { - return; - } - SwtUtils.invokeOnDisplayThreadAsync(() -> { - if (actionsComposite == null || actionsComposite.isDisposed()) { - return; - } - if (!isCursorWithinCodeBlockActions() && !isFocusWithinCodeBlockActions()) { - actionsComposite.moveBelow(sourceViewer.getTextWidget()); - actionsComposite.setVisible(false); - } - }, this); - } - - private boolean isCursorWithinCodeBlockActions() { - Point cursorLocation = actionsComposite.getDisplay().getCursorLocation(); - Point actionsLocation = actionsComposite.toDisplay(0, 0); - Point actionsSize = actionsComposite.getSize(); - Rectangle actionsBounds = new Rectangle(actionsLocation.x, actionsLocation.y, actionsSize.x, actionsSize.y); - return actionsBounds.contains(cursorLocation); - } - - private boolean isFocusWithinCodeBlockActions() { - if (this.actionsComposite == null || this.actionsComposite.isDisposed()) { - return false; - } - Control focusControl = getDisplay().getFocusControl(); - if (focusControl == null || focusControl.isDisposed()) { - return false; - } - if (this.sourceViewer != null && focusControl == this.sourceViewer.getTextWidget()) { - return true; - } - while (focusControl != null) { - if (focusControl == this.actionsComposite) { - return true; - } - focusControl = focusControl.getParent(); - } - return false; - } - private void refreshScrollerLayout() { if (this.sourceViewer == null) { return; From c8e1b0dfc09068b5dfd01b0611cb8efb774baa8b Mon Sep 17 00:00:00 2001 From: xinyi-gong Date: Wed, 27 May 2026 17:32:09 +0800 Subject: [PATCH 4/4] remove redundant name setting --- .../com/microsoft/copilot/eclipse/ui/chat/AddContextButton.java | 1 - 1 file changed, 1 deletion(-) diff --git a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/AddContextButton.java b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/AddContextButton.java index 1f31441a..a9091824 100644 --- a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/AddContextButton.java +++ b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/AddContextButton.java @@ -54,7 +54,6 @@ public AddContextButton(Composite parent) { btnAttachIcon.setImage(attachImage); String attachTooltip = Messages.chat_addContext_tooltip; btnAttachIcon.setToolTipText(attachTooltip); - AccessibilityUtils.addAccessibilityNameForUiComponent(this, attachTooltip); AccessibilityUtils.addAccessibilityNameForUiComponent(btnAttachIcon, attachTooltip); btnAttachIcon.addSelectionListener(new SelectionAdapter() { @Override