1 |
| |
2 |
| |
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 |
| |
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);
|
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 |
| |
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);
|
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)) {
|
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 |
| |
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 |
| |
674 |
| |
675 |
| |
676 |
0
| public static void main(String[] args) {
|
677 |
| |
678 |
| |
679 |
0
| new GUI();
|
680 |
| } |
681 |
| |
682 |
| } |