diff options
| author | Paul Pazderski | 2020-05-01 22:38:01 +0000 |
|---|---|---|
| committer | Paul Pazderski | 2020-05-07 20:29:56 +0000 |
| commit | 984bc060c83d55b3781435a1a966fafadd029ab2 (patch) | |
| tree | 420c14fe10d161d6fbfeeb134ae6bac44fd3d35f | |
| parent | 6ea564799a0ab24cce1db9b46541acaff0727774 (diff) | |
| download | eclipse.platform.swt-984bc060c83d55b3781435a1a966fafadd029ab2.tar.gz eclipse.platform.swt-984bc060c83d55b3781435a1a966fafadd029ab2.tar.xz eclipse.platform.swt-984bc060c83d55b3781435a1a966fafadd029ab2.zip | |
Bug 499215 - Chevron is wrapped to new line
The failure can also appear when min or max button is added to a visible
CTabFolder.
Precondition for this failure is that all CTabItems are smaller in
height than the icon + margins. When the min/max is to be shown the
following happened before this change:
- tab bar height is recalculated
- min/max button is created and bounds calculated (at once)
The fix for that scenario is to split the one button handling method
into a button creation and bounds calculation method and reorder the
invocation to: create button, updateTabHeight (which now consider the
created buttons) and set button bounds.
Situation for chevron is a bit more complicate because the decision if a
chevron is shown depends on the item size calculation which already
require the tab bar height.
The fix is similar to the previous. If chevron is added/removed the tab
bar height has to be recalculated for the case it changed from the
changed chevron.
Change-Id: I1fffac97333c4414ca0dc1394ea87377f12e74fb
Signed-off-by: Paul Pazderski <paul-eclipse@ppazderski.de>
2 files changed, 122 insertions, 11 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 7ee1a40016..86fac25b9f 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 @@ -784,9 +784,8 @@ void destroyItem (CTabItem item) { control.setVisible(false); } setToolTipText(null); - GC gc = new GC(this); - setButtonBounds(gc); - gc.dispose(); + updateButtons(); + setButtonBounds(); redraw(); return; } @@ -2497,8 +2496,11 @@ public void setBorderVisible(boolean show) { this.borderVisible = show; updateFolder(REDRAW); } -void setButtonBounds(GC gc) { - Point size = getSize(); + +/** + * Create or dispose min/max buttons. + */ +void updateButtons() { // max button Display display = getDisplay(); if (showMax) { @@ -2551,10 +2553,17 @@ void setButtonBounds(GC gc) { minMaxTb.dispose(); minMaxTb = null; } +} + +/** + * Update button bounds for min/max and update chevron button. + */ +void setButtonBounds() { if (showChevron) { updateChevronImage(false); } + Point size = getSize(); boolean[][] overflow = new boolean[1][0]; Rectangle[] rects = computeControlBounds(size, overflow); if (fixedTabHeight != SWT.DEFAULT) { @@ -3826,9 +3835,17 @@ boolean updateItems (int showIndex) { boolean oldShowChevron = showChevron; boolean changed = setItemSize(gc); + updateButtons(); + boolean chevronChanged = showChevron != oldShowChevron; + if (chevronChanged) { + if (updateTabHeight(false)) { + // Tab height has changed. Item sizes have to be set again. + changed |= setItemSize(gc); + } + } changed |= setItemLocation(gc); - setButtonBounds(gc); - changed |= showChevron != oldShowChevron; + setButtonBounds(); + changed |= chevronChanged; if (changed && getToolTipText() != null) { Point pt = getDisplay().getCursorLocation(); pt = toControl(pt); @@ -3872,6 +3889,7 @@ void runUpdate() { int flags = updateFlags; updateFlags = 0; Rectangle rectBefore = getClientArea(); + updateButtons(); updateTabHeight(false); updateItems(selectedIndex); if ((flags & REDRAW) != 0) { diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_custom_CTabFolder.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_custom_CTabFolder.java index eeced27d3c..8f0743c425 100644 --- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_custom_CTabFolder.java +++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_custom_CTabFolder.java @@ -44,6 +44,7 @@ import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.ToolBar; import org.eclipse.swt.widgets.ToolItem; @@ -122,8 +123,12 @@ private void makeCleanEnvironment(int style) { } private void createTabFolder(List<String> events) { + createTabFolder(events, 3); +} + +private void createTabFolder(List<String> events, int numItems) { makeCleanEnvironment(); - for (int i = 0; i < 3; i++) { + for (int i = 0; i < numItems; i++) { CTabItem item = new CTabItem(ctabFolder, SWT.NONE); item.setText("CTabItem &" + i); item.setToolTipText("CTabItem ToolTip" + i); @@ -285,6 +290,7 @@ public void test_chevronAppearanceChanged() { ToolItem chevron = showChevron(); Image oldChevronImg = new Image(display, chevron.getImage(), SWT.IMAGE_COPY); + Font newFont = null; try { ctabFolder.setForeground(display.getSystemColor(SWT.COLOR_DARK_GREEN)); Image newChevronImg = chevron.getImage(); @@ -296,12 +302,15 @@ public void test_chevronAppearanceChanged() { FontData[] existingFontData = ctabFolder.getFont().getFontData(); existingFontData[0].setName(SwtTestUtil.testFontName); existingFontData[0].setStyle(SWT.BOLD | SWT.ITALIC); - Font newFont = new Font(display, existingFontData); + newFont = new Font(display, existingFontData); ctabFolder.setFont(newFont); newChevronImg = chevron.getImage(); ImageTestUtil.assertImagesNotEqual(oldChevronImg.getImageData(), newChevronImg.getImageData()); } finally { oldChevronImg.dispose(); + if (newFont != null) { + newFont.dispose(); + } } } @@ -381,6 +390,37 @@ public void test_childControlOverlap() { setTopRightAndCheckOverlap.accept(null, 0); } +/** + * Min/max and chevron icon can appear below tab row. + * Test for bug 499215, 533582. + */ +@Test +public void test_iconWrappedOnNextLine() { + createTabFolder(null); + + FontData[] existingFontData = ctabFolder.getFont().getFontData(); + existingFontData[0].setName(SwtTestUtil.testFontName); + existingFontData[0].setHeight(3); + Font smallFont = new Font(ctabFolder.getDisplay(), existingFontData); + try { + SwtTestUtil.openShell(shell); + ctabFolder.setFont(smallFont); + + ctabFolder.setMaximizeVisible(true); + processEvents(); + assertTabElementsInLine(); + + createTabFolder(null, 20); + ctabFolder.setFont(smallFont); + shell.layout(true, true); + showChevron(); + processEvents(); + assertTabElementsInLine(); + } finally { + smallFont.dispose(); + } +} + private void processEvents() { Display display = shell.getDisplay(); @@ -422,9 +462,13 @@ private ToolItem showChevron() { itemWidth += item.getBounds().width; } // resize shell to force a chevron - shell.setSize(itemWidth*3/4, shell.getSize().y); + int newWidth = itemWidth*3/4; + shell.setSize(newWidth, shell.getSize().y); + boolean resizeFailed = Math.abs(newWidth - shell.getSize().x) > 10; ToolItem chevron = getChevron(ctabFolder); - assertNotNull("Chevron not shown", chevron); + assertNotNull("Chevron not shown" + (resizeFailed + ? ". Shell could not be resized to the desired size. Tab row width might be smaller than the minimum shell width." + : ""), chevron); return chevron; } @@ -498,4 +542,53 @@ private static Control[] reflection_getChildControls(CTabFolder tabFolder) { } } +/** + * Check if all CTabItems and toolbar icons like min/max, chevron are all in one line and not wrapped. + */ +private void assertTabElementsInLine() { + List<Rectangle> tabBarElementBounds = new ArrayList<>(); + Arrays.stream(ctabFolder.getItems()).filter(CTabItem::isShowing).map(this::getBoundsInShell).forEach(tabBarElementBounds::add); + for (Control child : ctabFolder.getChildren()) { + if (child instanceof ToolBar) { + for (ToolItem toolItem : ((ToolBar)child).getItems()) { + if (toolItem.getImage() != null) { + tabBarElementBounds.add(getBoundsInShell(toolItem)); + } + } + } + } + Rectangle maxBound = tabBarElementBounds.get(0); + for (Rectangle bound : tabBarElementBounds) { + if (bound.height > maxBound.height) { + assertTrue("Element at " + maxBound + " is not on line.", bound.y <= maxBound.y && bound.y + bound.height >= maxBound.y + maxBound.height); + maxBound = bound; + } else { + assertTrue("Element at " + bound + " is not on line.", bound.y >= maxBound.y && bound.y + bound.height <= maxBound.y + maxBound.height); + } + } +} + +private Rectangle getBoundsInShell(Widget control) { + Control parent; + Rectangle bounds; + if (control instanceof Control) { + parent = ((Control)control).getParent(); + bounds = ((Control)control).getBounds(); + } else if (control instanceof CTabItem) { + parent = ((CTabItem)control).getParent(); + bounds = ((CTabItem)control).getBounds(); + } else if (control instanceof ToolItem) { + parent = ((ToolItem)control).getParent(); + bounds = ((ToolItem)control).getBounds(); + } else { + throw new UnsupportedOperationException("Widget must provide bounds and parent"); + } + if (parent != null && !(parent instanceof Shell)) { + Rectangle absParentBound = getBoundsInShell(parent); + bounds.x += absParentBound.x; + bounds.y += absParentBound.y; + } + return bounds; +} + } |
