/* * FindBugs Eclipse Plug-in. * Copyright (C) 2003 - 2004, Peter Friese * * 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.actions; import java.util.List; import java.util.Map; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.IWorkspaceDescription; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.action.IAction; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.dialogs.MessageDialogWithToggle; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IObjectActionDelegate; import org.eclipse.ui.IPerspectiveDescriptor; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchPartSite; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.WorkbenchException; import de.tobject.findbugs.FindBugsJob; import de.tobject.findbugs.FindbugsPlugin; import de.tobject.findbugs.builder.FindBugsWorker; import de.tobject.findbugs.builder.ResourceUtils; import de.tobject.findbugs.builder.WorkItem; import de.tobject.findbugs.preferences.FindBugsConstants; import de.tobject.findbugs.reporter.MarkerUtil; import de.tobject.findbugs.view.FindBugsPerspectiveFactory; import edu.umd.cs.findbugs.plugin.eclipse.util.MutexSchedulingRule; /** * Run FindBugs on the currently selected element(s) in the package explorer. * * @author Peter Friese * @author Phil Crosby * @author Andrei Loskutov * @version 1.1 * @since 25.09.2003 */ public class FindBugsAction implements IObjectActionDelegate { /** The current selection. */ protected ISelection selection; /** true if this action is used from editor */ protected boolean usedInEditor; private IWorkbenchPart targetPart; private static boolean dialogAlreadyShown; @Override public final void setActivePart(final IAction action, final IWorkbenchPart targetPart) { this.targetPart = targetPart; } public static boolean isFindBugsPerspectiveActive(IWorkbenchPart part) { IPerspectiveDescriptor perspective = getWindow(part).getActivePage().getPerspective(); return perspective != null && FindBugsPerspectiveFactory.ID.equals(perspective.getId()); } @Override public final void selectionChanged(final IAction action, final ISelection newSelection) { if (!usedInEditor) { this.selection = newSelection; } } @Override public void run(final IAction action) { if (selection == null || selection.isEmpty()) { return; } IWorkspace workspace = ResourcesPlugin.getWorkspace(); IWorkspaceDescription description = workspace.getDescription(); if (!description.isAutoBuilding() && getClass().equals(FindBugsAction.class)) { boolean confirm = MessageDialog.openConfirm(null, "Project -> 'Build Automatically' disabled", "You are going to run FindBugs analysis on a not compiled or partially compiled project.\n\n" + "To get reliable analysis results, you should make sure that project is compiled first.\n\n" + "Continue with FindBugs analysis?"); if (!confirm) { return; } } if (selection instanceof IStructuredSelection) { IStructuredSelection sSelection = (IStructuredSelection) selection; dialogAlreadyShown = false; Map<IProject, List<WorkItem>> projectMap = ResourceUtils.getResourcesPerProject(sSelection); for (Map.Entry<IProject, List<WorkItem>> e : projectMap.entrySet()) { work(targetPart, e.getKey(), e.getValue()); } targetPart = null; selection = null; } } protected IDialogSettings getDialogSettings() { IDialogSettings settings = FindbugsPlugin.getDefault().getDialogSettings(); String settingsId = getDialogSettingsId(); IDialogSettings section = settings.getSection(settingsId); if (section == null) { section = settings.addNewSection(settingsId); } return section; } protected final IProject getProject(IStructuredSelection structuredSelection) { Object element = structuredSelection.getFirstElement(); IResource resource = ResourceUtils.getResource(element); if (resource == null) { return null; } IProject project = resource.getProject(); return project; } protected String getDialogSettingsId() { return "findBugsAction"; } /** * Run a FindBugs analysis on the given resource, displaying a progress * monitor. * * @param part * * @param resources * The resource to run the analysis on. */ protected void work(IWorkbenchPart part, final IResource resource, final List<WorkItem> resources) { FindBugsJob runFindBugs = new StartedFromViewJob("Finding bugs in " + resource.getName() + "...", resource, resources, part); runFindBugs.scheduleInteractive(); } protected static void refreshViewer(IWorkbenchPart targetPart, final List<WorkItem> resources) { if (targetPart == null) { return; } ISelectionProvider selProvider = (ISelectionProvider) targetPart.getAdapter(ISelectionProvider.class); if (!(selProvider instanceof TreeViewer)) { return; } final TreeViewer viewer = (TreeViewer) selProvider; Display.getDefault().asyncExec(new Runnable() { @Override public void run() { if (viewer.getControl().isDisposed()) { return; } for (WorkItem workItem : resources) { if (workItem.getMarkerTarget() instanceof IProject) { // this element has to be refreshed manually, because // there is no one real // resource associated with it => no resource change // notification after // creating a marker... viewer.refresh(workItem.getCorespondingJavaElement(), true); } } } }); } protected static void askUserToSwitch(IWorkbenchPart part, int warningsNumber) { final IPreferenceStore store = FindbugsPlugin.getDefault().getPreferenceStore(); String message = "FindBugs analysis finished, " + warningsNumber + " warnings found.\n\nSwitch to the FindBugs perspective?"; MessageDialogWithToggle dialog = MessageDialogWithToggle.openYesNoCancelQuestion(null, "FindBugs analysis finished", message, "Remember the choice and do not ask me in the future", false, store, FindBugsConstants.ASK_ABOUT_PERSPECTIVE_SWITCH); boolean remember = dialog.getToggleState(); int returnCode = dialog.getReturnCode(); if (returnCode == IDialogConstants.YES_ID) { if (remember) { store.setValue(FindBugsConstants.SWITCH_PERSPECTIVE_AFTER_ANALYSIS, true); } switchPerspective(part); } else if (returnCode == IDialogConstants.NO_ID) { if (remember) { store.setValue(FindBugsConstants.SWITCH_PERSPECTIVE_AFTER_ANALYSIS, false); } } } protected static IWorkbenchWindow getWindow(IWorkbenchPart part) { IWorkbenchWindow window; IWorkbenchPartSite currentSite = part != null ? part.getSite() : null; if (currentSite != null) { window = currentSite.getWorkbenchWindow(); } else { window = FindbugsPlugin.getActiveWorkbenchWindow(); } return window; } protected static void switchPerspective(IWorkbenchPart part) { IWorkbenchWindow window = getWindow(part); IWorkbenchPage page = window.getActivePage(); IAdaptable input; if (page != null) { input = page.getInput(); } else { input = ResourcesPlugin.getWorkspace().getRoot(); } try { PlatformUI.getWorkbench().showPerspective(FindBugsPerspectiveFactory.ID, window, input); } catch (WorkbenchException e) { FindbugsPlugin.getDefault().logException(e, "Failed to open FindBugs Perspective"); } } private final static class StartedFromViewJob extends FindBugsJob { private final List<WorkItem> resources; private final IResource resource; private final IWorkbenchPart targetPart; private StartedFromViewJob(String name, IResource resource, List<WorkItem> resources, IWorkbenchPart targetPart) { super(name, resource); this.resources = resources; this.resource = resource; this.targetPart = targetPart; } @Override protected boolean supportsMulticore(){ return MutexSchedulingRule.MULTICORE; } @Override protected void runWithProgress(IProgressMonitor monitor) throws CoreException { FindBugsWorker worker = new FindBugsWorker(resource, monitor); worker.work(resources); refreshViewer(targetPart, resources); checkPerspective(); } private void checkPerspective() { if (isFindBugsPerspectiveActive(targetPart)) { return; } final IMarker[] allMarkers = MarkerUtil.getAllMarkers(resource); if (allMarkers.length == 0) { return; } Display.getDefault().asyncExec(new Runnable() { @Override public void run() { if (isFindBugsPerspectiveActive(targetPart)) { return; } final IPreferenceStore store = FindbugsPlugin.getDefault().getPreferenceStore(); final boolean ask = store.getBoolean(FindBugsConstants.ASK_ABOUT_PERSPECTIVE_SWITCH); if (ask && !dialogAlreadyShown) { dialogAlreadyShown = true; askUserToSwitch(targetPart, allMarkers.length); } else if (store.getBoolean(FindBugsConstants.SWITCH_PERSPECTIVE_AFTER_ANALYSIS)) { switchPerspective(targetPart); } } }); } } }