3m9 compatible;
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / core / Openable.java
index 79481b1..1fb75fb 100644 (file)
@@ -10,6 +10,7 @@
  *******************************************************************************/
 package net.sourceforge.phpdt.internal.core;
 
+import java.text.NumberFormat;
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -31,6 +32,10 @@ import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.IWorkspace;
 import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.IProgressMonitor;
+import net.sourceforge.phpdt.internal.core.JavaElement;
+
+import net.sourceforge.phpdt.internal.core.JavaModelManager;
+import net.sourceforge.phpdt.internal.core.OpenableElementInfo;
 
 /**
  * Abstract class for implementations of java elements which are IOpenable.
@@ -40,8 +45,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
@@ -59,30 +64,70 @@ protected Openable(int type, IJavaElement parent, String name) {
                        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
+// * the new infos into the Java Model cache tables.
+// */
+//protected void buildStructure(OpenableElementInfo info, IProgressMonitor monitor) throws JavaModelException {
+//
+//     if (monitor != null && monitor.isCanceled()) return;
+//     
+//     // remove existing (old) infos
+//     removeInfo();
+//     HashMap newElements = new HashMap(11);
+//     info.setIsStructureKnown(generateInfos(info, monitor, newElements, getResource()));
+//     JavaModelManager.getJavaModelManager().getElementsOutOfSynchWithBuffers().remove(this);
+//     for (Iterator iter = newElements.keySet().iterator(); iter.hasNext();) {
+//             IJavaElement key = (IJavaElement) iter.next();
+//             Object value = newElements.get(key);
+//             JavaModelManager.getJavaModelManager().putInfo(key, value);
+//     }
+//             
+//     // add the info for this at the end, to ensure that a getInfo cannot reply null in case the LRU cache needs
+//     // to be flushed. Might lead to performance issues.
+//     // see PR 1G2K5S7: ITPJCORE:ALL - NPE when accessing source for a binary type
+//     JavaModelManager.getJavaModelManager().putInfo(this, 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();
+}
 /**
- * Updates the info objects for this element and all of its children by
- * removing the current infos, generating new infos, and then placing
- * the new infos into the Java Model cache tables.
+ * Close the buffer associated with this element, if any.
  */
-protected void buildStructure(OpenableElementInfo info, IProgressMonitor monitor) throws JavaModelException {
-
-       if (monitor != null && monitor.isCanceled()) return;
-       
-       // remove existing (old) infos
-       removeInfo();
-       HashMap newElements = new HashMap(11);
-       info.setIsStructureKnown(generateInfos(info, monitor, newElements, getResource()));
-       JavaModelManager.getJavaModelManager().getElementsOutOfSynchWithBuffers().remove(this);
-       for (Iterator iter = newElements.keySet().iterator(); iter.hasNext();) {
-               IJavaElement key = (IJavaElement) iter.next();
-               Object value = newElements.get(key);
-               JavaModelManager.getJavaModelManager().putInfo(key, value);
+protected void closeBuffer() {
+       if (!hasBuffer()) return; // nothing to do
+       IBuffer buffer = getBufferManager().getBuffer(this);
+       if (buffer != null) {
+               buffer.close();
+               buffer.removeBufferChangedListener(this);
        }
-               
-       // add the info for this at the end, to ensure that a getInfo cannot reply null in case the LRU cache needs
-       // to be flushed. Might lead to performance issues.
-       // 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.
@@ -99,11 +144,10 @@ protected void closeBuffer(OpenableElementInfo info) {
 /**
  * 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);
+protected void closing(Object info) {
+       closeBuffer();
 }
+
 ///**
 // * @see ICodeAssist
 // */
@@ -156,24 +200,56 @@ protected void closing(Object info) throws JavaModelException {
 //     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() {
+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
+// * 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 generateInfos(OpenableElementInfo info, IProgressMonitor pm, Map newElements, IResource underlyingResource) throws JavaModelException;
 
-/**
- * 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 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
@@ -235,14 +311,14 @@ public IOpenable getOpenable() {
  * @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 {
@@ -288,12 +364,13 @@ public boolean hasUnsavedChanges() throws JavaModelException{
        if (buf != null && buf.hasUnsavedChanges()) {
                return true;
        }
-       // for package fragments, package fragment roots, and projects must check open buffers
+//      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
+       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();
@@ -333,25 +410,54 @@ public boolean isOpen() {
 protected boolean isSourceElement() {
        return false;
 }
+///**
+// * @see IOpenable
+// */
+//public void makeConsistent(IProgressMonitor pm) throws JavaModelException {
+//     if (!isConsistent()) {
+//             buildStructure((OpenableElementInfo)getElementInfo(), pm);
+//     }
+//}
 /**
  * @see IOpenable
- */
-public void makeConsistent(IProgressMonitor pm) throws JavaModelException {
-       if (!isConsistent()) {
-               buildStructure((OpenableElementInfo)getElementInfo(), pm);
+ */ 
+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 {
-       if (!isOpen()) {
-               // TODO: need to synchronize (IOpenable.open(IProgressMonitor) is API
-               // TODO: could use getElementInfo instead
-               this.openWhenClosed(pm);
-       }
+       getElementInfo(pm);
 }
-
 /**
  * Opens a buffer on the contents of this element, and returns
  * the buffer, or returns <code>null</code> if opening fails.
@@ -363,57 +469,54 @@ protected IBuffer openBuffer(IProgressMonitor pm) throws JavaModelException {
 }
 
 /**
- *     Open the parent element if necessary
- * 
+ * Open the parent element if necessary.
  */
-protected void openParent(IProgressMonitor pm) throws JavaModelException {
+protected void openParent(Object childInfo, HashMap newElements, IProgressMonitor pm) throws JavaModelException {
 
        Openable openableParent = (Openable)getOpenableParent();
-       if (openableParent != null) {
-               if (!openableParent.isOpen()){
-                       openableParent.openWhenClosed(pm);
-               }
+       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>).
- */
-protected void openWhenClosed(IProgressMonitor pm) throws JavaModelException {
-       try {
-               
-               if (JavaModelManager.VERBOSE){
-                       System.out.println("OPENING Element ("+ Thread.currentThread()+"): " + this.toStringWithAncestors()); //$NON-NLS-1$//$NON-NLS-2$
-               }
-               
-               // 1) Parent must be open - open the parent if necessary
-               openParent(pm);
-
-               // 2) create the new element info and open a buffer if needed
-               OpenableElementInfo info = createElementInfo();
-               if (isSourceElement()) {
-                       this.openBuffer(pm);
-               } 
-
-               // 3) build the structure of the openable
-               buildStructure(info, pm);
-
-               // 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$
+///**
+// * Open an <code>Openable</code> that is known to be closed (no check for <code>isOpen()</code>).
+// */
+//protected void openWhenClosed(IProgressMonitor pm) throws JavaModelException {
+//     try {
+//             
+//             if (JavaModelManager.VERBOSE){
+//                     System.out.println("OPENING Element ("+ Thread.currentThread()+"): " + this.toStringWithAncestors()); //$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
-               // as they are being opened).
-       } catch (JavaModelException e) {
-               JavaModelManager.getJavaModelManager().removeInfo(this);
-               throw e;
-       }
-}
+//             
+//             // 1) Parent must be open - open the parent if necessary
+//             openParent(pm);
+//
+//             // 2) create the new element info and open a buffer if needed
+//             OpenableElementInfo info = createElementInfo();
+//             if (isSourceElement()) {
+//                     this.openBuffer(pm);
+//             } 
+//
+//             // 3) build the structure of the openable
+//             buildStructure(info, pm);
+//
+//             // 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 any problems occuring openning the element, ensure that it's info
+//             // does not remain in the cache (some elements, pre-cache their info
+//             // as they are being opened).
+//     } catch (JavaModelException e) {
+//             JavaModelManager.getJavaModelManager().removeInfo(this);
+//             throw e;
+//     }
+//}
 
 /**
  *  Answers true if the parent exists (null parent is answering true)