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