package de.ovgu.cide.editor.inlineprojection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.reconciler.DirtyRegion;
import org.eclipse.jface.text.reconciler.IReconcilingStrategy;
import org.eclipse.jface.text.reconciler.IReconcilingStrategyExtension;
import org.eclipse.jface.text.source.Annotation;
import cide.gast.IASTNode;
import cide.gast.ISourceFile;
import cide.gparser.ParseException;
import de.ovgu.cide.editor.CodeSegment;
import de.ovgu.cide.editor.CodeSegmentCalculator;
import de.ovgu.cide.editor.ColoredTextEditor;
public class ProjectionReconcilingStrategy implements IReconcilingStrategy,
IReconcilingStrategyExtension {
private IDocument fDocument;
private ColoredTextEditor editor;
private List<CodeSegment> fAddedPositions = new ArrayList<CodeSegment>();
private List<CodeSegment> fRemovedPositions = new ArrayList<CodeSegment>();
private List<ColoredInlineProjectionAnnotation> oldAnnotations = new ArrayList<ColoredInlineProjectionAnnotation>();
public void reconcile(DirtyRegion dirtyRegion, IRegion subRegion) {
initialReconcile();
}
public void reconcile(IRegion partition) {
initialReconcile();
}
public void setDocument(IDocument document) {
this.fDocument = document;
}
public void initialReconcile() {
try {
editor.getSourceFile().refreshAST();
ISourceFile ast = editor.getSourceFile().getAST();
reconcileAST(ast);
} catch (CoreException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void reconcileAST(ISourceFile ast) {
reconcilePositions(new IASTNode[] { ast });
updateInlineProjectionAnnotations(fAddedPositions, editor);
}
/**
* Reconcile positions based on the AST subtrees
*
* @param subtrees
* the AST subtrees
*/
private void reconcilePositions(IASTNode[] subtrees) {
List<CodeSegment> list = new ArrayList<CodeSegment>();
for (int i = 0, n = subtrees.length; i < n; i++)
list.addAll(CodeSegmentCalculator.getCodeSegments(subtrees[i],
editor.getSourceFile().getColorManager()));
// subtrees[i].accept(fCollector);
deleteEmptySegments(list);
fAddedPositions.addAll(list);
List<CodeSegment> oldPositions = fRemovedPositions;
List<CodeSegment> newPositions = list;
for (int i = 0, n = oldPositions.size(); i < n; i++) {
CodeSegment current = oldPositions.get(i);
if (current != null)
newPositions.add(current);
}
fRemovedPositions = newPositions;
}
private void deleteEmptySegments(List<CodeSegment> list) {
for (Iterator<CodeSegment> i = list.iterator(); i.hasNext();) {
CodeSegment segment = i.next();
if (segment.getColors().isEmpty())
i.remove();
}
}
public void setProgressMonitor(IProgressMonitor monitor) {
}
public void setEditor(ColoredTextEditor editor) {
this.editor = editor;
}
protected void updateInlineProjectionAnnotations(
List<CodeSegment> addedPositions, ColoredTextEditor editor) {
InlineProjectionAnnotationModel annotationModel = editor.getViewer()
.getInlineProjectionAnnotationModel();
ColoredInlineProjectionAnnotation[] annotations = new ColoredInlineProjectionAnnotation[addedPositions
.size()];
// this will hold the new annotations along
// with their corresponding positions
HashMap<ColoredInlineProjectionAnnotation, Position> newAnnotations = new HashMap<ColoredInlineProjectionAnnotation, Position>();
addedPositions = new ArrayList<CodeSegment>(addedPositions);
ArrayList<ColoredInlineProjectionAnnotation> knownPositions = new ArrayList<ColoredInlineProjectionAnnotation>(
oldAnnotations);
ArrayList<ColoredInlineProjectionAnnotation> savedPositions = new ArrayList<ColoredInlineProjectionAnnotation>();
// move unchanged segments from known to saved (those are not deleted)
for (Iterator<CodeSegment> i = addedPositions.iterator(); i.hasNext();) {
CodeSegment seg = i.next();
for (Iterator<ColoredInlineProjectionAnnotation> a = knownPositions
.iterator(); a.hasNext();) {
ColoredInlineProjectionAnnotation known = a.next();
if (seg.offset == known.getPosition().getOffset()
&& seg.length == known.getPosition().getLength()
&& seg.getColors().equals(known.getColors())) {
i.remove();
a.remove();
savedPositions.add(known);
}
}
}
for (int i = 0; i < addedPositions.size(); i++) {
Position pos = new Position(addedPositions.get(i).offset,
addedPositions.get(i).length);
ColoredInlineProjectionAnnotation annotation = new ColoredInlineProjectionAnnotation(
addedPositions.get(i).getColors(), editor.getSourceFile()
.getProject(), pos);
annotation.adjustCollapsing(editor.getProjectionColorManager()
.getExpandedColors());
newAnnotations.put(annotation, pos);
annotations[i] = annotation;
}
if (annotationModel != null) {
Annotation[] deletedAnnotations = new Annotation[knownPositions
.size()];
deletedAnnotations = knownPositions.toArray(deletedAnnotations);
annotationModel.modifyAnnotations(deletedAnnotations,
newAnnotations, null);
}
oldAnnotations = savedPositions;
oldAnnotations.addAll(newAnnotations.keySet());
}
}