Skip to content

Commit 281f5c2

Browse files
Merge
2 parents 946590e + 5de99be commit 281f5c2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1186
-30637
lines changed

modules/javafx.controls/src/main/java/javafx/scene/control/TextInputControl.java

+68-47
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ protected interface Content extends ObservableStringValue {
120120
public int length();
121121
}
122122

123+
private boolean blockSelectedTextUpdate;
124+
123125
/***************************************************************************
124126
* *
125127
* Constructors *
@@ -154,21 +156,8 @@ protected TextInputControl(final Content content) {
154156
});
155157

156158
// Bind the selected text to be based on the selection and text properties
157-
selectedText.bind(new StringBinding() {
158-
{ bind(selection, text); }
159-
@Override protected String computeValue() {
160-
String txt = text.get();
161-
IndexRange sel = selection.get();
162-
if (txt == null || sel == null) return "";
163-
164-
int start = sel.getStart();
165-
int end = sel.getEnd();
166-
int length = txt.length();
167-
if (end > start + length) end = length;
168-
if (start > length-1) start = end = 0;
169-
return txt.substring(start, end);
170-
}
171-
});
159+
selection.addListener((ob, o, n) -> updateSelectedText());
160+
text.addListener((ob, o, n) -> updateSelectedText());
172161

173162
focusedProperty().addListener((ob, o, n) -> {
174163
if (n) {
@@ -184,6 +173,20 @@ protected TextInputControl(final Content content) {
184173
getStyleClass().add("text-input");
185174
}
186175

176+
private void updateSelectedText() {
177+
if (!blockSelectedTextUpdate) {
178+
String txt = text.get();
179+
IndexRange sel = selection.get();
180+
if (txt == null || sel == null) {
181+
selectedText.set("");
182+
} else {
183+
int start = sel.getStart();
184+
int end = sel.getEnd();
185+
selectedText.set(txt.substring(start, end));
186+
}
187+
}
188+
}
189+
187190
/***************************************************************************
188191
* *
189192
* Properties *
@@ -1139,18 +1142,24 @@ public final void undo() {
11391142
final String newText = undoChange.newText;
11401143
final String oldText = undoChange.oldText;
11411144

1142-
if (newText != null) {
1143-
getContent().delete(start, start + newText.length(), oldText.isEmpty());
1144-
}
1145+
blockSelectedTextUpdate = true;
1146+
try {
1147+
if (newText != null) {
1148+
getContent().delete(start, start + newText.length(), oldText.isEmpty());
1149+
}
11451150

1146-
if (oldText != null) {
1147-
getContent().insert(start, oldText, true);
1148-
doSelectRange(start, start + oldText.length());
1149-
} else {
1150-
doSelectRange(start, start + newText.length());
1151-
}
1151+
if (oldText != null) {
1152+
getContent().insert(start, oldText, true);
1153+
doSelectRange(start, start + oldText.length());
1154+
} else {
1155+
doSelectRange(start, start + newText.length());
1156+
}
11521157

1153-
undoChange = undoChange.prev;
1158+
undoChange = undoChange.prev;
1159+
} finally {
1160+
blockSelectedTextUpdate = false;
1161+
updateSelectedText();
1162+
}
11541163
}
11551164
updateUndoRedoState();
11561165
}
@@ -1168,15 +1177,21 @@ public final void redo() {
11681177
final String newText = undoChange.newText;
11691178
final String oldText = undoChange.oldText;
11701179

1171-
if (oldText != null) {
1172-
getContent().delete(start, start + oldText.length(), newText.isEmpty());
1173-
}
1180+
blockSelectedTextUpdate = true;
1181+
try {
1182+
if (oldText != null) {
1183+
getContent().delete(start, start + oldText.length(), newText.isEmpty());
1184+
}
11741185

1175-
if (newText != null) {
1176-
getContent().insert(start, newText, true);
1177-
doSelectRange(start + newText.length(), start + newText.length());
1178-
} else {
1179-
doSelectRange(start, start);
1186+
if (newText != null) {
1187+
getContent().insert(start, newText, true);
1188+
doSelectRange(start + newText.length(), start + newText.length());
1189+
} else {
1190+
doSelectRange(start, start);
1191+
}
1192+
} finally {
1193+
blockSelectedTextUpdate = false;
1194+
updateSelectedText();
11801195
}
11811196
}
11821197
updateUndoRedoState();
@@ -1237,20 +1252,26 @@ private boolean filterAndSet(String value) {
12371252
private int replaceText(int start, int end, String value, int anchor, int caretPosition) {
12381253
// RT-16566: Need to take into account stripping of chars into the
12391254
// final anchor & caret position
1240-
int length = getLength();
1241-
int adjustmentAmount = 0;
1242-
if (end != start) {
1243-
getContent().delete(start, end, value.isEmpty());
1244-
length -= (end - start);
1245-
}
1246-
if (value != null) {
1247-
getContent().insert(start, value, true);
1248-
adjustmentAmount = value.length() - (getLength() - length);
1249-
anchor -= adjustmentAmount;
1250-
caretPosition -= adjustmentAmount;
1251-
}
1252-
doSelectRange(anchor, caretPosition);
1253-
return adjustmentAmount;
1255+
blockSelectedTextUpdate = true;
1256+
try {
1257+
int length = getLength();
1258+
int adjustmentAmount = 0;
1259+
if (end != start) {
1260+
getContent().delete(start, end, value.isEmpty());
1261+
length -= (end - start);
1262+
}
1263+
if (value != null) {
1264+
getContent().insert(start, value, true);
1265+
adjustmentAmount = value.length() - (getLength() - length);
1266+
anchor -= adjustmentAmount;
1267+
caretPosition -= adjustmentAmount;
1268+
}
1269+
doSelectRange(anchor, caretPosition);
1270+
return adjustmentAmount;
1271+
} finally {
1272+
blockSelectedTextUpdate = false;
1273+
updateSelectedText();
1274+
}
12541275
}
12551276

12561277
private <T> void updateText(TextFormatter<T> formatter) {

modules/javafx.controls/src/test/java/test/javafx/scene/control/TextAreaTest.java

+20
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import javafx.scene.Scene;
3535
import javafx.scene.control.TextArea;
3636
import javafx.scene.control.TextInputControlShim;
37+
import org.junit.After;
3738
import org.junit.Before;
3839
import org.junit.Ignore;
3940
import org.junit.Test;
@@ -52,6 +53,25 @@ public class TextAreaTest {
5253
@Before public void setup() {
5354
txtArea = new TextArea();
5455
dummyTxtArea = new TextArea("dummy");
56+
setUncaughtExceptionHandler();
57+
}
58+
59+
@After public void cleanup() {
60+
removeUncaughtExceptionHandler();
61+
}
62+
63+
private void setUncaughtExceptionHandler() {
64+
Thread.currentThread().setUncaughtExceptionHandler((thread, throwable) -> {
65+
if (throwable instanceof RuntimeException) {
66+
throw (RuntimeException)throwable;
67+
} else {
68+
Thread.currentThread().getThreadGroup().uncaughtException(thread, throwable);
69+
}
70+
});
71+
}
72+
73+
private void removeUncaughtExceptionHandler() {
74+
Thread.currentThread().setUncaughtExceptionHandler(null);
5575
}
5676

5777
/*********************************************************************

modules/javafx.controls/src/test/java/test/javafx/scene/control/TextFieldTest.java

+35-1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@
5353
import javafx.scene.Scene;
5454
import javafx.scene.control.ComboBox;
5555
import javafx.scene.control.TextField;
56+
import javafx.scene.control.TextFormatter;
57+
import javafx.scene.control.TextFormatter.Change;
5658
import javafx.scene.control.TextInputControlShim;
5759
import javafx.scene.input.KeyCode;
5860
import javafx.scene.input.KeyCodeCombination;
@@ -70,6 +72,21 @@ public class TextFieldTest {
7072
@Before public void setup() {
7173
txtField = new TextField();
7274
dummyTxtField = new TextField("dummy");
75+
setUncaughtExceptionHandler();
76+
}
77+
78+
private void setUncaughtExceptionHandler() {
79+
Thread.currentThread().setUncaughtExceptionHandler((thread, throwable) -> {
80+
if (throwable instanceof RuntimeException) {
81+
throw (RuntimeException)throwable;
82+
} else {
83+
Thread.currentThread().getThreadGroup().uncaughtException(thread, throwable);
84+
}
85+
});
86+
}
87+
88+
private void removeUncaughtExceptionHandler() {
89+
Thread.currentThread().setUncaughtExceptionHandler(null);
7390
}
7491

7592
/*********************************************************************
@@ -448,12 +465,28 @@ public void testEnterWithConsumingActionHandler() {
448465
assertTrue("action must be consumed ", actions.get(0).isConsumed());
449466
}
450467

468+
@Test public void replaceSelectionWithFilteredCharacters() {
469+
txtField.setText("x xxxyyy");
470+
txtField.selectRange(2, 5);
471+
txtField.setTextFormatter(new TextFormatter<>(this::noDigits));
472+
txtField.replaceSelection("a1234a");
473+
assertEquals("x aayyy", txtField.getText());
474+
assertEquals(4, txtField.getSelection().getStart());
475+
assertEquals(4, txtField.getSelection().getEnd());
476+
}
477+
478+
private Change noDigits(Change change) {
479+
Change filtered = change.clone();
480+
filtered.setText(change.getText().replaceAll("[0-9]","\n"));
481+
return filtered;
482+
}
483+
451484
/**
452485
* Helper method to init the stage only if really needed.
453486
*/
454487
private void initStage() {
455488
//This step is not needed (Just to make sure StubToolkit is loaded into VM)
456-
Toolkit tk = (StubToolkit)Toolkit.getToolkit();
489+
Toolkit tk = Toolkit.getToolkit();
457490
root = new StackPane();
458491
scene = new Scene(root);
459492
stage = new Stage();
@@ -465,5 +498,6 @@ public void cleanup() {
465498
if (stage != null) {
466499
stage.hide();
467500
}
501+
removeUncaughtExceptionHandler();
468502
}
469503
}

modules/javafx.controls/src/test/java/test/javafx/scene/control/TextInputControlTest.java

+79
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@
5252
import javafx.scene.control.TextField;
5353
import javafx.scene.control.TextInputControl;
5454
import com.sun.javafx.tk.Toolkit;
55+
56+
import org.junit.After;
5557
import org.junit.Before;
5658
import org.junit.Test;
5759
import org.junit.runner.RunWith;
@@ -85,6 +87,25 @@ public TextInputControlTest(Class type) {
8587

8688
@Before public void setup() throws Exception {
8789
textInput = (TextInputControl) type.newInstance();
90+
setUncaughtExceptionHandler();
91+
}
92+
93+
@After public void cleanup() {
94+
removeUncaughtExceptionHandler();
95+
}
96+
97+
private void setUncaughtExceptionHandler() {
98+
Thread.currentThread().setUncaughtExceptionHandler((thread, throwable) -> {
99+
if (throwable instanceof RuntimeException) {
100+
throw (RuntimeException)throwable;
101+
} else {
102+
Thread.currentThread().getThreadGroup().uncaughtException(thread, throwable);
103+
}
104+
});
105+
}
106+
107+
private void removeUncaughtExceptionHandler() {
108+
Thread.currentThread().setUncaughtExceptionHandler(null);
88109
}
89110

90111
/******************************************************
@@ -1865,6 +1886,64 @@ public void caretAndAnchorPositionAfterSettingText() {
18651886
assertEquals("", textInput.getText());
18661887
}
18671888

1889+
@Test public void test_redo_replaceText_selectionShortening() {
1890+
textInput.setText("0123456789");
1891+
assertEquals("0123456789", textInput.getText());
1892+
1893+
textInput.replaceText(8, 10, "x");
1894+
assertEquals("01234567x", textInput.getText());
1895+
1896+
textInput.undo();
1897+
assertEquals("0123456789", textInput.getText());
1898+
1899+
textInput.redo();
1900+
assertEquals("01234567x", textInput.getText());
1901+
}
1902+
1903+
@Test public void replaceSelectionAtEndWithListener() {
1904+
StringBuilder selectedTextLog = new StringBuilder();
1905+
StringBuilder selectionLog = new StringBuilder();
1906+
textInput.setText("x xxx");
1907+
textInput.selectRange(2, 5);
1908+
textInput.selectedTextProperty().addListener((observable, oldValue, newValue) -> selectedTextLog.append("|" + newValue));
1909+
textInput.selectionProperty().addListener((observable, oldValue, newValue) -> selectionLog.append("|" + newValue.getStart() + "," + newValue.getEnd()));
1910+
textInput.replaceSelection("a");
1911+
assertEquals("|", selectedTextLog.toString());
1912+
assertEquals("|3,3", selectionLog.toString());
1913+
assertEquals("x a", textInput.getText());
1914+
}
1915+
1916+
@Test public void testSelectionProperties() {
1917+
textInput.setText("abcdefghij");
1918+
1919+
StringBuilder selectedTextLog = new StringBuilder();
1920+
StringBuilder selectionLog = new StringBuilder();
1921+
StringBuilder textLog = new StringBuilder();
1922+
textInput.selectedTextProperty().addListener((observable, oldValue, newValue) -> selectedTextLog.append("|" + newValue));
1923+
textInput.selectionProperty().addListener((observable, oldValue, newValue) -> selectionLog.append("|" + newValue.getStart() + "," + newValue.getEnd()));
1924+
textInput.textProperty().addListener((observable, oldValue, newValue) -> textLog.append("|" + newValue));
1925+
1926+
textInput.selectRange(3, 6);
1927+
assertEquals("|def", selectedTextLog.toString());
1928+
assertEquals("|3,6", selectionLog.toString());
1929+
assertEquals("", textLog.toString());
1930+
1931+
textInput.replaceSelection("xyz");
1932+
assertEquals("|def|", selectedTextLog.toString());
1933+
assertEquals("|3,6|6,6", selectionLog.toString());
1934+
assertEquals("|abcxyzghij", textLog.toString());
1935+
1936+
textInput.undo();
1937+
assertEquals("|def||def", selectedTextLog.toString());
1938+
assertEquals("|3,6|6,6|3,6", selectionLog.toString());
1939+
assertEquals("|abcxyzghij|abcdefghij", textLog.toString());
1940+
1941+
textInput.redo();
1942+
assertEquals("|def||def|", selectedTextLog.toString());
1943+
assertEquals("|3,6|6,6|3,6|6,6", selectionLog.toString());
1944+
assertEquals("|abcxyzghij|abcdefghij|abcxyzghij", textLog.toString());
1945+
}
1946+
18681947
// Test for JDK-8178418
18691948
@Test public void UndoRedoSpaceSequence() {
18701949
Toolkit tk = (StubToolkit)Toolkit.getToolkit();

0 commit comments

Comments
 (0)