/*******************************************************************************
* 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.wst.jsdt.ui.text.java;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.ui.IEditorPart;
import org.eclipse.wst.jsdt.core.CompletionContext;
import org.eclipse.wst.jsdt.core.CompletionProposal;
import org.eclipse.wst.jsdt.core.IJavaScriptUnit;
import org.eclipse.wst.jsdt.core.IJavaScriptElement;
import org.eclipse.wst.jsdt.core.IJavaScriptProject;
import org.eclipse.wst.jsdt.core.IType;
import org.eclipse.wst.jsdt.core.JavaScriptModelException;
import org.eclipse.wst.jsdt.internal.corext.template.java.SignatureUtil;
import org.eclipse.wst.jsdt.internal.ui.JavaScriptPlugin;
import org.eclipse.wst.jsdt.internal.ui.javaeditor.EditorUtility;
import org.eclipse.wst.jsdt.internal.ui.text.java.ContentAssistHistory.RHSHistory;
/**
* Describes the context of a content assist invocation in a JavaScript editor.
* <p>
* Clients may use but not subclass this class.
* </p>
*
*
* Provisional API: This class/interface is part of an interim API that is still under development and expected to
* change significantly before reaching stability. It is being made available at this early stage to solicit feedback
* from pioneering adopters on the understanding that any code that uses this API will almost certainly be broken
* (repeatedly) as the API evolves. */
public class JavaContentAssistInvocationContext extends ContentAssistInvocationContext {
private final IEditorPart fEditor;
private IJavaScriptUnit 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);
fEditor= editor;
}
/**
* Creates a new context.
*
* @param unit the compilation unit in <code>document</code>
*/
public JavaContentAssistInvocationContext(IJavaScriptUnit 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 IJavaScriptUnit getCompilationUnit() {
if (!fCUComputed) {
fCUComputed= true;
if (fCollector != null)
fCU= fCollector.getCompilationUnit();
else {
IJavaScriptElement je= EditorUtility.getEditorInputJavaElement(fEditor, false);
if (je instanceof IJavaScriptUnit)
fCU= (IJavaScriptUnit)je;
}
}
return fCU;
}
/**
* Returns the project of the compilation unit that content assist is invoked in,
* <code>null</code> if none.
*
* @return the current JavaScript project, possibly <code>null</code>
*/
public IJavaScriptProject getProject() {
IJavaScriptUnit unit= getCompilationUnit();
return unit == null ? null : unit.getJavaScriptProject();
}
/**
* Returns the keyword proposals that are available in this context, possibly none.
* <p>
* <strong>Note:</strong> This method may run
* {@linkplain org.eclipse.wst.jsdt.core.ICodeAssist#codeComplete(int, org.eclipse.wst.jsdt.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 org.eclipse.wst.jsdt.core.ICodeAssist#codeComplete(int, org.eclipse.wst.jsdt.core.CompletionRequestor) codeComplete}
* on the compilation unit.
* </p>
*
* @return the core completion context if available, <code>null</code> otherwise
*/
public CompletionContext getCoreContext() {
if (fCoreContext == null) {
// use the context from the existing collector if it exists, retrieve one ourselves otherwise
if (fCollector != null)
fCoreContext= fCollector.getContext();
if (fCoreContext == null)
computeKeywordsAndContext();
}
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 org.eclipse.wst.jsdt.core.ICodeAssist#codeComplete(int, org.eclipse.wst.jsdt.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= JavaScriptPlugin.getDefault().getContentAssistHistory().getHistory(expected);
}
}
if (fRHSHistory == null)
fRHSHistory= JavaScriptPlugin.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 org.eclipse.wst.jsdt.core.ICodeAssist#codeComplete(int, org.eclipse.wst.jsdt.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) {
IJavaScriptProject project= getCompilationUnit().getJavaScriptProject();
if (project != null) {
try {
fType= project.findType(SignatureUtil.stripSignatureToFQN(String.valueOf(expectedTypes[0])));
} catch (JavaScriptModelException x) {
JavaScriptPlugin.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
*/
protected 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.
*
*
*/
private void computeKeywordsAndContext() {
IJavaScriptUnit cu= getCompilationUnit();
if (cu == null) {
if (fKeywordProposals == null)
fKeywordProposals= new IJavaCompletionProposal[0];
return;
}
CompletionProposalCollector collector= new CompletionProposalCollector(cu);
collector.setIgnored(CompletionProposal.KEYWORD, false);
collector.setIgnored(CompletionProposal.ANONYMOUS_CLASS_DECLARATION, true);
collector.setIgnored(CompletionProposal.FIELD_REF, true);
collector.setIgnored(CompletionProposal.LABEL_REF, true);
collector.setIgnored(CompletionProposal.LOCAL_VARIABLE_REF, true);
collector.setIgnored(CompletionProposal.METHOD_DECLARATION, true);
collector.setIgnored(CompletionProposal.METHOD_NAME_REFERENCE, true);
collector.setIgnored(CompletionProposal.METHOD_REF, true);
collector.setIgnored(CompletionProposal.PACKAGE_REF, true);
collector.setIgnored(CompletionProposal.POTENTIAL_METHOD_DECLARATION, true);
collector.setIgnored(CompletionProposal.VARIABLE_DECLARATION, true);
collector.setIgnored(CompletionProposal.JSDOC_BLOCK_TAG, true);
collector.setIgnored(CompletionProposal.JSDOC_FIELD_REF, true);
collector.setIgnored(CompletionProposal.JSDOC_INLINE_TAG, true);
collector.setIgnored(CompletionProposal.JSDOC_METHOD_REF, true);
collector.setIgnored(CompletionProposal.JSDOC_PARAM_REF, true);
collector.setIgnored(CompletionProposal.JSDOC_TYPE_REF, true);
collector.setIgnored(CompletionProposal.TYPE_REF, true);
try {
cu.codeComplete(getInvocationOffset(), collector);
if (fCoreContext == null)
fCoreContext= collector.getContext();
if (fKeywordProposals == null)
fKeywordProposals= collector.getKeywordCompletionProposals();
if (fLabelProvider == null)
fLabelProvider= collector.getLabelProvider();
} catch (JavaScriptModelException x) {
JavaScriptPlugin.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.
*/
}