001: /*******************************************************************************
002: * Copyright (c) 2005, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.ui.text.java;
011:
012: import org.eclipse.core.runtime.Assert;
013:
014: import org.eclipse.jface.text.ITextViewer;
015:
016: import org.eclipse.ui.IEditorPart;
017:
018: import org.eclipse.jdt.core.CompletionContext;
019: import org.eclipse.jdt.core.CompletionProposal;
020: import org.eclipse.jdt.core.ICodeAssist;
021: import org.eclipse.jdt.core.ICompilationUnit;
022: import org.eclipse.jdt.core.IJavaElement;
023: import org.eclipse.jdt.core.IJavaProject;
024: import org.eclipse.jdt.core.IType;
025: import org.eclipse.jdt.core.JavaModelException;
026:
027: import org.eclipse.jdt.internal.corext.template.java.SignatureUtil;
028:
029: import org.eclipse.jdt.internal.ui.JavaPlugin;
030: import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility;
031: import org.eclipse.jdt.internal.ui.text.java.ContentAssistHistory.RHSHistory;
032:
033: /**
034: * Describes the context of a content assist invocation in a Java editor.
035: * <p>
036: * Clients may use but not subclass this class.
037: * </p>
038: *
039: * @since 3.2
040: */
041: public class JavaContentAssistInvocationContext extends
042: ContentAssistInvocationContext {
043: private final IEditorPart fEditor;
044:
045: private ICompilationUnit fCU = null;
046: private boolean fCUComputed = false;
047:
048: private CompletionProposalLabelProvider fLabelProvider;
049: private CompletionProposalCollector fCollector;
050: private RHSHistory fRHSHistory;
051: private IType fType;
052:
053: private IJavaCompletionProposal[] fKeywordProposals = null;
054: private CompletionContext fCoreContext = null;
055:
056: /**
057: * Creates a new context.
058: *
059: * @param viewer the viewer used by the editor
060: * @param offset the invocation offset
061: * @param editor the editor that content assist is invoked in
062: */
063: public JavaContentAssistInvocationContext(ITextViewer viewer,
064: int offset, IEditorPart editor) {
065: super (viewer, offset);
066: Assert.isNotNull(editor);
067: fEditor = editor;
068: }
069:
070: /**
071: * Creates a new context.
072: *
073: * @param unit the compilation unit in <code>document</code>
074: */
075: public JavaContentAssistInvocationContext(ICompilationUnit unit) {
076: super ();
077: fCU = unit;
078: fCUComputed = true;
079: fEditor = null;
080: }
081:
082: /**
083: * Returns the compilation unit that content assist is invoked in, <code>null</code> if there
084: * is none.
085: *
086: * @return the compilation unit that content assist is invoked in, possibly <code>null</code>
087: */
088: public ICompilationUnit getCompilationUnit() {
089: if (!fCUComputed) {
090: fCUComputed = true;
091: if (fCollector != null)
092: fCU = fCollector.getCompilationUnit();
093: else {
094: IJavaElement je = EditorUtility
095: .getEditorInputJavaElement(fEditor, false);
096: if (je instanceof ICompilationUnit)
097: fCU = (ICompilationUnit) je;
098: }
099: }
100: return fCU;
101: }
102:
103: /**
104: * Returns the project of the compilation unit that content assist is invoked in,
105: * <code>null</code> if none.
106: *
107: * @return the current java project, possibly <code>null</code>
108: */
109: public IJavaProject getProject() {
110: ICompilationUnit unit = getCompilationUnit();
111: return unit == null ? null : unit.getJavaProject();
112: }
113:
114: /**
115: * Returns the keyword proposals that are available in this context, possibly none.
116: * <p>
117: * <strong>Note:</strong> This method may run
118: * {@linkplain ICodeAssist#codeComplete(int, org.eclipse.jdt.core.CompletionRequestor) codeComplete}
119: * on the compilation unit.
120: * </p>
121: *
122: * @return the available keyword proposals
123: */
124: public IJavaCompletionProposal[] getKeywordProposals() {
125: if (fKeywordProposals == null) {
126: if (fCollector != null
127: && !fCollector
128: .isIgnored(CompletionProposal.KEYWORD)
129: && fCollector.getContext() != null) {
130: // use the existing collector if it exists, collects keywords, and has already been invoked
131: fKeywordProposals = fCollector
132: .getKeywordCompletionProposals();
133: } else {
134: // otherwise, retrieve keywords ourselves
135: computeKeywordsAndContext();
136: }
137: }
138:
139: return fKeywordProposals;
140: }
141:
142: /**
143: * Returns the {@link CompletionContext core completion context} if available, <code>null</code>
144: * otherwise.
145: * <p>
146: * <strong>Note:</strong> This method may run
147: * {@linkplain ICodeAssist#codeComplete(int, org.eclipse.jdt.core.CompletionRequestor) codeComplete}
148: * on the compilation unit.
149: * </p>
150: *
151: * @return the core completion context if available, <code>null</code> otherwise
152: */
153: public CompletionContext getCoreContext() {
154: if (fCoreContext == null) {
155: // use the context from the existing collector if it exists, retrieve one ourselves otherwise
156: if (fCollector != null)
157: fCoreContext = fCollector.getContext();
158: if (fCoreContext == null)
159: computeKeywordsAndContext();
160: }
161: return fCoreContext;
162: }
163:
164: /**
165: * Returns an float in [0.0, 1.0] based on whether the type has been recently used as a
166: * right hand side for the type expected in the current context. 0 signals that the
167: * <code>qualifiedTypeName</code> does not match the expected type, while 1.0 signals that
168: * <code>qualifiedTypeName</code> has most recently been used in a similar context.
169: * <p>
170: * <strong>Note:</strong> This method may run
171: * {@linkplain ICodeAssist#codeComplete(int, org.eclipse.jdt.core.CompletionRequestor) codeComplete}
172: * on the compilation unit.
173: * </p>
174: *
175: * @param qualifiedTypeName the type name of the type of interest
176: * @return a relevance in [0.0, 1.0] based on previous content assist invocations
177: */
178: public float getHistoryRelevance(String qualifiedTypeName) {
179: return getRHSHistory().getRank(qualifiedTypeName);
180: }
181:
182: /**
183: * Returns the content assist type history for the expected type.
184: *
185: * @return the content assist type history for the expected type
186: */
187: private RHSHistory getRHSHistory() {
188: if (fRHSHistory == null) {
189: CompletionContext context = getCoreContext();
190: if (context != null) {
191: char[][] expectedTypes = context
192: .getExpectedTypesSignatures();
193: if (expectedTypes != null && expectedTypes.length > 0) {
194: String expected = SignatureUtil
195: .stripSignatureToFQN(String
196: .valueOf(expectedTypes[0]));
197: fRHSHistory = JavaPlugin.getDefault()
198: .getContentAssistHistory().getHistory(
199: expected);
200: }
201: }
202: if (fRHSHistory == null)
203: fRHSHistory = JavaPlugin.getDefault()
204: .getContentAssistHistory().getHistory(null);
205: }
206: return fRHSHistory;
207: }
208:
209: /**
210: * Returns the expected type if any, <code>null</code> otherwise.
211: * <p>
212: * <strong>Note:</strong> This method may run
213: * {@linkplain ICodeAssist#codeComplete(int, org.eclipse.jdt.core.CompletionRequestor) codeComplete}
214: * on the compilation unit.
215: * </p>
216: *
217: * @return the expected type if any, <code>null</code> otherwise
218: */
219: public IType getExpectedType() {
220: if (fType == null && getCompilationUnit() != null) {
221: CompletionContext context = getCoreContext();
222: if (context != null) {
223: char[][] expectedTypes = context
224: .getExpectedTypesSignatures();
225: if (expectedTypes != null && expectedTypes.length > 0) {
226: IJavaProject project = getCompilationUnit()
227: .getJavaProject();
228: if (project != null) {
229: try {
230: fType = project
231: .findType(SignatureUtil
232: .stripSignatureToFQN(String
233: .valueOf(expectedTypes[0])));
234: } catch (JavaModelException x) {
235: JavaPlugin.log(x);
236: }
237: }
238: }
239: }
240: }
241: return fType;
242: }
243:
244: /**
245: * Returns a label provider that can be used to compute proposal labels.
246: *
247: * @return a label provider that can be used to compute proposal labels
248: */
249: public CompletionProposalLabelProvider getLabelProvider() {
250: if (fLabelProvider == null) {
251: if (fCollector != null)
252: fLabelProvider = fCollector.getLabelProvider();
253: else
254: fLabelProvider = new CompletionProposalLabelProvider();
255: }
256:
257: return fLabelProvider;
258: }
259:
260: /**
261: * Sets the collector, which is used to access the compilation unit, the core context and the
262: * label provider. This is a performance optimization: {@link IJavaCompletionProposalComputer}s
263: * may instantiate a {@link CompletionProposalCollector} and set this invocation context via
264: * {@link CompletionProposalCollector#setInvocationContext(JavaContentAssistInvocationContext)},
265: * which in turn calls this method. This allows the invocation context to retrieve the core
266: * context and keyword proposals from the existing collector, instead of computing theses values
267: * itself via {@link #computeKeywordsAndContext()}.
268: *
269: * @param collector the collector
270: */
271: void setCollector(CompletionProposalCollector collector) {
272: fCollector = collector;
273: }
274:
275: /**
276: * Fallback to retrieve a core context and keyword proposals when no collector is available.
277: * Runs code completion on the cu and collects keyword proposals. {@link #fKeywordProposals} is
278: * non-<code>null</code> after this call.
279: *
280: * @since 3.3
281: */
282: private void computeKeywordsAndContext() {
283: ICompilationUnit cu = getCompilationUnit();
284: if (cu == null) {
285: if (fKeywordProposals == null)
286: fKeywordProposals = new IJavaCompletionProposal[0];
287: return;
288: }
289:
290: CompletionProposalCollector collector = new CompletionProposalCollector(
291: cu);
292: collector.setIgnored(CompletionProposal.KEYWORD, false);
293: collector.setIgnored(
294: CompletionProposal.ANNOTATION_ATTRIBUTE_REF, true);
295: collector.setIgnored(
296: CompletionProposal.ANONYMOUS_CLASS_DECLARATION, true);
297: collector.setIgnored(CompletionProposal.FIELD_REF, true);
298: collector.setIgnored(CompletionProposal.LABEL_REF, true);
299: collector.setIgnored(CompletionProposal.LOCAL_VARIABLE_REF,
300: true);
301: collector.setIgnored(CompletionProposal.METHOD_DECLARATION,
302: true);
303: collector.setIgnored(CompletionProposal.METHOD_NAME_REFERENCE,
304: true);
305: collector.setIgnored(CompletionProposal.METHOD_REF, true);
306: collector.setIgnored(CompletionProposal.PACKAGE_REF, true);
307: collector.setIgnored(
308: CompletionProposal.POTENTIAL_METHOD_DECLARATION, true);
309: collector.setIgnored(CompletionProposal.VARIABLE_DECLARATION,
310: true);
311: collector
312: .setIgnored(CompletionProposal.JAVADOC_BLOCK_TAG, true);
313: collector
314: .setIgnored(CompletionProposal.JAVADOC_FIELD_REF, true);
315: collector.setIgnored(CompletionProposal.JAVADOC_INLINE_TAG,
316: true);
317: collector.setIgnored(CompletionProposal.JAVADOC_METHOD_REF,
318: true);
319: collector
320: .setIgnored(CompletionProposal.JAVADOC_PARAM_REF, true);
321: collector.setIgnored(CompletionProposal.JAVADOC_TYPE_REF, true);
322: collector
323: .setIgnored(CompletionProposal.JAVADOC_VALUE_REF, true);
324: collector.setIgnored(CompletionProposal.TYPE_REF, true);
325:
326: try {
327: cu.codeComplete(getInvocationOffset(), collector);
328: if (fCoreContext == null)
329: fCoreContext = collector.getContext();
330: if (fKeywordProposals == null)
331: fKeywordProposals = collector
332: .getKeywordCompletionProposals();
333: if (fLabelProvider == null)
334: fLabelProvider = collector.getLabelProvider();
335: } catch (JavaModelException x) {
336: JavaPlugin.log(x);
337: if (fKeywordProposals == null)
338: fKeywordProposals = new IJavaCompletionProposal[0];
339: }
340: }
341:
342: /*
343: * Implementation note: There is no need to override hashCode and equals, as we only add cached
344: * values shared across one assist invocation.
345: */
346: }
|