KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > debug > ui > display > DisplayCompletionProcessor


1 /*******************************************************************************
2  * Copyright (c) 2000, 2005 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.debug.ui.display;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.Arrays JavaDoc;
15 import java.util.Iterator JavaDoc;
16 import java.util.List JavaDoc;
17
18 import org.eclipse.core.resources.IResource;
19 import org.eclipse.core.runtime.CoreException;
20 import org.eclipse.core.runtime.IAdaptable;
21 import org.eclipse.core.runtime.IPath;
22 import org.eclipse.core.runtime.Path;
23 import org.eclipse.debug.core.DebugException;
24 import org.eclipse.debug.core.ILaunch;
25 import org.eclipse.debug.core.model.ISourceLocator;
26 import org.eclipse.debug.core.model.IStackFrame;
27 import org.eclipse.debug.core.model.IVariable;
28 import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector;
29 import org.eclipse.debug.ui.DebugUITools;
30 import org.eclipse.jdt.core.IClassFile;
31 import org.eclipse.jdt.core.ICompilationUnit;
32 import org.eclipse.jdt.core.IJavaElement;
33 import org.eclipse.jdt.core.IJavaProject;
34 import org.eclipse.jdt.core.IType;
35 import org.eclipse.jdt.core.JavaCore;
36 import org.eclipse.jdt.core.JavaModelException;
37 import org.eclipse.jdt.debug.core.IJavaStackFrame;
38 import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin;
39 import org.eclipse.jdt.internal.ui.JavaPlugin;
40 import org.eclipse.jdt.internal.ui.text.java.JavaParameterListValidator;
41 import org.eclipse.jdt.internal.ui.text.template.contentassist.TemplateEngine;
42 import org.eclipse.jdt.internal.ui.text.template.contentassist.TemplateProposal;
43 import org.eclipse.jdt.ui.text.java.CompletionProposalCollector;
44 import org.eclipse.jdt.ui.text.java.CompletionProposalComparator;
45 import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal;
46 import org.eclipse.jface.dialogs.ErrorDialog;
47 import org.eclipse.jface.text.BadLocationException;
48 import org.eclipse.jface.text.Document;
49 import org.eclipse.jface.text.IDocument;
50 import org.eclipse.jface.text.ITextSelection;
51 import org.eclipse.jface.text.ITextViewer;
52 import org.eclipse.jface.text.contentassist.ICompletionProposal;
53 import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
54 import org.eclipse.jface.text.contentassist.IContextInformation;
55 import org.eclipse.jface.text.contentassist.IContextInformationValidator;
56 import org.eclipse.jface.text.templates.TemplateContextType;
57 import org.eclipse.swt.widgets.Shell;
58
59 import com.sun.jdi.ClassNotLoadedException;
60
61 /**
62  * Display snippet completion processor.
63  */

64 public class DisplayCompletionProcessor implements IContentAssistProcessor {
65         
66     private CompletionProposalCollector fCollector;
67     private IContextInformationValidator fValidator;
68     private TemplateEngine fTemplateEngine;
69     private String JavaDoc fErrorMessage = null;
70     
71     private char[] fProposalAutoActivationSet;
72     private CompletionProposalComparator fComparator;
73         
74     public DisplayCompletionProcessor() {
75         TemplateContextType contextType= JavaPlugin.getDefault().getTemplateContextRegistry().getContextType("java"); //$NON-NLS-1$
76
if (contextType != null) {
77             fTemplateEngine= new TemplateEngine(contextType);
78         }
79         fComparator= new CompletionProposalComparator();
80     }
81     
82     /**
83      * @see IContentAssistProcessor#getErrorMessage()
84      */

85     public String JavaDoc getErrorMessage() {
86         if (fErrorMessage != null) {
87             return fErrorMessage;
88         }
89         if (fCollector != null) {
90             return fCollector.getErrorMessage();
91         }
92         return null;
93     }
94     
95     /**
96      * Sets the error message for why completions could not be resolved.
97      * Clients should clear this before computing completions.
98      *
99      * @param string message
100      */

101     protected void setErrorMessage(String JavaDoc string) {
102         if (string != null && string.length() == 0) {
103             string = null;
104         }
105         fErrorMessage = string;
106     }
107
108     /**
109      * @see IContentAssistProcessor#getContextInformationValidator()
110      */

111     public IContextInformationValidator getContextInformationValidator() {
112         if (fValidator == null) {
113             fValidator= new JavaParameterListValidator();
114         }
115         return fValidator;
116     }
117
118     /**
119      * @see IContentAssistProcessor#getContextInformationAutoActivationCharacters()
120      */

121     public char[] getContextInformationAutoActivationCharacters() {
122         return null;
123     }
124
125     /**
126      * @see IContentAssistProcessor#computeContextInformation(ITextViewer, int)
127      */

128     public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) {
129         return null;
130     }
131     
132     /**
133      * @see IContentAssistProcessor#computeProposals(ITextViewer, int)
134      */

135     public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int documentOffset) {
136         try {
137             setErrorMessage(DisplayMessages.DisplayCompletionProcessor_0); //$NON-NLS-1$
138
IAdaptable context = DebugUITools.getDebugContext();
139             if (context == null) {
140                 return new ICompletionProposal[0];
141             }
142             
143             IJavaStackFrame stackFrame= (IJavaStackFrame)context.getAdapter(IJavaStackFrame.class);
144             if (stackFrame == null) {
145                 return new ICompletionProposal[0];
146             }
147             setErrorMessage(null);
148             return computeCompletionProposals(stackFrame, viewer, documentOffset);
149         } finally {
150             releaseCollector();
151         }
152     }
153
154     protected ICompletionProposal[] computeCompletionProposals(IJavaStackFrame stackFrame, ITextViewer viewer, int documentOffset) {
155         setErrorMessage(null);
156         try {
157             IType receivingType = resolveType(stackFrame.getLaunch(), stackFrame.getReceivingTypeName(), getReceivingSourcePath(stackFrame));
158             if (receivingType == null) {
159                 setErrorMessage(DisplayMessages.DisplayCompletionProcessor_1); //$NON-NLS-1$
160
return new ICompletionProposal[0];
161             }
162             IJavaProject project = receivingType.getJavaProject();
163                 
164             IVariable[] variables= stackFrame.getLocalVariables();
165             char[][][] res= resolveLocalVariables(variables);
166             char[][] localVariableNames= res[0];
167             char[][] localVariableTypeNames= res[1];
168             
169             ITextSelection selection= (ITextSelection)viewer.getSelectionProvider().getSelection();
170             configureResultCollector(project, selection);
171             
172             int[] localModifiers= new int[localVariableNames.length];
173             Arrays.fill(localModifiers, 0);
174             
175             int insertionPosition = computeInsertionPosition(receivingType, stackFrame);
176             
177             receivingType.codeComplete(viewer.getDocument().get().toCharArray(), insertionPosition, documentOffset,
178                  localVariableTypeNames, localVariableNames,
179                  localModifiers, stackFrame.isStatic(), fCollector);
180             
181             IJavaCompletionProposal[] results= fCollector.getJavaCompletionProposals();
182             
183             if (fTemplateEngine != null) {
184                 fTemplateEngine.reset();
185                 fTemplateEngine.complete(viewer, documentOffset, null);
186                 TemplateProposal[] templateResults= fTemplateEngine.getResults();
187
188                 // concatenate arrays
189
IJavaCompletionProposal[] total= new IJavaCompletionProposal[results.length + templateResults.length];
190                 System.arraycopy(templateResults, 0, total, 0, templateResults.length);
191                 System.arraycopy(results, 0, total, templateResults.length, results.length);
192                 results= total;
193             }
194              //Order here and not in result collector to make sure that the order
195
//applies to all proposals and not just those of the compilation unit.
196
return order(results);
197         } catch (JavaModelException x) {
198             handle(viewer, x);
199         } catch (DebugException de) {
200             handle(viewer, de);
201         }
202         
203         return null;
204     }
205
206     protected int computeInsertionPosition(IType receivingType, IJavaStackFrame stackFrame) throws JavaModelException, DebugException {
207         int insertion = -1;
208         if (!receivingType.isBinary() && receivingType.getDeclaringType() == null) {
209             ICompilationUnit stackCU= getCompilationUnit(stackFrame);
210             ICompilationUnit typeCU= receivingType.getCompilationUnit();
211             if (typeCU != null && typeCU.equals(stackCU)) {
212                 if (stackCU != null) {
213                     IDocument doc = new Document(stackCU.getSource());
214                     try {
215                         insertion = doc.getLineOffset(stackFrame.getLineNumber() - 1);
216                     } catch(BadLocationException e) {
217                         JDIDebugUIPlugin.log(e);
218                     }
219                 }
220             }
221         }
222         return insertion;
223     }
224     
225     /**
226      * Returns the compliation unit associated with this
227      * Java stack frame. Returns <code>null</code> for a binary stack
228      * frame.
229      */

230     protected ICompilationUnit getCompilationUnit(IJavaStackFrame stackFrame) {
231         // Get the corresponding element.
232
ILaunch launch = stackFrame.getLaunch();
233         if (launch == null) {
234             return null;
235         }
236         ISourceLocator locator= launch.getSourceLocator();
237         if (locator == null) {
238             return null;
239         }
240         Object JavaDoc sourceElement= locator.getSourceElement(stackFrame);
241         if (sourceElement instanceof IType) {
242             return ((IType)sourceElement).getCompilationUnit();
243         }
244         if (sourceElement instanceof ICompilationUnit) {
245             return (ICompilationUnit)sourceElement;
246         }
247         return null;
248     }
249     
250     protected void handle(ITextViewer viewer, CoreException x) {
251         Shell shell= viewer.getTextWidget().getShell();
252         ErrorDialog.openError(shell,
253             DisplayMessages.DisplayCompletionProcessor_Problems_during_completion_1, //$NON-NLS-1$
254
DisplayMessages.DisplayCompletionProcessor_An_exception_occurred_during_code_completion_2, //$NON-NLS-1$
255
x.getStatus());
256         JDIDebugUIPlugin.log(x);
257     }
258     
259     protected char[][][] resolveLocalVariables(IVariable[] variables) throws DebugException {
260         List JavaDoc localVariableNames= new ArrayList JavaDoc();
261         List JavaDoc localVariableTypeNames= new ArrayList JavaDoc();
262         for (int i = 0; i < variables.length; i++) {
263             IVariable variable = variables[i];
264             try {
265                 localVariableTypeNames.add(getTranslatedTypeName(variable.getReferenceTypeName()).toCharArray());
266                 localVariableNames.add(variable.getName().toCharArray());
267             } catch (DebugException e) {
268                 // do not throw ClassNotLoadedException
269
// nothing we can do, just ignore this local variable
270
if (!(e.getStatus().getException() instanceof ClassNotLoadedException)) {
271                     throw e;
272                 }
273             }
274         }
275         char[][] names= new char[localVariableNames.size()][];
276         int i= 0;
277         for (Iterator JavaDoc iter= localVariableNames.iterator(); iter.hasNext();) {
278             names[i++]= (char[]) iter.next();
279         }
280         char[][] typeNames= new char[localVariableNames.size()][];
281         i= 0;
282         for (Iterator JavaDoc iter= localVariableTypeNames.iterator(); iter.hasNext();) {
283             typeNames[i++]= (char[]) iter.next();
284         }
285         return new char[][][] {names, typeNames};
286     }
287     
288     /**
289      * Returns the Java project associated with the given stack
290      * frame, or <code>null</code> if none.
291      */

292     protected IJavaProject getJavaProject(IStackFrame stackFrame) {
293         
294         // Get the corresponding element.
295
ILaunch launch = stackFrame.getLaunch();
296         if (launch == null) {
297             return null;
298         }
299         ISourceLocator locator= launch.getSourceLocator();
300         if (locator == null)
301             return null;
302         
303         Object JavaDoc sourceElement = locator.getSourceElement(stackFrame);
304         if (sourceElement instanceof IJavaElement) {
305             return ((IJavaElement) sourceElement).getJavaProject();
306         }
307         if (sourceElement instanceof IResource) {
308             IJavaProject project = JavaCore.create(((IResource)sourceElement).getProject());
309             if (project.exists()) {
310                 return project;
311             }
312         }
313         return null;
314     }
315     
316     /**
317      * Order the given proposals.
318      */

319     protected IJavaCompletionProposal[] order(IJavaCompletionProposal[] proposals) {
320         Arrays.sort(proposals, fComparator);
321         return proposals;
322     }
323     
324     /**
325      * Configures the display result collection for the current code assist session
326      */

327     protected void configureResultCollector(IJavaProject project, ITextSelection selection) {
328         fCollector = new CompletionProposalCollector(project);
329         if (selection.getLength() != 0) {
330             fCollector.setReplacementLength(selection.getLength());
331         }
332     }
333     
334     /**
335      * Returns an array of simple type names that are
336      * part of the given type's qualified name. For
337      * example, if the given name is <code>x.y.A$B</code>,
338      * an array with <code>["A", "B"]</code> is returned.
339      *
340      * @param typeName fully qualified type name
341      * @return array of nested type names
342      */

343     protected String JavaDoc[] getNestedTypeNames(String JavaDoc typeName) {
344         int index = typeName.lastIndexOf('.');
345         if (index >= 0) {
346             typeName= typeName.substring(index + 1);
347         }
348         index = typeName.indexOf('$');
349         List JavaDoc list = new ArrayList JavaDoc(1);
350         while (index >= 0) {
351             list.add(typeName.substring(0, index));
352             typeName = typeName.substring(index + 1);
353             index = typeName.indexOf('$');
354         }
355         list.add(typeName);
356         return (String JavaDoc[])list.toArray(new String JavaDoc[list.size()]);
357     }
358     
359     /**
360      * Returns a copy of the type name with '$' replaced by
361      * '.', or returns <code>null</code> if the given type
362      * name refers to an anonymous inner class.
363      *
364      * @param typeName a fully qualified type name
365      * @return a copy of the type name with '$' replaced by
366      * '.', or returns <code>null</code> if the given type
367      * name refers to an anonymous inner class.
368      */

369     protected String JavaDoc getTranslatedTypeName(String JavaDoc typeName) {
370         int index = typeName.lastIndexOf('$');
371         if (index == -1) {
372             return typeName;
373         }
374         if (index + 1 > typeName.length()) {
375             // invalid name
376
return typeName;
377         }
378         String JavaDoc last = typeName.substring(index + 1);
379         try {
380             Integer.parseInt(last);
381             return null;
382         } catch (NumberFormatException JavaDoc e) {
383             return typeName.replace('$', '.');
384         }
385     }
386
387
388     /**
389      * Returns a file name for the receiving type associated with the given
390      * stack frame.
391      *
392      * @return file name for the receiving type associated with the given
393      * stack frame
394      * @exception DebugException if:<ul>
395      * <li>A failure occurs while accessing attributes of
396      * the stack frame</li>
397      * </ul>
398      */

399     protected String JavaDoc getReceivingSourcePath(IJavaStackFrame frame) throws DebugException {
400         String JavaDoc typeName= frame.getReceivingTypeName();
401         String JavaDoc sourceName= frame.getSourceName();
402         if (sourceName == null || !typeName.equals(frame.getDeclaringTypeName())) {
403             // if there is no debug attribute or the declaring type is not the
404
// same as the receiving type, we must guess at the receiver's source
405
// file
406
int dollarIndex= typeName.indexOf('$');
407             if (dollarIndex >= 0) {
408                 typeName= typeName.substring(0, dollarIndex);
409             }
410             typeName = typeName.replace('.', IPath.SEPARATOR);
411             typeName+= ".java"; //$NON-NLS-1$
412
} else {
413             int index = typeName.lastIndexOf('.');
414             if (index >= 0) {
415                 typeName = typeName.substring(0, index + 1);
416                 typeName = typeName.replace('.', IPath.SEPARATOR);
417             } else {
418                 typeName = ""; //$NON-NLS-1$
419
}
420             typeName+=sourceName;
421         }
422         return typeName;
423     }
424     
425     /**
426      * Tells this processor to order the proposals alphabetically.
427      *
428      * @param order <code>true</code> if proposals should be ordered.
429      */

430     public void orderProposalsAlphabetically(boolean order) {
431         fComparator.setOrderAlphabetically(order);
432     }
433     
434     /**
435      * @see IContentAssistProcessor#getCompletionProposalAutoActivationCharacters()
436      */

437     public char[] getCompletionProposalAutoActivationCharacters() {
438         return fProposalAutoActivationSet;
439     }
440     
441     /**
442      * Sets this processor's set of characters triggering the activation of the
443      * completion proposal computation.
444      *
445      * @param activationSet the activation set
446      */

447     public void setCompletionProposalAutoActivationCharacters(char[] activationSet) {
448         fProposalAutoActivationSet= activationSet;
449     }
450     
451     protected CompletionProposalCollector getCollector() {
452         return fCollector;
453     }
454     
455     /**
456      * Clears reference to result proposal collector.
457      */

458     protected void releaseCollector() {
459         if (fCollector != null && fCollector.getErrorMessage().length() > 0 && fErrorMessage != null) {
460             setErrorMessage(fCollector.getErrorMessage());
461         }
462         fCollector = null;
463     }
464
465     protected void setCollector(CompletionProposalCollector collector) {
466         fCollector = collector;
467     }
468
469     protected IType getType(IJavaProject project, String JavaDoc originalTypeName, String JavaDoc typeName) throws DebugException {
470         
471         int dollarIndex= typeName.indexOf('$');
472         if (dollarIndex > 0) {
473             typeName= typeName.substring(0, dollarIndex);
474         }
475         IPath sourcePath = new Path(typeName);
476         IType type = null;
477         try {
478             IJavaElement result= project.findElement(sourcePath);
479             String JavaDoc[] typeNames = getNestedTypeNames(originalTypeName);
480             if (result != null) {
481                 if (result instanceof IClassFile) {
482                     type = ((IClassFile)result).getType();
483                 } else if (result instanceof ICompilationUnit) {
484                     type = ((ICompilationUnit)result).getType(typeNames[0]);
485                 } else if (result instanceof IType) {
486                     type = (IType)result;
487                 }
488             }
489             for (int i = 1; i < typeNames.length; i++) {
490                 String JavaDoc innerTypeName= typeNames[i];
491                 try {
492                     Integer.parseInt(innerTypeName);
493                     return type;
494                 } catch (NumberFormatException JavaDoc e) {
495                 }
496                 type = type.getType(innerTypeName);
497             }
498         } catch (JavaModelException e) {
499             throw new DebugException(e.getStatus());
500         }
501         
502         return type;
503     }
504     /**
505      * Returns the templateEngine.
506      * @return TemplateEngine
507      */

508     public TemplateEngine getTemplateEngine() {
509         return fTemplateEngine;
510     }
511
512     
513     /**
514      * Returns the type associated with the given type name and source name
515      * from the given launch, or <code>null</code> if none.
516      *
517      * @param launch the launch in which to resolve a type
518      * @param typeName fully qualified receiving type name (may include inner types)
519      * @param sourceName fully qualified name source file name containing the type
520      * @return associated Java model type or <code>null</code>
521      * @throws DebugException
522      */

523     protected IType resolveType(ILaunch launch, String JavaDoc typeName, String JavaDoc sourceName) throws DebugException {
524         ISourceLocator sourceLocator = launch.getSourceLocator();
525         if (sourceLocator != null) {
526             if (sourceLocator instanceof ISourceLookupDirector) {
527                 ISourceLookupDirector director = (ISourceLookupDirector) sourceLocator;
528                 try {
529                     Object JavaDoc[] objects = director.findSourceElements(sourceName);
530                     if (objects.length > 0) {
531                         Object JavaDoc element = objects[0];
532                         if (element instanceof IAdaptable) {
533                             IAdaptable adaptable = (IAdaptable) element;
534                             IJavaElement javaElement = (IJavaElement) adaptable.getAdapter(IJavaElement.class);
535                             if (javaElement != null) {
536                                 IType type = null;
537                                 String JavaDoc[] typeNames = getNestedTypeNames(typeName);
538                                 if (javaElement instanceof IClassFile) {
539                                     type = ((IClassFile)javaElement).getType();
540                                 } else if (javaElement instanceof ICompilationUnit) {
541                                     type = ((ICompilationUnit)javaElement).getType(typeNames[0]);
542                                 } else if (javaElement instanceof IType) {
543                                     type = (IType)javaElement;
544                                 }
545                                 if (type != null) {
546                                     for (int i = 1; i < typeNames.length; i++) {
547                                         String JavaDoc innerTypeName= typeNames[i];
548                                         try {
549                                             Integer.parseInt(innerTypeName);
550                                             return type;
551                                         } catch (NumberFormatException JavaDoc e) {
552                                         }
553                                         type = type.getType(innerTypeName);
554                                     }
555                                 }
556                                 return type;
557                             }
558                         }
559                     }
560                 } catch (CoreException e) {
561                     throw new DebugException(e.getStatus());
562                 }
563             }
564         }
565         return null;
566     }
567 }
568
Popular Tags