/
Inet4AddressFormatter.java
147 lines (130 loc) · 5.67 KB
/
Inet4AddressFormatter.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package textformatter;
import javafx.scene.control.TextFormatter;
import javafx.util.StringConverter;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.List;
import java.util.function.UnaryOperator;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
class Inet4AddressFormatter extends TextFormatter<Inet4Address> {
final private static String SEPARATOR = " . ";
final private static Pattern NOT_NUMBER_PATTERN = Pattern.compile("[^0-9]+");
Inet4AddressFormatter(Inet4Address defaultValue) {
super(new Inet4AddressStringConverter(),
defaultValue,
textFormatterFilter());
}
static private UnaryOperator<Change> textFormatterFilter() {
return UnaryOperator.<Change>identity()
.andThen(Inet4AddressFormatter::nextSeparateFilter)
.andThen(Inet4AddressFormatter::disableNotNumberFilter)
.andThen(Inet4AddressFormatter::lockSeparatorFilter)
::apply;
}
static private Change nextSeparateFilter(Change c) {
// "."をタイプすると次のバイトを選択する
if (".".equals(c.getText())) {
restrictText(c, text -> "");
c.setRange(c.getRangeStart(), c.getRangeStart());
int currentIndex = getCurrentSeparateIndex(c);
if (currentIndex < 3) {
int nextBegin = getPositionOfSeparateIndex(c, currentIndex + 1);
int spaceIndex = c.getControlText().indexOf(" ", nextBegin);
c.setAnchor(nextBegin);
c.setCaretPosition(spaceIndex == -1 ? c.getControlText().length() : spaceIndex);
}
}
return c;
}
static private Change disableNotNumberFilter(Change c) {
// 数字以外は入力を受け付けない
if (!c.getText().isEmpty()) {
restrictText(c, text -> NOT_NUMBER_PATTERN.matcher(text).replaceAll(""));
}
return c;
}
static private Change lockSeparatorFilter(Change c) {
// セパレータ部分は書き換えさせない
if (c.isDeleted()) {
if (SEPARATOR.contains(c.getControlText().substring(c.getRangeStart(), c.getRangeEnd()))) {
c.setRange(c.getRangeStart(), c.getRangeStart());
c.selectRange(c.getControlAnchor(), c.getControlCaretPosition());
}
// セパレータ部分は選択させない
} else if (!c.isContentChange()) {
if (c.getAnchor() > 0 && c.getControlText().charAt(c.getAnchor() - 1) == '.')
c.setAnchor(c.getAnchor() + 1);
if (c.getAnchor() < c.getControlText().length() && c.getControlText().charAt(c.getAnchor()) == '.')
c.setAnchor(c.getAnchor() - 1);
if (c.getAnchor() < c.getCaretPosition()) {
int spaceIndex = c.getControlText().indexOf(" ", c.getAnchor());
if (spaceIndex != -1) c.setCaretPosition(Math.min(spaceIndex, c.getCaretPosition()));
}
if (c.getAnchor() > c.getCaretPosition()) {
int spaceIndex = c.getControlText().lastIndexOf(" ", c.getAnchor() - 1);
if (spaceIndex != -1) c.setCaretPosition(Math.max(spaceIndex + 1, c.getCaretPosition()));
}
}
return c;
}
static private void restrictText(Change c, UnaryOperator<String> restriction) {
String newStr = restriction.apply(c.getText());
int diffcount = c.getText().length() - newStr.length();
c.selectRange(c.getAnchor() - diffcount, c.getCaretPosition() - diffcount);
c.setText(newStr);
}
static private int getCurrentSeparateIndex(Change c) {
int count = 0, lastIndex = 0;
String target = c.getControlText().substring(0, c.getControlCaretPosition());
while (lastIndex != -1) {
lastIndex = target.indexOf(SEPARATOR, lastIndex);
if (lastIndex != -1) {
count++;
lastIndex += SEPARATOR.length();
}
}
return count;
}
static private int getPositionOfSeparateIndex(Change c, int index) {
int count = 0, lastIndex = 0;
String target = c.getControlText();
while (lastIndex != -1) {
if (count >= index) return lastIndex;
lastIndex = target.indexOf(SEPARATOR, lastIndex);
if (lastIndex != -1) {
count++;
lastIndex += SEPARATOR.length();
}
}
return 0;
}
public static class Inet4AddressStringConverter extends StringConverter<Inet4Address> {
@Override
public String toString(Inet4Address addr) {
List<String> as = Arrays.asList("0", "0", "0", "0");
if (addr != null) {
as = IntStream.range(0, 4).mapToObj(i -> Integer.toString(addr.getAddress()[i] & 0xFF)).collect(Collectors.toList());
}
return String.join(SEPARATOR, as);
}
@Override
public Inet4Address fromString(String string) {
byte[] bytes = new byte[]{0, 0, 0, 0};
if (string != null) {
String[] numbers = string.split(SEPARATOR);
for (int i = 0; i < bytes.length && i < numbers.length; i++) {
bytes[i] = (byte) Math.max(0, Math.min(255, Integer.parseInt(numbers[i])));
}
}
try {
return (Inet4Address) InetAddress.getByAddress(bytes);
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
}
}
}