1 package edu.jiangxin.apktoolbox.convert.base; 2 3 import edu.jiangxin.apktoolbox.swing.extend.EasyPanel; 4 import edu.jiangxin.apktoolbox.utils.Constants; 5 import org.apache.commons.lang3.StringUtils; 6 7 import javax.swing.*; 8 import javax.swing.event.DocumentEvent; 9 import javax.swing.event.DocumentListener; 10 import javax.swing.text.*; 11 import java.awt.*; 12 import java.awt.event.ActionEvent; 13 import java.awt.event.ActionListener; 14 import java.io.Serial; 15 import java.math.BigInteger; 16 import java.util.ArrayList; 17 import java.util.List; 18 19 public class BaseConvertPanel extends EasyPanel { 20 @Serial 21 private static final long serialVersionUID = 1L; 22 23 private static final String PROPERTY_KEY = "name"; 24 25 private static final String DECIMAL = "Decimal"; 26 27 private static final String BINARY = "Binary"; 28 29 private static final String OCTAL = "Octal"; 30 31 private static final String HEX = "Hex"; 32 33 private transient DocumentListener documentListener; 34 35 private transient DocumentFilter documentFilter; 36 37 private boolean isChangedByUser; 38 39 private transient final List<BaseUiObject> baseUiObjects = new ArrayList<>(); 40 41 @Override 42 public void initUI() { 43 BoxLayout boxLayout = new BoxLayout(this, BoxLayout.Y_AXIS); 44 setLayout(boxLayout); 45 46 documentListener = new TextFieldDocumentListener(); 47 documentFilter = new TextFieldDocumentFilter(); 48 49 isChangedByUser = true; 50 51 baseUiObjects.add(new BaseUiObject(2)); 52 baseUiObjects.add(new BaseUiObject(8)); 53 baseUiObjects.add(new BaseUiObject(10)); 54 baseUiObjects.add(new BaseUiObject(16)); 55 56 for (BaseUiObject baseUiObject : baseUiObjects) { 57 add(baseUiObject.panel); 58 add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER)); 59 } 60 61 JButton clearBtn = new JButton("Clear"); 62 clearBtn.addActionListener(new ClearButtonActionListener()); 63 add(clearBtn); 64 } 65 66 67 class ClearButtonActionListener implements ActionListener { 68 @Override 69 public void actionPerformed(ActionEvent arg0) { 70 isChangedByUser = false; 71 for (BaseUiObject baseUiObject : baseUiObjects) { 72 baseUiObject.textField.setText(""); 73 } 74 isChangedByUser = true; 75 } 76 } 77 78 class TextFieldDocumentListener implements DocumentListener { 79 @Override 80 public void changedUpdate(DocumentEvent e) { 81 } 82 83 @Override 84 public void insertUpdate(DocumentEvent e) { 85 detect(e); 86 } 87 88 @Override 89 public void removeUpdate(DocumentEvent e) { 90 detect(e); 91 } 92 } 93 94 class TextFieldDocumentFilter extends DocumentFilter { 95 @Override 96 public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException { 97 Document doc = fb.getDocument(); 98 StringBuilder sb = new StringBuilder(); 99 sb.append(doc.getText(0, doc.getLength())); 100 sb.insert(offset, string); 101 102 Object propertyObj = doc.getProperty(PROPERTY_KEY); 103 if (propertyObj == null) { 104 Toolkit.getDefaultToolkit().beep(); 105 return; 106 } 107 Integer radix = (Integer) doc.getProperty(PROPERTY_KEY); 108 if (isValidText(radix, sb.toString())) { 109 super.insertString(fb, offset, string, attr); 110 } else { 111 Toolkit.getDefaultToolkit().beep(); 112 } 113 } 114 115 @Override 116 public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException { 117 Document doc = fb.getDocument(); 118 StringBuilder sb = new StringBuilder(); 119 sb.append(doc.getText(0, doc.getLength())); 120 sb.replace(offset, offset + length, text); 121 122 Object propertyObj = doc.getProperty(PROPERTY_KEY); 123 if (propertyObj == null) { 124 Toolkit.getDefaultToolkit().beep(); 125 return; 126 } 127 Integer radix = (Integer) doc.getProperty(PROPERTY_KEY); 128 if (isValidText(radix, sb.toString())) { 129 super.replace(fb, offset, length, text, attrs); 130 } else { 131 Toolkit.getDefaultToolkit().beep(); 132 } 133 } 134 } 135 136 private void detect(DocumentEvent documentEvent) { 137 Document doc = documentEvent.getDocument(); 138 Integer radix = (Integer) doc.getProperty(PROPERTY_KEY); 139 convertMe(radix); 140 } 141 142 private void convertMe(int radix) { 143 if (!isChangedByUser) { 144 return; 145 } 146 147 BigInteger value = null; 148 for (BaseUiObject baseUiObject : baseUiObjects) { 149 if (baseUiObject.radix == radix) { 150 String text = baseUiObject.textField.getText(); 151 if (StringUtils.isEmpty(text)) { 152 value = null; 153 } else { 154 value = new BigInteger(text, radix); 155 } 156 } 157 } 158 isChangedByUser = false; 159 for (BaseUiObject baseUiObject : baseUiObjects) { 160 if (baseUiObject.radix != radix) { 161 if (value == null) { 162 baseUiObject.textField.setText(""); 163 } else { 164 baseUiObject.textField.setText(value.toString(baseUiObject.radix)); 165 } 166 } 167 } 168 isChangedByUser = true; 169 } 170 171 private boolean isBinStr(String str) { 172 if (str == null) { 173 return false; 174 } 175 for (int i = 0; i < str.length(); i++) { 176 if ((str.charAt(i) != '1') && (str.charAt(i) != '0')) { 177 return false; 178 } 179 } 180 return true; 181 } 182 183 private boolean isDecStr(String str) { 184 if (str == null) { 185 return false; 186 } 187 for (int i = 0; i < str.length(); i++) { 188 if ((str.charAt(i) < '0') || (str.charAt(i) > '9')) { 189 return false; 190 } 191 } 192 return true; 193 } 194 195 private boolean isOctStr(String str) { 196 if (str == null) { 197 return false; 198 } 199 for (int i = 0; i < str.length(); i++) { 200 if ((str.charAt(i) < '0') || (str.charAt(i) > '7')) { 201 return false; 202 } 203 } 204 return true; 205 } 206 207 private boolean isHexStr(String str) { 208 if (str == null) { 209 return false; 210 } 211 for (int i = 0; i < str.length(); i++) { 212 char c = str.charAt(i); 213 if ((c < '0' || c > '9') && (c < 'A' || c > 'F') && (c < 'a' || c > 'f')) { 214 return false; 215 } 216 } 217 return true; 218 } 219 220 private boolean isValidText(int radix, String text) { 221 switch (radix) { 222 case 2 -> { 223 return isBinStr(text); 224 } 225 case 8 -> { 226 return isOctStr(text); 227 } 228 case 10 -> { 229 return isDecStr(text); 230 } 231 case 16 -> { 232 return isHexStr(text); 233 } 234 default -> { 235 return false; 236 } 237 } 238 } 239 240 class BaseUiObject { 241 int radix; 242 243 JPanel panel; 244 245 JLabel label; 246 247 JTextField textField; 248 249 BaseUiObject(int radix) { 250 this.radix = radix; 251 panel = new JPanel(); 252 panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)); 253 254 label = new JLabel(this + ":"); 255 label.setPreferredSize(new Dimension(50, 25)); 256 257 textField = new JTextField(); 258 textField.getDocument().addDocumentListener(documentListener); 259 ((PlainDocument) textField.getDocument()).setDocumentFilter(documentFilter); 260 textField.getDocument().putProperty(PROPERTY_KEY, radix); 261 262 panel.add(label); 263 panel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER)); 264 panel.add(textField); 265 } 266 267 @Override 268 public String toString() { 269 switch (radix) { 270 case 2 -> { 271 return BINARY; 272 } 273 case 8 -> { 274 return OCTAL; 275 } 276 case 10 -> { 277 return DECIMAL; 278 } 279 case 16 -> { 280 return HEX; 281 } 282 default -> { 283 return String.valueOf(radix); 284 } 285 } 286 } 287 } 288 }