1 package edu.jiangxin.apktoolbox.android.i18n;
2
3 import edu.jiangxin.apktoolbox.swing.extend.EasyPanel;
4 import edu.jiangxin.apktoolbox.swing.extend.listener.SelectDirectoryListener;
5 import edu.jiangxin.apktoolbox.utils.Constants;
6 import edu.jiangxin.apktoolbox.utils.SAXBuilderHelper;
7 import org.apache.commons.collections4.CollectionUtils;
8 import org.apache.commons.lang3.StringUtils;
9 import org.jdom2.Document;
10 import org.jdom2.Element;
11 import org.jdom2.JDOMException;
12 import org.jdom2.input.SAXBuilder;
13
14 import javax.swing.*;
15 import java.awt.*;
16 import java.awt.event.ActionEvent;
17 import java.awt.event.ActionListener;
18 import java.io.File;
19 import java.io.FileFilter;
20 import java.io.IOException;
21 import java.io.Serial;
22 import java.util.ArrayList;
23 import java.util.List;
24
25
26
27
28
29
30 public class I18nFindLongestPanel extends EasyPanel {
31 @Serial
32 private static final long serialVersionUID = 1L;
33
34 private final transient List<I18nInfo> infos = new ArrayList<>();
35
36 private JTextField srcTextField;
37
38 private JTextField itemTextField;
39
40 public I18nFindLongestPanel() throws HeadlessException {
41 super();
42 }
43
44 @Override
45 public void initUI() {
46 BoxLayout boxLayout = new BoxLayout(this, BoxLayout.Y_AXIS);
47 setLayout(boxLayout);
48
49 createSourcePanel();
50 add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER));
51 createItemPanel();
52 add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER));
53 createOperationPanel();
54 }
55
56 private void createOperationPanel() {
57 JPanel operationPanel = new JPanel();
58 operationPanel.setLayout(new BoxLayout(operationPanel, BoxLayout.X_AXIS));
59 add(operationPanel);
60
61 JButton findButton = new JButton(bundle.getString("android.i18n.longest.find"));
62 findButton.addActionListener(new ActionListener() {
63 @Override
64 public void actionPerformed(ActionEvent e) {
65 infos.clear();
66
67 String srcPath = checkAndGetDirContent(srcTextField, "android.i18n.longest.src.dir", "Source directory is invalid");
68 if (StringUtils.isEmpty(srcPath)) {
69 return;
70 }
71
72 String item = checkAndGetStringContent(itemTextField, "android.i18n.longest.items", "Item is empty");
73 if (StringUtils.isEmpty(item)) {
74 return;
75 }
76
77 sort(srcPath, itemTextField.getText());
78 if (CollectionUtils.isEmpty(infos)) {
79 Toolkit.getDefaultToolkit().beep();
80 JOptionPane.showMessageDialog(I18nFindLongestPanel.this, "Failed, please see the log", "ERROR",
81 JOptionPane.ERROR_MESSAGE);
82 } else {
83 I18nInfo info = infos.get(0);
84 StringBuilder sb = new StringBuilder();
85 sb.append("length: ").append(info.length).append(System.lineSeparator())
86 .append("text: ").append(info.text).append(System.lineSeparator())
87 .append("path: ").append(info.path);
88 Toolkit.getDefaultToolkit().beep();
89 JOptionPane.showMessageDialog(I18nFindLongestPanel.this, sb.toString(), "INFO",
90 JOptionPane.INFORMATION_MESSAGE);
91 }
92
93 }
94 });
95
96 operationPanel.add(findButton);
97 }
98
99 private void createItemPanel() {
100 JPanel itemPanel = new JPanel();
101 itemPanel.setLayout(new BoxLayout(itemPanel, BoxLayout.X_AXIS));
102 add(itemPanel);
103
104 itemTextField = new JTextField();
105 itemTextField.setText(conf.getString("android.i18n.longest.items"));
106
107 JLabel itemLabel = new JLabel("Items");
108
109 itemPanel.add(itemTextField);
110 itemPanel.add(Box.createHorizontalGlue());
111 itemPanel.add(itemLabel);
112 }
113
114 private void createSourcePanel() {
115 JPanel sourcePanel = new JPanel();
116 sourcePanel.setLayout(new BoxLayout(sourcePanel, BoxLayout.X_AXIS));
117 add(sourcePanel);
118
119 srcTextField = new JTextField();
120 srcTextField.setText(conf.getString("android.i18n.longest.src.dir"));
121
122 JButton srcButton = new JButton("Source Directory");
123 srcButton.addActionListener(new SelectDirectoryListener("select a directory", srcTextField));
124
125 sourcePanel.add(srcTextField);
126 sourcePanel.add(Box.createHorizontalGlue());
127 sourcePanel.add(srcButton);
128 }
129
130 private String getCanonicalPath(File file) {
131 if (file == null) {
132 logger.error("file is null");
133 return null;
134 }
135 try {
136 return file.getCanonicalPath();
137 } catch (IOException e) {
138 logger.error("getCanonicalPath failed: {}", file.getAbsolutePath());
139 return null;
140 }
141 }
142
143 private void sort(String sourceBaseStr, String itemName) {
144 File[] sourceParentFiles = new File(sourceBaseStr).listFiles(new FileFilter() {
145 @Override
146 public boolean accept(File pathname) {
147 return pathname.getName().startsWith("values");
148 }
149 });
150 if (sourceParentFiles == null) {
151 logger.error("None valid directory found");
152 return;
153 }
154 for (File sourceParentFile : sourceParentFiles) {
155 File sourceFile = new File(sourceParentFile, "strings.xml");
156 if (sourceFile.exists()) {
157 SAXBuilder builder = new SAXBuilder();
158 SAXBuilderHelper.setSecurityFeatures(builder);
159 Document sourceDoc;
160 try {
161 sourceDoc = builder.build(sourceFile);
162 } catch (JDOMException | IOException e) {
163 logger.error("build failed: {}", sourceFile);
164 continue;
165 }
166 Element sourceRoot = sourceDoc.getRootElement();
167 for (Element child : sourceRoot.getChildren()) {
168 String value = child.getAttributeValue("name");
169 if (value != null && value.equals(itemName)) {
170 String text = child.getText();
171 if (text != null) {
172 I18nInfo info = new I18nInfo(getCanonicalPath(sourceFile), text, text.length());
173 infos.add(info);
174 break;
175 }
176 }
177 }
178
179 }
180
181 }
182 infos.sort((o1, o2) -> o2.length - o1.length);
183
184 logger.info(infos);
185 }
186
187 static class I18nInfo {
188 String path;
189 String text;
190 int length;
191
192 public I18nInfo(String path, String text, int length) {
193 this.path = path;
194 this.text = text;
195 this.length = length;
196 }
197
198 @Override
199 public String toString() {
200 return "I18NInfo [path=" + path + ", text=" + text + ", length=" + length + "]";
201 }
202 }
203 }