added a builder to parse files with eclipse's build mechanisms
authorkhartlage <khartlage>
Sat, 9 Aug 2003 17:32:28 +0000 (17:32 +0000)
committerkhartlage <khartlage>
Sat, 9 Aug 2003 17:32:28 +0000 (17:32 +0000)
40 files changed:
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/BufferChangedEvent.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IBuffer.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IBufferChangedListener.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IBufferFactory.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaElement.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaModel.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaModelStatus.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaModelStatusConstants.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IOpenable.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IParent.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/JavaModelException.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/util/ICacheEnumeration.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/util/ILRUCacheable.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/util/LRUCache.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/util/ToStringSorter.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/Buffer.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/BufferCache.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/BufferManager.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/JavaElement.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/JavaElementInfo.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/JavaModelStatus.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/LRUCacheEnumerator.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/OverflowingLRUCache.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/Util.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/util/CharArrayBuffer.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/phpdoc/PHPDocCommentReader.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/phpdoc/SingleCharReader.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/util/Strings.java [deleted file]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/PHPElementVisitor.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/PHPFileUtil.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/IPreferenceConstants.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/PHPEclipseParserPreferencePage.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/PHPeclipsePlugin.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/actions/PHPStartApacheAction.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/builder/ParserBuilder.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/builder/ParserVisitor.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPEditor.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPParserAction.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/resourcesview/PHPProject.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/views/PHPConsole.java

diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/BufferChangedEvent.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/BufferChangedEvent.java
new file mode 100644 (file)
index 0000000..2b030b5
--- /dev/null
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * 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.core;
+
+import java.util.EventObject;
+
+/**
+ * A buffer changed event describes how a buffer has changed. These events are
+ * used in <code>IBufferChangedListener</code> notifications.
+ * <p>
+ * For text insertions, <code>getOffset</code> is the offset
+ * of the first inserted character, <code>getText</code> is the
+ * inserted text, and <code>getLength</code> is 0.
+ * </p>
+ * <p>
+ * For text removals, <code>getOffset</code> is the offset
+ * of the first removed character, <code>getText</code> is <code>null</code>,
+ * and <code>getLength</code> is the length of the text that was removed.
+ * </p>
+ * <p>
+ * For replacements (including <code>IBuffer.setContents</code>), 
+ * <code>getOffset</code> is the offset
+ * of the first replaced character, <code>getText</code> is the replacement
+ * text, and <code>getLength</code> is the length of the original text
+ * that was replaced.
+ * </p>
+ * <p>
+ * When a buffer is closed, <code>getOffset</code> is 0, <code>getLength</code>
+ * is 0, and <code>getText</code> is <code>null</code>.
+ * </p>
+ * <p>
+ * This class is not intended to be instantiated or subclassed by clients.
+ * Instances of this class are automatically created by the Java model.
+ * </p>
+ *
+ * @see IBuffer
+ */
+public class BufferChangedEvent extends EventObject {
+
+       /**
+        * The length of text that has been modified in the buffer.
+        */
+       private int length;
+
+       /**
+        * The offset into the buffer where the modification took place.
+        */
+       private int offset;
+
+       /**
+        * The text that was modified.
+        */
+       private String text;
+
+/**
+ * Creates a new buffer changed event indicating that the given buffer has changed.
+ * 
+ * @param buffer the given buffer
+ * @param offset the given offset
+ * @param length the given length
+ * @param text the given text
+ */
+public BufferChangedEvent(IBuffer buffer, int offset, int length, String text) {
+       super(buffer);
+       this.offset = offset;
+       this.length = length;
+       this.text = text;
+}
+/**
+ * Returns the buffer which has changed.
+ *
+ * @return the buffer affected by the change
+ */
+public IBuffer getBuffer() {
+       return (IBuffer) source;
+}
+/**
+ * Returns the length of text removed or replaced in the buffer, or
+ * 0 if text has been inserted into the buffer.
+ *
+ * @return the length of the original text fragment modified by the 
+ *   buffer change (<code> 0 </code> in case of insertion).
+ */
+public int getLength() {
+       return this.length;
+}
+/**
+ * Returns the index of the first character inserted, removed, or replaced
+ * in the buffer.
+ *
+ * @return the source offset of the textual manipulation in the buffer
+ */
+public int getOffset() {
+       return this.offset;
+}
+/**
+ * Returns the text that was inserted, the replacement text,
+ * or <code>null</code> if text has been removed.
+ *
+ * @return the text corresponding to the buffer change (<code> null </code>
+ *   in case of deletion).
+ */
+public String getText() {
+       return this.text;
+}
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IBuffer.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IBuffer.java
new file mode 100644 (file)
index 0000000..0a84671
--- /dev/null
@@ -0,0 +1,263 @@
+/*******************************************************************************
+ * 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.core;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * A buffer contains the text contents of a resource. It is not language-specific.
+ * The contents may be in the process of being edited, differing from the actual contents of the 
+ * underlying resource. A buffer has an owner, which is an <code>IOpenable</code>. 
+ * If a buffer does not have an underlying resource, saving the buffer has no effect. 
+ * Buffers can be read-only.
+ * <p>
+ * Note that java model operations that manipulate an <code>IBuffer</code> (for example, 
+ * <code>IType.createMethod(...)</code>) ensures that the same line delimiter 
+ * (either <code>"\n"</code> or <code>"\r"</code> or <code>"\r\n"</code>) is 
+ * used across the whole buffer. Thus these operations may change the line delimiter(s) 
+ * included in the string to be append, or replaced.
+ * However implementers of this interface should be aware that other clients of <code>IBuffer</code>
+ * might not do such transformations beforehand.
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ */
+public interface IBuffer {
+       
+/**
+ * Adds the given listener for changes to this buffer.
+ * Has no effect if an identical listener is already registered or if the buffer
+ * is closed.
+ *
+ * @param listener the listener of buffer changes
+ */
+public void addBufferChangedListener(IBufferChangedListener listener);
+/**
+ * Appends the given character array to the contents of the buffer.
+ * This buffer will now have unsaved changes.
+ * Any client can append to the contents of the buffer, not just the owner of the buffer.
+ * Reports a buffer changed event.
+ * <p>
+ * Has no effect if this buffer is read-only.
+ * <p>
+ * A <code>RuntimeException</code> might be thrown if the buffer is closed.
+ *
+ * @param text the given character array to append to contents of the buffer
+ */
+public void append(char[] text);
+/**
+ * Appends the given string to the contents of the buffer.
+ * This buffer will now have unsaved changes.
+ * Any client can append to the contents of the buffer, not just the owner of the buffer.
+ * Reports a buffer changed event.
+ * <p>
+ * Has no effect if this buffer is read-only.
+ * <p>
+ * A <code>RuntimeException</code> might be thrown if the buffer is closed.
+ *
+ * @param text the <code>String</code> to append to the contents of the buffer
+ */
+public void append(String text);
+/**
+ * Closes the buffer. Any unsaved changes are lost. Reports a buffer changed event
+ * with a 0 offset and a 0 length. When this event is fired, the buffer should already
+ * be closed.
+ * <p>
+ * Further operations on the buffer are not allowed, except for close.  If an
+ * attempt is made to close an already closed buffer, the second attempt has no effect.
+ */
+public void close();
+/**
+ * Returns the character at the given position in this buffer.
+ * <p>
+ * A <code>RuntimeException</code> might be thrown if the buffer is closed.
+ *
+ * @param position a zero-based source offset in this buffer
+ * @return the character at the given position in this buffer
+ */
+public char getChar(int position);
+/**
+ * Returns the contents of this buffer as a character array, or <code>null</code> if
+ * the buffer has not been initialized.
+ * <p>
+ * Callers should make no assumption about whether the returned character array
+ * is or is not the genuine article or a copy. In other words, if the client
+ * wishes to change this array, they should make a copy. Likewise, if the
+ * client wishes to hang on to the array in its current state, they should
+ * make a copy.
+ * </p>
+ * <p>
+ * A <code>RuntimeException</code> might be thrown if the buffer is closed.
+ *
+ * @return the characters contained in this buffer
+ */
+public char[] getCharacters();
+/**
+ * Returns the contents of this buffer as a <code>String</code>. Like all strings,
+ * the result is an immutable value object., It can also answer <code>null</code> if
+ * the buffer has not been initialized.
+ * <p>
+ * A <code>RuntimeException</code> might be thrown if the buffer is closed.
+ *
+ * @return the contents of this buffer as a <code>String</code>
+ */
+public String getContents();
+/**
+ * Returns number of characters stored in this buffer.
+ * <p>
+ * A <code>RuntimeException</code> might be thrown if the buffer is closed.
+ *
+ * @return the number of characters in this buffer
+ */
+public int getLength();
+/**
+ * Returns the Java openable element owning of this buffer.
+ *
+ * @return the openable element owning this buffer
+ */
+public IOpenable getOwner();
+/**
+ * Returns the given range of text in this buffer.
+ * <p>
+ * A <code>RuntimeException</code> might be thrown if the buffer is closed.
+ *
+ * @param offset the  zero-based starting offset
+ * @param length the number of characters to retrieve
+ * @return the given range of text in this buffer
+ */
+public String getText(int offset, int length);
+/**
+ * Returns the underlying resource for which this buffer was opened,
+ * or <code>null</code> if this buffer was not opened on a resource.
+ *
+ * @return the underlying resource for this buffer, or <code>null</code>
+ *  if none.
+ */
+public IResource getUnderlyingResource();
+/**
+ * Returns whether this buffer has been modified since it
+ * was opened or since it was last saved.
+ * If a buffer does not have an underlying resource, this method always
+ * returns <code>true</code>.
+ *
+ * @return a <code>boolean</code> indicating presence of unsaved changes (in
+ *   the absence of any underlying resource, it will always return <code>true</code>).
+ */
+public boolean hasUnsavedChanges();
+/**
+ * Returns whether this buffer has been closed.
+ *
+ * @return a <code>boolean</code> indicating whether this buffer is closed.
+ */
+public boolean isClosed();
+/**
+ * Returns whether this buffer is read-only.
+ *
+ * @return a <code>boolean</code> indicating whether this buffer is read-only
+ */
+public boolean isReadOnly();
+/**
+ * Removes the given listener from this buffer.
+ * Has no affect if an identical listener is not registered or if the buffer is closed.
+ *
+ * @param listener the listener
+ */
+public void removeBufferChangedListener(IBufferChangedListener listener);
+/**
+ * Replaces the given range of characters in this buffer with the given text.
+ * <code>position</code> and <code>position + length</code> must be in the range [0, getLength()].
+ * <code>length</code> must not be negative.
+ * <p>
+ * A <code>RuntimeException</code> might be thrown if the buffer is closed.
+ *
+ * @param position the zero-based starting position of the affected text range in this buffer
+ * @param length the length of the affected text range in this buffer
+ * @param text the replacing text as a character array
+ */
+public void replace(int position, int length, char[] text);
+/**
+ * Replaces the given range of characters in this buffer with the given text.
+ * <code>position</code> and <code>position + length</code> must be in the range [0, getLength()].
+ * <code>length</code> must not be negative.
+ * <p>
+ * A <code>RuntimeException</code> might be thrown if the buffer is closed.
+ *
+ * @param position the zero-based starting position of the affected text range in this buffer
+ * @param length the length of the affected text range in this buffer
+ * @param text the replacing text as a <code>String</code>
+ */
+public void replace(int position, int length, String text);
+/**
+ * Saves the contents of this buffer to its underlying resource. If
+ * successful, this buffer will have no unsaved changes.
+ * The buffer is left open. Saving a buffer with no unsaved
+ * changes has no effect - the underlying resource is not changed.
+ * If the buffer does not have an underlying resource or is read-only, this
+ * has no effect.
+ * <p>
+ * The <code>force</code> parameter controls how this method deals with
+ * cases where the workbench is not completely in sync with the local file system.
+ * If <code>false</code> is specified, this method will only attempt
+ * to overwrite a corresponding file in the local file system provided
+ * it is in sync with the workbench. This option ensures there is no 
+ * unintended data loss; it is the recommended setting.
+ * However, if <code>true</code> is specified, an attempt will be made
+ * to write a corresponding file in the local file system, 
+ * overwriting any existing one if need be.
+ * In either case, if this method succeeds, the resource will be marked 
+ * as being local (even if it wasn't before).
+ * <p>
+ * A <code>RuntimeException</code> might be thrown if the buffer is closed.
+ *
+ * @param progress the progress monitor to notify
+ * @param force a <code> boolean </code> flag indicating how to deal with resource
+ *   inconsistencies.
+ *
+ * @exception JavaModelException if an error occurs writing the buffer
+ *     to the underlying resource
+ *
+ * @see org.eclipse.core.resources.IFile#setContents(java.io.InputStream, boolean, boolean, org.eclipse.core.runtime.IProgressMonitor)
+ */
+public void save(IProgressMonitor progress, boolean force) throws JavaModelException;
+/**
+ * Sets the contents of this buffer to the given character array.
+ * This buffer will now have unsaved changes.
+ * Any client can set the contents of the buffer, not just the owner of the buffer.
+ * Reports a buffer changed event.
+ * <p>
+ * Equivalent to <code>replace(0,getLength(),contents)</code>.
+ * </p>
+ * <p>
+ * Has no effect if this buffer is read-only.
+ * <p>
+ * A <code>RuntimeException</code> might be thrown if the buffer is closed.
+ *
+ * @param contents the new contents of this buffer as a character array
+ */
+public void setContents(char[] contents);
+/**
+ * Sets the contents of this buffer to the given <code>String</code>.
+ * This buffer will now have unsaved changes.
+ * Any client can set the contents of the buffer, not just the owner of the buffer.
+ * Reports a buffer changed event.
+ * <p>
+ * Equivalent to <code>replace(0,getLength(),contents)</code>.
+ * </p>
+ * <p>
+ * Has no effect if this buffer is read-only.
+ * <p>
+ * A <code>RuntimeException</code> might be thrown if the buffer is closed.
+ *
+ * @param contents the new contents of this buffer as a <code>String</code>
+ */
+public void setContents(String contents);
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IBufferChangedListener.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IBufferChangedListener.java
new file mode 100644 (file)
index 0000000..791fcc9
--- /dev/null
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * 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.core;
+
+/**
+ * A listener, which gets notified when the contents of a specific buffer
+ * have changed, or when the buffer is closed.
+ * When a buffer is closed, the listener is notified <em>after</em> the buffer has been closed.
+ * A listener is not notified when a buffer is saved.
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ */
+public interface IBufferChangedListener {
+
+       /** 
+        * Notifies that the given event has occurred.
+        *
+        * @param event the change event
+        */
+       public void bufferChanged(BufferChangedEvent event);
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IBufferFactory.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IBufferFactory.java
new file mode 100644 (file)
index 0000000..15b61e6
--- /dev/null
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * 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.core;
+
+/**
+ * A factory that creates <code>IBuffer</code>s for openables.
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ * @since 2.0
+ */
+public interface IBufferFactory {
+
+       /**
+        * Creates a buffer for the given owner.
+        * The new buffer will be initialized with the contents of the owner 
+        * if and only if it was not already initialized by the factory (a buffer is uninitialized if 
+        * its content is <code>null</code>).
+        * 
+        * @param owner the owner of the buffer
+        * @see IBuffer
+        */
+       IBuffer createBuffer(IOpenable owner);
+}
+
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaElement.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaElement.java
new file mode 100644 (file)
index 0000000..a4160bb
--- /dev/null
@@ -0,0 +1,304 @@
+/*******************************************************************************
+ * 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.core;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * Common protocol for all elements provided by the Java model.
+ * Java model elements are exposed to clients as handles to the actual underlying element.
+ * The Java model may hand out any number of handles for each element. Handles
+ * that refer to the same element are guaranteed to be equal, but not necessarily identical.
+ * <p>
+ * Methods annotated as "handle-only" do not require underlying elements to exist. 
+ * Methods that require underlying elements to exist throw
+ * a <code>JavaModelException</code> when an underlying element is missing.
+ * <code>JavaModelException.isDoesNotExist</code> can be used to recognize
+ * this common special case.
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ */
+public interface IJavaElement extends IAdaptable {
+
+       /**
+        * Constant representing a Java model (workspace level object).
+        * A Java element with this type can be safely cast to <code>IJavaModel</code>.
+        */
+       int JAVA_MODEL = 1;
+
+       /**
+        * Constant representing a Java project.
+        * A Java element with this type can be safely cast to <code>IJavaProject</code>.
+        */
+       int JAVA_PROJECT = 2;
+
+       /**
+        * Constant representing a package fragment root.
+        * A Java element with this type can be safely cast to <code>IPackageFragmentRoot</code>.
+        */
+       int PACKAGE_FRAGMENT_ROOT = 3;
+
+       /**
+        * Constant representing a package fragment.
+        * A Java element with this type can be safely cast to <code>IPackageFragment</code>.
+        */
+       int PACKAGE_FRAGMENT = 4;
+
+       /**
+        * Constant representing a Java compilation unit.
+        * A Java element with this type can be safely cast to <code>ICompilationUnit</code>.
+        */
+       int COMPILATION_UNIT = 5;
+
+       /**
+        * Constant representing a class file.
+        * A Java element with this type can be safely cast to <code>IClassFile</code>.
+        */
+       int CLASS_FILE = 6;
+
+       /**
+        * Constant representing a type (a class or interface).
+        * A Java element with this type can be safely cast to <code>IType</code>.
+        */
+       int TYPE = 7;
+
+       /**
+        * Constant representing a field.
+        * A Java element with this type can be safely cast to <code>IField</code>.
+        */
+       int FIELD = 8;
+
+       /**
+        * Constant representing a method or constructor.
+        * A Java element with this type can be safely cast to <code>IMethod</code>.
+        */
+       int METHOD = 9;
+
+       /**
+        * Constant representing a stand-alone instance or class initializer.
+        * A Java element with this type can be safely cast to <code>IInitializer</code>.
+        */
+       int INITIALIZER = 10;
+
+       /**
+        * Constant representing a package declaration within a compilation unit.
+        * A Java element with this type can be safely cast to <code>IPackageDeclaration</code>.
+        */
+       int PACKAGE_DECLARATION = 11;
+
+       /**
+        * Constant representing all import declarations within a compilation unit.
+        * A Java element with this type can be safely cast to <code>IImportContainer</code>.
+        */
+       int IMPORT_CONTAINER = 12;
+
+       /**
+        * Constant representing an import declaration within a compilation unit.
+        * A Java element with this type can be safely cast to <code>IImportDeclaration</code>.
+        */
+       int IMPORT_DECLARATION = 13;
+
+       /**
+        * Returns whether this Java element exists in the model.
+        * <p>
+        * Java elements are handle objects that may or may not be backed by an
+        * actual element. Java elements that are backed by an actual element are
+        * said to "exist", and this method returns <code>true</code>. For Java
+        * elements that are not working copies, it is always the case that if the
+        * element exists, then its parent also exists (provided it has one) and
+        * includes the element as one of its children. It is therefore possible
+        * to navigated to any existing Java element from the root of the Java model
+        * along a chain of existing Java elements. On the other hand, working
+        * copies are said to exist until they are destroyed (with
+        * <code>IWorkingCopy.destroy</code>). Unlike regular Java elements, a
+        * working copy never shows up among the children of its parent element
+        * (which may or may not exist).
+        * </p>
+        *
+        * @return <code>true</code> if this element exists in the Java model, and
+        * <code>false</code> if this element does not exist
+        */
+       boolean exists();
+       
+       /**
+        * Returns the first ancestor of this Java element that has the given type.
+        * Returns <code>null</code> if no such an ancestor can be found.
+        * This is a handle-only method.
+        * 
+        * @param ancestorType the given type
+        * @return the first ancestor of this Java element that has the given type, null if no such an ancestor can be found
+        * @since 2.0
+        */
+       IJavaElement getAncestor(int ancestorType);
+
+       /**
+        * Returns the resource that corresponds directly to this element,
+        * or <code>null</code> if there is no resource that corresponds to
+        * this element.
+        * <p>
+        * For example, the corresponding resource for an <code>ICompilationUnit</code>
+        * is its underlying <code>IFile</code>. The corresponding resource for
+        * an <code>IPackageFragment</code> that is not contained in an archive 
+        * is its underlying <code>IFolder</code>. An <code>IPackageFragment</code>
+        * contained in an archive has no corresponding resource. Similarly, there
+        * are no corresponding resources for <code>IMethods</code>,
+        * <code>IFields</code>, etc.
+        * <p>
+        *
+        * @return the corresponding resource, or <code>null</code> if none
+        * @exception JavaModelException if this element does not exist or if an
+        *              exception occurs while accessing its corresponding resource
+        */
+       IResource getCorrespondingResource() throws JavaModelException;
+
+       /**
+        * Returns the name of this element. This is a handle-only method.
+        *
+        * @return the element name
+        */
+       String getElementName();
+
+       /**
+        * Returns this element's kind encoded as an integer.
+        * This is a handle-only method.
+        *
+        * @return the kind of element; one of the constants declared in
+        *   <code>IJavaElement</code>
+        * @see IJavaElement
+        */
+       int getElementType();
+
+       /**
+        * Returns a string representation of this element handle. The format of
+        * the string is not specified; however, the identifier is stable across
+        * workspace sessions, and can be used to recreate this handle via the 
+        * <code>JavaCore.create(String)</code> method.
+        *
+        * @return the string handle identifier
+        * @see JavaCore#create(java.lang.String)
+        */
+       String getHandleIdentifier();
+
+       /**
+        * Returns the Java model.
+        * This is a handle-only method.
+        *
+        * @return the Java model
+        */
+       // IJavaModel getJavaModel();
+
+       /**
+        * Returns the Java project this element is contained in,
+        * or <code>null</code> if this element is not contained in any Java project
+        * (for instance, the <code>IJavaModel</code> is not contained in any Java 
+        * project).
+        * This is a handle-only method.
+        *
+        * @return the containing Java project, or <code>null</code> if this element is
+        *   not contained in a Java project
+        */
+//     IJavaProject getJavaProject();
+
+       /**
+        * Returns the first openable parent. If this element is openable, the element
+        * itself is returned. Returns <code>null</code> if this element doesn't have
+        * an openable parent.
+        * This is a handle-only method.
+        * 
+        * @return the first openable parent or <code>null</code> if this element doesn't have
+        * an openable parent.
+        * @since 2.0
+        */
+       IOpenable getOpenable();
+
+       /**
+        * Returns the element directly containing this element,
+        * or <code>null</code> if this element has no parent.
+        * This is a handle-only method.
+        *
+        * @return the parent element, or <code>null</code> if this element has no parent
+        */
+       IJavaElement getParent();
+
+       /**
+        * Returns the path to the innermost resource enclosing this element. 
+        * If this element is not included in an external archive, 
+        * the path returned is the full, absolute path to the underlying resource, 
+        * relative to the workbench. 
+        * If this element is included in an external archive, 
+        * the path returned is the absolute path to the archive in the file system.
+        * This is a handle-only method.
+        * 
+        * @return the path to the innermost resource enclosing this element
+        * @since 2.0
+        */
+       IPath getPath();
+
+       /**
+        * Returns the innermost resource enclosing this element. 
+        * If this element is included in an archive and this archive is not external, 
+        * this is the underlying resource corresponding to the archive. 
+        * If this element is included in an external archive, <code>null</code>
+        * is returned.
+        * If this element is a working copy, <code>null</code> is returned.
+        * This is a handle-only method.
+        * 
+        * @return the innermost resource enclosing this element, <code>null</code> if this 
+        * element is a working copy or is included in an external archive
+        * @since 2.0
+        */
+       IResource getResource();
+
+       /**
+        * Returns the smallest underlying resource that contains
+        * this element, or <code>null</code> if this element is not contained
+        * in a resource.
+        *
+        * @return the underlying resource, or <code>null</code> if none
+        * @exception JavaModelException if this element does not exist or if an
+        *              exception occurs while accessing its underlying resource
+        */
+       IResource getUnderlyingResource() throws JavaModelException;
+
+       /**
+        * Returns whether this Java element is read-only. An element is read-only
+        * if its structure cannot be modified by the java model. 
+        * <p>
+        * Note this is different from IResource.isReadOnly(). For example, .jar
+        * files are read-only as the java model doesn't know how to add/remove 
+        * elements in this file, but the underlying IFile can be writable.
+        * <p>
+        * This is a handle-only method.
+        *
+        * @return <code>true</code> if this element is read-only
+        */
+       boolean isReadOnly();
+
+       /**
+        * Returns whether the structure of this element is known. For example, for a
+        * compilation unit that could not be parsed, <code>false</code> is returned.
+        * If the structure of an element is unknown, navigations will return reasonable
+        * defaults. For example, <code>getChildren</code> will return an empty collection.
+        * <p>
+        * Note: This does not imply anything about consistency with the
+        * underlying resource/buffer contents.
+        * </p>
+        *
+        * @return <code>true</code> if the structure of this element is known
+        * @exception JavaModelException if this element does not exist or if an
+        *              exception occurs while accessing its corresponding resource
+        */
+       boolean isStructureKnown() throws JavaModelException;
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaModel.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaModel.java
new file mode 100644 (file)
index 0000000..d745883
--- /dev/null
@@ -0,0 +1,256 @@
+/*******************************************************************************
+ * 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.core;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * Represent the root Java element corresponding to the workspace. 
+ * Since there is only one such root element, it is commonly referred to as
+ * <em>the</em> Java model element.
+ * The Java model element needs to be opened before it can be navigated or manipulated.
+ * The Java model element has no parent (it is the root of the Java element 
+ * hierarchy). Its children are <code>IJavaProject</code>s.
+ * <p>
+ * This interface provides methods for performing copy, move, rename, and
+ * delete operations on multiple Java elements.
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients. An instance
+ * of one of these handles can be created via
+ * <code>JavaCore.create(workspace.getRoot())</code>.
+ * </p>
+ *
+ * @see JavaCore#create(org.eclipse.core.resources.IWorkspaceRoot)
+ */
+public interface IJavaModel extends IJavaElement, IOpenable, IParent {
+/**
+ * Returns whether this Java model contains an <code>IJavaElement</code> whose
+ * resource is the given resource or a non-Java resource which is the given resource.
+ * <p>
+ * Note: no existency check is performed on the argument resource. If it is not accessible 
+ * (see <code>IResource.isAccessible()</code>) yet but would be located in Java model 
+ * range, then it will return <code>true</code>.
+ * </p><p>
+ * If the resource is accessible, it can be reached by navigating the Java model down using the
+ * <code>getChildren()</code> and/or <code>getNonJavaResources()</code> methods.
+ * </p>
+ * @param resource the resource to check
+ * @return true if the resource is accessible through the Java model
+ * @since 2.1
+ */
+boolean contains(IResource resource);
+/**
+ * Copies the given elements to the specified container(s).
+ * If one container is specified, all elements are copied to that
+ * container. If more than one container is specified, the number of
+ * elements and containers must match, and each element is copied to
+ * its associated container.
+ * <p>
+ * Optionally, each copy can positioned before a sibling
+ * element. If <code>null</code> is specified for a given sibling, the copy
+ * is inserted as the last child of its associated container.
+ * </p>
+ * <p>
+ * Optionally, each copy can be renamed. If 
+ * <code>null</code> is specified for the new name, the copy
+ * is not renamed. 
+ * </p>
+ * <p>
+ * Optionally, any existing child in the destination container with
+ * the same name can be replaced by specifying <code>true</code> for
+ * force. Otherwise an exception is thrown in the event that a name
+ * collision occurs.
+ * </p>
+ *
+ * @param elements the elements to copy
+ * @param containers the container, or list of containers
+ * @param siblings the list of siblings element any of which may be
+ *   <code>null</code>; or <code>null</code>
+ * @param renamings the list of new names any of which may be
+ *   <code>null</code>; or <code>null</code>
+ * @param replace <code>true</code> if any existing child in a target container
+ *   with the target name should be replaced, and <code>false</code> to throw an
+ *   exception in the event of a name collision
+ * @param monitor a progress monitor
+ * @exception JavaModelException if an element could not be copied. Reasons include:
+ * <ul>
+ * <li> There is no element to process (NO_ELEMENTS_TO_PROCESS). The given elements is null or empty</li>
+ * <li> A specified element, container, or sibling does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * <li> A <code>CoreException</code> occurred while updating an underlying resource</li>
+ * <li> A container is of an incompatible type (<code>INVALID_DESTINATION</code>)</li>
+ * <li> A sibling is not a child of it associated container (<code>INVALID_SIBLING</code>)</li>
+ * <li> A new name is invalid (<code>INVALID_NAME</code>)</li>
+ * <li> A child in its associated container already exists with the same
+ *             name and <code>replace</code> has been specified as <code>false</code> (<code>NAME_COLLISION</code>)</li>
+ * <li> A container or element is read-only (<code>READ_ONLY</code>) </li>
+ * </ul>
+ */
+void copy(IJavaElement[] elements, IJavaElement[] containers, IJavaElement[] siblings, String[] renamings, boolean replace, IProgressMonitor monitor) throws JavaModelException;
+/**
+ * Deletes the given elements, forcing the operation if necessary and specified.
+ *
+ * @param elements the elements to delete
+ * @param force a flag controlling whether underlying resources that are not
+ *    in sync with the local file system will be tolerated
+ * @param monitor a progress monitor
+ * @exception JavaModelException if an element could not be deleted. Reasons include:
+ * <ul>
+ * <li> There is no element to process (NO_ELEMENTS_TO_PROCESS). The given elements is null or empty</li>
+ * <li> A specified element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * <li> A <code>CoreException</code> occurred while updating an underlying resource</li>
+ * <li> An element is read-only (<code>READ_ONLY</code>) </li>
+ * </ul>
+ */
+void delete(IJavaElement[] elements, boolean force, IProgressMonitor monitor) throws JavaModelException;
+/**
+ * Returns the Java project with the given name. This is a handle-only method. 
+ * The project may or may not exist.
+ * 
+ * @return the Java project with the given name
+ */
+// IJavaProject getJavaProject(String name);
+/**
+ * Returns the Java projects in this Java model, or an empty array if there
+ * are none.
+ *
+ * @return the Java projects in this Java model, or an empty array if there
+ * are none
+ * @exception JavaModelException if this request fails.
+ */
+// IJavaProject[] getJavaProjects() throws JavaModelException;
+/**
+ * Returns an array of non-Java resources (that is, non-Java projects) in
+ * the workspace.
+ * <p>
+ * Non-Java projects include all projects that are closed (even if they have the
+ * Java nature).
+ * </p>
+ * 
+ * @return an array of non-Java projects contained in the workspace.
+ * @throws JavaModelException if this element does not exist or if an
+ *             exception occurs while accessing its corresponding resource
+ * @since 2.1
+ */
+Object[] getNonJavaResources() throws JavaModelException;
+/**
+ * Returns the workspace associated with this Java model.
+ * 
+ * @return the workspace associated with this Java model
+ */
+IWorkspace getWorkspace();
+/**
+ * Moves the given elements to the specified container(s).
+ * If one container is specified, all elements are moved to that
+ * container. If more than one container is specified, the number of
+ * elements and containers must match, and each element is moved to
+ * its associated container.
+ * <p>
+ * Optionally, each element can positioned before a sibling
+ * element. If <code>null</code> is specified for sibling, the element
+ * is inserted as the last child of its associated container.
+ * </p>
+ * <p>
+ * Optionally, each element can be renamed. If 
+ * <code>null</code> is specified for the new name, the element
+ * is not renamed. 
+ * </p>
+ * <p>
+ * Optionally, any existing child in the destination container with
+ * the same name can be replaced by specifying <code>true</code> for
+ * force. Otherwise an exception is thrown in the event that a name
+ * collision occurs.
+ * </p>
+ *
+ * @param elements the elements to move
+ * @param containers the container, or list of containers
+ * @param siblings the list of siblings element any of which may be
+ *   <code>null</code>; or <code>null</code>
+ * @param renamings the list of new names any of which may be
+ *   <code>null</code>; or <code>null</code>
+ * @param replace <code>true</code> if any existing child in a target container
+ *   with the target name should be replaced, and <code>false</code> to throw an
+ *   exception in the event of a name collision
+ * @param monitor a progress monitor
+ * @exception JavaModelException if an element could not be moved. Reasons include:
+ * <ul>
+ * <li> There is no element to process (NO_ELEMENTS_TO_PROCESS). The given elements is null or empty</li>
+ * <li> A specified element, container, or sibling does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * <li> A <code>CoreException</code> occurred while updating an underlying resource</li>
+ * <li> A container is of an incompatible type (<code>INVALID_DESTINATION</code>)</li>
+ * <li> A sibling is not a child of it associated container (<code>INVALID_SIBLING</code>)</li>
+ * <li> A new name is invalid (<code>INVALID_NAME</code>)</li>
+ * <li> A child in its associated container already exists with the same
+ *             name and <code>replace</code> has been specified as <code>false</code> (<code>NAME_COLLISION</code>)</li>
+ * <li> A container or element is read-only (<code>READ_ONLY</code>) </li>
+ * </ul>
+ *
+ * @exception IllegalArgumentException any element or container is <code>null</code>
+ */
+void move(IJavaElement[] elements, IJavaElement[] containers, IJavaElement[] siblings, String[] renamings, boolean replace, IProgressMonitor monitor) throws JavaModelException;
+
+/**
+ * Triggers an update of the JavaModel with respect to the referenced external archives.
+ * This operation will issue a JavaModel delta describing the discovered changes, in term
+ * of Java element package fragment roots added, removed or changed.
+ * Note that a collection of elements can be passed so as to narrow the set of archives
+ * to refresh (passing <code>null</code> along is equivalent to refreshing the entire mode). 
+ * The elements can be:
+ * <ul>
+ * <li> package fragment roots corresponding to external archives
+ * <li> Java projects, which referenced external archives will be refreshed
+ * <li> Java model, all referenced external archives will be refreshed.
+ * </ul>
+ * <p> In case an archive is used by multiple projects, the delta issued will account for
+ * all of them. This means that even if a project was not part of the elements scope, it
+ * may still be notified of changes if it is referencing a library comprised in the scope.
+ * <p>
+ * @param elementsScope - a collection of elements defining the scope of the refresh
+ * @param monitor - a progress monitor used to report progress
+ * @exception JavaModelException in one of the corresponding situation:
+ * <ul>
+ *    <li> an exception occurs while accessing project resources </li>
+ * </ul>
+ * 
+ * @see IJavaElementDelta
+ * @since 2.0
+ */
+void refreshExternalArchives(IJavaElement[] elementsScope, IProgressMonitor monitor) throws JavaModelException;
+
+/**
+ * Renames the given elements as specified.
+ * If one container is specified, all elements are renamed within that
+ * container. If more than one container is specified, the number of
+ * elements and containers must match, and each element is renamed within
+ * its associated container.
+ *
+ * @param elements the elements to rename
+ * @param destinations the container, or list of containers
+ * @param names the list of new names
+ * @param replace <code>true</code> if an existing child in a target container
+ *   with the target name should be replaced, and <code>false</code> to throw an
+ *   exception in the event of a name collision
+ * @param monitor a progress monitor
+ * @exception JavaModelException if an element could not be renamed. Reasons include:
+ * <ul>
+ * <li> There is no element to process (NO_ELEMENTS_TO_PROCESS). The given elements is null or empty</li>
+ * <li> A specified element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * <li> A <code>CoreException</code> occurred while updating an underlying resource
+ * <li> A new name is invalid (<code>INVALID_NAME</code>)
+ * <li> A child already exists with the same name and <code>replace</code> has been specified as <code>false</code> (<code>NAME_COLLISION</code>)
+ * <li> An element is read-only (<code>READ_ONLY</code>) 
+ * </ul>
+ */
+void rename(IJavaElement[] elements, IJavaElement[] destinations, String[] names, boolean replace, IProgressMonitor monitor) throws JavaModelException;
+
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaModelStatus.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaModelStatus.java
new file mode 100644 (file)
index 0000000..98c8565
--- /dev/null
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * 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.core;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+
+/**
+ * Represents the outcome of an Java model operation. Status objects are
+ * used inside <code>JavaModelException</code> objects to indicate what went
+ * wrong.
+ * <p>
+ * Java model status object are distinguished by their plug-in id:
+ * <code>getPlugin</code> returns <code>"org.eclipse.jdt.core"</code>.
+ * <code>getCode</code> returns one of the status codes declared in
+ * <code>IJavaModelStatusConstants</code>.
+ * </p>
+ * <p>
+ * A Java model status may also carry additional information (that is, in 
+ * addition to the information defined in <code>IStatus</code>):
+ * <ul>
+ *   <li>elements - optional handles to Java elements associated with the failure</li>
+ *   <li>string - optional string associated with the failure</li>
+ * </ul>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ *
+ * @see org.eclipse.core.runtime.IStatus
+ * @see IJavaModelStatusConstants
+ */
+public interface IJavaModelStatus extends IStatus {
+/**
+ * Returns any Java elements associated with the failure (see specification
+ * of the status code), or an empty array if no elements are related to this
+ * particular status code.
+ *
+ * @return the list of Java element culprits
+ * @see IJavaModelStatusConstants
+ */
+public IJavaElement[] getElements();
+
+/**
+ * Returns the path associated with the failure (see specification
+ * of the status code), or <code>null</code> if the failure is not 
+ * one of <code>DEVICE_PATH</code>, <code>INVALID_PATH</code>, 
+ * <code>PATH_OUTSIDE_PROJECT</code>, or <code>RELATIVE_PATH</code>.
+ *
+ * @return the path that caused the failure, or <code>null</code> if none
+ * @see IJavaModelStatusConstants#DEVICE_PATH
+ * @see IJavaModelStatusConstants#INVALID_PATH
+ * @see IJavaModelStatusConstants#PATH_OUTSIDE_PROJECT
+ * @see IJavaModelStatusConstants#RELATIVE_PATH
+ */
+IPath getPath();
+/**
+ * Returns the string associated with the failure (see specification
+ * of the status code), or <code>null</code> if no string is related to this
+ * particular status code.
+ *
+ * @return the string culprit, or <code>null</code> if none
+ * @see IJavaModelStatusConstants
+ * @deprecated Use IStatus#getMessage instead
+ */
+String getString();
+/**
+ * Returns whether this status indicates that a Java model element does not exist.
+ * This convenience method is equivalent to
+ * <code>getCode() == IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST</code>.
+ *
+ * @return <code>true</code> if the status code indicates that a Java model
+ *   element does not exist
+ * @see IJavaModelStatusConstants#ELEMENT_DOES_NOT_EXIST
+ */
+boolean isDoesNotExist();
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaModelStatusConstants.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaModelStatusConstants.java
new file mode 100644 (file)
index 0000000..aa108f9
--- /dev/null
@@ -0,0 +1,283 @@
+/*******************************************************************************
+ * 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.core;
+
+/**
+ * Status codes used with Java model status objects.
+ * <p>
+ * This interface declares constants only; it is not intended to be implemented
+ * or extended.
+ * </p>
+ *
+ * @see IJavaModelStatus
+ * @see org.eclipse.core.runtime.IStatus#getCode()
+ */
+public interface IJavaModelStatusConstants {
+
+       /**
+        * Status constant indicating that a container path was resolved
+        * to invalid entries (null or container).
+        * 
+        * @since 2.0
+        */
+       public static final int INVALID_CP_CONTAINER_ENTRY = 962;
+
+       /**
+        * Status constant indicating that a container path was not resolvable
+        * indicating either the referred container is undefined, unbound.
+        * 
+        * @since 2.0
+        */
+       public static final int CP_CONTAINER_PATH_UNBOUND = 963;
+
+       /**
+        * Status constant indicating that a classpath entry was invalid
+        */
+       public static final int INVALID_CLASSPATH = 964;
+
+       /**
+        * Status constant indicating that a variable path was not resolvable
+        * indicating either the referred variable is undefined, unbound or the resolved
+        * variable path does not correspond to an existing file or folder.
+        */
+       public static final int CP_VARIABLE_PATH_UNBOUND = 965;
+
+       /**
+        * Status constant indicating a core exception occurred.
+        * Use <code>getException</code> to retrieve a <code>CoreException</code>.
+        */
+       public static final int CORE_EXCEPTION = 966;
+    
+       /**
+        * Status constant indicating one or more of the elements
+        * supplied are not of a valid type for the operation to
+        * process. 
+        * The element(s) can be retrieved using <code>getElements</code> on the status object.
+        */
+       public static final int INVALID_ELEMENT_TYPES = 967;
+
+       /**
+        * Status constant indicating that no elements were
+        * provided to the operation for processing.
+        */
+       public static final int NO_ELEMENTS_TO_PROCESS = 968;
+
+       /**
+        * Status constant indicating that one or more elements
+        * supplied do not exist. 
+        * The element(s) can be retrieved using <code>getElements</code> on the status object.
+        *
+        * @see IJavaModelStatus#isDoesNotExist
+        */
+       public static final int ELEMENT_DOES_NOT_EXIST = 969;
+
+       /**
+        * Status constant indicating that a <code>null</code> path was
+        * supplied to the operation.
+        */
+       public static final int NULL_PATH = 970;
+    
+       /**
+        * Status constant indicating that a path outside of the
+        * project was supplied to the operation. The path can be retrieved using 
+        * <code>getPath</code> on the status object.
+        */
+       public static final int PATH_OUTSIDE_PROJECT = 971;
+    
+       /**
+        * Status constant indicating that a relative path 
+        * was supplied to the operation when an absolute path is
+        * required. The path can be retrieved using <code>getPath</code> on the
+        * status object.
+        */
+       public static final int RELATIVE_PATH = 972;
+    
+       /**
+        * Status constant indicating that a path specifying a device
+        * was supplied to the operation when a path with no device is
+        * required. The path can be retrieved using <code>getPath</code> on the
+        * status object.
+        */
+       public static final int DEVICE_PATH = 973;
+    
+       /**
+        * Status constant indicating that a string
+        * was supplied to the operation that was <code>null</code>.
+        */
+       public static final int NULL_STRING = 974;
+    
+       /**
+        * Status constant indicating that the operation encountered
+        * a read-only element.
+        * The element(s) can be retrieved using <code>getElements</code> on the status object.
+        */
+       public static final int READ_ONLY = 976;
+    
+       /**
+        * Status constant indicating that a naming collision would occur
+        * if the operation proceeded.
+        */
+       public static final int NAME_COLLISION = 977;
+    
+       /**
+        * Status constant indicating that a destination provided for a copy/move/rename operation 
+        * is invalid. 
+        * The destination element can be retrieved using <code>getElements</code> on the status object.
+        */
+       public static final int INVALID_DESTINATION = 978;
+    
+       /**
+        * Status constant indicating that a path provided to an operation 
+        * is invalid. The path can be retrieved using <code>getPath</code> on the
+        * status object.
+        */
+       public static final int INVALID_PATH = 979;
+    
+       /**
+        * Status constant indicating the given source position is out of bounds.
+        */
+       public static final int INDEX_OUT_OF_BOUNDS = 980;
+    
+       /**
+        * Status constant indicating there is an update conflict
+        * for a working copy. The compilation unit on which the
+        * working copy is based has changed since the working copy
+        * was created.
+        */
+       public static final int UPDATE_CONFLICT = 981;
+
+       /**
+        * Status constant indicating that <code>null</code> was specified
+        * as a name argument.
+        */
+       public static final int NULL_NAME = 982;
+
+       /**
+        * Status constant indicating that a name provided is not syntactically correct.
+        * The name can be retrieved from <code>getString</code>.
+        */
+       public static final int INVALID_NAME = 983;
+
+       /**
+        * Status constant indicating that the specified contents
+        * are not valid.
+        */
+       public static final int INVALID_CONTENTS = 984;
+
+       /**
+        * Status constant indicating that an <code>java.io.IOException</code>
+        * occurred. 
+        */
+       public static final int IO_EXCEPTION = 985;
+
+       /**
+        * Status constant indicating that a <code>DOMException</code>
+        * occurred. 
+        */
+       public static final int DOM_EXCEPTION = 986;
+
+       /**
+        * Status constant indicating that a <code>TargetException</code>
+        * occurred. 
+        */
+       public static final int TARGET_EXCEPTION = 987;
+
+       /**
+        * Status constant indicating that the Java builder
+        * could not be initialized.
+        */
+       public static final int BUILDER_INITIALIZATION_ERROR = 990;
+
+       /**
+        * Status constant indicating that the Java builder's last built state
+        * could not be serialized or deserialized.
+        */
+       public static final int BUILDER_SERIALIZATION_ERROR = 991;
+
+       /**
+        * Status constant indicating that an error was encountered while
+        * trying to evaluate a code snippet, or other item.
+        */
+       public static final int EVALUATION_ERROR = 992;
+
+       /**
+        * Status constant indicating that a sibling specified is not valid.
+        */
+       public static final int INVALID_SIBLING = 993;
+
+       /**
+        * Status indicating that a Java element could not be created because
+        * the underlying resource is invalid.
+        * @see JavaCore
+        */
+        public static final int INVALID_RESOURCE = 995;
+
+       /**
+        * Status indicating that a Java element could not be created because
+        * the underlying resource is not of an appropriate type.
+        * @see JavaCore
+        */
+        public static final int INVALID_RESOURCE_TYPE = 996;
+
+       /**
+        * Status indicating that a Java element could not be created because
+        * the project owning underlying resource does not have the Java nature.
+        * @see JavaCore
+        */
+        public static final int INVALID_PROJECT = 997;
+
+       /**
+        * Status indicating that the package declaration in a <code>ICompilationUnit</code>
+        * does not correspond to the <code>IPackageFragment</code> it belongs to.
+        * The <code>getString</code> method of the associated status object
+        * gives the name of the package in which the <code>ICompilationUnit</code> is
+        * declared.
+        */
+        public static final int INVALID_PACKAGE = 998;
+
+       /**
+        * Status indicating that the corresponding resource has no local contents yet.
+        * This might happen when attempting to use a resource before its contents
+        * has been made locally available.
+        */
+        public static final int NO_LOCAL_CONTENTS = 999;
+        
+        /**
+         * Status indicating that a .classpath file is ill-formed, and thus cannot
+         * be read/written successfully.
+         * @since 2.1
+         */
+        public static final int INVALID_CLASSPATH_FILE_FORMAT = 1000;
+
+        /**
+         * Status indicating that a project is involved in a build path cycle.
+         * @since 2.1
+         */
+        public static final int CLASSPATH_CYCLE = 1001;
+        
+       /**
+        * Status constant indicating that an exclusion pattern got specified
+        * on a classpath source entry, though it was explicitely disabled 
+        * according to its project preference settings.
+        * @see org.eclipse.jdt.core.IJavaProject#getOptions(boolean)
+        * @since 2.1
+        */
+       public static final int DISABLED_CP_EXCLUSION_PATTERNS = 1002;
+
+       /**
+        * Status constant indicating that a specific output location got associated
+        * with a source entry, though it was explicitely disabled according to its project
+        * preference settings.
+        * @see org.eclipse.jdt.core.IJavaProject#getOptions(boolean)
+        * @since 2.1
+        */
+       public static final int DISABLED_CP_MULTIPLE_OUTPUT_LOCATIONS = 1003;
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IOpenable.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IOpenable.java
new file mode 100644 (file)
index 0000000..474e764
--- /dev/null
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * 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.core;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * Common protocol for Java elements that must be opened before they can be 
+ * navigated or modified. Opening a textual element (such as a compilation unit)
+ * involves opening a buffer on its contents.  While open, any changes to the buffer
+ * can be reflected in the element's structure; 
+ * see <code>isConsistent</code> and <code>makeConsistent(IProgressMonitor)</code>.
+ * <p>
+ * To reduce complexity in clients, elements are automatically opened
+ * by the Java model as element properties are accessed. The Java model maintains
+ * an LRU cache of open elements, and automatically closes elements as they
+ * are swapped out of the cache to make room for other elements. Elements with
+ * unsaved changes are never removed from the cache, and thus, if the client
+ * maintains many open elements with unsaved
+ * changes, the LRU cache can grow in size (in this case the cache is not
+ * bounded). However, as elements are saved, the cache will shrink back to its
+ * original bounded size.
+ * </p>
+ * <p>
+ * To open an element, all openable parent elements must be open.
+ * The Java model automatically opens parent elements, as it automatically opens elements.
+ * Opening an element may provide access to direct children and other descendants,
+ * but does not automatically open any descendents which are themselves <code>IOpenable</code>.
+ * For example, opening a compilation unit provides access to all its constituent elements,
+ * but opening a package fragment does not open all compilation units in the package fragment.
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ */
+public interface IOpenable {
+
+/**
+ * Closes this element and its buffer (if any).
+ * Closing an element which is not open has no effect.
+ *
+ * <p>Note: although <code>close</code> is exposed in the API, clients are
+ * not expected to open and close elements - the Java model does this automatically
+ * as elements are accessed.
+ *
+ * @exception JavaModelException if an error occurs closing this element
+ */
+public void close() throws JavaModelException;
+/**
+ * Returns the buffer opened for this element, or <code>null</code>
+ * if this element does not have a buffer.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ *             exception occurs while accessing its corresponding resource.
+ * @return the buffer opened for this element, or <code>null</code>
+ * if this element does not have a buffer
+ */
+public IBuffer getBuffer() throws JavaModelException;
+/**
+ * Returns <code>true</code> if this element is open and:
+ * <ul>
+ * <li>its buffer has unsaved changes, or
+ * <li>one of its descendants has unsaved changes, or
+ * <li>a working copy has been created on one of this
+ * element's children and has not yet destroyed
+ * </ul>
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ *             exception occurs while accessing its corresponding resource.
+ * @return <code>true</code> if this element is open and:
+ * <ul>
+ * <li>its buffer has unsaved changes, or
+ * <li>one of its descendants has unsaved changes, or
+ * <li>a working copy has been created on one of this
+ * element's children and has not yet destroyed
+ * </ul>
+ */
+boolean hasUnsavedChanges() throws JavaModelException;
+/**
+ * Returns whether the element is consistent with its underlying resource or buffer.
+ * The element is consistent when opened, and is consistent if the underlying resource
+ * or buffer has not been modified since it was last consistent.
+ *
+ * <p>NOTE: Child consistency is not considered. For example, a package fragment
+ * responds <code>true</code> when it knows about all of its
+ * compilation units present in its underlying folder. However, one or more of
+ * the compilation units could be inconsistent.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ *             exception occurs while accessing its corresponding resource.
+ * @return true if the element is consistent with its underlying resource or buffer, false otherwise.
+ * @see IOpenable#makeConsistent
+ */
+boolean isConsistent() throws JavaModelException;
+/**
+ * Returns whether this openable is open. This is a handle-only method.
+ * @return true if this openable is open, false otherwise
+ */
+boolean isOpen();
+/**
+ * Makes this element consistent with its underlying resource or buffer 
+ * by updating the element's structure and properties as necessary.
+ *
+ * @param progress the given progress monitor
+ * @exception JavaModelException if the element is unable to access the contents
+ *             of its underlying resource. Reasons include:
+ * <ul>
+ *  <li>This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * </ul>
+ * @see IOpenable#isConsistent
+ */
+void makeConsistent(IProgressMonitor progress) throws JavaModelException;
+/**
+ * Opens this element and all parent elements that are not already open.
+ * For compilation units, a buffer is opened on the contents of the underlying resource.
+ *
+ * <p>Note: although <code>open</code> is exposed in the API, clients are
+ * not expected to open and close elements - the Java model does this automatically
+ * as elements are accessed.
+ *
+ * @param progress the given progress monitor
+ * @exception JavaModelException if an error occurs accessing the contents
+ *             of its underlying resource. Reasons include:
+ * <ul>
+ *  <li>This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * </ul>
+ */
+public void open(IProgressMonitor progress) throws JavaModelException;
+/**
+ * Saves any changes in this element's buffer to its underlying resource
+ * via a workspace resource operation. This has no effect if the element has no underlying
+ * buffer, or if there are no unsaved changed in the buffer.
+ * <p>
+ * The <code>force</code> parameter controls how this method deals with
+ * cases where the workbench is not completely in sync with the local file system.
+ * If <code>false</code> is specified, this method will only attempt
+ * to overwrite a corresponding file in the local file system provided
+ * it is in sync with the workbench. This option ensures there is no 
+ * unintended data loss; it is the recommended setting.
+ * However, if <code>true</code> is specified, an attempt will be made
+ * to write a corresponding file in the local file system, 
+ * overwriting any existing one if need be.
+ * In either case, if this method succeeds, the resource will be marked 
+ * as being local (even if it wasn't before).
+ * <p>
+ * As a result of this operation, the element is consistent with its underlying 
+ * resource or buffer. 
+ *
+ * @param progress the given progress monitor
+ * @param force it controls how this method deals with
+ * cases where the workbench is not completely in sync with the local file system
+ * @exception JavaModelException if an error occurs accessing the contents
+ *             of its underlying resource. Reasons include:
+ * <ul>
+ *  <li>This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ *  <li>This Java element is read-only (READ_ONLY)</li>
+ * </ul>
+ */
+public void save(IProgressMonitor progress, boolean force) throws JavaModelException;
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IParent.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IParent.java
new file mode 100644 (file)
index 0000000..f1571c5
--- /dev/null
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * 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.core;
+
+/**
+ * Common protocol for Java elements that contain other Java elements.
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ */
+public interface IParent {
+/**
+ * Returns the immediate children of this element.
+ * Unless otherwise specified by the implementing element,
+ * the children are in no particular order.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ *      exception occurs while accessing its corresponding resource
+ * @return the immediate children of this element
+ */
+IJavaElement[] getChildren() throws JavaModelException;
+/**
+ * Returns whether this element has one or more immediate children.
+ * This is a convenience method, and may be more efficient than
+ * testing whether <code>getChildren</code> is an empty array.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ *      exception occurs while accessing its corresponding resource
+ * @return true if the immediate children of this element, false otherwise
+ */
+boolean hasChildren() throws JavaModelException;
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/JavaModelException.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/JavaModelException.java
new file mode 100644 (file)
index 0000000..a8d59f9
--- /dev/null
@@ -0,0 +1,134 @@
+/*******************************************************************************
+ * 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.core;
+
+import net.sourceforge.phpdt.internal.core.JavaModelStatus;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+
+//import org.eclipse.jdt.internal.core.JavaModelStatus;
+
+/**
+ * A checked exception representing a failure in the Java model.
+ * Java model exceptions contain a Java-specific status object describing the
+ * cause of the exception.
+ * <p>
+ * This class is not intended to be subclassed by clients. Instances of this
+ * class are automatically created by the Java model when problems arise, so
+ * there is generally no need for clients to create instances.
+ * </p>
+ *
+ * @see IJavaModelStatus
+ * @see IJavaModelStatusConstants
+ */
+public class JavaModelException extends CoreException {
+       CoreException nestedCoreException;
+/**
+ * Creates a Java model exception that wrappers the given <code>Throwable</code>.
+ * The exception contains a Java-specific status object with severity
+ * <code>IStatus.ERROR</code> and the given status code.
+ *
+ * @param exception the <code>Throwable</code>
+ * @param code one of the Java-specific status codes declared in
+ *   <code>IJavaModelStatusConstants</code>
+ * @see IJavaModelStatusConstants
+ * @see org.eclipse.core.runtime.IStatus#ERROR
+ */
+public JavaModelException(Throwable e, int code) {
+       this(new JavaModelStatus(code, e)); 
+}
+/**
+ * Creates a Java model exception for the given <code>CoreException</code>.
+ * Equivalent to 
+ * <code>JavaModelException(exception,IJavaModelStatusConstants.CORE_EXCEPTION</code>.
+ *
+ * @param exception the <code>CoreException</code>
+ */
+public JavaModelException(CoreException exception) {
+       super(exception.getStatus());
+       this.nestedCoreException = exception;
+}
+/**
+ * Creates a Java model exception for the given Java-specific status object.
+ *
+ * @param status the Java-specific status object
+ */
+public JavaModelException(IJavaModelStatus status) {
+       super(status);
+}
+/**
+ * Returns the underlying <code>Throwable</code> that caused the failure.
+ *
+ * @return the wrappered <code>Throwable</code>, or <code>null</code> if the
+ *   direct case of the failure was at the Java model layer
+ */
+public Throwable getException() {
+       if (this.nestedCoreException == null) {
+               return getStatus().getException();
+       } else {
+               return this.nestedCoreException;
+       }
+}
+/**
+ * Returns the Java model status object for this exception.
+ * Equivalent to <code>(IJavaModelStatus) getStatus()</code>.
+ *
+ * @return a status object
+ */
+public IJavaModelStatus getJavaModelStatus() {
+       IStatus status = this.getStatus();
+       if (status instanceof IJavaModelStatus) {
+               return (IJavaModelStatus)status;
+       } else {
+               // A regular IStatus is created only in the case of a CoreException.
+               // See bug 13492 Should handle JavaModelExceptions that contains CoreException more gracefully  
+               return new JavaModelStatus(this.nestedCoreException);
+       }
+}
+/**
+ * Returns whether this exception indicates that a Java model element does not
+ * exist. Such exceptions have a status with a code of
+ * <code>IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST</code>.
+ * This is a convenience method.
+ *
+ * @return <code>true</code> if this exception indicates that a Java model
+ *   element does not exist
+ * @see IJavaModelStatus#isDoesNotExist
+ * @see IJavaModelStatusConstants#ELEMENT_DOES_NOT_EXIST
+ */
+//public boolean isDoesNotExist() {
+//     IJavaModelStatus javaModelStatus = getJavaModelStatus();
+//     return javaModelStatus != null && javaModelStatus.isDoesNotExist();
+//}
+/**
+ * Returns a printable representation of this exception suitable for debugging
+ * purposes only.
+ */
+public String toString() {
+       StringBuffer buffer= new StringBuffer();
+       buffer.append("Java Model Exception: "); //$NON-NLS-1$
+       if (getException() != null) {
+               if (getException() instanceof CoreException) {
+                       CoreException c= (CoreException)getException();
+                       buffer.append("Core Exception [code "); //$NON-NLS-1$
+                       buffer.append(c.getStatus().getCode());
+                       buffer.append("] "); //$NON-NLS-1$
+                       buffer.append(c.getStatus().getMessage());
+               } else {
+                       buffer.append(getException().toString());
+               }
+       } else {
+               buffer.append(getStatus().toString());
+       }
+       return buffer.toString();
+}
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/util/ICacheEnumeration.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/util/ICacheEnumeration.java
new file mode 100644 (file)
index 0000000..c1cbc30
--- /dev/null
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * 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.core.util;
+
+import java.util.Enumeration;
+
+/**
+ * The <code>ICacheEnumeration</code> is used to iterate over both the keys 
+ * and values in an LRUCache.  The <code>getValue()</code> method returns the 
+ * value of the last key to be retrieved using <code>nextElement()</code>.  
+ * The <code>nextElement()</code> method must be called before the 
+ * <code>getValue()</code> method.
+ *
+ * <p>The iteration can be made efficient by making use of the fact that values in 
+ * the cache (instances of <code>LRUCacheEntry</code>), know their key.  For this reason,
+ * Hashtable lookups don't have to be made at each step of the iteration.
+ *
+ * <p>Modifications to the cache must not be performed while using the
+ * enumeration.  Doing so will lead to an illegal state.
+ *
+ * @see LRUCache
+ */
+public interface ICacheEnumeration extends Enumeration {
+       /**
+        * Returns the value of the previously accessed key in the enumeration.
+        * Must be called after a call to nextElement().
+        *
+        * @return Value of current cache entry
+        */
+       public Object getValue();
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/util/ILRUCacheable.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/util/ILRUCacheable.java
new file mode 100644 (file)
index 0000000..d6da8b9
--- /dev/null
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * 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.core.util;
+
+/**
+ * Types implementing this interface can occupy a variable amount of space
+ * in an LRUCache.  Cached items that do not implement this interface are
+ * considered to occupy one unit of space.
+ *
+ * @see LRUCache
+ */
+public interface ILRUCacheable {
+       /**
+        * Returns the space the receiver consumes in an LRU Cache.  The default space
+        * value is 1.
+        *
+        * @return int Amount of cache space taken by the receiver
+        */
+       public int getCacheFootprint();
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/util/LRUCache.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/util/LRUCache.java
new file mode 100644 (file)
index 0000000..5d715ce
--- /dev/null
@@ -0,0 +1,499 @@
+/*******************************************************************************
+ * 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.core.util;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+/**
+ * The <code>LRUCache</code> is a hashtable that stores a finite number of elements.  
+ * When an attempt is made to add values to a full cache, the least recently used values
+ * in the cache are discarded to make room for the new values as necessary.
+ * 
+ * <p>The data structure is based on the LRU virtual memory paging scheme.
+ * 
+ * <p>Objects can take up a variable amount of cache space by implementing
+ * the <code>ILRUCacheable</code> interface.
+ *
+ * <p>This implementation is NOT thread-safe.  Synchronization wrappers would
+ * have to be added to ensure atomic insertions and deletions from the cache.
+ *
+ * @see org.eclipse.jdt.internal.core.util.ILRUCacheable
+ */
+public class LRUCache implements Cloneable {
+
+       /**
+        * This type is used internally by the LRUCache to represent entries 
+        * stored in the cache.
+        * It is static because it does not require a pointer to the cache
+        * which contains it.
+        *
+        * @see LRUCache
+        */
+       protected static class LRUCacheEntry {
+               
+               /**
+                * Hash table key
+                */
+               public Object _fKey;
+                
+               /**
+                * Hash table value (an LRUCacheEntry object)
+                */
+               public Object _fValue;           
+
+               /**
+                * Time value for queue sorting
+                */
+               public int _fTimestamp;
+               
+               /**
+                * Cache footprint of this entry
+                */
+               public int _fSpace;
+               
+               /**
+                * Previous entry in queue
+                */
+               public LRUCacheEntry _fPrevious;
+                       
+               /**
+                * Next entry in queue
+                */
+               public LRUCacheEntry _fNext;
+                       
+               /**
+                * Creates a new instance of the receiver with the provided values
+                * for key, value, and space.
+                */
+               public LRUCacheEntry (Object key, Object value, int space) {
+                       _fKey = key;
+                       _fValue = value;
+                       _fSpace = space;
+               }
+
+               /**
+                * Returns a String that represents the value of this object.
+                */
+               public String toString() {
+
+                       return "LRUCacheEntry [" + _fKey + "-->" + _fValue + "]"; //$NON-NLS-3$ //$NON-NLS-1$ //$NON-NLS-2$
+               }
+       }       
+
+       /**
+        * Amount of cache space used so far
+        */
+       protected int fCurrentSpace;
+       
+       /**
+        * Maximum space allowed in cache
+        */
+       protected int fSpaceLimit;
+       
+       /**
+        * Counter for handing out sequential timestamps
+        */
+       protected int   fTimestampCounter;
+       
+       /**
+        * Hash table for fast random access to cache entries
+        */
+       protected Hashtable fEntryTable;
+
+       /**
+        * Start of queue (most recently used entry) 
+        */     
+       protected LRUCacheEntry fEntryQueue;
+
+       /**
+        * End of queue (least recently used entry)
+        */     
+       protected LRUCacheEntry fEntryQueueTail;
+               
+       /**
+        * Default amount of space in the cache
+        */
+       protected static final int DEFAULT_SPACELIMIT = 100;
+       /**
+        * Creates a new cache.  Size of cache is defined by 
+        * <code>DEFAULT_SPACELIMIT</code>.
+        */
+       public LRUCache() {
+               
+               this(DEFAULT_SPACELIMIT);
+       }
+       /**
+        * Creates a new cache.
+        * @param size Size of Cache
+        */
+       public LRUCache(int size) {
+               
+               fTimestampCounter = fCurrentSpace = 0;
+               fEntryQueue = fEntryQueueTail = null;
+               fEntryTable = new Hashtable(size);
+               fSpaceLimit = size;
+       }
+       /**
+        * Returns a new cache containing the same contents.
+        *
+        * @return New copy of object.
+        */
+       public Object clone() {
+               
+               LRUCache newCache = newInstance(fSpaceLimit);
+               LRUCacheEntry qEntry;
+               
+               /* Preserve order of entries by copying from oldest to newest */
+               qEntry = this.fEntryQueueTail;
+               while (qEntry != null) {
+                       newCache.privateAdd (qEntry._fKey, qEntry._fValue, qEntry._fSpace);
+                       qEntry = qEntry._fPrevious;
+               }
+               return newCache;
+       }
+       /**
+        * Flushes all entries from the cache.
+        */
+       public void flush() {
+
+               fCurrentSpace = 0;
+               LRUCacheEntry entry = fEntryQueueTail; // Remember last entry
+               fEntryTable = new Hashtable();  // Clear it out
+               fEntryQueue = fEntryQueueTail = null;  
+               while (entry != null) {  // send deletion notifications in LRU order
+                       privateNotifyDeletionFromCache(entry);
+                       entry = entry._fPrevious;
+               }
+       }
+       /**
+        * Flushes the given entry from the cache.  Does nothing if entry does not
+        * exist in cache.
+        *
+        * @param key Key of object to flush
+        */
+       public void flush (Object key) {
+               
+               LRUCacheEntry entry;
+               
+               entry = (LRUCacheEntry) fEntryTable.get(key);
+
+               /* If entry does not exist, return */
+               if (entry == null) return;
+
+               this.privateRemoveEntry (entry, false);
+       }
+       /**
+        * Answers the value in the cache at the given key.
+        * If the value is not in the cache, returns null
+        *
+        * @param key Hash table key of object to retrieve
+        * @return Retreived object, or null if object does not exist
+        */
+       public Object get(Object key) {
+               
+               LRUCacheEntry entry = (LRUCacheEntry) fEntryTable.get(key);
+               if (entry == null) {
+                       return null;
+               }
+               
+               this.updateTimestamp (entry);
+               return entry._fValue;
+       }
+       /**
+        * Returns the amount of space that is current used in the cache.
+        */
+       public int getCurrentSpace() {
+               return fCurrentSpace;
+       }
+       /**
+        * Returns the maximum amount of space available in the cache.
+        */
+       public int getSpaceLimit() {
+               return fSpaceLimit;
+       }
+       /**
+        * Returns an Enumeration of the keys currently in the cache.
+        */
+       public Enumeration keys() {
+               
+               return fEntryTable.keys();
+       }
+       /**
+        * Returns an enumeration that iterates over all the keys and values 
+        * currently in the cache.
+        */
+       public ICacheEnumeration keysAndValues() {
+               return new ICacheEnumeration() {
+               
+                       Enumeration fValues = fEntryTable.elements();
+                       LRUCacheEntry fEntry;
+                       
+                       public boolean hasMoreElements() {
+                               return fValues.hasMoreElements();
+                       }
+                       
+                       public Object nextElement() {
+                               fEntry = (LRUCacheEntry) fValues.nextElement();
+                               return fEntry._fKey;
+                       }
+                       
+                       public Object getValue() {
+                               if (fEntry == null) {
+                                       throw new java.util.NoSuchElementException();
+                               }
+                               return fEntry._fValue;
+                       }
+               };
+       }
+       /**
+        * Ensures there is the specified amount of free space in the receiver,
+        * by removing old entries if necessary.  Returns true if the requested space was
+        * made available, false otherwise.
+        *
+        * @param space Amount of space to free up
+        */
+       protected boolean makeSpace (int space) {
+               
+               int limit;
+               
+               limit = this.getSpaceLimit();
+               
+               /* if space is already available */
+               if (fCurrentSpace + space <= limit) {
+                       return true;
+               }
+               
+               /* if entry is too big for cache */
+               if (space > limit) {
+                       return false;
+               }
+               
+               /* Free up space by removing oldest entries */
+               while (fCurrentSpace + space > limit && fEntryQueueTail != null) {
+                       this.privateRemoveEntry (fEntryQueueTail, false);
+               }
+               return true;
+       }
+       /**
+        * Returns a new LRUCache instance
+        */
+       protected LRUCache newInstance(int size) {
+               return new LRUCache(size);
+       }
+       /**
+        * Adds an entry for the given key/value/space.
+        */
+       protected void privateAdd (Object key, Object value, int space) {
+               
+               LRUCacheEntry entry;
+               
+               entry = new LRUCacheEntry(key, value, space);
+               this.privateAddEntry (entry, false);
+       }
+       /**
+        * Adds the given entry from the receiver.
+        * @param shuffle Indicates whether we are just shuffling the queue 
+        * (in which case, the entry table is not modified).
+        */
+       protected void privateAddEntry (LRUCacheEntry entry, boolean shuffle) {
+               
+               if (!shuffle) {
+                       fEntryTable.put (entry._fKey, entry);
+                       fCurrentSpace += entry._fSpace;
+               }
+               
+               entry._fTimestamp = fTimestampCounter++;
+               entry._fNext = this.fEntryQueue;
+               entry._fPrevious = null;
+               
+               if (fEntryQueue == null) {
+                       /* this is the first and last entry */
+                       fEntryQueueTail = entry;
+               } else {
+                       fEntryQueue._fPrevious = entry;
+               }
+               
+               fEntryQueue = entry;
+       }
+       /**
+        * An entry has been removed from the cache, for example because it has 
+        * fallen off the bottom of the LRU queue.  
+        * Subclasses could over-ride this to implement a persistent cache below the LRU cache.
+        */
+       protected void privateNotifyDeletionFromCache(LRUCacheEntry entry) {
+               // Default is NOP.
+       }
+       /**
+        * Removes the entry from the entry queue.  
+        * @param shuffle indicates whether we are just shuffling the queue 
+        * (in which case, the entry table is not modified).
+        */
+       protected void privateRemoveEntry (LRUCacheEntry entry, boolean shuffle) {
+               
+               LRUCacheEntry previous, next;
+               
+               previous = entry._fPrevious;
+               next = entry._fNext;
+               
+               if (!shuffle) {
+                       fEntryTable.remove(entry._fKey);
+                       fCurrentSpace -= entry._fSpace;
+                       privateNotifyDeletionFromCache(entry);
+               }
+
+               /* if this was the first entry */
+               if (previous == null) {
+                       fEntryQueue = next;
+               } else {
+                       previous._fNext = next;
+               }
+
+               /* if this was the last entry */
+               if (next == null) {
+                       fEntryQueueTail = previous;
+               } else {
+                       next._fPrevious = previous;
+               }
+       }
+       /**
+        * Sets the value in the cache at the given key. Returns the value.
+        *
+        * @param key Key of object to add.
+        * @param value Value of object to add.
+        * @return added value.
+        */
+       public Object put(Object key, Object value) {
+               
+               int newSpace, oldSpace, newTotal;
+               LRUCacheEntry entry;
+               
+               /* Check whether there's an entry in the cache */
+               newSpace = spaceFor (key, value);
+               entry = (LRUCacheEntry) fEntryTable.get (key);
+               
+               if (entry != null) {
+                       
+                       /**
+                        * Replace the entry in the cache if it would not overflow
+                        * the cache.  Otherwise flush the entry and re-add it so as 
+                        * to keep cache within budget
+                        */
+                       oldSpace = entry._fSpace;
+                       newTotal = getCurrentSpace() - oldSpace + newSpace;
+                       if (newTotal <= getSpaceLimit()) {
+                               updateTimestamp (entry);
+                               entry._fValue = value;
+                               entry._fSpace = newSpace;
+                               this.fCurrentSpace = newTotal;
+                               return value;
+                       } else {
+                               privateRemoveEntry (entry, false);
+                       }
+               }
+               if (makeSpace(newSpace)) {
+                       privateAdd (key, value, newSpace);
+               }
+               return value;
+       }
+       /**
+        * Removes and returns the value in the cache for the given key.
+        * If the key is not in the cache, returns null.
+        *
+        * @param key Key of object to remove from cache.
+        * @return Value removed from cache.
+        */
+       public Object removeKey (Object key) {
+               
+               LRUCacheEntry entry = (LRUCacheEntry) fEntryTable.get(key);
+               if (entry == null) {
+                       return null;
+               }
+               Object value = entry._fValue;
+               this.privateRemoveEntry (entry, false);
+               return value;
+       }
+       /**
+        * Sets the maximum amount of space that the cache can store
+        *
+        * @param limit Number of units of cache space
+        */
+       public void setSpaceLimit(int limit) {
+               if (limit < fSpaceLimit) {
+                       makeSpace(fSpaceLimit - limit);
+               }
+               fSpaceLimit = limit;
+       }
+       /**
+        * Returns the space taken by the given key and value.
+        */
+       protected int spaceFor (Object key, Object value) {
+               
+               if (value instanceof ILRUCacheable) {
+                       return ((ILRUCacheable) value).getCacheFootprint();
+               } else {
+                       return 1;
+               }
+       }
+/**
+ * Returns a String that represents the value of this object.  This method
+ * is for debugging purposes only.
+ */
+public String toString() {
+       return 
+               "LRUCache " + (fCurrentSpace * 100.0 / fSpaceLimit) + "% full\n" + //$NON-NLS-1$ //$NON-NLS-2$
+               this.toStringContents();
+}
+/**
+ * Returns a String that represents the contents of this object.  This method
+ * is for debugging purposes only.
+ */
+protected String toStringContents() {
+       StringBuffer result = new StringBuffer();
+       int length = fEntryTable.size();
+       Object[] unsortedKeys = new Object[length];
+       String[] unsortedToStrings = new String[length];
+       Enumeration e = this.keys();
+       for (int i = 0; i < length; i++) {
+               Object key = e.nextElement();
+               unsortedKeys[i] = key;
+//             unsortedToStrings[i] = 
+//                     (key instanceof org.eclipse.jdt.internal.core.JavaElement) ?
+//                             ((org.eclipse.jdt.internal.core.JavaElement)key).getElementName() :
+//                             key.toString();
+               unsortedToStrings[i] = key.toString();
+       }
+       ToStringSorter sorter = new ToStringSorter();
+       sorter.sort(unsortedKeys, unsortedToStrings);
+       for (int i = 0; i < length; i++) {
+               String toString = sorter.sortedStrings[i];
+               Object value = this.get(sorter.sortedObjects[i]);
+               result.append(toString);                
+               result.append(" -> "); //$NON-NLS-1$
+               result.append(value);
+               result.append("\n"); //$NON-NLS-1$
+       }
+       return result.toString();
+}
+       /**
+        * Updates the timestamp for the given entry, ensuring that the queue is 
+        * kept in correct order.  The entry must exist
+        */
+       protected void updateTimestamp (LRUCacheEntry entry) {
+               
+               entry._fTimestamp = fTimestampCounter++;
+               if (fEntryQueue != entry) {
+                       this.privateRemoveEntry (entry, true);
+                       this.privateAddEntry (entry, true);
+               }
+               return;
+       }
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/util/ToStringSorter.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/util/ToStringSorter.java
new file mode 100644 (file)
index 0000000..ce4ed4f
--- /dev/null
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * 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.core.util;
+
+/**
+ * The SortOperation takes a collection of objects and returns
+ * a sorted collection of these objects. The sorting of these
+ * objects is based on their toString(). They are sorted in
+ * alphabetical order.
+ */
+public class ToStringSorter {
+       Object[] sortedObjects;
+       String[] sortedStrings;
+/**
+ *  Returns true if stringTwo is 'greater than' stringOne
+ *  This is the 'ordering' method of the sort operation.
+ */
+public boolean compare(String stringOne, String stringTwo) {
+       return stringOne.compareTo(stringTwo) < 0;
+}
+/**
+ *  Sort the objects in sorted collection and return that collection.
+ */
+private void quickSort(int left, int right) {
+       int originalLeft = left;
+       int originalRight = right;
+       int midIndex =  (left + right) / 2;
+       String midToString = this.sortedStrings[midIndex];
+       
+       do {
+               while (compare(this.sortedStrings[left], midToString))
+                       left++;
+               while (compare(midToString, this.sortedStrings[right]))
+                       right--;
+               if (left <= right) {
+                       Object tmp = this.sortedObjects[left];
+                       this.sortedObjects[left] = this.sortedObjects[right];
+                       this.sortedObjects[right] = tmp;
+                       String tmpToString = this.sortedStrings[left];
+                       this.sortedStrings[left] = this.sortedStrings[right];
+                       this.sortedStrings[right] = tmpToString;
+                       left++;
+                       right--;
+               }
+       } while (left <= right);
+       
+       if (originalLeft < right)
+               quickSort(originalLeft, right);
+       if (left < originalRight)
+               quickSort(left, originalRight);
+}
+/**
+ *  Return a new sorted collection from this unsorted collection.
+ *  Sort using quick sort.
+ */
+public void sort(Object[] unSortedObjects, String[] unsortedStrings) {
+       int size = unSortedObjects.length;
+       this.sortedObjects = new Object[size];
+       this.sortedStrings = new String[size];
+       
+       //copy the array so can return a new sorted collection  
+       System.arraycopy(unSortedObjects, 0, this.sortedObjects, 0, size);
+       System.arraycopy(unsortedStrings, 0, this.sortedStrings, 0, size);
+       if (size > 1)
+               quickSort(0, size - 1);
+}
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/Buffer.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/Buffer.java
new file mode 100644 (file)
index 0000000..c26691d
--- /dev/null
@@ -0,0 +1,441 @@
+/*******************************************************************************
+ * 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.internal.core;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+
+import net.sourceforge.phpdt.core.BufferChangedEvent;
+import net.sourceforge.phpdt.core.IBuffer;
+import net.sourceforge.phpdt.core.IBufferChangedListener;
+import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
+import net.sourceforge.phpdt.core.IOpenable;
+import net.sourceforge.phpdt.core.JavaModelException;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.Platform;
+
+/**
+ * @see IBuffer
+ */
+public class Buffer implements IBuffer {
+       protected IFile file;
+       protected int flags;
+       protected char[] contents;
+       protected ArrayList changeListeners;
+       protected IOpenable owner;
+       protected int gapStart= -1;
+       protected int gapEnd= -1;
+
+       protected Object lock= new Object();
+
+       protected static final int F_HAS_UNSAVED_CHANGES= 1;
+       protected static final int F_IS_READ_ONLY= 2;
+       protected static final int F_IS_CLOSED= 4;
+
+/**
+ * Creates a new buffer on an underlying resource.
+ */
+protected Buffer(IFile file, IOpenable owner, boolean readOnly) {
+       this.file = file;
+       this.owner = owner;
+       if (file == null) {
+               setReadOnly(readOnly);
+       }
+}
+/**
+ * @see IBuffer
+ */
+public void addBufferChangedListener(IBufferChangedListener listener) {
+       if (this.changeListeners == null) {
+               this.changeListeners = new ArrayList(5);
+       }
+       if (!this.changeListeners.contains(listener)) {
+               this.changeListeners.add(listener);
+       }
+}
+/**
+ * Append the <code>text</code> to the actual content, the gap is moved
+ * to the end of the <code>text</code>.
+ */
+public void append(char[] text) {
+       if (!isReadOnly()) {
+               if (text == null || text.length == 0) {
+                       return;
+               }
+               int length = getLength();
+               moveAndResizeGap(length, text.length);
+               System.arraycopy(text, 0, this.contents, length, text.length);
+               this.gapStart += text.length;
+               this.flags |= F_HAS_UNSAVED_CHANGES;
+               notifyChanged(new BufferChangedEvent(this, length, 0, new String(text)));
+       }
+}
+/**
+ * Append the <code>text</code> to the actual content, the gap is moved
+ * to the end of the <code>text</code>.
+ */
+public void append(String text) {
+       if (text == null) {
+               return;
+       }
+       this.append(text.toCharArray());
+}
+/**
+ * @see IBuffer
+ */
+public void close() throws IllegalArgumentException {
+       BufferChangedEvent event = null;
+       synchronized (this.lock) {
+               if (isClosed())
+                       return;
+               event = new BufferChangedEvent(this, 0, 0, null);
+               this.contents = null;
+               this.flags |= F_IS_CLOSED;
+       }
+       notifyChanged(event); // notify outside of synchronized block
+       this.changeListeners = null;
+}
+/**
+ * @see IBuffer
+ */
+public char getChar(int position) {
+       synchronized (this.lock) {
+               if (position < this.gapStart) {
+                       return this.contents[position];
+               }
+               int gapLength = this.gapEnd - this.gapStart;
+               return this.contents[position + gapLength];
+       }
+}
+/**
+ * @see IBuffer
+ */
+public char[] getCharacters() {
+       if (this.contents == null) return null;
+       synchronized (this.lock) {
+               if (this.gapStart < 0) {
+                       return this.contents;
+               }
+               int length = this.contents.length;
+               char[] newContents = new char[length - this.gapEnd + this.gapStart];
+               System.arraycopy(this.contents, 0, newContents, 0, this.gapStart);
+               System.arraycopy(this.contents, this.gapEnd, newContents, this.gapStart, length - this.gapEnd);
+               return newContents;
+       }
+}
+/**
+ * @see IBuffer
+ */
+public String getContents() {
+       char[] chars = this.getCharacters();
+       if (chars == null) return null;
+       return new String(chars);
+}
+/**
+ * @see IBuffer
+ */
+public int getLength() {
+       synchronized (this.lock) {
+               int length = this.gapEnd - this.gapStart;
+               return (this.contents.length - length);
+       }
+}
+/**
+ * @see IBuffer
+ */
+public IOpenable getOwner() {
+       return this.owner;
+}
+/**
+ * @see IBuffer
+ */
+public String getText(int offset, int length) {
+       if (this.contents == null)
+               return ""; //$NON-NLS-1$
+       synchronized (this.lock) {
+               if (offset + length < this.gapStart)
+                       return new String(this.contents, offset, length);
+               if (this.gapStart < offset) {
+                       int gapLength = this.gapEnd - this.gapStart;
+                       return new String(this.contents, offset + gapLength, length);
+               }
+               StringBuffer buf = new StringBuffer();
+               buf.append(this.contents, offset, this.gapStart - offset);
+               buf.append(this.contents, this.gapEnd, offset + length - this.gapStart);
+               return buf.toString();
+       }
+}
+/**
+ * @see IBuffer
+ */
+public IResource getUnderlyingResource() {
+       return this.file;
+}
+/**
+ * @see IBuffer
+ */
+public boolean hasUnsavedChanges() {
+       return (this.flags & F_HAS_UNSAVED_CHANGES) != 0;
+}
+/**
+ * @see IBuffer
+ */
+public boolean isClosed() {
+       return (this.flags & F_IS_CLOSED) != 0;
+}
+/**
+ * @see IBuffer
+ */
+public boolean isReadOnly() {
+       if (this.file == null) {
+               return (this.flags & F_IS_READ_ONLY) != 0;
+       } else {
+               return this.file.isReadOnly();
+       }
+}
+/**
+ * Moves the gap to location and adjust its size to the
+ * anticipated change size. The size represents the expected 
+ * range of the gap that will be filled after the gap has been moved.
+ * Thus the gap is resized to actual size + the specified size and
+ * moved to the given position.
+ */
+protected void moveAndResizeGap(int position, int size) {
+       char[] content = null;
+       int oldSize = this.gapEnd - this.gapStart;
+       if (size < 0) {
+               if (oldSize > 0) {
+                       content = new char[this.contents.length - oldSize];
+                       System.arraycopy(this.contents, 0, content, 0, this.gapStart);
+                       System.arraycopy(this.contents, this.gapEnd, content, this.gapStart, content.length - this.gapStart);
+                       this.contents = content;
+               }
+               this.gapStart = this.gapEnd = position;
+               return;
+       }
+       content = new char[this.contents.length + (size - oldSize)];
+       int newGapStart = position;
+       int newGapEnd = newGapStart + size;
+       if (oldSize == 0) {
+               System.arraycopy(this.contents, 0, content, 0, newGapStart);
+               System.arraycopy(this.contents, newGapStart, content, newGapEnd, content.length - newGapEnd);
+       } else
+               if (newGapStart < this.gapStart) {
+                       int delta = this.gapStart - newGapStart;
+                       System.arraycopy(this.contents, 0, content, 0, newGapStart);
+                       System.arraycopy(this.contents, newGapStart, content, newGapEnd, delta);
+                       System.arraycopy(this.contents, this.gapEnd, content, newGapEnd + delta, this.contents.length - this.gapEnd);
+               } else {
+                       int delta = newGapStart - this.gapStart;
+                       System.arraycopy(this.contents, 0, content, 0, this.gapStart);
+                       System.arraycopy(this.contents, this.gapEnd, content, this.gapStart, delta);
+                       System.arraycopy(this.contents, this.gapEnd + delta, content, newGapEnd, content.length - newGapEnd);
+               }
+       this.contents = content;
+       this.gapStart = newGapStart;
+       this.gapEnd = newGapEnd;
+}
+/**
+ * Notify the listeners that this buffer has changed.
+ * To avoid deadlock, this should not be called in a synchronized block.
+ */
+protected void notifyChanged(final BufferChangedEvent event) {
+       if (this.changeListeners != null) {
+               for (int i = 0, size = this.changeListeners.size(); i < size; ++i) {
+                       final IBufferChangedListener listener = (IBufferChangedListener) this.changeListeners.get(i);
+                       Platform.run(new ISafeRunnable() {
+                               public void handleException(Throwable exception) {
+                                       Util.log(exception, "Exception occurred in listener of buffer change notification"); //$NON-NLS-1$
+                               }
+                               public void run() throws Exception {
+                                       listener.bufferChanged(event);
+                               }
+                       });
+                       
+               }
+       }
+}
+/**
+ * @see IBuffer
+ */
+public void removeBufferChangedListener(IBufferChangedListener listener) {
+       if (this.changeListeners != null) {
+               this.changeListeners.remove(listener);
+               if (this.changeListeners.size() == 0) {
+                       this.changeListeners = null;
+               }
+       }
+}
+/**
+ * Replaces <code>length</code> characters starting from <code>position</code> with <code>text<code>.
+ * After that operation, the gap is placed at the end of the 
+ * inserted <code>text</code>.
+ */
+public void replace(int position, int length, char[] text) {
+       if (!isReadOnly()) {
+               int textLength = text == null ? 0 : text.length;
+               synchronized (this.lock) {
+                       // move gap
+                       moveAndResizeGap(position + length, textLength - length);
+
+                       // overwrite
+                       int min = Math.min(textLength, length);
+                       if (min > 0) {
+                               System.arraycopy(text, 0, this.contents, position, min);
+                       }
+                       if (length > textLength) {
+                               // enlarge the gap
+                               this.gapStart -= length - textLength;
+                       } else if (textLength > length) {
+                               // shrink gap
+                               this.gapStart += textLength - length;
+                               System.arraycopy(text, 0, this.contents, position, textLength);
+                       }
+               }
+               this.flags |= F_HAS_UNSAVED_CHANGES;
+               String string = null;
+               if (textLength > 0) {
+                       string = new String(text);
+               }
+               notifyChanged(new BufferChangedEvent(this, position, length, string));
+       }
+}
+/**
+ * Replaces <code>length</code> characters starting from <code>position</code> with <code>text<code>.
+ * After that operation, the gap is placed at the end of the 
+ * inserted <code>text</code>.
+ */
+public void replace(int position, int length, String text) {
+       this.replace(position, length, text == null ? null : text.toCharArray());
+}
+/**
+ * @see IBuffer
+ */
+public void save(IProgressMonitor progress, boolean force) throws JavaModelException {
+
+       // determine if saving is required 
+       if (isReadOnly() || this.file == null) {
+               return;
+       }
+       synchronized (this.lock) {
+               if (!hasUnsavedChanges())
+                       return;
+                       
+               // use a platform operation to update the resource contents
+               try {
+//                     String encoding = ((IJavaElement)this.owner).getJavaProject().getOption(PHPCore.CORE_ENCODING, true);
+                       String encoding = null;
+                       String contents = this.getContents();
+                       if (contents == null) return;
+                       byte[] bytes = encoding == null 
+                               ? contents.getBytes() 
+                               : contents.getBytes(encoding);
+                       ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
+
+                       this.file.setContents(
+                               stream, 
+                               force ? IResource.FORCE | IResource.KEEP_HISTORY : IResource.KEEP_HISTORY, 
+                               null);
+               } catch (IOException e) {
+                       throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
+               } catch (CoreException e) {
+                       throw new JavaModelException(e);
+               }
+
+               // the resource no longer has unsaved changes
+               this.flags &= ~ (F_HAS_UNSAVED_CHANGES);
+       }
+}
+/**
+ * @see IBuffer
+ */
+public void setContents(char[] newContents) {
+       // allow special case for first initialization 
+       // after creation by buffer factory
+       if (this.contents == null) {
+               this.contents = newContents;
+               this.flags &= ~ (F_HAS_UNSAVED_CHANGES);
+               return;
+       }
+       
+       if (!isReadOnly()) {
+               String string = null;
+               if (newContents != null) {
+                       string = new String(newContents);
+               }
+               BufferChangedEvent event = new BufferChangedEvent(this, 0, this.getLength(), string);
+               synchronized (this.lock) {
+                       this.contents = newContents;
+                       this.flags |= F_HAS_UNSAVED_CHANGES;
+                       this.gapStart = -1;
+                       this.gapEnd = -1;
+               }
+               notifyChanged(event);
+       }
+}
+/**
+ * @see IBuffer
+ */
+public void setContents(String newContents) {
+       this.setContents(newContents.toCharArray());
+}
+/**
+ * Sets this <code>Buffer</code> to be read only.
+ */
+protected void setReadOnly(boolean readOnly) {
+       if (readOnly) {
+               this.flags |= F_IS_READ_ONLY;
+       } else {
+               this.flags &= ~(F_IS_READ_ONLY);
+       }
+}
+public String toString() {
+       StringBuffer buffer = new StringBuffer();
+//     buffer.append("Owner: " + ((JavaElement)this.owner).toStringWithAncestors()); //$NON-NLS-1$
+       buffer.append("Owner: " + (this.owner).toString()); //$NON-NLS-1$
+       buffer.append("\nHas unsaved changes: " + this.hasUnsavedChanges()); //$NON-NLS-1$
+       buffer.append("\nIs readonly: " + this.isReadOnly()); //$NON-NLS-1$
+       buffer.append("\nIs closed: " + this.isClosed()); //$NON-NLS-1$
+       buffer.append("\nContents:\n"); //$NON-NLS-1$
+       char[] contents = this.getCharacters();
+       if (contents == null) {
+               buffer.append("<null>"); //$NON-NLS-1$
+       } else {
+               int length = contents.length;
+               for (int i = 0; i < length; i++) {
+                       char car = contents[i];
+                       switch (car) {
+                               case '\n': 
+                                       buffer.append("\\n\n"); //$NON-NLS-1$
+                                       break;
+                               case '\r':
+                                       if (i < length-1 && this.contents[i+1] == '\n') {
+                                               buffer.append("\\r\\n\n"); //$NON-NLS-1$
+                                               i++;
+                                       } else {
+                                               buffer.append("\\r\n"); //$NON-NLS-1$
+                                       }
+                                       break;
+                               default:
+                                       buffer.append(car);
+                                       break;
+                       }
+               }
+       }
+       return buffer.toString();
+}
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/BufferCache.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/BufferCache.java
new file mode 100644 (file)
index 0000000..62ad8f0
--- /dev/null
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * 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.internal.core;
+
+import net.sourceforge.phpdt.core.IBuffer;
+import net.sourceforge.phpdt.core.util.LRUCache;
+
+/**
+ * An LRU cache of <code>IBuffers</code>.
+ */
+public class BufferCache extends OverflowingLRUCache {
+/**
+ * Constructs a new buffer cache of the given size.
+ */
+public BufferCache(int size) {
+       super(size);
+}
+/**
+ * Constructs a new buffer cache of the given size.
+ */
+public BufferCache(int size, int overflow) {
+       super(size, overflow);
+}
+/**
+ * Returns true if the buffer is successfully closed and
+ * removed from the cache, otherwise false.
+ *
+ * <p>NOTE: this triggers an external removal of this buffer
+ * by closing the buffer.
+ */
+protected boolean close(LRUCacheEntry entry) {
+       IBuffer buffer= (IBuffer) entry._fValue;
+       if (buffer.hasUnsavedChanges()) {
+               return false;
+       } else {
+               buffer.close();
+               return true;
+       }
+}
+       /**
+        * Returns a new instance of the reciever.
+        */
+       protected LRUCache newInstance(int size, int overflow) {
+               return new BufferCache(size, overflow);
+       }
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/BufferManager.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/BufferManager.java
new file mode 100644 (file)
index 0000000..511d041
--- /dev/null
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * 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.internal.core;
+
+import java.util.Enumeration;
+
+import net.sourceforge.phpdt.core.IBuffer;
+import net.sourceforge.phpdt.core.IBufferFactory;
+import net.sourceforge.phpdt.core.IJavaElement;
+import net.sourceforge.phpdt.core.IOpenable;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+
+
+/**
+ * The buffer manager manages the set of open buffers.
+ * It implements an LRU cache of buffers.
+ */
+public class BufferManager implements IBufferFactory {
+
+       protected static BufferManager DEFAULT_BUFFER_MANAGER;
+
+       /**
+        * LRU cache of buffers. The key and value for an entry
+        * in the table is the identical buffer.
+        */
+       protected OverflowingLRUCache openBuffers = new BufferCache(60);
+
+/**
+ * Creates a new buffer manager.
+ */
+public BufferManager() {
+}
+/**
+ * Adds a buffer to the table of open buffers.
+ */
+protected void addBuffer(IBuffer buffer) {
+       openBuffers.put(buffer.getOwner(), buffer);
+}
+/**
+ * @see IBufferFactory#createBuffer(IOpenable)
+ */
+public IBuffer createBuffer(IOpenable owner) {
+       IJavaElement element = (IJavaElement)owner;
+       IResource resource = element.getResource();
+       return 
+               new Buffer(
+                       resource instanceof IFile ? (IFile)resource : null, 
+                       owner, 
+                       element.isReadOnly());
+}
+
+/**
+ * Returns the open buffer associated with the given owner,
+ * or <code>null</code> if the owner does not have an open
+ * buffer associated with it.
+ */
+public IBuffer getBuffer(IOpenable owner) {
+       return (IBuffer)openBuffers.get(owner);
+}
+/**
+ * Returns the default buffer manager.
+ */
+public synchronized static BufferManager getDefaultBufferManager() {
+       if (DEFAULT_BUFFER_MANAGER == null) {
+               DEFAULT_BUFFER_MANAGER = new BufferManager();
+       }
+       return DEFAULT_BUFFER_MANAGER;
+}
+/**
+ * Returns the default buffer factory.
+ */
+public IBufferFactory getDefaultBufferFactory() {
+       return this;
+}
+/**
+ * Returns an enumeration of all open buffers.
+ * <p> 
+ * The <code>Enumeration</code> answered is thread safe.
+ *
+ * @see OverflowingLRUCache
+ * @return Enumeration of IBuffer
+ */
+public Enumeration getOpenBuffers() {
+       synchronized (openBuffers) {
+               openBuffers.shrink();
+               return openBuffers.elements();
+       }
+}
+
+
+/**
+ * Removes a buffer from the table of open buffers.
+ */
+protected void removeBuffer(IBuffer buffer) {
+       openBuffers.remove(buffer.getOwner());
+}
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/JavaElement.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/JavaElement.java
new file mode 100644 (file)
index 0000000..590b8db
--- /dev/null
@@ -0,0 +1,654 @@
+/*******************************************************************************
+ * 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.internal.core;
+
+import net.sourceforge.phpdt.core.IJavaElement;
+import net.sourceforge.phpdt.core.IJavaModel;
+import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
+import net.sourceforge.phpdt.core.IOpenable;
+import net.sourceforge.phpdt.core.IParent;
+import net.sourceforge.phpdt.core.JavaModelException;
+import net.sourceforge.phpdt.internal.corext.Assert;
+
+import org.eclipse.core.resources.IResourceStatus;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.PlatformObject;
+
+/**
+ * Root of Java element handle hierarchy.
+ *
+ * @see IJavaElement
+ */
+public abstract class JavaElement extends PlatformObject implements IJavaElement {
+
+       public static final char JEM_JAVAPROJECT= '=';
+       public static final char JEM_PACKAGEFRAGMENTROOT= Path.SEPARATOR;
+       public static final char JEM_PACKAGEFRAGMENT= '<';
+       public static final char JEM_FIELD= '^';
+       public static final char JEM_METHOD= '~';
+       public static final char JEM_INITIALIZER= '|';
+       public static final char JEM_COMPILATIONUNIT= '{';
+       public static final char JEM_CLASSFILE= '(';
+       public static final char JEM_TYPE= '[';
+       public static final char JEM_PACKAGEDECLARATION= '%';
+       public static final char JEM_IMPORTDECLARATION= '#';
+
+       /**
+        * A count to uniquely identify this element in the case
+        * that a duplicate named element exists. For example, if
+        * there are two fields in a compilation unit with the
+        * same name, the occurrence count is used to distinguish
+        * them.  The occurrence count starts at 1 (thus the first 
+        * occurrence is occurrence 1, not occurrence 0).
+        */
+       protected int fOccurrenceCount = 1;
+
+
+       /**
+        * This element's type - one of the constants defined
+        * in IJavaLanguageElementTypes.
+        */
+       protected int fLEType = 0;
+
+       /**
+        * This element's parent, or <code>null</code> if this
+        * element does not have a parent.
+        */
+       protected IJavaElement fParent;
+
+       /**
+        * This element's name, or an empty <code>String</code> if this
+        * element does not have a name.
+        */
+       protected String fName;
+
+       protected static final Object NO_INFO = new Object();
+       
+       /**
+        * Constructs a handle for a java element of the specified type, with
+        * the given parent element and name.
+        *
+        * @param type - one of the constants defined in IJavaLanguageElement
+        *
+        * @exception IllegalArgumentException if the type is not one of the valid
+        *              Java element type constants
+        *
+        */
+       protected JavaElement(int type, IJavaElement parent, String name) throws IllegalArgumentException {
+               if (type < JAVA_MODEL || type > IMPORT_DECLARATION) {
+                       throw new IllegalArgumentException(Util.bind("element.invalidType")); //$NON-NLS-1$
+               }
+               fLEType= type;
+               fParent= parent;
+               fName= name;
+       }
+       /**
+        * @see IOpenable
+        */
+//     public void close() throws JavaModelException {
+//             Object info = JavaModelManager.getJavaModelManager().peekAtInfo(this);
+//             if (info != null) {
+//                     boolean wasVerbose = false;
+//                     try {
+//                             if (JavaModelManager.VERBOSE) {
+//                                     System.out.println("CLOSING Element ("+ Thread.currentThread()+"): " + this.toStringWithAncestors());  //$NON-NLS-1$//$NON-NLS-2$
+//                                     wasVerbose = true;
+//                                     JavaModelManager.VERBOSE = false;
+//                             }
+//                             if (this instanceof IParent) {
+//                                     IJavaElement[] children = ((JavaElementInfo) info).getChildren();
+//                                     for (int i = 0, size = children.length; i < size; ++i) {
+//                                             JavaElement child = (JavaElement) children[i];
+//                                             child.close();
+//                                     }
+//                             }
+//                             closing(info);
+//                             JavaModelManager.getJavaModelManager().removeInfo(this);
+//                             if (wasVerbose) {
+//                                     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$
+//                             }
+//                     } finally {
+//                             JavaModelManager.VERBOSE = wasVerbose;
+//                     }
+//             }
+//     }
+       /**
+        * This element is being closed.  Do any necessary cleanup.
+        */
+       protected void closing(Object info) throws JavaModelException {
+       }
+       /**
+        * Returns true if this handle represents the same Java element
+        * as the given handle. By default, two handles represent the same
+        * element if they are identical or if they represent the same type
+        * of element, have equal names, parents, and occurrence counts.
+        *
+        * <p>If a subclass has other requirements for equality, this method
+        * must be overridden.
+        *
+        * @see Object#equals
+        */
+       public boolean equals(Object o) {
+               
+               if (this == o) return true;
+       
+               // Java model parent is null
+               if (fParent == null) return super.equals(o);
+       
+               if (o instanceof JavaElement) {
+                       JavaElement other = (JavaElement) o;
+                       if (fLEType != other.fLEType) return false;
+                       
+                       return fName.equals(other.fName) &&
+                                       fParent.equals(other.fParent) &&
+                                       fOccurrenceCount == other.fOccurrenceCount;
+               }
+               return false;
+       }
+       /**
+        * Returns true if this <code>JavaElement</code> is equivalent to the given
+        * <code>IDOMNode</code>.
+        */
+//     protected boolean equalsDOMNode(IDOMNode node) throws JavaModelException {
+//             return false;
+//     }
+       /**
+        * @see IJavaElement
+        */
+//     public boolean exists() {
+//             
+//             try {
+//                     getElementInfo();
+//                     return true;
+//             } catch (JavaModelException e) {
+//             }
+//             return false;
+//     }
+       
+       /**
+        * Returns the <code>IDOMNode</code> that corresponds to this <code>JavaElement</code>
+        * or <code>null</code> if there is no corresponding node.
+        */
+//     public IDOMNode findNode(IDOMCompilationUnit dom) {
+//             int type = getElementType();
+//             if (type == IJavaElement.COMPILATION_UNIT || 
+//                     type == IJavaElement.FIELD || 
+//                     type == IJavaElement.IMPORT_DECLARATION || 
+//                     type == IJavaElement.INITIALIZER || 
+//                     type == IJavaElement.METHOD || 
+//                     type == IJavaElement.PACKAGE_DECLARATION || 
+//                     type == IJavaElement.TYPE) {
+//                     ArrayList path = new ArrayList();
+//                     IJavaElement element = this;
+//                     while (element != null && element.getElementType() != IJavaElement.COMPILATION_UNIT) {
+//                             if (element.getElementType() != IJavaElement.IMPORT_CONTAINER) {
+//                                     // the DOM does not have import containers, so skip them
+//                                     path.add(0, element);
+//                             }
+//                             element = element.getParent();
+//                     }
+//                     if (path.size() == 0) {
+//                             try {
+//                                     if (equalsDOMNode(dom)) {
+//                                             return dom;
+//                                     } else {
+//                                             return null;
+//                                     }
+//                             } catch(JavaModelException e) {
+//                                     return null;
+//                             }
+//                     }
+//                     return ((JavaElement) path.get(0)).followPath(path, 0, dom.getFirstChild());
+//             } else {
+//                     return null;
+//             }
+//     }
+//     /**
+//      */
+//     protected IDOMNode followPath(ArrayList path, int position, IDOMNode node) {
+//     
+//             try {
+//                     if (equalsDOMNode(node)) {
+//                             if (position == (path.size() - 1)) {
+//                                     return node;
+//                             } else {
+//                                     if (node.getFirstChild() != null) {
+//                                             position++;
+//                                             return ((JavaElement)path.get(position)).followPath(path, position, node.getFirstChild());
+//                                     } else {
+//                                             return null;
+//                                     }
+//                             }
+//                     } else if (node.getNextNode() != null) {
+//                             return followPath(path, position, node.getNextNode());
+//                     } else {
+//                             return null;
+//                     }
+//             } catch (JavaModelException e) {
+//                     return null;
+//             }
+//     
+//     }
+       /**
+        * @see IJavaElement
+        */
+       public IJavaElement getAncestor(int ancestorType) {
+               
+               IJavaElement element = this;
+               while (element != null) {
+                       if (element.getElementType() == ancestorType)  return element;
+                       element= element.getParent();
+               }
+               return null;                            
+       }
+       /**
+        * @see IParent 
+        */
+//     public IJavaElement[] getChildren() throws JavaModelException {
+//             return ((JavaElementInfo)getElementInfo()).getChildren();
+//     }
+       /**
+        * Returns a collection of (immediate) children of this node of the
+        * specified type.
+        *
+        * @param type - one of constants defined by IJavaLanguageElementTypes
+        */
+//     public ArrayList getChildrenOfType(int type) throws JavaModelException {
+//             IJavaElement[] children = getChildren();
+//             int size = children.length;
+//             ArrayList list = new ArrayList(size);
+//             for (int i = 0; i < size; ++i) {
+//                     JavaElement elt = (JavaElement)children[i];
+//                     if (elt.getElementType() == type) {
+//                             list.add(elt);
+//                     }
+//             }
+//             return list;
+//     }
+       /**
+        * @see IMember
+        */
+//     public IClassFile getClassFile() {
+//             return null;
+//     }
+//     /**
+//      * @see IMember
+//      */
+//     public ICompilationUnit getCompilationUnit() {
+//             return null;
+//     }
+       /**
+        * Returns the info for this handle.  
+        * If this element is not already open, it and all of its parents are opened.
+        * Does not return null.
+        * NOTE: BinaryType infos are NJOT rooted under JavaElementInfo.
+        * @exception JavaModelException if the element is not present or not accessible
+        */
+//     public Object getElementInfo() throws JavaModelException {
+//
+//             // workaround to ensure parent project resolved classpath is available to avoid triggering initializers
+//             // while the JavaModelManager lock is acquired (can cause deadlocks in clients)
+//             IJavaProject project = getJavaProject();
+//             if (project != null && !project.isOpen()) {
+//                     // TODO: need to revisit, since deadlock could still occur if perProjectInfo is removed concurrent before entering the lock
+//                     try {
+//                             project.getResolvedClasspath(true); // trigger all possible container/variable initialization outside the model lock
+//                     } catch (JavaModelException e) {
+//                             // project is not accessible or is not a java project
+//                     }
+//             }
+//
+//             // element info creation is done inside a lock on the JavaModelManager
+//             JavaModelManager manager;
+//             synchronized(manager = JavaModelManager.getJavaModelManager()){
+//                     Object info = manager.getInfo(this);
+//                     if (info == null) {
+//                             openHierarchy();
+//                             info= manager.getInfo(this);
+//                             if (info == null) {
+//                                     throw newNotPresentException();
+//                             }
+//                     }
+//                     return info;
+//             }
+//     }
+       /**
+        * @see IAdaptable
+        */
+       public String getElementName() {
+               return fName;
+       }
+       /**
+        * @see IJavaElement
+        */
+       public int getElementType() {
+               return fLEType;
+       }
+       /**
+        * @see IJavaElement
+        */
+       public String getHandleIdentifier() {
+               return getHandleMemento();
+       }
+       /**
+        * @see JavaElement#getHandleMemento()
+        */
+       public String getHandleMemento(){
+               StringBuffer buff= new StringBuffer(((JavaElement)getParent()).getHandleMemento());
+               buff.append(getHandleMementoDelimiter());
+               buff.append(getElementName());
+               return buff.toString();
+       }
+       /**
+        * Returns the <code>char</code> that marks the start of this handles
+        * contribution to a memento.
+        */
+       protected abstract char getHandleMementoDelimiter();
+       /**
+        * @see IJavaElement
+        */
+       public IJavaModel getJavaModel() {
+               IJavaElement current = this;
+               do {
+                       if (current instanceof IJavaModel) return (IJavaModel) current;
+               } while ((current = current.getParent()) != null);
+               return null;
+       }
+//
+//     /**
+//      * @see IJavaElement
+//      */
+//     public IJavaProject getJavaProject() {
+//             IJavaElement current = this;
+//             do {
+//                     if (current instanceof IJavaProject) return (IJavaProject) current;
+//             } while ((current = current.getParent()) != null);
+//             return null;
+//     }
+       /**
+        * Returns the occurrence count of the handle.
+        */
+       protected int getOccurrenceCount() {
+               return fOccurrenceCount;
+       }
+       /*
+        * @see IJavaElement
+        */
+       public IOpenable getOpenable() {
+               return this.getOpenableParent();        
+       }
+       /**
+        * Return the first instance of IOpenable in the parent
+        * hierarchy of this element.
+        *
+        * <p>Subclasses that are not IOpenable's must override this method.
+        */
+       public IOpenable getOpenableParent() {
+               
+               return (IOpenable)fParent;
+       }
+       /**
+        * @see IJavaElement
+        */
+       public IJavaElement getParent() {
+               return fParent;
+       }
+       
+       /**
+        * Returns the element that is located at the given source position
+        * in this element.  This is a helper method for <code>ICompilationUnit#getElementAt</code>,
+        * and only works on compilation units and types. The position given is
+        * known to be within this element's source range already, and if no finer
+        * grained element is found at the position, this element is returned.
+        */
+//     protected IJavaElement getSourceElementAt(int position) throws JavaModelException {
+//             if (this instanceof ISourceReference) {
+//                     IJavaElement[] children = getChildren();
+//                     int i;
+//                     for (i = 0; i < children.length; i++) {
+//                             IJavaElement aChild = children[i];
+//                             if (aChild instanceof SourceRefElement) {
+//                                     SourceRefElement child = (SourceRefElement) children[i];
+//                                     ISourceRange range = child.getSourceRange();
+//                                     if (position < range.getOffset() + range.getLength() && position >= range.getOffset()) {
+//                                             if (child instanceof IParent) {
+//                                                     return child.getSourceElementAt(position);
+//                                             } else {
+//                                                     return child;
+//                                             }
+//                                     }
+//                             }
+//                     }
+//             } else {
+//                     // should not happen
+//                     Assert.isTrue(false);
+//             }
+//             return this;
+//     }
+       /**
+        * Returns the SourceMapper facility for this element, or
+        * <code>null</code> if this element does not have a
+        * SourceMapper.
+        */
+//     public SourceMapper getSourceMapper() {
+//             return ((JavaElement)getParent()).getSourceMapper();
+//     }
+
+       /**
+        * Returns the hash code for this Java element. By default,
+        * the hash code for an element is a combination of its name
+        * and parent's hash code. Elements with other requirements must
+        * override this method.
+        */
+       public int hashCode() {
+               if (fParent == null) return super.hashCode();
+               return Util.combineHashCodes(fName.hashCode(), fParent.hashCode());
+       }
+       /**
+        * Returns true if this element is an ancestor of the given element,
+        * otherwise false.
+        */
+       protected boolean isAncestorOf(IJavaElement e) {
+               IJavaElement parent= e.getParent();
+               while (parent != null && !parent.equals(this)) {
+                       parent= parent.getParent();
+               }
+               return parent != null;
+       }
+       
+       /**
+        * @see IJavaElement
+        */
+       public boolean isReadOnly() {
+               return false;
+       }
+       /**
+        * @see IJavaElement
+        */
+//     public boolean isStructureKnown() throws JavaModelException {
+//             return ((JavaElementInfo)getElementInfo()).isStructureKnown();
+//     }
+//     /**
+//      * Creates and returns and not present exception for this element.
+//      */
+//     protected JavaModelException newNotPresentException() {
+//             return new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
+//     }
+//     /**
+//      * Opens this element and all parents that are not already open.
+//      *
+//      * @exception JavaModelException this element is not present or accessible
+//      */
+//     protected void openHierarchy() throws JavaModelException {
+//             if (this instanceof IOpenable) {
+//                     ((Openable) this).openWhenClosed(null);
+//             } else {
+//                     Openable openableParent = (Openable)getOpenableParent();
+//                     if (openableParent != null) {
+//                             JavaElementInfo openableParentInfo = (JavaElementInfo) JavaModelManager.getJavaModelManager().getInfo((IJavaElement) openableParent);
+//                             if (openableParentInfo == null) {
+//                                     openableParent.openWhenClosed(null);
+//                             } else {
+//                                     throw newNotPresentException();
+//                             }
+//                     }
+//             }
+//     }
+       /**
+        * This element has just been opened.  Do any necessary setup.
+        */
+       protected void opening(Object info) {
+       }
+       /**
+        */
+       public String readableName() {
+               return this.getElementName();
+       }
+       /**
+        * Removes all cached info from the Java Model, including all children,
+        * but does not close this element.
+        */
+//     protected void removeInfo() {
+//             Object info = JavaModelManager.getJavaModelManager().peekAtInfo(this);
+//             if (info != null) {
+//                     if (this instanceof IParent) {
+//                             IJavaElement[] children = ((JavaElementInfo)info).getChildren();
+//                             for (int i = 0, size = children.length; i < size; ++i) {
+//                                     JavaElement child = (JavaElement) children[i];
+//                                     child.removeInfo();
+//                             }
+//                     }
+//                     JavaModelManager.getJavaModelManager().removeInfo(this);
+//             }
+//     }
+//     /**
+//      * Returns a copy of this element rooted at the given project.
+//      */
+//     public abstract IJavaElement rootedAt(IJavaProject project);
+//     /**
+//      * Runs a Java Model Operation
+//      */
+//     public static void runOperation(JavaModelOperation operation, IProgressMonitor monitor) throws JavaModelException {
+//             try {
+//                     if (operation.isReadOnly() || ResourcesPlugin.getWorkspace().isTreeLocked()) {
+//                             operation.run(monitor);
+//                     } else {
+//                             // use IWorkspace.run(...) to ensure that a build will be done in autobuild mode
+//                             ResourcesPlugin.getWorkspace().run(operation, monitor);
+//                     }
+//             } catch (CoreException ce) {
+//                     if (ce instanceof JavaModelException) {
+//                             throw (JavaModelException)ce;
+//                     } else {
+//                             if (ce.getStatus().getCode() == IResourceStatus.OPERATION_FAILED) {
+//                                     Throwable e= ce.getStatus().getException();
+//                                     if (e instanceof JavaModelException) {
+//                                             throw (JavaModelException) e;
+//                                     }
+//                             }
+//                             throw new JavaModelException(ce);
+//                     }
+//             }
+//     }
+       /**
+        * Sets the occurrence count of the handle.
+        */
+       protected void setOccurrenceCount(int count) {
+               fOccurrenceCount = count;
+       }
+       protected String tabString(int tab) {
+               StringBuffer buffer = new StringBuffer();
+               for (int i = tab; i > 0; i--)
+                       buffer.append("  "); //$NON-NLS-1$
+               return buffer.toString();
+       }
+       /**
+        * Debugging purposes
+        */
+       public String toDebugString() {
+               StringBuffer buffer = new StringBuffer();
+               this.toStringInfo(0, buffer, NO_INFO);
+               return buffer.toString();
+       }
+       /**
+        *  Debugging purposes
+        */
+       public String toString() {
+               StringBuffer buffer = new StringBuffer();
+               toString(0, buffer);
+               return buffer.toString();
+       }
+       /**
+        *  Debugging purposes
+        */
+       protected void toString(int tab, StringBuffer buffer) {
+       //      Object info = this.toStringInfo(tab, buffer);
+               Object info = null;
+               if (tab == 0) {
+                       this.toStringAncestors(buffer);
+               }
+               this.toStringChildren(tab, buffer, info);
+       }
+       /**
+        *  Debugging purposes
+        */
+       public String toStringWithAncestors() {
+               StringBuffer buffer = new StringBuffer();
+               this.toStringInfo(0, buffer, NO_INFO);
+               this.toStringAncestors(buffer);
+               return buffer.toString();
+       }
+       /**
+        *  Debugging purposes
+        */
+       protected void toStringAncestors(StringBuffer buffer) {
+               JavaElement parent = (JavaElement)this.getParent();
+               if (parent != null && parent.getParent() != null) {
+                       buffer.append(" [in "); //$NON-NLS-1$
+                       parent.toStringInfo(0, buffer, NO_INFO);
+                       parent.toStringAncestors(buffer);
+                       buffer.append("]"); //$NON-NLS-1$
+               }
+       }
+       /**
+        *  Debugging purposes
+        */
+       protected void toStringChildren(int tab, StringBuffer buffer, Object info) {
+               if (info == null || !(info instanceof JavaElementInfo)) return;
+               IJavaElement[] children = ((JavaElementInfo)info).getChildren();
+               for (int i = 0; i < children.length; i++) {
+                       buffer.append("\n"); //$NON-NLS-1$
+                       ((JavaElement)children[i]).toString(tab + 1, buffer);
+               }
+       }
+       /**
+        *  Debugging purposes
+        */
+//     public Object toStringInfo(int tab, StringBuffer buffer) {
+//             Object info = JavaModelManager.getJavaModelManager().peekAtInfo(this);
+//             this.toStringInfo(tab, buffer, info);
+//             return info;
+//     }
+       /**
+        *  Debugging purposes
+        */
+       protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
+               buffer.append(this.tabString(tab));
+               buffer.append(getElementName());
+               if (info == null) {
+                       buffer.append(" (not open)"); //$NON-NLS-1$
+               }
+       }
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/JavaElementInfo.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/JavaElementInfo.java
new file mode 100644 (file)
index 0000000..532ddd3
--- /dev/null
@@ -0,0 +1,130 @@
+/*******************************************************************************
+ * 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.internal.core;
+
+import net.sourceforge.phpdt.core.IJavaElement;
+
+
+
+/**
+ * Holds cached structure and properties for a Java element.
+ * Subclassed to carry properties for specific kinds of elements.
+ */
+/* package */ class JavaElementInfo {
+
+       /**
+        * Collection of handles of immediate children of this
+        * object. This is an empty array if this element has
+        * no children.
+        */
+       protected IJavaElement[] fChildren;
+
+       /**
+        * Shared empty collection used for efficiency.
+        */
+       protected static IJavaElement[] fgEmptyChildren = new IJavaElement[]{};
+       /**
+        * Is the structure of this element known
+        * @see IJavaElement#isStructureKnown()
+        */
+       protected boolean fIsStructureKnown = false;
+
+       /**
+        * Shared empty collection used for efficiency.
+        */
+       static Object[] NO_NON_JAVA_RESOURCES = new Object[] {};        
+       protected JavaElementInfo() {
+               fChildren = fgEmptyChildren;
+       }
+       public void addChild(IJavaElement child) {
+               if (fChildren == fgEmptyChildren) {
+                       setChildren(new IJavaElement[] {child});
+               } else {
+                       if (!includesChild(child)) {
+                               setChildren(growAndAddToArray(fChildren, child));
+                       }
+               }
+       }
+       public Object clone() {
+               try {
+                       return super.clone();
+               }
+               catch (CloneNotSupportedException e) {
+                       throw new Error();
+               }
+       }
+       public IJavaElement[] getChildren() {
+               return fChildren;
+       }
+       /**
+        * Adds the new element to a new array that contains all of the elements of the old array.
+        * Returns the new array.
+        */
+       protected IJavaElement[] growAndAddToArray(IJavaElement[] array, IJavaElement addition) {
+               IJavaElement[] old = array;
+               array = new IJavaElement[old.length + 1];
+               System.arraycopy(old, 0, array, 0, old.length);
+               array[old.length] = addition;
+               return array;
+       }
+       /**
+        * Returns <code>true</code> if this child is in my children collection
+        */
+       protected boolean includesChild(IJavaElement child) {
+               
+               for (int i= 0; i < fChildren.length; i++) {
+                       if (fChildren[i].equals(child)) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+       /**
+        * @see IJavaElement#isStructureKnown()
+        */
+       public boolean isStructureKnown() {
+               return fIsStructureKnown;
+       }
+       /**
+        * Returns an array with all the same elements as the specified array except for
+        * the element to remove. Assumes that the deletion is contained in the array.
+        */
+       protected IJavaElement[] removeAndShrinkArray(IJavaElement[] array, IJavaElement deletion) {
+               IJavaElement[] old = array;
+               array = new IJavaElement[old.length - 1];
+               int j = 0;
+               for (int i = 0; i < old.length; i++) {
+                       if (!old[i].equals(deletion)) {
+                               array[j] = old[i];
+                       } else {
+                               System.arraycopy(old, i + 1, array, j, old.length - (i + 1));
+                               return array;
+                       }
+                       j++;
+               }
+               return array;
+       }
+       public void removeChild(IJavaElement child) {
+               if (includesChild(child)) {
+                       setChildren(removeAndShrinkArray(fChildren, child));
+               }
+       }
+       public void setChildren(IJavaElement[] children) {
+               fChildren = children;
+       }
+       /**
+        * Sets whether the structure of this element known
+        * @see IJavaElement#isStructureKnown()
+        */
+       public void setIsStructureKnown(boolean newIsStructureKnown) {
+               fIsStructureKnown = newIsStructureKnown;
+       }
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/JavaModelStatus.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/JavaModelStatus.java
new file mode 100644 (file)
index 0000000..e895a82
--- /dev/null
@@ -0,0 +1,451 @@
+/*******************************************************************************
+ * 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.internal.core;
+
+import net.sourceforge.phpdt.core.IJavaElement;
+import net.sourceforge.phpdt.core.IJavaModelStatus;
+import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
+import net.sourceforge.phpeclipse.PHPCore;
+
+import org.eclipse.core.resources.IResourceStatus;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+/**
+ * @see IJavaModelStatus
+ */
+
+public class JavaModelStatus
+  extends Status
+  implements IJavaModelStatus, IJavaModelStatusConstants, IResourceStatus {
+
+  /**
+   * The elements related to the failure, or <code>null</code>
+   * if no elements are involved.
+   */
+  protected IJavaElement[] fElements = new IJavaElement[0];
+  
+  /**
+   * The path related to the failure, or <code>null</code>
+   * if no path is involved.
+   */
+  protected IPath fPath;
+  /**
+   * The <code>String</code> related to the failure, or <code>null</code>
+   * if no <code>String</code> is involved.
+   */
+  protected String fString;
+  /**
+   * Empty children
+   */
+  protected final static IStatus[] fgEmptyChildren = new IStatus[] {
+  };
+  protected IStatus[] fChildren = fgEmptyChildren;
+
+  /**
+        * Shared empty collection used for efficiency.
+        */
+  protected static IJavaElement[] fgObjectEmptyChildren = new IJavaElement[]{};
+  
+
+  /**
+   * Singleton OK object
+   */
+  public static final IJavaModelStatus VERIFIED_OK = new JavaModelStatus(OK, OK, Util.bind("status.OK")); //$NON-NLS-1$
+
+  /**
+   * Constructs an Java model status with no corresponding elements.
+   */
+  public JavaModelStatus() {
+    // no code for an multi-status
+    super(ERROR, PHPCore.PLUGIN_ID, 0, "JavaModelStatus", null); //$NON-NLS-1$
+  }
+  /**
+   * Constructs an Java model status with no corresponding elements.
+   */
+  public JavaModelStatus(int code) {
+    super(ERROR, PHPCore.PLUGIN_ID, code, "JavaModelStatus", null); //$NON-NLS-1$
+    // fElements= JavaElementInfo.fgEmptyChildren;
+    fElements = fgObjectEmptyChildren;
+  }
+  /**
+   * Constructs an Java model status with the given corresponding
+   * elements.
+   */
+  public JavaModelStatus(int code, IJavaElement[] elements) {
+    super(ERROR, PHPCore.PLUGIN_ID, code, "JavaModelStatus", null); //$NON-NLS-1$
+    fElements = elements;
+    fPath = null;
+  }
+  /**
+   * Constructs an Java model status with no corresponding elements.
+   */
+  public JavaModelStatus(int code, String string) {
+    this(ERROR, code, string);
+  }
+  /**
+   * Constructs an Java model status with no corresponding elements.
+   */
+  public JavaModelStatus(int severity, int code, String string) {
+    super(severity, PHPCore.PLUGIN_ID, code, "JavaModelStatus", null); //$NON-NLS-1$
+    // fElements= JavaElementInfo.fgEmptyChildren;
+    fElements = fgObjectEmptyChildren;
+    fPath = null;
+    fString = string;
+  }
+  /**
+   * Constructs an Java model status with no corresponding elements.
+   */
+  public JavaModelStatus(int code, Throwable throwable) {
+    super(ERROR, PHPCore.PLUGIN_ID, code, "JavaModelStatus", throwable); //$NON-NLS-1$
+    // fElements= JavaElementInfo.fgEmptyChildren;
+    fElements = fgObjectEmptyChildren;
+  }
+  /**
+   * Constructs an Java model status with no corresponding elements.
+   */
+  public JavaModelStatus(int code, IPath path) {
+    super(ERROR, PHPCore.PLUGIN_ID, code, "JavaModelStatus", null); //$NON-NLS-1$
+    //         fElements= JavaElementInfo.fgEmptyChildren;
+    fElements = fgObjectEmptyChildren;
+    fPath = path;
+  }
+  /**
+   * Constructs an Java model status with the given corresponding
+   * element.
+   */
+  //   public JavaModelStatus(int code, IJavaElement element) {
+  //           this(code, new IJavaElement[]{element});
+  //   }
+  /**
+   * Constructs an Java model status with the given corresponding
+   * element and string
+   */
+  //   public JavaModelStatus(int code, IJavaElement element, String string) {
+  //           this(code, new IJavaElement[]{element});
+  //           fString = string;
+  //   }
+  //   
+  //   /**
+  //    * Constructs an Java model status with the given corresponding
+  //    * element and path
+  //    */
+  //   public JavaModelStatus(int code, IJavaElement element, IPath path) {
+  //           this(code, new IJavaElement[]{element});
+  //           fPath = path;
+  //   }       
+  /**
+   * Constructs an Java model status with no corresponding elements.
+   */
+  public JavaModelStatus(CoreException coreException) {
+    super(ERROR, PHPCore.PLUGIN_ID, CORE_EXCEPTION, "JavaModelStatus", coreException); //$NON-NLS-1$
+    // fElements= JavaElementInfo.fgEmptyChildren;
+    fElements = fgObjectEmptyChildren;
+  }
+  protected int getBits() {
+    int severity = 1 << (getCode() % 100 / 33);
+    int category = 1 << ((getCode() / 100) + 3);
+    return severity | category;
+  }
+  /**
+   * @see IStatus
+   */
+  public IStatus[] getChildren() {
+    return fChildren;
+  }
+  /**
+   * @see IJavaModelStatus
+   */
+  public IJavaElement[] getElements() {
+    return fElements;
+  }
+  /**
+   * Returns the message that is relevant to the code of this status.
+   */
+  public String getMessage() {
+    Throwable exception = getException();
+    if (exception == null) {
+      switch (getCode()) {
+        case CORE_EXCEPTION :
+          return Util.bind("status.coreException"); //$NON-NLS-1$
+
+        case BUILDER_INITIALIZATION_ERROR :
+          return Util.bind("build.initializationError"); //$NON-NLS-1$
+
+        case BUILDER_SERIALIZATION_ERROR :
+          return Util.bind("build.serializationError"); //$NON-NLS-1$
+
+        case DEVICE_PATH :
+          return Util.bind("status.cannotUseDeviceOnPath", getPath().toString()); //$NON-NLS-1$
+
+        case DOM_EXCEPTION :
+          return Util.bind("status.JDOMError"); //$NON-NLS-1$
+
+//                                     case ELEMENT_DOES_NOT_EXIST:
+//                                             return Util.bind("element.doesNotExist",((JavaElement)fElements[0]).toStringWithAncestors()); //$NON-NLS-1$
+
+        case EVALUATION_ERROR :
+          return Util.bind("status.evaluationError", fString); //$NON-NLS-1$
+
+        case INDEX_OUT_OF_BOUNDS :
+          return Util.bind("status.indexOutOfBounds"); //$NON-NLS-1$
+
+        case INVALID_CONTENTS :
+          return Util.bind("status.invalidContents"); //$NON-NLS-1$
+
+          //                           case INVALID_DESTINATION:
+          //                                   return Util.bind("status.invalidDestination", ((JavaElement)fElements[0]).toStringWithAncestors()); //$NON-NLS-1$
+          //
+          //                           case INVALID_ELEMENT_TYPES:
+          //                                   StringBuffer buff= new StringBuffer(Util.bind("operation.notSupported")); //$NON-NLS-1$
+          //                                   for (int i= 0; i < fElements.length; i++) {
+          //                                           if (i > 0) {
+          //                                                   buff.append(", "); //$NON-NLS-1$
+          //                                           }
+          //                                           buff.append(((JavaElement)fElements[i]).toStringWithAncestors());
+          //                                   }
+          //                                   return buff.toString();
+
+        case INVALID_NAME :
+          return Util.bind("status.invalidName", fString); //$NON-NLS-1$
+
+        case INVALID_PACKAGE :
+          return Util.bind("status.invalidPackage", fString); //$NON-NLS-1$
+
+        case INVALID_PATH :
+          if (fString != null) {
+            return fString;
+          } else {
+            return Util.bind("status.invalidPath", getPath() == null ? "null" : getPath().toString()); //$NON-NLS-1$ //$NON-NLS-2$
+          }
+
+        case INVALID_PROJECT :
+          return Util.bind("status.invalidProject", fString); //$NON-NLS-1$
+
+        case INVALID_RESOURCE :
+          return Util.bind("status.invalidResource", fString); //$NON-NLS-1$
+
+        case INVALID_RESOURCE_TYPE :
+          return Util.bind("status.invalidResourceType", fString); //$NON-NLS-1$
+
+          //                           case INVALID_SIBLING:
+          //                                   if (fString != null) {
+          //                                           return Util.bind("status.invalidSibling", fString); //$NON-NLS-1$
+          //                                   } else {
+          //                                           return Util.bind("status.invalidSibling", ((JavaElement)fElements[0]).toStringWithAncestors()); //$NON-NLS-1$
+          //                                   }
+
+        case IO_EXCEPTION :
+          return Util.bind("status.IOException"); //$NON-NLS-1$
+
+          //                           case NAME_COLLISION:
+          //                                   if (fElements != null && fElements.length > 0) {
+          //                                           IJavaElement element = fElements[0];
+          //                                           String name = element.getElementName();
+          //                                           if (element instanceof IPackageFragment && name.equals(IPackageFragment.DEFAULT_PACKAGE_NAME)) {
+          //                                                   return Util.bind("operation.cannotRenameDefaultPackage"); //$NON-NLS-1$
+          //                                           }
+          //                                   }
+          //                                   if (fString != null) {
+          //                                           return fString;
+          //                                   } else {
+          //                                           return Util.bind("status.nameCollision", ""); //$NON-NLS-1$ //$NON-NLS-2$
+          //                                   }
+        case NO_ELEMENTS_TO_PROCESS :
+          return Util.bind("operation.needElements"); //$NON-NLS-1$
+
+        case NULL_NAME :
+          return Util.bind("operation.needName"); //$NON-NLS-1$
+
+        case NULL_PATH :
+          return Util.bind("operation.needPath"); //$NON-NLS-1$
+
+        case NULL_STRING :
+          return Util.bind("operation.needString"); //$NON-NLS-1$
+
+          //                           case PATH_OUTSIDE_PROJECT:
+          //                                   return Util.bind("operation.pathOutsideProject", fString, ((JavaElement)fElements[0]).toStringWithAncestors()); //$NON-NLS-1$
+          //
+          //                           case READ_ONLY:
+          //                                   IJavaElement element = fElements[0];
+          //                                   String name = element.getElementName();
+          //                                   if (element instanceof IPackageFragment && name.equals(IPackageFragment.DEFAULT_PACKAGE_NAME)) {
+          //                                           return Util.bind("status.defaultPackageReadOnly"); //$NON-NLS-1$
+          //                                   }
+          //                                   return  Util.bind("status.readOnly", name); //$NON-NLS-1$
+
+        case RELATIVE_PATH :
+          return Util.bind("operation.needAbsolutePath", getPath().toString()); //$NON-NLS-1$
+
+        case TARGET_EXCEPTION :
+          return Util.bind("status.targetException"); //$NON-NLS-1$
+
+        case UPDATE_CONFLICT :
+          return Util.bind("status.updateConflict"); //$NON-NLS-1$
+
+        case NO_LOCAL_CONTENTS :
+          return Util.bind("status.noLocalContents", getPath().toString()); //$NON-NLS-1$
+
+          //                           case CP_CONTAINER_PATH_UNBOUND:
+          //                                   IPath path = this.fPath;
+          //                                   IJavaProject javaProject = (IJavaProject)fElements[0];
+          //                                   ClasspathContainerInitializer initializer = PHPCore.getClasspathContainerInitializer(path.segment(0));
+          //                                   String description = null;
+          //                                   if (initializer != null) description = initializer.getDescription(path, javaProject);
+          //                                   if (description == null) description = path.makeRelative().toString();
+          //                                   return Util.bind("classpath.unboundContainerPath", description); //$NON-NLS-1$
+          //
+          //                           case INVALID_CP_CONTAINER_ENTRY:
+          //                                   path = this.fPath;
+          //                                   javaProject = (IJavaProject)fElements[0];
+          //                                   IClasspathContainer container = null;
+          //                                   description = null;
+          //                                   try {
+          //                                           container = PHPCore.getClasspathContainer(path, javaProject);
+          //                                   } catch(JavaModelException e){
+          //                                   }
+          //                                   if (container == null) {
+          //                                            initializer = PHPCore.getClasspathContainerInitializer(path.segment(0));
+          //                                           if (initializer != null) description = initializer.getDescription(path, javaProject);
+          //                                   } else {
+          //                                           description = container.getDescription();
+          //                                   }
+          //                                   if (description == null) description = path.makeRelative().toString();
+          //                                   return Util.bind("classpath.invalidContainer", description); //$NON-NLS-1$
+          //
+          //                   case CP_VARIABLE_PATH_UNBOUND:
+          //                                   path = this.fPath;
+          //                                   return Util.bind("classpath.unboundVariablePath", path.makeRelative().toString()); //$NON-NLS-1$
+          //                                   
+          //                   case CLASSPATH_CYCLE: 
+          //                                   javaProject = (IJavaProject)fElements[0];
+          //                                   return Util.bind("classpath.cycle", javaProject.getElementName()); //$NON-NLS-1$
+
+          //                   case DISABLED_CP_EXCLUSION_PATTERNS:
+          //                                   path = this.fPath;
+          //                                   return Util.bind("classpath.disabledExclusionPatterns", path.makeRelative().toString()); //$NON-NLS-1$
+          //
+          //                   case DISABLED_CP_MULTIPLE_OUTPUT_LOCATIONS:
+          //                                   path = this.fPath;
+          //                                   return Util.bind("classpath.disabledMultipleOutputLocations", path.makeRelative().toString()); //$NON-NLS-1$
+      }
+      if (fString != null) {
+        return fString;
+      } else {
+        return ""; // //$NON-NLS-1$
+      }
+    } else {
+      String message = exception.getMessage();
+      if (message != null) {
+        return message;
+      } else {
+        return exception.toString();
+      }
+    }
+  }
+  /**
+   * @see IJavaModelStatus#getPath()
+   */
+  public IPath getPath() {
+    return fPath;
+  }
+  /**
+   * @see IStatus#getSeverity()
+   */
+  public int getSeverity() {
+    if (fChildren == fgEmptyChildren)
+      return super.getSeverity();
+    int severity = -1;
+    for (int i = 0, max = fChildren.length; i < max; i++) {
+      int childrenSeverity = fChildren[i].getSeverity();
+      if (childrenSeverity > severity) {
+        severity = childrenSeverity;
+      }
+    }
+    return severity;
+  }
+  /**
+   * @see IJavaModelStatus#getString()
+   * @deprecated
+   */
+  public String getString() {
+    return fString;
+  }
+  /**
+   * @see IJavaModelStatus#isDoesNotExist()
+   */
+  public boolean isDoesNotExist() {
+    return getCode() == ELEMENT_DOES_NOT_EXIST;
+  }
+  /**
+   * @see IStatus#isMultiStatus()
+   */
+  public boolean isMultiStatus() {
+    return fChildren != fgEmptyChildren;
+  }
+  /**
+   * @see IStatus#isOK()
+   */
+  public boolean isOK() {
+    return getCode() == OK;
+  }
+  /**
+   * @see IStatus#matches(int)
+   */
+  public boolean matches(int mask) {
+    if (!isMultiStatus()) {
+      return matches(this, mask);
+    } else {
+      for (int i = 0, max = fChildren.length; i < max; i++) {
+        if (matches((JavaModelStatus) fChildren[i], mask))
+          return true;
+      }
+      return false;
+    }
+  }
+  /**
+   * Helper for matches(int).
+   */
+  protected boolean matches(JavaModelStatus status, int mask) {
+    int severityMask = mask & 0x7;
+    int categoryMask = mask & ~0x7;
+    int bits = status.getBits();
+    return ((severityMask == 0) || (bits & severityMask) != 0)
+      && ((categoryMask == 0) || (bits & categoryMask) != 0);
+  }
+  /**
+   * Creates and returns a new <code>IJavaModelStatus</code> that is a
+   * a multi-status status.
+   *
+   * @see IStatus#isMultiStatus()
+   */
+  public static IJavaModelStatus newMultiStatus(IJavaModelStatus[] children) {
+    JavaModelStatus jms = new JavaModelStatus();
+    jms.fChildren = children;
+    return jms;
+  }
+  /**
+   * Returns a printable representation of this exception for debugging
+   * purposes.
+   */
+  public String toString() {
+    if (this == VERIFIED_OK) {
+      return "JavaModelStatus[OK]"; //$NON-NLS-1$
+    }
+    StringBuffer buffer = new StringBuffer();
+    buffer.append("Java Model Status ["); //$NON-NLS-1$
+    buffer.append(getMessage());
+    buffer.append("]"); //$NON-NLS-1$
+    return buffer.toString();
+  }
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/LRUCacheEnumerator.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/LRUCacheEnumerator.java
new file mode 100644 (file)
index 0000000..8a04b28
--- /dev/null
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * 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.internal.core;
+
+import java.util.Enumeration;
+
+/**
+ *     The <code>LRUCacheEnumerator</code> returns its elements in 
+ *     the order they are found in the <code>LRUCache</code>, with the
+ *     most recent elements first.
+ *
+ *     Once the enumerator is created, elements which are later added 
+ *     to the cache are not returned by the enumerator.  However,
+ *     elements returned from the enumerator could have been closed 
+ *     by the cache.
+ */
+public class LRUCacheEnumerator implements Enumeration {
+       /**
+        *      Current element;
+        */
+       protected LRUEnumeratorElement fElementQueue;
+
+       public static class LRUEnumeratorElement {
+               /**
+                *      Value returned by <code>nextElement()</code>;
+                */
+               public Object fValue;
+               
+               /**
+                *      Next element
+                */
+               public LRUEnumeratorElement fNext;
+
+               /**
+                * Constructor
+                */
+               public LRUEnumeratorElement(Object value) {
+                       fValue = value;
+               }
+       }
+/**
+ *     Creates a CacheEnumerator on the list of <code>LRUEnumeratorElements</code>.
+ */
+public LRUCacheEnumerator(LRUEnumeratorElement firstElement) {
+       fElementQueue = firstElement;
+}
+/**
+ * Returns true if more elements exist.
+ */
+public boolean hasMoreElements() {
+       return fElementQueue != null;
+}
+/**
+ * Returns the next element.
+ */
+public Object nextElement() {
+       Object temp = fElementQueue.fValue;
+       fElementQueue = fElementQueue.fNext;
+       return temp;
+}
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/OverflowingLRUCache.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/OverflowingLRUCache.java
new file mode 100644 (file)
index 0000000..8b415c0
--- /dev/null
@@ -0,0 +1,426 @@
+/*******************************************************************************
+ * 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.internal.core;
+
+import java.util.Enumeration;
+import java.util.Iterator;
+
+import net.sourceforge.phpdt.core.util.LRUCache;
+
+/**
+ *     The <code>OverflowingLRUCache</code> is an LRUCache which attempts
+ *     to maintain a size equal or less than its <code>fSpaceLimit</code>
+ *     by removing the least recently used elements.
+ *
+ *     <p>The cache will remove elements which successfully close and all
+ *     elements which are explicitly removed.
+ *
+ *     <p>If the cache cannot remove enough old elements to add new elements
+ *     it will grow beyond <code>fSpaceLimit</code>. Later, it will attempt to 
+ *     shink back to the maximum space limit.
+ *
+ *     The method <code>close</code> should attempt to close the element.  If
+ *     the element is successfully closed it will return true and the element will
+ *     be removed from the cache.  Otherwise the element will remain in the cache.
+ *
+ *     <p>The cache implicitly attempts shrinks on calls to <code>put</code>and
+ *     <code>setSpaceLimit</code>.  Explicitly calling the <code>shrink</code> method
+ *     will also cause the cache to attempt to shrink.
+ *
+ *     <p>The cache calculates the used space of all elements which implement 
+ *     <code>ILRUCacheable</code>.  All other elements are assumed to be of size one.
+ *
+ *     <p>Use the <code>#peek(Object)</code> and <code>#disableTimestamps()</code> method to
+ *     circumvent the timestamp feature of the cache.  This feature is intended to be used
+ *     only when the <code>#close(LRUCacheEntry)</code> method causes changes to the cache.  
+ *     For example, if a parent closes its children when </code>#close(LRUCacheEntry)</code> is called, 
+ *     it should be careful not to change the LRU linked list.  It can be sure it is not causing 
+ *     problems by calling <code>#peek(Object)</code> instead of <code>#get(Object)</code> method.
+ *     
+ *     @see LRUCache
+ */
+public abstract class OverflowingLRUCache extends LRUCache {
+       /**
+        * Indicates if the cache has been over filled and by how much.
+        */
+       protected int fOverflow = 0;
+       /**
+        *      Indicates whether or not timestamps should be updated
+        */
+       protected boolean fTimestampsOn = true;
+       /**
+        *      Indicates how much space should be reclaimed when the cache overflows.
+        *      Inital load factor of one third.
+        */
+       protected double fLoadFactor = 0.333;
+/**
+ * Creates a OverflowingLRUCache. 
+ * @param size Size limit of cache.
+ */
+public OverflowingLRUCache(int size) {
+       this(size, 0);
+}
+/**
+ * Creates a OverflowingLRUCache. 
+ * @param size Size limit of cache.
+ * @param overflow Size of the overflow.
+ */
+public OverflowingLRUCache(int size, int overflow) {
+       super(size);
+       fOverflow = overflow;
+}
+       /**
+        * Returns a new cache containing the same contents.
+        *
+        * @return New copy of this object.
+        */
+       public Object clone() {
+               
+               OverflowingLRUCache newCache = (OverflowingLRUCache)newInstance(fSpaceLimit, fOverflow);
+               LRUCacheEntry qEntry;
+               
+               /* Preserve order of entries by copying from oldest to newest */
+               qEntry = this.fEntryQueueTail;
+               while (qEntry != null) {
+                       newCache.privateAdd (qEntry._fKey, qEntry._fValue, qEntry._fSpace);
+                       qEntry = qEntry._fPrevious;
+               }
+               return newCache;
+       }
+/**
+ * Returns true if the element is successfully closed and
+ * removed from the cache, otherwise false.
+ *
+ * <p>NOTE: this triggers an external remove from the cache
+ * by closing the obejct.
+ *
+ */
+protected abstract boolean close(LRUCacheEntry entry);
+       /**
+        *      Returns an enumerator of the values in the cache with the most
+        *      recently used first.
+        */
+       public Enumeration elements() {
+               if (fEntryQueue == null)
+                       return new LRUCacheEnumerator(null);
+               LRUCacheEnumerator.LRUEnumeratorElement head = 
+                       new LRUCacheEnumerator.LRUEnumeratorElement(fEntryQueue._fValue);
+               LRUCacheEntry currentEntry = fEntryQueue._fNext;
+               LRUCacheEnumerator.LRUEnumeratorElement currentElement = head;
+               while(currentEntry != null) {
+                       currentElement.fNext = new LRUCacheEnumerator.LRUEnumeratorElement(currentEntry._fValue);
+                       currentElement = currentElement.fNext;
+                       
+                       currentEntry = currentEntry._fNext;
+               }
+               return new LRUCacheEnumerator(head);
+       }
+       public double fillingRatio() {
+               return (fCurrentSpace + fOverflow) * 100.0 / fSpaceLimit;
+       }
+       /**
+        * For internal testing only.
+        * This method exposed only for testing purposes!
+        *
+        * @return Hashtable of entries
+        */
+       public java.util.Hashtable getEntryTable() {
+               return fEntryTable;
+       }
+/**
+ * Returns the load factor for the cache.  The load factor determines how 
+ * much space is reclaimed when the cache exceeds its space limit.
+ * @return double
+ */
+public double getLoadFactor() {
+       return fLoadFactor;
+}
+       /**
+        *      @return The space by which the cache has overflown.
+        */
+       public int getOverflow() {
+               return fOverflow;
+       }
+       /**
+        * Ensures there is the specified amount of free space in the receiver,
+        * by removing old entries if necessary.  Returns true if the requested space was
+        * made available, false otherwise.  May not be able to free enough space
+        * since some elements cannot be removed until they are saved.
+        *
+        * @param space Amount of space to free up
+        */
+       protected boolean makeSpace(int space) {
+       
+               int limit = fSpaceLimit;
+               if (fOverflow == 0) {
+                       /* if space is already available */
+                       if (fCurrentSpace + space <= limit) {
+                               return true;
+                       }
+               }
+       
+               /* Free up space by removing oldest entries */
+               int spaceNeeded = (int)((1 - fLoadFactor) * fSpaceLimit);
+               spaceNeeded = (spaceNeeded > space) ? spaceNeeded : space;
+               LRUCacheEntry entry = fEntryQueueTail;
+       
+               while (fCurrentSpace + spaceNeeded > limit && entry != null) {
+                       this.privateRemoveEntry(entry, false, false);
+                       entry = entry._fPrevious;
+               }
+       
+               /* check again, since we may have aquired enough space */
+               if (fCurrentSpace + space <= limit) {
+                       fOverflow = 0;
+                       return true;
+               }
+       
+               /* update fOverflow */
+               fOverflow = fCurrentSpace + space - limit;
+               return false;
+       }
+       /**
+        * Returns a new instance of the reciever.
+        */
+       protected abstract LRUCache newInstance(int size, int overflow);
+       /**
+        * Answers the value in the cache at the given key.
+        * If the value is not in the cache, returns null
+        *
+        * This function does not modify timestamps.
+        */
+       public Object peek(Object key) {
+               
+               LRUCacheEntry entry = (LRUCacheEntry) fEntryTable.get(key);
+               if (entry == null) {
+                       return null;
+               }
+               return entry._fValue;
+       }
+/**
+ * For testing purposes only
+ */
+public void printStats() {
+       int forwardListLength = 0;
+       LRUCacheEntry entry = fEntryQueue;
+       while(entry != null) {
+               forwardListLength++;
+               entry = entry._fNext;
+       }
+       System.out.println("Forward length: " + forwardListLength); //$NON-NLS-1$
+       
+       int backwardListLength = 0;
+       entry = fEntryQueueTail;
+       while(entry != null) {
+               backwardListLength++;
+               entry = entry._fPrevious;
+       }
+       System.out.println("Backward length: " + backwardListLength); //$NON-NLS-1$
+
+       Enumeration keys = fEntryTable.keys();
+       class Temp {
+               public Class fClass;
+               public int fCount;
+               public Temp(Class aClass) {
+                       fClass = aClass;
+                       fCount = 1;
+               }
+               public String toString() {
+                       return "Class: " + fClass + " has " + fCount + " entries."; //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-1$
+               }
+       }
+       java.util.HashMap h = new java.util.HashMap();
+       while(keys.hasMoreElements()) {
+               entry = (LRUCacheEntry)fEntryTable.get(keys.nextElement());
+               Class key = entry._fValue.getClass();
+               Temp t = (Temp)h.get(key);
+               if (t == null) {
+                       h.put(key, new Temp(key));
+               } else {
+                       t.fCount++;
+               }
+       }
+
+       for (Iterator iter = h.keySet().iterator(); iter.hasNext();){
+               System.out.println(h.get(iter.next()));
+       }
+}
+       /**
+        *      Removes the entry from the entry queue.
+        *      Calls <code>privateRemoveEntry</code> with the external functionality enabled.
+        *
+        * @param shuffle indicates whether we are just shuffling the queue 
+        * (in which case, the entry table is not modified).
+        */
+       protected void privateRemoveEntry (LRUCacheEntry entry, boolean shuffle) {
+               privateRemoveEntry(entry, shuffle, true);
+       }
+/**
+ *     Removes the entry from the entry queue.  If <i>external</i> is true, the entry is removed
+ *     without checking if it can be removed.  It is assumed that the client has already closed
+ *     the element it is trying to remove (or will close it promptly).
+ *
+ *     If <i>external</i> is false, and the entry could not be closed, it is not removed and the 
+ *     pointers are not changed.
+ *
+ *     @param shuffle indicates whether we are just shuffling the queue 
+ *     (in which case, the entry table is not modified).
+ */
+protected void privateRemoveEntry(LRUCacheEntry entry, boolean shuffle, boolean external) {
+
+       if (!shuffle) {
+               if (external) {
+                       fEntryTable.remove(entry._fKey);                        
+                       fCurrentSpace -= entry._fSpace;
+                       privateNotifyDeletionFromCache(entry);
+               } else {
+                       if (!close(entry)) return;
+                       // buffer close will recursively call #privateRemoveEntry with external==true
+                       // thus entry will already be removed if reaching this point.
+                       if (fEntryTable.get(entry._fKey) == null){
+                               return;
+                       } else {
+                               // basic removal
+                               fEntryTable.remove(entry._fKey);                        
+                               fCurrentSpace -= entry._fSpace;
+                               privateNotifyDeletionFromCache(entry);
+                       }
+               }
+       }
+       LRUCacheEntry previous = entry._fPrevious;
+       LRUCacheEntry next = entry._fNext;
+               
+       /* if this was the first entry */
+       if (previous == null) {
+               fEntryQueue = next;
+       } else {
+               previous._fNext = next;
+       }
+       /* if this was the last entry */
+       if (next == null) {
+               fEntryQueueTail = previous;
+       } else {
+               next._fPrevious = previous;
+       }
+}
+       /**
+        * Sets the value in the cache at the given key. Returns the value.
+        *
+        * @param key Key of object to add.
+        * @param value Value of object to add.
+        * @return added value.
+        */
+       public Object put(Object key, Object value) {
+               /* attempt to rid ourselves of the overflow, if there is any */
+               if (fOverflow > 0)
+                       shrink();
+                       
+               /* Check whether there's an entry in the cache */
+               int newSpace = spaceFor (key, value);
+               LRUCacheEntry entry = (LRUCacheEntry) fEntryTable.get (key);
+               
+               if (entry != null) {
+                       
+                       /**
+                        * Replace the entry in the cache if it would not overflow
+                        * the cache.  Otherwise flush the entry and re-add it so as 
+                        * to keep cache within budget
+                        */
+                       int oldSpace = entry._fSpace;
+                       int newTotal = fCurrentSpace - oldSpace + newSpace;
+                       if (newTotal <= fSpaceLimit) {
+                               updateTimestamp (entry);
+                               entry._fValue = value;
+                               entry._fSpace = newSpace;
+                               fCurrentSpace = newTotal;
+                               fOverflow = 0;
+                               return value;
+                       } else {
+                               privateRemoveEntry (entry, false, false);
+                       }
+               }
+               
+               // attempt to make new space
+               makeSpace(newSpace);
+               
+               // add without worring about space, it will
+               // be handled later in a makeSpace call
+               privateAdd (key, value, newSpace);
+               
+               return value;
+       }
+       /**
+        * Removes and returns the value in the cache for the given key.
+        * If the key is not in the cache, returns null.
+        *
+        * @param key Key of object to remove from cache.
+        * @return Value removed from cache.
+        */
+       public Object remove(Object key) {
+               return removeKey(key);
+       }
+/**
+ * Sets the load factor for the cache.  The load factor determines how 
+ * much space is reclaimed when the cache exceeds its space limit.
+ * @param newLoadFactor double
+ * @throws IllegalArgumentException when the new load factor is not in (0.0, 1.0]
+ */
+public void setLoadFactor(double newLoadFactor) throws IllegalArgumentException {
+       if(newLoadFactor <= 1.0 && newLoadFactor > 0.0)
+               fLoadFactor = newLoadFactor;
+       else
+               throw new IllegalArgumentException(Util.bind("cache.invalidLoadFactor")); //$NON-NLS-1$
+}
+       /**
+        * Sets the maximum amount of space that the cache can store
+        *
+        * @param limit Number of units of cache space
+        */
+       public void setSpaceLimit(int limit) {
+               if (limit < fSpaceLimit) {
+                       makeSpace(fSpaceLimit - limit);
+               }
+               fSpaceLimit = limit;
+       }
+       /**
+        * Attempts to shrink the cache if it has overflown.
+        * Returns true if the cache shrinks to less than or equal to <code>fSpaceLimit</code>.
+        */
+       public boolean shrink() {
+               if (fOverflow > 0)
+                       return makeSpace(0);
+               return true;
+       }
+/**
+ * Returns a String that represents the value of this object.  This method
+ * is for debugging purposes only.
+ */
+public String toString() {
+       return 
+               "OverflowingLRUCache " + this.fillingRatio() + "% full\n" + //$NON-NLS-1$ //$NON-NLS-2$
+               this.toStringContents();
+}
+/**
+ * Updates the timestamp for the given entry, ensuring that the queue is 
+ * kept in correct order.  The entry must exist.
+ *
+ * <p>This method will do nothing if timestamps have been disabled.
+ */
+protected void updateTimestamp(LRUCacheEntry entry) {
+       if (fTimestampsOn) {
+               entry._fTimestamp = fTimestampCounter++;
+               if (fEntryQueue != entry) {
+                       this.privateRemoveEntry(entry, true);
+                       this.privateAddEntry(entry, true);
+               }
+       }
+}
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/Util.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/Util.java
new file mode 100644 (file)
index 0000000..6e68873
--- /dev/null
@@ -0,0 +1,1352 @@
+/*******************************************************************************
+ * 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.internal.core;
+
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.StringTokenizer;
+
+import net.sourceforge.phpdt.core.JavaModelException;
+import net.sourceforge.phpdt.core.compiler.CharOperation;
+import net.sourceforge.phpdt.internal.core.util.CharArrayBuffer;
+import net.sourceforge.phpdt.internal.corext.Assert;
+import net.sourceforge.phpeclipse.PHPCore;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+/**
+ * Provides convenient utility methods to other types in this package.
+ */
+public class Util {
+
+       private final static char[] DOUBLE_QUOTES = "''".toCharArray(); //$NON-NLS-1$
+       private final static char[] SINGLE_QUOTE = "'".toCharArray(); //$NON-NLS-1$
+       private static final String ARGUMENTS_DELIMITER = "#"; //$NON-NLS-1$
+       private static final String EMPTY_ARGUMENT = "   "; //$NON-NLS-1$
+
+       public interface Comparable {
+               /**
+                * Returns 0 if this and c are equal, >0 if this is greater than c,
+                * or <0 if this is less than c.
+                */
+               int compareTo(Comparable c);
+       }
+
+       public interface Comparer {
+               /**
+                * Returns 0 if a and b are equal, >0 if a is greater than b,
+                * or <0 if a is less than b.
+                */
+               int compare(Object a, Object b);
+       }
+       
+       public interface Displayable {
+               String displayString(Object o);
+       }
+       
+       public static final String[] fgEmptyStringArray = new String[0];
+
+       /**
+        * Are we running JDK 1.1?
+        */
+       private static boolean JDK1_1 = false;
+
+       /* Bundle containing messages */
+       protected static ResourceBundle bundle;
+       private final static String bundleName = "org.eclipse.jdt.internal.core.messages"; //$NON-NLS-1$
+
+       public final static char[] SUFFIX_class = ".class".toCharArray(); //$NON-NLS-1$
+       public final static char[] SUFFIX_CLASS = ".CLASS".toCharArray(); //$NON-NLS-1$
+       public final static char[] SUFFIX_java = ".java".toCharArray(); //$NON-NLS-1$
+       public final static char[] SUFFIX_JAVA = ".JAVA".toCharArray(); //$NON-NLS-1$
+       public final static char[] SUFFIX_jar = ".jar".toCharArray(); //$NON-NLS-1$
+       public final static char[] SUFFIX_JAR = ".JAR".toCharArray(); //$NON-NLS-1$
+       public final static char[] SUFFIX_zip = ".zip".toCharArray(); //$NON-NLS-1$
+       public final static char[] SUFFIX_ZIP = ".ZIP".toCharArray(); //$NON-NLS-1$
+
+       static {
+               String ver = System.getProperty("java.version"); //$NON-NLS-1$
+               JDK1_1 = ((ver != null) && ver.startsWith("1.1")); //$NON-NLS-1$
+               relocalize();
+       }       
+       
+       /**
+        * Lookup the message with the given ID in this catalog 
+        */
+       public static String bind(String id) {
+               return bind(id, (String[])null);
+       }
+       
+       /**
+        * Lookup the message with the given ID in this catalog and bind its
+        * substitution locations with the given string values.
+        */
+       public static String bind(String id, String[] bindings) {
+               if (id == null)
+                       return "No message available"; //$NON-NLS-1$
+               String message = null;
+               try {
+                       message = bundle.getString(id);
+               } catch (MissingResourceException e) {
+                       // If we got an exception looking for the message, fail gracefully by just returning
+                       // the id we were looking for.  In most cases this is semi-informative so is not too bad.
+                       return "Missing message: " + id + " in: " + bundleName; //$NON-NLS-2$ //$NON-NLS-1$
+               }
+               // for compatibility with MessageFormat which eliminates double quotes in original message
+               char[] messageWithNoDoubleQuotes =
+               CharOperation.replace(message.toCharArray(), DOUBLE_QUOTES, SINGLE_QUOTE);
+               message = new String(messageWithNoDoubleQuotes);
+       
+               if (bindings == null)
+                       return message;
+       
+               int length = message.length();
+               int start = -1;
+               int end = length;
+               StringBuffer output = new StringBuffer(80);
+               while (true) {
+                       if ((end = message.indexOf('{', start)) > -1) {
+                               output.append(message.substring(start + 1, end));
+                               if ((start = message.indexOf('}', end)) > -1) {
+                                       int index = -1;
+                                       try {
+                                               index = Integer.parseInt(message.substring(end + 1, start));
+                                               output.append(bindings[index]);
+                                       } catch (NumberFormatException nfe) {
+                                               output.append(message.substring(end + 1, start + 1));
+                                       } catch (ArrayIndexOutOfBoundsException e) {
+                                               output.append("{missing " + Integer.toString(index) + "}"); //$NON-NLS-2$ //$NON-NLS-1$
+                                       }
+                               } else {
+                                       output.append(message.substring(end, length));
+                                       break;
+                               }
+                       } else {
+                               output.append(message.substring(start + 1, length));
+                               break;
+                       }
+               }
+               return output.toString();
+       }
+
+       /**
+        * Lookup the message with the given ID in this catalog and bind its
+        * substitution locations with the given string.
+        */
+       public static String bind(String id, String binding) {
+               return bind(id, new String[] {binding});
+       }
+       
+       /**
+        * Lookup the message with the given ID in this catalog and bind its
+        * substitution locations with the given strings.
+        */
+       public static String bind(String id, String binding1, String binding2) {
+               return bind(id, new String[] {binding1, binding2});
+       }
+
+       /**
+        * Checks the type signature in String sig, 
+        * starting at start and ending before end (end is not included).
+        * Returns the index of the character immediately after the signature if valid,
+        * or -1 if not valid.
+        */
+       private static int checkTypeSignature(String sig, int start, int end, boolean allowVoid) {
+               if (start >= end) return -1;
+               int i = start;
+               char c = sig.charAt(i++);
+               int nestingDepth = 0;
+               while (c == '[') {
+                       ++nestingDepth;
+                       if (i >= end) return -1;
+                       c = sig.charAt(i++);
+               }
+               switch (c) {
+                       case 'B':
+                       case 'C': 
+                       case 'D':
+                       case 'F':
+                       case 'I':
+                       case 'J':
+                       case 'S': 
+                       case 'Z':
+                               break;
+                       case 'V':
+                               if (!allowVoid) return -1;
+                               // array of void is not allowed
+                               if (nestingDepth != 0) return -1;
+                               break;
+                       case 'L':
+                               int semicolon = sig.indexOf(';', i);
+                               // Must have at least one character between L and ;
+                               if (semicolon <= i || semicolon >= end) return -1;
+                               i = semicolon + 1;
+                               break;
+                       default:
+                               return -1;
+               }
+               return i;
+       }
+       
+       /**
+        * Combines two hash codes to make a new one.
+        */
+       public static int combineHashCodes(int hashCode1, int hashCode2) {
+               return hashCode1 * 17 + hashCode2;
+       }
+       
+       /**
+        * Compares two byte arrays.  
+        * Returns <0 if a byte in a is less than the corresponding byte in b, or if a is shorter, or if a is null.
+        * Returns >0 if a byte in a is greater than the corresponding byte in b, or if a is longer, or if b is null.
+        * Returns 0 if they are equal or both null.
+        */
+       public static int compare(byte[] a, byte[] b) {
+               if (a == b)
+                       return 0;
+               if (a == null)
+                       return -1;
+               if (b == null)
+                       return 1;
+               int len = Math.min(a.length, b.length);
+               for (int i = 0; i < len; ++i) {
+                       int diff = a[i] - b[i];
+                       if (diff != 0)
+                               return diff;
+               }
+               if (a.length > len)
+                       return 1;
+               if (b.length > len)
+                       return -1;
+               return 0;
+       }
+
+       /**
+        * Compares two char arrays lexicographically. 
+        * The comparison is based on the Unicode value of each character in
+        * the char arrays. 
+        * @return  the value <code>0</code> if a is equal to
+        *          b; a value less than <code>0</code> if a
+        *          is lexicographically less than b; and a
+        *          value greater than <code>0</code> if a is
+        *          lexicographically greater than b.
+        */
+       public static int compare(char[] v1, char[] v2) {
+               int len1 = v1.length;
+               int len2 = v2.length;
+               int n = Math.min(len1, len2);
+               int i = 0;
+               while (n-- != 0) {
+                       if (v1[i] != v2[i]) {
+                               return v1[i] - v2[i];
+                       }
+                       ++i;
+               }
+               return len1 - len2;
+       }
+
+       /**
+        * Concatenate two strings with a char in between.
+        * @see #concat(String, String)
+        */
+       public static String concat(String s1, char c, String s2) {
+               if (s1 == null) s1 = "null"; //$NON-NLS-1$
+               if (s2 == null) s2 = "null"; //$NON-NLS-1$
+               int l1 = s1.length();
+               int l2 = s2.length();
+               char[] buf = new char[l1 + 1 + l2];
+               s1.getChars(0, l1, buf, 0);
+               buf[l1] = c;
+               s2.getChars(0, l2, buf, l1 + 1);
+               return new String(buf);
+       }
+       
+       /**
+        * Concatenate two strings.
+        * Much faster than using +, which:
+        *              - creates a StringBuffer,
+        *              - which is synchronized,
+        *              - of default size, so the resulting char array is
+        *        often larger than needed.
+        * This implementation creates an extra char array, since the
+        * String constructor copies its argument, but there's no way around this.
+        */
+       public static String concat(String s1, String s2) {
+               if (s1 == null) s1 = "null"; //$NON-NLS-1$
+               if (s2 == null) s2 = "null"; //$NON-NLS-1$
+               int l1 = s1.length();
+               int l2 = s2.length();
+               char[] buf = new char[l1 + l2];
+               s1.getChars(0, l1, buf, 0);
+               s2.getChars(0, l2, buf, l1);
+               return new String(buf);
+       }
+
+       /**
+        * Concatenate three strings.
+        * @see #concat(String, String)
+        */
+       public static String concat(String s1, String s2, String s3) {
+               if (s1 == null) s1 = "null"; //$NON-NLS-1$
+               if (s2 == null) s2 = "null"; //$NON-NLS-1$
+               if (s3 == null) s3 = "null"; //$NON-NLS-1$
+               int l1 = s1.length();
+               int l2 = s2.length();
+               int l3 = s3.length();
+               char[] buf = new char[l1 + l2 + l3];
+               s1.getChars(0, l1, buf, 0);
+               s2.getChars(0, l2, buf, l1);
+               s3.getChars(0, l3, buf, l1 + l2);
+               return new String(buf);
+       }
+       
+       /**
+        * Converts a type signature from the IBinaryType representation to the DC representation.
+        */
+       public static String convertTypeSignature(char[] sig) {
+               return new String(sig).replace('/', '.');
+       }
+
+       /**
+        * Returns true iff str.toLowerCase().endsWith(end.toLowerCase())
+        * implementation is not creating extra strings.
+        */
+       public final static boolean endsWithIgnoreCase(String str, String end) {
+               
+               int strLength = str == null ? 0 : str.length();
+               int endLength = end == null ? 0 : end.length();
+               
+               // return false if the string is smaller than the end.
+               if(endLength > strLength)
+                       return false;
+                       
+               // return false if any character of the end are
+               // not the same in lower case.
+               for(int i = 1 ; i <= endLength; i++){
+                       if(Character.toLowerCase(end.charAt(endLength - i)) != Character.toLowerCase(str.charAt(strLength - i)))
+                               return false;
+               }
+               
+               return true;
+       }
+
+       /**
+        * Compares two arrays using equals() on the elements.
+        * Either or both arrays may be null.
+        * Returns true if both are null.
+        * Returns false if only one is null.
+        * If both are arrays, returns true iff they have the same length and
+        * all elements are equal.
+        */
+       public static boolean equalArraysOrNull(int[] a, int[] b) {
+               if (a == b)
+                       return true;
+               if (a == null || b == null)
+                       return false;
+               int len = a.length;
+               if (len != b.length)
+                       return false;
+               for (int i = 0; i < len; ++i) {
+                       if (a[i] != b[i])
+                               return false;
+               }
+               return true;
+       }
+
+       /**
+        * Compares two arrays using equals() on the elements.
+        * Either or both arrays may be null.
+        * Returns true if both are null.
+        * Returns false if only one is null.
+        * If both are arrays, returns true iff they have the same length and
+        * all elements compare true with equals.
+        */
+       public static boolean equalArraysOrNull(Object[] a, Object[] b) {
+               if (a == b)     return true;
+               if (a == null || b == null) return false;
+
+               int len = a.length;
+               if (len != b.length) return false;
+               for (int i = 0; i < len; ++i) {
+                       if (a[i] == null) {
+                               if (b[i] != null) return false;
+                       } else {
+                               if (!a[i].equals(b[i])) return false;
+                       }
+               }
+               return true;
+       }
+       
+       /**
+        * Compares two String arrays using equals() on the elements.
+        * The arrays are first sorted.
+        * Either or both arrays may be null.
+        * Returns true if both are null.
+        * Returns false if only one is null.
+        * If both are arrays, returns true iff they have the same length and
+        * iff, after sorting both arrays, all elements compare true with equals.
+        * The original arrays are left untouched.
+        */
+       public static boolean equalArraysOrNullSortFirst(String[] a, String[] b) {
+               if (a == b)     return true;
+               if (a == null || b == null) return false;
+               int len = a.length;
+               if (len != b.length) return false;
+               if (len >= 2) {  // only need to sort if more than two items
+                       a = sortCopy(a);
+                       b = sortCopy(b);
+               }
+               for (int i = 0; i < len; ++i) {
+                       if (!a[i].equals(b[i])) return false;
+               }
+               return true;
+       }
+       
+       /**
+        * Compares two arrays using equals() on the elements.
+        * The arrays are first sorted.
+        * Either or both arrays may be null.
+        * Returns true if both are null.
+        * Returns false if only one is null.
+        * If both are arrays, returns true iff they have the same length and
+        * iff, after sorting both arrays, all elements compare true with equals.
+        * The original arrays are left untouched.
+        */
+       public static boolean equalArraysOrNullSortFirst(Comparable[] a, Comparable[] b) {
+               if (a == b)     return true;
+               if (a == null || b == null) return false;
+               int len = a.length;
+               if (len != b.length) return false;
+               if (len >= 2) {  // only need to sort if more than two items
+                       a = sortCopy(a);
+                       b = sortCopy(b);
+               }
+               for (int i = 0; i < len; ++i) {
+                       if (!a[i].equals(b[i])) return false;
+               }
+               return true;
+       }
+       
+       /**
+        * Compares two objects using equals().
+        * Either or both array may be null.
+        * Returns true if both are null.
+        * Returns false if only one is null.
+        * Otherwise, return the result of comparing with equals().
+        */
+       public static boolean equalOrNull(Object a, Object b) {
+               if (a == b) {
+                       return true;
+               }
+               if (a == null || b == null) {
+                       return false;
+               }
+               return a.equals(b);
+       }
+       
+       /**
+        * Given a qualified name, extract the last component.
+        * If the input is not qualified, the same string is answered.
+        */
+       public static String extractLastName(String qualifiedName) {
+               int i = qualifiedName.lastIndexOf('.');
+               if (i == -1) return qualifiedName;
+               return qualifiedName.substring(i+1);
+       }
+       
+       /**
+        * Extracts the parameter types from a method signature.
+        */
+       public static String[] extractParameterTypes(char[] sig) {
+               int count = getParameterCount(sig);
+               String[] result = new String[count];
+               if (count == 0)
+                       return result;
+               int i = CharOperation.indexOf('(', sig) + 1;
+               count = 0;
+               int len = sig.length;
+               int start = i;
+               for (;;) {
+                       if (i == len)
+                               break;
+                       char c = sig[i];
+                       if (c == ')')
+                               break;
+                       if (c == '[') {
+                               ++i;
+                       } else
+                               if (c == 'L') {
+                                       i = CharOperation.indexOf(';', sig, i + 1) + 1;
+                                       Assert.isTrue(i != 0);
+                                       result[count++] = convertTypeSignature(CharOperation.subarray(sig, start, i));
+                                       start = i;
+                               } else {
+                                       ++i;
+                                       result[count++] = convertTypeSignature(CharOperation.subarray(sig, start, i));
+                                       start = i;
+                               }
+               }
+               return result;
+       }
+
+       /**
+        * Extracts the return type from a method signature.
+        */
+       public static String extractReturnType(String sig) {
+               int i = sig.lastIndexOf(')');
+               Assert.isTrue(i != -1);
+               return sig.substring(i+1);      
+       }
+       
+       /**
+        * Finds the first line separator used by the given text.
+        *
+        * @return </code>"\n"</code> or </code>"\r"</code> or  </code>"\r\n"</code>,
+        *                      or <code>null</code> if none found
+        */
+       public static String findLineSeparator(char[] text) {
+               // find the first line separator
+               int length = text.length;
+               if (length > 0) {
+                       char nextChar = text[0];
+                       for (int i = 0; i < length; i++) {
+                               char currentChar = nextChar;
+                               nextChar = i < length-1 ? text[i+1] : ' ';
+                               switch (currentChar) {
+                                       case '\n': return "\n"; //$NON-NLS-1$
+                                       case '\r': return nextChar == '\n' ? "\r\n" : "\r"; //$NON-NLS-1$ //$NON-NLS-2$
+                               }
+                       }
+               }
+               // not found
+               return null;
+       }
+       
+       /**
+        * Returns the line separator used by the given buffer.
+        * Uses the given text if none found.
+        *
+        * @return </code>"\n"</code> or </code>"\r"</code> or  </code>"\r\n"</code>
+        */
+       private static String getLineSeparator(char[] text, char[] buffer) {
+               // search in this buffer's contents first
+               String lineSeparator = findLineSeparator(buffer);
+               if (lineSeparator == null) {
+                       // search in the given text
+                       lineSeparator = findLineSeparator(text);
+                       if (lineSeparator == null) {
+                               // default to system line separator
+                               return System.getProperty("line.separator");
+                       }
+               }
+               return lineSeparator;
+       }
+               
+       /**
+        * Returns the number of parameter types in a method signature.
+        */
+       public static int getParameterCount(char[] sig) {
+               int i = CharOperation.indexOf('(', sig) + 1;
+               Assert.isTrue(i != 0);
+               int count = 0;
+               int len = sig.length;
+               for (;;) {
+                       if (i == len)
+                               break;
+                       char c = sig[i];
+                       if (c == ')')
+                               break;
+                       if (c == '[') {
+                               ++i;
+                       } else
+                               if (c == 'L') {
+                                       ++count;
+                                       i = CharOperation.indexOf(';', sig, i + 1) + 1;
+                                       Assert.isTrue(i != 0);
+                               } else {
+                                       ++count;
+                                       ++i;
+                               }
+               }
+               return count;
+       }
+       
+//     /**
+//      * Returns the given file's contents as a byte array.
+//      */
+//     public static byte[] getResourceContentsAsByteArray(IFile file) throws JavaModelException {
+//             InputStream stream= null;
+//             try {
+//                     stream = new BufferedInputStream(file.getContents(true));
+//             } catch (CoreException e) {
+//                     throw new JavaModelException(e);
+//             }
+//             try {
+//                     return org.eclipse.jdt.internal.compiler.util.Util.getInputStreamAsByteArray(stream, -1);
+//             } catch (IOException e) {
+//                     throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
+//             } finally {
+//                     try {
+//                             stream.close();
+//                     } catch (IOException e) {
+//                     }
+//             }
+//     }
+//     
+//     /**
+//      * Returns the given file's contents as a character array.
+//      */
+//     public static char[] getResourceContentsAsCharArray(IFile file) throws JavaModelException {
+//             String encoding = JavaCore.create(file.getProject()).getOption(JavaCore.CORE_ENCODING, true);
+//             return getResourceContentsAsCharArray(file, encoding);
+//     }
+//
+//     public static char[] getResourceContentsAsCharArray(IFile file, String encoding) throws JavaModelException {
+//             InputStream stream= null;
+//             try {
+//                     stream = new BufferedInputStream(file.getContents(true));
+//             } catch (CoreException e) {
+//                     throw new JavaModelException(e, IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST);
+//             }
+//             try {
+//                     return org.eclipse.jdt.internal.compiler.util.Util.getInputStreamAsCharArray(stream, -1, encoding);
+//             } catch (IOException e) {
+//                     throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
+//             } finally {
+//                     try {
+//                             stream.close();
+//                     } catch (IOException e) {
+//                     }
+//             }
+//     }
+//     
+//     /**
+//      * Returns a trimmed version the simples names returned by Signature.
+//      */
+//     public static String[] getTrimmedSimpleNames(String name) {
+//             String[] result = Signature.getSimpleNames(name);
+//             if (result == null) return null;
+//             for (int i = 0, length = result.length; i < length; i++) {
+//                     result[i] = result[i].trim();
+//             }
+//             return result;
+//     }
+       
+       /**
+        * Returns true iff str.toLowerCase().endsWith(".class")
+        * implementation is not creating extra strings.
+        */
+       public final static boolean isClassFileName(String name) {
+               int nameLength = name == null ? 0 : name.length();
+               int suffixLength = SUFFIX_CLASS.length;
+               if (nameLength < suffixLength) return false;
+
+               for (int i = 0, offset = nameLength - suffixLength; i < suffixLength; i++) {
+                       char c = name.charAt(offset + i);
+                       if (c != SUFFIX_class[i] && c != SUFFIX_CLASS[i]) return false;
+               }
+               return true;            
+       }
+       
+       /*
+        * Returns whether the given java element is exluded from its root's classpath.
+        */
+//     public static final boolean isExcluded(IJavaElement element) {
+//             int elementType = element.getElementType();
+//             switch (elementType) {
+//                     case IJavaElement.PACKAGE_FRAGMENT:
+//                             PackageFragmentRoot root = (PackageFragmentRoot)element.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
+//                             IResource resource = element.getResource();
+//                             return resource != null && Util.isExcluded(resource, root.fullExclusionPatternChars());
+//                     case IJavaElement.COMPILATION_UNIT:
+//                             root = (PackageFragmentRoot)element.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
+//                             resource = element.getResource();
+//                             if (resource != null && Util.isExcluded(resource, root.fullExclusionPatternChars()))
+//                                     return true;
+//                             return isExcluded(element.getParent());
+//                     default:
+//                             IJavaElement cu = element.getAncestor(IJavaElement.COMPILATION_UNIT);
+//                             return cu != null && isExcluded(cu);
+//             }
+//     }
+       /*
+        * Returns whether the given resource path matches one of the exclusion
+        * patterns.
+        * 
+        * @see IClasspathEntry#getExclusionPatterns
+        */
+       public final static boolean isExcluded(IPath resourcePath, char[][] exclusionPatterns) {
+               if (exclusionPatterns == null) return false;
+               char[] path = resourcePath.toString().toCharArray();
+               for (int i = 0, length = exclusionPatterns.length; i < length; i++)
+                       if (CharOperation.pathMatch(exclusionPatterns[i], path, true, '/'))
+                               return true;
+               return false;
+       }       
+       
+       /*
+        * Returns whether the given resource matches one of the exclusion patterns.
+        * 
+        * @see IClasspathEntry#getExclusionPatterns
+        */
+       public final static boolean isExcluded(IResource resource, char[][] exclusionPatterns) {
+               IPath path = resource.getFullPath();
+               // ensure that folders are only excluded if all of their children are excluded
+               if (resource.getType() == IResource.FOLDER)
+                       path = path.append("*"); //$NON-NLS-1$
+               return isExcluded(path, exclusionPatterns);
+       }
+
+       /**
+        * Returns true iff str.toLowerCase().endsWith(".jar" or ".zip")
+        * implementation is not creating extra strings.
+        */
+       public final static boolean isArchiveFileName(String name) {
+               int nameLength = name == null ? 0 : name.length();
+               int suffixLength = SUFFIX_JAR.length;
+               if (nameLength < suffixLength) return false;
+
+               int i, offset;
+               for ( i = 0, offset = nameLength - suffixLength; i < suffixLength; i++) {
+                       char c = name.charAt(offset + i);
+                       if (c != SUFFIX_jar[i] && c != SUFFIX_JAR[i]) break;
+               }
+               if (i == suffixLength) return true;             
+               for ( i = 0, offset = nameLength - suffixLength; i < suffixLength; i++) {
+                       char c = name.charAt(offset + i);
+                       if (c != SUFFIX_zip[i] && c != SUFFIX_ZIP[i]) return false;
+               }
+               return true;
+       }
+       
+       /**
+        * Validate the given compilation unit name.
+        * A compilation unit name must obey the following rules:
+        * <ul>
+        * <li> it must not be null
+        * <li> it must include the <code>".java"</code> suffix
+        * <li> its prefix must be a valid identifier
+        * </ul>
+        * </p>
+        * @param name the name of a compilation unit
+        * @return a status object with code <code>IStatus.OK</code> if
+        *              the given name is valid as a compilation unit name, otherwise a status 
+        *              object indicating what is wrong with the name
+        */
+//     public static boolean isValidCompilationUnitName(String name) {
+//             return JavaConventions.validateCompilationUnitName(name).getSeverity() != IStatus.ERROR;
+//     }
+
+       /**
+        * Validate the given .class file name.
+        * A .class file name must obey the following rules:
+        * <ul>
+        * <li> it must not be null
+        * <li> it must include the <code>".class"</code> suffix
+        * <li> its prefix must be a valid identifier
+        * </ul>
+        * </p>
+        * @param name the name of a .class file
+        * @return a status object with code <code>IStatus.OK</code> if
+        *              the given name is valid as a .class file name, otherwise a status 
+        *              object indicating what is wrong with the name
+        */
+//     public static boolean isValidClassFileName(String name) {
+//             return JavaConventions.validateClassFileName(name).getSeverity() != IStatus.ERROR;
+//     }
+
+       /**
+        * Returns true iff str.toLowerCase().endsWith(".java")
+        * implementation is not creating extra strings.
+        */
+       public final static boolean isJavaFileName(String name) {
+               int nameLength = name == null ? 0 : name.length();
+               int suffixLength = SUFFIX_JAVA.length;
+               if (nameLength < suffixLength) return false;
+
+               for (int i = 0, offset = nameLength - suffixLength; i < suffixLength; i++) {
+                       char c = name.charAt(offset + i);
+                       if (c != SUFFIX_java[i] && c != SUFFIX_JAVA[i]) return false;
+               }
+               return true;            
+       }
+
+       /**
+        * Returns true if the given method signature is valid,
+        * false if it is not.
+        */
+       public static boolean isValidMethodSignature(String sig) {
+               int len = sig.length();
+               if (len == 0) return false;
+               int i = 0;
+               char c = sig.charAt(i++);
+               if (c != '(') return false;
+               if (i >= len) return false;
+               while (sig.charAt(i) != ')') {
+                       // Void is not allowed as a parameter type.
+                       i = checkTypeSignature(sig, i, len, false);
+                       if (i == -1) return false;
+                       if (i >= len) return false;
+               }
+               ++i;
+               i = checkTypeSignature(sig, i, len, true);
+               return i == len;
+       }
+       
+       /**
+        * Returns true if the given type signature is valid,
+        * false if it is not.
+        */
+       public static boolean isValidTypeSignature(String sig, boolean allowVoid) {
+               int len = sig.length();
+               return checkTypeSignature(sig, 0, len, allowVoid) == len;
+       }
+       
+       /**
+        * Returns true if the given folder name is valid for a package,
+        * false if it is not.
+        */
+//     public static boolean isValidFolderNameForPackage(String folderName) {
+//             return JavaConventions.validateIdentifier(folderName).getSeverity() != IStatus.ERROR;
+//     }       
+
+       /*
+        * Add a log entry
+        */
+       public static void log(Throwable e, String message) {
+               Throwable nestedException;
+               if (e instanceof JavaModelException 
+                               && (nestedException = ((JavaModelException)e).getException()) != null) {
+                       e = nestedException;
+               }
+               IStatus status= new Status(
+                       IStatus.ERROR, 
+                       PHPCore.getPlugin().getDescriptor().getUniqueIdentifier(), 
+                       IStatus.ERROR, 
+                       message, 
+                       e); 
+               PHPCore.getPlugin().getLog().log(status);
+       }       
+       
+       /**
+        * Normalizes the cariage returns in the given text.
+        * They are all changed  to use the given buffer's line separator.
+        */
+       public static char[] normalizeCRs(char[] text, char[] buffer) {
+               CharArrayBuffer result = new CharArrayBuffer();
+               int lineStart = 0;
+               int length = text.length;
+               if (length == 0) return text;
+               String lineSeparator = getLineSeparator(text, buffer);
+               char nextChar = text[0];
+               for (int i = 0; i < length; i++) {
+                       char currentChar = nextChar;
+                       nextChar = i < length-1 ? text[i+1] : ' ';
+                       switch (currentChar) {
+                               case '\n':
+                                       int lineLength = i-lineStart;
+                                       char[] line = new char[lineLength];
+                                       System.arraycopy(text, lineStart, line, 0, lineLength);
+                                       result.append(line);
+                                       result.append(lineSeparator);
+                                       lineStart = i+1;
+                                       break;
+                               case '\r':
+                                       lineLength = i-lineStart;
+                                       if (lineLength >= 0) {
+                                               line = new char[lineLength];
+                                               System.arraycopy(text, lineStart, line, 0, lineLength);
+                                               result.append(line);
+                                               result.append(lineSeparator);
+                                               if (nextChar == '\n') {
+                                                       nextChar = ' ';
+                                                       lineStart = i+2;
+                                               } else {
+                                                       // when line separator are mixed in the same file
+                                                       // \r might not be followed by a \n. If not, we should increment
+                                                       // lineStart by one and not by two.
+                                                       lineStart = i+1;
+                                               }
+                                       } else {
+                                               // when line separator are mixed in the same file
+                                               // we need to prevent NegativeArraySizeException
+                                               lineStart = i+1;
+                                       }
+                                       break;
+                       }
+               }
+               char[] lastLine;
+               if (lineStart > 0) {
+                       int lastLineLength = length-lineStart;
+                       if (lastLineLength > 0) {
+                               lastLine = new char[lastLineLength];
+                               System.arraycopy(text, lineStart, lastLine, 0, lastLineLength);
+                               result.append(lastLine);
+                       }
+                       return result.getContents();
+               } else {
+                       return text;
+               }
+       }
+
+       /**
+        * Normalizes the cariage returns in the given text.
+        * They are all changed  to use given buffer's line sepatator.
+        */
+       public static String normalizeCRs(String text, String buffer) {
+               return new String(normalizeCRs(text.toCharArray(), buffer.toCharArray()));
+       }
+
+       /**
+        * Sort the objects in the given collection using the given sort order.
+        */
+       private static void quickSort(Object[] sortedCollection, int left, int right, int[] sortOrder) {
+               int original_left = left;
+               int original_right = right;
+               int mid = sortOrder[ (left + right) / 2];
+               do {
+                       while (sortOrder[left] < mid) {
+                               left++;
+                       }
+                       while (mid < sortOrder[right]) {
+                               right--;
+                       }
+                       if (left <= right) {
+                               Object tmp = sortedCollection[left];
+                               sortedCollection[left] = sortedCollection[right];
+                               sortedCollection[right] = tmp;
+                               int tmp2 = sortOrder[left];
+                               sortOrder[left] = sortOrder[right];
+                               sortOrder[right] = tmp2;
+                               left++;
+                               right--;
+                       }
+               } while (left <= right);
+               if (original_left < right) {
+                       quickSort(sortedCollection, original_left, right, sortOrder);
+               }
+               if (left < original_right) {
+                       quickSort(sortedCollection, left, original_right, sortOrder);
+               }
+       }
+
+       /**
+        * Sort the objects in the given collection using the given comparer.
+        */
+       private static void quickSort(Object[] sortedCollection, int left, int right, Comparer comparer) {
+               int original_left = left;
+               int original_right = right;
+               Object mid = sortedCollection[ (left + right) / 2];
+               do {
+                       while (comparer.compare(sortedCollection[left], mid) < 0) {
+                               left++;
+                       }
+                       while (comparer.compare(mid, sortedCollection[right]) < 0) {
+                               right--;
+                       }
+                       if (left <= right) {
+                               Object tmp = sortedCollection[left];
+                               sortedCollection[left] = sortedCollection[right];
+                               sortedCollection[right] = tmp;
+                               left++;
+                               right--;
+                       }
+               } while (left <= right);
+               if (original_left < right) {
+                       quickSort(sortedCollection, original_left, right, comparer);
+               }
+               if (left < original_right) {
+                       quickSort(sortedCollection, left, original_right, comparer);
+               }
+       }
+
+       /**
+        * Sort the strings in the given collection.
+        */
+       private static void quickSort(String[] sortedCollection, int left, int right) {
+               int original_left = left;
+               int original_right = right;
+               String mid = sortedCollection[ (left + right) / 2];
+               do {
+                       while (sortedCollection[left].compareTo(mid) < 0) {
+                               left++;
+                       }
+                       while (mid.compareTo(sortedCollection[right]) < 0) {
+                               right--;
+                       }
+                       if (left <= right) {
+                               String tmp = sortedCollection[left];
+                               sortedCollection[left] = sortedCollection[right];
+                               sortedCollection[right] = tmp;
+                               left++;
+                               right--;
+                       }
+               } while (left <= right);
+               if (original_left < right) {
+                       quickSort(sortedCollection, original_left, right);
+               }
+               if (left < original_right) {
+                       quickSort(sortedCollection, left, original_right);
+               }
+       }
+
+       /**
+        * Converts the given relative path into a package name.
+        * Returns null if the path is not a valid package name.
+        */
+//     public static String packageName(IPath pkgPath) {
+//             StringBuffer pkgName = new StringBuffer(IPackageFragment.DEFAULT_PACKAGE_NAME);
+//             for (int j = 0, max = pkgPath.segmentCount(); j < max; j++) {
+//                     String segment = pkgPath.segment(j);
+//                     if (!isValidFolderNameForPackage(segment)) {
+//                             return null;
+//                     }
+//                     pkgName.append(segment);
+//                     if (j < pkgPath.segmentCount() - 1) {
+//                             pkgName.append("." ); //$NON-NLS-1$
+//                     }
+//             }
+//             return pkgName.toString();
+//     }
+
+       /**
+        * Sort the comparable objects in the given collection.
+        */
+       private static void quickSort(Comparable[] sortedCollection, int left, int right) {
+               int original_left = left;
+               int original_right = right;
+               Comparable mid = sortedCollection[ (left + right) / 2];
+               do {
+                       while (sortedCollection[left].compareTo(mid) < 0) {
+                               left++;
+                       }
+                       while (mid.compareTo(sortedCollection[right]) < 0) {
+                               right--;
+                       }
+                       if (left <= right) {
+                               Comparable tmp = sortedCollection[left];
+                               sortedCollection[left] = sortedCollection[right];
+                               sortedCollection[right] = tmp;
+                               left++;
+                               right--;
+                       }
+               } while (left <= right);
+               if (original_left < right) {
+                       quickSort(sortedCollection, original_left, right);
+               }
+               if (left < original_right) {
+                       quickSort(sortedCollection, left, original_right);
+               }
+       }
+
+       /**
+        * Sort the strings in the given collection in reverse alphabetical order.
+        */
+       private static void quickSortReverse(String[] sortedCollection, int left, int right) {
+               int original_left = left;
+               int original_right = right;
+               String mid = sortedCollection[ (left + right) / 2];
+               do {
+                       while (sortedCollection[left].compareTo(mid) > 0) {
+                               left++;
+                       }
+                       while (mid.compareTo(sortedCollection[right]) > 0) {
+                               right--;
+                       }
+                       if (left <= right) {
+                               String tmp = sortedCollection[left];
+                               sortedCollection[left] = sortedCollection[right];
+                               sortedCollection[right] = tmp;
+                               left++;
+                               right--;
+                       }
+               } while (left <= right);
+               if (original_left < right) {
+                       quickSortReverse(sortedCollection, original_left, right);
+               }
+               if (left < original_right) {
+                       quickSortReverse(sortedCollection, left, original_right);
+               }
+       }
+
+       /**
+        * Sorts an array of objects in place, using the sort order given for each item.
+        */
+       public static void sort(Object[] objects, int[] sortOrder) {
+               if (objects.length > 1)
+                       quickSort(objects, 0, objects.length - 1, sortOrder);
+       }
+
+       /**
+        * Sorts an array of objects in place.
+        * The given comparer compares pairs of items.
+        */
+       public static void sort(Object[] objects, Comparer comparer) {
+               if (objects.length > 1)
+                       quickSort(objects, 0, objects.length - 1, comparer);
+       }
+
+       /**
+        * Sorts an array of strings in place using quicksort.
+        */
+       public static void sort(String[] strings) {
+               if (strings.length > 1)
+                       quickSort(strings, 0, strings.length - 1);
+       }
+
+       /**
+        * Sorts an array of Comparable objects in place.
+        */
+       public static void sort(Comparable[] objects) {
+               if (objects.length > 1)
+                       quickSort(objects, 0, objects.length - 1);
+       }
+
+       /**
+        * Sorts an array of Strings, returning a new array
+        * with the sorted items.  The original array is left untouched.
+        */
+       public static Object[] sortCopy(Object[] objects, Comparer comparer) {
+               int len = objects.length;
+               Object[] copy = new Object[len];
+               System.arraycopy(objects, 0, copy, 0, len);
+               sort(copy, comparer);
+               return copy;
+       }
+
+       /**
+        * Sorts an array of Strings, returning a new array
+        * with the sorted items.  The original array is left untouched.
+        */
+       public static String[] sortCopy(String[] objects) {
+               int len = objects.length;
+               String[] copy = new String[len];
+               System.arraycopy(objects, 0, copy, 0, len);
+               sort(copy);
+               return copy;
+       }
+
+       /**
+        * Sorts an array of Comparable objects, returning a new array
+        * with the sorted items.  The original array is left untouched.
+        */
+       public static Comparable[] sortCopy(Comparable[] objects) {
+               int len = objects.length;
+               Comparable[] copy = new Comparable[len];
+               System.arraycopy(objects, 0, copy, 0, len);
+               sort(copy);
+               return copy;
+       }
+
+       /**
+        * Sorts an array of strings in place using quicksort
+        * in reverse alphabetical order.
+        */
+       public static void sortReverseOrder(String[] strings) {
+               if (strings.length > 1)
+                       quickSortReverse(strings, 0, strings.length - 1);
+       }
+
+       /**
+        * Converts a String[] to char[][].
+        */
+       public static char[][] toCharArrays(String[] a) {
+               int len = a.length;
+               char[][] result = new char[len][];
+               for (int i = 0; i < len; ++i) {
+                       result[i] = toChars(a[i]);
+               }
+               return result;
+       }
+
+       /**
+        * Converts a String to char[].
+        */
+       public static char[] toChars(String s) {
+               int len = s.length();
+               char[] chars = new char[len];
+               s.getChars(0, len, chars, 0);
+               return chars;
+       }
+
+       /**
+        * Converts a String to char[][], where segments are separate by '.'.
+        */
+       public static char[][] toCompoundChars(String s) {
+               int len = s.length();
+               if (len == 0) {
+                       return CharOperation.NO_CHAR_CHAR;
+               }
+               int segCount = 1;
+               for (int off = s.indexOf('.'); off != -1; off = s.indexOf('.', off + 1)) {
+                       ++segCount;
+               }
+               char[][] segs = new char[segCount][];
+               int start = 0;
+               for (int i = 0; i < segCount; ++i) {
+                       int dot = s.indexOf('.', start);
+                       int end = (dot == -1 ? s.length() : dot);
+                       segs[i] = new char[end - start];
+                       s.getChars(start, end, segs[i], 0);
+                       start = end + 1;
+               }
+               return segs;
+       }
+
+       /**
+        * Converts a char[][] to String, where segments are separated by '.'.
+        */
+       public static String toString(char[][] c) {
+               StringBuffer sb = new StringBuffer();
+               for (int i = 0, max = c.length; i < max; ++i) {
+                       if (i != 0) sb.append('.');
+                       sb.append(c[i]);
+               }
+               return sb.toString();
+       }
+
+       /**
+        * Converts a char[][] and a char[] to String, where segments are separated by '.'.
+        */
+       public static String toString(char[][] c, char[] d) {
+               if (c == null) return new String(d);
+               StringBuffer sb = new StringBuffer();
+               for (int i = 0, max = c.length; i < max; ++i) {
+                       sb.append(c[i]);
+                       sb.append('.');
+               }
+               sb.append(d);
+               return sb.toString();
+       }
+
+       /**
+        * Converts a char[] to String.
+        */
+       public static String toString(char[] c) {
+               return new String(c);
+       }
+
+       /**
+        * Converts an array of Objects into String.
+        */
+       public static String toString(Object[] objects) {
+               return toString(objects, 
+                       new Displayable(){ 
+                               public String displayString(Object o) { 
+                                       if (o == null) return "null"; //$NON-NLS-1$
+                                       return o.toString(); 
+                               }
+                       });
+       }
+
+       /**
+        * Converts an array of Objects into String.
+        */
+       public static String toString(Object[] objects, Displayable renderer) {
+               if (objects == null) return ""; //$NON-NLS-1$
+               StringBuffer buffer = new StringBuffer(10);
+               for (int i = 0; i < objects.length; i++){
+                       if (i > 0) buffer.append(", "); //$NON-NLS-1$
+                       buffer.append(renderer.displayString(objects[i]));
+               }
+               return buffer.toString();
+       }
+       
+       /**
+        * Asserts that the given method signature is valid.
+        */
+       public static void validateMethodSignature(String sig) {
+               Assert.isTrue(isValidMethodSignature(sig));
+       }
+
+       /**
+        * Asserts that the given type signature is valid.
+        */
+       public static void validateTypeSignature(String sig, boolean allowVoid) {
+               Assert.isTrue(isValidTypeSignature(sig, allowVoid));
+       }
+
+       /**
+        * Creates a NLS catalog for the given locale.
+        */
+       public static void relocalize() {
+               try {
+                       bundle = ResourceBundle.getBundle(bundleName, Locale.getDefault());
+               } catch(MissingResourceException e) {
+                       System.out.println("Missing resource : " + bundleName.replace('.', '/') + ".properties for locale " + Locale.getDefault()); //$NON-NLS-1$//$NON-NLS-2$
+                       throw e;
+               }
+       }
+       
+       /**
+        * Put all the arguments in one String.
+        */
+       public static String getProblemArgumentsForMarker(String[] arguments){
+               StringBuffer args = new StringBuffer(10);
+               
+               args.append(arguments.length);
+               args.append(':');
+               
+                       
+               for (int j = 0; j < arguments.length; j++) {
+                       if(j != 0)
+                               args.append(ARGUMENTS_DELIMITER);
+                       
+                       if(arguments[j].length() == 0) {
+                               args.append(EMPTY_ARGUMENT);
+                       } else {                        
+                               args.append(arguments[j]);
+                       }
+               }
+               
+               return args.toString();
+       }
+       
+       /**
+        * Separate all the arguments of a String made by getProblemArgumentsForMarker
+        */
+       public static String[] getProblemArgumentsFromMarker(String argumentsString){
+               if (argumentsString == null) return null;
+               int index = argumentsString.indexOf(':');
+               if(index == -1)
+                       return null;
+               
+               int length = argumentsString.length();
+               int numberOfArg;
+               try{
+                       numberOfArg = Integer.parseInt(argumentsString.substring(0 , index));
+               } catch (NumberFormatException e) {
+                       return null;
+               }
+               argumentsString = argumentsString.substring(index + 1, length);
+               
+               String[] args = new String[length];
+               int count = 0;
+               
+               StringTokenizer tokenizer = new StringTokenizer(argumentsString, ARGUMENTS_DELIMITER);
+               while(tokenizer.hasMoreTokens()) {
+                       String argument = tokenizer.nextToken();
+                       if(argument.equals(EMPTY_ARGUMENT))
+                               argument = "";  //$NON-NLS-1$
+                       args[count++] = argument;
+               }
+               
+               if(count != numberOfArg)
+                       return null;
+               
+               System.arraycopy(args, 0, args = new String[count], 0, count);
+               return args;
+       }
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/util/CharArrayBuffer.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/util/CharArrayBuffer.java
new file mode 100644 (file)
index 0000000..38be3f8
--- /dev/null
@@ -0,0 +1,191 @@
+/*******************************************************************************
+ * 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.internal.core.util;
+
+/**
+ * The <code>CharArrayBuffer</code> is intended as a lightweight partial implementation
+ * of the StringBuffer class, but using <code>char[]'s</code> instead of Strings.
+ *
+ * <p>The <code>CharArrayBuffer</code> maintains a list of <code>char[]'s</code>
+ * which don't get appended until the user asks for them.  The following
+ * code illustrates how to use the class.
+ *
+ * <code>
+ * CharArrayBuffer buffer = new CharArrayBuffer(myCharArray);
+ * buffer.append(moreBytes, 0, someLength);
+ * myCharArray = buffer.getContents();
+ * </code>
+ *
+ * <p>NOTE: This class is not Thread safe!
+ */
+public class CharArrayBuffer {
+       /**
+        * This is the buffer of char arrays which must be appended together
+        * during the getContents method.
+        */
+       protected char[][] fBuffer;
+
+       /**
+        * The default buffer size.
+        */
+       public static final int DEFAULT_BUFFER_SIZE = 10;
+
+       /**
+        * The end of the buffer
+        */
+       protected int fEnd;
+
+       /**
+        * The current size of the buffer.
+        */
+       protected int fSize;
+
+       /**
+        * A buffer of ranges which is maintained along with
+        * the buffer.  Ranges are of the form {start, length}.
+        * Enables append(char[] array, int start, int end).
+        */
+       protected int[][] fRanges;
+/**
+ * Creates a <code>CharArrayBuffer</code> with the default buffer size (10).
+ */
+public CharArrayBuffer() {
+       this(null, DEFAULT_BUFFER_SIZE);
+}
+/**
+ * Creates a <code>CharArrayBuffer</code> with the default buffer size,
+ * and sets the first element in the buffer to be the given char[].
+ *
+ * @param first - the first element to be placed in the buffer, ignored if null
+ */
+public CharArrayBuffer(char[] first) {
+       this(first, DEFAULT_BUFFER_SIZE);
+}
+/**
+ * Creates a <code>CharArrayBuffer</code> with the given buffer size,
+ * and sets the first element in the buffer to be the given char array.
+ *
+ * @param first - the first element of the buffer, ignored if null.
+ * @param size - the buffer size, if less than 1, set to the DEFAULT_BUFFER_SIZE.
+ */
+public CharArrayBuffer(char[] first, int size) {
+       fSize = (size > 0) ? size : DEFAULT_BUFFER_SIZE;
+       fBuffer = new char[fSize][];
+       fRanges = new int[fSize][];
+       fEnd = 0;
+       if (first != null)
+               append(first, 0, first.length);
+}
+/**
+ * Creates a <code>CharArrayBuffer</code> with the given buffer size.
+ *
+ * @param size - the size of the buffer.
+ */
+public CharArrayBuffer(int size) {
+       this(null, size);
+}
+/**
+ * Appends the entire given char array.  Given for convenience.
+ *
+ * @param src - a char array which is appended to the end of the buffer.
+ */
+public CharArrayBuffer append(char[] src) {
+       if (src != null)
+               append(src, 0, src.length);
+       return this;
+}
+/**
+ * Appends a sub array of the given array to the buffer.
+ *
+ * @param src - the next array of characters to be appended to the buffer, ignored if null
+ * @param start - the start index in the src array.
+ * @param length - the number of characters from start to be appended
+ *
+ * @throws ArrayIndexOutOfBoundsException - if arguments specify an array index out of bounds.
+ */
+public CharArrayBuffer append(char[] src, int start, int length) {
+       if (start < 0) throw new ArrayIndexOutOfBoundsException();
+       if (length < 0) throw new ArrayIndexOutOfBoundsException();
+       if (src != null) {
+               int srcLength = src.length;
+               if (start > srcLength) throw new ArrayIndexOutOfBoundsException();
+               if (length + start > srcLength) throw new ArrayIndexOutOfBoundsException();
+               /** do length check here to allow exceptions to be thrown */
+               if (length > 0) {
+                       if (fEnd == fSize) {
+                               int size2 = fSize * 2;
+                               System.arraycopy(fBuffer, 0, (fBuffer = new char[size2][]), 0, fSize);
+                               System.arraycopy(fRanges, 0, (fRanges = new int[size2][]), 0, fSize);
+                               fSize *= 2;
+                       }
+                       fBuffer[fEnd] = src;
+                       fRanges[fEnd] = new int[] {start, length};
+                       fEnd++;
+               }
+       }
+       return this;
+}
+/**
+ * Appends the given char.  Given for convenience.
+ *
+ * @param src - a char which is appended to the end of the buffer.
+ */
+public CharArrayBuffer append(char c) {
+       append(new char[] {c}, 0, 1);
+       return this;
+}
+/**
+ * Appends the given String to the buffer.  Given for convenience, use
+ * #append(char[]) if possible
+ *
+ * @param src - a char array which is appended to the end of the buffer.
+ */
+public CharArrayBuffer append(String src) {
+       if (src != null)
+               append(src.toCharArray(), 0, src.length());
+       return this;
+}
+/**
+ * Returns the entire contents of the buffer as one
+ * char[] or null if nothing has been put in the buffer.
+ */
+public char[] getContents() {
+       if (fEnd == 0)
+               return null;
+
+       // determine the size of the array
+       int size = 0;
+       for (int i = 0; i < fEnd; i++)
+               size += fRanges[i][1];
+
+       if (size > 0) {
+               char[] result = new char[size];
+               int current = 0;
+               // copy the results
+               for(int i = 0; i < fEnd; i++) {
+                       int[] range = fRanges[i];
+                       int length = range[1];
+                       System.arraycopy(fBuffer[i], range[0], result, current, length);
+                       current += length;
+               }
+               return result;
+       }
+       return null;
+}
+/**
+ * Returns the contents of the buffer as a String, or
+ * <code>null</code> if the buffer is empty.
+ */
+public String toString() {
+       char[] contents = getContents();
+       return (contents != null) ? new String(contents) : null;
+}
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/phpdoc/PHPDocCommentReader.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/phpdoc/PHPDocCommentReader.java
new file mode 100644 (file)
index 0000000..7b1f275
--- /dev/null
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * 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.internal.corext.phpdoc;
+
+import net.sourceforge.phpdt.core.IBuffer;
+import net.sourceforge.phpdt.internal.corext.util.Strings;
+
+
+/**
+ * Reads a java doc comment from a java doc comment. Skips star-character
+ * on begin of line
+ */
+public class PHPDocCommentReader extends SingleCharReader {
+
+       private IBuffer fBuffer;
+       
+       private int fCurrPos;
+       private int fStartPos;
+       private int fEndPos;
+       
+       private boolean fWasNewLine;
+               
+       public PHPDocCommentReader(IBuffer buf, int start, int end) {
+               fBuffer= buf;
+               fStartPos= start + 3;
+               fEndPos= end - 2;
+               
+               reset();
+       }
+               
+       /**
+        * @see java.io.Reader#read()
+        */
+       public int read() {
+               if (fCurrPos < fEndPos) {
+                       char ch;
+                       if (fWasNewLine) {
+                               do {
+                                       ch= fBuffer.getChar(fCurrPos++);
+                               } while (fCurrPos < fEndPos && Character.isWhitespace(ch));
+                               if (ch == '*') {
+                                       if (fCurrPos < fEndPos) {
+                                               do {
+                                                       ch= fBuffer.getChar(fCurrPos++);
+                                               } while (ch == '*');
+                                       } else {
+                                               return -1;
+                                       }
+                               }
+                       } else {
+                               ch= fBuffer.getChar(fCurrPos++);
+                       }
+                       fWasNewLine= Strings.isLineDelimiterChar(ch);
+                       
+                       return ch;
+               }
+               return -1;
+       }
+               
+       /**
+        * @see java.io.Reader#close()
+        */             
+       public void close() {
+               fBuffer= null;
+       }
+       
+       /**
+        * @see java.io.Reader#reset()
+        */             
+       public void reset() {
+               fCurrPos= fStartPos;
+               fWasNewLine= true;
+       }       
+               
+               
+}
index 2507032..87340b4 100644 (file)
@@ -1,9 +1,15 @@
+/*******************************************************************************
+ * 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.internal.corext.phpdoc;
 
-/*
- * (c) Copyright IBM Corp. 2000, 2001.
- * All Rights Reserved.
- */
 
 import java.io.IOException;
 import java.io.Reader;
@@ -52,4 +58,4 @@ public abstract class SingleCharReader extends Reader {
                }
                return buf.toString();
        }
-}
\ No newline at end of file
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/util/Strings.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/util/Strings.java
deleted file mode 100644 (file)
index ab80732..0000000
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * (c) Copyright IBM Corp. 2000, 2001.
- * All Rights Reserved.
- */
-package net.sourceforge.phpdt.internal.corext.util;
-
-import org.eclipse.jface.text.BadLocationException;
-import org.eclipse.jface.text.DefaultLineTracker;
-import org.eclipse.jface.text.ILineTracker;
-import org.eclipse.jface.text.IRegion;
-
-//import org.eclipse.jdt.internal.corext.Assert;
-
-/**
- * Helper class to provide String manipulation functions not available in standard JDK.
- */
-public class Strings {
-
-       public static String removeNewLine(String message) {
-               StringBuffer result= new StringBuffer();
-               int current= 0;
-               int index= message.indexOf('\n', 0);
-               while (index != -1) {
-                       result.append(message.substring(current, index));
-                       if (current < index && index != 0)
-                               result.append(' ');
-                       current= index + 1;
-                       index= message.indexOf('\n', current);
-               }
-               result.append(message.substring(current));
-               return result.toString();
-       }
-
-       /**
-        * Converts the given string into an array of lines. The lines 
-        * don't contain any line delimiter characters.
-        *
-        * @return the string converted into an array of strings. Returns <code>
-        *      null</code> if the input string can't be converted in an array of lines.
-        */
-       public static String[] convertIntoLines(String input) {
-               try {
-                       ILineTracker tracker= new DefaultLineTracker();
-                       tracker.set(input);
-                       int size= tracker.getNumberOfLines();
-                       String result[]= new String[size];
-                       for (int i= 0; i < size; i++) {
-                               IRegion region= tracker.getLineInformation(i);
-                               int offset= region.getOffset();
-                               result[i]= input.substring(offset, offset + region.getLength());
-                       }
-                       return result;
-               } catch (BadLocationException e) {
-                       return null;
-               }
-       }
-
-       /**
-        * Returns <code>true</code> if the given string only consists of
-        * white spaces according to Java. If the string is empty, <code>true
-        * </code> is returned.
-        * 
-        * @return <code>true</code> if the string only consists of white
-        *      spaces; otherwise <code>false</code> is returned
-        * 
-        * @see java.lang.Character#isWhitespace(char)
-        */
-       public static boolean containsOnlyWhitespaces(String s) {
-               int size= s.length();
-               for (int i= 0; i < size; i++) {
-                       if (!Character.isWhitespace(s.charAt(i)))
-                               return false;
-               }
-               return true;
-       }
-       
-       /**
-        * Removes leading tabs and spaces from the given string. If the string
-        * doesn't contain any leading tabs or spaces then the string itself is 
-        * returned.
-        */
-       public static String trimLeadingTabsAndSpaces(String line) {
-               int size= line.length();
-               int start= size;
-               for (int i= 0; i < size; i++) {
-                       char c= line.charAt(i);
-                       if (c != '\t' && !Character.isSpaceChar(c)) {
-                               start= i;
-                               break;
-                       }
-               }
-               if (start == 0)
-                       return line;
-               else if (start == size)
-                       return ""; //$NON-NLS-1$
-               else
-                       return line.substring(start);
-       }
-       
-       public static String trimTrailingTabsAndSpaces(String line) {
-               int size= line.length();
-               int end= size;
-               for (int i= size - 1; i >= 0; i--) {
-                       char c= line.charAt(i);
-                       if (c == '\t' || Character.isSpaceChar(c)) {
-                               end= i;
-                       } else {
-                               break;
-                       }
-               }
-               if (end == size)
-                       return line;
-               else if (end == 0)
-                       return ""; //$NON-NLS-1$
-               else
-                       return line.substring(0, end);
-       }
-       
-       /**
-        * Returns the indent of the given string.
-        * 
-        * @param line the text line
-        * @param tabWidth the width of the '\t' character.
-        */
-       public static int computeIndent(String line, int tabWidth) {
-               int result= 0;
-               int blanks= 0;
-               int size= line.length();
-               for (int i= 0; i < size; i++) {
-                       char c= line.charAt(i);
-                       if (c == '\t') {
-                               result++;
-                               blanks= 0;
-                       } else if (Character.isSpaceChar(c)) {
-                               blanks++;
-                               if (blanks == tabWidth) {
-                                       result++;
-                                       blanks= 0;
-                               }
-                       } else {
-                               return result;
-                       }
-               }
-               return result;
-       }
-       
-       /**
-        * Removes the given number of idents from the line. Asserts that the given line 
-        * has the requested number of indents. If <code>indentsToRemove <= 0</code>
-        * the line is returned.
-        */
-       public static String trimIndent(String line, int indentsToRemove, int tabWidth) {
-               if (line == null || indentsToRemove <= 0)
-                       return line;
-                       
-               int start= 0;
-               int indents= 0;
-               int blanks= 0;
-               int size= line.length();
-               for (int i= 0; i < size; i++) {
-                       char c= line.charAt(i);
-                       if (c == '\t') {
-                               indents++;
-                               blanks= 0;
-                       } else if (Character.isSpaceChar(c)) {
-                                       blanks++;
-                                       if (blanks == tabWidth) {
-                                               indents++;
-                                               blanks= 0;
-                                       }
-                       } else {
-//                             Assert.isTrue(false, "Line does not have requested number of indents"); //$NON-NLS-1$
-                       }
-                       if (indents == indentsToRemove) {
-                               start= i + 1;
-                               break;
-                       }       
-               }
-               if (start == size)
-                       return ""; //$NON-NLS-1$
-               else
-                       return line.substring(start);
-       }
-       
-       /**
-        * Removes all leading indents from the given line. If the line doesn't contain
-        * any indents the line itself is returned.
-        */
-       public static String trimIndents(String s, int tabWidth) {
-               int indent= computeIndent(s, tabWidth);
-               if (indent == 0)
-                       return s;
-               return trimIndent(s, indent, tabWidth);
-       }
-       
-       /**
-        * Removes the common number of indents from all lines. If a line
-        * only consists out of white space it is ignored.
-        */
-       public static void trimIndentation(String[] lines, int tabWidth) {
-               String[] toDo= new String[lines.length];
-               // find indentation common to all lines
-               int minIndent= Integer.MAX_VALUE; // very large
-               for (int i= 0; i < lines.length; i++) {
-                       String line= lines[i];
-                       if (containsOnlyWhitespaces(line))
-                               continue;
-                       toDo[i]= line;
-                       int indent= computeIndent(line, tabWidth);
-                       if (indent < minIndent) {
-                               minIndent= indent;
-                       }
-               }
-               
-               if (minIndent > 0) {
-                       // remove this indent from all lines
-                       for (int i= 0; i < toDo.length; i++) {
-                               String s= toDo[i];
-                               if (s != null)
-                                       lines[i]= trimIndent(s, minIndent, tabWidth);
-                               else {
-                                       String line= lines[i];
-                                       int indent= computeIndent(line, tabWidth);
-                                       if (indent > minIndent)
-                                               lines[i]= trimIndent(line, minIndent, tabWidth);
-                                       else
-                                               lines[i]= trimLeadingTabsAndSpaces(line);
-                               }
-                       }
-               }
-       }
-       
-       public static String getIndentString(String line, int tabWidth) {
-               int size= line.length();
-               int end= 0;
-               int blanks= 0;
-               for (int i= 0; i < size; i++) {
-                       char c= line.charAt(i);
-                       if (c == '\t') {
-                               end= i;
-                               blanks= 0;
-                       } else if (Character.isSpaceChar(c)) {
-                               blanks++;
-                               if (blanks == tabWidth) {
-                                       end= i;
-                                       blanks= 0;
-                               }
-                       } else {
-                               break;
-                       }
-               }
-               if (end == 0)
-                       return ""; //$NON-NLS-1$
-               else if (end == size)
-                       return line;
-               else
-                       return line.substring(0, end + 1);
-       }
-}
-
index da79e24..347ff8c 100644 (file)
@@ -25,9 +25,7 @@ public class PHPElementVisitor implements IResourceVisitor {
 
                        case IResource.FILE :
                                IFile fileResource = (IFile) resource;
-                               if ( "php".equals(fileResource.getFileExtension()) ||
-             "php3".equals(fileResource.getFileExtension()) ||
-             "php4".equals(fileResource.getFileExtension()) ) {
+                               if ( PHPFileUtil.isPHPFile(fileResource) ) {
                                        phpFiles.add(fileResource);
                                        return true;
                                }
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/PHPFileUtil.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/PHPFileUtil.java
new file mode 100644 (file)
index 0000000..4917de5
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Created on 09.08.2003
+ *
+ */
+package net.sourceforge.phpdt.internal.ui.util;
+
+import org.eclipse.core.resources.IFile;
+
+/**
+ * @author khartlage
+ *
+ */
+public class PHPFileUtil {
+  static public boolean isPHPFile(IFile file) {
+    if ("php".equalsIgnoreCase(file.getFileExtension())
+      || "php3".equalsIgnoreCase(file.getFileExtension())
+      || "php4".equalsIgnoreCase(file.getFileExtension())
+      || "inc".equalsIgnoreCase(file.getFileExtension())) {
+      return true;
+    }
+    return false;
+  }
+}
index 356a860..833cb2b 100644 (file)
@@ -36,7 +36,7 @@ public interface IPreferenceConstants {
   public static final String PHP_PARSER_DEFAULT = "_php_parser_default";
   public static final String PHP_INTERNAL_PARSER = "_php_internal_parser";
   public static final String PHP_EXTERNAL_PARSER = "_php_external_parser";
-  public static final String PHP_PARSE_ON_SAVE = "_php_parse_on_save";
+  // public static final String PHP_PARSE_ON_SAVE = "_php_parse_on_save";
   public static final String PHP_MULTILINE_COMMENT = "_php_multilineComment";
   public static final String PHP_MULTILINE_COMMENT_BOLD = "_php_multilineComment_bold";
   public static final String PHP_MULTILINE_COMMENT_ITALIC = "_php_multilineComment_italic";
index 45b4179..6460f92 100644 (file)
@@ -30,7 +30,7 @@ public class PHPEclipseParserPreferencePage extends PreferencePage implements IW
 
   RadioGroupFieldEditor chooseParser;
   StringFieldEditor externalParserSFE;
-  BooleanFieldEditor parseOnSave;
+ // BooleanFieldEditor parseOnSave;
 
   public PHPEclipseParserPreferencePage() {
     super();
@@ -42,14 +42,14 @@ public class PHPEclipseParserPreferencePage extends PreferencePage implements IW
   protected void performDefaults() {
     chooseParser.loadDefault();
     externalParserSFE.loadDefault();
-    parseOnSave.loadDefault();
+//    parseOnSave.loadDefault();
     super.performDefaults();
   }
 
   public boolean performOk() {
     chooseParser.store();
     externalParserSFE.store();
-    parseOnSave.store();
+//    parseOnSave.store();
     return super.performOk();
   }
 
@@ -99,14 +99,14 @@ public class PHPEclipseParserPreferencePage extends PreferencePage implements IW
     externalParserSFE.setPreferenceStore(getPreferenceStore());
     externalParserSFE.load();
 
-    parseOnSave =
-      new BooleanFieldEditor(
-        PHPeclipsePlugin.PHP_PARSE_ON_SAVE,
-        PHPPreferencesMessages.getString("PHPBasePreferencePage.parsers.pos"),
-        parserSettingsGroup);
-    parseOnSave.setPreferencePage(this);
-    parseOnSave.setPreferenceStore(getPreferenceStore());
-    parseOnSave.load();
+//    parseOnSave =
+//      new BooleanFieldEditor(
+//        PHPeclipsePlugin.PHP_PARSE_ON_SAVE,
+//        PHPPreferencesMessages.getString("PHPBasePreferencePage.parsers.pos"),
+//        parserSettingsGroup);
+//    parseOnSave.setPreferencePage(this);
+//    parseOnSave.setPreferenceStore(getPreferenceStore());
+//    parseOnSave.load();
 
     return composite;
   }
index 7f027b7..7619c59 100644 (file)
@@ -56,6 +56,13 @@ public class PHPeclipsePlugin extends AbstractUIPlugin implements IPreferenceCon
    */
   public static final String PLUGIN_ID = "net.sourceforge.phpeclipse"; //$NON-NLS-1$
   public final static String PHP_NATURE_ID = PLUGIN_ID + ".phpnature";
+  
+       /** 
+        * id of builder - matches plugin.xml (concatenate pluginid.builderid) 
+        */
+       public static final String BUILDER_INDEX_ID =   PLUGIN_ID + ".indexbuilder";
+       public static final String BUILDER_PARSER_ID =  PLUGIN_ID + ".parserbuilder";
+               
   // public static final String PHP_RESOURCES_VIEW_ID = PLUGIN_ID + ".resourcesview.ViewPHPResources"; //$NON-NLS-1$
   public static final String PHP_CODING_ACTION_SET_ID = PLUGIN_ID + ".ui.CodingActionSet"; //$NON-NLS-1$
 
@@ -323,7 +330,7 @@ public class PHPeclipsePlugin extends AbstractUIPlugin implements IPreferenceCon
     store.setDefault(PHP_INTERNAL_PARSER, "false");
     store.setDefault(PHP_EXTERNAL_PARSER, "true");
 
-    store.setDefault(PHP_PARSE_ON_SAVE, "true");
+//    store.setDefault(PHP_PARSE_ON_SAVE, "true");
 
     // show line numbers:
     //   store.setDefault(LINE_NUMBER_RULER, "false");
index 5883fbe..f6ab554 100644 (file)
@@ -29,12 +29,14 @@ public class PHPStartApacheAction implements IWorkbenchWindowActionDelegate {
   protected IWorkbenchWindow activeWindow = null;
 
   public void run(IAction action) {
-    final IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
+    final IPreferenceStore store =
+      PHPeclipsePlugin.getDefault().getPreferenceStore();
     String documentRoot = store.getString(PHPeclipsePlugin.DOCUMENTROOT_PREF);
     // replace backslash with slash in the DocumentRoot under Windows
     documentRoot = documentRoot.replace('\\', '/');
     String[] arguments = { documentRoot };
-    MessageFormat form = new MessageFormat(store.getString(PHPeclipsePlugin.APACHE_START_PREF));
+    MessageFormat form =
+      new MessageFormat(store.getString(PHPeclipsePlugin.APACHE_START_PREF));
     execute(
       "apache_start",
       store.getString(PHPeclipsePlugin.APACHE_RUN_PREF),
@@ -77,13 +79,29 @@ public class PHPStartApacheAction implements IWorkbenchWindowActionDelegate {
         * @param arguments arguments for this configuration
         * @param background run this configuration in background mode
         */
-  public static void execute(String command, String executable, String arguments, boolean background) {
+  public static void execute(
+    String command,
+    String executable,
+    String arguments,
+    boolean background) {
     PHPConsole console = PHPConsole.getInstance();
     String consoleMessage;
     if (background) {
-      consoleMessage = "run in background mode-" + command + ": " + executable + " " + arguments;
+      consoleMessage =
+        "run in background mode-"
+          + command
+          + ": "
+          + executable
+          + " "
+          + arguments;
     } else {
-      consoleMessage = "run in foreground mode-" + command + ": " + executable + " " + arguments;
+      consoleMessage =
+        "run in foreground mode-"
+          + command
+          + ": "
+          + executable
+          + " "
+          + arguments;
     }
     console.write(consoleMessage + "\n");
 
@@ -120,9 +138,14 @@ public class PHPStartApacheAction implements IWorkbenchWindowActionDelegate {
   public static String getParserOutput(String command, String consoleMessage) {
     //    MessageDialog.openInformation(activeWindow.getShell(), "Exec command: ", command);
     try {
-      PHPConsole console = PHPConsole.getInstance();
-      if (console != null) {
-        console.write(consoleMessage + command + "\n");
+      PHPConsole console = null;
+      try {
+        console = PHPConsole.getInstance();
+        if (console != null) {
+          console.write(consoleMessage + command + "\n");
+        }
+      } catch (Throwable th) {
+
       }
 
       Runtime runtime = Runtime.getRuntime();
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/builder/ParserBuilder.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/builder/ParserBuilder.java
new file mode 100644 (file)
index 0000000..4b9babe
--- /dev/null
@@ -0,0 +1,159 @@
+package net.sourceforge.phpeclipse.builder;
+
+import java.util.Map;
+
+import net.sourceforge.phpdt.internal.ui.util.PHPFileUtil;
+import net.sourceforge.phpeclipse.phpeditor.PHPParserAction;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.resources.IResourceVisitor;
+import org.eclipse.core.resources.IncrementalProjectBuilder;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
+
+/**
+ * Builder for .php files. 
+ * 
+ * 
+ * @see org.eclipse.core.resources.IncrementalProjectBuilder
+ * @see org.eclipse.core.resources.IResourceDelta
+ */
+public class ParserBuilder extends IncrementalProjectBuilder {
+  private final static int TOTAL_WORK = 100;
+
+  /**
+   * Constructor
+   */
+  public ParserBuilder() {
+  }
+
+  /**
+   * 
+   */
+  protected IProject[] build(int kind, Map args, IProgressMonitor monitor)
+    throws CoreException {
+    monitor.beginTask("Parsing files", TOTAL_WORK);
+
+    if (kind == IncrementalProjectBuilder.FULL_BUILD) {
+      IResourceDelta delta = getDelta(getProject());
+
+      processFull(getProject(), monitor);
+
+    } else { // INCREMENTAL_BUILD or AUTO_BUILD
+
+      IResourceDelta delta = getDelta(getProject());
+      if (delta != null) {
+        delta.accept(new ParserVisitor(monitor));
+      }
+
+    }
+    monitor.done();
+    return null;
+  }
+
+  /**
+   * Performs a <code>FULL_BUILD</code> by visiting all nodes in the resource
+   * tree under the specified project.  
+   * 
+   * @param iProject
+   */
+  public void processFull(IProject iProject, final IProgressMonitor monitor) {
+
+    // Create resource visitor logic
+    IResourceVisitor myVisitor = new IResourceVisitor() {
+      public boolean visit(IResource resource) throws CoreException {
+        if (resource.getType() == IResource.FILE) {
+          if (monitor.isCanceled()) {
+            throw new OperationCanceledException();
+          }
+          if ((resource.getFileExtension() != null)
+            && PHPFileUtil.isPHPFile((IFile) resource)) {
+            monitor.worked(1);
+            monitor.subTask("Parsing: " + resource.getFullPath());
+            PHPParserAction.parseFile((IFile) resource);
+          }
+        }
+
+        return true;
+      }
+    };
+
+    // Process the project using the visitor just created
+    try {
+      iProject.accept(myVisitor);
+    } catch (CoreException e) {
+      e.printStackTrace();
+    }
+
+  }
+
+  /** 
+   * Sets initialization data for this builder.
+   * <p>
+   * This method is part of the <code>IExecutableExtension</code>
+   * interface.
+   * </p>
+   * <p>
+   * Subclasses are free to extend this method to pick up 
+   * initialization parameters from the plug-in plug-in manifest 
+   * (<code>plugin.xml</code>) file,
+   * but should be sure to invoke this method on their superclass.
+   * <p>
+   * For example, the following method looks for a boolean-valued 
+   * parameter named "trace":
+   * <pre>
+   *     public void setInitializationData(IConfigurationElement cfig, 
+   *             String propertyName, Object data) 
+   *                   throws CoreException {
+   *         super.setInitializationData(cfig, propertyName, data);
+   *         if (data instanceof Hashtable) { 
+   *             Hashtable args = (Hashtable) data; 
+   *             String traceValue = (String) args.get("trace"); 
+   *             TRACING = (traceValue!=null && traceValue.equals("true"));
+   *         }
+   *     }
+   * </pre>
+   * </p>
+   */
+  public void setInitializationData(
+    IConfigurationElement config,
+    String propertyName,
+    Object data)
+    throws CoreException {
+    super.setInitializationData(config, propertyName, data);
+
+  }
+
+  /**
+   * Informs this builder that it is being started by the build management
+   * infrastructure.  By the time this method is run, the builder's project
+   * is available and <code>setInitializationData</code> has been called.
+   * The default implementation should be called by all overriding methods.
+   *
+   * @see #setInitializationData
+   */
+  protected void startupOnInitialize() {
+    //   traceMsg("Parse Builder Initialize - startupOnInitialize()");
+  }
+
+  /**
+  * Write trace statements.  
+  * System.out.println with prefix tagging used for simplicity.
+  */
+  //  private void traceMsg(String msg) {
+  //    if (PHPeclipsePlugin.DEBUG | traceEnabled)
+  //      System.out.println(
+  //        buildMode
+  //          + "<"
+  //          + getProject()
+  //          + "> "
+  //          + "\t\t\t"
+  //          + buildMark
+  //          + msg);
+  //  }
+}
\ No newline at end of file
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/builder/ParserVisitor.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/builder/ParserVisitor.java
new file mode 100644 (file)
index 0000000..5dbc801
--- /dev/null
@@ -0,0 +1,71 @@
+package net.sourceforge.phpeclipse.builder;
+
+import net.sourceforge.phpdt.internal.ui.util.PHPFileUtil;
+import net.sourceforge.phpeclipse.phpeditor.PHPParserAction;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.resources.IResourceDeltaVisitor;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
+
+/**
+ *
+ * @see org.eclipse.core.resources.IResourceDelta
+ * @see org.eclipse.core.resources.IResourceDeltaVisitor
+ */
+public class ParserVisitor implements IResourceDeltaVisitor {
+  final IProgressMonitor fMonitor;
+  public ParserVisitor(IProgressMonitor monitor) {
+    fMonitor = monitor;
+  }
+  
+       protected void checkCancel() {
+                               if (fMonitor.isCanceled()) {
+                                        throw new OperationCanceledException();
+                               }
+                }
+  /** 
+   * Visits the given resource delta.
+   * 
+   * @return <code>true</code> if the resource delta's children should
+   *           be visited; <code>false</code> if they should be skipped.
+   * @exception CoreException if the visit fails for some reason.
+   */
+  public boolean visit(IResourceDelta delta) throws CoreException {
+
+    IResource resource = delta.getResource();
+    int resourceType = resource.getType();
+               checkCancel();
+               
+    switch (delta.getKind()) {
+      case IResourceDelta.ADDED :
+        if (resourceType == IResource.FILE) {
+          if ((resource.getFileExtension() != null)
+            && PHPFileUtil.isPHPFile((IFile) resource)) {
+                                               fMonitor.worked(1);
+            fMonitor.subTask("Parsing: " + resource.getFullPath());
+            PHPParserAction.parseFile((IFile) resource);
+          }
+        }
+        break;
+
+      case IResourceDelta.CHANGED :
+        if (resourceType == IResource.FILE) {
+          if ((resource.getFileExtension() != null)
+            && PHPFileUtil.isPHPFile((IFile) resource)) {
+                                       fMonitor.worked(1);
+            fMonitor.subTask("Parsing: " + resource.getFullPath());
+            PHPParserAction.parseFile((IFile) resource);
+          }
+        }
+        break;
+
+      case IResourceDelta.REMOVED :
+        }
+    return true; // carry on
+  }
+
+}
\ No newline at end of file
index 712a200..ac8fa19 100644 (file)
@@ -346,11 +346,14 @@ public class PHPEditor
     super.doSave(monitor);
     // compile or not, according to the user preferences
     IPreferenceStore store = getPreferenceStore(); // fPHPPrefStore;
-    if (store.getBoolean(PHPeclipsePlugin.PHP_PARSE_ON_SAVE)) {
-      IAction a = PHPParserAction.getInstance();
-      if (a != null)
-        a.run();
-    }
+
+    // the parse on save was changed to the eclipse "builders" concept
+    //    if (store.getBoolean(PHPeclipsePlugin.PHP_PARSE_ON_SAVE)) {
+    //      IAction a = PHPParserAction.getInstance();
+    //      if (a != null)
+    //        a.run();
+    //    }
+
     //    if (SWT.getPlatform().equals("win32")) {
     //      IAction a = ShowExternalPreviewAction.getInstance();
     //      if (a != null)
@@ -393,20 +396,25 @@ public class PHPEditor
    */
   public void editorContextMenuAboutToShow(MenuManager menu) {
     super.editorContextMenuAboutToShow(menu);
-               menu.appendToGroup(ITextEditorActionConstants.GROUP_UNDO, new Separator(IContextMenuConstants.GROUP_OPEN));     
-               menu.insertAfter(IContextMenuConstants.GROUP_OPEN, new GroupMarker(IContextMenuConstants.GROUP_SHOW));  
-               
-               ActionContext context= new ActionContext(getSelectionProvider().getSelection());
-               fContextMenuGroup.setContext(context);
-               fContextMenuGroup.fillContextMenu(menu);
-               fContextMenuGroup.setContext(null);
-//    addAction(menu, ITextEditorActionConstants.GROUP_EDIT, "Format"); //$NON-NLS-1$
-//
-//    ActionContext context =
-//      new ActionContext(getSelectionProvider().getSelection());
-//    fContextMenuGroup.setContext(context);
-//    fContextMenuGroup.fillContextMenu(menu);
-//    fContextMenuGroup.setContext(null);
+    menu.appendToGroup(
+      ITextEditorActionConstants.GROUP_UNDO,
+      new Separator(IContextMenuConstants.GROUP_OPEN));
+    menu.insertAfter(
+      IContextMenuConstants.GROUP_OPEN,
+      new GroupMarker(IContextMenuConstants.GROUP_SHOW));
+
+    ActionContext context =
+      new ActionContext(getSelectionProvider().getSelection());
+    fContextMenuGroup.setContext(context);
+    fContextMenuGroup.fillContextMenu(menu);
+    fContextMenuGroup.setContext(null);
+    //    addAction(menu, ITextEditorActionConstants.GROUP_EDIT, "Format"); //$NON-NLS-1$
+    //
+    //    ActionContext context =
+    //      new ActionContext(getSelectionProvider().getSelection());
+    //    fContextMenuGroup.setContext(context);
+    //    fContextMenuGroup.fillContextMenu(menu);
+    //    fContextMenuGroup.setContext(null);
   }
 
   protected void updateStateDependentActions() {
index b40c10b..fbef0f3 100644 (file)
@@ -58,46 +58,53 @@ public class PHPParserAction extends TextEditorAction {
    */
   public void run() {
     boolean phpFlag = false;
-    try {
+               
+  //  try {
       fileToParse = getPHPFile();
-      if (fileToParse == null) {
-        // should never happen
-        System.err.println("Error : no file in the editor");
-        // should throw an exception
-        return;
-      }
-      String name = fileToParse.getName().toLowerCase();
-      for (int i = 0; i<EXTENSIONS.length; i++) {
-        if (name.endsWith(EXTENSIONS[i])) {
-          phpFlag = true;  // php file extension
-          break;
-        }
-      }
-      if (phpFlag) {
-        IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
-        if (store.getString(PHPeclipsePlugin.PHP_PARSER_DEFAULT).equals(PHPeclipsePlugin.PHP_INTERNAL_PARSER)) {
-          // first delete all the previous markers
-          fileToParse.deleteMarkers(IMarker.PROBLEM, false, 0);
-
-          //the tasks are removed here
-          fileToParse.deleteMarkers(IMarker.TASK, false, 0);
-
-          try {
-            InputStream iStream = fileToParse.getContents();
-            //        int c = iStream.read();
-            parse(iStream);
-            iStream.close();
-          } catch (IOException e) {
-          }
-        } else {
-          PHPParserSuperclass.phpExternalParse(fileToParse);
-        }
-      }
-    } catch (CoreException e) {
-    }
-
+                       parseFile(fileToParse);
   }
 
+       public static void parseFile(IFile fileToParse) {
+                       boolean phpFlag = false;
+                       try {
+                               
+                               if (fileToParse == null) {
+                                       // should never happen
+                                       System.err.println("Error : no file in the editor");
+                                       // should throw an exception
+                                       return;
+                               }
+                               String name = fileToParse.getName().toLowerCase();
+                               for (int i = 0; i<EXTENSIONS.length; i++) {
+                                       if (name.endsWith(EXTENSIONS[i])) {
+                                               phpFlag = true;  // php file extension
+                                               break;
+                                       }
+                               }
+                               if (phpFlag) {
+                                       IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
+                                       if (store.getString(PHPeclipsePlugin.PHP_PARSER_DEFAULT).equals(PHPeclipsePlugin.PHP_INTERNAL_PARSER)) {
+                                               // first delete all the previous markers
+                                               fileToParse.deleteMarkers(IMarker.PROBLEM, false, 0);
+
+                                               //the tasks are removed here
+                                               fileToParse.deleteMarkers(IMarker.TASK, false, 0);
+
+                                               try {
+                                                       InputStream iStream = fileToParse.getContents();
+                                                       //        int c = iStream.read();
+                                                       parse(fileToParse,iStream);
+                                                       iStream.close();
+                                               } catch (IOException e) {
+                                               }
+                                       } else {
+                                               PHPParserSuperclass.phpExternalParse(fileToParse);
+                                       }
+                               }
+                       } catch (CoreException e) {
+                       }
+
+               }
   /**
    * Finds the file that's currently opened in the PHP Text Editor
    */
@@ -155,7 +162,7 @@ public class PHPParserAction extends TextEditorAction {
   //    return identifier.toString();
   //  }
 
-  protected void parse(InputStream iStream) {
+  protected static void parse(IFile fileToParse, InputStream iStream) {
 
     StringBuffer buf = new StringBuffer();
     int c0;
index e903be5..775c6d7 100644 (file)
@@ -11,8 +11,10 @@ import javax.xml.parsers.SAXParserFactory;
 import net.sourceforge.phpeclipse.LoadPathEntry;
 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
 
+import org.eclipse.core.resources.ICommand;
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IProjectDescription;
 import org.eclipse.core.resources.IProjectNature;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.CoreException;
@@ -26,150 +28,201 @@ import org.xml.sax.SAXException;
 import org.xml.sax.XMLReader;
 
 public class PHPProject implements IProjectNature, PHPElement {
-       protected IProject fProject;
-       protected List loadPathEntries;
-       protected boolean scratched;
-
-       public PHPProject() {}
-
-       public void configure() throws CoreException {}
-
-       public void deconfigure() throws CoreException {}
-
-       public IProject getProject() {
-               return fProject;
-       }
-
-       protected IProject getProject(String name) {
-               return PHPeclipsePlugin.getWorkspace().getRoot().getProject(name);
-       }
-
-       public void setProject(IProject aProject) {
-               fProject = aProject;
-       }
-
-       public void addLoadPathEntry(IProject anotherPHPProject) {
-               scratched = true;
-
-               LoadPathEntry newEntry = new LoadPathEntry(anotherPHPProject);
-               getLoadPathEntries().add(newEntry);
-       }
-
-       public void removeLoadPathEntry(IProject anotherPHPProject) {
-               Iterator entries = getLoadPathEntries().iterator();
-               while (entries.hasNext()) {
-                       LoadPathEntry entry = (LoadPathEntry) entries.next();
-                       if (entry.getType() == LoadPathEntry.TYPE_PROJECT && entry.getProject().getName().equals(anotherPHPProject.getName())) {
-                               getLoadPathEntries().remove(entry);
-                               scratched = true;
-                               break;
-                       }
-               }
-       }
-
-       public List getLoadPathEntries() {
-               if (loadPathEntries == null) {
-                       loadLoadPathEntries();
-               }
-
-               return loadPathEntries;
-       }
-
-       public List getReferencedProjects() {
-               List referencedProjects = new ArrayList();
-
-               Iterator iterator = getLoadPathEntries().iterator();
-               while (iterator.hasNext()) {
-                       LoadPathEntry pathEntry = (LoadPathEntry) iterator.next();
-                       if (pathEntry.getType() == LoadPathEntry.TYPE_PROJECT)
-                               referencedProjects.add(pathEntry.getProject());
-               }
-
-               return referencedProjects;
-       }
-
-       protected void loadLoadPathEntries() {
-               loadPathEntries = new ArrayList();
-
-               IFile loadPathsFile = getLoadPathEntriesFile();
-
-               XMLReader reader = null;
-               try {
-                       reader = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
-                       reader.setContentHandler(getLoadPathEntriesContentHandler());
-                       reader.parse(new InputSource(loadPathsFile.getContents()));
-               } catch (Exception e) {
-                       //the file is nonextant or unreadable
-               }
-       }
-
-       protected ContentHandler getLoadPathEntriesContentHandler() {
-               return new ContentHandler() {
-                       public void characters(char[] arg0, int arg1, int arg2) throws SAXException {}
-
-                       public void endDocument() throws SAXException {}
-
-                       public void endElement(String arg0, String arg1, String arg2) throws SAXException {}
-
-                       public void endPrefixMapping(String arg0) throws SAXException {}
-
-                       public void ignorableWhitespace(char[] arg0, int arg1, int arg2) throws SAXException {}
-
-                       public void processingInstruction(String arg0, String arg1) throws SAXException {}
-
-                       public void setDocumentLocator(Locator arg0) {}
-
-                       public void skippedEntity(String arg0) throws SAXException {}
-
-                       public void startDocument() throws SAXException {}
-
-                       public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
-                               if ("pathentry".equals(qName))
-                                       if ("project".equals(atts.getValue("type"))) {
-                                               IPath referencedProjectPath = new Path(atts.getValue("path"));
-                                               IProject referencedProject = getProject(referencedProjectPath.lastSegment());
-                                               loadPathEntries.add(new LoadPathEntry(referencedProject));
-                                       }
-                       }
-
-                       public void startPrefixMapping(String arg0, String arg1) throws SAXException {}
-               };
-       }
-
-       protected IFile getLoadPathEntriesFile() {
-               return fProject.getFile(".loadpath");
-       }
-
-       public void save() throws CoreException {
-               if (scratched) {
-                       InputStream xmlPath = new ByteArrayInputStream(getLoadPathXML().getBytes());
-                       IFile loadPathsFile = getLoadPathEntriesFile();
-                       if (!loadPathsFile.exists())
-                               loadPathsFile.create(xmlPath, true, null);
-                       else
-                               loadPathsFile.setContents(xmlPath, true, false, null);
-
-                       scratched = false;
-               }
-       }
-
-       protected String getLoadPathXML() {
-               StringBuffer buffer = new StringBuffer();
-               buffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><loadpath>");
-
-               Iterator pathEntriesIterator = loadPathEntries.iterator();
-
-               while (pathEntriesIterator.hasNext()) {
-                       LoadPathEntry entry = (LoadPathEntry) pathEntriesIterator.next();
-                       buffer.append(entry.toXML());
-               }
-
-               buffer.append("</loadpath>");
-               return buffer.toString();
-       }
-       
-       public IResource getUnderlyingResource() {
-               return fProject;
-       }
+  protected IProject fProject;
+  protected List loadPathEntries;
+  protected boolean scratched;
+
+  public PHPProject() {
+  }
+
+  public void configure() throws CoreException {
+    // get project description and then the associated build commands 
+    IProjectDescription desc = fProject.getDescription();
+    ICommand[] commands = desc.getBuildSpec();
+
+    // determine if builder already associated
+    boolean found = false;
+    for (int i = 0; i < commands.length; ++i) {
+      if (commands[i].getBuilderName().equals(PHPeclipsePlugin.BUILDER_PARSER_ID)) {
+        found = true;
+        break;
+      }
+    }
+
+    // add builder if not already in project
+    if (!found) {
+      ICommand command = desc.newCommand();
+      command.setBuilderName(PHPeclipsePlugin.BUILDER_PARSER_ID);
+      ICommand[] newCommands = new ICommand[commands.length + 1];
+
+      // Add it before other builders. 
+      System.arraycopy(commands, 0, newCommands, 1, commands.length);
+      newCommands[0] = command;
+      desc.setBuildSpec(newCommands);
+      fProject.setDescription(desc, null);
+    }
+  }
+
+  public void deconfigure() throws CoreException {
+  }
+
+  public IProject getProject() {
+    return fProject;
+  }
+
+  protected IProject getProject(String name) {
+    return PHPeclipsePlugin.getWorkspace().getRoot().getProject(name);
+  }
+
+  public void setProject(IProject aProject) {
+    fProject = aProject;
+  }
+
+  public void addLoadPathEntry(IProject anotherPHPProject) {
+    scratched = true;
+
+    LoadPathEntry newEntry = new LoadPathEntry(anotherPHPProject);
+    getLoadPathEntries().add(newEntry);
+  }
+
+  public void removeLoadPathEntry(IProject anotherPHPProject) {
+    Iterator entries = getLoadPathEntries().iterator();
+    while (entries.hasNext()) {
+      LoadPathEntry entry = (LoadPathEntry) entries.next();
+      if (entry.getType() == LoadPathEntry.TYPE_PROJECT
+        && entry.getProject().getName().equals(anotherPHPProject.getName())) {
+        getLoadPathEntries().remove(entry);
+        scratched = true;
+        break;
+      }
+    }
+  }
+
+  public List getLoadPathEntries() {
+    if (loadPathEntries == null) {
+      loadLoadPathEntries();
+    }
+
+    return loadPathEntries;
+  }
+
+  public List getReferencedProjects() {
+    List referencedProjects = new ArrayList();
+
+    Iterator iterator = getLoadPathEntries().iterator();
+    while (iterator.hasNext()) {
+      LoadPathEntry pathEntry = (LoadPathEntry) iterator.next();
+      if (pathEntry.getType() == LoadPathEntry.TYPE_PROJECT)
+        referencedProjects.add(pathEntry.getProject());
+    }
+
+    return referencedProjects;
+  }
+
+  protected void loadLoadPathEntries() {
+    loadPathEntries = new ArrayList();
+
+    IFile loadPathsFile = getLoadPathEntriesFile();
+
+    XMLReader reader = null;
+    try {
+      reader = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
+      reader.setContentHandler(getLoadPathEntriesContentHandler());
+      reader.parse(new InputSource(loadPathsFile.getContents()));
+    } catch (Exception e) {
+      //the file is nonextant or unreadable
+    }
+  }
+
+  protected ContentHandler getLoadPathEntriesContentHandler() {
+    return new ContentHandler() {
+      public void characters(char[] arg0, int arg1, int arg2)
+        throws SAXException {
+      }
+
+      public void endDocument() throws SAXException {
+      }
+
+      public void endElement(String arg0, String arg1, String arg2)
+        throws SAXException {
+      }
+
+      public void endPrefixMapping(String arg0) throws SAXException {
+      }
+
+      public void ignorableWhitespace(char[] arg0, int arg1, int arg2)
+        throws SAXException {
+      }
+
+      public void processingInstruction(String arg0, String arg1)
+        throws SAXException {
+      }
+
+      public void setDocumentLocator(Locator arg0) {
+      }
+
+      public void skippedEntity(String arg0) throws SAXException {
+      }
+
+      public void startDocument() throws SAXException {
+      }
+
+      public void startElement(
+        String namespaceURI,
+        String localName,
+        String qName,
+        Attributes atts)
+        throws SAXException {
+        if ("pathentry".equals(qName))
+          if ("project".equals(atts.getValue("type"))) {
+            IPath referencedProjectPath = new Path(atts.getValue("path"));
+            IProject referencedProject =
+              getProject(referencedProjectPath.lastSegment());
+            loadPathEntries.add(new LoadPathEntry(referencedProject));
+          }
+      }
+
+      public void startPrefixMapping(String arg0, String arg1)
+        throws SAXException {
+      }
+    };
+  }
+
+  protected IFile getLoadPathEntriesFile() {
+    return fProject.getFile(".loadpath");
+  }
+
+  public void save() throws CoreException {
+    if (scratched) {
+      InputStream xmlPath =
+        new ByteArrayInputStream(getLoadPathXML().getBytes());
+      IFile loadPathsFile = getLoadPathEntriesFile();
+      if (!loadPathsFile.exists())
+        loadPathsFile.create(xmlPath, true, null);
+      else
+        loadPathsFile.setContents(xmlPath, true, false, null);
+
+      scratched = false;
+    }
+  }
+
+  protected String getLoadPathXML() {
+    StringBuffer buffer = new StringBuffer();
+    buffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><loadpath>");
+
+    Iterator pathEntriesIterator = loadPathEntries.iterator();
+
+    while (pathEntriesIterator.hasNext()) {
+      LoadPathEntry entry = (LoadPathEntry) pathEntriesIterator.next();
+      buffer.append(entry.toXML());
+    }
+
+    buffer.append("</loadpath>");
+    return buffer.toString();
+  }
+
+  public IResource getUnderlyingResource() {
+    return fProject;
+  }
 
 }
index 638ca71..9529dd2 100644 (file)
@@ -36,15 +36,12 @@ import org.eclipse.jface.text.TextViewer;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.custom.StyledText;
 import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Label;
 import org.eclipse.swt.widgets.Menu;
 import org.eclipse.ui.IActionBars;
 import org.eclipse.ui.IWorkbenchActionConstants;
 import org.eclipse.ui.IWorkbenchPage;
 import org.eclipse.ui.PartInitException;
-import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.part.ViewPart;
 
 /**
@@ -53,15 +50,16 @@ import org.eclipse.ui.part.ViewPart;
  */
 public class PHPConsole extends ViewPart {
 
-  public static final String CONSOLE_ID = "net.sourceforge.phpeclipse.views.phpconsoleview";
+  public static final String CONSOLE_ID =
+    "net.sourceforge.phpeclipse.views.phpconsoleview";
   private int COMMAND_COMBO_SIZE = 10;
 
   private TextViewer fViewer = null;
   private Document fDocument = null;
   private StyledText fStyledText;
   // private Combo fCommandCombo;
-//  private ProcessOutputWriter consoleOut;
-//  private ProcessOutputWriter consoleErr;
+  //  private ProcessOutputWriter consoleOut;
+  //  private ProcessOutputWriter consoleErr;
 
   // private Action goAction;
 
@@ -101,20 +99,20 @@ public class PHPConsole extends ViewPart {
    * @see ViewPart#createPartControl
    */
   public void createPartControl(Composite parent) {
-//    Composite container = new Composite(parent, SWT.NULL);
-//    //   control = container;
-//    GridLayout layout = new GridLayout();
-//    layout.marginWidth = 0;
-//    layout.marginHeight = 0;
-//    layout.verticalSpacing = 0;
-//    container.setLayout(layout);
-//    Composite navContainer = new Composite(container, SWT.NONE);
-//    layout = new GridLayout();
-//    layout.numColumns = 2;
-//    layout.marginHeight = 1;
-//    navContainer.setLayout(layout);
-//    createCommandBar(navContainer);
-//    navContainer.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+    //    Composite container = new Composite(parent, SWT.NULL);
+    //    //   control = container;
+    //    GridLayout layout = new GridLayout();
+    //    layout.marginWidth = 0;
+    //    layout.marginHeight = 0;
+    //    layout.verticalSpacing = 0;
+    //    container.setLayout(layout);
+    //    Composite navContainer = new Composite(container, SWT.NONE);
+    //    layout = new GridLayout();
+    //    layout.numColumns = 2;
+    //    layout.marginHeight = 1;
+    //    navContainer.setLayout(layout);
+    //    createCommandBar(navContainer);
+    //    navContainer.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
 
     fViewer = new TextViewer(parent, SWT.WRAP | SWT.V_SCROLL | SWT.H_SCROLL);
     GridData viewerData = new GridData(GridData.FILL_BOTH);
@@ -122,7 +120,8 @@ public class PHPConsole extends ViewPart {
     fViewer.setEditable(false);
 
     fStyledText = fViewer.getTextWidget();
-    fStyledText.setFont(JFaceResources.getFontRegistry().get(JFaceResources.TEXT_FONT));
+    fStyledText.setFont(
+      JFaceResources.getFontRegistry().get(JFaceResources.TEXT_FONT));
 
     cutAction.setText("Cut");
     copyAction.setText("Copy");
@@ -147,8 +146,8 @@ public class PHPConsole extends ViewPart {
   }
 
   private void createCommandBar(Composite parent) {
-//    Label addressLabel = new Label(parent, SWT.NONE);
-//    addressLabel.setText("Command:");
+    //    Label addressLabel = new Label(parent, SWT.NONE);
+    //    addressLabel.setText("Command:");
 
     //    fCommandCombo = new Combo(parent, SWT.DROP_DOWN | SWT.BORDER);
     //    fCommandCombo.addModifyListener(new ModifyListener() {
@@ -368,10 +367,20 @@ public class PHPConsole extends ViewPart {
   }
 
   public static PHPConsole getInstance() {
-    IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+    // IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+    IWorkbenchPage page =
+      PHPeclipsePlugin
+        .getDefault()
+        .getWorkbench()
+        .getActiveWorkbenchWindow()
+        .getActivePage();
     PHPConsole console = (PHPConsole) page.findView(PHPConsole.CONSOLE_ID);
 
-    if (PHPeclipsePlugin.getDefault().getPreferenceStore().getBoolean(PHPeclipsePlugin.SHOW_OUTPUT_IN_CONSOLE) == true) {
+    if (PHPeclipsePlugin
+      .getDefault()
+      .getPreferenceStore()
+      .getBoolean(PHPeclipsePlugin.SHOW_OUTPUT_IN_CONSOLE) 
+      == true) {
       try {
         page.showView(PHPConsole.CONSOLE_ID);
         if (console == null) {
@@ -383,7 +392,8 @@ public class PHPConsole extends ViewPart {
             IStatus.ERROR,
             PHPeclipsePlugin.getPluginId(),
             0,
-            PHPActionMessages.getString("PHPStartApacheAction.consoleViewOpeningProblem"),
+            PHPActionMessages.getString(
+              "PHPStartApacheAction.consoleViewOpeningProblem"),
             e));
       }
     }
@@ -400,7 +410,8 @@ public class PHPConsole extends ViewPart {
   /**
    * Creates a string buffer from the given input stream
    */
-  public static String getStringFromStream(InputStream stream) throws IOException {
+  public static String getStringFromStream(InputStream stream)
+    throws IOException {
     StringBuffer buffer = new StringBuffer();
     byte[] b = new byte[100];
     int finished = 0;
@@ -451,7 +462,8 @@ public class PHPConsole extends ViewPart {
 
     public void run() {
       try {
-        BufferedReader in = new BufferedReader(new InputStreamReader(fInputStream));
+        BufferedReader in =
+          new BufferedReader(new InputStreamReader(fInputStream));
 
         String line;
         while ((line = in.readLine()) != null) {