001: /*******************************************************************************
002: * Copyright (c) 2006, 2007 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.pde.internal.ui.editor.contentassist;
011:
012: import java.util.Arrays;
013: import java.util.Collection;
014: import java.util.Comparator;
015:
016: import org.eclipse.core.resources.IProject;
017: import org.eclipse.core.runtime.CoreException;
018: import org.eclipse.core.runtime.NullProgressMonitor;
019: import org.eclipse.jdt.core.CompletionProposal;
020: import org.eclipse.jdt.core.CompletionRequestor;
021: import org.eclipse.jdt.core.Flags;
022: import org.eclipse.jdt.core.IBuffer;
023: import org.eclipse.jdt.core.ICompilationUnit;
024: import org.eclipse.jdt.core.IJavaElement;
025: import org.eclipse.jdt.core.IPackageFragment;
026: import org.eclipse.jdt.core.IPackageFragmentRoot;
027: import org.eclipse.jdt.core.JavaCore;
028: import org.eclipse.jdt.core.JavaModelException;
029: import org.eclipse.jdt.core.search.IJavaSearchConstants;
030: import org.eclipse.jdt.core.search.IJavaSearchScope;
031: import org.eclipse.jdt.core.search.SearchEngine;
032: import org.eclipse.jdt.core.search.SearchPattern;
033: import org.eclipse.jdt.core.search.TypeNameRequestor;
034: import org.eclipse.jface.text.ITextViewer;
035: import org.eclipse.jface.text.contentassist.ICompletionProposal;
036: import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
037: import org.eclipse.jface.text.contentassist.IContextInformation;
038: import org.eclipse.jface.text.contentassist.IContextInformationValidator;
039: import org.eclipse.pde.internal.core.util.PDEJavaHelper;
040: import org.eclipse.pde.internal.ui.PDEPluginImages;
041: import org.eclipse.swt.graphics.Image;
042:
043: public abstract class TypePackageCompletionProcessor implements
044: IContentAssistProcessor {
045:
046: private String fErrorMessage;
047: private SearchEngine fSearchEngine;
048: private Comparator fComparator;
049:
050: abstract class ProposalGenerator {
051: abstract protected ICompletionProposal generateClassCompletion(
052: String pName, String cName, boolean isClass);
053:
054: abstract protected ICompletionProposal generatePackageCompletion(
055: String pName);
056: }
057:
058: public TypePackageCompletionProcessor() {
059: fSearchEngine = new SearchEngine();
060: }
061:
062: public ICompletionProposal[] computeCompletionProposals(
063: ITextViewer viewer, int offset) {
064: return null;
065: }
066:
067: public IContextInformation[] computeContextInformation(
068: ITextViewer viewer, int offset) {
069: return null;
070: }
071:
072: public char[] getCompletionProposalAutoActivationCharacters() {
073: return null;
074: }
075:
076: public char[] getContextInformationAutoActivationCharacters() {
077: return null;
078: }
079:
080: public IContextInformationValidator getContextInformationValidator() {
081: return null;
082: }
083:
084: public String getErrorMessage() {
085: return fErrorMessage;
086: }
087:
088: protected void generateTypePackageProposals(String currentContent,
089: IProject project, Collection c, int startOffset,
090: int typeScope) {
091: generateTypePackageProposals(currentContent, project, c,
092: startOffset, typeScope, false);
093: }
094:
095: protected void generateTypePackageProposals(String currentContent,
096: IProject project, Collection c, int startOffset,
097: int typeScope, boolean replaceEntireContents) {
098: currentContent = removeLeadingSpaces(currentContent);
099: if (c == null || currentContent.length() == 0)
100: return;
101: int length = (replaceEntireContents) ? -1 : currentContent
102: .length();
103: generateProposals(currentContent, project, c, startOffset,
104: length, typeScope);
105: }
106:
107: private void generateProposals(String currentContent,
108: IProject project, final Collection c,
109: final int startOffset, final int length, final int typeScope) {
110: try {
111: ICompilationUnit unit = getWorkingCopy(project);
112: if (unit == null) {
113: generateTypeProposals(currentContent, project, c,
114: startOffset, length, 1);
115: return;
116: }
117: IBuffer buff = unit.getBuffer();
118: buff.setContents("class Dummy2 { " + currentContent); //$NON-NLS-1$
119: CompletionRequestor req = new CompletionRequestor() {
120:
121: public void accept(CompletionProposal proposal) {
122: if (proposal.getKind() == CompletionProposal.PACKAGE_REF) {
123: String pkgName = new String(proposal
124: .getCompletion());
125: addProposalToCollection(
126: c,
127: startOffset,
128: length,
129: pkgName,
130: pkgName,
131: PDEPluginImages
132: .get(PDEPluginImages.OBJ_DESC_PACKAGE));
133: } else {
134: boolean isInterface = Flags
135: .isInterface(proposal.getFlags());
136: String completion = new String(proposal
137: .getCompletion());
138: if (isInterface
139: && typeScope == IJavaSearchConstants.CLASS
140: || (!isInterface && typeScope == IJavaSearchConstants.INTERFACE)
141: || completion.equals("Dummy2")) //$NON-NLS-1$
142: // don't want Dummy class showing up as option.
143: return;
144: int period = completion.lastIndexOf('.');
145: String cName = null, pName = null;
146: if (period == -1) {
147: cName = completion;
148: } else {
149: cName = completion.substring(period + 1);
150: pName = completion.substring(0, period);
151: }
152: Image image = isInterface ? PDEPluginImages
153: .get(PDEPluginImages.OBJ_DESC_GENERATE_INTERFACE)
154: : PDEPluginImages
155: .get(PDEPluginImages.OBJ_DESC_GENERATE_CLASS);
156: addProposalToCollection(c, startOffset, length,
157: cName + " - " + pName, //$NON-NLS-1$
158: completion, image);
159: }
160: }
161:
162: };
163: for (int i = 1; i <= 20; i++)
164: if (i != CompletionProposal.PACKAGE_REF
165: && i != CompletionProposal.TYPE_REF) // ignore everything but class and package references
166: req.setIgnored(i, true);
167: unit.codeComplete(15 + currentContent.length(), req);
168: unit.discardWorkingCopy();
169: } catch (JavaModelException e) {
170: }
171: }
172:
173: private ICompilationUnit getWorkingCopy(IProject project)
174: throws JavaModelException {
175: IPackageFragmentRoot[] roots = JavaCore.create(project)
176: .getPackageFragmentRoots();
177: if (roots.length > 0) {
178: IPackageFragment frag = null;
179: for (int i = 0; i < roots.length; i++)
180: if (roots[i].getKind() == IPackageFragmentRoot.K_SOURCE
181: || project.equals(roots[i]
182: .getCorrespondingResource())
183: || (roots[i].isArchive() && !roots[i]
184: .isExternal())) {
185: IJavaElement[] elems = roots[i].getChildren();
186: if ((elems.length > 0) && (i < elems.length)
187: && (elems[i] instanceof IPackageFragment)) {
188: frag = (IPackageFragment) elems[i];
189: break;
190: }
191: }
192: if (frag != null)
193: return frag
194: .getCompilationUnit("Dummy2.java").getWorkingCopy(new NullProgressMonitor()); //$NON-NLS-1$
195: }
196: return null;
197: }
198:
199: protected void generateTypeProposals(String currentContent,
200: IProject project, final Collection c,
201: final int startOffset, final int length, int typeScope) {
202: // Dynamically adjust the search scope depending on the current
203: // state of the project
204: IJavaSearchScope scope = PDEJavaHelper.getSearchScope(project);
205: char[] packageName = null;
206: char[] typeName = null;
207: int index = currentContent.lastIndexOf('.');
208:
209: if (index == -1) {
210: // There is no package qualification
211: // Perform the search only on the type name
212: typeName = currentContent.toCharArray();
213: } else if ((index + 1) == currentContent.length()) {
214: // There is a package qualification and the last character is a
215: // dot
216: // Perform the search for all types under the given package
217: // Pattern for all types
218: typeName = "".toCharArray(); //$NON-NLS-1$
219: // Package name without the trailing dot
220: packageName = currentContent.substring(0, index)
221: .toCharArray();
222: } else {
223: // There is a package qualification, followed by a dot, and
224: // a type fragment
225: // Type name without the package qualification
226: typeName = currentContent.substring(index + 1)
227: .toCharArray();
228: // Package name without the trailing dot
229: packageName = currentContent.substring(0, index)
230: .toCharArray();
231: }
232:
233: try {
234: TypeNameRequestor req = new TypeNameRequestor() {
235: public void acceptType(int modifiers,
236: char[] packageName, char[] simpleTypeName,
237: char[][] enclosingTypeNames, String path) {
238: // Accept search results from the JDT SearchEngine
239: String cName = new String(simpleTypeName);
240: String pName = new String(packageName);
241: String label = cName + " - " + pName; //$NON-NLS-1$
242: String content = pName + "." + cName; //$NON-NLS-1$
243: Image image = (Flags.isInterface(modifiers)) ? PDEPluginImages
244: .get(PDEPluginImages.OBJ_DESC_GENERATE_CLASS)
245: : PDEPluginImages
246: .get(PDEPluginImages.OBJ_DESC_GENERATE_CLASS);
247: addProposalToCollection(c, startOffset, length,
248: label, content, image);
249: }
250: };
251: // Note: Do not use the search() method, its performance is
252: // bad compared to the searchAllTypeNames() method
253: fSearchEngine.searchAllTypeNames(packageName,
254: SearchPattern.R_EXACT_MATCH, typeName,
255: SearchPattern.R_PREFIX_MATCH, typeScope, scope,
256: req,
257: IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH,
258: null);
259: } catch (CoreException e) {
260: fErrorMessage = e.getMessage();
261: }
262: }
263:
264: public void sortCompletions(ICompletionProposal[] proposals) {
265: Arrays.sort(proposals, getComparator());
266: }
267:
268: private Comparator getComparator() {
269: if (fComparator == null) {
270: fComparator = new Comparator() {
271: /* (non-Javadoc)
272: * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
273: */
274: public int compare(Object arg0, Object arg1) {
275: ICompletionProposal p1 = (ICompletionProposal) arg0;
276: ICompletionProposal p2 = (ICompletionProposal) arg1;
277:
278: return getSortKey(p1).compareToIgnoreCase(
279: getSortKey(p2));
280: }
281:
282: protected String getSortKey(ICompletionProposal p) {
283: return p.getDisplayString();
284: }
285: };
286: }
287: return fComparator;
288: }
289:
290: protected final String removeLeadingSpaces(String value) {
291: char[] valueArray = value.toCharArray();
292: int i = 0;
293: for (; i < valueArray.length; i++)
294: if (!Character.isWhitespace(valueArray[i]))
295: break;
296: return (i == valueArray.length) ? "" : new String(valueArray, i, valueArray.length - i); //$NON-NLS-1$
297: }
298:
299: /**
300: * @param c
301: * @param startOffset
302: * @param length
303: * @param label
304: * @param content
305: * @param image
306: */
307: protected void addProposalToCollection(final Collection c,
308: final int startOffset, final int length, String label,
309: String content, Image image) {
310: TypeCompletionProposal proposal = new TypeCompletionProposal(
311: content, image, label, startOffset, length);
312: c.add(proposal);
313: }
314:
315: }
|