package net.sourceforge.pmd.eclipse.ui.preferences; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import net.sourceforge.pmd.Rule; import net.sourceforge.pmd.RuleSet; import net.sourceforge.pmd.RuleSetFactory; import net.sourceforge.pmd.RuleSetNotFoundException; import net.sourceforge.pmd.RuleSets; import net.sourceforge.pmd.eclipse.plugin.PMDPlugin; import net.sourceforge.pmd.eclipse.ui.nls.StringKeys; import net.sourceforge.pmd.eclipse.ui.preferences.br.RuleColumnDescriptor; import net.sourceforge.pmd.eclipse.ui.preferences.br.RuleLabelProvider; import net.sourceforge.pmd.util.StringUtil; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.viewers.CheckStateChangedEvent; import org.eclipse.jface.viewers.CheckboxTableViewer; import org.eclipse.jface.viewers.ICheckStateListener; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.TableItem; /** * Implements a dialog for the user to select a rule set to import * * @author Philippe Herlin * @author Brian Remedios * */ public class RuleSetSelectionDialog extends Dialog { private Combo inputCombo; private Button referenceButton; private Button copyButton; private String importedRuleSetName; private RuleSet selectedRuleSet; private boolean importByReference; private Label warningField; private CheckboxTableViewer ruleTable; private RuleSet checkedRules; private final RuleDupeChecker dupeChecker; private final String title; private final RuleSet[] ruleSets; private final String[] ruleSetNames; private final RuleColumnDescriptor[] columns; /** * Constructor for RuleSetSelectionDialog. * @param parentdlgArea */ public RuleSetSelectionDialog(Shell parent, String theTitle, RuleColumnDescriptor[] theColumns, RuleDupeChecker theDupeChecker) { super(parent); title = theTitle; dupeChecker = theDupeChecker; columns = theColumns; setShellStyle(getShellStyle() | SWT.RESIZE ); Set<RuleSet> registeredRuleSets = PMDPlugin.getDefault().getRuleSetManager().getRegisteredRuleSets(); SortedSet<RuleSet> sortedRuleSets = new TreeSet<RuleSet>(new Comparator<RuleSet>() { public int compare(RuleSet ruleSet1, RuleSet ruleSet2) { return labelFor(ruleSet1).compareToIgnoreCase(labelFor(ruleSet2)); } }); sortedRuleSets.addAll(registeredRuleSets); ruleSets = new RuleSet[sortedRuleSets.size()]; ruleSetNames = new String[sortedRuleSets.size()]; Iterator<RuleSet> i = sortedRuleSets.iterator(); int index = 0; while (i.hasNext()) { ruleSets[index] = i.next(); ruleSetNames[index] = ruleSets[index].getName(); if (!ruleSets[index].getRules().isEmpty()) { ruleSetNames[index] = labelFor(ruleSets[index]); } index++; } } private static String labelFor(RuleSet rs) { Collection<Rule> rules = rs.getRules(); String lang = rules.iterator().next().getLanguage().getShortName(); return lang + " - " + rs.getName() + " (" + rules.size() + ")"; } protected void configureShell(Shell shell) { super.configureShell(shell); shell.setSize(500, 400); } protected boolean isResizable() { return true; } /** * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(Composite) */ @Override protected Control createDialogArea(Composite parent) { Composite dlgArea = new Composite(parent, SWT.NULL); dlgArea.setLayoutData(new GridData(GridData.FILL_BOTH)); // Layout controls GridLayout gridLayout = new GridLayout(); gridLayout.numColumns = 3; dlgArea.setLayout(gridLayout); // Create controls (order is important) Label enterRuleSetLabel = buildLabel(dlgArea, getMessage(StringKeys.PREF_RULESETSELECTION_LABEL_ENTER_RULESET)); GridData data = new GridData(); data.horizontalSpan = 3; enterRuleSetLabel.setLayoutData(data); inputCombo = buildInputCombo(dlgArea); data = new GridData(); data.horizontalAlignment = GridData.FILL; data.horizontalSpan = 2; data.grabExcessHorizontalSpace = true; inputCombo.setLayoutData(data); buildBrowseButton(dlgArea); referenceButton = buildReferenceButton(dlgArea); copyButton = buildCopyButton(dlgArea); data = new GridData(); data.horizontalAlignment = GridData.FILL; data.horizontalSpan = 2; data.grabExcessHorizontalSpace = true; copyButton.setLayoutData(data); ruleTable = CheckboxTableViewer.newCheckList(dlgArea, SWT.BORDER); data = new GridData(GridData.FILL_BOTH); data.horizontalSpan = 3; ruleTable.getTable().setLayoutData(data); setupRuleTable(); warningField = new Label(dlgArea, SWT.NONE); data = new GridData(); data.horizontalAlignment = GridData.FILL; data.horizontalSpan = 3; data.grabExcessHorizontalSpace = true; warningField.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_RED)); warningField.setLayoutData(data); getShell().setText(title); return dlgArea; } protected void createCheckBoxColumn(Table table) { TableColumn tc = new TableColumn(table, 0); tc.setWidth(30); tc.setResizable(false); tc.pack(); // tc.addListener(SWT.Selection, new Listener() { // public void handleEvent(Event e) { // sortByCheckedItems(); // } // }); } private void setupRuleTable() { Table tbl = ruleTable.getTable(); tbl.setLinesVisible(true); tbl.setHeaderVisible(true); ruleTable.setContentProvider( new IStructuredContentProvider() { public Object[] getElements(Object inputElement) { RuleSet rs = selectedRuleset(); return rs == null ? new Object[0] : rs.getRules().toArray(); } public void dispose() { } public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } }); ruleTable.addCheckStateListener(new ICheckStateListener() { public void checkStateChanged(CheckStateChangedEvent event) { ruleChecked(); }} ); createCheckBoxColumn(tbl); for (int i=0; i<columns.length; i++) { columns[i].newTableColumnFor(tbl, i+1, null, null); } ruleTable.setLabelProvider( new RuleLabelProvider(columns) ); } private void checkNonDupes() { List<Rule> nonDupes = new ArrayList<Rule>(); for (TableItem item : ruleTable.getTable().getItems()) { Rule rule = (Rule) item.getData(); if (dupeChecker.isDuplicate(rule)) { continue; } nonDupes.add(rule); } ruleTable.setCheckedElements(nonDupes.toArray()); } public void create() { super.create(); updateControls(); } /** * Build the labels */ private Label buildLabel(Composite parent, String text) { Label label = new Label(parent, SWT.NONE); label.setText(text); return label; } /** * Build the input combo box */ private Combo buildInputCombo(Composite parent) { Combo combo = new Combo(parent, SWT.NONE); combo.setItems(ruleSetNames); combo.setText(""); combo.setToolTipText(getMessage(StringKeys.PREF_RULESETSELECTION_TOOLTIP_RULESET)); combo.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent event) { ruleSetChanged(); } }); return combo; } /** * Build the browse push button */ private Button buildBrowseButton(Composite parent) { Button button = new Button(parent, SWT.PUSH); button.setText(getMessage(StringKeys.PREF_RULESETSELECTION_BUTTON_BROWSE)); button.setEnabled(true); button.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent event) { FileDialog dialog = new FileDialog(getShell(), SWT.OPEN); String fileName = dialog.open(); if (StringUtil.isNotEmpty(fileName)) { inputCombo.setText(fileName); ruleSetChanged(); } } }); return button; } /** * Build the reference button */ private Button buildReferenceButton(Composite parent) { final Button button = new Button(parent, SWT.RADIO); button.setText(getMessage(StringKeys.PREF_RULESETSELECTION_BUTTON_REFERENCE)); button.setSelection(true); importByReference = true; button.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent event) { importByReference = true; } }); return button; } /** * Build the copy button */ private Button buildCopyButton(Composite parent) { final Button button = new Button(parent, SWT.RADIO); button.setText(getMessage(StringKeys.PREF_RULESETSELECTION_BUTTON_COPY)); button.setSelection(false); button.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent event) { importByReference = false; } }); return button; } private void ruleSetChanged() { updateRuleTable(); checkNonDupes(); warningField.setText(""); adjustOKButton(); } /** * Returns the importedRuleSetName. * @return String */ public String getImportedRuleSetName() { return importedRuleSetName; } private boolean hasCheckedRules() { return ruleTable.getCheckedElements().length > 0; } /** * Return the effective ruleset as the ones selected by the user. * * @return */ private RuleSet getSelectedRules() { RuleSet rs = new RuleSet(); rs.setFileName( selectedRuleSet.getFileName() ); rs.addExcludePatterns( selectedRuleSet.getExcludePatterns() ); rs.addIncludePatterns( selectedRuleSet.getIncludePatterns() ); for (Object rul : ruleTable.getCheckedElements()) { rs.addRule((Rule) rul); } return rs; } /** * @return import by reference */ public boolean isImportByReference() { return importByReference; } private void adjustOKButton() { boolean hasChecks = hasCheckedRules(); getButton(IDialogConstants.OK_ID).setEnabled(hasChecks); } private void ruleChecked() { updateWarningField(); adjustOKButton(); } private void updateControls() { updateWarningField(); adjustOKButton(); } private void updateRuleTable() { RuleSet candidateRS = selectedRuleset(); if (candidateRS == null) { // warningField.setText(""); ruleTable.getTable().clearAll(); return; } showRules(candidateRS); } private boolean updateWarningField() { int dupeCount = 0; for (Object rule : ruleTable.getCheckedElements()) { if (dupeChecker.isDuplicate((Rule)rule)) dupeCount++; } warningField.setText( dupeCount == 0 ? "" : "Warning, " + dupeCount + " checked rules already exist in your ruleset"); return dupeCount > 0; } private void showRules(RuleSet rs) { ruleTable.setInput(rs); TableColumn[] columns = ruleTable.getTable().getColumns(); for (TableColumn column : columns) column.pack(); } private RuleSet selectedRuleset() { int selectionIndex = inputCombo.getSelectionIndex(); if (selectionIndex == -1) { importedRuleSetName = inputCombo.getText(); if (StringUtil.isNotEmpty(importedRuleSetName)) { try { RuleSetFactory factory = new RuleSetFactory(); RuleSets rs = factory.createRuleSets(importedRuleSetName); return rs.getAllRuleSets()[0]; } catch (RuleSetNotFoundException rsnfe) { warningField.setText( rsnfe.getMessage() ); return null; } } } return ruleSets[selectionIndex]; } public RuleSet checkedRules() { return checkedRules; } /** * @see org.eclipse.jface.dialogs.Dialog#okPressed() */ @Override protected void okPressed() { // get the selections before the widget goes away selectedRuleSet = selectedRuleset(); checkedRules = getSelectedRules(); super.okPressed(); } /** * Helper method to shorten message access * @param key a message key * @return requested message */ private String getMessage(String key) { return PMDPlugin.getDefault().getStringTable().getString(key); } }