avoid NullPointerException in debug
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / ui / StandardJavaElementContentProvider.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.ui;
12
13 import java.util.ArrayList;
14 import java.util.List;
15
16 import net.sourceforge.phpdt.core.ICompilationUnit;
17 import net.sourceforge.phpdt.core.IJavaElement;
18 import net.sourceforge.phpdt.core.IJavaElementDelta;
19 import net.sourceforge.phpdt.core.IJavaModel;
20 import net.sourceforge.phpdt.core.IJavaProject;
21 import net.sourceforge.phpdt.core.IPackageFragment;
22 import net.sourceforge.phpdt.core.IPackageFragmentRoot;
23 import net.sourceforge.phpdt.core.IParent;
24 import net.sourceforge.phpdt.core.ISourceReference;
25 import net.sourceforge.phpdt.core.JavaCore;
26 import net.sourceforge.phpdt.core.JavaModelException;
27 import net.sourceforge.phpdt.internal.corext.util.JavaModelUtil;
28
29 import org.eclipse.core.resources.IFile;
30 import org.eclipse.core.resources.IFolder;
31 import org.eclipse.core.resources.IProject;
32 import org.eclipse.core.resources.IResource;
33 import org.eclipse.core.runtime.CoreException;
34 import org.eclipse.jface.viewers.ITreeContentProvider;
35 import org.eclipse.jface.viewers.Viewer;
36
37  
38 /**
39  * A base content provider for Java elements. It provides access to the
40  * Java element hierarchy without listening to changes in the Java model.
41  * If updating the presentation on Java model change is required than 
42  * clients have to subclass, listen to Java model changes and have to update
43  * the UI using corresponding methods provided by the JFace viewers or their 
44  * own UI presentation.
45  * <p>
46  * The following Java element hierarchy is surfaced by this content provider:
47  * <p>
48  * <pre>
49 Java model (<code>IJavaModel</code>)
50    Java project (<code>IJavaProject</code>)
51       package fragment root (<code>IPackageFragmentRoot</code>)
52          package fragment (<code>IPackageFragment</code>)
53             compilation unit (<code>ICompilationUnit</code>)
54             binary class file (<code>IClassFile</code>)
55  * </pre>
56  * </p>                         
57  * <p>
58  * Note that when the entire Java project is declared to be package fragment root,
59  * the corresponding package fragment root element that normally appears between the
60  * Java project and the package fragments is automatically filtered out.
61  * </p>
62  * This content provider can optionally return working copy elements for members 
63  * below compilation units. If enabled, working copy members are returned for those
64  * compilation units in the Java element hierarchy for which a shared working copy exists 
65  * in JDT core.
66  * 
67  * @see net.sourceforge.phpdt.ui.IWorkingCopyProvider
68  * @see JavaCore#getSharedWorkingCopies(net.sourceforge.phpdt.core.IBufferFactory)
69  * 
70  * @since 2.0
71  */
72 public class StandardJavaElementContentProvider implements ITreeContentProvider, IWorkingCopyProvider {
73
74         protected static final Object[] NO_CHILDREN= new Object[0];
75
76         protected boolean fProvideMembers= false;
77         protected boolean fProvideWorkingCopy= false;
78         
79         /**
80          * Creates a new content provider. The content provider does not
81          * provide members of compilation units or class files and it does 
82          * not provide working copy elements.
83          */     
84         public StandardJavaElementContentProvider() {
85         }
86         
87         /**
88          * Creates a new <code>StandardJavaElementContentProvider</code>.
89          *
90          * @param provideMembers if <code>true</code> members below compilation units 
91          * and class files are provided. 
92          * @param provideWorkingCopy if <code>true</code> the element provider provides
93          * working copies members of compilation units which have an associated working 
94          * copy in JDT core. Otherwise only original elements are provided.
95          */
96         public StandardJavaElementContentProvider(boolean provideMembers, boolean provideWorkingCopy) {
97                 fProvideMembers= provideMembers;
98                 fProvideWorkingCopy= provideWorkingCopy;
99         }
100         
101         /**
102          * Returns whether members are provided when asking
103          * for a compilation units or class file for its children.
104          * 
105          * @return <code>true</code> if the content provider provides members; 
106          * otherwise <code>false</code> is returned
107          */
108         public boolean getProvideMembers() {
109                 return fProvideMembers;
110         }
111
112         /**
113          * Sets whether the content provider is supposed to return members
114          * when asking a compilation unit or class file for its children.
115          * 
116          * @param b if <code>true</code> then members are provided. 
117          * If <code>false</code> compilation units and class files are the
118          * leaves provided by this content provider.
119          */
120         public void setProvideMembers(boolean b) {
121                 fProvideMembers= b;
122         }
123         
124         /**
125          * Returns whether the provided members are from a working
126          * copy or the original compilation unit. 
127          * 
128          * @return <code>true</code> if the content provider provides
129          * working copy members; otherwise <code>false</code> is
130          * returned
131          * 
132          * @see #setProvideWorkingCopy(boolean)
133          */
134         public boolean getProvideWorkingCopy() {
135                 return fProvideWorkingCopy;
136         }
137
138         /**
139          * Sets whether the members are provided from a shared working copy 
140          * that exists for a original compilation unit in the Java element hierarchy.
141          * 
142          * @param b if <code>true</code> members are provided from a 
143          * working copy if one exists in JDT core. If <code>false</code> the 
144          * provider always returns original elements.
145          */
146         public void setProvideWorkingCopy(boolean b) {
147                 fProvideWorkingCopy= b;
148         }
149
150         /* (non-Javadoc)
151          * @see IWorkingCopyProvider#providesWorkingCopies()
152          */
153         public boolean providesWorkingCopies() {
154                 return fProvideWorkingCopy;
155         }
156
157         /* (non-Javadoc)
158          * Method declared on IStructuredContentProvider.
159          */
160         public Object[] getElements(Object parent) {
161                 return getChildren(parent);
162         }
163         
164         /* (non-Javadoc)
165          * Method declared on IContentProvider.
166          */
167         public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
168         }
169
170         /* (non-Javadoc)
171          * Method declared on IContentProvider.
172          */
173         public void dispose() {
174         }
175
176         /* (non-Javadoc)
177          * Method declared on ITreeContentProvider.
178          */
179         public Object[] getChildren(Object element) {
180                 if (!exists(element))
181                         return NO_CHILDREN;
182                         
183                 try {
184                         if (element instanceof IJavaModel) 
185                                 return getJavaProjects((IJavaModel)element);
186                         
187 //                      if (element instanceof IJavaProject) 
188 //                              return getPackageFragmentRoots((IJavaProject)element);
189 //                      
190                         if (element instanceof IPackageFragmentRoot) 
191                                 return getPackageFragments((IPackageFragmentRoot)element);
192                         
193 //                      if (element instanceof IPackageFragment) 
194 //                              return getPackageContents((IPackageFragment)element);
195                                 
196                         if (element instanceof IFolder)
197                                 return getResources((IFolder)element);
198                         
199                         if (fProvideMembers && element instanceof ISourceReference && element instanceof IParent) {
200                                 if (fProvideWorkingCopy && element instanceof ICompilationUnit) {
201                                         element= JavaModelUtil.toWorkingCopy((ICompilationUnit) element);
202                                 }
203                                 return ((IParent)element).getChildren();
204                         }
205                 } catch (JavaModelException e) {
206                         return NO_CHILDREN;
207                 }               
208                 return NO_CHILDREN;     
209         }
210
211         /* (non-Javadoc)
212          * @see ITreeContentProvider
213          */
214         public boolean hasChildren(Object element) {
215                 if (fProvideMembers) {
216                         // assume CUs and class files are never empty
217                         if (element instanceof ICompilationUnit ){
218 //                              ||
219 //                              element instanceof IClassFile) {
220                                 return true;
221                         }
222                 } else {
223                         // don't allow to drill down into a compilation unit or class file
224                         if (element instanceof ICompilationUnit ||
225 //                              element instanceof IClassFile ||
226                                 element instanceof IFile)
227                         return false;
228                 }
229                         
230                 if (element instanceof IJavaProject) {
231                         IJavaProject jp= (IJavaProject)element;
232                         if (!jp.getProject().isOpen()) {
233                                 return false;
234                         }       
235                 }
236                 
237                 if (element instanceof IParent) {
238                         try {
239                                 // when we have Java children return true, else we fetch all the children
240                                 if (((IParent)element).hasChildren())
241                                         return true;
242                         } catch(JavaModelException e) {
243                                 return true;
244                         }
245                 }
246                 Object[] children= getChildren(element);
247                 return (children != null) && children.length > 0;
248         }
249          
250         /* (non-Javadoc)
251          * Method declared on ITreeContentProvider.
252          */
253         public Object getParent(Object element) {
254                 if (!exists(element))
255                         return null;
256                 return internalGetParent(element);                      
257         }
258         
259         private Object[] getPackageFragments(IPackageFragmentRoot root) throws JavaModelException {
260                 IJavaElement[] fragments= root.getChildren();
261 //              Object[] nonJavaResources= root.getNonJavaResources();
262 //              if (nonJavaResources == null)
263                         return fragments;
264 //              return concatenate(fragments, nonJavaResources);
265         }
266         
267         /**
268          * Note: This method is for internal use only. Clients should not call this method.
269          */
270 //      protected Object[] getPackageFragmentRoots(IJavaProject project) throws JavaModelException {
271 //              if (!project.getProject().isOpen())
272 //                      return NO_CHILDREN;
273 //                      
274 //              IPackageFragmentRoot[] roots= project.getPackageFragmentRoots();
275 //              List list= new ArrayList(roots.length);
276 //              // filter out package fragments that correspond to projects and
277 //              // replace them with the package fragments directly
278 //              for (int i= 0; i < roots.length; i++) {
279 //                      IPackageFragmentRoot root= (IPackageFragmentRoot)roots[i];
280 //                      if (isProjectPackageFragmentRoot(root)) {
281 //                              Object[] children= root.getChildren();
282 //                              for (int k= 0; k < children.length; k++) 
283 //                                      list.add(children[k]);
284 //                      }
285 //                      else if (hasChildren(root)) {
286 //                              list.add(root);
287 //                      } 
288 //              }
289 //              return concatenate(list.toArray(), project.getNonJavaResources());
290 //      }
291
292         /**
293          * Note: This method is for internal use only. Clients should not call this method.
294          */
295         protected Object[] getJavaProjects(IJavaModel jm) throws JavaModelException {
296                 return jm.getJavaProjects();
297         }
298         
299 //      private Object[] getPackageContents(IPackageFragment fragment) throws JavaModelException {
300 //              if (fragment.getKind() == IPackageFragmentRoot.K_SOURCE) {
301 //                      return concatenate(fragment.getCompilationUnits(), fragment.getNonJavaResources());
302 //              }
303 //              return concatenate(fragment.getClassFiles(), fragment.getNonJavaResources());
304 //      }
305                 
306         private Object[] getResources(IFolder folder) {
307                 try {
308                         // filter out folders that are package fragment roots
309                         Object[] members= folder.members();
310                         List nonJavaResources= new ArrayList();
311                         for (int i= 0; i < members.length; i++) {
312                                 Object o= members[i];
313                                 // A folder can also be a package fragement root in the following case
314                                 // Project
315                                 //  + src <- source folder
316                                 //    + excluded <- excluded from class path
317                                 //      + included  <- a new source folder.
318                                 // Included is a member of excluded, but since it is rendered as a source
319                                 // folder we have to exclude it as a normal child.
320                                 if (o instanceof IFolder) {
321                                         IJavaElement element= JavaCore.create((IFolder)o);
322                                         if (element instanceof IPackageFragmentRoot && element.exists()) {
323                                                 continue;
324                                         }
325                                 }
326                                 nonJavaResources.add(o);
327                         }
328                         return nonJavaResources.toArray();
329                 } catch(CoreException e) {
330                         return NO_CHILDREN;
331                 }
332         }
333         
334         /**
335          * Note: This method is for internal use only. Clients should not call this method.
336          */
337         protected boolean isClassPathChange(IJavaElementDelta delta) {
338                 
339                 // need to test the flags only for package fragment roots
340                 if (delta.getElement().getElementType() != IJavaElement.PACKAGE_FRAGMENT_ROOT)
341                         return false;
342                 
343                 int flags= delta.getFlags();
344                 return (delta.getKind() == IJavaElementDelta.CHANGED && 
345                         ((flags & IJavaElementDelta.F_ADDED_TO_CLASSPATH) != 0) ||
346                          ((flags & IJavaElementDelta.F_REMOVED_FROM_CLASSPATH) != 0) ||
347                          ((flags & IJavaElementDelta.F_REORDER) != 0));
348         }
349         
350         /**
351          * Note: This method is for internal use only. Clients should not call this method.
352          */
353         protected Object skipProjectPackageFragmentRoot(IPackageFragmentRoot root) {
354                 try {
355                         if (isProjectPackageFragmentRoot(root))
356                                 return root.getParent(); 
357                         return root;
358                 } catch(JavaModelException e) {
359                         return root;
360                 }
361         }
362         
363         /**
364          * Note: This method is for internal use only. Clients should not call this method.
365          */
366         protected boolean isPackageFragmentEmpty(IJavaElement element) throws JavaModelException {
367                 if (element instanceof IPackageFragment) {
368                         IPackageFragment fragment= (IPackageFragment)element;
369                         if (!(fragment.hasChildren() ) )
370 //                      || 
371 //                      fragment.getNonJavaResources().length > 0) && fragment.hasSubpackages()) 
372                                 return true;
373                 }
374                 return false;
375         }
376
377         /**
378          * Note: This method is for internal use only. Clients should not call this method.
379          */
380         protected boolean isProjectPackageFragmentRoot(IPackageFragmentRoot root) throws JavaModelException {
381                 IResource resource= root.getResource();
382                 return (resource instanceof IProject);
383         }
384         
385         /**
386          * Note: This method is for internal use only. Clients should not call this method.
387          */
388         protected boolean exists(Object element) {
389                 if (element == null) {
390                         return false;
391                 }
392                 if (element instanceof IResource) {
393                         return ((IResource)element).exists();
394                 }
395                 if (element instanceof IJavaElement) {
396                         return ((IJavaElement)element).exists();
397                 }
398                 return true;
399         }
400         
401         /**
402          * Note: This method is for internal use only. Clients should not call this method.
403          */
404         protected Object internalGetParent(Object element) {
405                 if (element instanceof IJavaProject) {
406                         return ((IJavaProject)element).getJavaModel();
407                 }
408                 // try to map resources to the containing package fragment
409                 if (element instanceof IResource) {
410                         IResource parent= ((IResource)element).getParent();
411                         IJavaElement jParent= JavaCore.create(parent);
412                         // http://bugs.eclipse.org/bugs/show_bug.cgi?id=31374
413                         if (jParent != null && jParent.exists()) 
414                                 return jParent;
415                         return parent;
416                 }
417
418                 // for package fragments that are contained in a project package fragment
419                 // we have to skip the package fragment root as the parent.
420                 if (element instanceof IPackageFragment) {
421                         IPackageFragmentRoot parent= (IPackageFragmentRoot)((IPackageFragment)element).getParent();
422                         return skipProjectPackageFragmentRoot(parent);
423                 }
424                 if (element instanceof IJavaElement) {
425                         IJavaElement candidate= ((IJavaElement)element).getParent();
426                         // If the parent is a CU we might have shown working copy elements below CU level. If so
427                         // return the original element instead of the working copy.
428                         if (candidate != null && candidate.getElementType() == IJavaElement.COMPILATION_UNIT) {
429                                 candidate= JavaModelUtil.toOriginal((ICompilationUnit) candidate);
430                         }
431                         return candidate;
432                 }
433                 return null;
434         }
435         
436         /**
437          * Note: This method is for internal use only. Clients should not call this method.
438          */
439         protected static Object[] concatenate(Object[] a1, Object[] a2) {
440                 int a1Len= a1.length;
441                 int a2Len= a2.length;
442                 Object[] res= new Object[a1Len + a2Len];
443                 System.arraycopy(a1, 0, res, 0, a1Len);
444                 System.arraycopy(a2, 0, res, a1Len, a2Len); 
445                 return res;
446         }
447
448
449 }