001: package org.acm.seguin.pmd.cpd;
002:
003: import javax.swing.BorderFactory;
004: import javax.swing.JButton;
005: import javax.swing.JCheckBox;
006: import javax.swing.JComboBox;
007: import javax.swing.JFileChooser;
008: import javax.swing.JFrame;
009: import javax.swing.JMenu;
010: import javax.swing.JMenuBar;
011: import javax.swing.JMenuItem;
012: import javax.swing.JOptionPane;
013: import javax.swing.JPanel;
014: import javax.swing.JProgressBar;
015: import javax.swing.JScrollPane;
016: import javax.swing.JTextArea;
017: import javax.swing.JTextField;
018: import javax.swing.Timer;
019: import java.awt.BorderLayout;
020: import java.awt.Dimension;
021: import java.awt.FileDialog;
022: import java.awt.event.ActionEvent;
023: import java.awt.event.ActionListener;
024: import java.io.File;
025: import java.io.FileOutputStream;
026: import java.io.IOException;
027: import java.io.PrintWriter;
028:
029: public class GUI implements CPDListener {
030:
031: private static class CancelListener implements ActionListener {
032: public void actionPerformed(ActionEvent e) {
033: System.exit(0);
034: }
035: }
036:
037: private class GoListener implements ActionListener {
038: public void actionPerformed(ActionEvent e) {
039: new Thread(new Runnable() {
040: public void run() {
041: tokenizingFilesBar.setValue(0);
042: tokenizingFilesBar.setString("");
043: resultsTextArea.setText("");
044: comparisonsField.setText("");
045: timeField.setText("");
046: go();
047: }
048: }).start();
049: }
050: }
051:
052: private class SaveListener implements ActionListener {
053: public void actionPerformed(ActionEvent evt) {
054: FileDialog fdlg = new FileDialog(GUI.this .frame, "Save",
055: FileDialog.SAVE);
056: fdlg.setVisible(true);
057: String selected = fdlg.getDirectory()
058: + System.getProperty("file.separator")
059: + fdlg.getFile();
060: if (fdlg.getFile() == null) {
061: return;
062: }
063: if (!new File(selected).canWrite()) {
064: try {
065: PrintWriter pw = new PrintWriter(
066: new FileOutputStream(selected));
067: String report = resultsTextArea.getText();
068: pw.print(report);
069: pw.flush();
070: pw.close();
071: JOptionPane.showMessageDialog(frame, "File saved");
072: } catch (IOException e) {
073: error("Couldn't save file"
074: + new File(selected).getAbsolutePath(), e);
075: }
076: } else {
077: error("Could not write to file "
078: + new File(selected).getAbsolutePath(), null);
079: }
080: }
081:
082: private void error(String message, Exception e) {
083: if (e != null) {
084: e.printStackTrace();
085: }
086: JOptionPane.showMessageDialog(GUI.this .frame, message);
087: }
088:
089: }
090:
091: private class BrowseListener implements ActionListener {
092: public void actionPerformed(ActionEvent e) {
093: JFileChooser fc = new JFileChooser(rootDirectoryField
094: .getText());
095: fc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
096: fc.showDialog(frame, "Select");
097: if (fc.getSelectedFile() != null) {
098: rootDirectoryField.setText(fc.getSelectedFile()
099: .getAbsolutePath());
100: }
101: }
102: }
103:
104: private JTextField rootDirectoryField = new JTextField(System
105: .getProperty("user.home"));
106: private JTextField minimumLengthField = new JTextField("75");
107: private JTextField timeField = new JTextField(6);
108: private JTextField comparisonsField = new JTextField(8);
109: private JProgressBar tokenizingFilesBar = new JProgressBar();
110: private JTextArea resultsTextArea = new JTextArea();
111: private JCheckBox recurseCheckbox = new JCheckBox("", true);
112: private JComboBox languageBox = new JComboBox();
113:
114: private JFrame frame;
115:
116: public GUI() {
117: frame = new JFrame("PMD Cut and Paste Detector");
118:
119: timeField.setEditable(false);
120: comparisonsField.setEditable(false);
121:
122: JMenu fileMenu = new JMenu("File");
123: fileMenu.setMnemonic('f');
124: JMenuItem saveItem = new JMenuItem("Save");
125: saveItem.setMnemonic('s');
126: saveItem.addActionListener(new SaveListener());
127: fileMenu.add(saveItem);
128: JMenuItem exitItem = new JMenuItem("Exit");
129: exitItem.setMnemonic('x');
130: exitItem.addActionListener(new CancelListener());
131: fileMenu.add(exitItem);
132: JMenuBar menuBar = new JMenuBar();
133: menuBar.add(fileMenu);
134: frame.setJMenuBar(menuBar);
135:
136: // first make all the buttons
137: JButton browseButton = new JButton("Browse");
138: browseButton.setMnemonic('b');
139: browseButton.addActionListener(new BrowseListener());
140: JButton goButton = new JButton("Go");
141: goButton.setMnemonic('g');
142: goButton.addActionListener(new GoListener());
143: JButton cxButton = new JButton("Cancel");
144: cxButton.addActionListener(new CancelListener());
145:
146: JPanel settingsPanel = makeSettingsPanel(browseButton,
147: goButton, cxButton);
148: JPanel progressPanel = makeProgressPanel();
149: JPanel resultsPanel = makeResultsPanel();
150:
151: frame.getContentPane().setLayout(new BorderLayout());
152: JPanel topPanel = new JPanel();
153: topPanel.setLayout(new BorderLayout());
154: topPanel.add(settingsPanel, BorderLayout.NORTH);
155: topPanel.add(progressPanel, BorderLayout.CENTER);
156: frame.getContentPane().add(topPanel, BorderLayout.NORTH);
157: frame.getContentPane().add(resultsPanel, BorderLayout.CENTER);
158: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
159: frame.pack();
160: frame.show();
161: }
162:
163: private JPanel makeSettingsPanel(JButton browseButton,
164: JButton goButton, JButton cxButton) {
165: JPanel settingsPanel = new JPanel();
166: GridBagHelper helper = new GridBagHelper(settingsPanel,
167: new double[] { 0.2, 0.7, 0.1, 0.1 });
168: helper.addLabel("Root source directory:");
169: helper.add(rootDirectoryField);
170: helper.add(browseButton, 2);
171: helper.nextRow();
172: helper.addLabel("Minimum tile size:");
173: minimumLengthField.setColumns(4);
174: helper.add(minimumLengthField);
175: helper.addLabel("Language:");
176: languageBox.addItem("Java");
177: languageBox.addItem("C++");
178: languageBox.addItem("PHP");
179: helper.add(languageBox);
180: helper.nextRow();
181: helper.addLabel("Also scan subdirectories?");
182: helper.add(recurseCheckbox);
183: helper.add(goButton);
184: helper.add(cxButton);
185: helper.nextRow();
186: settingsPanel.setBorder(BorderFactory
187: .createTitledBorder("Settings"));
188: return settingsPanel;
189: }
190:
191: private JPanel makeProgressPanel() {
192: JPanel progressPanel = new JPanel();
193: final double[] weights = { 0.0, 0.8, 0.4, 0.2 };
194: GridBagHelper helper = new GridBagHelper(progressPanel, weights);
195: helper.addLabel("Tokenizing files:");
196: helper.add(tokenizingFilesBar, 3);
197: helper.nextRow();
198: helper.addLabel("Comparisons so far:");
199: helper.add(comparisonsField);
200: helper.addLabel("Time elapsed:");
201: helper.add(timeField);
202: helper.nextRow();
203: progressPanel.setBorder(BorderFactory
204: .createTitledBorder("Progress"));
205: return progressPanel;
206: }
207:
208: private JPanel makeResultsPanel() {
209: JPanel resultsPanel = new JPanel();
210: resultsPanel.setLayout(new BorderLayout());
211: JScrollPane areaScrollPane = new JScrollPane(resultsTextArea);
212: areaScrollPane
213: .setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
214: areaScrollPane.setPreferredSize(new Dimension(600, 300));
215: resultsPanel.add(areaScrollPane, BorderLayout.CENTER);
216: resultsPanel.setBorder(BorderFactory
217: .createTitledBorder("Results"));
218: return resultsPanel;
219: }
220:
221: private void go() {
222: try {
223: if (!(new File(rootDirectoryField.getText())).exists()) {
224: JOptionPane.showMessageDialog(frame,
225: "Can't read from that root source directory",
226: "Error", JOptionPane.ERROR_MESSAGE);
227: return;
228: }
229:
230: Language language = null;
231: LanguageFactory lf = new LanguageFactory();
232: if (languageBox.getSelectedItem().equals("Java")) {
233: language = lf.createLanguage(LanguageFactory.JAVA_KEY);
234: } else if (languageBox.getSelectedItem().equals("C++")) {
235: language = lf.createLanguage(LanguageFactory.CPP_KEY);
236: } else if (languageBox.getSelectedItem().equals("PHP")) {
237: language = lf.createLanguage(LanguageFactory.PHP_KEY);
238: }
239:
240: CPD cpd = new CPD(Integer.parseInt(minimumLengthField
241: .getText()), language);
242: cpd.setCpdListener(this );
243: tokenizingFilesBar.setMinimum(0);
244: comparisonsField.setText("");
245: if (rootDirectoryField.getText().endsWith(".class")
246: || rootDirectoryField.getText().endsWith(".php")
247: || rootDirectoryField.getText().endsWith(".java")
248: || rootDirectoryField.getText().endsWith(".cpp")
249: || rootDirectoryField.getText().endsWith(".c")) {
250: cpd.add(new File(rootDirectoryField.getText()));
251: } else {
252: if (recurseCheckbox.isSelected()) {
253: cpd.addRecursively(rootDirectoryField.getText());
254: } else {
255: cpd.addAllInDirectory(rootDirectoryField.getText());
256: }
257: }
258: final long start = System.currentTimeMillis();
259: Timer t = new Timer(1000, new ActionListener() {
260: public void actionPerformed(ActionEvent e) {
261: long now = System.currentTimeMillis();
262: long elapsedMillis = now - start;
263: long elapsedSeconds = elapsedMillis / 1000;
264: long hours = (long) Math
265: .floor(elapsedSeconds / 3600);
266: long minutes = (long) Math
267: .floor((elapsedSeconds - (hours * 3600)) / 60);
268: long seconds = elapsedSeconds
269: - ((minutes * 60) + (hours * 3600));
270: timeField.setText("" + munge(String.valueOf(hours))
271: + ":" + munge(String.valueOf(minutes))
272: + ":" + munge(String.valueOf(seconds)));
273: }
274:
275: private String munge(String in) {
276: if (in.length() < 2) {
277: in = "0" + in;
278: }
279: return in;
280: }
281:
282: });
283: t.start();
284: cpd.go();
285: t.stop();
286: String report = new SimpleRenderer().render(cpd
287: .getMatches());
288: if (report.length() == 0) {
289: JOptionPane.showMessageDialog(frame,
290: "Done; couldn't find any duplicates longer than "
291: + minimumLengthField.getText()
292: + " tokens");
293: } else {
294: resultsTextArea.setText(report);
295: }
296: } catch (Throwable t) {
297: t.printStackTrace();
298: JOptionPane.showMessageDialog(frame, "Halted due to "
299: + t.getClass().getName() + "; " + t.getMessage());
300: }
301: }
302:
303: // CPDListener
304: public void comparisonCountUpdate(long comparisons) {
305: comparisonsField.setText(String.valueOf(comparisons));
306: }
307:
308: public void addedFile(int fileCount, File file) {
309: tokenizingFilesBar.setMaximum(fileCount);
310: tokenizingFilesBar.setValue(tokenizingFilesBar.getValue() + 1);
311: }
312:
313: // CPDListener
314:
315: public static void main(String[] args) {
316: new GUI();
317: }
318:
319: }
|