diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledText.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledText.java index 3d22f3fa3f8..0a052957681 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledText.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledText.java @@ -1077,31 +1077,47 @@ void calculateTopIndex(int delta) { } } } else { + int lineCount = content.getLineCount(); if (delta >= 0) { delta -= topIndexY; - int lineIndex = topIndex; - int lineCount = content.getLineCount(); + int lineIndex = Math.max(0, topIndex); while (lineIndex < lineCount) { if (delta <= 0) break; - delta -= renderer.getCachedLineHeight(lineIndex++); + delta -= renderer.getCachedLineHeight(lineIndex); + lineIndex++; + } + int lineHeight = 0; + if (lineExists(lineIndex)) { + lineHeight = renderer.getCachedLineHeight(lineIndex); } - if (lineIndex < lineCount && -delta + renderer.getCachedLineHeight(lineIndex) <= clientAreaHeight - topMargin - bottomMargin) { + if (lineIndex < lineCount && -delta + lineHeight <= clientAreaHeight - topMargin - bottomMargin) { topIndex = lineIndex; topIndexY = -delta; } else { topIndex = lineIndex - 1; - topIndexY = -renderer.getCachedLineHeight(topIndex) - delta; + if (lineExists(topIndex)) { + topIndexY = -renderer.getCachedLineHeight(topIndex); + } + topIndexY -= delta; } } else { delta -= topIndexY; int lineIndex = topIndex; while (lineIndex > 0) { - int lineHeight = renderer.getCachedLineHeight(lineIndex - 1); + int previousLineIndex = lineIndex - 1; + int lineHeight = 0; + if (lineExists(previousLineIndex)) { + lineHeight = renderer.getCachedLineHeight(previousLineIndex); + } if (delta + lineHeight > 0) break; delta += lineHeight; lineIndex--; } - if (lineIndex == 0 || -delta + renderer.getCachedLineHeight(lineIndex) <= clientAreaHeight - topMargin - bottomMargin) { + int lineHeight = 0; + if (lineExists(lineIndex)) { + lineHeight = renderer.getCachedLineHeight(lineIndex); + } + if (lineIndex == 0 || -delta + lineHeight <= clientAreaHeight - topMargin - bottomMargin) { topIndex = lineIndex; topIndexY = - delta; } else { @@ -1379,14 +1395,24 @@ int getAvailableHeightAbove(int height) { int lineIndex = topIndex - 1; maxHeight = -topIndexY; if (topIndexY > 0) { - maxHeight += renderer.getLineHeight(lineIndex--); + if (lineExists(lineIndex)) { + maxHeight += renderer.getLineHeight(lineIndex); + } + lineIndex--; } while (height > maxHeight && lineIndex >= 0) { - maxHeight += renderer.getLineHeight(lineIndex--); + if (lineExists(lineIndex)) { + maxHeight += renderer.getLineHeight(lineIndex); + } + lineIndex--; } } return Math.min(height, maxHeight); } +private boolean lineExists(int lineNumber) { + int lineCount = content.getLineCount(); + return lineNumber >= 0 && lineNumber < lineCount; +} int getAvailableHeightBellow(int height) { int partialBottomIndex = getPartialBottomIndex(); int topY = getLinePixel(partialBottomIndex); @@ -3876,11 +3902,13 @@ public int getLinePixel(int lineIndex) { return topIndexY + topMargin; int height = topIndexY; if (lineIndex > topIndex) { - for (int i = topIndex; i < lineIndex; i++) { + for (int i = Math.max(topIndex, 0); i < Math.min(lineIndex, lineCount); i++) { height += renderer.getLineHeight(i); } } else { - for (int i = topIndex - 1; i >= lineIndex; i--) { + int lastLineToConsider = Math.min(topIndex - 1, lineCount - 1); + int firstLineToConsider = Math.max(0, lineIndex); + for (int i = firstLineToConsider; i <= lastLineToConsider; i++) { height -= renderer.getLineHeight(i); } } @@ -3914,10 +3942,18 @@ public int getLineIndex(int y) { } } else { int lineCount = content.getLineCount(); - int lineHeight = renderer.getLineHeight(line); + int lineHeight = 0; + if (lineExists(line)) { + lineHeight = renderer.getLineHeight(line); + } while (y - lineHeight >= topIndexY && line < lineCount - 1) { y -= lineHeight; - lineHeight = renderer.getLineHeight(++line); + ++line; + if (lineExists(line)) { + lineHeight = renderer.getLineHeight(line); + }else { + lineHeight = 0; + } } } return line; @@ -7818,7 +7854,7 @@ void resetCache(SortedSet lines) { int maxLineIndex = renderer.maxWidthLineIndex; renderer.reset(lines); renderer.calculateClientArea(); - if (0 <= maxLineIndex && maxLineIndex < content.getLineCount()) { + if (lineExists(maxLineIndex)) { renderer.calculate(maxLineIndex, 1); } setScrollBars(true); @@ -7833,7 +7869,7 @@ void resetCache(int firstLine, int count) { int maxLineIndex = renderer.maxWidthLineIndex; renderer.reset(firstLine, count); renderer.calculateClientArea(); - if (0 <= maxLineIndex && maxLineIndex < content.getLineCount()) { + if (lineExists(maxLineIndex)) { renderer.calculate(maxLineIndex, 1); } setScrollBars(true); diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_custom_StyledText.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_custom_StyledText.java index 125cb014724..62b3af33a01 100644 --- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_custom_StyledText.java +++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_custom_StyledText.java @@ -70,6 +70,7 @@ import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.internal.BidiUtil; +import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.printing.Printer; @@ -77,6 +78,7 @@ import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.ScrollBar; +import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.Widget; import org.junit.Assume; import org.junit.Before; @@ -195,6 +197,35 @@ public void test_getTextBounds() { } } +@Test +public void test_replaceTextRangeWithVariableHeight() { + shell.setLayout(new FillLayout()); + StyledText styledText = new StyledText(shell, SWT.BORDER | SWT.V_SCROLL); + Text text = new Text(shell, SWT.BORDER); + try { + String lines = IntStream.range(0, 10) + .collect(StringBuilder::new, (s, i) -> s.append("line " + (i + 1) + "\n"), StringBuilder::append).toString(); + styledText.setText(lines); + StyleRange style = new StyleRange(); + style.start = 0; + style.length = lines.length(); + style.font = styledText.getFont(); // To make the line-height non-fixed + styledText.setStyleRange(style); + + shell.setSize(100, 3 * styledText.getLineHeight()); + shell.open(); + + text.setFocus(); + styledText.setTopIndex(styledText.getLineCount() - 1); + assertFalse(styledText.isFocusControl()); + // ensure no IllegalArgumentException is thrown when styledText control has not the focus and the text is replaced + styledText.replaceTextRange(0, styledText.getCharCount(), ""); + }finally { + styledText.dispose(); + text.dispose(); + } +} + @Test public void test_addExtendedModifyListenerLorg_eclipse_swt_custom_ExtendedModifyListener() { final String line = "Line1";