Skip to content

Commit 4244f7b

Browse files
authored
fix: Nested scrolling and full-row table selection for auto-approve preferences (#256)
1 parent 5cc8358 commit 4244f7b

5 files changed

Lines changed: 104 additions & 16 deletions

File tree

com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/preferences/CustomInstructionPreferencePage.java

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import org.eclipse.jface.text.ITextViewer;
2323
import org.eclipse.swt.SWT;
2424
import org.eclipse.swt.custom.StyledText;
25-
import org.eclipse.swt.events.ControlAdapter;
2625
import org.eclipse.swt.events.SelectionListener;
2726
import org.eclipse.swt.graphics.Point;
2827
import org.eclipse.swt.layout.GridData;
@@ -269,18 +268,7 @@ private void createProjectInstructionsField(Composite parent, GridLayout gl) {
269268
// Set the file location column to take remaining width (table width - project name column width)
270269
fileLocationColumn.setWidth(tableGridData.widthHint > 0 ? tableGridData.widthHint - 150 : 400);
271270

272-
// Add resize listener to make the file location column take remaining width
273-
table.addControlListener(new ControlAdapter() {
274-
@Override
275-
public void controlResized(org.eclipse.swt.events.ControlEvent e) {
276-
int tableWidth = table.getClientArea().width;
277-
int projectNameWidth = projectNameColumn.getWidth();
278-
int remainingWidth = tableWidth - projectNameWidth;
279-
if (remainingWidth > 100) { // Minimum width for file location column
280-
fileLocationColumn.setWidth(remainingWidth);
281-
}
282-
}
283-
});
271+
SwtUtils.resizeColumnToFillTable(table, fileLocationColumn, 100, projectNameColumn);
284272

285273
// Populate table with actual workspace projects
286274
populateProjectTable(table);

com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/preferences/FileOperationAutoApproveSection.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,14 @@ private void createContents() {
112112

113113
private void createTable(Composite parent) {
114114
tableViewer = new TableViewer(parent,
115-
SWT.BORDER | SWT.FULL_SELECTION | SWT.SINGLE);
115+
SWT.BORDER | SWT.FULL_SELECTION | SWT.SINGLE | SWT.V_SCROLL);
116116
Table table = tableViewer.getTable();
117117
GridData tableData = new GridData(SWT.FILL, SWT.FILL, true, false);
118118
tableData.heightHint = TABLE_HEIGHT_HINT;
119119
table.setLayoutData(tableData);
120120
table.setHeaderVisible(true);
121121
table.setLinesVisible(true);
122+
SwtUtils.forwardVerticalMouseWheelToParentScrollerAtBoundary(table);
122123

123124
TableViewerColumn patternCol =
124125
new TableViewerColumn(tableViewer, SWT.NONE);
@@ -177,6 +178,8 @@ public Color getForeground(Object element) {
177178
? Display.getDefault().getSystemColor(SWT.COLOR_DARK_GRAY) : null;
178179
}
179180
});
181+
SwtUtils.resizeColumnToFillTable(table, statusCol.getColumn(), 100,
182+
patternCol.getColumn(), descCol.getColumn());
180183

181184
tableViewer.setContentProvider(ArrayContentProvider.getInstance());
182185
tableViewer.addSelectionChangedListener(e -> updateButtonState());

com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/preferences/McpAutoApproveSection.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,11 @@ private void createContents() {
9090

9191
// Tree viewer for server/tool approval
9292
treeViewer = new CheckboxTreeViewer(group,
93-
SWT.BORDER | SWT.FULL_SELECTION);
93+
SWT.BORDER | SWT.FULL_SELECTION | SWT.V_SCROLL);
9494
GridData treeData = new GridData(SWT.FILL, SWT.FILL, true, false);
9595
treeData.heightHint = TREE_HEIGHT_HINT;
9696
treeViewer.getTree().setLayoutData(treeData);
97+
SwtUtils.forwardVerticalMouseWheelToParentScrollerAtBoundary(treeViewer.getTree());
9798

9899
treeViewer.setContentProvider(new McpTreeContentProvider());
99100
treeViewer.setLabelProvider(new McpTreeLabelProvider());

com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/preferences/TerminalAutoApproveSection.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import com.microsoft.copilot.eclipse.core.CopilotCore;
3131
import com.microsoft.copilot.eclipse.core.chat.TerminalAutoApproveRule;
3232
import com.microsoft.copilot.eclipse.ui.chat.confirmation.TerminalConfirmationHandler;
33+
import com.microsoft.copilot.eclipse.ui.utils.SwtUtils;
3334

3435
/**
3536
* Terminal auto-approve section with a rule table, action buttons, and
@@ -90,13 +91,14 @@ private void createContents() {
9091

9192
private void createTable(Composite parent) {
9293
tableViewer = new TableViewer(parent,
93-
SWT.BORDER | SWT.FULL_SELECTION | SWT.SINGLE);
94+
SWT.BORDER | SWT.FULL_SELECTION | SWT.SINGLE | SWT.V_SCROLL);
9495
Table table = tableViewer.getTable();
9596
GridData tableData = new GridData(SWT.FILL, SWT.FILL, true, false);
9697
tableData.heightHint = TABLE_HEIGHT_HINT;
9798
table.setLayoutData(tableData);
9899
table.setHeaderVisible(true);
99100
table.setLinesVisible(true);
101+
SwtUtils.forwardVerticalMouseWheelToParentScrollerAtBoundary(table);
100102

101103
TableViewerColumn commandCol =
102104
new TableViewerColumn(tableViewer, SWT.NONE);
@@ -123,6 +125,8 @@ public String getText(Object element) {
123125
: Messages.preferences_page_auto_approve_deny;
124126
}
125127
});
128+
SwtUtils.resizeColumnToFillTable(table, statusCol.getColumn(), 100,
129+
commandCol.getColumn());
126130

127131
tableViewer.setContentProvider(ArrayContentProvider.getInstance());
128132
tableViewer.addSelectionChangedListener(e -> updateButtonState());

com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/utils/SwtUtils.java

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,25 @@
1212
import org.eclipse.jface.resource.ColorRegistry;
1313
import org.eclipse.jface.resource.JFaceResources;
1414
import org.eclipse.jface.text.ITextViewer;
15+
import org.eclipse.swt.SWT;
16+
import org.eclipse.swt.custom.ScrolledComposite;
1517
import org.eclipse.swt.custom.StyledText;
1618
import org.eclipse.swt.dnd.Clipboard;
1719
import org.eclipse.swt.dnd.TextTransfer;
1820
import org.eclipse.swt.dnd.Transfer;
21+
import org.eclipse.swt.events.ControlAdapter;
22+
import org.eclipse.swt.events.ControlEvent;
1923
import org.eclipse.swt.graphics.Color;
24+
import org.eclipse.swt.graphics.Point;
2025
import org.eclipse.swt.graphics.RGB;
26+
import org.eclipse.swt.widgets.Composite;
2127
import org.eclipse.swt.widgets.Control;
2228
import org.eclipse.swt.widgets.Display;
29+
import org.eclipse.swt.widgets.ScrollBar;
30+
import org.eclipse.swt.widgets.Scrollable;
2331
import org.eclipse.swt.widgets.Shell;
32+
import org.eclipse.swt.widgets.Table;
33+
import org.eclipse.swt.widgets.TableColumn;
2434
import org.eclipse.ui.IEditorPart;
2535
import org.eclipse.ui.IWorkbench;
2636
import org.eclipse.ui.IWorkbenchPage;
@@ -272,6 +282,88 @@ public static Color getDefaultGhostTextColor(Display display) {
272282
return new Color(display, new RGB(DEFAULT_GHOST_TEXT_SCALE, DEFAULT_GHOST_TEXT_SCALE, DEFAULT_GHOST_TEXT_SCALE));
273283
}
274284

285+
/**
286+
* Forwards vertical mouse wheel scrolling from a nested scrollable to its nearest parent scroller when the nested
287+
* control is already at the scroll boundary.
288+
*/
289+
public static void forwardVerticalMouseWheelToParentScrollerAtBoundary(Scrollable scrollable) {
290+
scrollable.addListener(SWT.MouseWheel, event -> {
291+
if (event.count == 0 || scrollable.isDisposed()
292+
|| canScrollVertically(scrollable.getVerticalBar(), event.count)) {
293+
return;
294+
}
295+
296+
ScrolledComposite parentScroller = findParentScroller(scrollable);
297+
if (parentScroller != null
298+
&& canScrollVertically(parentScroller.getVerticalBar(), event.count)) {
299+
event.doit = false;
300+
scrollParentVertically(parentScroller, event.count);
301+
}
302+
});
303+
}
304+
305+
private static ScrolledComposite findParentScroller(Scrollable scrollable) {
306+
Composite parent = scrollable.getParent();
307+
while (parent != null) {
308+
if (parent instanceof ScrolledComposite scrolledComposite) {
309+
return scrolledComposite;
310+
}
311+
parent = parent.getParent();
312+
}
313+
return null;
314+
}
315+
316+
private static void scrollParentVertically(ScrolledComposite scrolledComposite, int wheelCount) {
317+
ScrollBar verticalBar = scrolledComposite.getVerticalBar();
318+
if (verticalBar == null || verticalBar.isDisposed()) {
319+
return;
320+
}
321+
322+
Point origin = scrolledComposite.getOrigin();
323+
int minimum = verticalBar.getMinimum();
324+
int maximum = Math.max(minimum,
325+
verticalBar.getMaximum() - verticalBar.getThumb());
326+
int delta = -wheelCount * Math.max(1, verticalBar.getIncrement());
327+
int nextY = Math.max(minimum, Math.min(maximum, origin.y + delta));
328+
scrolledComposite.setOrigin(origin.x, nextY);
329+
}
330+
331+
private static boolean canScrollVertically(ScrollBar verticalBar, int wheelCount) {
332+
if (verticalBar == null || verticalBar.isDisposed()
333+
|| !verticalBar.getEnabled()) {
334+
return false;
335+
}
336+
337+
int minimum = verticalBar.getMinimum();
338+
int maximum = Math.max(minimum,
339+
verticalBar.getMaximum() - verticalBar.getThumb());
340+
int selection = Math.max(minimum,
341+
Math.min(maximum, verticalBar.getSelection()));
342+
if (wheelCount > 0) {
343+
return selection > minimum;
344+
}
345+
return selection < maximum;
346+
}
347+
348+
/**
349+
* Resizes a table column to fill the table client area not occupied by the fixed-width columns.
350+
*/
351+
public static void resizeColumnToFillTable(Table table, TableColumn fillColumn,
352+
int minWidth, TableColumn... fixedColumns) {
353+
table.addControlListener(new ControlAdapter() {
354+
@Override
355+
public void controlResized(ControlEvent e) {
356+
int remainingWidth = table.getClientArea().width;
357+
for (TableColumn fixedColumn : fixedColumns) {
358+
remainingWidth -= fixedColumn.getWidth();
359+
}
360+
if (remainingWidth > minWidth) {
361+
fillColumn.setWidth(remainingWidth);
362+
}
363+
}
364+
});
365+
}
366+
275367
/**
276368
* Copy the given text to the clipboard.
277369
*/

0 commit comments

Comments
 (0)