/*******************************************************************************
* Copyright (c) 2007, 2008 Spring IDE Developers
* 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:
* Spring IDE Developers - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.mylyn.ui.editor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.internal.ui.text.java.JavaCompletionProposal;
import org.eclipse.jface.fieldassist.IContentProposal;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.text.contentassist.IContextInformationValidator;
import org.eclipse.mylyn.commons.ui.CommonImages;
import org.eclipse.mylyn.context.core.IInteractionElement;
import org.eclipse.mylyn.internal.context.core.ContextCorePlugin;
import org.eclipse.mylyn.internal.java.ui.editor.FocusedJavaProposalProcessor;
import org.eclipse.wst.sse.ui.internal.contentassist.IRelevanceCompletionProposal;
import org.eclipse.wst.xml.ui.internal.contentassist.ProposalComparator;
import org.springframework.ide.eclipse.beans.ui.editor.contentassist.BeansJavaCompletionProposal;
/**
* This {@link IContentAssistProcessor} reorders the calculated
* {@link IContentProposal} based on the current interest level of the proposed
* elements.
* <p>
* This implementation is greatly influenced by Mylyn's
* {@link FocusedJavaProposalProcessor}.
* @author Christian Dupuis
* @since 2.0.1
*/
@SuppressWarnings("restriction")
public class FocusedStructuredTextViewerContentAssistProcessor implements
IContentAssistProcessor {
static class FocusedProposalSeparator extends JavaCompletionProposal
implements IRelevanceCompletionProposal {
public FocusedProposalSeparator(int baseRelevance) {
super("", 0, 0, CommonImages.getImage(CommonImages.SEPARATOR_LIST),
LABEL_SEPARATOR, THRESHOLD_INTEREST + baseRelevance);
}
}
private static final int THRESHOLD_INTEREST = 10000;
private static final int THRESHOLD_IMPLICIT_INTEREST = THRESHOLD_INTEREST * 2;
private static final int RELEVANCE_IMPLICIT_INTEREST = 300;
private static final String IDENTIFIER_THIS = "this";
public static final String LABEL_SEPARATOR = " -------------------------------------------- ";
private final IContentAssistProcessor processor;
public FocusedStructuredTextViewerContentAssistProcessor(
IContentAssistProcessor processor) {
this.processor = processor;
}
private boolean boostRelevanceWithInterest(
BeansJavaCompletionProposal proposal, int baseRelevance) {
boolean hasInteresting = false;
Object element = proposal.getProposedObject();
if (element != null) {
String handle = determineHandleForProposedElement(element);
if (handle != null) {
hasInteresting = determineRelevanceForProposedElements(
proposal, baseRelevance, handle);
}
}
else if (isImplicitlyInteresting(proposal)) {
proposal.setRelevance(THRESHOLD_IMPLICIT_INTEREST
+ proposal.getRelevance());
hasInteresting = true;
}
return hasInteresting;
}
@SuppressWarnings("unchecked")
public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer,
int offset) {
ICompletionProposal[] rawProposals = processor
.computeCompletionProposals(viewer, offset);
List<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>();
if (rawProposals != null && rawProposals.length > 0) {
proposals.addAll(Arrays.asList(rawProposals));
}
if (!ContextCorePlugin.getContextManager().isContextActive()) {
return rawProposals;
}
else {
int baseRelevance = 0;
for (Object object : proposals) {
if (object instanceof IRelevanceCompletionProposal
&& ((IRelevanceCompletionProposal) object)
.getRelevance() > baseRelevance) {
baseRelevance = ((IRelevanceCompletionProposal) object)
.getRelevance();
}
}
int foundInterestingCount = 0;
boolean hasInterestingProposals = false;
for (Object object : proposals) {
if (object instanceof BeansJavaCompletionProposal) {
boolean foundInteresting = boostRelevanceWithInterest(
(BeansJavaCompletionProposal) object, baseRelevance);
if (!hasInterestingProposals && foundInteresting) {
hasInterestingProposals = true;
}
if (foundInteresting) {
foundInterestingCount++;
}
}
}
if (hasInterestingProposals
&& proposals.size() > foundInterestingCount) {
proposals.add(new FocusedProposalSeparator(baseRelevance));
}
}
ICompletionProposal[] newProposals = proposals
.toArray(new ICompletionProposal[proposals.size()]);
Arrays.sort(newProposals, new ProposalComparator());
return newProposals;
}
public IContextInformation[] computeContextInformation(ITextViewer viewer,
int offset) {
return processor.computeContextInformation(viewer, offset);
}
protected String determineHandleForProposedElement(Object element) {
if (element != null && element instanceof IJavaElement) {
return ((IJavaElement) element).getHandleIdentifier();
}
return null;
}
private boolean determineRelevanceForProposedElements(
BeansJavaCompletionProposal proposal, int baseRelevance,
String handle) {
IInteractionElement mylynElement = ContextCorePlugin
.getContextManager().getElement(handle);
if (mylynElement.getInterest().isInteresting()) {
float interest = mylynElement.getInterest().getValue();
proposal.setRelevance(THRESHOLD_INTEREST + baseRelevance
+ (int) (interest * 10));
return true;
}
return false;
}
public char[] getCompletionProposalAutoActivationCharacters() {
return processor.getCompletionProposalAutoActivationCharacters();
}
public char[] getContextInformationAutoActivationCharacters() {
return processor.getContextInformationAutoActivationCharacters();
}
public IContextInformationValidator getContextInformationValidator() {
return processor.getContextInformationValidator();
}
public String getErrorMessage() {
return processor.getErrorMessage();
}
public boolean isImplicitlyInteresting(BeansJavaCompletionProposal proposal) {
return proposal.getRelevance() > RELEVANCE_IMPLICIT_INTEREST
&& !IDENTIFIER_THIS.equals(proposal.getDisplayString());
}
}