Skip to content

Commit ae6330d

Browse files
authored
Add auto capitalization unit tests (#4168)
1 parent c8cb24d commit ae6330d

File tree

3 files changed

+232
-16
lines changed

3 files changed

+232
-16
lines changed

maven/core-unittests/src/test/java/com/codename1/io/services/CachedDataServiceTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public void actionPerformed(ActionEvent evt) {
5858
connection.setInputData(payload);
5959
connection.setContentLength(payload.length);
6060

61-
request.readResponse(new ByteArrayInputStream(connection.getInputData()));
61+
request.readResponse(new ByteArrayInputStream(payload));
6262
assertTrue(callbackInvoked[0]);
6363
assertEquals("Sun, 02 Jan 2000 00:00:00 GMT", data.getModified());
6464
assertEquals("etag-2", data.getEtag());
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package com.codename1.samples;
2+
3+
import com.codename1.junit.FormTest;
4+
import com.codename1.junit.UITestBase;
5+
import com.codename1.ui.DisplayTest;
6+
import com.codename1.ui.Form;
7+
import com.codename1.ui.Label;
8+
import com.codename1.ui.TextArea;
9+
import com.codename1.ui.TextField;
10+
import com.codename1.ui.layouts.BoxLayout;
11+
12+
import static org.junit.jupiter.api.Assertions.*;
13+
14+
class AutoCapitalizationSampleTest extends UITestBase {
15+
16+
@FormTest
17+
void sentenceConstraintCapitalizesFirstLetters() {
18+
implementation.setDisplaySize(1080, 1920);
19+
20+
Form form = new Form("Hi World", BoxLayout.y());
21+
form.add(new Label("Hi World"));
22+
TextField textField = createSampleField(TextArea.INITIAL_CAPS_SENTENCE);
23+
form.add(textField);
24+
25+
form.show();
26+
startEditing(textField);
27+
28+
implementation.dispatchKeyPress('h');
29+
implementation.dispatchKeyPress('e');
30+
implementation.dispatchKeyPress('l');
31+
implementation.dispatchKeyPress('l');
32+
implementation.dispatchKeyPress('o');
33+
implementation.dispatchKeyPress('.');
34+
implementation.dispatchKeyPress(' ');
35+
implementation.dispatchKeyPress('n');
36+
implementation.dispatchKeyPress('e');
37+
implementation.dispatchKeyPress('x');
38+
implementation.dispatchKeyPress('t');
39+
implementation.dispatchKeyPress(' ');
40+
implementation.dispatchKeyPress('s');
41+
implementation.dispatchKeyPress('e');
42+
implementation.dispatchKeyPress('n');
43+
implementation.dispatchKeyPress('t');
44+
implementation.dispatchKeyPress('e');
45+
implementation.dispatchKeyPress('n');
46+
implementation.dispatchKeyPress('c');
47+
implementation.dispatchKeyPress('e');
48+
49+
assertEquals("Hello. Next sentence", textField.getText());
50+
}
51+
52+
@FormTest
53+
void wordConstraintCapitalizesEachWordAcrossLines() {
54+
implementation.setDisplaySize(1080, 1920);
55+
56+
Form form = new Form("Hi World", BoxLayout.y());
57+
form.add(new Label("Hi World"));
58+
TextField textField = createSampleField(TextArea.INITIAL_CAPS_WORD);
59+
form.add(textField);
60+
61+
form.show();
62+
startEditing(textField);
63+
64+
implementation.dispatchKeyPress('m');
65+
implementation.dispatchKeyPress('u');
66+
implementation.dispatchKeyPress('l');
67+
implementation.dispatchKeyPress('t');
68+
implementation.dispatchKeyPress('i');
69+
implementation.dispatchKeyPress(' ');
70+
implementation.dispatchKeyPress('l');
71+
implementation.dispatchKeyPress('i');
72+
implementation.dispatchKeyPress('n');
73+
implementation.dispatchKeyPress('e');
74+
implementation.dispatchKeyPress('\n');
75+
implementation.dispatchKeyPress('a');
76+
implementation.dispatchKeyPress('u');
77+
implementation.dispatchKeyPress('t');
78+
implementation.dispatchKeyPress('o');
79+
implementation.dispatchKeyPress(' ');
80+
implementation.dispatchKeyPress('c');
81+
implementation.dispatchKeyPress('a');
82+
implementation.dispatchKeyPress('p');
83+
implementation.dispatchKeyPress('i');
84+
implementation.dispatchKeyPress('t');
85+
implementation.dispatchKeyPress('a');
86+
implementation.dispatchKeyPress('l');
87+
implementation.dispatchKeyPress('i');
88+
implementation.dispatchKeyPress('z');
89+
implementation.dispatchKeyPress('a');
90+
implementation.dispatchKeyPress('t');
91+
implementation.dispatchKeyPress('i');
92+
implementation.dispatchKeyPress('o');
93+
implementation.dispatchKeyPress('n');
94+
95+
assertEquals("Multi Line\nAuto Capitalization", textField.getText());
96+
}
97+
98+
private void startEditing(TextField textField) {
99+
textField.startEditingAsync();
100+
flushSerialCalls();
101+
DisplayTest.flushEdt();
102+
flushSerialCalls();
103+
104+
if (!implementation.isEditingText(textField)) {
105+
textField.requestFocus();
106+
flushSerialCalls();
107+
DisplayTest.flushEdt();
108+
flushSerialCalls();
109+
}
110+
111+
if (!implementation.isEditingText(textField)) {
112+
textField.startEditingAsync();
113+
flushSerialCalls();
114+
DisplayTest.flushEdt();
115+
flushSerialCalls();
116+
}
117+
}
118+
119+
private TextField createSampleField(int constraint) {
120+
TextField textField = new TextField();
121+
textField.setSingleLineTextArea(false);
122+
textField.setConstraint(constraint);
123+
textField.setGrowLimit(-1);
124+
textField.setMaxSize(1600);
125+
textField.setHint("Type Something...");
126+
textField.setQwertyInput(true);
127+
return textField;
128+
}
129+
}

maven/core-unittests/src/test/java/com/codename1/testing/TestCodenameOneImplementation.java

Lines changed: 102 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ public class TestCodenameOneImplementation extends CodenameOneImplementation {
179179
private MediaRecorderBuilder lastMediaRecorderBuilder;
180180
private VideoCaptureConstraints lastVideoConstraints;
181181
private final List<AudioCaptureFrame> audioCaptureFrames = new ArrayList<AudioCaptureFrame>();
182+
private TextArea activeTextEditor;
182183

183184

184185
public TestCodenameOneImplementation() {
@@ -1050,17 +1051,18 @@ public int getDisplayHeight() {
10501051

10511052
@Override
10521053
public void editString(com.codename1.ui.Component cmp, int maxSize, int constraint, String text, int initiatingKeycode) {
1053-
if (cmp instanceof TextField) {
1054-
TextField field = (TextField) cmp;
1055-
if (shouldInsertCharacter(field.isEditable(), initiatingKeycode)) {
1056-
field.insertChars(String.valueOf((char) initiatingKeycode));
1057-
return;
1058-
}
1059-
field.setText(text);
1060-
return;
1061-
}
10621054
if (cmp instanceof TextArea) {
10631055
TextArea area = (TextArea) cmp;
1056+
activeTextEditor = area;
1057+
if (cmp instanceof TextField) {
1058+
TextField field = (TextField) cmp;
1059+
if (shouldInsertCharacter(field.isEditable(), initiatingKeycode)) {
1060+
insertCharacter(field, (char) initiatingKeycode, maxSize);
1061+
return;
1062+
}
1063+
field.setText(text);
1064+
return;
1065+
}
10641066
if (shouldInsertCharacter(area.isEditable(), initiatingKeycode)) {
10651067
insertCharacter(area, (char) initiatingKeycode, maxSize);
10661068
return;
@@ -1109,13 +1111,94 @@ private void insertCharacter(TextArea area, char character, int maxSize) {
11091111
if (cursor < 0 || cursor > current.length()) {
11101112
cursor = current.length();
11111113
}
1114+
char adjustedCharacter = applyAutoCapitalization(area, character, current, cursor);
11121115
StringBuilder sb = new StringBuilder(current.length() + 1);
11131116
sb.append(current, 0, cursor);
1114-
sb.append(character);
1117+
sb.append(adjustedCharacter);
11151118
if (cursor < current.length()) {
11161119
sb.append(current.substring(cursor));
11171120
}
11181121
area.setText(sb.toString());
1122+
if (area instanceof TextField) {
1123+
((TextField) area).setCursorPosition(cursor + 1);
1124+
}
1125+
}
1126+
1127+
private TextArea getActiveEditingArea() {
1128+
Component editing = getEditingText();
1129+
if (editing instanceof TextArea) {
1130+
return (TextArea) editing;
1131+
}
1132+
Display display = Display.getInstance();
1133+
if (display == null) {
1134+
return null;
1135+
}
1136+
Form current = display.getCurrent();
1137+
if (current == null) {
1138+
return null;
1139+
}
1140+
Component focused = current.getFocused();
1141+
if (focused instanceof TextArea) {
1142+
return (TextArea) focused;
1143+
}
1144+
if (current != null) {
1145+
TextArea firstTextArea = findFirstTextArea(current.getContentPane());
1146+
if (firstTextArea != null) {
1147+
activeTextEditor = firstTextArea;
1148+
return firstTextArea;
1149+
}
1150+
}
1151+
if (activeTextEditor != null) {
1152+
return activeTextEditor;
1153+
}
1154+
return null;
1155+
}
1156+
1157+
private TextArea findFirstTextArea(Container container) {
1158+
if (container == null) {
1159+
return null;
1160+
}
1161+
int componentCount = container.getComponentCount();
1162+
for (int i = 0; i < componentCount; i++) {
1163+
Component child = container.getComponentAt(i);
1164+
if (child instanceof TextArea) {
1165+
return (TextArea) child;
1166+
}
1167+
if (child instanceof Container) {
1168+
TextArea nested = findFirstTextArea((Container) child);
1169+
if (nested != null) {
1170+
return nested;
1171+
}
1172+
}
1173+
}
1174+
return null;
1175+
}
1176+
1177+
private char applyAutoCapitalization(TextArea area, char character, String currentText, int cursorPosition) {
1178+
if (!Character.isLetter(character)) {
1179+
return character;
1180+
}
1181+
int constraint = area.getConstraint();
1182+
boolean initialCapsSentence = (constraint & TextArea.INITIAL_CAPS_SENTENCE) == TextArea.INITIAL_CAPS_SENTENCE;
1183+
boolean initialCapsWord = (constraint & TextArea.INITIAL_CAPS_WORD) == TextArea.INITIAL_CAPS_WORD;
1184+
if (!initialCapsSentence && !initialCapsWord) {
1185+
return character;
1186+
}
1187+
int index = cursorPosition - 1;
1188+
if (initialCapsSentence) {
1189+
while (index >= 0 && Character.isWhitespace(currentText.charAt(index))) {
1190+
index--;
1191+
}
1192+
if (index < 0 || currentText.charAt(index) == '.' || currentText.charAt(index) == '!' || currentText.charAt(index) == '?') {
1193+
return Character.toUpperCase(character);
1194+
}
1195+
}
1196+
if (initialCapsWord) {
1197+
if (index < 0 || Character.isWhitespace(currentText.charAt(index))) {
1198+
return Character.toUpperCase(character);
1199+
}
1200+
}
1201+
return character;
11191202
}
11201203

11211204
@Override
@@ -1125,6 +1208,7 @@ public boolean isAsyncEditMode() {
11251208

11261209
@Override
11271210
public void stopTextEditing() {
1211+
activeTextEditor = null;
11281212
hideTextEditor();
11291213
}
11301214

@@ -1133,7 +1217,11 @@ public void dispatchKeyPress(final int keyCode) {
11331217
if (display == null) {
11341218
return;
11351219
}
1220+
final TextArea editing = getActiveEditingArea();
11361221
final boolean reenter = beginAllowingEditDuringKey(keyCode);
1222+
if (editing != null && shouldInsertCharacter(editing.isEditable(), keyCode)) {
1223+
insertCharacter(editing, (char) keyCode, editing.getMaxSize());
1224+
}
11371225
display.keyPressed(keyCode);
11381226
display.keyReleased(keyCode);
11391227
if (reenter) {
@@ -1166,16 +1254,15 @@ public void tapComponent(Component component) {
11661254
}
11671255

11681256
private boolean beginAllowingEditDuringKey(int keyCode) {
1169-
Component editing = getEditingText();
1170-
if (!(editing instanceof TextArea)) {
1257+
TextArea area = getActiveEditingArea();
1258+
if (area == null) {
11711259
return false;
11721260
}
1173-
TextArea area = (TextArea) editing;
11741261
if (!shouldInsertCharacter(area.isEditable(), keyCode)) {
11751262
return false;
11761263
}
1177-
if (editing instanceof TextField) {
1178-
TextField tf = (TextField) editing;
1264+
if (area instanceof TextField) {
1265+
TextField tf = (TextField) area;
11791266
if (!tf.isQwertyInput()) {
11801267
return false;
11811268
}

0 commit comments

Comments
 (0)