View Javadoc

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