/* * Contributions to FindBugs * Copyright (C) 2008, Andrei Loskutov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package de.tobject.findbugs.properties; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.viewers.CheckboxTableViewer; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.program.Program; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Link; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.TabFolder; import org.eclipse.swt.widgets.TabItem; import de.tobject.findbugs.FindbugsPlugin; import de.tobject.findbugs.builder.FindBugsWorker; import edu.umd.cs.findbugs.config.UserPreferences; /** * @author Andrei Loskutov */ public class FilterFilesTab extends Composite { private final FindbugsPropertyPage propertyPage; private final FilterProvider filterIncl; private final FilterProvider filterExcl; private final FilterProvider filterExclBugs; static final class SelectionValidator { private final UserPreferences prefs; private final Map<String, Boolean> exclFiles; public SelectionValidator(FilterKind kind, FindbugsPropertyPage propertyPage) { prefs = propertyPage.getCurrentUserPreferences(); exclFiles = kind.excludedPaths(prefs); } public IStatus validate(String path) { if (exclFiles.containsKey(path)) { return FindbugsPlugin.createErrorStatus("Filter selected in a conflicting list", null); } return Status.OK_STATUS; } } public static class FilterProvider extends PathsProvider { private final FilterKind kind; protected FilterProvider(TableViewer viewer, FilterKind kind, FindbugsPropertyPage propertyPage) { super(viewer, propertyPage); this.kind = kind; setFilters(propertyPage.getCurrentUserPreferences()); } List<IPathElement> getFilterFiles(UserPreferences prefs) { IProject project = propertyPage.getProject(); final List<IPathElement> newPaths = new ArrayList<IPathElement>(); Map<String, Boolean> filterPaths = kind.selectedPaths(prefs); if (filterPaths != null) { for (Entry<String, Boolean> entry : filterPaths.entrySet()) { IPath filterPath = FindBugsWorker.getFilterPath(entry.getKey(), project); PathElement element = new PathElement(filterPath, Status.OK_STATUS); element.setEnabled(entry.getValue().booleanValue()); newPaths.add(element); } } return newPaths; } @Override protected void applyToPreferences() { super.applyToPreferences(); kind.setPaths(propertyPage.getCurrentUserPreferences(), pathsToStrings()); } void setFilters(UserPreferences prefs) { setFilters(getFilterFiles(prefs)); } @Override protected IStatus validate() { SelectionValidator validator = new SelectionValidator(kind, propertyPage); IStatus bad = null; IProject project = propertyPage.getProject(); for (IPathElement path : paths) { String filterPath = FindBugsWorker.toFilterPath(path.getPath(), project).toOSString(); IStatus status = validator.validate(filterPath); path.setStatus(status); if (!status.isOK()) { bad = status; } } return bad; } @Override protected void configureDialog(FileDialog dialog) { dialog.setFilterExtensions(new String[] { "*.xml" }); dialog.setText(FindbugsPlugin.getDefault().getMessage(kind.propertyName) + ": select xml file(s) containing filters"); } } public FilterFilesTab(TabFolder parent, FindbugsPropertyPage page, int style) { super(parent, style); this.propertyPage = page; setLayout(new GridLayout(2, true)); Link label = new Link(this, SWT.NONE); label.setText("Filter files may be used to include or exclude bug detection for particular classes and methods.\n" + "<a href=\"http://findbugs.sourceforge.net/manual/filter.html\">Details...</a>\n"); label.addSelectionListener(new SelectionListener() { public void widgetSelected(SelectionEvent e) { Program.launch(e.text); } public void widgetDefaultSelected(SelectionEvent e) { // noop } }); label.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, true, false, 2, 1)); TabItem tabDetector = new TabItem(parent, SWT.NONE); tabDetector.setText(getMessage("property.filterFilesTab")); tabDetector.setControl(this); tabDetector.setToolTipText("Configure external bug reporting filters"); ManagePathsWidget incl = new ManagePathsWidget(this); CheckboxTableViewer viewer = incl.createViewer(getMessage(FilterKind.INCLUDE.propertyName), null, true); filterIncl = createFilterProvider(viewer, FilterKind.INCLUDE, page); incl.createButtonsArea(filterIncl); ManagePathsWidget excl = new ManagePathsWidget(this); viewer = excl.createViewer(getMessage(FilterKind.EXCLUDE.propertyName), null, true); filterExcl = createFilterProvider(viewer, FilterKind.EXCLUDE, page); excl.createButtonsArea(filterExcl); ManagePathsWidget excl2 = new ManagePathsWidget(this); viewer = excl2.createViewer(getMessage(FilterKind.EXCLUDE_BUGS.propertyName), "You can include past FindBugs result XML files here to exclude those bugs from analysis. " + "<a href=\"http://findbugs.sourceforge.net/manual/filter.html\">Details...</a>", true); filterExclBugs = createFilterProvider(viewer, FilterKind.EXCLUDE_BUGS, page); excl2.createButtonsArea(filterExclBugs); refreshTables(); } public void refreshTables() { propertyPage.setErrorMessage(null); filterIncl.refresh(); filterExcl.refresh(); filterExclBugs.refresh(); } /** * Helper method to shorten message access * * @param key * a message key * @return requested message */ protected static String getMessage(String key) { return FindbugsPlugin.getDefault().getMessage(key); } protected FilterProvider createFilterProvider(TableViewer viewer, FilterKind kind, FindbugsPropertyPage page) { FilterProvider filterProvider = new FilterProvider(viewer, kind, propertyPage); filterProvider.addListener(new Listener() { public void handleEvent(Event event) { refreshTables(); } }); return filterProvider; } public static enum FilterKind { INCLUDE("property.includefilter") { @Override Map<String, Boolean> selectedPaths(UserPreferences u) { return u.getIncludeFilterFiles(); } @Override Map<String, Boolean> excludedPaths(UserPreferences u) { Map<String, Boolean> excl = new TreeMap<String, Boolean>(); excl.putAll(u.getExcludeFilterFiles()); excl.putAll(u.getExcludeBugsFiles()); return excl; } @Override void setPaths(UserPreferences u, Map<String, Boolean> files) { u.setIncludeFilterFiles(files); } }, EXCLUDE("property.excludefilter") { @Override Map<String, Boolean> selectedPaths(UserPreferences u) { return u.getExcludeFilterFiles(); } @Override Map<String, Boolean> excludedPaths(UserPreferences u) { Map<String, Boolean> excl = new TreeMap<String, Boolean>(); excl.putAll(u.getIncludeFilterFiles()); excl.putAll(u.getExcludeBugsFiles()); return excl; } @Override void setPaths(UserPreferences u, Map<String, Boolean> files) { u.setExcludeFilterFiles(files); } }, EXCLUDE_BUGS("property.excludebugs") { @Override Map<String, Boolean> selectedPaths(UserPreferences u) { return u.getExcludeBugsFiles(); } @Override Map<String, Boolean> excludedPaths(UserPreferences u) { Map<String, Boolean> excl = new TreeMap<String, Boolean>(); excl.putAll(u.getIncludeFilterFiles()); excl.putAll(u.getExcludeFilterFiles()); return excl; } @Override void setPaths(UserPreferences u, Map<String, Boolean> files) { u.setExcludeBugsFiles(files); } }; final String propertyName; FilterKind(String propertyName) { this.propertyName = propertyName; } abstract Map<String, Boolean> selectedPaths(UserPreferences u); abstract Map<String, Boolean> excludedPaths(UserPreferences u); abstract void setPaths(UserPreferences u, Map<String, Boolean> files); } @Override public void setEnabled(boolean enabled) { filterExcl.setControlEnabled(enabled); filterIncl.setControlEnabled(enabled); filterExclBugs.setControlEnabled(enabled); super.setEnabled(enabled); } void refreshUI(UserPreferences prefs) { filterExcl.setFilters(prefs); filterExclBugs.setFilters(prefs); filterIncl.setFilters(prefs); refreshTables(); } protected PathsProvider getFilterIncl() { return filterIncl; } protected PathsProvider getFilterExcl() { return filterExcl; } protected PathsProvider getFilterExclBugs() { return filterExclBugs; } }