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