Java tutorial
/******************************************************************************* * Copyright (c) 2004, 2009 Tasktop Technologies 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: * Tasktop Technologies - initial API and implementation *******************************************************************************/ package org.eclipse.mylyn.internal.java.ui.editor; import java.util.ArrayList; import java.util.List; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.internal.ui.text.java.AbstractJavaCompletionProposal; import org.eclipse.jdt.internal.ui.text.java.JavaCompletionProposal; import org.eclipse.jdt.ui.text.java.IJavaCompletionProposalComputer; import org.eclipse.mylyn.commons.core.StatusHandler; import org.eclipse.mylyn.commons.ui.CommonImages; import org.eclipse.mylyn.context.core.ContextCore; import org.eclipse.mylyn.context.core.IInteractionElement; import org.eclipse.mylyn.internal.java.ui.JavaUiBridgePlugin; /** * TODO: parametrize relevance levels (requires JDT changes, bug 119063) * * @author Mik Kersten */ public class FocusedJavaProposalProcessor { /** * Range above which elements are part of the context. */ private static final int THRESHOLD_INTEREST = 10000; /** * Range for implicitly interesting element, such as method parameters. */ private static final int THRESHOLD_IMPLICIT_INTEREST = THRESHOLD_INTEREST * 2; /** * Threshold for determining which JDT proposals should be implicitly interesting. */ private static final int RELEVANCE_IMPLICIT_INTEREST_JAVA = 600; /** * Threshold for implicit interest of IJavaElement proposals. */ private static final int RELEVANCE_IMPLICIT_INTEREST_MISC = 300; private static final String IDENTIFIER_THIS = "this"; //$NON-NLS-1$ public static final String LABEL_SEPARATOR = " -------------------------------------------- "; //$NON-NLS-1$ public static final FocusedProposalSeparator PROPOSAL_SEPARATOR = new FocusedProposalSeparator(); private final List<IJavaCompletionProposalComputer> monitoredProposalComputers = new ArrayList<IJavaCompletionProposalComputer>(); private final List<IJavaCompletionProposalComputer> alreadyComputedProposals = new ArrayList<IJavaCompletionProposalComputer>(); private final List<IJavaCompletionProposalComputer> alreadyContainSeparator = new ArrayList<IJavaCompletionProposalComputer>(); private final List<IJavaCompletionProposalComputer> containsSingleInterestingProposal = new ArrayList<IJavaCompletionProposalComputer>(); private static FocusedJavaProposalProcessor INSTANCE = new FocusedJavaProposalProcessor(); private FocusedJavaProposalProcessor() { } public static FocusedJavaProposalProcessor getDefault() { return INSTANCE; } public void addMonitoredComputer(IJavaCompletionProposalComputer proposalComputer) { monitoredProposalComputers.add(proposalComputer); } @SuppressWarnings({ "unchecked", "rawtypes" }) public List projectInterestModel(IJavaCompletionProposalComputer proposalComputer, List proposals) { try { if (!ContextCore.getContextManager().isContextActive()) { return proposals; } else { boolean hasInterestingProposals = false; for (Object object : proposals) { if (object instanceof AbstractJavaCompletionProposal) { boolean foundInteresting = boostRelevanceWithInterest( (AbstractJavaCompletionProposal) object); if (!hasInterestingProposals && foundInteresting) { hasInterestingProposals = true; } } } // NOTE: this annoying state needs to be maintainted to ensure // the // separator is added only once, and not added for single // proposals if (containsSingleInterestingProposal.size() > 0 && proposals.size() > 0) { proposals.add(FocusedJavaProposalProcessor.PROPOSAL_SEPARATOR); } else if (hasInterestingProposals && alreadyContainSeparator.isEmpty()) { if (proposals.size() == 1) { containsSingleInterestingProposal.add(proposalComputer); } else { proposals.add(FocusedJavaProposalProcessor.PROPOSAL_SEPARATOR); alreadyContainSeparator.add(proposalComputer); } } alreadyComputedProposals.add(proposalComputer); if (alreadyComputedProposals.size() == monitoredProposalComputers.size()) { alreadyComputedProposals.clear(); alreadyContainSeparator.clear(); containsSingleInterestingProposal.clear(); } return proposals; } } catch (Throwable t) { StatusHandler.log(new Status(IStatus.ERROR, JavaUiBridgePlugin.ID_PLUGIN, "Failed to project interest onto propsals", t)); //$NON-NLS-1$ return proposals; } } private boolean boostRelevanceWithInterest(AbstractJavaCompletionProposal proposal) { boolean hasInteresting = false; IJavaElement javaElement = proposal.getJavaElement(); if (javaElement != null) { IInteractionElement interactionElement = ContextCore.getContextManager() .getElement(javaElement.getHandleIdentifier()); float interest = interactionElement.getInterest().getValue(); if (interest > ContextCore.getCommonContextScaling().getInteresting()) { // TODO: losing precision here, only going to one decimal place proposal.setRelevance(THRESHOLD_INTEREST + (int) (interest * 10)); hasInteresting = true; } else if (proposal.getRelevance() > RELEVANCE_IMPLICIT_INTEREST_JAVA) { proposal.setRelevance(THRESHOLD_IMPLICIT_INTEREST + proposal.getRelevance()); } } else if (isImplicitlyInteresting(proposal)) { proposal.setRelevance(THRESHOLD_IMPLICIT_INTEREST + proposal.getRelevance()); hasInteresting = true; } return hasInteresting; } public boolean isImplicitlyInteresting(AbstractJavaCompletionProposal proposal) { return proposal.getRelevance() > RELEVANCE_IMPLICIT_INTEREST_MISC && !IDENTIFIER_THIS.equals(proposal.getDisplayString()); } static class FocusedProposalSeparator extends JavaCompletionProposal { public FocusedProposalSeparator() { super("", 0, 0, CommonImages.getImage(CommonImages.SEPARATOR_LIST), LABEL_SEPARATOR, //$NON-NLS-1$ FocusedJavaProposalProcessor.THRESHOLD_INTEREST); } } }