From 0f590d7a63826c2e78f32e3fa27cac129940e730 Mon Sep 17 00:00:00 2001 From: Lars Vogel Date: Thu, 19 Mar 2026 16:30:00 +0100 Subject: [PATCH 1/3] Add dirty indicator bullet style for CTabFolder tabs When enabled via CTabFolder.setDirtyIndicatorCloseStyle(true), dirty tabs show a filled circle at the close button location instead of the traditional '*' prefix. The bullet transforms into the close button on hover, matching the behavior of VS Code and similar editors. This is opt-in (disabled by default) to preserve backward compatibility. The feature adds: - CTabFolder.setDirtyIndicatorCloseStyle(boolean) / getDirtyIndicatorCloseStyle() - CTabItem.setShowDirty(boolean) / getShowDirty() - Rendering via fillOval for cross-platform consistency - Snippet391 demonstrating the feature Based on the approach from PR #1632 by schneidermic0, with fixes for the copy-paste bug, preference toggle support per PMC request, and fillOval rendering instead of drawString for pixel-perfect results. See: https://github.com/eclipse-platform/eclipse.platform.swt/pull/1632 Co-Authored-By: Claude Opus 4.6 --- .../org/eclipse/swt/custom/CTabFolder.java | 55 ++++++++++++++-- .../swt/custom/CTabFolderRenderer.java | 53 ++++++++++++--- .../org/eclipse/swt/custom/CTabItem.java | 44 +++++++++++++ .../org/eclipse/swt/snippets/Snippet393.java | 66 +++++++++++++++++++ .../Test_org_eclipse_swt_custom_CTabItem.java | 20 ++++++ 5 files changed, 225 insertions(+), 13 deletions(-) create mode 100644 examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet393.java diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java index 23717891c7b..fb9751b4f64 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java @@ -199,6 +199,7 @@ public class CTabFolder extends Composite { // close, min/max and chevron buttons boolean showClose = false; boolean showUnselectedClose = true; + boolean dirtyIndicatorStyle = false; boolean showMin = false; boolean minimized = false; @@ -2791,7 +2792,7 @@ boolean setItemLocation(GC gc) { item.x = leftItemEdge; item.y = y; item.showing = true; - if (showClose || item.showClose) { + if (showClose || item.showClose || (dirtyIndicatorStyle && item.showDirty)) { item.closeRect.x = leftItemEdge - renderer.computeTrim(i, SWT.NONE, 0, 0, 0, 0).x; item.closeRect.y = onBottom ? size.y - borderBottom - tabHeight + (tabHeight - closeButtonSize.y)/2: borderTop + (tabHeight - closeButtonSize.y)/2; } @@ -2892,7 +2893,7 @@ boolean setItemSize(GC gc) { tab.height = tabHeight; tab.width = width; tab.closeRect.width = tab.closeRect.height = 0; - if (showClose || tab.showClose) { + if (showClose || tab.showClose || (dirtyIndicatorStyle && tab.showDirty)) { Point closeSize = renderer.computeSize(CTabFolderRenderer.PART_CLOSE_BUTTON, SWT.SELECTED, gc, SWT.DEFAULT, SWT.DEFAULT); tab.closeRect.width = closeSize.x; tab.closeRect.height = closeSize.y; @@ -2976,8 +2977,8 @@ boolean setItemSize(GC gc) { tab.height = tabHeight; tab.width = width; tab.closeRect.width = tab.closeRect.height = 0; - if (showClose || tab.showClose) { - if (i == selectedIndex || showUnselectedClose) { + if (showClose || tab.showClose || (dirtyIndicatorStyle && tab.showDirty)) { + if (i == selectedIndex || showUnselectedClose || (dirtyIndicatorStyle && tab.showDirty)) { Point closeSize = renderer.computeSize(CTabFolderRenderer.PART_CLOSE_BUTTON, SWT.NONE, gc, SWT.DEFAULT, SWT.DEFAULT); tab.closeRect.width = closeSize.x; tab.closeRect.height = closeSize.y; @@ -3662,6 +3663,50 @@ public void setUnselectedCloseVisible(boolean visible) { showUnselectedClose = visible; updateFolder(REDRAW); } +/** + * Sets whether the dirty indicator uses the close button style. When enabled, + * dirty items (marked via {@link CTabItem#setShowDirty(boolean)}) show a + * bullet dot at the close button location instead of the traditional + * * prefix. The bullet transforms into the close button on hover. + *

+ * The default value is false (traditional * prefix + * behavior). + *

+ * + * @param useCloseButtonStyle true to use the bullet-on-close-button + * style for dirty indicators + * + * @exception SWTException + * + * @see CTabItem#setShowDirty(boolean) + * @since 3.134 + */ +public void setDirtyIndicatorCloseStyle(boolean useCloseButtonStyle) { + checkWidget(); + if (dirtyIndicatorStyle == useCloseButtonStyle) return; + dirtyIndicatorStyle = useCloseButtonStyle; + updateFolder(REDRAW_TABS); +} +/** + * Returns whether the dirty indicator uses the close button style. + * + * @return true if the dirty indicator uses the close button style + * + * @exception SWTException + * + * @see #setDirtyIndicatorCloseStyle(boolean) + * @since 3.134 + */ +public boolean getDirtyIndicatorCloseStyle() { + checkWidget(); + return dirtyIndicatorStyle; +} /** * Specify whether the image appears on unselected tabs. * @@ -3996,7 +4041,7 @@ String _getToolTip(int x, int y) { CTabItem item = getItem(new Point (x, y)); if (item == null) return null; if (!item.showing) return null; - if ((showClose || item.showClose) && item.closeRect.contains(x, y)) { + if ((showClose || item.showClose || (dirtyIndicatorStyle && item.showDirty)) && item.closeRect.contains(x, y)) { return SWT.getMessage("SWT_Close"); //$NON-NLS-1$ } return item.getToolTipText(); diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolderRenderer.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolderRenderer.java index b0908703e81..d765689481d 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolderRenderer.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolderRenderer.java @@ -265,7 +265,7 @@ protected Point computeSize (int part, int state, GC gc, int wHint, int hHint) { if (shouldApplyLargeTextPadding(parent)) { width += getLargeTextPadding(item) * 2; - } else if (shouldDrawCloseIcon(item)) { + } else if (shouldAllocateCloseRect(item)) { if (width > 0) width += INTERNAL_SPACING; width += computeSize(PART_CLOSE_BUTTON, SWT.NONE, gc, SWT.DEFAULT, SWT.DEFAULT).x; } @@ -285,6 +285,15 @@ private boolean shouldDrawCloseIcon(CTabItem item) { return showClose && isSelectedOrShowCloseForUnselected; } + private boolean shouldDrawDirtyIndicator(CTabItem item) { + CTabFolder folder = item.getParent(); + return folder.dirtyIndicatorStyle && item.showDirty; + } + + private boolean shouldAllocateCloseRect(CTabItem item) { + return shouldDrawCloseIcon(item) || shouldDrawDirtyIndicator(item); + } + /** * Returns padding for the text of a tab item when showing images is disabled for the tab folder. */ @@ -692,8 +701,21 @@ void drawBody(GC gc, Rectangle bounds, int state) { } void drawClose(GC gc, Rectangle closeRect, int closeImageState) { + drawClose(gc, closeRect, closeImageState, false); + } + + void drawClose(GC gc, Rectangle closeRect, int closeImageState, boolean showDirtyIndicator) { if (closeRect.width == 0 || closeRect.height == 0) return; + // When dirty and not hovered/pressed, draw bullet instead of X + if (showDirtyIndicator) { + int maskedState = closeImageState & (SWT.HOT | SWT.SELECTED | SWT.BACKGROUND); + if (maskedState != SWT.HOT && maskedState != SWT.SELECTED) { + drawDirtyIndicator(gc, closeRect); + return; + } + } + // draw X with length of this constant final int lineLength = 8; int x = closeRect.x + Math.max(1, (closeRect.width-lineLength)/2); @@ -724,6 +746,17 @@ void drawClose(GC gc, Rectangle closeRect, int closeImageState) { gc.setForeground(originalForeground); } + private void drawDirtyIndicator(GC gc, Rectangle closeRect) { + int diameter = 8; + int x = closeRect.x + (closeRect.width - diameter) / 2; + int y = closeRect.y + (closeRect.height - diameter) / 2; + y += parent.onBottom ? -1 : 1; + Color originalBackground = gc.getBackground(); + gc.setBackground(gc.getForeground()); + gc.fillOval(x, y, diameter, diameter); + gc.setBackground(originalBackground); + } + private void drawCloseLines(GC gc, int x, int y, int lineLength, boolean hot) { if (hot) { gc.setLineWidth(gc.getLineWidth() + 2); @@ -1070,7 +1103,7 @@ void drawSelected(int itemIndex, GC gc, Rectangle bounds, int state ) { // draw Image Rectangle trim = computeTrim(itemIndex, SWT.NONE, 0, 0, 0, 0); int xDraw = x - trim.x; - if (parent.single && shouldDrawCloseIcon(item)) xDraw += item.closeRect.width; + if (parent.single && shouldAllocateCloseRect(item)) xDraw += item.closeRect.width; Image image = item.getImage(); if (image != null && !image.isDisposed() && parent.showSelectedImage) { Rectangle imageBounds = image.getBounds(); @@ -1118,7 +1151,9 @@ void drawSelected(int itemIndex, GC gc, Rectangle bounds, int state ) { gc.setBackground(orginalBackground); } } - if (shouldDrawCloseIcon(item)) drawClose(gc, item.closeRect, item.closeImageState); + if (shouldAllocateCloseRect(item)) { + drawClose(gc, item.closeRect, item.closeImageState, shouldDrawDirtyIndicator(item)); + } } } @@ -1126,7 +1161,7 @@ private int getLeftTextMargin(CTabItem item) { int margin = 0; if (shouldApplyLargeTextPadding(parent)) { margin += getLargeTextPadding(item); - if (shouldDrawCloseIcon(item)) { + if (shouldAllocateCloseRect(item)) { margin -= item.closeRect.width / 2; } } @@ -1264,7 +1299,7 @@ void drawUnselected(int index, GC gc, Rectangle bounds, int state) { Rectangle imageBounds = image.getBounds(); // only draw image if it won't overlap with close button int maxImageWidth = x + width - xDraw - (trim.width + trim.x); - if (shouldDrawCloseIcon(item)) { + if (shouldAllocateCloseRect(item)) { maxImageWidth -= item.closeRect.width + INTERNAL_SPACING; } if (imageBounds.width < maxImageWidth) { @@ -1280,7 +1315,7 @@ void drawUnselected(int index, GC gc, Rectangle bounds, int state) { // draw Text xDraw += getLeftTextMargin(item); int textWidth = x + width - xDraw - (trim.width + trim.x); - if (shouldDrawCloseIcon(item)) { + if (shouldAllocateCloseRect(item)) { textWidth -= item.closeRect.width + INTERNAL_SPACING; } if (textWidth > 0) { @@ -1297,8 +1332,10 @@ void drawUnselected(int index, GC gc, Rectangle bounds, int state) { gc.drawText(item.shortenedText, xDraw, textY, FLAGS); gc.setFont(gcFont); } - // draw close - if (shouldDrawCloseIcon(item)) drawClose(gc, item.closeRect, item.closeImageState); + // draw close or dirty indicator + if (shouldAllocateCloseRect(item)) { + drawClose(gc, item.closeRect, item.closeImageState, shouldDrawDirtyIndicator(item)); + } } } diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabItem.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabItem.java index 24aa3e17725..2b4f518ffb2 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabItem.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabItem.java @@ -55,6 +55,7 @@ public class CTabItem extends Item { int closeImageState = SWT.BACKGROUND; int state = SWT.NONE; boolean showClose = false; + boolean showDirty = false; boolean showing = false; /** @@ -276,6 +277,26 @@ public boolean getShowClose() { checkWidget(); return showClose; } +/** + * Returns true to indicate that the receiver is dirty + * (has unsaved changes). When the parent folder's dirty indicator style + * is enabled, dirty items show a bullet dot at the close button location + * instead of the default * prefix. + * + * @return true if the item is marked as dirty + * + * @exception SWTException + * + * @see CTabFolder#setDirtyIndicatorCloseStyle(boolean) + * @since 3.134 + */ +public boolean getShowDirty() { + checkWidget(); + return showDirty; +} /** * Returns the receiver's tool tip text, or null if it has * not been set. @@ -490,6 +511,29 @@ public void setShowClose(boolean close) { showClose = close; parent.updateFolder(CTabFolder.REDRAW_TABS); } +/** + * Marks this item as dirty (having unsaved changes). When the parent + * folder's dirty indicator style is enabled via + * {@link CTabFolder#setDirtyIndicatorCloseStyle(boolean)}, dirty items + * show a bullet dot at the close button location. The bullet transforms + * into the close button on hover. + * + * @param dirty true to mark the item as dirty + * + * @exception SWTException + * + * @see CTabFolder#setDirtyIndicatorCloseStyle(boolean) + * @since 3.134 + */ +public void setShowDirty(boolean dirty) { + checkWidget(); + if (showDirty == dirty) return; + showDirty = dirty; + parent.updateFolder(CTabFolder.REDRAW_TABS); +} /** * Sets the text to display on the tab. * A carriage return '\n' allows to display multi line text. diff --git a/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet393.java b/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet393.java new file mode 100644 index 00000000000..07d922d6dd9 --- /dev/null +++ b/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet393.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.swt.snippets; + +/* + * CTabFolder example: dirty indicator using bullet dot on close button + * + * For a list of all SWT example snippets see + * http://www.eclipse.org/swt/snippets/ + */ +import org.eclipse.swt.*; +import org.eclipse.swt.custom.*; +import org.eclipse.swt.layout.*; +import org.eclipse.swt.widgets.*; + +public class Snippet393 { + public static void main(String[] args) { + Display display = new Display(); + Shell shell = new Shell(display); + shell.setLayout(new GridLayout()); + shell.setText("CTabFolder Dirty Indicator"); + + CTabFolder folder = new CTabFolder(shell, SWT.CLOSE | SWT.BORDER); + folder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + folder.setDirtyIndicatorCloseStyle(true); + + for (int i = 0; i < 4; i++) { + CTabItem item = new CTabItem(folder, SWT.NONE); + item.setText("Tab " + i); + Text text = new Text(folder, SWT.MULTI | SWT.WRAP); + text.setText("Content for tab " + i); + item.setControl(text); + } + + // Mark tabs 0 and 2 as dirty + folder.getItem(0).setShowDirty(true); + folder.getItem(2).setShowDirty(true); + folder.setSelection(0); + + Button toggleButton = new Button(shell, SWT.PUSH); + toggleButton.setText("Toggle dirty on selected tab"); + toggleButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + toggleButton.addListener(SWT.Selection, e -> { + CTabItem selected = folder.getSelection(); + if (selected != null) { + selected.setShowDirty(!selected.getShowDirty()); + } + }); + + shell.setSize(400, 300); + shell.open(); + while (!shell.isDisposed()) { + if (!display.readAndDispatch()) + display.sleep(); + } + display.dispose(); + } +} diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_custom_CTabItem.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_custom_CTabItem.java index 25fe59923ae..3f6e9e201cd 100644 --- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_custom_CTabItem.java +++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_custom_CTabItem.java @@ -14,6 +14,8 @@ package org.eclipse.swt.tests.junit; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.CTabFolder; @@ -76,4 +78,22 @@ public void test_setSelectionForegroundLorg_eclipse_swt_graphics_Color() { cTabItem.setSelectionForeground(null); assertEquals(red, cTabItem.getSelectionForeground()); } + +@Test +public void test_setShowDirty() { + assertFalse(cTabItem.getShowDirty()); + cTabItem.setShowDirty(true); + assertTrue(cTabItem.getShowDirty()); + cTabItem.setShowDirty(false); + assertFalse(cTabItem.getShowDirty()); +} + +@Test +public void test_dirtyIndicatorCloseStyle() { + assertFalse(cTabFolder.getDirtyIndicatorCloseStyle()); + cTabFolder.setDirtyIndicatorCloseStyle(true); + assertTrue(cTabFolder.getDirtyIndicatorCloseStyle()); + cTabFolder.setDirtyIndicatorCloseStyle(false); + assertFalse(cTabFolder.getDirtyIndicatorCloseStyle()); +} } \ No newline at end of file From 74d48e30cdab5bbdddc1884ddc7ef44ffcc21b88 Mon Sep 17 00:00:00 2001 From: Lars Vogel Date: Thu, 26 Mar 2026 11:42:53 +0100 Subject: [PATCH 2/3] Fix dirty indicator pixel offset, add theme-switching snippet, fix test EOF - Remove spurious y+1/-1 offset in drawDirtyIndicator; the oval is already centered from closeRect bounds, unlike the X drawing which needs the nudge due to its Math.max(1,...) coordinate logic - Extend Snippet393 with a dark/light theme toggle button to demonstrate that the dirty bullet color adapts to the tab foreground color - Add missing newline at end of Test_org_eclipse_swt_custom_CTabItem.java Co-Authored-By: Claude Sonnet 4.6 --- .../swt/custom/CTabFolderRenderer.java | 1 - .../org/eclipse/swt/snippets/Snippet393.java | 43 ++++++++++++++++++- .../Test_org_eclipse_swt_custom_CTabItem.java | 2 +- 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolderRenderer.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolderRenderer.java index d765689481d..fa5c72407b8 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolderRenderer.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolderRenderer.java @@ -750,7 +750,6 @@ private void drawDirtyIndicator(GC gc, Rectangle closeRect) { int diameter = 8; int x = closeRect.x + (closeRect.width - diameter) / 2; int y = closeRect.y + (closeRect.height - diameter) / 2; - y += parent.onBottom ? -1 : 1; Color originalBackground = gc.getBackground(); gc.setBackground(gc.getForeground()); gc.fillOval(x, y, diameter, diameter); diff --git a/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet393.java b/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet393.java index 07d922d6dd9..eaded3f5337 100644 --- a/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet393.java +++ b/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet393.java @@ -11,13 +11,15 @@ package org.eclipse.swt.snippets; /* - * CTabFolder example: dirty indicator using bullet dot on close button + * CTabFolder example: dirty indicator using bullet dot on close button, + * with runtime dark/light theme switching to show color adaptation. * * For a list of all SWT example snippets see * http://www.eclipse.org/swt/snippets/ */ import org.eclipse.swt.*; import org.eclipse.swt.custom.*; +import org.eclipse.swt.graphics.*; import org.eclipse.swt.layout.*; import org.eclipse.swt.widgets.*; @@ -55,6 +57,45 @@ public static void main(String[] args) { } }); + boolean[] isDark = {false}; + Button toggleThemeButton = new Button(shell, SWT.PUSH); + toggleThemeButton.setText("Switch to Dark Theme"); + toggleThemeButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + toggleThemeButton.addListener(SWT.Selection, e -> { + isDark[0] = !isDark[0]; + if (isDark[0]) { + Color tabBg = new Color(display, 43, 43, 43); + Color selBg = new Color(display, 60, 63, 65); + Color contentBg = new Color(display, 30, 30, 30); + Color fg = new Color(display, 187, 187, 187); + folder.setBackground(tabBg); + folder.setForeground(fg); + folder.setSelectionBackground(selBg); + folder.setSelectionForeground(fg); + for (int i = 0; i < folder.getItemCount(); i++) { + Control ctrl = folder.getItem(i).getControl(); + if (ctrl != null) { + ctrl.setBackground(contentBg); + ctrl.setForeground(fg); + } + } + toggleThemeButton.setText("Switch to Light Theme"); + } else { + folder.setBackground(null); + folder.setForeground(null); + folder.setSelectionBackground((Color) null); + folder.setSelectionForeground(null); + for (int i = 0; i < folder.getItemCount(); i++) { + Control ctrl = folder.getItem(i).getControl(); + if (ctrl != null) { + ctrl.setBackground(null); + ctrl.setForeground(null); + } + } + toggleThemeButton.setText("Switch to Dark Theme"); + } + }); + shell.setSize(400, 300); shell.open(); while (!shell.isDisposed()) { diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_custom_CTabItem.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_custom_CTabItem.java index 3f6e9e201cd..baec16653b3 100644 --- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_custom_CTabItem.java +++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_custom_CTabItem.java @@ -96,4 +96,4 @@ public void test_dirtyIndicatorCloseStyle() { cTabFolder.setDirtyIndicatorCloseStyle(false); assertFalse(cTabFolder.getDirtyIndicatorCloseStyle()); } -} \ No newline at end of file +} From 6212db051f373f0fdfbd54e814487e6908957d71 Mon Sep 17 00:00:00 2001 From: Lars Vogel Date: Thu, 26 Mar 2026 12:00:21 +0100 Subject: [PATCH 3/3] Rename setDirtyIndicatorCloseStyle to setDirtyIndicatorStyle "CloseStyle" leaks the implementation detail that the bullet occupies the close button area. The shorter name describes the feature, not the mechanism. Co-Authored-By: Claude Sonnet 4.6 --- .../org/eclipse/swt/custom/CTabFolder.java | 19 +++++++++---------- .../org/eclipse/swt/custom/CTabItem.java | 6 +++--- .../org/eclipse/swt/snippets/Snippet393.java | 2 +- .../Test_org_eclipse_swt_custom_CTabItem.java | 10 +++++----- 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java index fb9751b4f64..50b089f99b7 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java @@ -3664,7 +3664,7 @@ public void setUnselectedCloseVisible(boolean visible) { updateFolder(REDRAW); } /** - * Sets whether the dirty indicator uses the close button style. When enabled, + * Sets whether the dirty indicator style is enabled. When enabled, * dirty items (marked via {@link CTabItem#setShowDirty(boolean)}) show a * bullet dot at the close button location instead of the traditional * * prefix. The bullet transforms into the close button on hover. @@ -3673,8 +3673,7 @@ public void setUnselectedCloseVisible(boolean visible) { * behavior). *

* - * @param useCloseButtonStyle true to use the bullet-on-close-button - * style for dirty indicators + * @param enabled true to enable the dirty indicator style * * @exception SWTException
    *
  • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
  • @@ -3684,26 +3683,26 @@ public void setUnselectedCloseVisible(boolean visible) { * @see CTabItem#setShowDirty(boolean) * @since 3.134 */ -public void setDirtyIndicatorCloseStyle(boolean useCloseButtonStyle) { +public void setDirtyIndicatorStyle(boolean enabled) { checkWidget(); - if (dirtyIndicatorStyle == useCloseButtonStyle) return; - dirtyIndicatorStyle = useCloseButtonStyle; + if (dirtyIndicatorStyle == enabled) return; + dirtyIndicatorStyle = enabled; updateFolder(REDRAW_TABS); } /** - * Returns whether the dirty indicator uses the close button style. + * Returns whether the dirty indicator style is enabled. * - * @return true if the dirty indicator uses the close button style + * @return true if the dirty indicator style is enabled * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * - * @see #setDirtyIndicatorCloseStyle(boolean) + * @see #setDirtyIndicatorStyle(boolean) * @since 3.134 */ -public boolean getDirtyIndicatorCloseStyle() { +public boolean getDirtyIndicatorStyle() { checkWidget(); return dirtyIndicatorStyle; } diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabItem.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabItem.java index 2b4f518ffb2..895afaef505 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabItem.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabItem.java @@ -290,7 +290,7 @@ public boolean getShowClose() { *
  • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
  • *
* - * @see CTabFolder#setDirtyIndicatorCloseStyle(boolean) + * @see CTabFolder#setDirtyIndicatorStyle(boolean) * @since 3.134 */ public boolean getShowDirty() { @@ -514,7 +514,7 @@ public void setShowClose(boolean close) { /** * Marks this item as dirty (having unsaved changes). When the parent * folder's dirty indicator style is enabled via - * {@link CTabFolder#setDirtyIndicatorCloseStyle(boolean)}, dirty items + * {@link CTabFolder#setDirtyIndicatorStyle(boolean)}, dirty items * show a bullet dot at the close button location. The bullet transforms * into the close button on hover. * @@ -525,7 +525,7 @@ public void setShowClose(boolean close) { *
  • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
  • * * - * @see CTabFolder#setDirtyIndicatorCloseStyle(boolean) + * @see CTabFolder#setDirtyIndicatorStyle(boolean) * @since 3.134 */ public void setShowDirty(boolean dirty) { diff --git a/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet393.java b/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet393.java index eaded3f5337..0f6115be3a7 100644 --- a/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet393.java +++ b/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet393.java @@ -32,7 +32,7 @@ public static void main(String[] args) { CTabFolder folder = new CTabFolder(shell, SWT.CLOSE | SWT.BORDER); folder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - folder.setDirtyIndicatorCloseStyle(true); + folder.setDirtyIndicatorStyle(true); for (int i = 0; i < 4; i++) { CTabItem item = new CTabItem(folder, SWT.NONE); diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_custom_CTabItem.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_custom_CTabItem.java index baec16653b3..5ecb72fe6bd 100644 --- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_custom_CTabItem.java +++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_custom_CTabItem.java @@ -90,10 +90,10 @@ public void test_setShowDirty() { @Test public void test_dirtyIndicatorCloseStyle() { - assertFalse(cTabFolder.getDirtyIndicatorCloseStyle()); - cTabFolder.setDirtyIndicatorCloseStyle(true); - assertTrue(cTabFolder.getDirtyIndicatorCloseStyle()); - cTabFolder.setDirtyIndicatorCloseStyle(false); - assertFalse(cTabFolder.getDirtyIndicatorCloseStyle()); + assertFalse(cTabFolder.getDirtyIndicatorStyle()); + cTabFolder.setDirtyIndicatorStyle(true); + assertTrue(cTabFolder.getDirtyIndicatorStyle()); + cTabFolder.setDirtyIndicatorStyle(false); + assertFalse(cTabFolder.getDirtyIndicatorStyle()); } }