package org.erlide.cover.ui.annotations; import java.util.Iterator; import java.util.List; import java.util.Set; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.Position; import org.eclipse.jface.text.source.Annotation; import org.eclipse.jface.text.source.IAnnotationModel; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorReference; import org.eclipse.ui.IPartListener2; import org.eclipse.ui.IWindowListener; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchPartReference; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.texteditor.ITextEditor; import org.erlide.cover.core.Activator; import org.erlide.cover.core.ICoverAnnotationMarker; import org.erlide.cover.core.Logger; import org.erlide.cover.views.model.LineResult; import org.erlide.cover.views.model.ModuleSet; import org.erlide.cover.views.model.ModuleStats; import org.erlide.util.ErlLogger; /** * Attaches coverage annotation models. * * @author Aleksandra Lipiec <aleksandra.lipiec@erlang-solutions.com> */ public class EditorTracker implements ICoverAnnotationMarker { private static EditorTracker editorTracker; private final IWorkbench workbench; private final CoverageMap coverage; private final Logger log; private EditorTracker(final IWorkbench workbench) { this.workbench = workbench; log = Activator.getDefault(); final IWorkbenchWindow[] windows = workbench.getWorkbenchWindows(); for (final IWorkbenchWindow w : windows) { w.getPartService().addPartListener(partListener); } coverage = new CoverageMap(); this.workbench.addWindowListener(windowListener); } public static synchronized EditorTracker getInstance() { if (editorTracker == null) { editorTracker = new EditorTracker(PlatformUI.getWorkbench()); } return editorTracker; } public void dispose() { workbench.removeWindowListener(windowListener); final IWorkbenchWindow[] windows = workbench.getWorkbenchWindows(); for (final IWorkbenchWindow w : windows) { w.getPartService().removePartListener(partListener); } } /** * Marks coverage of all tested modules (if they are opened) */ @Override public void addAnnotations() { final IWorkbenchWindow[] windows = workbench.getWorkbenchWindows(); createAnnotationMap(); for (final IWorkbenchWindow w : windows) { for (final IWorkbenchPage page : w.getPages()) { for (final IEditorReference editor : page.getEditorReferences()) { if (editor.isDirty()) { continue; } annotateEditor(editor.getEditor(false)); } } } } private void createAnnotationMap() { final Iterator<ModuleStats> it = ModuleSet.iterator(); while (it.hasNext()) { final ModuleStats module = it.next(); if (!module.couldBeMarked) { continue; } final List<LineResult> list = module.getLineResults(); final String modName = module.getLabel() + ".erl"; for (final LineResult lr : list) { coverage.addAnnotation(modName, lr, null); } } } /** * Marks coverage for a specified file. * * @param fileName */ public void addAnnotationsToFile(final String fileName) { final IEditorPart currentEditor = workbench.getActiveWorkbenchWindow() .getActivePage().getActiveEditor(); if (currentEditor.getTitle().equals(fileName) && !currentEditor.isDirty()) { final ModuleStats module = ModuleSet.get(fileName.replace(".erl", "")); if (module == null || !module.couldBeMarked) { return; } final List<LineResult> list = module.getLineResults(); for (final LineResult lr : list) { coverage.addAnnotation(fileName, lr, null); } annotateEditor(currentEditor); } } public void removeAnnotationsFromFile(final String fileName) { final IEditorPart currentEditor = workbench.getActiveWorkbenchWindow() .getActivePage().getActiveEditor(); if (currentEditor.getTitle().equals(fileName)) { coverage.removeAll(fileName); clearAnnotations(currentEditor); } } /** * Makrs coverage of fragment of a file, e.g. of a single function. * * @param fileName * @param start * @param end */ public void addAnnotationsFragment(final String fileName, final int start, final int end) { final IEditorPart currentEditor = workbench.getActiveWorkbenchWindow() .getActivePage().getActiveEditor(); if (currentEditor.getTitle().equals(fileName) && currentEditor instanceof ITextEditor && !currentEditor.isDirty()) { final ModuleStats module = ModuleSet.get(fileName.replace(".erl", "")); if (module == null || !module.couldBeMarked) { return; } final List<LineResult> list = module.getLineResults(); final ITextEditor editor = (ITextEditor) currentEditor; log.info(fileName); for (final LineResult lr : list) { if (lr.getLineNum() < start || end != -1 && lr.getLineNum() > end) { continue; } if (!coverage.containsAnnotation(fileName, lr)) { coverage.addAnnotation(fileName, lr, null); } markLine(editor, lr); } } } /** * Removes coverage annotations from a fragment of file * * @param fileName * @param start * @param end */ public void removeAnnotationsFragment(final String fileName, final int start, final int end) { final IEditorPart currentEditor = workbench.getActiveWorkbenchWindow() .getActivePage().getActiveEditor(); if (currentEditor.getTitle().equals(fileName) && currentEditor instanceof ITextEditor) { final ITextEditor editor = (ITextEditor) currentEditor; final IAnnotationModel annMod = editor.getDocumentProvider() .getAnnotationModel(editor.getEditorInput()); final Set<LineResult> list = coverage.getLineSet(editor.getTitle()); for (final LineResult lr : list) { if (lr.getLineNum() < start || end != -1 && lr.getLineNum() > end) { continue; } log.info(lr.getLineNum()); if (coverage.containsAnnotation(editor.getTitle(), lr)) { final Annotation ann = coverage.getAnnotation(editor.getTitle(), lr); annMod.removeAnnotation(ann); coverage.removeAnnotation(editor.getTitle(), lr); } } } } public void annotateEditor(final IWorkbenchPart part) { if (!(part instanceof ITextEditor)) { return; } final ITextEditor editor = (ITextEditor) part; log.info(editor.getTitle()); if (!coverage.containsFile(editor.getTitle())) { return; } log.info(coverage); final Set<LineResult> list = coverage.getLineSet(editor.getTitle()); for (final LineResult lr : list) { if (lr.getLineNum() == 0) { continue; } markLine(editor, lr); } } private void markLine(final ITextEditor editor, final LineResult lr) { final IDocument doc = editor.getDocumentProvider() .getDocument(editor.getEditorInput()); final IAnnotationModel annMod = editor.getDocumentProvider() .getAnnotationModel(editor.getEditorInput()); log.info("mark line " + lr.getLineNum()); try { final IRegion reg = doc.getLineInformation(lr.getLineNum() - 1); final int length = reg.getLength(); final int offset = reg.getOffset(); final Position pos = new Position(offset, length); Annotation annotation; if (lr.called()) { annotation = CoverageAnnotationFactory .create(CoverageTypes.FULL_COVERAGE); } else { annotation = CoverageAnnotationFactory.create(CoverageTypes.NO_COVERAGE); } final Annotation lastAnn = coverage.getAnnotation(editor.getTitle(), lr); log.info(lastAnn); if (lastAnn == null) { annMod.addAnnotation(annotation, pos); coverage.addAnnotation(editor.getTitle(), lr, annotation); } else if (annMod.getPosition(lastAnn) == null) { annMod.addAnnotation(lastAnn, pos); } else if (lastAnn.getType().equals(CoverageTypes.NO_COVERAGE) && annotation.getType().equals(CoverageTypes.FULL_COVERAGE)) { annMod.removeAnnotation(lastAnn); annMod.addAnnotation(annotation, pos); coverage.addAnnotation(editor.getTitle(), lr, annotation); } } catch (final BadLocationException e) { log.error(e); ErlLogger.error(e); } } /** * clears coverage annotations from all files opened in the editor */ @Override public void clearAllAnnotations() { final IWorkbenchWindow[] windows = workbench.getWorkbenchWindows(); coverage.removeAll(); for (final IWorkbenchWindow w : windows) { for (final IWorkbenchPage page : w.getPages()) { for (final IEditorReference editor : page.getEditorReferences()) { clearAnnotations(editor.getPart(false)); } } } } public void clearAnnotations(final IWorkbenchPart part) { if (part != null) { log.info(part.getTitle()); } if (part instanceof ITextEditor) { final ITextEditor editor = (ITextEditor) part; final IAnnotationModel annMod = editor.getDocumentProvider() .getAnnotationModel(editor.getEditorInput()); @SuppressWarnings("rawtypes") final Iterator it = annMod.getAnnotationIterator(); while (it.hasNext()) { final Annotation annotation = (Annotation) it.next(); if (annotation.getType().equals(CoverageTypes.FULL_COVERAGE) || annotation.getType().equals(CoverageTypes.NO_COVERAGE)) { annMod.removeAnnotation(annotation); } } } } private final IWindowListener windowListener = new IWindowListener() { @Override public void windowOpened(final IWorkbenchWindow window) { window.getPartService().addPartListener(partListener); } @Override public void windowClosed(final IWorkbenchWindow window) { window.getPartService().removePartListener(partListener); } @Override public void windowActivated(final IWorkbenchWindow window) { } @Override public void windowDeactivated(final IWorkbenchWindow window) { } }; private final IPartListener2 partListener = new IPartListener2() { @Override public void partOpened(final IWorkbenchPartReference partref) { annotateEditor(partref.getPart(false)); } @Override public void partActivated(final IWorkbenchPartReference partref) { } @Override public void partBroughtToTop(final IWorkbenchPartReference partref) { } @Override public void partVisible(final IWorkbenchPartReference partref) { } @Override public void partInputChanged(final IWorkbenchPartReference partref) { } @Override public void partClosed(final IWorkbenchPartReference partref) { } @Override public void partDeactivated(final IWorkbenchPartReference partref) { } @Override public void partHidden(final IWorkbenchPartReference partref) { } }; }