Clover coverage report - PMD - 3.9 Coverage timestamp: Tue Dec 19 2006 09:38:44 EST FRAMES NO FRAMES |
file stats: | LOC: | 682 |  | Methods: | 80
| NCLOC: | 575 |  | Classes: | 10
Source file | Conditionals | Statements | Methods | TOTAL
GUI.java | 0% | 0% | 0% | 0% |

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 javax.swing.event.ListSelectionEvent;
8 |  | import javax.swing.event.ListSelectionListener;
9 |  | import javax.swing.event.TableModelListener;
10 |  | import javax.swing.table.DefaultTableCellRenderer;
11 |  | import javax.swing.table.JTableHeader;
12 |  | import javax.swing.table.TableColumn;
13 |  | import javax.swing.table.TableColumnModel;
14 |  | import javax.swing.table.TableModel;
15 |  | import java.awt.BorderLayout;
16 |  | import java.awt.Component;
17 |  | import java.awt.Dimension;
18 |  | import java.awt.Point;
19 |  | import java.awt.Toolkit;
20 |  | import java.awt.datatransfer.StringSelection;
21 |  | import java.awt.event.ActionEvent;
22 |  | import java.awt.event.ActionListener;
23 |  | import java.awt.event.ItemEvent;
24 |  | import java.awt.event.ItemListener;
25 |  | import java.awt.event.KeyEvent;
26 |  | import java.awt.event.MouseAdapter;
27 |  | import java.awt.event.MouseEvent;
28 |  | import java.io.File;
29 |  | import java.io.FileOutputStream;
30 |  | import java.io.IOException;
31 |  | import java.io.PrintWriter;
32 |  | import java.util.ArrayList;
33 |  | import java.util.Collections;
34 |  | import java.util.Comparator;
35 |  | import java.util.HashMap;
36 |  | import java.util.HashSet;
37 |  | import java.util.Iterator;
38 |  | import java.util.List;
39 |  | import java.util.Map;
40 |  | import java.util.Properties;
41 |  | import java.util.Set;
42 |  |
43 |  | public class GUI implements CPDListener {
44 |  |
45 |  | private interface Renderer {
46 |  | String render(Iterator items);
47 |  | }
48 |  |
49 |  | private static final Object[][] rendererSets = new Object[][] {
50 | 0 | { "Text", new Renderer() { public String render(Iterator items) { return new SimpleRenderer().render(items); } } },
51 | 0 | { "XML", new Renderer() { public String render(Iterator items) { return new XMLRenderer().render(items); } } },
52 | 0 | { "CSV (comma)",new Renderer() { public String render(Iterator items) { return new CSVRenderer(',').render(items); } } },
53 | 0 | { "CSV (tab)", new Renderer() { public String render(Iterator items) { return new CSVRenderer('\t').render(items); } } }
54 |  | };
55 |  |
56 |  | private interface LanguageConfig {
57 |  | Language languageFor(LanguageFactory lf, Properties p);
58 |  | boolean ignoreLiteralsByDefault();
59 |  | String[] extensions();
60 |  | };
61 |  |
62 |  | private static final Object[][] languageSets = new Object[][] {
63 |  | {"Java", new LanguageConfig() {
64 | 0 | public Language languageFor(LanguageFactory lf, Properties p) { return lf.createLanguage(LanguageFactory.JAVA_KEY); }
65 | 0 | public boolean ignoreLiteralsByDefault() { return true; }
66 | 0 | public String[] extensions() { return new String[] {".java", ".class" }; }; } },
67 |  | {"JSP", new LanguageConfig() {
68 | 0 | public Language languageFor(LanguageFactory lf, Properties p) { return lf.createLanguage(LanguageFactory.JSP_KEY); }
69 | 0 | public boolean ignoreLiteralsByDefault() { return false; }
70 | 0 | public String[] extensions() { return new String[] {".jsp" }; }; } },
71 |  | {"C++", new LanguageConfig() {
72 | 0 | public Language languageFor(LanguageFactory lf, Properties p) { return lf.createLanguage(LanguageFactory.CPP_KEY); }
73 | 0 | public boolean ignoreLiteralsByDefault() { return false; }
74 | 0 | public String[] extensions() { return new String[] {".cpp", ".c" }; }; } },
75 |  | {"Ruby", new LanguageConfig() {
76 | 0 | public Language languageFor(LanguageFactory lf, Properties p) { return lf.createLanguage(LanguageFactory.RUBY_KEY); }
77 | 0 | public boolean ignoreLiteralsByDefault() { return false; }
78 | 0 | public String[] extensions() { return new String[] {".rb" }; }; } },
79 |  | {"by extension...", new LanguageConfig() {
80 | 0 | public Language languageFor(LanguageFactory lf, Properties p) { return lf.createLanguage(LanguageFactory.BY_EXTENSION, p); }
81 | 0 | public boolean ignoreLiteralsByDefault() { return false; }
82 | 0 | public String[] extensions() { return new String[] {"" }; }; } },
83 |  | {"PHP", new LanguageConfig() {
84 | 0 | public Language languageFor(LanguageFactory lf, Properties p) { return lf.createLanguage(LanguageFactory.PHP_KEY); }
85 | 0 | public boolean ignoreLiteralsByDefault() { return false; }
86 | 0 | public String[] extensions() { return new String[] {".php" }; }; } },
87 |  | };
88 |  |
89 |  | private static final int defaultCPDMinimumLength = 75;
90 |  | private static final Map langConfigsByLabel = new HashMap(languageSets.length);
91 |  | private static final KeyStroke copy = KeyStroke.getKeyStroke(KeyEvent.VK_C,ActionEvent.CTRL_MASK,false);
92 |  | private static final KeyStroke delete = KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0);
93 |  |
94 |  | private class ColumnSpec {
95 |  | private String label;
96 |  | private int alignment;
97 |  | private int width;
98 |  | private Comparator sorter;
99 |  |
100 | 0 | public ColumnSpec(String aLabel, int anAlignment, int aWidth, Comparator aSorter) {
101 | 0 | label = aLabel;
102 | 0 | alignment = anAlignment;
103 | 0 | width = aWidth;
104 | 0 | sorter = aSorter;
105 |  | }
106 | 0 | public String label() { return label; };
107 | 0 | public int alignment() { return alignment; };
108 | 0 | public int width() { return width; };
109 | 0 | public Comparator sorter() { return sorter; };
110 |  | }
111 |  |
112 |  | private final ColumnSpec[] matchColumns = new ColumnSpec[] {
113 |  | new ColumnSpec("Source", SwingConstants.LEFT, -1, Match.LabelComparator),
114 |  | new ColumnSpec("Matches", SwingConstants.RIGHT, 60, Match.MatchesComparator),
115 |  | new ColumnSpec("Lines", SwingConstants.RIGHT, 45, Match.LinesComparator),
116 |  | };
117 |  |
118 |  | static {
119 | 0 | for (int i=0; i<languageSets.length; i++) {
120 | 0 | langConfigsByLabel.put(languageSets[i][0], languageSets[i][1]);
121 |  | }
122 |  | }
123 |  |
124 | 0 | private static LanguageConfig languageConfigFor(String label) {
125 | 0 | return (LanguageConfig)langConfigsByLabel.get(label);
126 |  | }
127 |  |
128 |  | private static class CancelListener implements ActionListener {
129 | 0 | public void actionPerformed(ActionEvent e) {
130 | 0 | System.exit(0);
131 |  | }
132 |  | }
133 |  |
134 |  | private class GoListener implements ActionListener {
135 | 0 | public void actionPerformed(ActionEvent e) {
136 | 0 | new Thread(new Runnable() {
137 | 0 | public void run() {
138 | 0 | tokenizingFilesBar.setValue(0);
139 | 0 | tokenizingFilesBar.setString("");
140 | 0 | resultsTextArea.setText("");
141 | 0 | phaseLabel.setText("");
142 | 0 | timeField.setText("");
143 | 0 | go();
144 |  | }
145 |  | }).start();
146 |  | }
147 |  | }
148 |  |
149 |  | private class SaveListener implements ActionListener {
150 |  |
151 |  | final Renderer renderer;
152 |  |
153 | 0 | public SaveListener(Renderer theRenderer) {
154 | 0 | renderer = theRenderer;
155 |  | }
156 |  |
157 | 0 | public void actionPerformed(ActionEvent evt) {
158 | 0 | JFileChooser fcSave = new JFileChooser();
159 | 0 | int ret = fcSave.showSaveDialog(GUI.this.frame);
160 | 0 | File f = fcSave.getSelectedFile();
161 | 0 | if (f == null || ret != JFileChooser.APPROVE_OPTION) return;
162 |  |
163 | 0 | if (!f.canWrite()) {
164 | 0 | PrintWriter pw = null;
165 | 0 | try {
166 | 0 | pw = new PrintWriter(new FileOutputStream(f));
167 | 0 | pw.write(renderer.render(matches.iterator()));
168 | 0 | pw.flush();
169 | 0 | JOptionPane.showMessageDialog(frame, "Saved " + matches.size() + " matches");
170 |  | } catch (IOException e) {
171 | 0 | error("Couldn't save file" + f.getAbsolutePath(), e);
172 |  | } finally {
173 | 0 | if (pw != null) pw.close();
174 |  | }
175 |  | } else {
176 | 0 | error("Could not write to file " + f.getAbsolutePath(), null);
177 |  | }
178 |  | }
179 |  |
180 | 0 | private void error(String message, Exception e) {
181 | 0 | if (e != null) {
182 | 0 | e.printStackTrace();
183 |  | }
184 | 0 | JOptionPane.showMessageDialog(GUI.this.frame, message);
185 |  | }
186 |  |
187 |  | }
188 |  |
189 |  | private class BrowseListener implements ActionListener {
190 | 0 | public void actionPerformed(ActionEvent e) {
191 | 0 | JFileChooser fc = new JFileChooser(rootDirectoryField.getText());
192 | 0 | fc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
193 | 0 | fc.showDialog(frame, "Select");
194 | 0 | if (fc.getSelectedFile() != null) {
195 | 0 | rootDirectoryField.setText(fc.getSelectedFile().getAbsolutePath());
196 |  | }
197 |  | }
198 |  | }
199 |  |
200 |  | private class AlignmentRenderer extends DefaultTableCellRenderer {
201 |  |
202 |  | private int[] alignments;
203 |  |
204 | 0 | public AlignmentRenderer(int[] theAlignments) {
205 | 0 | alignments = theAlignments;
206 |  | };
207 |  |
208 | 0 | public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
209 | 0 | super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
210 |  |
211 | 0 | setHorizontalAlignment(alignments[column]);
212 |  |
213 | 0 | return this;
214 |  | }
215 |  | }
216 |  |
217 |  | private JTextField rootDirectoryField = new JTextField(System.getProperty("user.home"));
218 |  | private JTextField minimumLengthField = new JTextField(Integer.toString(defaultCPDMinimumLength));
219 |  | private JTextField timeField = new JTextField(6);
220 |  | private JLabel phaseLabel = new JLabel();
221 |  | private JProgressBar tokenizingFilesBar = new JProgressBar();
222 |  | private JTextArea resultsTextArea = new JTextArea();
223 |  | private JCheckBox recurseCheckbox = new JCheckBox("", true);
224 |  | private JCheckBox ignoreLiteralsCheckbox = new JCheckBox("", false);
225 |  | private JComboBox languageBox = new JComboBox();
226 |  | private JTextField extensionField = new JTextField();
227 |  | private JLabel extensionLabel = new JLabel("Extension:", SwingConstants.RIGHT);
228 |  | private JTable resultsTable = new JTable();
229 |  | private JButton goButton;
230 |  | private JButton cancelButton;
231 |  | private JPanel progressPanel;
232 |  | private JFrame frame;
233 |  | private boolean trimLeadingWhitespace;
234 |  |
235 |  | private List matches = new ArrayList();
236 |  |
237 | 0 | private void addSaveOptionsTo(JMenu menu) {
238 |  |
239 | 0 | JMenuItem saveItem;
240 |  |
241 | 0 | for (int i=0; i<rendererSets.length; i++) {
242 | 0 | saveItem = new JMenuItem("Save as " + rendererSets[i][0]);
243 | 0 | saveItem.addActionListener(new SaveListener((Renderer)rendererSets[i][1]));
244 | 0 | menu.add(saveItem);
245 |  | }
246 |  | }
247 |  |
248 | 0 | public GUI() {
249 | 0 | frame = new JFrame("PMD Duplicate Code Detector");
250 |  |
251 | 0 | timeField.setEditable(false);
252 |  |
253 | 0 | JMenu fileMenu = new JMenu("File");
254 | 0 | fileMenu.setMnemonic('f');
255 |  |
256 | 0 | addSaveOptionsTo(fileMenu);
257 |  |
258 | 0 | JMenuItem exitItem = new JMenuItem("Exit");
259 | 0 | exitItem.setMnemonic('x');
260 | 0 | exitItem.addActionListener(new CancelListener());
261 | 0 | fileMenu.add(exitItem);
262 | 0 | JMenu viewMenu = new JMenu("View");
263 | 0 | fileMenu.setMnemonic('v');
264 | 0 | JMenuItem trimItem = new JCheckBoxMenuItem("Trim leading whitespace");
265 | 0 | trimItem.addItemListener(new ItemListener() {
266 | 0 | public void itemStateChanged(ItemEvent e) {
267 | 0 | AbstractButton button = (AbstractButton)e.getItem();
268 | 0 | GUI.this.trimLeadingWhitespace = button.isSelected();
269 |  | }
270 |  | });
271 | 0 | viewMenu.add(trimItem);
272 | 0 | JMenuBar menuBar = new JMenuBar();
273 | 0 | menuBar.add(fileMenu);
274 | 0 | menuBar.add(viewMenu);
275 | 0 | frame.setJMenuBar(menuBar);
276 |  |
277 |  | // first make all the buttons
278 | 0 | JButton browseButton = new JButton("Browse");
279 | 0 | browseButton.setMnemonic('b');
280 | 0 | browseButton.addActionListener(new BrowseListener());
281 | 0 | goButton = new JButton("Go");
282 | 0 | goButton.setMnemonic('g');
283 | 0 | goButton.addActionListener(new GoListener());
284 | 0 | cancelButton = new JButton("Cancel");
285 | 0 | cancelButton.addActionListener(new CancelListener());
286 |  |
287 | 0 | JPanel settingsPanel = makeSettingsPanel(browseButton, goButton, cancelButton);
288 | 0 | progressPanel = makeProgressPanel();
289 | 0 | JPanel resultsPanel = makeResultsPanel();
290 |  |
291 | 0 | adjustLanguageControlsFor((LanguageConfig)languageSets[0][1]);
292 |  |
293 | 0 | frame.getContentPane().setLayout(new BorderLayout());
294 | 0 | JPanel topPanel = new JPanel();
295 | 0 | topPanel.setLayout(new BorderLayout());
296 | 0 | topPanel.add(settingsPanel, BorderLayout.NORTH);
297 | 0 | topPanel.add(progressPanel, BorderLayout.CENTER);
298 | 0 | setProgressControls(false); // not running now
299 | 0 | frame.getContentPane().add(topPanel, BorderLayout.NORTH);
300 | 0 | frame.getContentPane().add(resultsPanel, BorderLayout.CENTER);
301 | 0 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
302 | 0 | frame.pack();
303 | 0 | frame.setVisible(true);
304 |  | }
305 |  |
306 | 0 | private void adjustLanguageControlsFor(LanguageConfig current) {
307 | 0 | ignoreLiteralsCheckbox.setEnabled(current.ignoreLiteralsByDefault());
308 | 0 | extensionField.setText(current.extensions()[0]);
309 | 0 | boolean enableExtension = current.extensions()[0].length() == 0;
310 | 0 | extensionField.setEnabled(enableExtension);
311 | 0 | extensionLabel.setEnabled(enableExtension);
312 |  | }
313 |  |
314 | 0 | private JPanel makeSettingsPanel(JButton browseButton, JButton goButton, JButton cxButton) {
315 | 0 | JPanel settingsPanel = new JPanel();
316 | 0 | GridBagHelper helper = new GridBagHelper(settingsPanel, new double[]{0.2, 0.7, 0.1, 0.1});
317 | 0 | helper.addLabel("Root source directory:");
318 | 0 | helper.add(rootDirectoryField);
319 | 0 | helper.add(browseButton, 2);
320 | 0 | helper.nextRow();
321 | 0 | helper.addLabel("Report duplicate chunks larger than:");
322 | 0 | minimumLengthField.setColumns(4);
323 | 0 | helper.add(minimumLengthField);
324 | 0 | helper.addLabel("Language:");
325 | 0 | for (int i=0; i<languageSets.length; i++) {
326 | 0 | languageBox.addItem(languageSets[i][0]);
327 |  | }
328 | 0 | languageBox.addActionListener(new ActionListener() {
329 | 0 | public void actionPerformed(ActionEvent e) {
330 | 0 | adjustLanguageControlsFor(
331 |  | languageConfigFor((String)languageBox.getSelectedItem())
332 |  | );
333 |  | }
334 |  | });
335 | 0 | helper.add(languageBox);
336 | 0 | helper.nextRow();
337 | 0 | helper.addLabel("Also scan subdirectories?");
338 | 0 | helper.add(recurseCheckbox);
339 |  |
340 | 0 | helper.add(extensionLabel);
341 | 0 | helper.add(extensionField);
342 |  |
343 | 0 | helper.nextRow();
344 | 0 | helper.addLabel("Ignore literals and identifiers?");
345 | 0 | helper.add(ignoreLiteralsCheckbox);
346 | 0 | helper.add(goButton);
347 | 0 | helper.add(cxButton);
348 | 0 | helper.nextRow();
349 |  | // settingsPanel.setBorder(BorderFactory.createTitledBorder("Settings"));
350 | 0 | return settingsPanel;
351 |  | }
352 |  |
353 | 0 | private JPanel makeProgressPanel() {
354 | 0 | JPanel progressPanel = new JPanel();
355 | 0 | final double[] weights = {0.0, 0.8, 0.4, 0.2};
356 | 0 | GridBagHelper helper = new GridBagHelper(progressPanel, weights);
357 | 0 | helper.addLabel("Tokenizing files:");
358 | 0 | helper.add(tokenizingFilesBar, 3);
359 | 0 | helper.nextRow();
360 | 0 | helper.addLabel("Phase:");
361 | 0 | helper.add(phaseLabel);
362 | 0 | helper.addLabel("Time elapsed:");
363 | 0 | helper.add(timeField);
364 | 0 | helper.nextRow();
365 | 0 | progressPanel.setBorder(BorderFactory.createTitledBorder("Progress"));
366 | 0 | return progressPanel;
367 |  | }
368 |  |
369 | 0 | private JPanel makeResultsPanel() {
370 | 0 | JPanel resultsPanel = new JPanel();
371 | 0 | resultsPanel.setLayout(new BorderLayout());
372 | 0 | JScrollPane areaScrollPane = new JScrollPane(resultsTextArea);
373 | 0 | resultsTextArea.setEditable(false);
374 | 0 | areaScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
375 | 0 | areaScrollPane.setPreferredSize(new Dimension(600, 300));
376 |  |
377 | 0 | resultsPanel.add(makeMatchList(), BorderLayout.WEST);
378 | 0 | resultsPanel.add(areaScrollPane, BorderLayout.CENTER);
379 | 0 | return resultsPanel;
380 |  | }
381 |  |
382 | 0 | private void populateResultArea() {
383 | 0 | int[] selectionIndices = resultsTable.getSelectedRows();
384 | 0 | TableModel model = resultsTable.getModel();
385 | 0 | List selections = new ArrayList(selectionIndices.length);
386 | 0 | for (int i=0; i<selectionIndices.length; i++) {
387 | 0 | selections.add(model.getValueAt(selectionIndices[i], 99));
388 |  | }
389 | 0 | String report = new SimpleRenderer(trimLeadingWhitespace).render(selections.iterator());
390 | 0 | resultsTextArea.setText(report);
391 | 0 | resultsTextArea.setCaretPosition(0); // move to the top
392 |  | }
393 |  |
394 | 0 | private void copyMatchListSelectionsToClipboard() {
395 |  |
396 | 0 | int[] selectionIndices = resultsTable.getSelectedRows();
397 | 0 | int colCount = resultsTable.getColumnCount();
398 |  |
399 | 0 | StringBuffer sb = new StringBuffer();
400 |  |
401 | 0 | for (int r=0; r<selectionIndices.length; r++) {
402 | 0 | if (r > 0) sb.append('\n');
403 | 0 | sb.append(resultsTable.getValueAt(selectionIndices[r], 0));
404 | 0 | for (int c=1; c<colCount; c++) {
405 | 0 | sb.append('\t');
406 | 0 | sb.append(resultsTable.getValueAt(selectionIndices[r], c));
407 |  | }
408 |  | }
409 |  |
410 | 0 | StringSelection ss = new StringSelection(sb.toString());
411 | 0 | Toolkit.getDefaultToolkit().getSystemClipboard().setContents(ss, null);
412 |  | }
413 |  |
414 | 0 | private void deleteMatchlistSelections() {
415 |  |
416 | 0 | int[] selectionIndices = resultsTable.getSelectedRows();
417 |  |
418 | 0 | for (int i=selectionIndices.length-1; i >=0; i--) {
419 | 0 | matches.remove(selectionIndices[i]);
420 |  | }
421 |  |
422 | 0 | resultsTable.getSelectionModel().clearSelection();
423 | 0 | resultsTable.addNotify();
424 |  | }
425 |  |
426 | 0 | private JComponent makeMatchList() {
427 |  |
428 | 0 | resultsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
429 | 0 | public void valueChanged(ListSelectionEvent e) {
430 | 0 | populateResultArea();
431 |  | }});
432 |  |
433 | 0 | resultsTable.registerKeyboardAction(new ActionListener() {
434 | 0 | public void actionPerformed(ActionEvent e) { copyMatchListSelectionsToClipboard(); }
435 |  | },"Copy", copy, JComponent.WHEN_FOCUSED);
436 |  |
437 | 0 | resultsTable.registerKeyboardAction(new ActionListener() {
438 | 0 | public void actionPerformed(ActionEvent e) { deleteMatchlistSelections(); }
439 |  | },"Del", delete, JComponent.WHEN_FOCUSED);
440 |  |
441 | 0 | int[] alignments = new int[matchColumns.length];
442 | 0 | for (int i=0; i<alignments.length; i++) alignments[i] = matchColumns[i].alignment();
443 |  |
444 | 0 | resultsTable.setDefaultRenderer(Object.class, new AlignmentRenderer(alignments));
445 |  |
446 | 0 | final JTableHeader header = resultsTable.getTableHeader();
447 | 0 | header.addMouseListener( new MouseAdapter() {
448 | 0 | public void mouseClicked(MouseEvent e) {
449 | 0 | sortOnColumn(header.columnAtPoint(new Point(e.getX(), e.getY())));
450 |  | }
451 |  | });
452 |  |
453 | 0 | return new JScrollPane(resultsTable);
454 |  | }
455 |  |
456 | 0 | private boolean isLegalPath(String path, LanguageConfig config) {
457 | 0 | String[] extensions = config.extensions();
458 | 0 | for (int i=0; i<extensions.length; i++) {
459 | 0 | if (path.endsWith(extensions[i]) && extensions[i].length() > 0) return true;
460 |  | }
461 | 0 | return false;
462 |  | }
463 |  |
464 | 0 | private String setLabelFor(Match match) {
465 |  |
466 | 0 | Set sourceIDs = new HashSet(match.getMarkCount());
467 | 0 | for (Iterator occurrences = match.iterator(); occurrences.hasNext();) {
468 | 0 | sourceIDs.add( ((TokenEntry) occurrences.next()).getTokenSrcID());
469 |  | }
470 | 0 | String label;
471 |  |
472 | 0 | if (sourceIDs.size() == 1) {
473 | 0 | String sourceId = (String)sourceIDs.iterator().next();
474 | 0 | int separatorPos = sourceId.lastIndexOf(File.separatorChar);
475 | 0 | label = "..." + sourceId.substring(separatorPos);
476 |  | } else {
477 | 0 | label = "(" + sourceIDs.size() + " separate files)";
478 |  | }
479 |  |
480 | 0 | match.setLabel(label);
481 | 0 | return label;
482 |  | }
483 |  |
484 | 0 | private void setProgressControls(boolean isRunning) {
485 | 0 | progressPanel.setVisible(isRunning);
486 | 0 | goButton.setEnabled(!isRunning);
487 | 0 | cancelButton.setEnabled(isRunning);
488 |  | }
489 |  |
490 | 0 | private void go() {
491 | 0 | String dirPath = rootDirectoryField.getText();
492 | 0 | try {
493 | 0 | if (!(new File(dirPath)).exists()) {
494 | 0 | JOptionPane.showMessageDialog(frame,
495 |  | "Can't read from that root source directory",
496 |  | "Error", JOptionPane.ERROR_MESSAGE);
497 | 0 | return;
498 |  | }
499 |  |
500 | 0 | setProgressControls(true);
501 |  |
502 | 0 | Properties p = new Properties();
503 | 0 | p.setProperty(JavaTokenizer.IGNORE_LITERALS, String.valueOf(ignoreLiteralsCheckbox.isSelected()));
504 | 0 | p.setProperty(LanguageFactory.EXTENSION, extensionField.getText());
505 | 0 | LanguageConfig conf = languageConfigFor((String)languageBox.getSelectedItem());
506 | 0 | Language language = conf.languageFor(new LanguageFactory(), p);
507 | 0 | CPD cpd = new CPD(Integer.parseInt(minimumLengthField.getText()), language);
508 | 0 | cpd.setCpdListener(this);
509 | 0 | tokenizingFilesBar.setMinimum(0);
510 | 0 | phaseLabel.setText("");
511 | 0 | if (isLegalPath(dirPath, conf)) { // should use the language file filter instead?
512 | 0 | cpd.add(new File(dirPath));
513 |  | } else {
514 | 0 | if (recurseCheckbox.isSelected()) {
515 | 0 | cpd.addRecursively(dirPath);
516 |  | } else {
517 | 0 | cpd.addAllInDirectory(dirPath);
518 |  | }
519 |  | }
520 | 0 | final long start = System.currentTimeMillis();
521 | 0 | Timer t = new Timer(1000, new ActionListener() {
522 | 0 | public void actionPerformed(ActionEvent e) {
523 | 0 | long now = System.currentTimeMillis();
524 | 0 | long elapsedMillis = now - start;
525 | 0 | long elapsedSeconds = elapsedMillis / 1000;
526 | 0 | long minutes = (long) Math.floor(elapsedSeconds / 60);
527 | 0 | long seconds = elapsedSeconds - (minutes * 60);
528 | 0 | timeField.setText(""
529 |  | + munge(String.valueOf(minutes))
530 |  | + ':'
531 |  | + munge(String.valueOf(seconds)));
532 |  | }
533 |  |
534 | 0 | private String munge(String in) {
535 | 0 | if (in.length() < 2) {
536 | 0 | in = "0" + in;
537 |  | }
538 | 0 | return in;
539 |  | }
540 |  | });
541 | 0 | t.start();
542 | 0 | cpd.go();
543 | 0 | t.stop();
544 |  |
545 | 0 | matches = new ArrayList();
546 | 0 | Match match;
547 | 0 | for (Iterator i = cpd.getMatches(); i.hasNext();) {
548 | 0 | match = (Match)i.next();
549 | 0 | setLabelFor(match);
550 | 0 | matches.add(match);
551 |  | }
552 |  |
553 | 0 | String report = new SimpleRenderer().render(cpd.getMatches());
554 | 0 | if (report.length() == 0) {
555 | 0 | JOptionPane.showMessageDialog(frame,
556 |  | "Done; couldn't find any duplicates longer than " + minimumLengthField.getText() + " tokens");
557 |  | } else {
558 | 0 | resultsTextArea.setText(report);
559 | 0 | setListDataFrom(cpd.getMatches());
560 |  |
561 |  | }
562 |  | } catch (Throwable t) {
563 | 0 | t.printStackTrace();
564 | 0 | JOptionPane.showMessageDialog(frame, "Halted due to " + t.getClass().getName() + "; " + t.getMessage());
565 |  | }
566 | 0 | setProgressControls(false);
567 |  | }
568 |  |
569 |  | private interface SortingTableModel extends TableModel {
570 |  | public int sortColumn();
571 |  | public void sortColumn(int column);
572 |  | public boolean sortDescending();
573 |  | public void sortDescending(boolean flag);
574 |  | public void sort(Comparator comparator);
575 |  | }
576 |  |
577 | 0 | private TableModel tableModelFrom(final List items) {
578 |  |
579 | 0 | TableModel model = new SortingTableModel() {
580 |  |
581 |  | private int sortColumn;
582 |  | private boolean sortDescending;
583 |  |
584 | 0 | public Object getValueAt(int rowIndex, int columnIndex) {
585 | 0 | Match match = (Match) items.get(rowIndex);
586 | 0 | switch (columnIndex) {
587 | 0 | case 0: return match.getLabel();
588 | 0 | case 2: return Integer.toString(match.getLineCount());
589 | 0 | case 1: return match.getMarkCount() > 2 ? Integer.toString(match.getMarkCount()) : "";
590 | 0 | case 99: return match;
591 |  | }
592 | 0 | return "";
593 |  | }
594 | 0 | public int getColumnCount() { return matchColumns.length; }
595 | 0 | public int getRowCount() { return items.size(); }
596 | 0 | public boolean isCellEditable(int rowIndex, int columnIndex) { return false; }
597 | 0 | public Class getColumnClass(int columnIndex) { return Object.class; }
598 | 0 | public void setValueAt(Object aValue, int rowIndex, int columnIndex) { }
599 | 0 | public String getColumnName(int i) { return matchColumns[i].label(); }
600 | 0 | public void addTableModelListener(TableModelListener l) { }
601 | 0 | public void removeTableModelListener(TableModelListener l) { }
602 | 0 | public int sortColumn() { return sortColumn; };
603 | 0 | public void sortColumn(int column) { sortColumn = column; };
604 | 0 | public boolean sortDescending() { return sortDescending; };
605 | 0 | public void sortDescending(boolean flag) { sortDescending = flag; };
606 | 0 | public void sort(Comparator comparator) {
607 | 0 | Collections.sort(items, comparator);
608 | 0 | if (sortDescending) Collections.reverse(items);
609 |  | }
610 |  | };
611 |  |
612 | 0 | return model;
613 |  | }
614 |  |
615 | 0 | private void sortOnColumn(int columnIndex) {
616 | 0 | Comparator comparator = matchColumns[columnIndex].sorter();
617 | 0 | SortingTableModel model = (SortingTableModel)resultsTable.getModel();
618 | 0 | if (model.sortColumn() == columnIndex) {
619 | 0 | model.sortDescending(!model.sortDescending());
620 |  | }
621 | 0 | model.sortColumn(columnIndex);
622 | 0 | model.sort(comparator);
623 |  |
624 | 0 | resultsTable.getSelectionModel().clearSelection();
625 | 0 | resultsTable.repaint();
626 |  | }
627 |  |
628 | 0 | private void setListDataFrom(Iterator iter) {
629 |  |
630 | 0 | resultsTable.setModel(tableModelFrom(matches));
631 |  |
632 | 0 | TableColumnModel colModel = resultsTable.getColumnModel();
633 | 0 | TableColumn column;
634 | 0 | int width;
635 |  |
636 | 0 | for (int i=0; i<matchColumns.length; i++) {
637 | 0 | if (matchColumns[i].width() > 0) {
638 | 0 | column = colModel.getColumn(i);
639 | 0 | width = matchColumns[i].width();
640 | 0 | column.setPreferredWidth(width);
641 | 0 | column.setMinWidth(width);
642 | 0 | column.setMaxWidth(width);
643 |  | }
644 |  | }
645 |  | }
646 |  |
647 |  | // CPDListener
648 | 0 | public void phaseUpdate(int phase) {
649 | 0 | phaseLabel.setText(getPhaseText(phase));
650 |  | }
651 |  |
652 | 0 | public String getPhaseText(int phase) {
653 | 0 | switch (phase) {
654 | 0 | case CPDListener.INIT:
655 | 0 | return "Initializing";
656 | 0 | case CPDListener.HASH:
657 | 0 | return "Hashing";
658 | 0 | case CPDListener.MATCH:
659 | 0 | return "Matching";
660 | 0 | case CPDListener.GROUPING:
661 | 0 | return "Grouping";
662 | 0 | case CPDListener.DONE:
663 | 0 | return "Done";
664 | 0 | default :
665 | 0 | return "Unknown";
666 |  | }
667 |  | }
668 |  |
669 | 0 | public void addedFile(int fileCount, File file) {
670 | 0 | tokenizingFilesBar.setMaximum(fileCount);
671 | 0 | tokenizingFilesBar.setValue(tokenizingFilesBar.getValue() + 1);
672 |  | }
673 |  | // CPDListener
674 |  |
675 |  |
676 | 0 | public static void main(String[] args) {
677 |  | //this should prevent the disk not found popup
678 |  | // System.setSecurityManager(null);
679 | 0 | new GUI();
680 |  | }
681 |  |
682 |  | }