new version with WorkingCopy Management
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / ui / StandardJavaElementContentProvider.java
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/StandardJavaElementContentProvider.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/StandardJavaElementContentProvider.java
new file mode 100644 (file)
index 0000000..21b7dc1
--- /dev/null
@@ -0,0 +1,449 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpdt.ui;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import net.sourceforge.phpdt.core.ICompilationUnit;
+import net.sourceforge.phpdt.core.IJavaElement;
+import net.sourceforge.phpdt.core.IJavaElementDelta;
+import net.sourceforge.phpdt.core.IJavaModel;
+import net.sourceforge.phpdt.core.IJavaProject;
+import net.sourceforge.phpdt.core.IPackageFragment;
+import net.sourceforge.phpdt.core.IPackageFragmentRoot;
+import net.sourceforge.phpdt.core.IParent;
+import net.sourceforge.phpdt.core.ISourceReference;
+import net.sourceforge.phpdt.core.JavaModelException;
+import net.sourceforge.phpdt.internal.corext.util.JavaModelUtil;
+import net.sourceforge.phpeclipse.PHPCore;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+
+/**
+ * A base content provider for Java elements. It provides access to the
+ * Java element hierarchy without listening to changes in the Java model.
+ * If updating the presentation on Java model change is required than 
+ * clients have to subclass, listen to Java model changes and have to update
+ * the UI using corresponding methods provided by the JFace viewers or their 
+ * own UI presentation.
+ * <p>
+ * The following Java element hierarchy is surfaced by this content provider:
+ * <p>
+ * <pre>
+Java model (<code>IJavaModel</code>)
+   Java project (<code>IJavaProject</code>)
+      package fragment root (<code>IPackageFragmentRoot</code>)
+         package fragment (<code>IPackageFragment</code>)
+            compilation unit (<code>ICompilationUnit</code>)
+            binary class file (<code>IClassFile</code>)
+ * </pre>
+ * </p>                        
+ * <p>
+ * Note that when the entire Java project is declared to be package fragment root,
+ * the corresponding package fragment root element that normally appears between the
+ * Java project and the package fragments is automatically filtered out.
+ * </p>
+ * This content provider can optionally return working copy elements for members 
+ * below compilation units. If enabled, working copy members are returned for those
+ * compilation units in the Java element hierarchy for which a shared working copy exists 
+ * in JDT core.
+ * 
+ * @see org.eclipse.jdt.ui.IWorkingCopyProvider
+ * @see JavaCore#getSharedWorkingCopies(org.eclipse.jdt.core.IBufferFactory)
+ * 
+ * @since 2.0
+ */
+public class StandardJavaElementContentProvider implements ITreeContentProvider, IWorkingCopyProvider {
+
+       protected static final Object[] NO_CHILDREN= new Object[0];
+
+       protected boolean fProvideMembers= false;
+       protected boolean fProvideWorkingCopy= false;
+       
+       /**
+        * Creates a new content provider. The content provider does not
+        * provide members of compilation units or class files and it does 
+        * not provide working copy elements.
+        */     
+       public StandardJavaElementContentProvider() {
+       }
+       
+       /**
+        * Creates a new <code>StandardJavaElementContentProvider</code>.
+        *
+        * @param provideMembers if <code>true</code> members below compilation units 
+        * and class files are provided. 
+        * @param provideWorkingCopy if <code>true</code> the element provider provides
+        * working copies members of compilation units which have an associated working 
+        * copy in JDT core. Otherwise only original elements are provided.
+        */
+       public StandardJavaElementContentProvider(boolean provideMembers, boolean provideWorkingCopy) {
+               fProvideMembers= provideMembers;
+               fProvideWorkingCopy= provideWorkingCopy;
+       }
+       
+       /**
+        * Returns whether members are provided when asking
+        * for a compilation units or class file for its children.
+        * 
+        * @return <code>true</code> if the content provider provides members; 
+        * otherwise <code>false</code> is returned
+        */
+       public boolean getProvideMembers() {
+               return fProvideMembers;
+       }
+
+       /**
+        * Sets whether the content provider is supposed to return members
+        * when asking a compilation unit or class file for its children.
+        * 
+        * @param b if <code>true</code> then members are provided. 
+        * If <code>false</code> compilation units and class files are the
+        * leaves provided by this content provider.
+        */
+       public void setProvideMembers(boolean b) {
+               fProvideMembers= b;
+       }
+       
+       /**
+        * Returns whether the provided members are from a working
+        * copy or the original compilation unit. 
+        * 
+        * @return <code>true</code> if the content provider provides
+        * working copy members; otherwise <code>false</code> is
+        * returned
+        * 
+        * @see #setProvideWorkingCopy(boolean)
+        */
+       public boolean getProvideWorkingCopy() {
+               return fProvideWorkingCopy;
+       }
+
+       /**
+        * Sets whether the members are provided from a shared working copy 
+        * that exists for a original compilation unit in the Java element hierarchy.
+        * 
+        * @param b if <code>true</code> members are provided from a 
+        * working copy if one exists in JDT core. If <code>false</code> the 
+        * provider always returns original elements.
+        */
+       public void setProvideWorkingCopy(boolean b) {
+               fProvideWorkingCopy= b;
+       }
+
+       /* (non-Javadoc)
+        * @see IWorkingCopyProvider#providesWorkingCopies()
+        */
+       public boolean providesWorkingCopies() {
+               return fProvideWorkingCopy;
+       }
+
+       /* (non-Javadoc)
+        * Method declared on IStructuredContentProvider.
+        */
+       public Object[] getElements(Object parent) {
+               return getChildren(parent);
+       }
+       
+       /* (non-Javadoc)
+        * Method declared on IContentProvider.
+        */
+       public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+       }
+
+       /* (non-Javadoc)
+        * Method declared on IContentProvider.
+        */
+       public void dispose() {
+       }
+
+       /* (non-Javadoc)
+        * Method declared on ITreeContentProvider.
+        */
+       public Object[] getChildren(Object element) {
+               if (!exists(element))
+                       return NO_CHILDREN;
+                       
+               try {
+                       if (element instanceof IJavaModel) 
+                               return getJavaProjects((IJavaModel)element);
+                       
+//                     if (element instanceof IJavaProject) 
+//                             return getPackageFragmentRoots((IJavaProject)element);
+//                     
+                       if (element instanceof IPackageFragmentRoot) 
+                               return getPackageFragments((IPackageFragmentRoot)element);
+                       
+//                     if (element instanceof IPackageFragment) 
+//                             return getPackageContents((IPackageFragment)element);
+                               
+                       if (element instanceof IFolder)
+                               return getResources((IFolder)element);
+                       
+                       if (fProvideMembers && element instanceof ISourceReference && element instanceof IParent) {
+                               if (fProvideWorkingCopy && element instanceof ICompilationUnit) {
+                                       element= JavaModelUtil.toWorkingCopy((ICompilationUnit) element);
+                               }
+                               return ((IParent)element).getChildren();
+                       }
+               } catch (JavaModelException e) {
+                       return NO_CHILDREN;
+               }               
+               return NO_CHILDREN;     
+       }
+
+       /* (non-Javadoc)
+        * @see ITreeContentProvider
+        */
+       public boolean hasChildren(Object element) {
+               if (fProvideMembers) {
+                       // assume CUs and class files are never empty
+                       if (element instanceof ICompilationUnit ){
+//                             ||
+//                             element instanceof IClassFile) {
+                               return true;
+                       }
+               } else {
+                       // don't allow to drill down into a compilation unit or class file
+                       if (element instanceof ICompilationUnit ||
+//                             element instanceof IClassFile ||
+                               element instanceof IFile)
+                       return false;
+               }
+                       
+               if (element instanceof IJavaProject) {
+                       IJavaProject jp= (IJavaProject)element;
+                       if (!jp.getProject().isOpen()) {
+                               return false;
+                       }       
+               }
+               
+               if (element instanceof IParent) {
+                       try {
+                               // when we have Java children return true, else we fetch all the children
+                               if (((IParent)element).hasChildren())
+                                       return true;
+                       } catch(JavaModelException e) {
+                               return true;
+                       }
+               }
+               Object[] children= getChildren(element);
+               return (children != null) && children.length > 0;
+       }
+        
+       /* (non-Javadoc)
+        * Method declared on ITreeContentProvider.
+        */
+       public Object getParent(Object element) {
+               if (!exists(element))
+                       return null;
+               return internalGetParent(element);                      
+       }
+       
+       private Object[] getPackageFragments(IPackageFragmentRoot root) throws JavaModelException {
+               IJavaElement[] fragments= root.getChildren();
+//             Object[] nonJavaResources= root.getNonJavaResources();
+//             if (nonJavaResources == null)
+                       return fragments;
+//             return concatenate(fragments, nonJavaResources);
+       }
+       
+       /**
+        * Note: This method is for internal use only. Clients should not call this method.
+        */
+//     protected Object[] getPackageFragmentRoots(IJavaProject project) throws JavaModelException {
+//             if (!project.getProject().isOpen())
+//                     return NO_CHILDREN;
+//                     
+//             IPackageFragmentRoot[] roots= project.getPackageFragmentRoots();
+//             List list= new ArrayList(roots.length);
+//             // filter out package fragments that correspond to projects and
+//             // replace them with the package fragments directly
+//             for (int i= 0; i < roots.length; i++) {
+//                     IPackageFragmentRoot root= (IPackageFragmentRoot)roots[i];
+//                     if (isProjectPackageFragmentRoot(root)) {
+//                             Object[] children= root.getChildren();
+//                             for (int k= 0; k < children.length; k++) 
+//                                     list.add(children[k]);
+//                     }
+//                     else if (hasChildren(root)) {
+//                             list.add(root);
+//                     } 
+//             }
+//             return concatenate(list.toArray(), project.getNonJavaResources());
+//     }
+
+       /**
+        * Note: This method is for internal use only. Clients should not call this method.
+        */
+       protected Object[] getJavaProjects(IJavaModel jm) throws JavaModelException {
+               return jm.getJavaProjects();
+       }
+       
+//     private Object[] getPackageContents(IPackageFragment fragment) throws JavaModelException {
+//             if (fragment.getKind() == IPackageFragmentRoot.K_SOURCE) {
+//                     return concatenate(fragment.getCompilationUnits(), fragment.getNonJavaResources());
+//             }
+//             return concatenate(fragment.getClassFiles(), fragment.getNonJavaResources());
+//     }
+               
+       private Object[] getResources(IFolder folder) {
+               try {
+                       // filter out folders that are package fragment roots
+                       Object[] members= folder.members();
+                       List nonJavaResources= new ArrayList();
+                       for (int i= 0; i < members.length; i++) {
+                               Object o= members[i];
+                               // A folder can also be a package fragement root in the following case
+                               // Project
+                               //  + src <- source folder
+                               //    + excluded <- excluded from class path
+                               //      + included  <- a new source folder.
+                               // Included is a member of excluded, but since it is rendered as a source
+                               // folder we have to exclude it as a normal child.
+                               if (o instanceof IFolder) {
+                                       IJavaElement element= PHPCore.create((IFolder)o);
+                                       if (element instanceof IPackageFragmentRoot && element.exists()) {
+                                               continue;
+                                       }
+                               }
+                               nonJavaResources.add(o);
+                       }
+                       return nonJavaResources.toArray();
+               } catch(CoreException e) {
+                       return NO_CHILDREN;
+               }
+       }
+       
+       /**
+        * Note: This method is for internal use only. Clients should not call this method.
+        */
+       protected boolean isClassPathChange(IJavaElementDelta delta) {
+               
+               // need to test the flags only for package fragment roots
+               if (delta.getElement().getElementType() != IJavaElement.PACKAGE_FRAGMENT_ROOT)
+                       return false;
+               
+               int flags= delta.getFlags();
+               return (delta.getKind() == IJavaElementDelta.CHANGED && 
+                       ((flags & IJavaElementDelta.F_ADDED_TO_CLASSPATH) != 0) ||
+                        ((flags & IJavaElementDelta.F_REMOVED_FROM_CLASSPATH) != 0) ||
+                        ((flags & IJavaElementDelta.F_REORDER) != 0));
+       }
+       
+       /**
+        * Note: This method is for internal use only. Clients should not call this method.
+        */
+       protected Object skipProjectPackageFragmentRoot(IPackageFragmentRoot root) {
+               try {
+                       if (isProjectPackageFragmentRoot(root))
+                               return root.getParent(); 
+                       return root;
+               } catch(JavaModelException e) {
+                       return root;
+               }
+       }
+       
+       /**
+        * Note: This method is for internal use only. Clients should not call this method.
+        */
+       protected boolean isPackageFragmentEmpty(IJavaElement element) throws JavaModelException {
+               if (element instanceof IPackageFragment) {
+                       IPackageFragment fragment= (IPackageFragment)element;
+                       if (!(fragment.hasChildren() ) )
+//                     || 
+//                     fragment.getNonJavaResources().length > 0) && fragment.hasSubpackages()) 
+                               return true;
+               }
+               return false;
+       }
+
+       /**
+        * Note: This method is for internal use only. Clients should not call this method.
+        */
+       protected boolean isProjectPackageFragmentRoot(IPackageFragmentRoot root) throws JavaModelException {
+               IResource resource= root.getResource();
+               return (resource instanceof IProject);
+       }
+       
+       /**
+        * Note: This method is for internal use only. Clients should not call this method.
+        */
+       protected boolean exists(Object element) {
+               if (element == null) {
+                       return false;
+               }
+               if (element instanceof IResource) {
+                       return ((IResource)element).exists();
+               }
+               if (element instanceof IJavaElement) {
+                       return ((IJavaElement)element).exists();
+               }
+               return true;
+       }
+       
+       /**
+        * Note: This method is for internal use only. Clients should not call this method.
+        */
+       protected Object internalGetParent(Object element) {
+               if (element instanceof IJavaProject) {
+                       return ((IJavaProject)element).getJavaModel();
+               }
+               // try to map resources to the containing package fragment
+               if (element instanceof IResource) {
+                       IResource parent= ((IResource)element).getParent();
+                       IJavaElement jParent= PHPCore.create(parent);
+                       // http://bugs.eclipse.org/bugs/show_bug.cgi?id=31374
+                       if (jParent != null && jParent.exists()) 
+                               return jParent;
+                       return parent;
+               }
+
+               // for package fragments that are contained in a project package fragment
+               // we have to skip the package fragment root as the parent.
+               if (element instanceof IPackageFragment) {
+                       IPackageFragmentRoot parent= (IPackageFragmentRoot)((IPackageFragment)element).getParent();
+                       return skipProjectPackageFragmentRoot(parent);
+               }
+               if (element instanceof IJavaElement) {
+                       IJavaElement candidate= ((IJavaElement)element).getParent();
+                       // If the parent is a CU we might have shown working copy elements below CU level. If so
+                       // return the original element instead of the working copy.
+                       if (candidate != null && candidate.getElementType() == IJavaElement.COMPILATION_UNIT) {
+                               candidate= JavaModelUtil.toOriginal((ICompilationUnit) candidate);
+                       }
+                       return candidate;
+               }
+               return null;
+       }
+       
+       /**
+        * Note: This method is for internal use only. Clients should not call this method.
+        */
+       protected static Object[] concatenate(Object[] a1, Object[] a2) {
+               int a1Len= a1.length;
+               int a2Len= a2.length;
+               Object[] res= new Object[a1Len + a2Len];
+               System.arraycopy(a1, 0, res, 0, a1Len);
+               System.arraycopy(a2, 0, res, a1Len, a2Len); 
+               return res;
+       }
+
+
+}