|
1 |
| |
|
2 |
| |
|
3 |
| |
|
4 |
| package net.sourceforge.pmd.cpd; |
|
5 |
| |
|
6 |
| import javax.swing.*; |
|
7 |
| import java.awt.BorderLayout; |
|
8 |
| import java.awt.Dimension; |
|
9 |
| import java.awt.event.ActionEvent; |
|
10 |
| import java.awt.event.ActionListener; |
|
11 |
| import java.io.File; |
|
12 |
| import java.io.FileOutputStream; |
|
13 |
| import java.io.IOException; |
|
14 |
| import java.io.PrintWriter; |
|
15 |
| import java.util.ArrayList; |
|
16 |
| import java.util.Iterator; |
|
17 |
| import java.util.List; |
|
18 |
| import java.util.Properties; |
|
19 |
| |
|
20 |
| public class GUI implements CPDListener { |
|
21 |
| |
|
22 |
| private static class CancelListener implements ActionListener { |
|
23 |
0
| public void actionPerformed(ActionEvent e) {
|
|
24 |
0
| System.exit(0);
|
|
25 |
| } |
|
26 |
| } |
|
27 |
| |
|
28 |
| private class GoListener implements ActionListener { |
|
29 |
0
| public void actionPerformed(ActionEvent e) {
|
|
30 |
0
| new Thread(new Runnable() {
|
|
31 |
0
| public void run() {
|
|
32 |
0
| tokenizingFilesBar.setValue(0);
|
|
33 |
0
| tokenizingFilesBar.setString("");
|
|
34 |
0
| resultsTextArea.setText("");
|
|
35 |
0
| phaseLabel.setText("");
|
|
36 |
0
| timeField.setText("");
|
|
37 |
0
| go();
|
|
38 |
| } |
|
39 |
| }).start(); |
|
40 |
| } |
|
41 |
| } |
|
42 |
| |
|
43 |
| private class SaveListener implements ActionListener { |
|
44 |
0
| public void actionPerformed(ActionEvent evt) {
|
|
45 |
0
| int ret = fcSave.showSaveDialog(GUI.this.frame);
|
|
46 |
0
| File f = fcSave.getSelectedFile();
|
|
47 |
0
| if (f == null || ret != JFileChooser.APPROVE_OPTION) {
|
|
48 |
0
| return;
|
|
49 |
| } |
|
50 |
0
| if (!f.canWrite()) {
|
|
51 |
0
| PrintWriter pw = null;
|
|
52 |
0
| try {
|
|
53 |
0
| pw = new PrintWriter(new FileOutputStream(f));
|
|
54 |
0
| if (evt.getActionCommand().equals(".txt")) {
|
|
55 |
0
| pw.write(new SimpleRenderer().render(matches.iterator()));
|
|
56 |
0
| } else if (evt.getActionCommand().equals(".xml")) {
|
|
57 |
0
| pw.write(new XMLRenderer().render(matches.iterator()));
|
|
58 |
0
| } else if (evt.getActionCommand().equals(".csv")) {
|
|
59 |
0
| pw.write(new CSVRenderer().render(matches.iterator()));
|
|
60 |
| } |
|
61 |
0
| pw.flush();
|
|
62 |
0
| JOptionPane.showMessageDialog(frame, "File saved");
|
|
63 |
| } catch (IOException e) { |
|
64 |
0
| error("Couldn't save file" + f.getAbsolutePath(), e);
|
|
65 |
| } finally { |
|
66 |
0
| if (pw != null) {
|
|
67 |
0
| pw.close();
|
|
68 |
| } |
|
69 |
| } |
|
70 |
| } else { |
|
71 |
0
| error("Could not write to file " + f.getAbsolutePath(), null);
|
|
72 |
| } |
|
73 |
| } |
|
74 |
| |
|
75 |
0
| private void error(String message, Exception e) {
|
|
76 |
0
| if (e != null) {
|
|
77 |
0
| e.printStackTrace();
|
|
78 |
| } |
|
79 |
0
| JOptionPane.showMessageDialog(GUI.this.frame, message);
|
|
80 |
| } |
|
81 |
| |
|
82 |
| } |
|
83 |
| |
|
84 |
| private class BrowseListener implements ActionListener { |
|
85 |
0
| public void actionPerformed(ActionEvent e) {
|
|
86 |
0
| JFileChooser fc = new JFileChooser(rootDirectoryField.getText());
|
|
87 |
0
| fc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
|
|
88 |
0
| fc.showDialog(frame, "Select");
|
|
89 |
0
| if (fc.getSelectedFile() != null) {
|
|
90 |
0
| rootDirectoryField.setText(fc.getSelectedFile().getAbsolutePath());
|
|
91 |
| } |
|
92 |
| } |
|
93 |
| } |
|
94 |
| |
|
95 |
| private JTextField rootDirectoryField = new JTextField(System.getProperty("user.home")); |
|
96 |
| private JTextField minimumLengthField = new JTextField("75"); |
|
97 |
| private JTextField timeField = new JTextField(6); |
|
98 |
| private JLabel phaseLabel = new JLabel(); |
|
99 |
| private JProgressBar tokenizingFilesBar = new JProgressBar(); |
|
100 |
| private JTextArea resultsTextArea = new JTextArea(); |
|
101 |
| private JCheckBox recurseCheckbox = new JCheckBox("", true); |
|
102 |
| private JCheckBox ignoreLiteralsCheckbox = new JCheckBox("", false); |
|
103 |
| private JComboBox languageBox = new JComboBox(); |
|
104 |
| private JTextField extensionField = new JTextField(".java"); |
|
105 |
| private JFileChooser fcSave = new JFileChooser(); |
|
106 |
| |
|
107 |
| private JFrame frame; |
|
108 |
| |
|
109 |
| private List matches = new ArrayList(); |
|
110 |
| |
|
111 |
0
| public GUI() {
|
|
112 |
0
| frame = new JFrame("PMD Duplicate Code Detector");
|
|
113 |
| |
|
114 |
0
| timeField.setEditable(false);
|
|
115 |
| |
|
116 |
0
| JMenu fileMenu = new JMenu("File");
|
|
117 |
0
| fileMenu.setMnemonic('f');
|
|
118 |
0
| JMenuItem saveItem = new JMenuItem("Save Text");
|
|
119 |
0
| saveItem.setMnemonic('s');
|
|
120 |
0
| saveItem.addActionListener(new SaveListener());
|
|
121 |
0
| fileMenu.add(saveItem);
|
|
122 |
0
| saveItem.setActionCommand(".txt");
|
|
123 |
0
| saveItem = new JMenuItem("Save XML");
|
|
124 |
0
| saveItem.addActionListener(new SaveListener());
|
|
125 |
0
| fileMenu.add(saveItem);
|
|
126 |
0
| saveItem.setActionCommand(".xml");
|
|
127 |
0
| saveItem = new JMenuItem("Save CSV");
|
|
128 |
0
| saveItem.setActionCommand(".csv");
|
|
129 |
0
| saveItem.addActionListener(new SaveListener());
|
|
130 |
0
| fileMenu.add(saveItem);
|
|
131 |
0
| JMenuItem exitItem = new JMenuItem("Exit");
|
|
132 |
0
| exitItem.setMnemonic('x');
|
|
133 |
0
| exitItem.addActionListener(new CancelListener());
|
|
134 |
0
| fileMenu.add(exitItem);
|
|
135 |
0
| JMenuBar menuBar = new JMenuBar();
|
|
136 |
0
| menuBar.add(fileMenu);
|
|
137 |
0
| frame.setJMenuBar(menuBar);
|
|
138 |
| |
|
139 |
| |
|
140 |
0
| JButton browseButton = new JButton("Browse");
|
|
141 |
0
| browseButton.setMnemonic('b');
|
|
142 |
0
| browseButton.addActionListener(new BrowseListener());
|
|
143 |
0
| JButton goButton = new JButton("Go");
|
|
144 |
0
| goButton.setMnemonic('g');
|
|
145 |
0
| goButton.addActionListener(new GoListener());
|
|
146 |
0
| JButton cxButton = new JButton("Cancel");
|
|
147 |
0
| cxButton.addActionListener(new CancelListener());
|
|
148 |
| |
|
149 |
0
| JPanel settingsPanel = makeSettingsPanel(browseButton, goButton, cxButton);
|
|
150 |
0
| JPanel progressPanel = makeProgressPanel();
|
|
151 |
0
| JPanel resultsPanel = makeResultsPanel();
|
|
152 |
| |
|
153 |
0
| frame.getContentPane().setLayout(new BorderLayout());
|
|
154 |
0
| JPanel topPanel = new JPanel();
|
|
155 |
0
| topPanel.setLayout(new BorderLayout());
|
|
156 |
0
| topPanel.add(settingsPanel, BorderLayout.NORTH);
|
|
157 |
0
| topPanel.add(progressPanel, BorderLayout.CENTER);
|
|
158 |
0
| frame.getContentPane().add(topPanel, BorderLayout.NORTH);
|
|
159 |
0
| frame.getContentPane().add(resultsPanel, BorderLayout.CENTER);
|
|
160 |
0
| frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
|
161 |
0
| frame.pack();
|
|
162 |
0
| frame.show();
|
|
163 |
| } |
|
164 |
| |
|
165 |
0
| private JPanel makeSettingsPanel(JButton browseButton, JButton goButton, JButton cxButton) {
|
|
166 |
0
| JPanel settingsPanel = new JPanel();
|
|
167 |
0
| GridBagHelper helper = new GridBagHelper(settingsPanel, new double[]{0.2, 0.7, 0.1, 0.1});
|
|
168 |
0
| helper.addLabel("Root source directory:");
|
|
169 |
0
| helper.add(rootDirectoryField);
|
|
170 |
0
| helper.add(browseButton, 2);
|
|
171 |
0
| helper.nextRow();
|
|
172 |
0
| helper.addLabel("Report duplicate chunks larger than:");
|
|
173 |
0
| minimumLengthField.setColumns(4);
|
|
174 |
0
| helper.add(minimumLengthField);
|
|
175 |
0
| helper.addLabel("Language:");
|
|
176 |
0
| languageBox.addItem("Java");
|
|
177 |
0
| languageBox.addItem("C++");
|
|
178 |
0
| languageBox.addItem("PHP");
|
|
179 |
0
| languageBox.addItem("Ruby");
|
|
180 |
0
| languageBox.addItem("by extension...");
|
|
181 |
0
| languageBox.addActionListener(new ActionListener() {
|
|
182 |
0
| public void actionPerformed(ActionEvent e) {
|
|
183 |
0
| ignoreLiteralsCheckbox.setEnabled(languageBox.getSelectedItem().equals("Java"));
|
|
184 |
0
| extensionField.setEnabled(languageBox.getSelectedItem().equals("by extension..."));
|
|
185 |
| } |
|
186 |
| }); |
|
187 |
0
| helper.add(languageBox);
|
|
188 |
0
| helper.nextRow();
|
|
189 |
0
| helper.addLabel("Also scan subdirectories?");
|
|
190 |
0
| helper.add(recurseCheckbox);
|
|
191 |
| |
|
192 |
0
| helper.addLabel("Extension:");
|
|
193 |
0
| helper.add(extensionField);
|
|
194 |
0
| extensionField.setEnabled(false);
|
|
195 |
| |
|
196 |
0
| helper.nextRow();
|
|
197 |
0
| helper.addLabel("Ignore literals and identifiers?");
|
|
198 |
0
| helper.add(ignoreLiteralsCheckbox);
|
|
199 |
0
| helper.add(goButton);
|
|
200 |
0
| helper.add(cxButton);
|
|
201 |
0
| helper.nextRow();
|
|
202 |
0
| settingsPanel.setBorder(BorderFactory.createTitledBorder("Settings"));
|
|
203 |
0
| return settingsPanel;
|
|
204 |
| } |
|
205 |
| |
|
206 |
0
| private JPanel makeProgressPanel() {
|
|
207 |
0
| JPanel progressPanel = new JPanel();
|
|
208 |
0
| final double[] weights = {0.0, 0.8, 0.4, 0.2};
|
|
209 |
0
| GridBagHelper helper = new GridBagHelper(progressPanel, weights);
|
|
210 |
0
| helper.addLabel("Tokenizing files:");
|
|
211 |
0
| helper.add(tokenizingFilesBar, 3);
|
|
212 |
0
| helper.nextRow();
|
|
213 |
0
| helper.addLabel("Phase:");
|
|
214 |
0
| helper.add(phaseLabel);
|
|
215 |
0
| helper.addLabel("Time elapsed:");
|
|
216 |
0
| helper.add(timeField);
|
|
217 |
0
| helper.nextRow();
|
|
218 |
0
| progressPanel.setBorder(BorderFactory.createTitledBorder("Progress"));
|
|
219 |
0
| return progressPanel;
|
|
220 |
| } |
|
221 |
| |
|
222 |
0
| private JPanel makeResultsPanel() {
|
|
223 |
0
| JPanel resultsPanel = new JPanel();
|
|
224 |
0
| resultsPanel.setLayout(new BorderLayout());
|
|
225 |
0
| JScrollPane areaScrollPane = new JScrollPane(resultsTextArea);
|
|
226 |
0
| areaScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
|
|
227 |
0
| areaScrollPane.setPreferredSize(new Dimension(600, 300));
|
|
228 |
0
| resultsPanel.add(areaScrollPane, BorderLayout.CENTER);
|
|
229 |
0
| resultsPanel.setBorder(BorderFactory.createTitledBorder("Results"));
|
|
230 |
0
| return resultsPanel;
|
|
231 |
| } |
|
232 |
| |
|
233 |
0
| private void go() {
|
|
234 |
0
| try {
|
|
235 |
0
| if (!(new File(rootDirectoryField.getText())).exists()) {
|
|
236 |
0
| JOptionPane.showMessageDialog(frame,
|
|
237 |
| "Can't read from that root source directory", |
|
238 |
| "Error", |
|
239 |
| JOptionPane.ERROR_MESSAGE); |
|
240 |
0
| return;
|
|
241 |
| } |
|
242 |
| |
|
243 |
0
| Language language = null;
|
|
244 |
0
| LanguageFactory lf = new LanguageFactory();
|
|
245 |
0
| Properties p = new Properties();
|
|
246 |
0
| p.setProperty(JavaTokenizer.IGNORE_LITERALS, String.valueOf(ignoreLiteralsCheckbox.isSelected()));
|
|
247 |
0
| p.setProperty(LanguageFactory.EXTENSION, extensionField.getText());
|
|
248 |
0
| if (languageBox.getSelectedItem().equals("Java")) {
|
|
249 |
0
| language = lf.createLanguage(LanguageFactory.JAVA_KEY, p);
|
|
250 |
0
| } else if (languageBox.getSelectedItem().equals("C++")) {
|
|
251 |
0
| language = lf.createLanguage(LanguageFactory.CPP_KEY);
|
|
252 |
0
| } else if (languageBox.getSelectedItem().equals("Ruby")) {
|
|
253 |
0
| language = lf.createLanguage(LanguageFactory.RUBY_KEY);
|
|
254 |
0
| } else if (languageBox.getSelectedItem().equals("by extension...")) {
|
|
255 |
0
| language = lf.createLanguage(LanguageFactory.BY_EXTENSION, p);
|
|
256 |
0
| } else if (languageBox.getSelectedItem().equals("PHP")) {
|
|
257 |
0
| language = lf.createLanguage(LanguageFactory.PHP_KEY);
|
|
258 |
| } |
|
259 |
0
| CPD cpd = new CPD(Integer.parseInt(minimumLengthField.getText()), language);
|
|
260 |
0
| cpd.setCpdListener(this);
|
|
261 |
0
| tokenizingFilesBar.setMinimum(0);
|
|
262 |
0
| phaseLabel.setText("");
|
|
263 |
0
| if (rootDirectoryField.getText().endsWith(".class")
|
|
264 |
| || rootDirectoryField.getText().endsWith(".php") |
|
265 |
| || rootDirectoryField.getText().endsWith(".rb") |
|
266 |
| || rootDirectoryField.getText().endsWith(".java") |
|
267 |
| || rootDirectoryField.getText().endsWith(".cpp") |
|
268 |
| || rootDirectoryField.getText().endsWith(".c")) { |
|
269 |
0
| cpd.add(new File(rootDirectoryField.getText()));
|
|
270 |
| } else { |
|
271 |
0
| if (recurseCheckbox.isSelected()) {
|
|
272 |
0
| cpd.addRecursively(rootDirectoryField.getText());
|
|
273 |
| } else { |
|
274 |
0
| cpd.addAllInDirectory(rootDirectoryField.getText());
|
|
275 |
| } |
|
276 |
| } |
|
277 |
0
| final long start = System.currentTimeMillis();
|
|
278 |
0
| Timer t = new Timer(1000, new ActionListener() {
|
|
279 |
0
| public void actionPerformed(ActionEvent e) {
|
|
280 |
0
| long now = System.currentTimeMillis();
|
|
281 |
0
| long elapsedMillis = now - start;
|
|
282 |
0
| long elapsedSeconds = elapsedMillis / 1000;
|
|
283 |
0
| long minutes = (long) Math.floor(elapsedSeconds / 60);
|
|
284 |
0
| long seconds = elapsedSeconds - (minutes * 60);
|
|
285 |
0
| timeField.setText(""
|
|
286 |
| + munge(String.valueOf(minutes)) |
|
287 |
| + ":" |
|
288 |
| + munge(String.valueOf(seconds))); |
|
289 |
| } |
|
290 |
| |
|
291 |
0
| private String munge(String in) {
|
|
292 |
0
| if (in.length() < 2) {
|
|
293 |
0
| in = "0" + in;
|
|
294 |
| } |
|
295 |
0
| return in;
|
|
296 |
| } |
|
297 |
| |
|
298 |
| }); |
|
299 |
0
| t.start();
|
|
300 |
0
| cpd.go();
|
|
301 |
0
| t.stop();
|
|
302 |
0
| matches = new ArrayList();
|
|
303 |
0
| for (Iterator i = cpd.getMatches(); i.hasNext();) {
|
|
304 |
0
| Match m = (Match) i.next();
|
|
305 |
0
| matches.add(m);
|
|
306 |
| } |
|
307 |
| |
|
308 |
0
| String report = new SimpleRenderer().render(cpd.getMatches());
|
|
309 |
0
| if (report.length() == 0) {
|
|
310 |
0
| JOptionPane.showMessageDialog(frame,
|
|
311 |
| "Done; couldn't find any duplicates longer than " + minimumLengthField.getText() + " tokens"); |
|
312 |
| } else { |
|
313 |
0
| resultsTextArea.setText(report);
|
|
314 |
| } |
|
315 |
| } catch (Throwable t) { |
|
316 |
0
| t.printStackTrace();
|
|
317 |
0
| JOptionPane.showMessageDialog(frame, "Halted due to " + t.getClass().getName() + "; " + t.getMessage());
|
|
318 |
| } |
|
319 |
| } |
|
320 |
| |
|
321 |
| |
|
322 |
0
| public void phaseUpdate(int phase) {
|
|
323 |
0
| phaseLabel.setText(getPhaseText(phase));
|
|
324 |
| } |
|
325 |
| |
|
326 |
0
| public String getPhaseText(int phase) {
|
|
327 |
0
| switch (phase) {
|
|
328 |
0
| case CPDListener.INIT:
|
|
329 |
0
| return "Initializing";
|
|
330 |
0
| case CPDListener.HASH:
|
|
331 |
0
| return "Hashing";
|
|
332 |
0
| case CPDListener.MATCH:
|
|
333 |
0
| return "Matching";
|
|
334 |
0
| case CPDListener.GROUPING:
|
|
335 |
0
| return "Grouping";
|
|
336 |
0
| case CPDListener.DONE:
|
|
337 |
0
| return "Done";
|
|
338 |
0
| default :
|
|
339 |
0
| return "Unknown";
|
|
340 |
| } |
|
341 |
| } |
|
342 |
| |
|
343 |
0
| public void addedFile(int fileCount, File file) {
|
|
344 |
0
| tokenizingFilesBar.setMaximum(fileCount);
|
|
345 |
0
| tokenizingFilesBar.setValue(tokenizingFilesBar.getValue() + 1);
|
|
346 |
| } |
|
347 |
| |
|
348 |
| |
|
349 |
0
| public static void main(String[] args) {
|
|
350 |
| |
|
351 |
0
| System.setSecurityManager(null);
|
|
352 |
0
| new GUI();
|
|
353 |
| } |
|
354 |
| |
|
355 |
| } |