package it.tref.eclipse.wicket.plugin.editors;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.IBinding;
import org.eclipse.jdt.core.dom.IVariableBinding;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.NodeFinder;
import org.eclipse.jdt.core.util.IModifierConstants;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility;
import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
import org.eclipse.jdt.internal.ui.search.BreakContinueTargetFinder;
import org.eclipse.jdt.internal.ui.search.ExceptionOccurrencesFinder;
import org.eclipse.jdt.internal.ui.search.IOccurrencesFinder.OccurrenceLocation;
import org.eclipse.jdt.internal.ui.search.ImplementOccurrencesFinder;
import org.eclipse.jdt.internal.ui.search.MethodExitsFinder;
import org.eclipse.jdt.internal.ui.search.OccurrencesFinder;
import org.eclipse.jdt.internal.ui.text.JavaWordFinder;
import org.eclipse.jdt.internal.ui.viewsupport.ISelectionListenerWithAST;
import org.eclipse.jdt.ui.SharedASTProvider;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentExtension4;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ISelectionValidator;
import org.eclipse.jface.text.ISynchronizable;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.link.LinkedModeModel;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.jface.text.source.IAnnotationModelExtension;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.texteditor.IDocumentProvider;
@SuppressWarnings("restriction")
public class WicketFunMarkOccurrenceInstaller {
private ISelection fForcedMarkOccurrencesSelection;
private IRegion fMarkOccurrenceTargetRegion;
private OccurrencesFinderJob fOccurrencesFinderJob;
private Annotation[] fOccurrenceAnnotations;
private long fMarkOccurrenceModificationStamp;
private boolean fMarkExceptions = true;
private boolean fMarkTypeOccurrences = true;
private boolean fMarkMethodExitPoints = true;
private boolean fMarkBreakContinueTargets = true;
private boolean fMarkImplementors = true;
private boolean fMarkMethodOccurrences = true;
private boolean fMarkConstantOccurrences = true;
private boolean fMarkFieldOccurrences = true;
private boolean fMarkLocalVariableypeOccurrences = true;
private boolean fStickyOccurrenceAnnotations = false;
private final JavaEditor editor;
private ISelectionListenerWithAST fPostSelectionListenerWithAST;
public WicketFunMarkOccurrenceInstaller(JavaEditor editor) {
this.editor = editor;
}
public void installOccurrencesFinder(boolean forceUpdate) {
fPostSelectionListenerWithAST = new ISelectionListenerWithAST()
{
public void selectionChanged(IEditorPart part, ITextSelection selection, CompilationUnit astRoot)
{
if(editor.getViewer() == null)
{
SelectionListenerWithASTManager.getDefault().removeListener(editor, fPostSelectionListenerWithAST);
}
else
{
updateOccurrenceAnnotations(selection, astRoot, editor);
}
}
};
SelectionListenerWithASTManager.getDefault().addListener(editor,
fPostSelectionListenerWithAST);
if (forceUpdate && editor.getSelectionProvider() != null) {
fForcedMarkOccurrencesSelection = editor.getSelectionProvider()
.getSelection();
updateOccurrenceAnnotations(
(ITextSelection) fForcedMarkOccurrencesSelection,
JavaPlugin
.getDefault()
.getASTProvider()
.getAST(EditorUtility.getEditorInputJavaElement(
editor, false), SharedASTProvider.WAIT_YES,
null), editor);
}
/*
* if (fOccurrencesFinderJobCanceler == null) {
* fOccurrencesFinderJobCanceler= new OccurrencesFinderJobCanceler();
* fOccurrencesFinderJobCanceler.install(); }
*/
}
private void updateOccurrenceAnnotations(ITextSelection selection,
CompilationUnit astRoot, JavaEditor editor) {
if (fOccurrencesFinderJob != null)
fOccurrencesFinderJob.cancel();
/*
* if (!fMarkOccurrenceAnnotations) return;
*/
if (astRoot == null || selection == null)
return;
IDocument document = editor.getViewer().getDocument();
if (document == null)
return;
if (document instanceof IDocumentExtension4) {
int offset = selection.getOffset();
long currentModificationStamp = ((IDocumentExtension4) document)
.getModificationStamp();
IRegion markOccurrenceTargetRegion = fMarkOccurrenceTargetRegion;
if (markOccurrenceTargetRegion != null
&& currentModificationStamp == fMarkOccurrenceModificationStamp) {
if (markOccurrenceTargetRegion.getOffset() <= offset
&& offset <= markOccurrenceTargetRegion.getOffset()
+ markOccurrenceTargetRegion.getLength())
return;
}
fMarkOccurrenceTargetRegion = JavaWordFinder.findWord(document,
offset);
fMarkOccurrenceModificationStamp = currentModificationStamp;
}
OccurrenceLocation[] matches = null;
ASTNode selectedNode = NodeFinder.perform(astRoot,
selection.getOffset(), selection.getLength());
if (fMarkExceptions || fMarkTypeOccurrences) {
ExceptionOccurrencesFinder exceptionFinder = new ExceptionOccurrencesFinder();
String message = exceptionFinder.initialize(astRoot, selectedNode);
if (message == null) {
matches = exceptionFinder.getOccurrences();
if (!fMarkExceptions && matches != null)
matches = null;
}
}
if ((matches == null)
&& (fMarkMethodExitPoints || fMarkTypeOccurrences)) {
MethodExitsFinder finder = new MethodExitsFinder();
String message = finder.initialize(astRoot, selectedNode);
if (message == null) {
matches = finder.getOccurrences();
if (!fMarkMethodExitPoints && matches != null)
matches = null;
}
}
if ((matches == null)
&& (fMarkBreakContinueTargets || fMarkTypeOccurrences)) {
BreakContinueTargetFinder finder = new BreakContinueTargetFinder();
String message = finder.initialize(astRoot, selectedNode);
if (message == null) {
matches = finder.getOccurrences();
if (!fMarkBreakContinueTargets && matches != null)
matches = null;
}
}
if ((matches == null) && (fMarkImplementors || fMarkTypeOccurrences)) {
ImplementOccurrencesFinder finder = new ImplementOccurrencesFinder();
String message = finder.initialize(astRoot, selectedNode);
if (message == null) {
matches = finder.getOccurrences();
if (!fMarkImplementors && matches != null)
matches = null;
}
}
if (matches == null) {
IBinding binding = null;
if (selectedNode instanceof Name)
binding = ((Name) selectedNode).resolveBinding();
if (binding != null && markOccurrencesOfType(binding)) {
// Find the matches && extract positions so we can forget the
// AST
OccurrencesFinder finder = new OccurrencesFinder();
String message = finder.initialize(astRoot, selectedNode);
if (message == null)
matches = finder.getOccurrences();
}
}
if (matches == null || matches.length == 0) {
if (!fStickyOccurrenceAnnotations)
removeOccurrenceAnnotations(editor);
return;
}
Position[] positions = new Position[matches.length];
int i = 0;
for (int c = 0; c < matches.length; c++) {
positions[i++] = new Position(matches[c].getOffset(),
matches[c].getLength());
}
fOccurrencesFinderJob = new OccurrencesFinderJob(document, positions,
selection, editor);
fOccurrencesFinderJob.run(new NullProgressMonitor());
}
private void removeOccurrenceAnnotations(JavaEditor editor) {
fMarkOccurrenceModificationStamp = IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP;
fMarkOccurrenceTargetRegion = null;
IDocumentProvider documentProvider = editor.getDocumentProvider();
if (documentProvider == null)
return;
IAnnotationModel annotationModel = documentProvider
.getAnnotationModel(editor.getEditorInput());
if (annotationModel == null || fOccurrenceAnnotations == null)
return;
synchronized (getLockObject(annotationModel)) {
if (annotationModel instanceof IAnnotationModelExtension) {
((IAnnotationModelExtension) annotationModel)
.replaceAnnotations(fOccurrenceAnnotations, null);
} else {
for (int i = 0, length = fOccurrenceAnnotations.length; i < length; i++)
annotationModel.removeAnnotation(fOccurrenceAnnotations[i]);
}
fOccurrenceAnnotations = null;
}
}
private class OccurrencesFinderJob extends Job {
private IDocument fDocument;
private ISelection fSelection;
private ISelectionValidator fPostSelectionValidator;
private boolean fCanceled = false;
private IProgressMonitor fProgressMonitor;
private Position[] fPositions;
private JavaEditor editor;
public OccurrencesFinderJob(IDocument document, Position[] positions,
ISelection selection, JavaEditor editor) {
super("WicketFun_MarkOccurrencesJob");
fDocument = document;
fSelection = selection;
fPositions = positions;
this.editor = editor;
if (editor.getSelectionProvider() instanceof ISelectionValidator)
fPostSelectionValidator = (ISelectionValidator) editor
.getSelectionProvider();
}
// cannot use cancel() because it is declared final
@SuppressWarnings("unused")
private void doCancel() {
fCanceled = true;
cancel();
}
private boolean isCanceled() {
return fCanceled
|| fProgressMonitor.isCanceled()
|| fPostSelectionValidator != null
&& !(fPostSelectionValidator.isValid(fSelection) || fForcedMarkOccurrencesSelection == fSelection)
|| LinkedModeModel.hasInstalledModel(fDocument);
}
/*
* @see Job#run(org.eclipse.core.runtime.IProgressMonitor)
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public IStatus run(IProgressMonitor progressMonitor) {
fProgressMonitor = progressMonitor;
if (isCanceled())
return Status.CANCEL_STATUS;
ITextViewer textViewer = editor.getViewer();
if (textViewer == null)
return Status.CANCEL_STATUS;
IDocument document = textViewer.getDocument();
if (document == null)
return Status.CANCEL_STATUS;
IDocumentProvider documentProvider = editor.getDocumentProvider();
if (documentProvider == null)
return Status.CANCEL_STATUS;
IAnnotationModel annotationModel = documentProvider
.getAnnotationModel(editor.getEditorInput());
if (annotationModel == null)
return Status.CANCEL_STATUS;
// Add occurrence annotations
int length = fPositions.length;
Map annotationMap = new HashMap(length);
for (int i = 0; i < length; i++) {
if (isCanceled())
return Status.CANCEL_STATUS;
String message;
Position position = fPositions[i];
// Create & add annotation
try {
message = document.get(position.offset, position.length);
} catch (BadLocationException ex) {
// Skip this match
continue;
}
annotationMap.put(new Annotation(
"org.eclipse.jdt.ui.occurrences", false, message), //$NON-NLS-1$
position);
}
if (isCanceled())
return Status.CANCEL_STATUS;
synchronized (getLockObject(annotationModel)) {
if (annotationModel instanceof IAnnotationModelExtension) {
((IAnnotationModelExtension) annotationModel)
.replaceAnnotations(fOccurrenceAnnotations,
annotationMap);
} else {
// removeOccurrenceAnnotations();
Iterator iter = annotationMap.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry mapEntry = (Map.Entry) iter.next();
annotationModel.addAnnotation(
(Annotation) mapEntry.getKey(),
(Position) mapEntry.getValue());
}
}
fOccurrenceAnnotations = (Annotation[]) annotationMap.keySet()
.toArray(new Annotation[annotationMap.keySet().size()]);
}
return Status.OK_STATUS;
}
}
private Object getLockObject(IAnnotationModel annotationModel) {
if (annotationModel instanceof ISynchronizable) {
Object lock = ((ISynchronizable) annotationModel).getLockObject();
if (lock != null)
return lock;
}
return annotationModel;
}
boolean markOccurrencesOfType(IBinding binding) {
if (binding == null)
return false;
int kind = binding.getKind();
if (fMarkTypeOccurrences && kind == IBinding.TYPE)
return true;
if (fMarkMethodOccurrences && kind == IBinding.METHOD)
return true;
if (kind == IBinding.VARIABLE) {
IVariableBinding variableBinding = (IVariableBinding) binding;
if (variableBinding.isField()) {
int constantModifier = IModifierConstants.ACC_STATIC
| IModifierConstants.ACC_FINAL;
boolean isConstant = (variableBinding.getModifiers() & constantModifier) == constantModifier;
if (isConstant)
return fMarkConstantOccurrences;
else
return fMarkFieldOccurrences;
}
return fMarkLocalVariableypeOccurrences;
}
return false;
}
}