View Javadoc
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 }