/*******************************************************************************
* Copyright (c) 2007 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:
* Robert Fuhrer (rfuhrer@watson.ibm.com) - initial API and implementation
*******************************************************************************/
package org.eclipse.imp.editor.internal;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.eclipse.imp.editor.UniversalEditor;
import org.eclipse.imp.editor.quickfix.IAnnotation;
import org.eclipse.imp.parser.IMessageHandler;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.jface.text.source.IAnnotationModelExtension;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.ITextEditor;
/**
* An implementation of the IMessageHandler interface that creates editor annotations
* directly from messages. Used for live parsing within a source editor (cf. building,
* which uses the class MarkerCreator to create markers).
* @author rmfuhrer
*/
@SuppressWarnings("unchecked")
public class AnnotationCreator implements IMessageHandler {
private static class PositionedMessage {
public final String message;
/**
* Textual position expressed as an offset and length
*/
public final Position pos;
/**
* Additional attributes, if any, like severity and error code
*/
public final Map<String, Object> attributes;
public PositionedMessage(String msg, Position pos, Map<String, Object> attributes) {
this.message= msg;
this.pos= pos;
this.attributes= attributes;
}
public PositionedMessage(String msg, Position pos) {
this(msg, pos, null);
}
}
private final ITextEditor fEditor;
private final List<PositionedMessage> fMessages= new LinkedList<PositionedMessage>();
private final List<Annotation> fAnnotations= new LinkedList<Annotation>();
public AnnotationCreator(ITextEditor textEditor) {
fEditor= textEditor;
}
public void clearMessages() {
removeAnnotations();
fMessages.clear();
}
public void startMessageGroup(String groupName) { }
public void endMessageGroup() { }
public void handleSimpleMessage(String msg, int startOffset, int endOffset,
int startCol, int endCol, int startLine, int endLine) {
Position pos= new Position(startOffset, endOffset - startOffset + 1);
fMessages.add(new PositionedMessage(msg, pos));
}
public void handleSimpleMessage(String message, int startOffset, int endOffset,
int startCol, int endCol, int startLine, int endLine,
Map<String, Object> attributes) {
Position pos= new Position(startOffset, endOffset - startOffset + 1);
fMessages.add(new PositionedMessage(message, pos, attributes));
}
public void endMessages() {
IDocumentProvider docProvider= fEditor.getDocumentProvider();
if (docProvider != null) {
IAnnotationModel model= docProvider.getAnnotationModel(fEditor.getEditorInput());
if (model instanceof IAnnotationModelExtension) {
IAnnotationModelExtension modelExt= (IAnnotationModelExtension) model;
Annotation[] oldAnnotations= fAnnotations.toArray(new Annotation[fAnnotations.size()]);
Map<Annotation, Position> newAnnotations= new HashMap<Annotation, Position>(fMessages.size());
for(PositionedMessage pm: fMessages) {
Annotation anno= createAnnotation(pm);
newAnnotations.put(anno, pm.pos);
fAnnotations.add(anno);
}
modelExt.replaceAnnotations(oldAnnotations, newAnnotations);
} else if (model != null) { // model could be null if, e.g., we're directly browsing a file version in a src repo
for(Iterator i= model.getAnnotationIterator(); i.hasNext(); ) {
Annotation a= (Annotation) i.next();
if (UniversalEditor.isParseAnnotation(a)) {
model.removeAnnotation(a);
}
}
for(PositionedMessage pm: fMessages) {
Annotation annotation= createAnnotation(pm);
model.addAnnotation(annotation, pm.pos);
fAnnotations.add(annotation);
}
}
// System.out.println("Annotation model updated.");
}
fMessages.clear();
}
private Annotation createAnnotation(PositionedMessage pm) {
if (pm.attributes == null || !(fEditor instanceof UniversalEditor)) {
return new Annotation(UniversalEditor.PARSE_ANNOTATION_TYPE, false, pm.message);
} else {
return new DefaultAnnotation(getAnnotationType(pm), false, pm.message,
(UniversalEditor) fEditor, pm.attributes);
}
}
private String getAnnotationType(PositionedMessage pm) {
if (pm.attributes.containsKey(SEVERITY_KEY)) {
int severity= (Integer) pm.attributes.get(SEVERITY_KEY);
switch(severity) {
case IAnnotation.ERROR:
return UniversalEditor.PARSE_ANNOTATION_TYPE_ERROR;
case IAnnotation.WARNING:
return UniversalEditor.PARSE_ANNOTATION_TYPE_WARNING;
case IAnnotation.INFO:
return UniversalEditor.PARSE_ANNOTATION_TYPE_INFO;
}
}
return UniversalEditor.PARSE_ANNOTATION_TYPE;
}
private void removeAnnotations() {
final IDocumentProvider docProvider= fEditor.getDocumentProvider();
if (docProvider == null) {
return;
}
IAnnotationModel model= docProvider.getAnnotationModel(fEditor.getEditorInput());
if (model == null)
return;
if (model instanceof IAnnotationModelExtension) {
IAnnotationModelExtension modelExt= (IAnnotationModelExtension) model;
Annotation[] oldAnnotations= fAnnotations.toArray(new Annotation[fAnnotations.size()]);
modelExt.replaceAnnotations(oldAnnotations, Collections.EMPTY_MAP);
} else {
for(Iterator i= model.getAnnotationIterator(); i.hasNext(); ) {
Annotation a= (Annotation) i.next();
if (UniversalEditor.isParseAnnotation(a)) {
model.removeAnnotation(a);
}
}
}
// System.out.println("Annotations removed.");
fAnnotations.clear();
}
}