1 8 package com.mountainminds.eclemma.internal.ui.annotation; 9 10 import java.util.ArrayList ; 11 import java.util.Iterator ; 12 import java.util.List ; 13 14 import org.eclipse.core.resources.IResource; 15 import org.eclipse.core.runtime.IAdaptable; 16 import org.eclipse.jdt.core.IJavaElement; 17 import org.eclipse.jdt.core.ISourceReference; 18 import org.eclipse.jdt.core.JavaModelException; 19 import org.eclipse.jface.text.BadLocationException; 20 import org.eclipse.jface.text.DocumentEvent; 21 import org.eclipse.jface.text.IDocument; 22 import org.eclipse.jface.text.IDocumentListener; 23 import org.eclipse.jface.text.IRegion; 24 import org.eclipse.jface.text.Position; 25 import org.eclipse.jface.text.source.Annotation; 26 import org.eclipse.jface.text.source.AnnotationModelEvent; 27 import org.eclipse.jface.text.source.IAnnotationModel; 28 import org.eclipse.jface.text.source.IAnnotationModelExtension; 29 import org.eclipse.jface.text.source.IAnnotationModelListener; 30 import org.eclipse.jface.text.source.IAnnotationModelListenerExtension; 31 import org.eclipse.ui.IEditorInput; 32 import org.eclipse.ui.texteditor.IDocumentProvider; 33 import org.eclipse.ui.texteditor.ITextEditor; 34 35 import com.mountainminds.eclemma.core.CoverageTools; 36 import com.mountainminds.eclemma.core.analysis.IJavaCoverageListener; 37 import com.mountainminds.eclemma.core.analysis.IJavaElementCoverage; 38 import com.mountainminds.eclemma.core.analysis.ILineCoverage; 39 import com.mountainminds.eclemma.internal.ui.EclEmmaUIPlugin; 40 41 47 public class CoverageAnnotationModel implements IAnnotationModel { 48 49 50 private static final Object KEY = new Object (); 51 52 53 private List annotations = new ArrayList (32); 54 55 56 private List annotationModelListeners = new ArrayList (2); 57 58 private final ITextEditor editor; 59 private final IDocument document; 60 private int openConnections = 0; 61 private boolean annotated = false; 62 63 private IJavaCoverageListener coverageListener = new IJavaCoverageListener() { 64 public void coverageChanged() { 65 updateAnnotations(true); 66 } 67 }; 68 69 private IDocumentListener documentListener = new IDocumentListener() { 70 public void documentChanged(DocumentEvent event) { 71 updateAnnotations(false); 72 } 73 public void documentAboutToBeChanged(DocumentEvent event) { 74 } 75 }; 76 77 private CoverageAnnotationModel(ITextEditor editor, IDocument document) { 78 this.editor = editor; 79 this.document = document; 80 updateAnnotations(true); 81 } 82 83 89 public static void attach(ITextEditor editor) { 90 IDocumentProvider provider = editor.getDocumentProvider(); 91 if (provider == null) return; 93 IAnnotationModel model = provider.getAnnotationModel(editor.getEditorInput()); 94 if (!(model instanceof IAnnotationModelExtension)) return; 95 IAnnotationModelExtension modelex = (IAnnotationModelExtension) model; 96 97 IDocument document = provider.getDocument(editor.getEditorInput()); 98 99 CoverageAnnotationModel coveragemodel = (CoverageAnnotationModel) modelex.getAnnotationModel(KEY); 100 if (coveragemodel == null) { 101 coveragemodel = new CoverageAnnotationModel(editor, document); 102 modelex.addAnnotationModel(KEY, coveragemodel); 103 } 104 } 105 106 112 public static void detach(ITextEditor editor) { 113 IDocumentProvider provider = editor.getDocumentProvider(); 114 if (provider == null) return; 116 IAnnotationModel model = provider.getAnnotationModel(editor.getEditorInput()); 117 if (!(model instanceof IAnnotationModelExtension)) return; 118 IAnnotationModelExtension modelex = (IAnnotationModelExtension) model; 119 modelex.removeAnnotationModel(KEY); 120 } 121 122 protected void updateAnnotations(boolean force) { 123 ILineCoverage lineCoverage = null; 124 boolean annotate = false; 125 preconditions: { 126 if (editor.isDirty()) break preconditions; 127 IEditorInput input = editor.getEditorInput(); 128 if (input == null) break preconditions; 129 Object element = input.getAdapter(IJavaElement.class); 130 lineCoverage = findLineCoverage(element); 131 if (lineCoverage == null || !hasSource((IJavaElement) element)) 132 break preconditions; 133 annotate = true; 134 } 135 if (annotate) { 136 if (!annotated || force) { 137 createAnnotations(lineCoverage); 138 annotated = true; 139 } 140 } else { 141 if (annotated) { 142 clear(); 143 annotated = false; 144 } 145 } 146 } 147 148 protected boolean hasSource(IJavaElement element) { 149 if (element instanceof ISourceReference) { 150 try { 151 return ((ISourceReference) element).getSourceRange() != null; 152 } catch (JavaModelException ex) { 153 } 155 } 156 return false; 157 } 158 159 protected ILineCoverage findLineCoverage(Object element) { 160 IJavaElementCoverage coverage = CoverageTools.getCoverageInfo(element); 162 if (coverage == null) return null; 163 164 IResource resource = (IResource) ((IAdaptable) element).getAdapter(IResource.class); 166 if (resource != null) { 167 if (resource.getModificationStamp() != coverage.getResourceModificationStamp()) return null; 168 } 169 170 return coverage.getLineCoverage(); 171 } 172 173 protected void clear() { 174 AnnotationModelEvent event = new AnnotationModelEvent(this); 175 clear(event); 176 fireModelChanged(event); 177 } 178 179 protected void clear(AnnotationModelEvent event) { 180 for (Iterator i = annotations.iterator(); i.hasNext();) { 181 CoverageAnnotation ca = (CoverageAnnotation) i.next(); 182 event.annotationRemoved(ca, ca.getPosition()); 183 } 184 annotations.clear(); 185 } 186 187 protected void createAnnotations(ILineCoverage linecoverage) { 188 AnnotationModelEvent event = new AnnotationModelEvent(this); 189 clear(event); 190 int firstline = linecoverage.getFirstLine(); 191 int lastline = linecoverage.getLastLine(); 192 int offset = linecoverage.getOffset(); 193 byte[] coverage = linecoverage.getCoverage(); 194 try { 195 for (int l = firstline ; l <= lastline; l++) { 196 int status = coverage[l - offset]; 197 if (status != ILineCoverage.NO_CODE) { 198 IRegion region = document.getLineInformation(l - 1); 199 int docoffset = region.getOffset(); 200 int doclength = region.getLength(); 201 while (l < lastline && coverage[l + 1 - offset] == status) { 203 l++; 204 region = document.getLineInformation(l - 1); 205 doclength = region.getOffset() - docoffset + region.getLength(); 206 } 207 CoverageAnnotation ca = new CoverageAnnotation(docoffset, doclength, status); 208 annotations.add(ca); 209 event.annotationAdded(ca); 210 } 211 } 212 } catch (BadLocationException ex) { 213 EclEmmaUIPlugin.log(ex); 214 } 215 fireModelChanged(event); 216 } 217 218 219 public void addAnnotationModelListener(IAnnotationModelListener listener) { 220 if (!annotationModelListeners.contains(listener)) { 221 annotationModelListeners.add(listener); 222 fireModelChanged(new AnnotationModelEvent(this, true)); 223 } 224 } 225 226 public void removeAnnotationModelListener(IAnnotationModelListener listener) { 227 annotationModelListeners.remove(listener); 228 } 229 230 protected void fireModelChanged(AnnotationModelEvent event) { 231 event.markSealed(); 232 if (!event.isEmpty()) { 233 for (Iterator i = annotationModelListeners.iterator(); i.hasNext(); ) { 234 IAnnotationModelListener l = (IAnnotationModelListener) i.next(); 235 if (l instanceof IAnnotationModelListenerExtension) { 236 ((IAnnotationModelListenerExtension) l).modelChanged(event); 237 } else { 238 l.modelChanged(this); 239 } 240 } 241 } 242 } 243 244 public void connect(IDocument document) { 245 if (this.document != document) 246 throw new RuntimeException ("Can't connect to different document."); for (Iterator i = annotations.iterator(); i.hasNext();) { 248 CoverageAnnotation ca = (CoverageAnnotation) i.next(); 249 try { 250 document.addPosition(ca.getPosition()); 251 } catch (BadLocationException ex) { 252 EclEmmaUIPlugin.log(ex); 253 } 254 } 255 if (openConnections++ == 0) { 256 CoverageTools.addJavaCoverageListener(coverageListener); 257 document.addDocumentListener(documentListener); 258 } 259 } 260 261 public void disconnect(IDocument document) { 262 if (this.document != document) 263 throw new RuntimeException ("Can't disconnect from different document."); for (Iterator i = annotations.iterator(); i.hasNext();) { 265 CoverageAnnotation ca = (CoverageAnnotation) i.next(); 266 document.removePosition(ca.getPosition()); 267 } 268 if (--openConnections == 0) { 269 CoverageTools.removeJavaCoverageListener(coverageListener); 270 document.removeDocumentListener(documentListener); 271 } 272 } 273 274 277 public void addAnnotation(Annotation annotation, Position position) { 278 throw new UnsupportedOperationException (); 279 } 280 281 284 public void removeAnnotation(Annotation annotation) { 285 throw new UnsupportedOperationException (); 286 } 287 288 public Iterator getAnnotationIterator() { 289 return annotations.iterator(); 290 } 291 292 public Position getPosition(Annotation annotation) { 293 if (annotation instanceof CoverageAnnotation) { 294 return ((CoverageAnnotation) annotation).getPosition(); 295 } else { 296 return null; 297 } 298 } 299 300 } 301 | Popular Tags |