/*******************************************************************************
* Copyright (c) 2005, 2009 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.jdt.ui.text.java;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.ui.IEditorPart;
import org.eclipse.jdt.core.CompletionContext;
import org.eclipse.jdt.core.CompletionProposal;
import org.eclipse.jdt.core.ICodeAssist;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.corext.template.java.SignatureUtil;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility;
import org.eclipse.jdt.internal.ui.text.java.ContentAssistHistory.RHSHistory;
/**
* Describes the context of a content assist invocation in a Java editor.
* <p>
* Clients may use but not subclass this class.
* </p>
*
* @since 3.2
*
* @noextend This class is not intended to be subclassed by clients.
*/
public class JavaContentAssistInvocationContext extends ContentAssistInvocationContext {
private final IEditorPart fEditor;
private ICompilationUnit fCU= null;
private boolean fCUComputed= false;
private CompletionProposalLabelProvider fLabelProvider;
private CompletionProposalCollector fCollector;
private RHSHistory fRHSHistory;
private IType fType;
private IJavaCompletionProposal[] fKeywordProposals= null;
private CompletionContext fCoreContext= null;
/**
* Creates a new context.
*
* @param viewer the viewer used by the editor
* @param offset the invocation offset
* @param editor the editor that content assist is invoked in
*/
public JavaContentAssistInvocationContext(ITextViewer viewer, int offset, IEditorPart editor) {
super(viewer, offset);
Assert.isNotNull(editor);
fEditor= editor;
}
/**
* Creates a new context.
*
* @param unit the compilation unit in <code>document</code>
*/
public JavaContentAssistInvocationContext(ICompilationUnit unit) {
super();
fCU= unit;
fCUComputed= true;
fEditor= null;
}
/**
* Returns the compilation unit that content assist is invoked in, <code>null</code> if there
* is none.
*
* @return the compilation unit that content assist is invoked in, possibly <code>null</code>
*/
public ICompilationUnit getCompilationUnit() {
if (!fCUComputed) {
fCUComputed= true;
if (fCollector != null)
fCU= fCollector.getCompilationUnit();
else {
IJavaElement je= EditorUtility.getEditorInputJavaElement(fEditor, false);
if (je instanceof ICompilationUnit)
fCU= (ICompilationUnit)je;
}
}
return fCU;
}
/**
* Returns the project of the compilation unit that content assist is invoked in,
* <code>null</code> if none.
*
* @return the current java project, possibly <code>null</code>
*/
public IJavaProject getProject() {
ICompilationUnit unit= getCompilationUnit();
return unit == null ? null : unit.getJavaProject();
}
/**
* Returns the keyword proposals that are available in this context, possibly none.
* <p>
* <strong>Note:</strong> This method may run
* {@linkplain ICodeAssist#codeComplete(int, org.eclipse.jdt.core.CompletionRequestor) codeComplete}
* on the compilation unit.
* </p>
*
* @return the available keyword proposals
*/
public IJavaCompletionProposal[] getKeywordProposals() {
if (fKeywordProposals == null) {
if (fCollector != null && !fCollector.isIgnored(CompletionProposal.KEYWORD) && fCollector.getContext() != null) {
// use the existing collector if it exists, collects keywords, and has already been invoked
fKeywordProposals= fCollector.getKeywordCompletionProposals();
} else {
// otherwise, retrieve keywords ourselves
computeKeywordsAndContext();
}
}
return fKeywordProposals;
}
/**
* Returns the {@link CompletionContext core completion context} if available, <code>null</code>
* otherwise.
* <p>
* <strong>Note:</strong> This method may run
* {@linkplain ICodeAssist#codeComplete(int, org.eclipse.jdt.core.CompletionRequestor) codeComplete}
* on the compilation unit.
* </p>
*
* @return the core completion context if available, <code>null</code> otherwise
*/
public CompletionContext getCoreContext() {
if (fCollector != null) {
CompletionContext context= fCollector.getContext();
if (context != null) {
if (fCoreContext == null)
fCoreContext= context;
return context;
}
}
if (fCoreContext == null)
computeKeywordsAndContext(); // Retrieve the context ourselves
return fCoreContext;
}
/**
* Returns an float in [0.0, 1.0] based on whether the type has been recently used as a
* right hand side for the type expected in the current context. 0 signals that the
* <code>qualifiedTypeName</code> does not match the expected type, while 1.0 signals that
* <code>qualifiedTypeName</code> has most recently been used in a similar context.
* <p>
* <strong>Note:</strong> This method may run
* {@linkplain ICodeAssist#codeComplete(int, org.eclipse.jdt.core.CompletionRequestor) codeComplete}
* on the compilation unit.
* </p>
*
* @param qualifiedTypeName the type name of the type of interest
* @return a relevance in [0.0, 1.0] based on previous content assist invocations
*/
public float getHistoryRelevance(String qualifiedTypeName) {
return getRHSHistory().getRank(qualifiedTypeName);
}
/**
* Returns the content assist type history for the expected type.
*
* @return the content assist type history for the expected type
*/
private RHSHistory getRHSHistory() {
if (fRHSHistory == null) {
CompletionContext context= getCoreContext();
if (context != null) {
char[][] expectedTypes= context.getExpectedTypesSignatures();
if (expectedTypes != null && expectedTypes.length > 0) {
String expected= SignatureUtil.stripSignatureToFQN(String.valueOf(expectedTypes[0]));
fRHSHistory= JavaPlugin.getDefault().getContentAssistHistory().getHistory(expected);
}
}
if (fRHSHistory == null)
fRHSHistory= JavaPlugin.getDefault().getContentAssistHistory().getHistory(null);
}
return fRHSHistory;
}
/**
* Returns the expected type if any, <code>null</code> otherwise.
* <p>
* <strong>Note:</strong> This method may run
* {@linkplain ICodeAssist#codeComplete(int, org.eclipse.jdt.core.CompletionRequestor) codeComplete}
* on the compilation unit.
* </p>
*
* @return the expected type if any, <code>null</code> otherwise
*/
public IType getExpectedType() {
if (fType == null && getCompilationUnit() != null) {
CompletionContext context= getCoreContext();
if (context != null) {
char[][] expectedTypes= context.getExpectedTypesSignatures();
if (expectedTypes != null && expectedTypes.length > 0) {
IJavaProject project= getCompilationUnit().getJavaProject();
if (project != null) {
try {
fType= project.findType(SignatureUtil.stripSignatureToFQN(String.valueOf(expectedTypes[0])));
} catch (JavaModelException x) {
JavaPlugin.log(x);
}
}
}
}
}
return fType;
}
/**
* Returns a label provider that can be used to compute proposal labels.
*
* @return a label provider that can be used to compute proposal labels
*/
public CompletionProposalLabelProvider getLabelProvider() {
if (fLabelProvider == null) {
if (fCollector != null)
fLabelProvider= fCollector.getLabelProvider();
else
fLabelProvider= new CompletionProposalLabelProvider();
}
return fLabelProvider;
}
/**
* Sets the collector, which is used to access the compilation unit, the core context and the
* label provider. This is a performance optimization: {@link IJavaCompletionProposalComputer}s
* may instantiate a {@link CompletionProposalCollector} and set this invocation context via
* {@link CompletionProposalCollector#setInvocationContext(JavaContentAssistInvocationContext)},
* which in turn calls this method. This allows the invocation context to retrieve the core
* context and keyword proposals from the existing collector, instead of computing theses values
* itself via {@link #computeKeywordsAndContext()}.
*
* @param collector the collector
*/
void setCollector(CompletionProposalCollector collector) {
fCollector= collector;
}
/**
* Fallback to retrieve a core context and keyword proposals when no collector is available.
* Runs code completion on the cu and collects keyword proposals. {@link #fKeywordProposals} is
* non-<code>null</code> after this call.
*
* @since 3.3
*/
private void computeKeywordsAndContext() {
ICompilationUnit cu= getCompilationUnit();
if (cu == null) {
if (fKeywordProposals == null)
fKeywordProposals= new IJavaCompletionProposal[0];
return;
}
CompletionProposalCollector collector= new CompletionProposalCollector(cu, true);
collector.setIgnored(CompletionProposal.KEYWORD, false);
try {
cu.codeComplete(getInvocationOffset(), collector);
if (fCoreContext == null)
fCoreContext= collector.getContext();
if (fKeywordProposals == null)
fKeywordProposals= collector.getKeywordCompletionProposals();
if (fLabelProvider == null)
fLabelProvider= collector.getLabelProvider();
} catch (JavaModelException x) {
if (!x.isDoesNotExist() || cu.getJavaProject() == null || cu.getJavaProject().isOnClasspath(cu))
JavaPlugin.log(x);
if (fKeywordProposals == null)
fKeywordProposals= new IJavaCompletionProposal[0];
}
}
/*
* Implementation note: There is no need to override hashCode and equals, as we only add cached
* values shared across one assist invocation.
*/
}