Skip to content

Commit 747348b

Browse files
Fix replaceTextRange logic for unfocused StyledText with variable line
height - Updated productive code to prevent IllegalArgumentException when replacing text in a StyledText control with variable line height and no focus, by adding boundary checks. - Added a regression test to validate the fix: ensures no exception is thrown when replacing the full text range under these conditions. Fixes: #2302
1 parent 95b46b6 commit 747348b

File tree

2 files changed

+78
-9
lines changed

2 files changed

+78
-9
lines changed

bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledText.java

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,31 +1077,50 @@ void calculateTopIndex(int delta) {
10771077
}
10781078
}
10791079
} else {
1080+
int lineCount = content.getLineCount();
10801081
if (delta >= 0) {
10811082
delta -= topIndexY;
10821083
int lineIndex = topIndex;
1083-
int lineCount = content.getLineCount();
10841084
while (lineIndex < lineCount) {
10851085
if (delta <= 0) break;
1086-
delta -= renderer.getCachedLineHeight(lineIndex++);
1086+
if (lineIndex >= 0 && lineIndex < lineCount) {
1087+
delta -= renderer.getCachedLineHeight(lineIndex);
1088+
}
1089+
lineIndex++;
1090+
}
1091+
int lineHeight = 0;
1092+
if (lineIndex >= 0 && lineIndex < lineCount) {
1093+
lineHeight = renderer.getCachedLineHeight(lineIndex);
10871094
}
1088-
if (lineIndex < lineCount && -delta + renderer.getCachedLineHeight(lineIndex) <= clientAreaHeight - topMargin - bottomMargin) {
1095+
if (lineIndex < lineCount && -delta + lineHeight <= clientAreaHeight - topMargin - bottomMargin) {
10891096
topIndex = lineIndex;
10901097
topIndexY = -delta;
10911098
} else {
10921099
topIndex = lineIndex - 1;
1093-
topIndexY = -renderer.getCachedLineHeight(topIndex) - delta;
1100+
int topIndexHeight = 0;
1101+
if (topIndex >= 0 && topIndex < lineCount) {
1102+
topIndexHeight = renderer.getCachedLineHeight(topIndex);
1103+
}
1104+
topIndexY = -topIndexHeight - delta;
10941105
}
10951106
} else {
10961107
delta -= topIndexY;
10971108
int lineIndex = topIndex;
10981109
while (lineIndex > 0) {
1099-
int lineHeight = renderer.getCachedLineHeight(lineIndex - 1);
1110+
int previousLineIndex = lineIndex - 1;
1111+
int lineHeight = 0;
1112+
if (previousLineIndex >= 0 && previousLineIndex < lineCount) {
1113+
lineHeight = renderer.getCachedLineHeight(previousLineIndex);
1114+
}
11001115
if (delta + lineHeight > 0) break;
11011116
delta += lineHeight;
11021117
lineIndex--;
11031118
}
1104-
if (lineIndex == 0 || -delta + renderer.getCachedLineHeight(lineIndex) <= clientAreaHeight - topMargin - bottomMargin) {
1119+
int lineHeight = 0;
1120+
if (lineIndex >= 0 && lineIndex < lineCount) {
1121+
lineHeight = renderer.getCachedLineHeight(lineIndex);
1122+
}
1123+
if (lineIndex == 0 || -delta + lineHeight <= clientAreaHeight - topMargin - bottomMargin) {
11051124
topIndex = lineIndex;
11061125
topIndexY = - delta;
11071126
} else {
@@ -1381,8 +1400,12 @@ int getAvailableHeightAbove(int height) {
13811400
if (topIndexY > 0) {
13821401
maxHeight += renderer.getLineHeight(lineIndex--);
13831402
}
1403+
int lineCount=content.getLineCount();
13841404
while (height > maxHeight && lineIndex >= 0) {
1385-
maxHeight += renderer.getLineHeight(lineIndex--);
1405+
if (lineIndex>=0 && lineIndex<lineCount) {
1406+
maxHeight += renderer.getLineHeight(lineIndex);
1407+
}
1408+
lineIndex--;
13861409
}
13871410
}
13881411
return Math.min(height, maxHeight);
@@ -3877,10 +3900,16 @@ public int getLinePixel(int lineIndex) {
38773900
int height = topIndexY;
38783901
if (lineIndex > topIndex) {
38793902
for (int i = topIndex; i < lineIndex; i++) {
3903+
if (i < 0 || i >= lineCount) {
3904+
continue;
3905+
}
38803906
height += renderer.getLineHeight(i);
38813907
}
38823908
} else {
38833909
for (int i = topIndex - 1; i >= lineIndex; i--) {
3910+
if (i < 0 || i >= lineCount) {
3911+
continue;
3912+
}
38843913
height -= renderer.getLineHeight(i);
38853914
}
38863915
}
@@ -3914,10 +3943,18 @@ public int getLineIndex(int y) {
39143943
}
39153944
} else {
39163945
int lineCount = content.getLineCount();
3917-
int lineHeight = renderer.getLineHeight(line);
3946+
int lineHeight = 0;
3947+
if (line>=0 && line<lineCount) {
3948+
lineHeight = renderer.getLineHeight(line);
3949+
}
39183950
while (y - lineHeight >= topIndexY && line < lineCount - 1) {
39193951
y -= lineHeight;
3920-
lineHeight = renderer.getLineHeight(++line);
3952+
++line;
3953+
if (line >= 0 && line < lineCount) {
3954+
lineHeight = renderer.getLineHeight(line);
3955+
}else {
3956+
lineHeight = 0;
3957+
}
39213958
}
39223959
}
39233960
return line;

tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_custom_StyledText.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,15 @@
7070
import org.eclipse.swt.graphics.RGB;
7171
import org.eclipse.swt.graphics.Rectangle;
7272
import org.eclipse.swt.internal.BidiUtil;
73+
import org.eclipse.swt.layout.FillLayout;
7374
import org.eclipse.swt.layout.GridData;
7475
import org.eclipse.swt.layout.GridLayout;
7576
import org.eclipse.swt.printing.Printer;
7677
import org.eclipse.swt.widgets.Caret;
7778
import org.eclipse.swt.widgets.Display;
7879
import org.eclipse.swt.widgets.Event;
7980
import org.eclipse.swt.widgets.ScrollBar;
81+
import org.eclipse.swt.widgets.Text;
8082
import org.eclipse.swt.widgets.Widget;
8183
import org.junit.Assume;
8284
import org.junit.Before;
@@ -195,6 +197,36 @@ public void test_getTextBounds() {
195197
}
196198
}
197199

200+
@Test
201+
public void test_replaceTextRangeWithVariableHeight() {
202+
shell.setLayout(new FillLayout());
203+
StyledText styledText = new StyledText(shell, SWT.BORDER | SWT.V_SCROLL);
204+
Text text = new Text(shell, SWT.BORDER);
205+
try {
206+
String lines = IntStream.range(0, 10)
207+
.collect(StringBuilder::new, (s, i) -> s.append("line " + (i + 1) + "\n"), StringBuilder::append).toString();
208+
styledText.setText(lines);
209+
StyleRange style = new StyleRange();
210+
style.start = 0;
211+
style.length = lines.length();
212+
style.font = styledText.getFont(); // To make the line-height non-fixed
213+
styledText.setStyleRange(style);
214+
215+
shell.setSize(100, 3 * styledText.getLineHeight());
216+
shell.open();
217+
218+
text.setFocus();
219+
styledText.setTopIndex(styledText.getLineCount() - 1);
220+
assertFalse(styledText.isFocusControl());
221+
assertTrue(text.isFocusControl());
222+
// ensure no IllegalArgumentException is thrown when styledText control has not the focus and the text is replaced
223+
styledText.replaceTextRange(0, styledText.getCharCount(), "");
224+
}finally {
225+
styledText.dispose();
226+
text.dispose();
227+
}
228+
}
229+
198230
@Test
199231
public void test_addExtendedModifyListenerLorg_eclipse_swt_custom_ExtendedModifyListener() {
200232
final String line = "Line1";

0 commit comments

Comments
 (0)