/*******************************************************************************
* Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, Canada
* and IBM Corporation. All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* The Chisel Group, University of Victoria
*******************************************************************************/
package net.sourceforge.tagsea.parsed.core.internal.resources;
import java.util.HashMap;
import java.util.Iterator;
import net.sourceforge.tagsea.parsed.ParsedWaypointPlugin;
import net.sourceforge.tagsea.parsed.core.internal.ThreadQueue;
import net.sourceforge.tagsea.parsed.parser.WaypointParseProblem;
import org.eclipse.core.filebuffers.FileBuffers;
import org.eclipse.core.filebuffers.IFileBuffer;
import org.eclipse.core.filebuffers.ITextFileBuffer;
import org.eclipse.core.filebuffers.LocationKind;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.runtime.jobs.Job;
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.texteditor.MarkerAnnotation;
/**
* A class that connects to documents and annotates them with parse problems.
* @author Del Myers
*
*/
public class ProblemAnnotator {
private HashMap<IMarker, WaypointParseProblem> markerProblemMap;
public ProblemAnnotator() {
markerProblemMap = new HashMap<IMarker, WaypointParseProblem>();
}
/**
* Cleans the given document of all parse problems.
* @param document
* @param file
*/
void cleanDocument(final IDocument document, final IFile file) {
if (file == null) return;
spawnAnnotator(new Runnable(){
public void run() {
ISchedulingRule rule = file.getWorkspace().getRuleFactory().markerRule(file);
try {
Job.getJobManager().beginRule(rule, new NullProgressMonitor());
try {
IMarker[] markers = file.findMarkers(IProblemConstants.PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
for (IMarker marker : markers) {
if (marker != null && marker.exists()) {
markerProblemMap.remove(marker);
marker.delete();
}
}
} catch (CoreException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} finally {
Job.getJobManager().endRule(rule);
}
}
});
}
/**
* Cleans all of the parse problems intersecting with the given region.
* @param document
* @param file
* @param region
*/
void cleanDocument(final IDocument document, final IFile file, final IRegion region) {
spawnAnnotator(new Runnable(){
public void run() {
IAnnotationModel annotations = getAnnotationModel(file);
if (annotations == null) return;
ISchedulingRule rule = file.getWorkspace().getRuleFactory().markerRule(file);
try {
Job.getJobManager().beginRule(rule, new NullProgressMonitor());
for (Iterator<?> i=annotations.getAnnotationIterator(); i.hasNext();) {
Annotation a = (Annotation) i.next();
if (a instanceof MarkerAnnotation) {
MarkerAnnotation ppa = (MarkerAnnotation) a;
try {
if (!ppa.getMarker().exists()) {
markerProblemMap.remove(ppa.getMarker());
} else {
if (ppa.getMarker().getType().equals(IProblemConstants.PROBLEM_MARKER)) {
Position p = annotations.getPosition(ppa);
if (intersects(region, p)) {
ppa.getMarker().delete();
synchronized (markerProblemMap) {
markerProblemMap.remove(ppa.getMarker());
}
}
}
}
} catch (CoreException e) {
ParsedWaypointPlugin.getDefault().log(e);
}
}
}
} finally {
Job.getJobManager().endRule(rule);
}
}
});
}
/**
* @param region
* @param p
* @return
*/
private boolean intersects(IRegion region, Position p) {
int pStart = p.getOffset();
int pEnd = p.getOffset()+p.getLength();
int rStart = region.getOffset();
int rEnd = region.getOffset()+region.getLength();
return (
(pStart == rStart || pEnd == rEnd) ||
(pStart >= rStart && pStart <= rEnd) ||
(rStart >= pStart && rStart <= rEnd)
);
}
/**
* Gets the annotation model for the given file if it can be found (i.e. a file buffer is opened for it)
* or null if it cannot.
* @param file
* @return
*/
private IAnnotationModel getAnnotationModel(IFile file) {
if (file == null) return null;
IFileBuffer buffer =
FileBuffers.getTextFileBufferManager().getFileBuffer(file.getFullPath(), LocationKind.IFILE);
if (buffer instanceof ITextFileBuffer) {
return ((ITextFileBuffer)buffer).getAnnotationModel();
}
return null;
}
/**
* @param marker
* @return
*/
public WaypointParseProblem getProblemForMarker(IMarker marker) {
synchronized (markerProblemMap) {
return markerProblemMap.get(marker);
}
}
/**
* @param problem
* @param file
*/
public void createAnnotation(final WaypointParseProblem problem, final IFile file) {
spawnAnnotator(new Runnable(){
public void run() {
int start = problem.getOffset();
int end = problem.getEnd();
if (start != -1 && end != -1) {
final HashMap<String, Object> attributes = new HashMap<String, Object>();
attributes.put(IMarker.CHAR_START, start);
attributes.put(IMarker.CHAR_END, end);
attributes.put(IMarker.MESSAGE, problem.getMessage());
try {
int line = problem.getDocument().getLineOfOffset(start);
attributes.put(IMarker.LINE_NUMBER, line);
} catch (BadLocationException e1) {
//return with no annotation
return;
}
attributes.put(IProblemConstants.ATTR_PROBLEM_SEVERITY, problem.getSeverity());
ISchedulingRule rule = file.getWorkspace().getRuleFactory().markerRule(file);
try {
Job.getJobManager().beginRule(rule, new NullProgressMonitor());
IMarker marker= file.createMarker(IProblemConstants.PROBLEM_MARKER);
marker.setAttributes(attributes);
synchronized (markerProblemMap) {
markerProblemMap.put(marker, problem);
}
} catch (CoreException e) {
ParsedWaypointPlugin.getDefault().log(e);
} finally {
Job.getJobManager().endRule(rule);
}
}
}
});
}
private void spawnAnnotator(Runnable r) {
ThreadQueue.queue(r);
}
}