/** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ package net.sourceforge.pmd.cpd; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class GUI implements CPDListener { private static class CancelListener implements ActionListener { public void actionPerformed(ActionEvent e) { System.exit(0); } } private class GoListener implements ActionListener { public void actionPerformed(ActionEvent e) { new Thread(new Runnable() { public void run() { tokenizingFilesBar.setValue(0); tokenizingFilesBar.setString(""); resultsTextArea.setText(""); phaseLabel.setText(""); timeField.setText(""); go(); } }).start(); } } private class SaveListener implements ActionListener { public void actionPerformed(ActionEvent evt) { int ret = fcSave.showSaveDialog(GUI.this.frame); File f = fcSave.getSelectedFile(); if (f == null || ret != JFileChooser.APPROVE_OPTION) { return; } if (!f.canWrite()) { try { PrintWriter pw = new PrintWriter(new FileOutputStream(f)); if (evt.getActionCommand().equals(".txt")) { pw.write(new SimpleRenderer().render(matches.iterator())); } else if (evt.getActionCommand().equals(".xml")) { pw.write(new XMLRenderer().render(matches.iterator())); } else if (evt.getActionCommand().equals(".csv")) { pw.write(new CSVRenderer().render(matches.iterator())); } pw.flush(); pw.close(); JOptionPane.showMessageDialog(frame, "File saved"); } catch (IOException e) { error("Couldn't save file" + f.getAbsolutePath(), e); } } else { error("Could not write to file " + f.getAbsolutePath(), null); } } private void error(String message, Exception e) { if (e != null) { e.printStackTrace(); } JOptionPane.showMessageDialog(GUI.this.frame, message); } } private class BrowseListener implements ActionListener { public void actionPerformed(ActionEvent e) { JFileChooser fc = new JFileChooser(rootDirectoryField.getText()); fc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); fc.showDialog(frame, "Select"); if (fc.getSelectedFile() != null) { rootDirectoryField.setText(fc.getSelectedFile().getAbsolutePath()); } } } private JTextField rootDirectoryField = new JTextField(System.getProperty("user.home")); private JTextField minimumLengthField = new JTextField("75"); private JTextField timeField = new JTextField(6); private JLabel phaseLabel = new JLabel(); private JProgressBar tokenizingFilesBar = new JProgressBar(); private JTextArea resultsTextArea = new JTextArea(); private JCheckBox recurseCheckbox = new JCheckBox("", true); private JComboBox languageBox = new JComboBox(); private JFileChooser fcSave = new JFileChooser(); private JFrame frame; private List matches = new ArrayList(); public GUI() { frame = new JFrame("PMD Cut and Paste Detector"); timeField.setEditable(false); JMenu fileMenu = new JMenu("File"); fileMenu.setMnemonic('f'); JMenuItem saveItem = new JMenuItem("Save Text"); saveItem.setMnemonic('s'); saveItem.addActionListener(new SaveListener()); fileMenu.add(saveItem); saveItem.setActionCommand(".txt"); saveItem = new JMenuItem("Save XML"); saveItem.addActionListener(new SaveListener()); fileMenu.add(saveItem); saveItem.setActionCommand(".xml"); saveItem = new JMenuItem("Save CSV"); saveItem.setActionCommand(".csv"); saveItem.addActionListener(new SaveListener()); fileMenu.add(saveItem); JMenuItem exitItem = new JMenuItem("Exit"); exitItem.setMnemonic('x'); exitItem.addActionListener(new CancelListener()); fileMenu.add(exitItem); JMenuBar menuBar = new JMenuBar(); menuBar.add(fileMenu); frame.setJMenuBar(menuBar); // first make all the buttons JButton browseButton = new JButton("Browse"); browseButton.setMnemonic('b'); browseButton.addActionListener(new BrowseListener()); JButton goButton = new JButton("Go"); goButton.setMnemonic('g'); goButton.addActionListener(new GoListener()); JButton cxButton = new JButton("Cancel"); cxButton.addActionListener(new CancelListener()); JPanel settingsPanel = makeSettingsPanel(browseButton, goButton, cxButton); JPanel progressPanel = makeProgressPanel(); JPanel resultsPanel = makeResultsPanel(); frame.getContentPane().setLayout(new BorderLayout()); JPanel topPanel = new JPanel(); topPanel.setLayout(new BorderLayout()); topPanel.add(settingsPanel, BorderLayout.NORTH); topPanel.add(progressPanel, BorderLayout.CENTER); frame.getContentPane().add(topPanel, BorderLayout.NORTH); frame.getContentPane().add(resultsPanel, BorderLayout.CENTER); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.show(); } private JPanel makeSettingsPanel(JButton browseButton, JButton goButton, JButton cxButton) { JPanel settingsPanel = new JPanel(); GridBagHelper helper = new GridBagHelper(settingsPanel, new double[] { 0.2, 0.7, 0.1, 0.1 }); helper.addLabel("Root source directory:"); helper.add(rootDirectoryField); helper.add(browseButton, 2); helper.nextRow(); helper.addLabel("Minimum tile size:"); minimumLengthField.setColumns(4); helper.add(minimumLengthField); helper.addLabel("Language:"); languageBox.addItem("Java"); languageBox.addItem("C++"); languageBox.addItem("PHP"); helper.add(languageBox); helper.nextRow(); helper.addLabel("Also scan subdirectories?"); helper.add(recurseCheckbox); helper.add(goButton); helper.add(cxButton); helper.nextRow(); settingsPanel.setBorder(BorderFactory.createTitledBorder("Settings")); return settingsPanel; } private JPanel makeProgressPanel() { JPanel progressPanel = new JPanel(); final double[] weights = { 0.0, 0.8, 0.4, 0.2 }; GridBagHelper helper = new GridBagHelper(progressPanel, weights); helper.addLabel("Tokenizing files:"); helper.add(tokenizingFilesBar, 3); helper.nextRow(); helper.addLabel("Phase:"); helper.add(phaseLabel); helper.addLabel("Time elapsed:"); helper.add(timeField); helper.nextRow(); progressPanel.setBorder(BorderFactory.createTitledBorder("Progress")); return progressPanel; } private JPanel makeResultsPanel() { JPanel resultsPanel = new JPanel(); resultsPanel.setLayout(new BorderLayout()); JScrollPane areaScrollPane = new JScrollPane(resultsTextArea); areaScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); areaScrollPane.setPreferredSize(new Dimension(600, 300)); resultsPanel.add(areaScrollPane, BorderLayout.CENTER); resultsPanel.setBorder(BorderFactory.createTitledBorder("Results")); return resultsPanel; } private void go() { try { if (!(new File(rootDirectoryField.getText())).exists()) { JOptionPane.showMessageDialog( frame, "Can't read from that root source directory", "Error", JOptionPane.ERROR_MESSAGE); return; } Language language = null; LanguageFactory lf = new LanguageFactory(); if (languageBox.getSelectedItem().equals("Java")) { language = lf.createLanguage(LanguageFactory.JAVA_KEY); } else if (languageBox.getSelectedItem().equals("C++")) { language = lf.createLanguage(LanguageFactory.CPP_KEY); } else if (languageBox.getSelectedItem().equals("PHP")) { language = lf.createLanguage(LanguageFactory.PHP_KEY); } CPD cpd = new CPD(Integer.parseInt(minimumLengthField.getText()), language); cpd.setCpdListener(this); tokenizingFilesBar.setMinimum(0); phaseLabel.setText(""); if (rootDirectoryField.getText().endsWith(".class") || rootDirectoryField.getText().endsWith(".php") || rootDirectoryField.getText().endsWith(".java") || rootDirectoryField.getText().endsWith(".cpp") || rootDirectoryField.getText().endsWith(".c")) { cpd.add(new File(rootDirectoryField.getText())); } else { if (recurseCheckbox.isSelected()) { cpd.addRecursively(rootDirectoryField.getText()); } else { cpd.addAllInDirectory(rootDirectoryField.getText()); } } final long start = System.currentTimeMillis(); Timer t = new Timer(1000, new ActionListener() { public void actionPerformed(ActionEvent e) { long now = System.currentTimeMillis(); long elapsedMillis = now - start; long elapsedSeconds = elapsedMillis / 1000; long hours = (long) Math.floor(elapsedSeconds / 3600); long minutes = (long) Math.floor((elapsedSeconds - (hours * 3600)) / 60); long seconds = elapsedSeconds - ((minutes * 60) + (hours * 3600)); timeField.setText( "" + munge(String.valueOf(hours)) + ":" + munge(String.valueOf(minutes)) + ":" + munge(String.valueOf(seconds))); } private String munge(String in) { if (in.length() < 2) { in = "0" + in; } return in; } }); t.start(); cpd.go(); t.stop(); matches = new ArrayList(); for (Iterator i = cpd.getMatches(); i.hasNext();) { Match m = (Match) i.next(); matches.add(m); } String report = new SimpleRenderer().render(cpd.getMatches()); if (report.length() == 0) { JOptionPane.showMessageDialog( frame, "Done; couldn't find any duplicates longer than " + minimumLengthField.getText() + " tokens"); } else { resultsTextArea.setText(report); } } catch (Throwable t) { t.printStackTrace(); JOptionPane.showMessageDialog(frame, "Halted due to " + t.getClass().getName() + "; " + t.getMessage()); } } // CPDListener public void phaseUpdate(int phase) { phaseLabel.setText(getPhaseText(phase)); } public String getPhaseText(int phase) { switch (phase) { case CPDListener.INIT : return "Initializing"; case CPDListener.HASH : return "Hashing"; case CPDListener.MATCH : return "Matching"; case CPDListener.GROUPING : return "Grouping"; case CPDListener.DONE : return "Done"; default : return "Unknown"; } } public void addedFile(int fileCount, File file) { tokenizingFilesBar.setMaximum(fileCount); tokenizingFilesBar.setValue(tokenizingFilesBar.getValue() + 1); } // CPDListener public static void main(String[] args) { //this should prevent the disk not found popup System.setSecurityManager(null); new GUI(); } }