package net.sourceforge.pmd.eclipse.ui.filters; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import net.sourceforge.pmd.PropertyDescriptor; import net.sourceforge.pmd.PropertySource; import net.sourceforge.pmd.RuleSet; import net.sourceforge.pmd.eclipse.runtime.preferences.IPreferencesManager; import net.sourceforge.pmd.eclipse.ui.BasicTableLabelProvider; import net.sourceforge.pmd.eclipse.ui.PMDUiConstants; import net.sourceforge.pmd.eclipse.ui.nls.StringKeys; import net.sourceforge.pmd.eclipse.ui.preferences.br.AbstractPMDPreferencePage; import net.sourceforge.pmd.eclipse.ui.preferences.br.BasicTableManager; import net.sourceforge.pmd.eclipse.ui.preferences.br.RuleSelection; import net.sourceforge.pmd.eclipse.ui.preferences.br.SizeChangeListener; import net.sourceforge.pmd.eclipse.ui.preferences.br.ValueChangeListener; import net.sourceforge.pmd.eclipse.util.ResourceManager; import org.eclipse.jface.preference.PreferencePage; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.FocusAdapter; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.TableItem; import org.eclipse.swt.widgets.Text; /** * The available report formats and their properties. * * @author Brian Remedios */ public class FilterPreferencesPage extends AbstractPMDPreferencePage implements ValueChangeListener, SizeChangeListener { private TableViewer tableViewer; private Button addButton; private Button removeButton; private Button excludeButt; private Button includeButt; // private Button cpdButt; // private Button pmdButt; private Text patternField; private BasicTableManager<FilterHolder> reportTableMgr; private Collection<Control> editorWidgets = new ArrayList<Control>(); private static Image IncludeIcon = plugin.getImage("include", "icons/ok.gif"); private static Image ExcludeIcon = plugin.getImage("exclude", "icons/forbidden.png"); private static final String NewFilterPattern = "<finish this>"; public static Image typeIconFor(FilterHolder holder) { return holder.isInclude ? IncludeIcon : ExcludeIcon; } private static Label createLabel(Composite panel, String text) { Label label = new Label(panel, SWT.None); label.setLayoutData( new GridData()); label.setText(text); return label; } // private static Button createButton(Composite panel, int type, String label) { // Button butt = new Button(panel, type); // butt.setLayoutData( new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1)); // butt.setText(label); // return butt; // } private static Button createButton(Composite panel, int type, Image image, String tooltip) { Button butt = new Button(panel, type); butt.setLayoutData( new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1)); butt.setImage(image); butt.setToolTipText(tooltip); return butt; } /** * Create and initialize the controls of the page * * @param parent Composite * @return Control * @see PreferencePage#createContents */ @Override protected Control createContents(Composite parent) { // Create parent composite Composite composite = new Composite(parent, SWT.NONE); GridLayout layout = new GridLayout(2, false); layout.verticalSpacing = 10; composite.setLayout(layout); // Create panels Composite filterGroup = buildFilterGroup(composite); Composite buttonPanel = buildTableButtons(composite); // Layout children filterGroup.setLayoutData(new GridData(GridData.FILL_BOTH)); buttonPanel.setLayoutData(new GridData()); buildFilterEditor(parent); updateControls(); return composite; } private FilterHolder[] currentFilters() { List<FilterHolder> holders = new ArrayList<FilterHolder>(); RuleSet ruleSet = plugin.getPreferencesManager().getRuleSet(); for (String pattern : ruleSet.getExcludePatterns() ) { holders.add( new FilterHolder(pattern, true, false, false) ); } for (String pattern : ruleSet.getIncludePatterns() ) { holders.add( new FilterHolder(pattern, true, false, true) ); } return holders.toArray(new FilterHolder[holders.size()]); } private void enableEditor(boolean flag) { for (Control control : editorWidgets) { control.setEnabled(flag); } } private List<String> tableFilters(boolean isInclude) { List<String> filters = new ArrayList<String>(); for (TableItem ti : tableViewer.getTable().getItems()) { FilterHolder fh = (FilterHolder)ti.getData(); if (fh.isInclude == isInclude) filters.add(fh.pattern); } return filters; } /** * Build the group of priority preferences * @param parent the parent composite * @return the group widget */ private Composite buildFilterGroup(Composite parent) { IStructuredContentProvider contentProvider = new IStructuredContentProvider() { public void dispose() { } public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } public Object[] getElements(Object inputElement) { return (FilterHolder[])inputElement; } }; BasicTableLabelProvider labelProvider = new BasicTableLabelProvider(FilterColumnUI.VisibleColumns); reportTableMgr = new BasicTableManager<FilterHolder>("renderers", null, FilterColumnUI.VisibleColumns); tableViewer = reportTableMgr.buildTableViewer( parent, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI | SWT.FULL_SELECTION | SWT.CHECK ); reportTableMgr.setupColumns(FilterColumnUI.VisibleColumns); Table table = tableViewer.getTable(); table.setLayoutData( new GridData(GridData.FILL, GridData.FILL, true, true, 1, 1) ); tableViewer.setLabelProvider(labelProvider); tableViewer.setContentProvider(contentProvider); table.setHeaderVisible(true); tableViewer.setInput( currentFilters() ); selectCheckedFilters(); TableColumn[] columns = table.getColumns(); for (TableColumn column : columns) column.pack(); tableViewer.addSelectionChangedListener(new ISelectionChangedListener() { public void selectionChanged(SelectionChangedEvent event) { patternsSelected(); } }); tableViewer.getTable().addListener(SWT.Selection, new Listener () { public void handleEvent(Event event) { if (event.detail == SWT.CHECK) { checked(event.item); } } }); return parent; } private void patternsSelected() { IStructuredSelection selection = (IStructuredSelection)tableViewer.getSelection(); selectedPatterns(filtersIn(selection.toList())); updateControls(); } private void selectedPatterns(Collection<FilterHolder> holders) { setState(holders, excludeButt, FilterHolder.ExcludeAccessor); setState(holders, includeButt, FilterHolder.IncludeAccessor); // setState(holders, pmdButt, FilterHolder.PMDAccessor); // setState(holders, cpdButt, FilterHolder.CPDAccessor); setValue(holders, patternField, FilterHolder.PatternAccessor); } private static void setState(Collection<FilterHolder> holders, Button button, FilterHolder.Accessor accessor) { Boolean state = FilterHolder.boolValueOf(holders, accessor); if (state == null) { button.setGrayed(true); return; } button.setSelection(state); } private static void setValue(Collection<FilterHolder> holders, Text field, FilterHolder.Accessor accessor) { String text = FilterHolder.textValueOf(holders, accessor); field.setText(text); } // private void setAllPMD(boolean state) { // for (FilterHolder fh : selectedFilters()) { // fh.forPMD = state; // } // } // // private void setAllCPD(boolean state) { // for (FilterHolder fh : selectedFilters()) { // fh.forCPD = state; // } // } private void setAllInclude(boolean state) { for (FilterHolder fh : selectedFilters()) { fh.isInclude = state; } } private void setAllPatterns(String pattern) { for (FilterHolder fh : selectedFilters()) { fh.pattern = pattern; } } private void buildFilterEditor(Composite parent) { Composite editorPanel = new Composite(parent, SWT.None); editorPanel.setLayoutData( new GridData(GridData.FILL, GridData.FILL, false, true) ); editorPanel.setLayout(new GridLayout(3, false)); Label typeLabel = new Label(editorPanel, SWT.None); typeLabel.setLayoutData( new GridData()); typeLabel.setText("Type:"); editorWidgets.add(typeLabel); excludeButt = createButton(editorPanel, SWT.RADIO, ExcludeIcon, "Exclude"); excludeButt.addSelectionListener( new SelectionAdapter() { public void widgetSelected(SelectionEvent se) { setAllInclude(!includeButt.getSelection()); tableViewer.refresh(); } }); includeButt = createButton(editorPanel, SWT.RADIO, IncludeIcon, "Include"); includeButt.addSelectionListener( new SelectionAdapter() { public void widgetSelected(SelectionEvent se) { setAllInclude(includeButt.getSelection()); tableViewer.refresh(); } }); editorWidgets.add(excludeButt); editorWidgets.add(includeButt); // Label contextLabel = createLabel(editorPanel, "Applies to:"); // editorWidgets.add(contextLabel); // pmdButt = createButton(editorPanel, SWT.CHECK, "PMD"); // pmdButt.addSelectionListener( new SelectionAdapter() { // public void widgetSelected(SelectionEvent se) { // setAllPMD(pmdButt.getSelection()); // tableViewer.refresh(); // } // }); // // cpdButt = createButton(editorPanel, SWT.CHECK, "CPD"); // cpdButt.addSelectionListener( new SelectionAdapter() { // public void widgetSelected(SelectionEvent se) { // setAllCPD(cpdButt.getSelection()); // tableViewer.refresh(); // } // }); // editorWidgets.add(pmdButt); // editorWidgets.add(cpdButt); Label patternLabel = createLabel(editorPanel, "Pattern:"); editorWidgets.add(patternLabel); patternField = new Text(editorPanel, SWT.BORDER); patternField.setLayoutData( new GridData(GridData.FILL, GridData.CENTER, true, false, 2, 1) ); patternField.addFocusListener(new FocusAdapter() { public void focusLost(FocusEvent fe) { setAllPatterns(patternField.getText()); tableViewer.refresh(); } }); editorWidgets.add(patternField); createLabel(editorPanel, ""); // spacer Label description = new Label(editorPanel, SWT.None); description.setLayoutData( new GridData(GridData.FILL, GridData.BEGINNING, true, false, 2, 1) ); description.setText("name or path pattern (* = any string, ? = any character)"); editorWidgets.add(description); } /** * Create buttons for rule table management * @param parent Composite * @return Composite */ public Composite buildTableButtons(Composite parent) { Composite composite = new Composite(parent, SWT.NULL); GridLayout gridLayout = new GridLayout(); gridLayout.numColumns = 1; gridLayout.verticalSpacing = 3; composite.setLayout(gridLayout); addButton = buildAddButton(composite); removeButton = buildRemoveButton(composite); GridData data = new GridData(); addButton.setLayoutData(data); return composite; } /** * Check the filters as noted from the preferences. */ private void selectCheckedFilters() { Set<String> activeOnes = preferences.activeExclusionPatterns(); activeOnes.addAll(preferences.activeInclusionPatterns()); for (TableItem item : tableViewer.getTable().getItems()) { FilterHolder holder = (FilterHolder)item.getData(); item.setChecked( activeOnes.contains(holder.pattern) ); } } /** * * @return Set<String> */ private Set<FilterHolder> currentCheckedFilters() { Set<FilterHolder> holders = new HashSet<FilterHolder>(); for (Object holder : checkedItems(tableViewer.getTable())) { holders.add((FilterHolder) holder); } return holders; } /** * * @return Set<String> */ private Set<FilterHolder> selectedFilters() { Set<FilterHolder> holders = new HashSet<FilterHolder>(); for (Object tItem : tableViewer.getTable().getSelection()) { holders.add((FilterHolder) (((TableItem)tItem).getData())); } return holders; } /** * * @return Set<String> */ private static Collection<FilterHolder> filtersIn(List<?> tableItems) { Set<FilterHolder> holders = new HashSet<FilterHolder>(); for (Object tItem : tableItems) { holders.add((FilterHolder) tItem); } return holders; } /** * Method checkedItems. * @param table Table * @return Set<Object> */ private static Set<Object> checkedItems(Table table) { Set<Object> checkedItems = new HashSet<Object>(); for (TableItem ti : table.getItems()) { if (ti.getChecked()) checkedItems.add( ti.getData() ); } return checkedItems; } /** * * @param item Object */ private void checked(Object item) { //FIXME boolean matches = currentCheckedFilters().equals(preferences.activeExclusionPatterns()); setModified(!matches); } /** * @see org.eclipse.jface.preference.PreferencePage#performDefaults() */ @Override protected void performDefaults() { } /** * * @return boolean * @see org.eclipse.jface.preference.IPreferencePage#performCancel() */ @Override public boolean performCancel() { // clear out any changes for next possible usage selectCheckedFilters(); return true; } private static Set<String> patternsIn(Collection<FilterHolder> holders, boolean getInclusions) { if (holders.isEmpty()) return Collections.emptySet(); Set<String> patterns = new HashSet<String>(); for (FilterHolder holder : holders) { if (holder.isInclude == getInclusions) { patterns.add(holder.pattern); } } return patterns; } protected Button newImageButton(Composite parent, String imageId, String toolTipId) { Button button = new Button(parent, SWT.PUSH | SWT.LEFT); button.setImage(ResourceManager.imageFor(imageId)); button.setToolTipText(getMessage(toolTipId)); button.setEnabled(true); return button; } /** * Build the edit rule button * @param parent Composite * @return Button */ public Button buildAddButton(final Composite parent) { Button button = newImageButton(parent, PMDUiConstants.ICON_BUTTON_ADD, StringKeys.PREF_RULESET_BUTTON_ADDFILTER); button.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent event) { addNewFilter(); } }); return button; } private FilterHolder[] tableFiltersWith(FilterHolder anotherOne) { FilterHolder[] holders = new FilterHolder[ tableViewer.getTable().getItemCount() + (anotherOne == null ? 0 : 1) ]; TableItem[] items = tableViewer.getTable().getItems(); for (int i=0; i<items.length; i++) { holders[i] = (FilterHolder)items[i].getData(); } if (anotherOne != null) holders[holders.length-1] = anotherOne; return holders; } private void addNewFilter() { FilterHolder newHolder = new FilterHolder(NewFilterPattern, true, false, false); FilterHolder[] holders = tableFiltersWith(newHolder); tableViewer.setInput( holders ); tableViewer.getTable().setSelection(holders.length-1); patternsSelected(); patternField.selectAll(); patternField.forceFocus(); } /** * Build the edit rule button * @param parent Composite * @return Button */ public Button buildRemoveButton(final Composite parent) { Button button = newImageButton(parent, PMDUiConstants.ICON_BUTTON_DELETE, StringKeys.PREF_RULESET_BUTTON_REMOVEFILTER); button.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent event) { deleteSelected(); } }); return button; } private void deleteSelected() { IStructuredSelection sel = (IStructuredSelection)tableViewer.getSelection(); if (sel.isEmpty()) return; Object[] selections = sel.toArray(); tableViewer.remove(selections); } /** * @return boolean * @see org.eclipse.jface.preference.IPreferencePage#performOk() */ @Override public boolean performOk() { IPreferencesManager ipMgr = plugin.getPreferencesManager(); RuleSet ruleSet = ipMgr.getRuleSet(); ruleSet.setExcludePatterns( tableFilters(false) ); ruleSet.setIncludePatterns( tableFilters(true) ); ipMgr.setRuleSet(ruleSet); Set<FilterHolder> filters = currentCheckedFilters(); preferences.activeExclusionPatterns( patternsIn(filters, false) ); preferences.activeInclusionPatterns( patternsIn(filters, true) ); preferences.sync(); if (isModified()) { rebuildProjects(); } return super.performOk(); } /** * Method descriptionId. * @return String */ @Override protected String descriptionId() { return "???"; // TODO } public void changed(PropertySource source, PropertyDescriptor<?> desc, Object newValue) { // TODO enable/disable save/cancel buttons } private void updateControls() { boolean hasSelections = !selectedFilters().isEmpty(); removeButton.setEnabled( hasSelections ); enableEditor(hasSelections); } // ignore these public void addedRows(int newRowCount) { } public void changed(RuleSelection rule, PropertyDescriptor<?> desc, Object newValue) { } }