/*******************************************************************************
* Copyright (c) 2000, 2010 IBM Corporation and others.
* 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.imp.editor.internal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.imp.editor.EditorUtility;
import org.eclipse.imp.editor.UniversalEditor;
import org.eclipse.imp.editor.hover.ProblemLocation;
import org.eclipse.imp.editor.internal.quickfix.MarkerResolutionProposal;
import org.eclipse.imp.editor.quickfix.IAnnotation;
import org.eclipse.imp.language.Language;
import org.eclipse.imp.language.ServiceFactory;
import org.eclipse.imp.model.ICompilationUnit;
import org.eclipse.imp.model.ModelFactory;
import org.eclipse.imp.services.IQuickFixAssistant;
import org.eclipse.imp.services.IQuickFixInvocationContext;
import org.eclipse.imp.services.base.DefaultQuickFixAssistant;
import org.eclipse.imp.utils.AnnotationUtils;
import org.eclipse.imp.utils.MarkerUtils;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext;
import org.eclipse.jface.text.quickassist.IQuickAssistProcessor;
import org.eclipse.jface.text.quickassist.QuickAssistAssistant;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IMarkerResolution;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.texteditor.MarkerAnnotation;
import org.eclipse.ui.texteditor.SimpleMarkerAnnotation;
public class QuickFixController extends QuickAssistAssistant implements IQuickAssistProcessor {
private IQuickFixAssistant fAssistant;
private ICompilationUnit fCU;
public QuickFixController(IMarker marker) {
this(MarkerUtils.getLanguage(marker), null);
IFileEditorInput input = MarkerUtils.getInput(marker);
if (input != null) {
fCU = ModelFactory.open(input.getFile(), EditorUtility.getSourceProject(input));
}
}
public QuickFixController(UniversalEditor editor) {
this(editor.getLanguage(), null);
if (editor.getEditorInput() instanceof FileEditorInput) {
FileEditorInput input = (FileEditorInput) editor.getEditorInput();
fCU = ModelFactory.open(input.getFile(), EditorUtility.getSourceProject(input));
}
}
public QuickFixController(Language lang, ICompilationUnit cu) {
super();
this.fCU = cu;
setQuickAssistProcessor(this);
if (lang != null) {
fAssistant = ServiceFactory.getInstance().getQuickFixAssistant(lang);
}
if (fAssistant == null) {
fAssistant = new DefaultQuickFixAssistant();
}
}
public IQuickFixInvocationContext getContext(IQuickAssistInvocationContext quickAssistContext) {
return new DefaultQuickFixInvocationContext(quickAssistContext, fCU);
}
public String getErrorMessage() {
return null;
}
@Override
public boolean canFix(Annotation annotation) {
return fAssistant.canFix(annotation);
}
@Override
public boolean canAssist(IQuickAssistInvocationContext quickAssistContext) {
return fAssistant.canAssist(getContext(quickAssistContext));
}
public boolean canFix(IMarker marker) throws CoreException {
for (String type : fAssistant.getSupportedMarkerTypes()) {
if (marker.getType().equals(type)) {
MarkerAnnotation ma = new MarkerAnnotation(marker);
return fAssistant.canFix(ma);
}
}
return false;
}
public void collectProposals(IQuickFixInvocationContext context,
IAnnotationModel model, Collection<Annotation> annotations,
boolean addQuickFixes, boolean addQuickAssists,
Collection<ICompletionProposal> proposals) {
ArrayList<ProblemLocation> problems = new ArrayList<ProblemLocation>();
// collect problem locations and corrections from marker annotations
for (Annotation curr : annotations) {
ProblemLocation problemLocation = null;
if (curr instanceof IAnnotation) {
problemLocation = getProblemLocation((IAnnotation) curr, model);
if (problemLocation != null) {
problems.add(problemLocation);
}
}
if (problemLocation == null && addQuickFixes
&& curr instanceof SimpleMarkerAnnotation) {
collectMarkerProposals((SimpleMarkerAnnotation) curr, proposals);
}
}
ProblemLocation[] problemLocations =
(ProblemLocation[]) problems.toArray(new ProblemLocation[problems.size()]);
if (addQuickFixes) {
collectCorrections(context, problemLocations, proposals);
}
if (addQuickAssists) {
collectAssists(context, problemLocations, proposals);
}
}
private static ProblemLocation getProblemLocation(IAnnotation annotation, IAnnotationModel model) {
int problemId = annotation.getId();
if (problemId != -1) {
Position pos = model.getPosition((Annotation) annotation);
if (pos != null) {
return new ProblemLocation(pos.getOffset(), pos.getLength(),
annotation); // java problems all handled by the quick
// assist processors
}
}
return null;
}
public static void collectAssists(IQuickAssistInvocationContext context,
ProblemLocation[] locations, Collection<ICompletionProposal> proposals) {
return;
}
private static void collectMarkerProposals(SimpleMarkerAnnotation annotation, Collection<ICompletionProposal> proposals) {
IMarker marker = annotation.getMarker();
IMarkerResolution[] res = IDE.getMarkerHelpRegistry().getResolutions(marker);
if (res.length > 0) {
for (int i = 0; i < res.length; i++) {
proposals.add(new MarkerResolutionProposal(res[i], marker));
}
}
}
public ICompletionProposal[] computeQuickAssistProposals(IQuickAssistInvocationContext quickAssistContext) {
ArrayList<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>();
ISourceViewer viewer = quickAssistContext.getSourceViewer();
collectProposals(getContext(quickAssistContext), AnnotationUtils
.getAnnotationModel(viewer),
AnnotationUtils.getAnnotationsForOffset(viewer,
quickAssistContext.getOffset()), true, true, proposals);
return proposals.toArray(new ICompletionProposal[proposals.size()]);
}
private static class DefaultQuickFixInvocationContext implements
IQuickFixInvocationContext {
private IQuickAssistInvocationContext context;
private ICompilationUnit model;
public DefaultQuickFixInvocationContext(
IQuickAssistInvocationContext context, ICompilationUnit model) {
this.context = context;
this.model = model;
}
public int getLength() {
return context.getLength();
}
public int getOffset() {
return context.getOffset();
}
public ISourceViewer getSourceViewer() {
return context.getSourceViewer();
}
public ICompilationUnit getModel() {
return model;
}
}
/*
* (non-Javadoc)
*
* @see
* IAssistProcessor#getCorrections(org.eclipse.jdt.internal.ui.text.correction
* .IAssistContext,
* org.eclipse.jdt.internal.ui.text.correction.IProblemLocation[])
*/
public void collectCorrections(IQuickAssistInvocationContext quickAssistContext,
ProblemLocation[] locations, Collection<ICompletionProposal> proposals) {
if (locations == null || locations.length == 0) {
return;
}
HashSet<Integer> handledProblems = new HashSet<Integer>(locations.length);
for (int i = 0; i < locations.length; i++) {
ProblemLocation curr = locations[i];
Integer id = new Integer(curr.getProblemId());
if (handledProblems.add(id)) {
fAssistant.addProposals(getContext(quickAssistContext), curr,
proposals);
}
}
}
}