* Added browser like links (Ctrl+Mouseclick on identifier; same as F3 shortcut)
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / core / SearchableEnvironment.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core;
12
13 import net.sourceforge.phpdt.core.ICompilationUnit;
14 import net.sourceforge.phpdt.core.IJavaElement;
15 import net.sourceforge.phpdt.core.IJavaProject;
16 import net.sourceforge.phpdt.core.IPackageFragment;
17 import net.sourceforge.phpdt.core.IType;
18 import net.sourceforge.phpdt.core.JavaModelException;
19 import net.sourceforge.phpdt.core.WorkingCopyOwner;
20 import net.sourceforge.phpdt.core.compiler.CharOperation;
21 import net.sourceforge.phpdt.core.search.IJavaSearchConstants;
22 import net.sourceforge.phpdt.core.search.ITypeNameRequestor;
23 import net.sourceforge.phpdt.internal.codeassist.ISearchRequestor;
24 import net.sourceforge.phpdt.internal.codeassist.ISearchableNameEnvironment;
25 import net.sourceforge.phpdt.internal.compiler.env.IConstants;
26 import net.sourceforge.phpdt.internal.compiler.env.INameEnvironment;
27 import net.sourceforge.phpdt.internal.compiler.env.ISourceType;
28 import net.sourceforge.phpdt.internal.compiler.env.NameEnvironmentAnswer;
29
30 import org.eclipse.core.runtime.IProgressMonitor;
31
32 /**
33  *      This class provides a <code>SearchableBuilderEnvironment</code> for code assist which
34  *      uses the Java model as a search tool.  
35  */
36 public class SearchableEnvironment implements ISearchableNameEnvironment, IJavaSearchConstants {
37   protected NameLookup nameLookup;
38   protected ICompilationUnit unitToSkip;
39
40   protected IJavaProject project;
41   //protected IJavaSearchScope searchScope;
42
43         /**
44          * Creates a Sea
45   /**
46    * Creates a SearchableEnvironment on the given project
47    */
48   public SearchableEnvironment(IJavaProject project) throws JavaModelException {
49     this.project = project;
50     this.nameLookup = (NameLookup) ((JavaProject) project).getNameLookup();
51
52     // Create search scope with visible entry on the project's classpath
53     //          this.searchScope = SearchEngine.createJavaSearchScope(this.project.getAllPackageFragmentRoots());
54   }
55   
56         
57
58         /**
59          * Creates a SearchableEnvironment on the given project
60          */
61         public SearchableEnvironment(JavaProject project, WorkingCopyOwner owner) throws JavaModelException {
62                 this.project = project;
63                 this.nameLookup = project.newNameLookup(owner);
64
65                 // Create search scope with visible entry on the project's classpath
66 //              this.searchScope = SearchEngine.createJavaSearchScope(this.project.getAllPackageFragmentRoots());
67         }
68   /**
69    * Returns the given type in the the given package if it exists,
70    * otherwise <code>null</code>.
71    */
72   protected NameEnvironmentAnswer find(String typeName, String packageName) {
73     if (packageName == null)
74       packageName = IPackageFragment.DEFAULT_PACKAGE_NAME;
75    
76     if (this.nameLookup!=null) { // ins axelcl
77     IType type = this.nameLookup.findType(typeName, packageName, false, NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
78     if (type != null) {
79       //                        if (type instanceof BinaryType) {
80       //                                try {
81       //                                        return new NameEnvironmentAnswer(
82       //                                                (IBinaryType) ((BinaryType) type).getElementInfo());
83       //                                } catch (JavaModelException npe) {
84       //                                        return null;
85       //                                }
86       //                        } else { //SourceType
87       try {
88         // retrieve the requested type
89         SourceTypeElementInfo sourceType = (SourceTypeElementInfo) ((SourceType) type).getElementInfo();
90         ISourceType topLevelType = sourceType;
91         while (topLevelType.getEnclosingType() != null) {
92           topLevelType = topLevelType.getEnclosingType();
93         }
94         // find all siblings (other types declared in same unit, since may be used for name resolution)
95         IType[] types = sourceType.getHandle().getCompilationUnit().getTypes();
96         ISourceType[] sourceTypes = new ISourceType[types.length];
97
98         // in the resulting collection, ensure the requested type is the first one
99         sourceTypes[0] = sourceType;
100         for (int i = 0, index = 1; i < types.length; i++) {
101           ISourceType otherType = (ISourceType) ((JavaElement) types[i]).getElementInfo();
102           if (!otherType.equals(topLevelType))
103             sourceTypes[index++] = otherType;
104         }
105         return new NameEnvironmentAnswer(sourceTypes);
106       } catch (JavaModelException npe) {
107         return null;
108       }
109       //                        }
110     }
111     }
112     return null;
113   }
114
115   /**
116    * @see ISearchableNameEnvironment#findPackages(char[], ISearchRequestor)
117    */
118   public void findPackages(char[] prefix, ISearchRequestor requestor) {
119     //          this.nameLookup.seekPackageFragments(
120     //                  new String(prefix),
121     //                  true,
122     //                  new SearchableEnvironmentRequestor(requestor));
123   }
124
125   /**
126    * @see INameEnvironment#findType(char[][])
127    */
128   public NameEnvironmentAnswer findType(char[][] compoundTypeName) {
129     if (compoundTypeName == null)
130       return null;
131
132     int length = compoundTypeName.length;
133     if (length <= 1) {
134       if (length == 0)
135         return null;
136       return find(new String(compoundTypeName[0]), null);
137     }
138
139     int lengthM1 = length - 1;
140     char[][] packageName = new char[lengthM1][];
141     System.arraycopy(compoundTypeName, 0, packageName, 0, lengthM1);
142
143     return find(new String(compoundTypeName[lengthM1]), CharOperation.toString(packageName));
144   }
145
146   /**
147    * @see INameEnvironment#findType(char[], char[][])
148    */
149   public NameEnvironmentAnswer findType(char[] name, char[][] packageName) {
150     if (name == null)
151       return null;
152
153     return find(new String(name), packageName == null || packageName.length == 0 ? null : CharOperation.toString(packageName));
154   }
155
156   /**
157    * @see ISearchableNameEnvironment#findTypes(char[], ISearchRequestor)
158    */
159   public void findTypes(char[] prefix, final ISearchRequestor storage) {
160
161     /*
162         if (true){
163                 findTypes(new String(prefix), storage, NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
164                 return;         
165         }
166     */
167     //          try {
168     final String excludePath;
169     if (this.unitToSkip != null) {
170       if (!(this.unitToSkip instanceof IJavaElement)) {
171         // revert to model investigation
172         findTypes(new String(prefix), storage, NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
173         return;
174       }
175       excludePath = ((IJavaElement) this.unitToSkip).getPath().toString();
176     } else {
177       excludePath = null;
178     }
179     int lastDotIndex = CharOperation.lastIndexOf('.', prefix);
180     char[] qualification, simpleName;
181     if (lastDotIndex < 0) {
182       qualification = null;
183       simpleName = CharOperation.toLowerCase(prefix);
184     } else {
185       qualification = CharOperation.subarray(prefix, 0, lastDotIndex);
186       simpleName = CharOperation.toLowerCase(CharOperation.subarray(prefix, lastDotIndex + 1, prefix.length));
187     }
188
189     IProgressMonitor progressMonitor = new IProgressMonitor() {
190       boolean isCanceled = false;
191       public void beginTask(String name, int totalWork) {
192       }
193       public void done() {
194       }
195       public void internalWorked(double work) {
196       }
197       public boolean isCanceled() {
198         return isCanceled;
199       }
200       public void setCanceled(boolean value) {
201         isCanceled = value;
202       }
203       public void setTaskName(String name) {
204       }
205       public void subTask(String name) {
206       }
207       public void worked(int work) {
208       }
209     };
210     ITypeNameRequestor nameRequestor = new ITypeNameRequestor() {
211       public void acceptClass(char[] packageName, char[] simpleTypeName, char[][] enclosingTypeNames, String path) {
212         if (excludePath != null && excludePath.equals(path))
213           return;
214         if (enclosingTypeNames != null && enclosingTypeNames.length > 0)
215           return; // accept only top level types
216         storage.acceptClass(packageName, simpleTypeName, IConstants.AccPublic);
217       }
218       public void acceptInterface(char[] packageName, char[] simpleTypeName, char[][] enclosingTypeNames, String path) {
219         if (excludePath != null && excludePath.equals(path))
220           return;
221         if (enclosingTypeNames != null && enclosingTypeNames.length > 0)
222           return; // accept only top level types
223         storage.acceptInterface(packageName, simpleTypeName, IConstants.AccPublic);
224       }
225     };
226     //                  try {
227     //                          new SearchEngine().searchAllTypeNames(
228     //                                  this.project.getProject().getWorkspace(),
229     //                                  qualification,
230     //                                  simpleName,
231     //                                  PREFIX_MATCH,
232     //                                  CASE_INSENSITIVE,
233     //                                  IJavaSearchConstants.TYPE,
234     //                                  this.searchScope,
235     //                                  nameRequestor,
236     //                                  CANCEL_IF_NOT_READY_TO_SEARCH,
237     //                                  progressMonitor);
238     //                  } catch (OperationCanceledException e) {
239     //                          findTypes(
240     //                                  new String(prefix),
241     //                                  storage,
242     //                                  NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
243     //                  }
244     //          } catch (JavaModelException e) {
245     //                  findTypes(
246     //                          new String(prefix),
247     //                          storage,
248     //                          NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
249     //          }
250   }
251
252   /**
253    * Returns all types whose name starts with the given (qualified) <code>prefix</code>.
254    *
255    * If the <code>prefix</code> is unqualified, all types whose simple name matches
256    * the <code>prefix</code> are returned.
257    */
258   private void findTypes(String prefix, ISearchRequestor storage, int type) {
259     SearchableEnvironmentRequestor requestor = new SearchableEnvironmentRequestor(storage, this.unitToSkip);
260     int index = prefix.lastIndexOf('.');
261     if (index == -1) {
262       this.nameLookup.seekTypes(prefix, null, true, type, requestor);
263     } else {
264       String packageName = prefix.substring(0, index);
265       JavaElementRequestor elementRequestor = new JavaElementRequestor();
266       this.nameLookup.seekPackageFragments(packageName, false, elementRequestor);
267       IPackageFragment[] fragments = elementRequestor.getPackageFragments();
268       if (fragments != null) {
269         String className = prefix.substring(index + 1);
270         for (int i = 0, length = fragments.length; i < length; i++)
271           if (fragments[i] != null)
272             this.nameLookup.seekTypes(className, fragments[i], true, type, requestor);
273       }
274     }
275   }
276
277   /**
278    * @see INameEnvironment#isPackage(char[][], char[])
279    */
280   public boolean isPackage(char[][] parentPackageName, char[] subPackageName) {
281     if (subPackageName == null || CharOperation.contains('.', subPackageName))
282       return false;
283     if (parentPackageName == null || parentPackageName.length == 0)
284       return isTopLevelPackage(subPackageName);
285     for (int i = 0, length = parentPackageName.length; i < length; i++)
286       if (parentPackageName[i] == null || CharOperation.contains('.', parentPackageName[i]))
287         return false;
288
289     String packageName = new String(CharOperation.concatWith(parentPackageName, subPackageName, '.'));
290     return this.nameLookup.findPackageFragments(packageName, false) != null;
291   }
292
293   public boolean isTopLevelPackage(char[] packageName) {
294     return packageName != null
295       && !CharOperation.contains('.', packageName)
296       && this.nameLookup.findPackageFragments(new String(packageName), false) != null;
297   }
298
299   /**
300    * Returns a printable string for the array.
301    */
302   protected String toStringChar(char[] name) {
303     return "[" //$NON-NLS-1$
304     + new String(name) + "]"; //$NON-NLS-1$
305   }
306
307   /**
308    * Returns a printable string for the array.
309    */
310   protected String toStringCharChar(char[][] names) {
311     StringBuffer result = new StringBuffer();
312     for (int i = 0; i < names.length; i++) {
313       result.append(toStringChar(names[i]));
314     }
315     return result.toString();
316   }
317
318   public void cleanup() {
319   }
320 }