Parser detects wrong include files now
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / core / Openable.java
index a8ed665..d73ef9d 100644 (file)
  *******************************************************************************/
 package net.sourceforge.phpdt.internal.core;
 
+import java.text.NumberFormat;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
 import net.sourceforge.phpdt.core.BufferChangedEvent;
 import net.sourceforge.phpdt.core.IBuffer;
 import net.sourceforge.phpdt.core.IBufferChangedListener;
+import net.sourceforge.phpdt.core.IBufferFactory;
 import net.sourceforge.phpdt.core.IJavaElement;
+import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
 import net.sourceforge.phpdt.core.IOpenable;
+import net.sourceforge.phpdt.core.IPackageFragmentRoot;
+import net.sourceforge.phpdt.core.IParent;
 import net.sourceforge.phpdt.core.JavaModelException;
 
 import org.eclipse.core.resources.IContainer;
 import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.IProgressMonitor;
 
 /**
@@ -29,8 +41,8 @@ import org.eclipse.core.runtime.IProgressMonitor;
  */
 public abstract class Openable extends JavaElement implements IOpenable, IBufferChangedListener {
 
-protected Openable(int type, IJavaElement parent, String name) {
-       super(type, parent, name);
+protected Openable(JavaElement parent, String name) {
+       super(parent, name);
 }
        /**
         * The buffer associated with this element has changed. Registers
@@ -42,12 +54,25 @@ protected Openable(int type, IJavaElement parent, String name) {
         */
        public void bufferChanged(BufferChangedEvent event) {
                if (event.getBuffer().isClosed()) {
-//                     JavaModelManager.getJavaModelManager().getElementsOutOfSynchWithBuffers().remove(this);
-//                     getBufferManager().removeBuffer(event.getBuffer());
+                       JavaModelManager.getJavaModelManager().getElementsOutOfSynchWithBuffers().remove(this);
+                       getBufferManager().removeBuffer(event.getBuffer());
                } else {
-//                     JavaModelManager.getJavaModelManager().getElementsOutOfSynchWithBuffers().put(this, this);
+                       JavaModelManager.getJavaModelManager().getElementsOutOfSynchWithBuffers().put(this, this);
                }
        }       
+       
+       /**
+        * Builds this element's structure and properties in the given
+        * info object, based on this element's current contents (reuse buffer
+        * contents if this element has an open buffer, or resource contents
+        * if this element does not have an open buffer). Children
+        * are placed in the given newElements table (note, this element
+        * has already been placed in the newElements table). Returns true
+        * if successful, or false if an error is encountered while determining
+        * the structure of this element.
+        */
+       protected abstract boolean buildStructure(OpenableElementInfo info, IProgressMonitor pm, Map newElements, IResource underlyingResource) throws JavaModelException;
+
 ///**
 // * Updates the info objects for this element and all of its children by
 // * removing the current infos, generating new infos, and then placing
@@ -73,32 +98,58 @@ protected Openable(int type, IJavaElement parent, String name) {
 //     // see PR 1G2K5S7: ITPJCORE:ALL - NPE when accessing source for a binary type
 //     JavaModelManager.getJavaModelManager().putInfo(this, info);     
 //}
-///**
-// * Close the buffer associated with this element, if any.
-// */
-//protected void closeBuffer(OpenableElementInfo info) {
-//     if (!hasBuffer()) return; // nothing to do
-//     IBuffer buffer = null;
-//     buffer = getBufferManager().getBuffer(this);
-//     if (buffer != null) {
-//             buffer.close();
-//             buffer.removeBufferChangedListener(this);
-//     }
-//}
-///**
-// * This element is being closed.  Do any necessary cleanup.
-// */
-//protected void closing(Object info) throws JavaModelException {
-//     OpenableElementInfo openableInfo = (OpenableElementInfo) info;
-//     closeBuffer(openableInfo);
-//     super.closing(info);
-//}
+/*
+ * Returns whether this element can be removed from the Java model cache to make space.
+ */
+public boolean canBeRemovedFromCache() {
+       try {
+               return !hasUnsavedChanges();
+       } catch (JavaModelException e) {
+               return false;
+       }
+}
+/*
+ * Returns whether the buffer of this element can be removed from the Java model cache to make space.
+ */
+public boolean canBufferBeRemovedFromCache(IBuffer buffer) {
+       return !buffer.hasUnsavedChanges();
+}
+/**
+ * Close the buffer associated with this element, if any.
+ */
+protected void closeBuffer() {
+       if (!hasBuffer()) return; // nothing to do
+       IBuffer buffer = getBufferManager().getBuffer(this);
+       if (buffer != null) {
+               buffer.close();
+               buffer.removeBufferChangedListener(this);
+       }
+}
+/**
+ * Close the buffer associated with this element, if any.
+ */
+protected void closeBuffer(OpenableElementInfo info) {
+       if (!hasBuffer()) return; // nothing to do
+       IBuffer buffer = null;
+       buffer = getBufferManager().getBuffer(this);
+       if (buffer != null) {
+               buffer.close();
+               buffer.removeBufferChangedListener(this);
+       }
+}
+/**
+ * This element is being closed.  Do any necessary cleanup.
+ */
+protected void closing(Object info) {
+       closeBuffer();
+}
+
 ///**
 // * @see ICodeAssist
 // */
 //protected void codeComplete(org.eclipse.jdt.internal.compiler.env.ICompilationUnit cu, org.eclipse.jdt.internal.compiler.env.ICompilationUnit unitToSkip, int position, ICompletionRequestor requestor) throws JavaModelException {
 //     if (requestor == null) {
-//             throw new IllegalArgumentException(Util.bind("codeAssist.nullRequestor")); //$NON-NLS-1$
+//             throw new IllegalArgumentException(ProjectPrefUtil.bind("codeAssist.nullRequestor")); //$NON-NLS-1$
 //     }
 //     IBuffer buffer = getBuffer();
 //     if (buffer == null) {
@@ -116,18 +167,18 @@ protected Openable(int type, IJavaElement parent, String name) {
 //     engine.complete(cu, position, 0);
 //     environment.unitToSkip = null;
 //}
-///**
-// * @see ICodeAssist
-// */
-//protected IJavaElement[] codeSelect(org.eclipse.jdt.internal.compiler.env.ICompilationUnit cu, int offset, int length) throws JavaModelException {
+/**
+ * @see ICodeAssist
+ */
+//protected IJavaElement[] codeSelect(net.sourceforge.phpdt.internal.compiler.env.ICompilationUnit cu, int offset, int length) throws JavaModelException {
 //     SelectionRequestor requestor= new SelectionRequestor(((JavaProject)getJavaProject()).getNameLookup(), this);
 //     this.codeSelect(cu, offset, length, requestor);
 //     return requestor.getElements();
 //}
-///**
-// * @see ICodeAssist
-// */
-//protected void codeSelect(org.eclipse.jdt.internal.compiler.env.ICompilationUnit cu, int offset, int length, ISelectionRequestor requestor) throws JavaModelException {
+/**
+ * @see ICodeAssist
+ */
+//protected void codeSelect(net.sourceforge.phpdt.internal.compiler.env.ICompilationUnit cu, int offset, int length, ISelectionRequestor requestor) throws JavaModelException {
 //     IBuffer buffer = getBuffer();
 //     if (buffer == null) {
 //             return;
@@ -145,13 +196,12 @@ protected Openable(int type, IJavaElement parent, String name) {
 //     SelectionEngine engine = new SelectionEngine(environment, requestor, project.getOptions(true));
 //     engine.select(cu, offset, offset + length - 1);
 //}
-///**
-// * Returns a new element info for this element.
-// */
-//protected OpenableElementInfo createElementInfo() {
-//     return new OpenableElementInfo();
-//}
-//
+/*
+ * Returns a new element info for this element.
+ */
+protected Object createElementInfo() {
+       return new OpenableElementInfo();
+}
 ///**
 // * Builds this element's structure and properties in the given
 // * info object, based on this element's current contents (reuse buffer
@@ -163,6 +213,39 @@ protected Openable(int type, IJavaElement parent, String name) {
 // * the structure of this element.
 // */
 //protected abstract boolean generateInfos(OpenableElementInfo info, IProgressMonitor pm, Map newElements, IResource underlyingResource) throws JavaModelException;
+
+protected void generateInfos(Object info, HashMap newElements, IProgressMonitor monitor) throws JavaModelException {
+
+       if (JavaModelManager.VERBOSE){
+               System.out.println("OPENING Element ("+ Thread.currentThread()+"): " + this.toStringWithAncestors()); //$NON-NLS-1$//$NON-NLS-2$
+       }
+       
+       // open the parent if necessary
+       openParent(info, newElements, monitor);
+       if (monitor != null && monitor.isCanceled()) return;
+
+        // puts the info before building the structure so that questions to the handle behave as if the element existed
+        // (case of compilation units becoming working copies)
+       newElements.put(this, info);
+
+       // build the structure of the openable (this will open the buffer if needed)
+       try {
+               OpenableElementInfo openableElementInfo = (OpenableElementInfo)info;
+               boolean isStructureKnown = buildStructure(openableElementInfo, monitor, newElements, getResource());
+               openableElementInfo.setIsStructureKnown(isStructureKnown);
+       } catch (JavaModelException e) {
+               newElements.remove(this);
+               throw e;
+       }
+       
+       // remove out of sync buffer for this element
+       JavaModelManager.getJavaModelManager().getElementsOutOfSynchWithBuffers().remove(this);
+
+       if (JavaModelManager.VERBOSE) {
+               System.out.println("-> Package cache size = " + JavaModelManager.getJavaModelManager().cache.pkgSize()); //$NON-NLS-1$
+               System.out.println("-> Openable cache filling ratio = " + NumberFormat.getInstance().format(JavaModelManager.getJavaModelManager().cache.openableFillingRatio()) + "%"); //$NON-NLS-1$//$NON-NLS-2$
+       }
+}
 /**
  * Note: a buffer with no unsaved changes can be closed by the Java Model
  * since it has a finite number of buffers allowed open at one time. If this
@@ -188,14 +271,14 @@ public IBuffer getBuffer() throws JavaModelException {
                return null;
        }
 }
-//
-///**
-// * Answers the buffer factory to use for creating new buffers
-// */
-//public IBufferFactory getBufferFactory(){
-//     return getBufferManager().getDefaultBufferFactory();
-//}
-//
+
+/**
+ * Answers the buffer factory to use for creating new buffers
+ */
+public IBufferFactory getBufferFactory(){
+       return getBufferManager().getDefaultBufferFactory();
+}
+
 /**
  * Returns the buffer manager for this element.
  */
@@ -211,27 +294,27 @@ protected BufferManager getBufferManager() {
 public IResource getCorrespondingResource() throws JavaModelException {
        return getUnderlyingResource();
 }
-///*
-// * @see IJavaElement
-// */
-//public IOpenable getOpenable() {
-//     return this;    
-//}
-//
-//
-//
+/*
+ * @see IJavaElement
+ */
+public IOpenable getOpenable() {
+       return this;    
+}
+
+
+
 /**
  * @see IJavaElement
  */
 public IResource getUnderlyingResource() throws JavaModelException {
-       IResource parentResource = fParent.getUnderlyingResource();
+       IResource parentResource = parent.getUnderlyingResource();
        if (parentResource == null) {
                return null;
        }
        int type = parentResource.getType();
        if (type == IResource.FOLDER || type == IResource.PROJECT) {
                IContainer folder = (IContainer) parentResource;
-               IResource resource = folder.findMember(fName);
+               IResource resource = folder.findMember(name);
                if (resource == null) {
                        throw newNotPresentException();
                } else {
@@ -242,15 +325,15 @@ public IResource getUnderlyingResource() throws JavaModelException {
        }
 }
 
-//public boolean exists() {
-//     
-//     IPackageFragmentRoot root = this.getPackageFragmentRoot();
-//     if (root == null || root == this || !root.isArchive()) {
-//             return parentExists() && resourceExists();
-//     } else {
-//             return super.exists();
-//     }
-//}    
+public boolean exists() {
+       
+       IPackageFragmentRoot root = this.getPackageFragmentRoot();
+       if (root == null || root == this || !root.isArchive()) {
+               return parentExists() && resourceExists();
+       } else {
+               return super.exists();
+       }
+}      
 
 /**
  * Returns true if this element may have an associated source buffer,
@@ -259,44 +342,45 @@ public IResource getUnderlyingResource() throws JavaModelException {
 protected boolean hasBuffer() {
        return false;
 }
-///**
-// * @see IParent 
-// */
-//public boolean hasChildren() throws JavaModelException {
-//     return getChildren().length > 0;
-//}
-///**
-// * @see IOpenable
-// */
-//public boolean hasUnsavedChanges() throws JavaModelException{
-//     
-//     if (isReadOnly() || !isOpen()) {
-//             return false;
-//     }
-//     IBuffer buf = this.getBuffer();
-//     if (buf != null && buf.hasUnsavedChanges()) {
-//             return true;
-//     }
-//     // for package fragments, package fragment roots, and projects must check open buffers
-//     // to see if they have an child with unsaved changes
-//     if (fLEType == PACKAGE_FRAGMENT ||
-//             fLEType == PACKAGE_FRAGMENT_ROOT ||
-//             fLEType == JAVA_PROJECT ||
-//             fLEType == JAVA_MODEL) { // fix for 1FWNMHH
-//             Enumeration openBuffers= getBufferManager().getOpenBuffers();
-//             while (openBuffers.hasMoreElements()) {
-//                     IBuffer buffer= (IBuffer)openBuffers.nextElement();
-//                     if (buffer.hasUnsavedChanges()) {
-//                             IJavaElement owner= (IJavaElement)buffer.getOwner();
-//                             if (isAncestorOf(owner)) {
-//                                     return true;
-//                             }
-//                     }
-//             }
-//     }
-//     
-//     return false;
-//}
+/**
+ * @see IParent 
+ */
+public boolean hasChildren() throws JavaModelException {
+       return getChildren().length > 0;
+}
+/**
+ * @see IOpenable
+ */
+public boolean hasUnsavedChanges() throws JavaModelException{
+       
+       if (isReadOnly() || !isOpen()) {
+               return false;
+       }
+       IBuffer buf = this.getBuffer();
+       if (buf != null && buf.hasUnsavedChanges()) {
+               return true;
+       }
+//      for package fragments, package fragment roots, and projects must check open buffers
+       // to see if they have an child with unsaved changes
+       int elementType = getElementType();
+       if (elementType == PACKAGE_FRAGMENT ||
+                       elementType == PACKAGE_FRAGMENT_ROOT ||
+                       elementType == JAVA_PROJECT ||
+                       elementType == JAVA_MODEL) { // fix for 1FWNMHH
+               Enumeration openBuffers= getBufferManager().getOpenBuffers();
+               while (openBuffers.hasMoreElements()) {
+                       IBuffer buffer= (IBuffer)openBuffers.nextElement();
+                       if (buffer.hasUnsavedChanges()) {
+                               IJavaElement owner= (IJavaElement)buffer.getOwner();
+                               if (isAncestorOf(owner)) {
+                                       return true;
+                               }
+                       }
+               }
+       }
+       
+       return false;
+}
 /**
  * Subclasses must override as required.
  *
@@ -310,20 +394,18 @@ public boolean isConsistent() throws JavaModelException {
  * @see IOpenable
  */
 public boolean isOpen() {
-       // TODO isOpen - Openable needs JavaModelManager
-//     synchronized(JavaModelManager.getJavaModelManager()){
-//             return JavaModelManager.getJavaModelManager().getInfo(this) != null;
-//     }
-  return false;
+       synchronized(JavaModelManager.getJavaModelManager()){
+               return JavaModelManager.getJavaModelManager().getInfo(this) != null;
+       }
+}
+/**
+ * Returns true if this represents a source element.
+ * Openable source elements have an associated buffer created
+ * when they are opened.
+ */
+protected boolean isSourceElement() {
+       return false;
 }
-///**
-// * Returns true if this represents a source element.
-// * Openable source elements have an associated buffer created
-// * when they are opened.
-// */
-//protected boolean isSourceElement() {
-//     return false;
-//}
 ///**
 // * @see IOpenable
 // */
@@ -332,17 +414,46 @@ public boolean isOpen() {
 //             buildStructure((OpenableElementInfo)getElementInfo(), pm);
 //     }
 //}
-///**
-// * @see IOpenable
-// */
-//public void open(IProgressMonitor pm) throws JavaModelException {
-//     if (!isOpen()) {
-//             // TODO: need to synchronize (IOpenable.open(IProgressMonitor) is API
-//             // TODO: could use getElementInfo instead
-//             this.openWhenClosed(pm);
-//     }
-//}
-//
+/**
+ * @see IOpenable
+ */ 
+public void makeConsistent(IProgressMonitor monitor) throws JavaModelException {
+       if (isConsistent()) return;
+       
+       // create a new info and make it the current info
+       // (this will remove the info and its children just before storing the new infos)
+       JavaModelManager manager = JavaModelManager.getJavaModelManager();
+       boolean hadTemporaryCache = manager.hasTemporaryCache();
+       try {
+               HashMap newElements = manager.getTemporaryCache();
+               openWhenClosed(newElements, monitor);
+               if (newElements.get(this) == null) {
+                       // close any buffer that was opened for the new elements
+                       Iterator iterator = newElements.keySet().iterator();
+                       while (iterator.hasNext()) {
+                               IJavaElement element = (IJavaElement)iterator.next();
+                               if (element instanceof Openable) {
+                                       ((Openable)element).closeBuffer();
+                               }
+                       }
+                       throw newNotPresentException();
+               }
+               if (!hadTemporaryCache) {
+                       manager.putInfos(this, newElements);
+               }
+       } finally {
+               if (!hadTemporaryCache) {
+                       manager.resetTemporaryCache();
+               }
+       }
+}
+
+/**
+ * @see IOpenable
+ */
+public void open(IProgressMonitor pm) throws JavaModelException {
+       getElementInfo(pm);
+}
 /**
  * Opens a buffer on the contents of this element, and returns
  * the buffer, or returns <code>null</code> if opening fails.
@@ -352,21 +463,18 @@ public boolean isOpen() {
 protected IBuffer openBuffer(IProgressMonitor pm) throws JavaModelException {
        return null;
 }
-//
-///**
-// *   Open the parent element if necessary
-// * 
-// */
-//protected void openParent(IProgressMonitor pm) throws JavaModelException {
-//
-//     Openable openableParent = (Openable)getOpenableParent();
-//     if (openableParent != null) {
-//             if (!openableParent.isOpen()){
-//                     openableParent.openWhenClosed(pm);
-//             }
-//     }
-//}
-//
+
+/**
+ * Open the parent element if necessary.
+ */
+protected void openParent(Object childInfo, HashMap newElements, IProgressMonitor pm) throws JavaModelException {
+
+       Openable openableParent = (Openable)getOpenableParent();
+       if (openableParent != null && !openableParent.isOpen()){
+               openableParent.generateInfos(openableParent.createElementInfo(), newElements, pm);
+       }
+}
+
 ///**
 // * Open an <code>Openable</code> that is known to be closed (no check for <code>isOpen()</code>).
 // */
@@ -392,10 +500,10 @@ protected IBuffer openBuffer(IProgressMonitor pm) throws JavaModelException {
 //             // 4) anything special
 //             opening(info);
 //             
-//             if (JavaModelManager.VERBOSE) {
-//                     System.out.println("-> Package cache size = " + JavaModelManager.getJavaModelManager().cache.pkgSize()); //$NON-NLS-1$
-//                     System.out.println("-> Openable cache filling ratio = " + JavaModelManager.getJavaModelManager().cache.openableFillingRatio() + "%"); //$NON-NLS-1$//$NON-NLS-2$
-//             }
+////           if (JavaModelManager.VERBOSE) {
+////                   System.out.println("-> Package cache size = " + JavaModelManager.getJavaModelManager().cache.pkgSize()); //$NON-NLS-1$
+////                   System.out.println("-> Openable cache filling ratio = " + JavaModelManager.getJavaModelManager().cache.openableFillingRatio() + "%"); //$NON-NLS-1$//$NON-NLS-2$
+////           }
 //
 //             // if any problems occuring openning the element, ensure that it's info
 //             // does not remain in the cache (some elements, pre-cache their info
@@ -405,45 +513,45 @@ protected IBuffer openBuffer(IProgressMonitor pm) throws JavaModelException {
 //             throw e;
 //     }
 //}
-//
-///**
-// *  Answers true if the parent exists (null parent is answering true)
-// * 
-// */
-//protected boolean parentExists(){
-//     
-//     IJavaElement parent = this.getParent();
-//     if (parent == null) return true;
-//     return parent.exists();
-//}
-//
-///**
-// * Returns whether the corresponding resource or associated file exists
-// */
-//protected boolean resourceExists() {
-//     IWorkspace workspace = ResourcesPlugin.getWorkspace();
-//     if (workspace == null) return false; // workaround for http://bugs.eclipse.org/bugs/show_bug.cgi?id=34069
-//     return 
-//             JavaModel.getTarget(
-//                     workspace.getRoot(), 
-//                     this.getPath().makeRelative(), // ensure path is relative (see http://dev.eclipse.org/bugs/show_bug.cgi?id=22517)
-//                     true) != null;
-//}
-//
-///**
-// * @see IOpenable
-// */
-//public void save(IProgressMonitor pm, boolean force) throws JavaModelException {
-//     if (isReadOnly() || this.getResource().isReadOnly()) {
-//             throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.READ_ONLY, this));
-//     }
-//     IBuffer buf = getBuffer();
-//     if (buf != null) { // some Openables (like a JavaProject) don't have a buffer
-//             buf.save(pm, force);
-//             this.makeConsistent(pm); // update the element info of this element
-//     }
-//}
-//
+
+/**
+ *  Answers true if the parent exists (null parent is answering true)
+ * 
+ */
+protected boolean parentExists(){
+       
+       IJavaElement parent = this.getParent();
+       if (parent == null) return true;
+       return parent.exists();
+}
+
+/**
+ * Returns whether the corresponding resource or associated file exists
+ */
+protected boolean resourceExists() {
+       IWorkspace workspace = ResourcesPlugin.getWorkspace();
+       if (workspace == null) return false; // workaround for http://bugs.eclipse.org/bugs/show_bug.cgi?id=34069
+       return 
+               JavaModel.getTarget(
+                       workspace.getRoot(), 
+                       this.getPath().makeRelative(), // ensure path is relative (see http://dev.eclipse.org/bugs/show_bug.cgi?id=22517)
+                       true) != null;
+}
+
+/**
+ * @see IOpenable
+ */
+public void save(IProgressMonitor pm, boolean force) throws JavaModelException {
+       if (isReadOnly() || this.getResource().isReadOnly()) {
+               throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.READ_ONLY, this));
+       }
+       IBuffer buf = getBuffer();
+       if (buf != null) { // some Openables (like a JavaProject) don't have a buffer
+               buf.save(pm, force);
+               this.makeConsistent(pm); // update the element info of this element
+       }
+}
+
 /**
  * Find enclosing package fragment root if any
  */