/* * 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.ArrayList; import javax.annotation.CheckForNull; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.Assert; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.Position; import org.eclipse.jface.text.source.IAnnotationModel; import org.eclipse.jface.text.source.IVerticalRulerInfo; import org.eclipse.jface.viewers.ISelection; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.widgets.Control; import org.eclipse.ui.IEditorActionDelegate; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.texteditor.AbstractMarkerAnnotationModel; import org.eclipse.ui.texteditor.IDocumentProvider; import org.eclipse.ui.texteditor.ITextEditor; import org.eclipse.ui.texteditor.ITextEditorExtension; import org.eclipse.ui.texteditor.IUpdate; import de.tobject.findbugs.FindbugsPlugin; import de.tobject.findbugs.reporter.MarkerUtil; /** * An action that can display a bug marker's details in the FindBugs details * view. TODO (PeterF) We should replace this action with a marker resolution or * a marker help contribution. * * @author Phil Crosby * @author Peter Friese * @version 1.0 * @since 20.4.2004 */ public class MarkerRulerAction implements IEditorActionDelegate, IUpdate, MouseListener, IMenuListener { private IVerticalRulerInfo ruler; @CheckForNull private ITextEditor editor; /** Contains the markers of the currently selected line in the ruler margin. */ private final ArrayList<IMarker> markers; /** * The action sent to this delegate. Enable and disable it based upon * whether there are FindBugs markers on the current line */ private IAction action; public MarkerRulerAction() { super(); markers = new ArrayList<IMarker>(); } public void setActiveEditor(IAction callerAction, IEditorPart targetEditor) { Control control; // See if we're already listenting to an editor; if so, stop listening if (editor != null) { if (ruler != null) { control = ruler.getControl(); if (control != null && !control.isDisposed()) { control.removeMouseListener(this); } } if (editor instanceof ITextEditorExtension) { ((ITextEditorExtension) editor).removeRulerContextMenuListener(this); } } // Start listening to the current editor if (targetEditor instanceof ITextEditor) { ITextEditor textEditor = (ITextEditor) targetEditor; editor = textEditor; // Check for editor's ruler context listener capability if (textEditor instanceof ITextEditorExtension) { ((ITextEditorExtension) textEditor).addRulerContextMenuListener(this); } ruler = (IVerticalRulerInfo) textEditor.getAdapter(IVerticalRulerInfo.class); if (ruler != null) { control = ruler.getControl(); if (control != null && !control.isDisposed()) { control.addMouseListener(this); } } } else { ruler = null; editor = null; } } public void run(IAction action1) { this.action = action1; obtainFindBugsMarkers(); if (markers.size() == 0 && editor != null) { MessageDialog.openError(editor.getSite().getShell(), "Error Showing Bug Details", "You must first select a FindBugs marker to view bug details."); } else { update(); } } public void selectionChanged(IAction action1, ISelection selection) { this.action = action1; } /** * Fills markers field with all of the FindBugs markers associated with the * current line in the text editor's ruler marign. */ protected void obtainFindBugsMarkers() { // Delete old markers markers.clear(); if (editor == null || ruler == null) { return; } // Obtain all markers in the editor IResource resource = (IResource) editor.getEditorInput().getAdapter(IFile.class); if(resource == null){ return; } IMarker[] allMarkers = MarkerUtil.getMarkers(resource, IResource.DEPTH_ZERO); if(allMarkers.length == 0) { return; } // Discover relevant markers, i.e. FindBugsMarkers AbstractMarkerAnnotationModel model = getModel(); IDocument document = getDocument(); for (int i = 0; i < allMarkers.length; i++) { if (includesRulerLine(model.getMarkerPosition(allMarkers[i]), document)) { if (MarkerUtil.isFindBugsMarker(allMarkers[i])) { markers.add(allMarkers[i]); } } } } public void update() { if (markers.size() > 0) { IMarker marker = markers.get(0); if (action.getId().endsWith("showBugInfo")) { FindbugsPlugin.showMarker(marker, FindbugsPlugin.DETAILS_VIEW_ID, editor); } else { // TODO show all FindbugsPlugin.showMarker(marker, FindbugsPlugin.TREE_VIEW_ID, editor); } markers.clear(); } } /** * Checks a Position in a document to see whether the line of last mouse * activity falls within this region. * * @param position * Position of the marker * @param document * the Document the marker resides in * @return true if the last mouse click falls on the same line as the marker */ protected boolean includesRulerLine(Position position, IDocument document) { if (position != null && ruler != null) { try { int markerLine = document.getLineOfOffset(position.getOffset()); int line = ruler.getLineOfLastMouseButtonActivity(); if (line == markerLine) { return true; } } catch (BadLocationException x) { FindbugsPlugin.getDefault().logException(x, "Error getting marker line"); } } return false; } /** * Retrieves the AbstractMarkerAnnontationsModel from the editor. * * @return AbstractMarkerAnnotatiosnModel from the editor */ @CheckForNull protected AbstractMarkerAnnotationModel getModel() { if(editor == null) { return null; } IDocumentProvider provider = editor.getDocumentProvider(); IAnnotationModel model = provider.getAnnotationModel(editor.getEditorInput()); if (model instanceof AbstractMarkerAnnotationModel) { return (AbstractMarkerAnnotationModel) model; } return null; } /** * Retrieves the document from the editor. * * @return the document from the editor */ protected IDocument getDocument() { Assert.isNotNull(editor); IDocumentProvider provider = editor.getDocumentProvider(); return provider.getDocument(editor.getEditorInput()); } public void menuAboutToShow(IMenuManager manager) { if (action != null) { obtainFindBugsMarkers(); action.setEnabled(markers.size() > 0); } } public void mouseDoubleClick(MouseEvent e) { // } public void mouseDown(MouseEvent e) { // Only capture left clicks. if (e.button == 1) { obtainFindBugsMarkers(); if (markers.size() > 0) { update(); } } } public void mouseUp(MouseEvent e) { // } }