From: khartlage  
+ * The source range for this type of node is ordinarily the entire source file,
+ * including leading and trailing whitespace and comments.
+ *  
+//	 * N.B. This constructor is package-private; all subclasses must be 
+//	 * declared in the same package; clients are unable to declare 
+//	 * additional subclasses.
+//	 *  
+//     * Note that in JLS3, the types may include both enum declarations
+//     * and annotation type declarations introduced in J2SE 1.5.
+//     * For JLS2, the elements are always  
+//	 * The following table indicates the expected node type for the various
+//	 * different kinds of bindings:
+//	 * 
+ * CompilationUnit:
+ *    [ PackageDeclaration ]
+ *        { ImportDeclaration }
+ *        { TypeDeclaration | ; }
+ * 
+ * For JLS3, the kinds of type declarations
+ * grew to include enum and annotation type declarations:
+ * 
+ * CompilationUnit:
+ *    [ PackageDeclaration ]
+ *        { ImportDeclaration }
+ *        { TypeDeclaration | EnumDeclaration | AnnotationTypeDeclaration | ; }
+ * 
+ * 
+ * @since 2.0
+ */
+public class CompilationUnit  {
+
+//	/**
+//	 * The "package" structural property of this node type.
+//	 * 
+//	 * @since 3.0
+//	 */
+//	public static final ChildPropertyDescriptor PACKAGE_PROPERTY = 
+//		new ChildPropertyDescriptor(CompilationUnit.class, "package", PackageDeclaration.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$
+//	
+//	/**
+//	 * The "imports" structural property of this node type.
+//	 * 
+//	 * @since 3.0
+//	 */
+//	public static final ChildListPropertyDescriptor IMPORTS_PROPERTY =
+//		new ChildListPropertyDescriptor(CompilationUnit.class, "imports", ImportDeclaration.class, NO_CYCLE_RISK); //$NON-NLS-1$
+//	
+//	/**
+//	 * The "types" structural property of this node type.
+//	 * 
+//	 * @since 3.0
+//	 */
+//	public static final ChildListPropertyDescriptor TYPES_PROPERTY =
+//		new ChildListPropertyDescriptor(CompilationUnit.class, "types", AbstractTypeDeclaration.class, CYCLE_RISK); //$NON-NLS-1$
+//	
+//	/**
+//	 * A list of property descriptors (element type: 
+//	 * {@link StructuralPropertyDescriptor}),
+//	 * or null if uninitialized.
+//	 * @since 3.0
+//	 */
+//	private static final List PROPERTY_DESCRIPTORS;
+//	
+//	static {
+//		createPropertyList(CompilationUnit.class);
+//		addProperty(PACKAGE_PROPERTY);
+//		addProperty(IMPORTS_PROPERTY);
+//		addProperty(TYPES_PROPERTY);
+//		PROPERTY_DESCRIPTORS = reapPropertyList();
+//	}
+//
+//	/**
+//	 * Returns a list of structural property descriptors for this node type.
+//	 * Clients must not modify the result.
+//	 * 
+//	 * @param apiLevel the API level; one of the
+//	 * AST.JLS* constants
+//
+//	 * @return a list of property descriptors (element type: 
+//	 * {@link StructuralPropertyDescriptor})
+//	 * @since 3.0
+//	 */
+//	public static List propertyDescriptors(int apiLevel) {
+//		return PROPERTY_DESCRIPTORS;
+//	}
+//			
+//	/**
+//	 * The comment table, or null if none; initially
+//	 * null. This array is the storage underlying
+//	 * the optionalCommentList ArrayList.
+//	 * @since 3.0
+//	 */
+//	Comment[] optionalCommentTable = null;
+//	
+//	/**
+//	 * The comment list (element type: Comment, 
+//	 * or null if none; initially null.
+//	 * @since 3.0
+//	 */
+//	private List optionalCommentList = null;
+//	
+//	/**
+//	 * The package declaration, or null if none; initially
+//	 * null.
+//	 */
+//	private PackageDeclaration optionalPackageDeclaration = null;
+//	
+//	/**
+//	 * The list of import declarations in textual order order; 
+//	 * initially none (elementType: ImportDeclaration).
+//	 */
+//	private ASTNode.NodeList imports =
+//		new ASTNode.NodeList(IMPORTS_PROPERTY);
+//	
+//	/**
+//	 * The list of type declarations in textual order order; 
+//	 * initially none (elementType: AbstractTypeDeclaration)
+//	 */
+//	private ASTNode.NodeList types =
+//		new ASTNode.NodeList(TYPES_PROPERTY);
+//	
+//	/**
+//	 * Line end table. If lineEndTable[i] == p then the
+//	 * line number i+1 ends at character position 
+//	 * p. Except for the last line, the positions are that
+//	 * of the last character of the line delimiter. 
+//	 * For example, the source string A\nB\nC has
+//	 * line end table {1, 3} (if \n is one character).
+//	 */
+//	private int[] lineEndTable = new int[0];
+//
+//	/**
+//	 * Canonical empty list of messages.
+//	 */
+//	private static final Message[] EMPTY_MESSAGES = new Message[0];
+//
+//	/**
+//	 * Canonical empty list of problems.
+//	 */
+//	private static final IProblem[] EMPTY_PROBLEMS = new IProblem[0];
+//
+//	/**
+//	 * Messages reported by the compiler during parsing or name resolution.
+//	 */
+//	private Message[] messages;
+//	
+//	/**
+//	 * Problems reported by the compiler during parsing or name resolution.
+//	 */
+//	private IProblem[] problems = EMPTY_PROBLEMS;
+//	
+//	/**
+//	 * The comment mapper, or null in none; 
+//	 * initially null.
+//	 * @since 3.0
+//	 */
+//	private DefaultCommentMapper commentMapper = null;
+//	
+//	/**
+//	 * Sets the line end table for this compilation unit.
+//	 * If lineEndTable[i] == p then line number i+1 
+//	 * ends at character position p. Except for the last line, the 
+//	 * positions are that of (the last character of) the line delimiter.
+//	 * For example, the source string A\nB\nC has
+//	 * line end table {1, 3, 4}.
+//	 * 
+//	 * @param lineEndtable the line end table
+//	 */
+//	void setLineEndTable(int[] lineEndTable) {
+//		if (lineEndTable == null) {
+//			throw new NullPointerException();
+//		}
+//		// alternate root is *not* considered a structural property
+//		// but we protect them nevertheless
+//		checkModifiable();
+//		this.lineEndTable = lineEndTable;
+//	}
+//
+//	/**
+//	 * Creates a new AST node for a compilation owned by the given AST.
+//	 * The compilation unit initially has no package declaration, no
+//	 * import declarations, and no type declarations.
+//	 * null if this compilation unit is in the 
+//	 * default package.
+//	 * 
+//	 * @return the package declaration node, or null if none
+//	 */ 
+//	public PackageDeclaration getPackage() {
+//		return this.optionalPackageDeclaration;
+//	}
+//	
+//	/**
+//	 * Sets or clears the package declaration of this compilation unit 
+//	 * node to the given package declaration node.
+//	 * 
+//	 * @param pkgDecl the new package declaration node, or 
+//	 *   null if this compilation unit does not have a package
+//	 *   declaration (that is in the default package)
+//	 * @exception IllegalArgumentException if:
+//	 * 
+//	 * 
+//	 */ 
+//	public void setPackage(PackageDeclaration pkgDecl) {
+//		ASTNode oldChild = this.optionalPackageDeclaration;
+//		preReplaceChild(oldChild, pkgDecl, PACKAGE_PROPERTY);
+//		this.optionalPackageDeclaration = pkgDecl;
+//		postReplaceChild(oldChild, pkgDecl, PACKAGE_PROPERTY);
+//	}
+//
+//	/**
+//	 * Returns the live list of nodes for the import declarations of this 
+//	 * compilation unit, in order of appearance.
+//	 * 
+//	 * @return the live list of import declaration nodes
+//	 *    (elementType:ImportDeclaration)
+//	 */ 
+//	public List imports() {
+//		return this.imports;
+//	}
+//	
+//	/**
+//	 * Returns the live list of nodes for the top-level type declarations of this 
+//	 * compilation unit, in order of appearance.
+//     * TypeDeclaration.
+//     * AbstractTypeDeclaration)
+//	 */ 
+//	public List types() {
+//		return this.types;
+//	}
+//
+//	/**
+//	 * Finds the corresponding AST node in the given compilation unit from 
+//	 * which the given binding originated. Returns null if the
+//	 * binding does not correspond to any node in this compilation unit.
+//	 * This method always returns null if bindings were not requested
+//	 * when this AST was built.
+//	 * 
+//	 * 
+//	 * 
+//	 *PackageDeclarationTypeDeclaration or a
+//	 *    AnonymousClassDeclaration (for anonymous classes)VariableDeclarationFragment in a 
+//	 *    FieldDeclaration SingleVariableDeclaration, or
+//	 *    a VariableDeclarationFragment in a 
+//	 *    VariableDeclarationStatement or 
+//	 *    VariableDeclarationExpressionMethodDeclaration MethodDeclaration AnnotationTypeDeclarationAnnotationTypeMemberDeclarationEnumDeclarationEnumConstantDeclaration
+//	 * Each call to {@link ASTParser#createAST(IProgressMonitor)} with a request for bindings
+//	 * gives rise to separate universe of binding objects. This method always returns
+//	 * null when the binding object comes from a different AST.
+//	 * Use findDeclaringNode(binding.getKey()) when the binding comes
+//	 * from a different AST.
+//	 * 
null if the binding does not correspond to a node in this
+//	 * compilation unit or if bindings were not requested when this AST was built
+//	 * @see #findDeclaringNode(String)
+//	 */
+//	public ASTNode findDeclaringNode(IBinding binding) {
+//		return this.ast.getBindingResolver().findDeclaringNode(binding);
+//	}
+//
+//	/**
+//	 * Finds the corresponding AST node in the given compilation unit from 
+//	 * which the binding with the given key originated. Returns
+//	 * null if the corresponding node cannot be determined.
+//	 * This method always returns null if bindings were not requested
+//	 * when this AST was built.
+//	 * +// * The following table indicates the expected node type for the various +// * different kinds of binding keys: +// *
PackageDeclarationTypeDeclaration or a
+//	 *    AnonymousClassDeclaration (for anonymous classes)VariableDeclarationFragment in a 
+//	 *    FieldDeclaration SingleVariableDeclaration, or
+//	 *    a VariableDeclarationFragment in a 
+//	 *    VariableDeclarationStatement or 
+//	 *    VariableDeclarationExpressionMethodDeclaration MethodDeclaration AnnotationTypeDeclarationAnnotationTypeMemberDeclarationEnumDeclarationEnumConstantDeclaration+// * Note that as explained in {@link IBinding#getKey() IBinding.getkey} +// * there may be no keys for finding the declaring node for local variables, +// * local or anonymous classes, etc. +// *
+// * +// * @param key the binding key, ornull
+//	 * @return the corresponding node where a binding with the given
+//	 * key is declared, or null if the key is null
+//	 * or if the key does not correspond to a node in this compilation unit
+//	 * or if bindings were not requested when this AST was built
+//	 * @see IBinding#getKey()
+//	 * @since 2.1
+//	 */
+//	public ASTNode findDeclaringNode(String key) {
+//		return this.ast.getBindingResolver().findDeclaringNode(key);
+//	}
+//	
+//	/**
+//	 * Returns the internal comment mapper.
+//	 * 
+//	 * @return the comment mapper, or null if none.
+//	 * @since 3.0
+//	 */
+//	DefaultCommentMapper getCommentMapper() {
+//		return this.commentMapper;
+//	}
+//
+//	/**
+//	 * Initializes the internal comment mapper with the given
+//	 * scanner.
+//	 * 
+//	 * @param scanner the scanner
+//	 * @since 3.0
+//	 */
+//	void initCommentMapper(Scanner scanner) {
+//		this.commentMapper = new DefaultCommentMapper(this.optionalCommentTable);
+//		this.commentMapper.initialize(this, scanner);
+//	}
+//
+//	/**
+//	 * Returns the extended start position of the given node. Unlike
+//	 * {@link ASTNode#getStartPosition()} and {@link ASTNode#getLength()()},
+//	 * the extended source range may include comments and whitespace
+//	 * immediately before or after the normal source range for the node.
+//	 * 
+//	 * @param node the node
+//	 * @return the 0-based character index, or -1
+//	 *    if no source position information is recorded for this node
+//	 * @see #getExtendedLength(ASTNode)
+//	 * @since 3.0
+//	 */
+//	public int getExtendedStartPosition(ASTNode node) {
+//		if (this.commentMapper == null) {
+//			return -1;
+//		} else {
+//			return this.commentMapper.getExtendedStartPosition(node);
+//		}
+//	}
+//
+//	/**
+//	 * Returns the extended source length of the given node. Unlike
+//	 * {@link ASTNode#getStartPosition()} and {@link ASTNode#getLength()()},
+//	 * the extended source range may include comments and whitespace
+//	 * immediately before or after the normal source range for the node.
+//	 * 
+//	 * @param node the node
+//	 * @return a (possibly 0) length, or 0
+//	 *    if no source position information is recorded for this node
+//	 * @see #getExtendedStartPosition(ASTNode)
+//	 * @since 3.0
+//	 */
+//	public int getExtendedLength(ASTNode node) {
+//		if (this.commentMapper == null) {
+//			return 0;
+//		} else {
+//			return this.commentMapper.getExtendedLength(node);
+//		}
+//	}
+//		
+//	/**
+//	 * Returns the line number corresponding to the given source character
+//	 * position in the original source string. The initial line of the 
+//	 * compilation unit is numbered 1, and each line extends through the
+//	 * last character of the end-of-line delimiter. The very last line extends
+//	 * through the end of the source string and has no line delimiter.
+//	 * For example, the source string class A\n{\n} has 3 lines
+//	 * corresponding to inclusive character ranges [0,7], [8,9], and [10,10].
+//	 * Returns 1 for a character position that does not correspond to any
+//	 * source line, or if no line number information is available for this
+//	 * compilation unit.
+//	 * 
+//	 * @param position a 0-based character position, possibly
+//	 *   negative or out of range
+//	 * @return the 1-based line number, or 1 if the character
+//	 *    position does not correspond to a source line in the original
+//	 *    source file or if line number information is not known for this
+//	 *    compilation unit
+//	 * @see ASTParser
+//	 */
+//	public int lineNumber(int position) {
+//		int length = lineEndTable.length;
+//		if (length == 0) {
+//			// no line number info
+//			return 1;
+//		}
+//		int low = 0;
+//		if (position <= lineEndTable[low]) {
+//			// position illegal or before the first line delimiter
+//			return 1;
+//		}
+//		// assert position > lineEndTable[low+1]  && low == 0
+//		int hi = length - 1;
+//		if (position > lineEndTable[hi]) {
+//			// position beyond the last line separator
+//			if (position >= getStartPosition() + getLength()) {
+//				// this is beyond the end of the source length
+//				return 1;
+//			} else {
+//				return length + 1;
+//			}
+//		}
+//		// assert lineEndTable[low]  < position <= lineEndTable[hi]
+//		// && low == 0 && hi == length - 1 && low < hi
+//		
+//		// binary search line end table
+//		while (true) {
+//			// invariant lineEndTable[low] < position <= lineEndTable[hi]
+//			// && 0 <= low < hi <= length - 1
+//			// reducing measure hi - low
+//			if (low + 1 == hi) {
+//				// assert lineEndTable[low] < position <= lineEndTable[low+1]
+//				// position is on line low+1 (line number is low+2)
+//				return low + 2;
+//			}
+//			// assert hi - low >= 2, so average is truly in between
+//			int mid = (low + hi) / 2;
+//			// assert 0 <= low < mid < hi <= length - 1
+//			if (position <= lineEndTable[mid]) {
+//				// assert lineEndTable[low] < position <= lineEndTable[mid]
+//				// && 0 <= low < mid < hi <= length - 1
+//				hi = mid;
+//			} else {
+//				// position > lineEndTable[mid]
+//				// assert lineEndTable[mid] < position <= lineEndTable[hi]
+//				// && 0 <= low < mid < hi <= length - 1
+//				low = mid;
+//			}
+//			// in both cases, invariant reachieved with reduced measure
+//		}
+//	}
+//
+//	/**
+//	 * Returns the list of messages reported by the compiler during the parsing 
+//	 * or the type checking of this compilation unit. This list might be a subset of 
+//	 * errors detected and reported by a Java compiler.
+//	 * 
+//	 * This list of messages is suitable for simple clients that do little
+//	 * more than log the messages or display them to the user. Clients that
+//	 * need further details should call getProblems to get
+//	 * compiler problem objects.
+//	 * 
+//	 * Simple clients that do little more than log the messages or display
+//	 * them to the user should probably call getMessages instead.
+//	 * 
+// * Since the Java language allows comments to appear most anywhere +// * in the source text, it is problematic to locate comments in relation +// * to the structure of an AST. The one exception is doc comments +// * which, by convention, immediately precede type, field, and +// * method declarations; these comments are located in the AST +// * by {@link BodyDeclaration#getJavadoc BodyDeclaration.getJavadoc}. +// * Other comments do not show up in the AST. The table of comments +// * is provided for clients that need to find the source ranges of +// * all comments in the original source string. It includes entries +// * for comments of all kinds (line, block, and doc), arranged in order +// * of increasing source position. +// *
+// * Note on comment parenting: The {@link ASTNode#getParent() getParent()} +// * of a doc comment associated with a body declaration is the body +// * declaration node; for these comment nodes +// * {@link ASTNode#getRoot() getRoot()} will return the compilation unit +// * (assuming an unmodified AST) reflecting the fact that these nodes +// * are property located in the AST for the compilation unit. +// * However, for other comment nodes, {@link ASTNode#getParent() getParent()} +// * will returnnull, and {@link ASTNode#getRoot() getRoot()}
+//	 * will return the comment node itself, indicating that these comment nodes
+//	 * are not directly connected to the AST for the compilation unit. The 
+//	 * {@link Comment#getAlternateRoot Comment.getAlternateRoot}
+//	 * method provides a way to navigate from a comment to its compilation
+//	 * unit.
+//	 * 
+//	 * +// * A note on visitors: The only comment nodes that will be visited when +// * visiting a compilation unit are the doc comments parented by body +// * declarations. To visit all comments in normal reading order, iterate +// * over the comment table and call {@link ASTNode#accept(ASTVisitor) accept} +// * on each element. +// *
+// *+// * Clients cannot modify the resulting list. +// *
+// * +// * @return an unmodifiable list of comments in increasing order of source +// * start position, ornull if comment information
+//	 * for this compilation unit is not available
+//	 * @see ASTParser
+//	 * @since 3.0
+//	 */
+//	public List getCommentList() {
+//		return this.optionalCommentList;
+//	}
+//	
+//	/**
+//	 * Sets the list of the comments encountered while parsing
+//	 * this compilation unit.
+//	 * 
+//	 * @param commentTable a list of comments in increasing order
+//	 * of source start position, or null if comment
+//	 * information for this compilation unit is not available
+//	 * @exception IllegalArgumentException if the comment table is
+//	 * not in increasing order of source position
+//	 * @see #getCommentList()
+//	 * @see ASTParser
+//	 * @since 3.0
+//	 */
+//	void setCommentTable(Comment[] commentTable) {
+//		// double check table to ensure that all comments have
+//		// source positions and are in strictly increasing order
+//		if (commentTable == null) {
+//			this.optionalCommentList = null;
+//			this.optionalCommentTable = null;
+//		} else {
+//			int nextAvailablePosition = 0;
+//			for (int i = 0; i < commentTable.length; i++) {
+//				Comment comment = commentTable[i];
+//				if (comment == null) {
+//					throw new IllegalArgumentException();
+//				}
+//				int start = comment.getStartPosition();
+//				int length = comment.getLength();
+//				if (start < 0 || length < 0 || start < nextAvailablePosition) {
+//					throw new IllegalArgumentException();
+//				}
+//				nextAvailablePosition = comment.getStartPosition() + comment.getLength();
+//			}
+//			this.optionalCommentTable = commentTable;
+//			List commentList = Arrays.asList(commentTable);
+//			// protect the list from further modification
+//			this.optionalCommentList = Collections.unmodifiableList(commentList);
+//		}
+//	}
+//	
+//	
+//	/* (omit javadoc for this method)
+//	 * Method declared on ASTNode.
+//	 */
+//	void appendDebugString(StringBuffer buffer) {
+//		buffer.append("CompilationUnit"); //$NON-NLS-1$
+//		// include the type names
+//		buffer.append("["); //$NON-NLS-1$
+//		for (Iterator it = types().iterator(); it.hasNext(); ) {
+//			AbstractTypeDeclaration d = (AbstractTypeDeclaration) it.next();
+//			buffer.append(d.getName().getIdentifier());
+//			if (it.hasNext()) {
+//				buffer.append(","); //$NON-NLS-1$
+//			}
+//		}
+//		buffer.append("]"); //$NON-NLS-1$
+//	}
+//		
+//	/* (omit javadoc for this method)
+//	 * Method declared on ASTNode.
+//	 */
+//	int memSize() {
+//		int size = BASE_NODE_SIZE + 8 * 4;
+//		if (this.lineEndTable != null) {
+//			size += HEADERS + 4 * this.lineEndTable.length;
+//		}
+//		if (this.optionalCommentTable != null) {
+//			size += HEADERS + 4 * this.optionalCommentTable.length;
+//		}
+//		// ignore the space taken up by optionalCommentList
+//		return size;
+//	}
+//	
+//	/* (omit javadoc for this method)
+//	 * Method declared on ASTNode.
+//	 */
+//	int treeSize() {
+//		int size = memSize();
+//		if (this.optionalPackageDeclaration != null) {
+//			size += getPackage().treeSize();
+//		}
+//		size += this.imports.listSize();
+//		size += this.types.listSize();
+//		// include disconnected comments
+//		if (this.optionalCommentList != null) {
+//			for (int i = 0; i < this.optionalCommentList.size(); i++) {
+//				Comment comment = (Comment) this.optionalCommentList.get(i);
+//				if (comment != null && comment.getParent() == null) {
+//					size += comment.treeSize();
+//				}
+//			}
+//		}
+//		return size;
+//	}
+//	
+//	/**
+//	 * Enables the recording of changes to this compilation
+//	 * unit and its descendents. The compilation unit must have
+//	 * been created by ASTParser and still be in
+//	 * its original state. Once recording is on,
+//	 * arbitrary changes to the subtree rooted at this compilation
+//	 * unit are recorded internally. Once the modification has
+//	 * been completed, call rewrite to get an object
+//	 * representing the corresponding edits to the original 
+//	 * source code string.
+//	 *
+//	 * @exception IllegalArgumentException if this compilation unit is
+//	 * marked as unmodifiable, or if this compilation unit has already 
+//	 * been tampered with, or recording has already been enabled
+//	 * @since 3.0
+//	 */
+//	public void recordModifications() {
+//		getAST().recordModifications(this);
+//	}
+//	
+//	/**
+//	 * Converts all modifications recorded for this compilation
+//	 * unit into an object representing the corresponding text
+//	 * edits to the given document containing the original source
+//	 * code for this compilation unit.
+//	 * 
+//	 * The compilation unit must have been created by
+//	 * ASTParser from the source code string in the
+//	 * given document, and recording must have been turned
+//	 * on with a prior call to recordModifications
+//	 * while the AST was still in its original state.
+//	 * 
+// * Calling this methods does not discard the modifications +// * on record. Subsequence modifications made to the AST +// * are added to the ones already on record. If this method +// * is called again later, the resulting text edit object will +// * accurately reflect the net cumulative affect of all those +// * changes. +// *
+// * +// * @param document original document containing source code +// * for this compilation unit +// * @param options the table of formatter options +// * (key type:String; value type: String);
+//	 * or null to use the standard global options
+//	 * {@link JavaCore#getOptions() JavaCore.getOptions()}.
+//	 * @return text edit object describing the changes to the
+//	 * document corresponding to the recorded AST modifications
+//	 * @exception IllegalArgumentException if the document passed is
+//	 * null or does not correspond to this AST
+//	 * @exception IllegalStateException if recordModifications
+//	 * was not called to enable recording
+//	 * @see #recordModifications()
+//	 * @since 3.0
+//	 */
+//	public TextEdit rewrite(IDocument document, Map options) {
+//		return getAST().rewrite(document, options);
+//	}
+}
+
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/jdom/DOMFactory.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/jdom/DOMFactory.java
index 0e61752..fdc8bbd 100644
--- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/jdom/DOMFactory.java
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/jdom/DOMFactory.java
@@ -10,9 +10,9 @@
  *******************************************************************************/
 package net.sourceforge.phpdt.core.jdom;
 
-import net.sourceforge.phpdt.internal.core.Util;
 import net.sourceforge.phpdt.internal.core.jdom.DOMBuilder;
 import net.sourceforge.phpdt.internal.core.jdom.SimpleDOMBuilder;
+import net.sourceforge.phpdt.internal.core.util.Util;
 
 
 /**
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/UnitParser.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/UnitParser.java
index 3a40512..5ee16b9 100644
--- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/UnitParser.java
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/UnitParser.java
@@ -19,8 +19,7 @@ import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.CoreException;
 
 /**
- * @author jsurfer
- *
+ * 
  * 
  */
 public class UnitParser extends Parser {
@@ -202,7 +201,7 @@ public class UnitParser extends Parser {
             new Integer(problem.getSourceStart()),
             new Integer(problem.getSourceEnd() + 1),
             new Integer(problem.getSourceLineNumber()),
-            net.sourceforge.phpdt.internal.core.Util.getProblemArgumentsForMarker(problem.getArguments())});
+            net.sourceforge.phpdt.internal.core.util.Util.getProblemArgumentsForMarker(problem.getArguments())});
       }
 
     }
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/util/Util.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/util/Util.java
index 9ece7dc..66208c0 100644
--- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/util/Util.java
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/util/Util.java
@@ -24,6 +24,7 @@ import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
 import net.sourceforge.phpdt.core.compiler.CharOperation;
+import net.sourceforge.phpdt.internal.ui.util.PHPFileUtil;
 
 public class Util {
 
@@ -373,15 +374,16 @@ public class Util {
 	 * 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; i < suffixLength; i++) {
-			char c = name.charAt(nameLength - i - 1);
-			int suffixIndex = suffixLength - i - 1;
-			if (c != SUFFIX_java[suffixIndex] && c != SUFFIX_JAVA[suffixIndex]) return false;
-		}
-		return true;		
+		return PHPFileUtil.isPHPFileName(name);
+//		int nameLength = name == null ? 0 : name.length();
+//		int suffixLength = SUFFIX_JAVA.length;
+//		if (nameLength < suffixLength) return false;
+//
+//		for (int i = 0; i < suffixLength; i++) {
+//			char c = name.charAt(nameLength - i - 1);
+//			int suffixIndex = suffixLength - i - 1;
+//			if (c != SUFFIX_java[suffixIndex] && c != SUFFIX_JAVA[suffixIndex]) return false;
+//		}
+//		return true;		
 	}
 }
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/util/Util.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/util/Util.java
new file mode 100644
index 0000000..ea8125b
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/util/Util.java
@@ -0,0 +1,1365 @@
+/*******************************************************************************
+ * 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;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.StringTokenizer;
+
+import net.sourceforge.phpdt.core.IJavaElement;
+import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
+import net.sourceforge.phpdt.core.IPackageFragment;
+import net.sourceforge.phpdt.core.JavaModelException;
+import net.sourceforge.phpdt.core.JavaCore;
+import net.sourceforge.phpdt.core.Signature;
+import net.sourceforge.phpdt.core.compiler.CharOperation;
+import net.sourceforge.phpdt.internal.core.PackageFragmentRoot;
+import net.sourceforge.phpdt.internal.corext.Assert;
+import net.sourceforge.phpdt.internal.ui.util.PHPFileUtil;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+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 = "net.sourceforge.phpdt.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 0 if a is equal to
+	 *          b; a value less than 0 if a
+	 *          is lexicographically less than b; and a
+	 *          value greater than 0 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 "\n" or "\r" or  "\r\n",
+	 *			or null 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 "\n" or "\r" or  "\r\n"
+	 */
+	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 net.sourceforge.phpdt.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 net.sourceforge.phpdt.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();
+  	PackageFragmentRoot root = null;
+  	IResource resource = null;
+		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:
+	 * ".java" suffix
+	 * IStatus.OK 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 PHPFileUtil.isPHPFileName(name);
+//		return JavaConventions.validateCompilationUnitName(name).getSeverity() != IStatus.ERROR;
+	}
+
+	/**
+	 * Validate the given .class file name.
+	 * A .class file name must obey the following rules:
+	 * ".class" suffix
+	 * IStatus.OK 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 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;
+	  return true;
+	}	
+
+	/*
+	 * 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, 
+			JavaCore.getPlugin().getDescriptor().getUniqueIdentifier(), 
+			IStatus.ERROR, 
+			message, 
+			e); 
+		JavaCore.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));
+	}
+	public static void verbose(String log) {
+		verbose(log, System.out);
+	}
+	public static synchronized void verbose(String log, PrintStream printStream) {
+		int start = 0;
+		do {
+			int end = log.indexOf('\n', start);
+			printStream.print(Thread.currentThread());
+			printStream.print(" "); //$NON-NLS-1$
+			printStream.print(log.substring(start, end == -1 ? log.length() : end+1));
+			start = end+1;
+		} while (start != 0);
+		printStream.println();
+	}
+	/**
+	 * 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/corext/template/TemplateSet.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/template/TemplateSet.java
index ab30dd3..3ddf18f 100644
--- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/template/TemplateSet.java
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/template/TemplateSet.java
@@ -22,11 +22,16 @@ import javax.xml.parsers.ParserConfigurationException;
 
 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
 
-import org.apache.xml.serialize.OutputFormat;
-import org.apache.xml.serialize.Serializer;
-import org.apache.xml.serialize.SerializerFactory;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
 import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IStatus;
 import org.w3c.dom.Attr;
 import org.w3c.dom.Document;
 import org.w3c.dom.NamedNodeMap;
@@ -218,16 +223,27 @@ public class TemplateSet {
         node.appendChild(pattern);
       }
 
-      OutputFormat format = new OutputFormat();
-      format.setPreserveSpace(true);
-      Serializer serializer = SerializerFactory.getSerializerFactory("xml").makeSerializer(stream, format); //$NON-NLS-1$
-      serializer.asDOMSerializer().serialize(document);
+      Transformer transformer=TransformerFactory.newInstance().newTransformer();
+	  transformer.setOutputProperty(OutputKeys.METHOD, "xml"); //$NON-NLS-1$
+	  transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); //$NON-NLS-1$
+	  DOMSource source = new DOMSource(document);
+	  StreamResult result = new StreamResult(stream);
+
+	  transformer.transform(source, result);
+      
+//      OutputFormat format = new OutputFormat();
+//      format.setPreserveSpace(true);
+//      Serializer serializer = SerializerFactory.getSerializerFactory("xml").makeSerializer(stream, format); //$NON-NLS-1$
+//      serializer.asDOMSerializer().serialize(document);
 
     } catch (ParserConfigurationException e) {
       throwWriteException(e);
-    } catch (IOException e) {
-      throwWriteException(e);
-    }
+    } catch (TransformerException e) {
+		throwWriteException(e);
+	}
+//    } catch (IOException e) {
+//      throwWriteException(e);
+//    }
   }
 
   private static void throwReadException(Throwable t) throws CoreException {
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/ActionMessages.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/ActionMessages.java
index 120b578..3a0465f 100644
--- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/ActionMessages.java
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/ActionMessages.java
@@ -41,7 +41,15 @@ public class ActionMessages {
 			return '!' + key + '!';
 		}
 	}
-	
+	/**
+	 * Returns the resource bundle managed by the receiver.
+	 * 
+	 * @return the resource bundle
+	 * @since 3.0
+	 */
+	public static ResourceBundle getResourceBundle() {
+		return RESOURCE_BUNDLE;
+	}
 	/**
 	 * Returns the formatted resource string associated with the given key in the resource bundle. 
 	 * MessageFormat is used to format the message. If there isn't  any value 
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/AddBlockCommentAction.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/AddBlockCommentAction.java
index 1567bca..2da463d 100644
--- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/AddBlockCommentAction.java
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/AddBlockCommentAction.java
@@ -53,7 +53,7 @@ public class AddBlockCommentAction extends BlockCommentAction {
 		int selectionOffset= selection.getOffset();
 		int selectionEndOffset= selectionOffset + selection.getLength();
 		List edits= new LinkedList();
-		ITypedRegion partition= docExtension.getPartition(IPHPPartitions.PHP_PARTITIONING, selectionOffset);
+		ITypedRegion partition= docExtension.getPartition(IPHPPartitions.PHP_PARTITIONING, selectionOffset, false);
 
 		handleFirstPartition(partition, edits, factory, selectionOffset);
 
@@ -124,7 +124,7 @@ public class AddBlockCommentAction extends BlockCommentAction {
 		}
 
 		// advance to next partition
-		partition= docExtension.getPartition(IPHPPartitions.PHP_PARTITIONING, partEndOffset);
+		partition= docExtension.getPartition(IPHPPartitions.PHP_PARTITIONING, partEndOffset, false);
 		partType= partition.getType();
 
 		// start of next partition
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/FoldingActionGroup.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/FoldingActionGroup.java
new file mode 100644
index 0000000..e40f478
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/FoldingActionGroup.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * 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.ui.actions;
+
+import org.eclipse.jface.action.IMenuManager;
+
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.source.projection.IProjectionListener;
+import org.eclipse.jface.text.source.projection.ProjectionViewer;
+
+import org.eclipse.ui.actions.ActionGroup;
+import org.eclipse.ui.editors.text.IFoldingCommandIds;
+import org.eclipse.ui.texteditor.ITextEditor;
+import org.eclipse.ui.texteditor.TextOperationAction;
+
+
+/**
+ * Groups the JDT folding actions.
+ *  
+ * @since 3.0
+ */
+public class FoldingActionGroup extends ActionGroup {
+	private ProjectionViewer fViewer;
+	
+	private TextOperationAction fToggle;
+	private TextOperationAction fExpand;
+	private TextOperationAction fCollapse;
+	private TextOperationAction fExpandAll;
+
+	private IProjectionListener fProjectionListener;
+	
+	/**
+	 * Creates a new projection action group for editor. If the
+	 * supplied viewer is not an instance of ProjectionViewer, the
+	 * action group is disabled.
+	 * 
+	 * @param editor the text editor to operate on
+	 * @param viewer the viewer of the editor
+	 */
+	public FoldingActionGroup(ITextEditor editor, ITextViewer viewer) {
+		if (viewer instanceof ProjectionViewer) {
+			fViewer= (ProjectionViewer) viewer;
+			
+			fProjectionListener= new IProjectionListener() {
+
+				public void projectionEnabled() {
+					update();
+				}
+
+				public void projectionDisabled() {
+					update();
+				}
+			};
+			
+			fViewer.addProjectionListener(fProjectionListener);
+			
+			fToggle= new TextOperationAction(ActionMessages.getResourceBundle(), "Projection.Toggle.", editor, ProjectionViewer.TOGGLE, true); //$NON-NLS-1$
+			fToggle.setChecked(true);
+			fToggle.setActionDefinitionId(IFoldingCommandIds.FOLDING_TOGGLE);
+			editor.setAction("FoldingToggle", fToggle); //$NON-NLS-1$
+			
+			fExpandAll= new TextOperationAction(ActionMessages.getResourceBundle(), "Projection.ExpandAll.", editor, ProjectionViewer.EXPAND_ALL, true); //$NON-NLS-1$
+			fExpandAll.setActionDefinitionId(IFoldingCommandIds.FOLDING_EXPAND_ALL);
+			editor.setAction("FoldingExpandAll", fExpandAll); //$NON-NLS-1$
+			
+			fExpand= new TextOperationAction(ActionMessages.getResourceBundle(), "Projection.Expand.", editor, ProjectionViewer.EXPAND, true); //$NON-NLS-1$
+			fExpand.setActionDefinitionId(IFoldingCommandIds.FOLDING_EXPAND);
+			editor.setAction("FoldingExpand", fExpand); //$NON-NLS-1$
+			
+			fCollapse= new TextOperationAction(ActionMessages.getResourceBundle(), "Projection.Collapse.", editor, ProjectionViewer.COLLAPSE, true); //$NON-NLS-1$
+			fCollapse.setActionDefinitionId(IFoldingCommandIds.FOLDING_COLLAPSE);
+			editor.setAction("FoldingCollapse", fCollapse); //$NON-NLS-1$
+		}
+	}
+	
+	/**
+	 * Returns true if the group is enabled. 
+	 * + * Invariant: isEnabled() <=> fViewer and all actions are != null. + *+ * + * @return
true if the group is enabled
+	 */
+	protected boolean isEnabled() {
+		return fViewer != null;
+	}
+	
+	/*
+	 * @see org.eclipse.ui.actions.ActionGroup#dispose()
+	 */
+	public void dispose() {
+		if (isEnabled()) {
+			fViewer.removeProjectionListener(fProjectionListener);
+			fViewer= null;
+		}
+		super.dispose();
+	}
+	
+	/**
+	 * Updates the actions.
+	 */
+	protected void update() {
+		if (isEnabled()) {
+			fToggle.update();
+			fToggle.setChecked(fViewer.getProjectionAnnotationModel() != null);
+			fExpand.update();
+			fExpandAll.update();
+			fCollapse.update();
+		}
+	}
+	
+	/**
+	 * Fills the menu with all folding actions.
+	 * 
+	 * @param manager the menu manager for the folding submenu
+	 */
+	public void fillMenu(IMenuManager manager) {
+		if (isEnabled()) {
+			update();
+			manager.add(fToggle);
+			manager.add(fExpandAll);
+			manager.add(fExpand);
+			manager.add(fCollapse);
+		}
+	}
+	
+	/*
+	 * @see org.eclipse.ui.actions.ActionGroup#updateActionBars()
+	 */
+	public void updateActionBars() {
+		update();
+	}
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/FoldingExpandAllRulerAction.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/FoldingExpandAllRulerAction.java
new file mode 100644
index 0000000..7619360
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/FoldingExpandAllRulerAction.java
@@ -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.internal.ui.actions;
+
+import org.eclipse.jface.action.IAction;
+
+import org.eclipse.jface.text.source.IVerticalRulerInfo;
+import org.eclipse.jface.text.source.projection.ProjectionViewer;
+
+import org.eclipse.ui.editors.text.IFoldingCommandIds;
+import org.eclipse.ui.texteditor.AbstractRulerActionDelegate;
+import org.eclipse.ui.texteditor.ITextEditor;
+import org.eclipse.ui.texteditor.TextOperationAction;
+
+
+/**
+ * Groups the JDT folding actions.
+ *  
+ * @since 3.0
+ */
+public class FoldingExpandAllRulerAction extends AbstractRulerActionDelegate {
+
+	/*
+	 * @see org.eclipse.ui.texteditor.AbstractRulerActionDelegate#createAction(org.eclipse.ui.texteditor.ITextEditor, org.eclipse.jface.text.source.IVerticalRulerInfo)
+	 */
+	protected IAction createAction(ITextEditor editor, IVerticalRulerInfo rulerInfo) {
+		TextOperationAction action= new TextOperationAction(ActionMessages.getResourceBundle(), "Projection.ExpandAll.", editor, ProjectionViewer.EXPAND_ALL, true); //$NON-NLS-1$
+		action.setActionDefinitionId(IFoldingCommandIds.FOLDING_EXPAND_ALL);
+		return action;
+	}
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/FoldingToggleRulerAction.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/FoldingToggleRulerAction.java
new file mode 100644
index 0000000..d22d55f
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/FoldingToggleRulerAction.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * 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.ui.actions;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuManager;
+
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.jface.text.source.IVerticalRulerInfo;
+import org.eclipse.jface.text.source.projection.ProjectionViewer;
+
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.editors.text.IFoldingCommandIds;
+import org.eclipse.ui.texteditor.AbstractRulerActionDelegate;
+import org.eclipse.ui.texteditor.ITextEditor;
+import org.eclipse.ui.texteditor.TextOperationAction;
+
+import net.sourceforge.phpeclipse.phpeditor.PHPEditor;
+
+
+/**
+ * Groups the JDT folding actions.
+ *  
+ * @since 3.0
+ */
+public class FoldingToggleRulerAction extends AbstractRulerActionDelegate {
+
+	private IAction fUIAction;
+	private TextOperationAction fAction;
+	private ITextEditor fTextEditor;
+
+	/*
+	 * @see org.eclipse.ui.texteditor.AbstractRulerActionDelegate#createAction(org.eclipse.ui.texteditor.ITextEditor, org.eclipse.jface.text.source.IVerticalRulerInfo)
+	 */
+	protected IAction createAction(ITextEditor editor, IVerticalRulerInfo rulerInfo) {
+		fTextEditor= editor;
+		fAction= new TextOperationAction(ActionMessages.getResourceBundle(), "Projection.Toggle.", editor, ProjectionViewer.TOGGLE, true); //$NON-NLS-1$
+		fAction.setActionDefinitionId(IFoldingCommandIds.FOLDING_TOGGLE);
+
+		return fAction;
+	}
+	
+	/*
+	 * @see org.eclipse.ui.texteditor.AbstractRulerActionDelegate#setActiveEditor(org.eclipse.jface.action.IAction, org.eclipse.ui.IEditorPart)
+	 */
+	public void setActiveEditor(IAction callerAction, IEditorPart targetEditor) {
+		fUIAction= callerAction;
+		super.setActiveEditor(callerAction, targetEditor);
+	}
+	
+	/*
+	 * @see org.eclipse.ui.texteditor.AbstractRulerActionDelegate#menuAboutToShow(org.eclipse.jface.action.IMenuManager)
+	 */
+	public void menuAboutToShow(IMenuManager manager) {
+		update();
+		super.menuAboutToShow(manager);
+	}
+	
+	private void update() {
+		if (fTextEditor instanceof PHPEditor) {
+			ISourceViewer viewer= ((PHPEditor) fTextEditor).getViewer();
+			if (viewer instanceof ProjectionViewer) {
+				boolean enabled= ((ProjectionViewer) viewer).getProjectionAnnotationModel() != null;
+				fUIAction.setChecked(enabled);
+			}
+		}
+	}
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/RemoveBlockCommentAction.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/RemoveBlockCommentAction.java
index 60eadc2..2af8550 100644
--- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/RemoveBlockCommentAction.java
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/RemoveBlockCommentAction.java
@@ -54,7 +54,7 @@ public class RemoveBlockCommentAction extends BlockCommentAction {
 		int offset= selection.getOffset();
 		int endOffset= offset + selection.getLength();
 
-		ITypedRegion partition= docExtension.getPartition(IPHPPartitions.PHP_PARTITIONING, offset);
+		ITypedRegion partition= docExtension.getPartition(IPHPPartitions.PHP_PARTITIONING, offset, false);
 		int partOffset= partition.getOffset();
 		int partEndOffset= partOffset + partition.getLength();
 		
@@ -65,7 +65,7 @@ public class RemoveBlockCommentAction extends BlockCommentAction {
 				edits.add(factory.createEdit(partEndOffset - tokenLength, tokenLength, "")); //$NON-NLS-1$
 			}
 			
-			partition= docExtension.getPartition(IPHPPartitions.PHP_PARTITIONING, partEndOffset);
+			partition= docExtension.getPartition(IPHPPartitions.PHP_PARTITIONING, partEndOffset, false);
 			partOffset= partition.getOffset();
 			partEndOffset= partOffset + partition.getLength();
 		}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/ITypingRunListener.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/ITypingRunListener.java
new file mode 100644
index 0000000..0d79e10
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/ITypingRunListener.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * 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.ui.text;
+
+import net.sourceforge.phpdt.internal.ui.text.TypingRun.ChangeType;
+
+
+/**
+ * Listener for TypingRun events.
+ * 
+ * @since 3.0
+ */
+public interface ITypingRunListener {
+	/**
+	 * Called when a new TypingRun is started.
+	 * 
+	 * @param run the newly started run
+	 */
+	void typingRunStarted(TypingRun run);
+	
+	/**
+	 * Called whenever a TypingRun is ended.
+	 * 
+	 * @param run the ended run
+	 * @param reason the type of change that caused the end of the run
+	 */
+	void typingRunEnded(TypingRun run, ChangeType reason);
+}
\ No newline at end of file
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/JavaPresentationReconciler.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/JavaPresentationReconciler.java
new file mode 100644
index 0000000..67b0c5e
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/JavaPresentationReconciler.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 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.ui.text;
+
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.TextPresentation;
+import org.eclipse.jface.text.presentation.PresentationReconciler;
+
+
+/**
+ * Presentation reconciler, adding functionality for operation without a viewer.
+ * 
+ * @since 3.0
+ */
+public class JavaPresentationReconciler extends PresentationReconciler {
+	
+	/** Last used document */
+	private IDocument fLastDocument;
+	
+	/**
+	 * Constructs a "repair description" for the given damage and returns
+	 * this description as a text presentation.
+	 * + * NOTE: Should not be used if this reconciler is installed on a viewer. + *
+ * + * @param damage the damage to be repaired + * @param document the document whose presentation must be repaired + * @return the presentation repair description as text presentation + */ + public TextPresentation createRepairDescription(IRegion damage, IDocument document) { + if (document != fLastDocument) { + setDocumentToDamagers(document); + setDocumentToRepairers(document); + } + return createPresentation(damage, document); + } +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/PreferencesAdapter.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/PreferencesAdapter.java new file mode 100644 index 0000000..0302dc9 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/PreferencesAdapter.java @@ -0,0 +1,309 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 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.ui.text; + +import org.eclipse.core.runtime.Preferences; + +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.ListenerList; +import org.eclipse.jface.util.PropertyChangeEvent; + +/** + * Adapts {@link org.eclipse.core.runtime.Preferences} to + * {@link org.eclipse.jface.preference.IPreferenceStore} + * + * @since 3.0 + */ +public class PreferencesAdapter implements IPreferenceStore { + + /** + * Property change listener. Listens for events of type + * {@link org.eclipse.core.runtime.Preferences.PropertyChangeEvent} and fires + * a {@link org.eclipse.jface.util.PropertyChangeEvent} on the + * adapter with arguments from the received event. + */ + private class PropertyChangeListener implements Preferences.IPropertyChangeListener { + + /* + * @see org.eclipse.core.runtime.Preferences.IPropertyChangeListener#propertyChange(org.eclipse.core.runtime.Preferences.PropertyChangeEvent) + */ + public void propertyChange(Preferences.PropertyChangeEvent event) { + firePropertyChangeEvent(event.getProperty(), event.getOldValue(), event.getNewValue()); + } + } + + /** Listeners on the adapter */ + private ListenerList fListeners= new ListenerList(); + + /** Listener on the adapted Preferences */ + private PropertyChangeListener fListener= new PropertyChangeListener(); + + /** Adapted Preferences */ + private Preferences fPreferences; + + /** True iff no events should be forwarded */ + private boolean fSilent; + + /** + * Initialize with empty Preferences. + */ + public PreferencesAdapter() { + this(new Preferences()); + } + /** + * Initialize with the given Preferences. + * + * @param preferences The preferences to wrap. + */ + public PreferencesAdapter(Preferences preferences) { + fPreferences= preferences; + } + + /** + * {@inheritDoc} + */ + public void addPropertyChangeListener(IPropertyChangeListener listener) { + if (fListeners.size() == 0) + fPreferences.addPropertyChangeListener(fListener); + fListeners.add(listener); + } + + /** + * {@inheritDoc} + */ + public void removePropertyChangeListener(IPropertyChangeListener listener) { + fListeners.remove(listener); + if (fListeners.size() == 0) + fPreferences.removePropertyChangeListener(fListener); + } + + /** + * {@inheritDoc} + */ + public boolean contains(String name) { + return fPreferences.contains(name); + } + + /** + * {@inheritDoc} + */ + public void firePropertyChangeEvent(String name, Object oldValue, Object newValue) { + if (!fSilent) { + PropertyChangeEvent event= new PropertyChangeEvent(this, name, oldValue, newValue); + Object[] listeners= fListeners.getListeners(); + for (int i= 0; i < listeners.length; i++) + ((IPropertyChangeListener) listeners[i]).propertyChange(event); + } + } + + /** + * {@inheritDoc} + */ + public boolean getBoolean(String name) { + return fPreferences.getBoolean(name); + } + + /** + * {@inheritDoc} + */ + public boolean getDefaultBoolean(String name) { + return fPreferences.getDefaultBoolean(name); + } + + /** + * {@inheritDoc} + */ + public double getDefaultDouble(String name) { + return fPreferences.getDefaultDouble(name); + } + + /** + * {@inheritDoc} + */ + public float getDefaultFloat(String name) { + return fPreferences.getDefaultFloat(name); + } + + /** + * {@inheritDoc} + */ + public int getDefaultInt(String name) { + return fPreferences.getDefaultInt(name); + } + + /** + * {@inheritDoc} + */ + public long getDefaultLong(String name) { + return fPreferences.getDefaultLong(name); + } + + /** + * {@inheritDoc} + */ + public String getDefaultString(String name) { + return fPreferences.getDefaultString(name); + } + + /** + * {@inheritDoc} + */ + public double getDouble(String name) { + return fPreferences.getDouble(name); + } + + /** + * {@inheritDoc} + */ + public float getFloat(String name) { + return fPreferences.getFloat(name); + } + + /** + * {@inheritDoc} + */ + public int getInt(String name) { + return fPreferences.getInt(name); + } + + /** + * {@inheritDoc} + */ + public long getLong(String name) { + return fPreferences.getLong(name); + } + + /** + * {@inheritDoc} + */ + public String getString(String name) { + return fPreferences.getString(name); + } + + /** + * {@inheritDoc} + */ + public boolean isDefault(String name) { + return fPreferences.isDefault(name); + } + + /** + * {@inheritDoc} + */ + public boolean needsSaving() { + return fPreferences.needsSaving(); + } + + /** + * {@inheritDoc} + */ + public void putValue(String name, String value) { + try { + fSilent= true; + fPreferences.setValue(name, value); + } finally { + fSilent= false; + } + } + + /** + * {@inheritDoc} + */ + public void setDefault(String name, double value) { + fPreferences.setDefault(name, value); + } + + /** + * {@inheritDoc} + */ + public void setDefault(String name, float value) { + fPreferences.setDefault(name, value); + } + + /** + * {@inheritDoc} + */ + public void setDefault(String name, int value) { + fPreferences.setDefault(name, value); + } + + /** + * {@inheritDoc} + */ + public void setDefault(String name, long value) { + fPreferences.setDefault(name, value); + } + + /** + * {@inheritDoc} + */ + public void setDefault(String name, String defaultObject) { + fPreferences.setDefault(name, defaultObject); + } + + /** + * {@inheritDoc} + */ + public void setDefault(String name, boolean value) { + fPreferences.setDefault(name, value); + } + + /** + * {@inheritDoc} + */ + public void setToDefault(String name) { + fPreferences.setToDefault(name); + } + + /** + * {@inheritDoc} + */ + public void setValue(String name, double value) { + fPreferences.setValue(name, value); + } + + /** + * {@inheritDoc} + */ + public void setValue(String name, float value) { + fPreferences.setValue(name, value); + } + + /** + * {@inheritDoc} + */ + public void setValue(String name, int value) { + fPreferences.setValue(name, value); + } + + /** + * {@inheritDoc} + */ + public void setValue(String name, long value) { + fPreferences.setValue(name, value); + } + + /** + * {@inheritDoc} + */ + public void setValue(String name, String value) { + fPreferences.setValue(name, value); + } + + /** + * {@inheritDoc} + */ + public void setValue(String name, boolean value) { + fPreferences.setValue(name, value); + } +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/SmartBackspaceManager.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/SmartBackspaceManager.java new file mode 100644 index 0000000..99484ea --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/SmartBackspaceManager.java @@ -0,0 +1,280 @@ +/******************************************************************************* + * 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.ui.text; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.eclipse.text.edits.MalformedTreeException; +import org.eclipse.text.edits.TextEdit; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.VerifyKeyListener; +import org.eclipse.swt.events.VerifyEvent; +import org.eclipse.swt.graphics.Point; + +import org.eclipse.jface.text.Assert; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.ITextViewerExtension; +import org.eclipse.jface.text.TextViewer; + +import net.sourceforge.phpdt.internal.ui.text.TypingRun.ChangeType; + + + +/** + * Installs as a verify key listener on a viewer and overwrites the behaviour + * of the backspace key. Clients may register undo specifications for certain + * offsets in a document. TheSmartBackspaceManager will manage the
+ * specfications and execute the contained TextEdits when backspace
+ * is pressed at the given offset and the specification is still valid.
+ * + * Undo specifications are removed after a number of typing runs. + *
+ * + * @since 3.0 + */ +public class SmartBackspaceManager { + /* independent of JDT - may be moved to jface.text */ + + /** + * An undo specification describes the change that should be executed if + * backspace is pressed at its trigger offset. + * + * @since 3.0 + */ + public static final class UndoSpec { + private final int triggerOffset; + private final IRegion selection; + private final TextEdit[] undoEdits; + private final UndoSpec child; + int lives; + + /** + * Creates a new spec. A specification consists of a number of + *TextEdit s that will be executed when backspace is
+		 * pressed at triggerOffset. The spec will be removed
+		 * when it is executed, or if more than lives
+		 * TypingRuns have ended after registering the spec.
+		 * 
+		 * Optionally, a child specification can be registered. After executing
+		 * the spec, the child spec will be registered with the manager. This allows
+		 * to create chains of UndoSpecs that will be executed upon
+		 * repeated pressing of backspace.
+		 * 
TextEdit s to perform when executing
+		 *        the spec
+		 * @param lives the number of TypingRun s before removing
+		 *        the spec
+		 * @param child a child specification that will be registered after
+		 *        executing this spec, or null
+		 */
+		public UndoSpec(int triggerOffset, IRegion selection, TextEdit[] edits, int lives, UndoSpec child) {
+			Assert.isLegal(triggerOffset >= 0);
+			Assert.isLegal(selection != null);
+			Assert.isLegal(lives >= 0);
+			Assert.isLegal(edits != null);
+			Assert.isLegal(edits.length > 0);
+			for (int i= 0; i < edits.length; i++) {
+				Assert.isLegal(edits[i] != null);
+			}
+			
+			this.triggerOffset= triggerOffset;
+			this.selection= selection;
+			this.undoEdits= edits;
+			this.lives= lives;
+			this.child= child;
+		}
+	}
+
+
+	private class BackspaceListener implements VerifyKeyListener {
+
+		/*
+		 * @see org.eclipse.swt.custom.VerifyKeyListener#verifyKey(org.eclipse.swt.events.VerifyEvent)
+		 */
+		public void verifyKey(VerifyEvent event) {
+			if (fViewer != null && isBackspace(event)) {
+				int offset= getCaretOffset();
+				UndoSpec spec= removeEdit(offset);
+				if (spec != null) {
+					try {
+						beginChange();
+						for (int i= 0; i < spec.undoEdits.length; i++) {
+							spec.undoEdits[i].apply(getDocument(), TextEdit.UPDATE_REGIONS);
+						}
+						fViewer.setSelectedRange(spec.selection.getOffset(), spec.selection.getLength());
+						if (spec.child != null)
+							register(spec.child);
+					} catch (MalformedTreeException e) {
+						// fall back to standard bs
+						return;
+					} catch (BadLocationException e) {
+						// fall back to standard bs
+						return;
+					} finally {
+						endChange();
+					}
+					event.doit= false;
+				}
+				
+			}
+		}
+
+		private void beginChange() {
+			ITextViewer viewer= fViewer;
+			if (viewer instanceof TextViewer) {
+				TextViewer v= (TextViewer) viewer;
+				v.getRewriteTarget().beginCompoundChange();
+				v.setRedraw(false);
+			}
+		}
+
+		private void endChange() {
+			ITextViewer viewer= fViewer;
+			if (viewer instanceof TextViewer) {
+				TextViewer v= (TextViewer) viewer;
+				v.getRewriteTarget().endCompoundChange();
+				v.setRedraw(true);
+			}
+		}
+
+		private boolean isBackspace(VerifyEvent event) {
+			return event.doit == true && event.character == SWT.BS && event.stateMask == 0;
+		}
+
+		private int getCaretOffset() {
+			ITextViewer viewer= fViewer;
+			Point point= viewer.getSelectedRange();
+			return point.x;
+		}
+
+	}
+	
+	private ITextViewer fViewer;
+	private BackspaceListener fBackspaceListener;
+	private Map fSpecs;
+	private TypingRunDetector fRunDetector;
+	private ITypingRunListener fRunListener;
+
+	/**
+	 * Registers an undo specification with this manager.
+	 * 
+	 * @param spec the specification to register
+	 * @throws IllegalStateException if the manager is not installed
+	 */
+	public void register(UndoSpec spec) {
+		if (fViewer == null)
+			throw new IllegalStateException();
+		
+		ensureListenerInstalled();
+		addEdit(spec);
+	}
+
+	private void addEdit(UndoSpec spec) {
+		Integer i= new Integer(spec.triggerOffset);
+		fSpecs.put(i, spec);
+	}
+	
+	private UndoSpec removeEdit(int offset) {
+		Integer i= new Integer(offset);
+		UndoSpec spec= (UndoSpec) fSpecs.remove(i);
+		return spec;
+	}
+
+	private void ensureListenerInstalled() {
+		if (fBackspaceListener == null) {
+			fBackspaceListener= new BackspaceListener();
+			ITextViewer viewer= fViewer;
+			if (viewer instanceof ITextViewerExtension)
+				((ITextViewerExtension) viewer).prependVerifyKeyListener(fBackspaceListener);
+			else
+				viewer.getTextWidget().addVerifyKeyListener(fBackspaceListener);
+		}
+	}
+
+	private void ensureListenerRemoved() {
+		if (fBackspaceListener != null) {
+			ITextViewer viewer= fViewer;
+			if (viewer instanceof ITextViewerExtension)
+				((ITextViewerExtension) viewer).removeVerifyKeyListener(fBackspaceListener);
+			else
+				viewer.getTextWidget().removeVerifyKeyListener(fBackspaceListener);
+			fBackspaceListener= null;
+		}
+	}
+
+	private IDocument getDocument() {
+		return fViewer.getDocument();
+	}
+
+	/**
+	 * Installs the receiver on a text viewer.
+	 * 
+	 * @param viewer
+	 */
+	public void install(ITextViewer viewer) {
+		Assert.isLegal(viewer != null);
+		
+		fViewer= viewer;
+		fSpecs= new HashMap();
+		fRunDetector= new TypingRunDetector();
+		fRunDetector.install(viewer);
+		fRunListener= new ITypingRunListener() {
+
+			/*
+			 * @see org.eclipse.jface.text.TypingRunDetector.ITypingRunListener#typingRunStarted(org.eclipse.jface.text.TypingRunDetector.TypingRun)
+			 */
+			public void typingRunStarted(TypingRun run) {
+			}
+
+			/*
+			 * @see org.eclipse.jface.text.TypingRunDetector.ITypingRunListener#typingRunEnded(org.eclipse.jface.text.TypingRunDetector.TypingRun)
+			 */
+			public void typingRunEnded(TypingRun run, ChangeType reason) {
+				if (reason == TypingRun.SELECTION)
+					fSpecs.clear();
+				else
+					prune();
+			}
+		};
+		fRunDetector.addTypingRunListener(fRunListener);
+	}
+	
+	private void prune() {
+		for (Iterator it= fSpecs.values().iterator(); it.hasNext();) {
+			UndoSpec spec= (UndoSpec) it.next();
+			if (--spec.lives < 0)
+				it.remove();
+		}
+	}
+	
+	/**
+	 * Uninstalls the receiver. No undo specifications may be registered on an
+	 * uninstalled manager.
+	 */
+	public void uninstall() {
+		if (fViewer != null) {
+			fRunDetector.removeTypingRunListener(fRunListener);
+			fRunDetector.uninstall();
+			fRunDetector= null;
+			ensureListenerRemoved();
+			fViewer= null;
+		}
+	}
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/TypingRun.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/TypingRun.java
new file mode 100644
index 0000000..350672a
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/TypingRun.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * 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.ui.text;
+
+
+
+/**
+ * Describes a run of similar typing changes.
+ * + * XXX to be extended with further information, e.g. offset, length, and + * content of the run. + *
+ * + * @since 3.0 + */ +public final class TypingRun { + /** + * A change of typeDELETE deletes one single character (through delete or
+	 * backspace or empty paste).
+	 */ 
+	public static final ChangeType DELETE= new ChangeType(true, "DELETE"); //$NON-NLS-1$
+	/**
+	 * A change of type INSERT inserts one single character
+	 * (normal typing).
+	 */ 
+	public static final ChangeType INSERT= new ChangeType(true, "INSERT"); //$NON-NLS-1$
+	/**
+	 * A change of type NO_CHANGE does not change anything.
+	 */
+	public static final ChangeType NO_CHANGE= new ChangeType(false, "NO_CHANGE"); //$NON-NLS-1$
+	/**
+	 * A change of type OVERTYPE replaces one single character
+	 * (overwrite mode, pasting a single character).
+	 */
+	public static final ChangeType OVERTYPE= new ChangeType(true, "OVERTYPE"); //$NON-NLS-1$
+	/**
+	 * A change of type SELECTION does not change text, but
+	 * changes the focus, or selection. Such a change ends all typing runs.
+	 */
+	public static final ChangeType SELECTION= new ChangeType(false, "SELECTION"); //$NON-NLS-1$
+	/**
+	 * A change of type UNKNOWN modifies text in an
+	 * unspecified way. An example is pasting more than one character, or 
+	 * deleting an entire selection, or reverting a file. Such a change ends
+	 * all typing runs and cannot form a typing run with any other change,
+	 * including a change of type UNKNOWN.
+	 */
+	public static final ChangeType UNKNOWN= new ChangeType(true, "UNKNOWN"); //$NON-NLS-1$
+
+
+	/**
+	 * Enumeration of change types.
+	 * 
+	 * @since 3.0
+	 */
+	public static final class ChangeType {
+		private final boolean fIsModification;
+		private final String fName;
+		
+		/** Private ctor for type safe enumeration. */
+		private ChangeType(boolean isRunPart, String name) {
+			fIsModification= isRunPart;
+			fName= name;
+		}
+		
+		/**
+		 * Returns true if changes of this type modify text.
+		 * 
+		 * @return true if changes of this type modify text,
+		 *         false otherwise
+		 */
+		boolean isModification() {
+			return fIsModification;
+		}
+		
+		/*
+		 * @see java.lang.Object#toString()
+		 */
+		public String toString() {
+			return fName;
+		}
+	}
+	
+	/**
+	 * Creates a new run.
+	 * 
+	 * @param type the type of the run
+	 */
+	TypingRun(ChangeType type) {
+		this.type= type;
+	}
+	
+	/** The change type of this run. */
+	public final ChangeType type;
+}
\ No newline at end of file
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/TypingRunDetector.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/TypingRunDetector.java
new file mode 100644
index 0000000..61d59e1
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/TypingRunDetector.java
@@ -0,0 +1,471 @@
+/*******************************************************************************
+ * 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.ui.text;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+
+import org.eclipse.jface.text.Assert;
+import org.eclipse.jface.text.DocumentEvent;
+import org.eclipse.jface.text.ITextListener;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.TextEvent;
+
+import net.sourceforge.phpdt.internal.ui.text.TypingRun.ChangeType;
+
+
+/**
+ * When connected to a text viewer, a TypingRunDetector observes
+ * TypingRun events. A typing run is a sequence of similar text
+ * modifications, such as inserting or deleting single characters.
+ * 
+ * Listeners are informed about the start and end of a TypingRun.
+ * 
type.
+		 * 
+		 * @param type the ChangeType of the new change
+		 * @param nextOffset the offset of the next change in a typing run
+		 */
+		public Change(ChangeType type, int nextOffset) {
+			fType= type;
+			fNextOffset= nextOffset;
+		}
+		
+		/**
+		 * Returns true if the receiver can extend the typing
+		 * range the last change of which is described by change.
+		 * 
+		 * @param change the last change in a typing run
+		 * @return true if the receiver is a valid extension to
+		 *         change,false otherwise
+		 */
+		public boolean canFollow(Change change) {
+			if (fType == TypingRun.NO_CHANGE)
+				return true;
+			else if (fType.equals(TypingRun.UNKNOWN))
+				return false;
+			if (fType.equals(change.fType)) {
+				if (fType == TypingRun.DELETE)
+					return fNextOffset == change.fNextOffset - 1;
+				else if (fType == TypingRun.INSERT)
+					return fNextOffset == change.fNextOffset + 1;
+				else if (fType == TypingRun.OVERTYPE)
+					return fNextOffset == change.fNextOffset + 1;
+				else if (fType == TypingRun.SELECTION)
+					return true;
+			}
+			return false;
+		}
+
+		/**
+		 * Returns true if the receiver describes a text
+		 * modification, false if it describes a focus /
+		 * selection change.
+		 * 
+		 * @return true if the receiver is a text modification
+		 */
+		public boolean isModification() {
+			return fType.isModification();
+		}
+
+		/*
+		 * @see java.lang.Object#toString()
+		 */
+		public String toString() {
+			return fType.toString() + "@" + fNextOffset; //$NON-NLS-1$
+		}
+		
+		/**
+		 * Returns the change type of this change.
+		 * 
+		 * @return the change type of this change
+		 */
+		public ChangeType getType() {
+			return fType;
+		}
+	}
+	
+	/**
+	 * Observes any events that modify the content of the document displayed in
+	 * the editor. Since text events may start a new run, this listener is
+	 * always registered if the detector is connected.
+	 */
+	private class TextListener implements ITextListener {
+
+		/*
+		 * @see org.eclipse.jface.text.ITextListener#textChanged(org.eclipse.jface.text.TextEvent)
+		 */
+		public void textChanged(TextEvent event) {
+			handleTextChanged(event);
+		}
+	}
+	
+	/**
+	 * Observes non-modifying events that will end a run, such as clicking into
+	 * the editor, moving the caret, and the editor losing focus. These events
+	 * can never start a run, therefore this listener is only registered if
+	 * there is an ongoing run.
+	 */
+	private class SelectionListener implements MouseListener, KeyListener, FocusListener {
+
+		/*
+		 * @see org.eclipse.swt.events.FocusListener#focusGained(org.eclipse.swt.events.FocusEvent)
+		 */
+		public void focusGained(FocusEvent e) {
+			handleSelectionChanged();
+		}
+
+		/*
+		 * @see org.eclipse.swt.events.FocusListener#focusLost(org.eclipse.swt.events.FocusEvent)
+		 */
+		public void focusLost(FocusEvent e) {
+		}
+		
+		/*
+		 * @see MouseListener#mouseDoubleClick
+		 */
+		public void mouseDoubleClick(MouseEvent e) {
+		}
+		
+		/*
+		 * If the right mouse button is pressed, the current editing command is closed
+		 * @see MouseListener#mouseDown
+		 */
+		public void mouseDown(MouseEvent e) {
+			if (e.button == 1)
+				handleSelectionChanged();
+		}
+		
+		/*
+		 * @see MouseListener#mouseUp
+		 */
+		public void mouseUp(MouseEvent e) {
+		}
+
+		/*
+		 * @see KeyListener#keyPressed
+		 */
+		public void keyReleased(KeyEvent e) {
+		}
+		
+		/*
+		 * On cursor keys, the current editing command is closed
+		 * @see KeyListener#keyPressed
+		 */
+		public void keyPressed(KeyEvent e) {
+			switch (e.keyCode) {
+				case SWT.ARROW_UP:
+				case SWT.ARROW_DOWN:
+				case SWT.ARROW_LEFT:
+				case SWT.ARROW_RIGHT:
+				case SWT.END:
+				case SWT.HOME:
+				case SWT.PAGE_DOWN:
+				case SWT.PAGE_UP:
+					handleSelectionChanged();
+					break;
+			}
+		}
+	}
+	
+	/** The listeners. */
+	private final Set fListeners= new HashSet();
+	/**
+	 * The viewer we work upon. Set to null in
+	 * uninstall.
+	 */
+	private ITextViewer fViewer;
+	/** The text event listener. */
+	private final TextListener fTextListener= new TextListener();
+	/** 
+	 * The selection listener. Set to null when no run is active.
+	 */
+	private SelectionListener fSelectionListener;
+	
+	/* state variables */
+	
+	/** The most recently observed change. Never null. */
+	private Change fLastChange;
+	/** The current run, or null if there is none. */
+	private TypingRun fRun;
+	
+	/**
+	 * Installs the receiver with a text viewer.
+	 * 
+	 * @param viewer the viewer to install on
+	 */
+	public void install(ITextViewer viewer) {
+		Assert.isLegal(viewer != null);
+		fViewer= viewer;
+		connect();
+	}
+	
+	/**
+	 * Initializes the state variables and registers any permanent listeners.
+	 */
+	private void connect() {
+		if (fViewer != null) {
+			fLastChange= new Change(TypingRun.UNKNOWN, -1);
+			fRun= null;
+			fSelectionListener= null;
+			fViewer.addTextListener(fTextListener);
+		}
+	}
+
+	/**
+	 * Uninstalls the receiver and removes all listeners. install()
+	 * must be called for events to be generated.
+	 */
+	public void uninstall() {
+		if (fViewer != null) {
+			fListeners.clear();
+			disconnect();
+			fViewer= null;
+		}
+	}
+	
+	/**
+	 * Disconnects any registered listeners.
+	 */
+	private void disconnect() {
+		fViewer.removeTextListener(fTextListener);
+		ensureSelectionListenerRemoved();
+	}
+
+	/**
+	 * Adds a listener for TypingRun events. Repeatedly adding
+	 * the same listener instance has no effect. Listeners may be added even
+	 * if the receiver is neither connected nor installed.
+	 * 
+	 * @param listener the listener add
+	 */
+	public void addTypingRunListener(ITypingRunListener listener) {
+		Assert.isLegal(listener != null);
+		fListeners.add(listener);
+		if (fListeners.size() == 1)
+			connect();
+	}
+	
+	/**
+	 * Removes the listener from this manager. If listener is not
+	 * registered with the receiver, nothing happens.
+	 *  
+	 * @param listener the listener to remove, or null
+	 */
+	public void removeTypingRunListener(ITypingRunListener listener) {
+		fListeners.remove(listener);
+		if (fListeners.size() == 0)
+			disconnect();
+	}
+	
+	/**
+	 * Handles an incoming text event.
+	 * 
+	 * @param event the text event that describes the text modification
+	 */
+	void handleTextChanged(TextEvent event) {
+		Change type= computeChange(event);
+		handleChange(type);
+	}
+
+	/**
+	 * Computes the change abstraction given a text event.
+	 * 
+	 * @param event the text event to analyze
+	 * @return a change object describing the event
+	 */
+	private Change computeChange(TextEvent event) {
+		DocumentEvent e= event.getDocumentEvent();
+		if (e == null)
+			return new Change(TypingRun.NO_CHANGE, -1);
+		
+		int start= e.getOffset();
+		int end= e.getOffset() + e.getLength();
+		String newText= e.getText();
+		if (newText == null)
+			newText= new String();
+		
+		if (start == end) {
+			// no replace / delete / overwrite
+			if (newText.length() == 1)
+				return new Change(TypingRun.INSERT, end + 1);
+		} else if (start == end - 1) {
+			if (newText.length() == 1)
+				return new Change(TypingRun.OVERTYPE, end);
+			if (newText.length() == 0)
+				return new Change(TypingRun.DELETE, start);
+		}
+		
+		return new Change(TypingRun.UNKNOWN, -1);
+	}
+	
+	/**
+	 * Handles an incoming selection event.
+	 */
+	void handleSelectionChanged() {
+		handleChange(new Change(TypingRun.SELECTION, -1));
+	}
+	
+	/**
+	 * State machine. Changes state given the current state and the incoming
+	 * change.
+	 * 
+	 * @param change the incoming change
+	 */
+	private void handleChange(Change change) {
+		if (change.getType() == TypingRun.NO_CHANGE)
+			return;
+		
+		if (DEBUG)
+			System.err.println("Last change: " + fLastChange); //$NON-NLS-1$
+
+		if (!change.canFollow(fLastChange))
+			endIfStarted(change);
+		fLastChange= change;
+		if (change.isModification())
+			startOrContinue();
+		
+		if (DEBUG)
+			System.err.println("New change: " + change); //$NON-NLS-1$
+	}
+
+	/**
+	 * Starts a new run if there is none and informs all listeners. If there
+	 * already is a run, nothing happens.
+	 */
+	private void startOrContinue() {
+		if (!hasRun()) {
+			if (DEBUG)
+				System.err.println("+Start run"); //$NON-NLS-1$
+			fRun= new TypingRun(fLastChange.getType());
+			ensureSelectionListenerAdded();
+			fireRunBegun(fRun);
+		}
+	}
+
+	/**
+	 * Returns true if there is an active run, false
+	 * otherwise.
+	 * 
+	 * @return true if there is an active run, false
+	 *         otherwise
+	 */
+	private boolean hasRun() {
+		return fRun != null;
+	}
+
+	/**
+	 * Ends any active run and informs all listeners. If there is none, nothing
+	 * happens.
+	 * 
+	 * @param change the change that triggered ending the active run
+	 */
+	private void endIfStarted(Change change) {
+		if (hasRun()) {
+			ensureSelectionListenerRemoved();
+			if (DEBUG)
+				System.err.println("-End run"); //$NON-NLS-1$
+			fireRunEnded(fRun, change.getType());
+			fRun= null;
+		}
+	}
+
+	/**
+	 * Adds the selection listener to the text widget underlying the viewer, if
+	 * not already done.
+	 */
+	private void ensureSelectionListenerAdded() {
+		if (fSelectionListener == null) {
+			fSelectionListener= new SelectionListener();
+			StyledText textWidget= fViewer.getTextWidget();
+			textWidget.addFocusListener(fSelectionListener);
+			textWidget.addKeyListener(fSelectionListener);
+			textWidget.addMouseListener(fSelectionListener);
+		}
+	}
+
+	/**
+	 * If there is a selection listener, it is removed from the text widget
+	 * underlying the viewer.
+	 */
+	private void ensureSelectionListenerRemoved() {
+		if (fSelectionListener != null) {
+			StyledText textWidget= fViewer.getTextWidget();
+			textWidget.removeFocusListener(fSelectionListener);
+			textWidget.removeKeyListener(fSelectionListener);
+			textWidget.removeMouseListener(fSelectionListener);
+			fSelectionListener= null;
+		}
+	}
+
+	/**
+	 * Informs all listeners about a newly started TypingRun.
+	 * 
+	 * @param run the new run
+	 */
+	private void fireRunBegun(TypingRun run) {
+		List listeners= new ArrayList(fListeners);
+		for (Iterator it= listeners.iterator(); it.hasNext();) {
+			ITypingRunListener listener= (ITypingRunListener) it.next();
+			listener.typingRunStarted(fRun);
+		}
+	}
+
+	/**
+	 * Informs all listeners about an ended TypingRun.
+	 * 
+	 * @param run the previously active run
+	 * @param reason the type of change that caused the run to be ended
+	 */
+	private void fireRunEnded(TypingRun run, ChangeType reason) {
+		List listeners= new ArrayList(fListeners);
+		for (Iterator it= listeners.iterator(); it.hasNext();) {
+			ITypingRunListener listener= (ITypingRunListener) it.next();
+			listener.typingRunEnded(fRun, reason);
+		}
+	}
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/java/IJavaReconcilingListener.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/java/IJavaReconcilingListener.java
new file mode 100644
index 0000000..6fc5499
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/java/IJavaReconcilingListener.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 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.ui.text.java;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import net.sourceforge.phpdt.core.dom.CompilationUnit;
+
+
+/**
+ * Interface of an object listening to Java reconciling.
+ * 
+ * @since 3.0
+ */
+public interface IJavaReconcilingListener {
+
+	/**
+	 * Called before reconciling is started.
+	 */
+	void aboutToBeReconciled();
+	
+	/**
+	 * Called after reconciling has been finished.
+	 * @param ast				the compilation unit AST or null if
+ * 								the working copy was consistent or reconciliation has been cancelled
+	 * @param forced			true iff this reconciliation was forced
+	 * @param progressMonitor	the progress monitor
+	 */
+	void reconciled(CompilationUnit ast, boolean forced, IProgressMonitor progressMonitor);
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/java/JavaStringAutoIndentStrategy.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/java/JavaStringAutoIndentStrategy.java
index 319980b..56d3d75 100644
--- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/java/JavaStringAutoIndentStrategy.java
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/java/JavaStringAutoIndentStrategy.java
@@ -147,7 +147,7 @@ public class JavaStringAutoIndentStrategy extends DefaultAutoIndentStrategy {
 
 	private void javaStringIndentAfterNewLine(IDocument document, DocumentCommand command) throws BadLocationException {
 
-		ITypedRegion partition= TextUtilities.getPartition(document, fPartitioning, command.offset);
+		ITypedRegion partition= TextUtilities.getPartition(document, fPartitioning, command.offset, false);
 		int offset= partition.getOffset();
 		int length= partition.getLength();
 
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/java/hover/BestMatchHover.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/java/hover/BestMatchHover.java
index cb927fb..5b5e1cf 100644
--- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/java/hover/BestMatchHover.java
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/java/hover/BestMatchHover.java
@@ -9,7 +9,6 @@
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
 package net.sourceforge.phpdt.internal.ui.text.java.hover;
-
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
@@ -109,12 +108,12 @@ public class BestMatchHover extends AbstractJavaEditorTextHover implements IText
 	}
 
 	/*
-	 * @see org.eclipse.jface.text.ITextHoverExtension#getInformationControlCreator()
+	 * @see org.eclipse.jface.text.ITextHoverExtension#getHoverControlCreator()
 	 * @since 3.0
 	 */
-	public IInformationControlCreator getInformationControlCreator() {
+	public IInformationControlCreator getHoverControlCreator() {
 		if (fBestHover instanceof ITextHoverExtension)
-			return ((ITextHoverExtension)fBestHover).getInformationControlCreator();
+			return ((ITextHoverExtension)fBestHover).getHoverControlCreator();
 
 		return null;
 	}
@@ -129,4 +128,4 @@ public class BestMatchHover extends AbstractJavaEditorTextHover implements IText
 
 		return null;
 	}
-}
+}
\ No newline at end of file
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/java/hover/SourceViewerInformationControl.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/java/hover/SourceViewerInformationControl.java
new file mode 100644
index 0000000..2936e54
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/java/hover/SourceViewerInformationControl.java
@@ -0,0 +1,398 @@
+/*******************************************************************************
+ * 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.ui.text.java.hover;
+
+import net.sourceforge.phpeclipse.PHPeclipsePlugin;
+import net.sourceforge.phpeclipse.phpeditor.JavaSourceViewer;
+import net.sourceforge.phpeclipse.phpeditor.PHPSourceViewerConfiguration;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.text.Document;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IInformationControl;
+import org.eclipse.jface.text.IInformationControlExtension;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.jface.text.source.SourceViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * Source viewer based implementation of IInformationControl. 
+ * Displays information in a source viewer. 
+ * 
+ * @since 3.0
+ */
+public class SourceViewerInformationControl implements IInformationControl, IInformationControlExtension, DisposeListener {
+	
+	/** Border thickness in pixels. */
+	private static final int BORDER= 1;
+	/** The control's shell */
+	private Shell fShell;
+	/** The control's text widget */
+	private StyledText fText;
+	/** The control's source viewer */
+	private SourceViewer fViewer;	
+	/**
+	 * The optional status field.
+	 * 
+	 * @since 3.0
+	 */
+	private Label fStatusField; 
+	/**
+	 * The separator for the optional status field.
+	 * 
+	 * @since 3.0
+	 */
+	private Label fSeparator; 
+	/**
+	 * The font of the optional status text label.
+	 * 
+	 * @since 3.0
+	 */
+	private Font fStatusTextFont;
+	
+	/**
+	 * Creates a default information control with the given shell as parent. The given
+	 * information presenter is used to process the information to be displayed. The given
+	 * styles are applied to the created styled text widget.
+	 * 
+	 * @param parent the parent shell
+	 * @param shellStyle the additional styles for the shell
+	 * @param style the additional styles for the styled text widget
+	 */
+	public SourceViewerInformationControl(Shell parent, int shellStyle, int style) {
+		this(parent, shellStyle, style, null);
+	}
+	
+	/**
+	 * Creates a default information control with the given shell as parent. The given
+	 * information presenter is used to process the information to be displayed. The given
+	 * styles are applied to the created styled text widget.
+	 * 
+	 * @param parent the parent shell
+	 * @param shellStyle the additional styles for the shell
+	 * @param style the additional styles for the styled text widget
+	 * @param statusFieldText the text to be used in the optional status field
+	 *                         or null if the status field should be hidden
+	 * @since 3.0
+	 */
+	public SourceViewerInformationControl(Shell parent, int shellStyle, int style, String statusFieldText) {
+		GridLayout layout;
+		GridData gd;
+
+		fShell= new Shell(parent, SWT.NO_FOCUS | SWT.ON_TOP | shellStyle);
+		Display display= fShell.getDisplay();		
+		fShell.setBackground(display.getSystemColor(SWT.COLOR_BLACK));
+
+		Composite composite= fShell;
+		layout= new GridLayout(1, false);
+		int border= ((shellStyle & SWT.NO_TRIM) == 0) ? 0 : BORDER;
+		layout.marginHeight= border;
+		layout.marginWidth= border;
+		composite.setLayout(layout);
+		gd= new GridData(GridData.FILL_HORIZONTAL);
+		composite.setLayoutData(gd);
+
+		if (statusFieldText != null) {
+			composite= new Composite(composite, SWT.NONE);
+			layout= new GridLayout(1, false);
+			layout.marginHeight= 0;
+			layout.marginWidth= 0;
+			composite.setLayout(layout);
+			gd= new GridData(GridData.FILL_BOTH);
+			composite.setLayoutData(gd);
+			composite.setForeground(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND));
+			composite.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
+		}		
+
+		// Source viewer
+		IPreferenceStore store= PHPeclipsePlugin.getDefault().getCombinedPreferenceStore();
+		fViewer= new JavaSourceViewer(composite, null, null, false, style, store);
+		fViewer.configure(new PHPSourceViewerConfiguration(PHPeclipsePlugin.getDefault().getJavaTextTools().getColorManager(), store, null, null));
+		fViewer.setEditable(false);
+		
+		fText= fViewer.getTextWidget();
+		gd= new GridData(GridData.BEGINNING | GridData.FILL_BOTH);
+		fText.setLayoutData(gd);
+		fText.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_INFO_FOREGROUND));
+		fText.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND));
+			
+		fText.addKeyListener(new KeyListener() {
+				
+			public void keyPressed(KeyEvent e)  {
+				if (e.character == 0x1B) // ESC
+					fShell.dispose();
+			}
+				
+			public void keyReleased(KeyEvent e) {}
+		});
+
+		// Status field
+		if (statusFieldText != null) {
+
+			// Horizontal separator line
+			fSeparator= new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL | SWT.LINE_DOT);
+			fSeparator.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+			// Status field label
+			fStatusField= new Label(composite, SWT.RIGHT);
+			fStatusField.setText(statusFieldText);
+			Font font= fStatusField.getFont();
+			FontData[] fontDatas= font.getFontData();
+			for (int i= 0; i < fontDatas.length; i++)
+				fontDatas[i].setHeight(fontDatas[i].getHeight() * 9 / 10);
+			fStatusTextFont= new Font(fStatusField.getDisplay(), fontDatas);
+			fStatusField.setFont(fStatusTextFont);
+			GridData gd2= new GridData(GridData.FILL_VERTICAL | GridData.FILL_HORIZONTAL | GridData.HORIZONTAL_ALIGN_BEGINNING | GridData.VERTICAL_ALIGN_BEGINNING);
+			fStatusField.setLayoutData(gd2);
+
+			// Regarding the color see bug 41128
+			fStatusField.setForeground(display.getSystemColor(SWT.COLOR_WIDGET_DARK_SHADOW));
+
+			fStatusField.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
+		}
+		
+		addDisposeListener(this);
+	}
+
+	/**
+	 * Creates a default information control with the given shell as parent. The given
+	 * information presenter is used to process the information to be displayed. The given
+	 * styles are applied to the created styled text widget.
+	 * 
+	 * @param parent the parent shell
+	 * @param style the additional styles for the styled text widget
+	 */	
+	public SourceViewerInformationControl(Shell parent,int style) {
+		this(parent, SWT.NO_TRIM, style);
+	}
+	
+	/**
+	 * Creates a default information control with the given shell as parent. The given
+	 * information presenter is used to process the information to be displayed. The given
+	 * styles are applied to the created styled text widget.
+	 * 
+	 * @param parent the parent shell
+	 * @param style the additional styles for the styled text widget
+	 * @param statusFieldText the text to be used in the optional status field
+	 *                         or null if the status field should be hidden
+	 * @since 3.0
+	 */	
+	public SourceViewerInformationControl(Shell parent,int style, String statusFieldText) {
+		this(parent, SWT.NO_TRIM, style, statusFieldText);
+	}
+
+	/**
+	 * Creates a default information control with the given shell as parent.
+	 * No information presenter is used to process the information
+	 * to be displayed. No additional styles are applied to the styled text widget.
+	 * 
+	 * @param parent the parent shell
+	 */
+	public SourceViewerInformationControl(Shell parent) {
+		this(parent, SWT.NONE);
+	}
+
+	/**
+	 * Creates a default information control with the given shell as parent.
+	 * No information presenter is used to process the information
+	 * to be displayed. No additional styles are applied to the styled text widget.
+	 * 
+	 * @param parent the parent shell
+	 * @param statusFieldText the text to be used in the optional status field
+	 *                         or null if the status field should be hidden
+	 * @since 3.0
+	 */
+	public SourceViewerInformationControl(Shell parent, String statusFieldText) {
+		this(parent, SWT.NONE, statusFieldText);
+	}
+	
+	/*
+	 * @see org.eclipse.jface.text.IInformationControlExtension2#setInput(java.lang.Object)
+	 */
+	public void setInput(Object input) {
+		if (input instanceof String)
+			setInformation((String)input);
+		else
+			setInformation(null);
+	}
+
+	/*
+	 * @see IInformationControl#setInformation(String)
+	 */
+	public void setInformation(String content) {
+		if (content == null) {
+			fViewer.setInput(null);
+			return;
+		}
+				
+		IDocument doc= new Document(content);
+		PHPeclipsePlugin.getDefault().getJavaTextTools().setupJavaDocumentPartitioner(doc);
+		
+		fViewer.setInput(doc);
+	}
+	
+	/*
+	 * @see IInformationControl#setVisible(boolean)
+	 */
+	public void setVisible(boolean visible) {
+			fShell.setVisible(visible);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * @since 3.0
+	 */
+	public void widgetDisposed(DisposeEvent event) {
+		if (fStatusTextFont != null && !fStatusTextFont.isDisposed())
+			fStatusTextFont.dispose();
+		
+		fStatusTextFont= null;
+		fShell= null;
+		fText= null;
+	}
+		
+	/**
+	 * {@inheritDoc}
+	 */
+	public final void dispose() {
+		if (fShell != null && !fShell.isDisposed())
+			fShell.dispose();
+		else
+			widgetDisposed(null);
+	}
+	
+	/*
+	 * @see IInformationControl#setSize(int, int)
+	 */
+	public void setSize(int width, int height) {
+		
+		if (fStatusField != null) {
+			GridData gd= (GridData)fViewer.getTextWidget().getLayoutData();
+			Point statusSize= fStatusField.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
+			Point separatorSize= fSeparator.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
+			gd.heightHint= height - statusSize.y - separatorSize.y;
+		}
+		fShell.setSize(width, height);
+		
+		if (fStatusField != null)
+			fShell.pack(true);
+	}
+	
+	/*
+	 * @see IInformationControl#setLocation(Point)
+	 */
+	public void setLocation(Point location) {
+		Rectangle trim= fShell.computeTrim(0, 0, 0, 0);
+		Point textLocation= fText.getLocation();				
+		location.x += trim.x - textLocation.x;		
+		location.y += trim.y - textLocation.y;		
+		fShell.setLocation(location);		
+	}
+	
+	/*
+	 * @see IInformationControl#setSizeConstraints(int, int)
+	 */
+	public void setSizeConstraints(int maxWidth, int maxHeight) {
+		maxWidth= maxHeight;
+	}
+	
+	/*
+	 * @see IInformationControl#computeSizeHint()
+	 */
+	public Point computeSizeHint() {
+		return fShell.computeSize(SWT.DEFAULT, SWT.DEFAULT);
+	}
+	
+	/*
+	 * @see IInformationControl#addDisposeListener(DisposeListener)
+	 */
+	public void addDisposeListener(DisposeListener listener) {
+		fShell.addDisposeListener(listener);
+	}
+	
+	/*
+	 * @see IInformationControl#removeDisposeListener(DisposeListener)
+	 */
+	public void removeDisposeListener(DisposeListener listener) {
+		fShell.removeDisposeListener(listener);
+	}
+	
+	/*
+	 * @see IInformationControl#setForegroundColor(Color)
+	 */
+	public void setForegroundColor(Color foreground) {
+		fText.setForeground(foreground);
+	}
+	
+	/*
+	 * @see IInformationControl#setBackgroundColor(Color)
+	 */
+	public void setBackgroundColor(Color background) {
+		fText.setBackground(background);
+	}
+	
+	/*
+	 * @see IInformationControl#isFocusControl()
+	 */
+	public boolean isFocusControl() {
+		return fText.isFocusControl();
+	}
+	
+	/*
+	 * @see IInformationControl#setFocus()
+	 */
+	public void setFocus() {
+		fShell.forceFocus();
+		fText.setFocus();
+	}
+	
+	/*
+	 * @see IInformationControl#addFocusListener(FocusListener)
+	 */
+	public void addFocusListener(FocusListener listener) {
+		fText.addFocusListener(listener);
+	}
+	
+	/*
+	 * @see IInformationControl#removeFocusListener(FocusListener)
+	 */
+	public void removeFocusListener(FocusListener listener) {
+		fText.removeFocusListener(listener);
+	}
+	
+	/*
+	 * @see IInformationControlExtension#hasContents()
+	 */
+	public boolean hasContents() {
+		return fText.getCharCount() > 0;
+	}
+	
+	protected ISourceViewer getViewer()  {
+		return fViewer;
+	}
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/link/LinkedPositionManager.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/link/LinkedPositionManager.java
index 11403b2..4fb0216 100644
--- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/link/LinkedPositionManager.java
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/link/LinkedPositionManager.java
@@ -722,7 +722,7 @@ public class LinkedPositionManager implements IDocumentListener, IPositionUpdate
 			
 			try {
 				if (position.getType().equals(currentPosition.getType()) && !position.equals(currentPosition))
-					command.addCommand(position.getOffset() + deltaOffset, command.length, command.text, true, this);
+					command.addCommand(position.getOffset() + deltaOffset, command.length, command.text, this);
 			} catch (BadLocationException e) {
 			  PHPeclipsePlugin.log(e);
 			}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/viewsupport/ProblemMarkerManager.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/viewsupport/ProblemMarkerManager.java
index 3be74d5..69bbfb9 100644
--- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/viewsupport/ProblemMarkerManager.java
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/viewsupport/ProblemMarkerManager.java
@@ -127,7 +127,6 @@ public class ProblemMarkerManager implements IResourceChangeListener, IAnnotatio
 			fireChanges(changes, true);
 		}
 	}
-	
 	/* (non-Javadoc)
 	 * @see IAnnotationModelListener#modelChanged(IAnnotationModel)
 	 */
@@ -141,14 +140,13 @@ public class ProblemMarkerManager implements IResourceChangeListener, IAnnotatio
 	public void modelChanged(AnnotationModelEvent event) {
 		if (event instanceof CompilationUnitAnnotationModelEvent) {
 			CompilationUnitAnnotationModelEvent cuEvent= (CompilationUnitAnnotationModelEvent) event;
-			if (cuEvent.includesMarkerAnnotationChanges()) {
+			if (cuEvent.includesProblemMarkerAnnotationChanges()) {
 				IResource[] changes= new IResource[] { cuEvent.getUnderlyingResource() };
 				fireChanges(changes, false);
 			}
 		}
 	}	
 	
-	
 	/**
 	 * Adds a listener for problem marker changes.
 	 */
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/text/JavaTextTools.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/text/JavaTextTools.java
index 946e308..5c025c8 100644
--- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/text/JavaTextTools.java
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/text/JavaTextTools.java
@@ -5,7 +5,6 @@ package net.sourceforge.phpdt.ui.text;
  * All Rights Reserved.
  */
 
-import net.sourceforge.phpdt.internal.ui.text.FastJavaPartitionScanner;
 import net.sourceforge.phpdt.internal.ui.text.IPHPPartitions;
 import net.sourceforge.phpdt.internal.ui.text.JavaColorManager;
 import net.sourceforge.phpdt.internal.ui.text.phpdoc.PHPDocCodeScanner;
@@ -16,6 +15,7 @@ import net.sourceforge.phpeclipse.phpeditor.php.PHPPartitionScanner;
 import net.sourceforge.phpeclipse.phpeditor.php.SmartyCodeScanner;
 import net.sourceforge.phpeclipse.phpeditor.php.SmartyDocCodeScanner;
 
+import org.eclipse.core.resources.IFile;
 import org.eclipse.core.runtime.Preferences;
 import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.jface.text.IDocument;
@@ -26,6 +26,7 @@ import org.eclipse.jface.text.rules.IPartitionTokenScanner;
 import org.eclipse.jface.text.rules.RuleBasedScanner;
 import org.eclipse.jface.util.IPropertyChangeListener;
 import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.ui.part.FileEditorInput;
 //
 //import org.phpeclipse.phpdt.internal.ui.text.FastJavaPartitionScanner;
 //import org.phpeclipse.phpdt.internal.ui.text.JavaColorManager;
@@ -364,25 +365,56 @@ public class JavaTextTools {
 
     return partitioner;
   }
-
 	/**
-	 * Sets up the Java document partitioner for the given document for the given partitioning.
+	 * Sets up the Java document partitioner for the given document for the default partitioning.
 	 * 
 	 * @param document the document to be set up
+	 * @since 3.0
+	 */
+	public void setupJavaDocumentPartitioner(IDocument document) {
+		setupJavaDocumentPartitioner(document, IDocumentExtension3.DEFAULT_PARTITIONING,null);
+	}
+	/**
+	 * Sets up the Java document partitioner for the given document for the given partitioning.
+	 * @param document the document to be set up
 	 * @param partitioning the document partitioning
+	 * @param element TODO
+	 * 
 	 * @since 3.0
 	 */
-	public void setupJavaDocumentPartitioner(IDocument document, String partitioning) {
-		IDocumentPartitioner partitioner= createDocumentPartitioner();
-		if (document instanceof IDocumentExtension3) {
-			IDocumentExtension3 extension3= (IDocumentExtension3) document;
-			extension3.setDocumentPartitioner(partitioning, partitioner);
-		} else {
+	public void setupJavaDocumentPartitioner(IDocument document, String partitioning, Object element) {
+		IDocumentPartitioner partitioner = createDocumentPartitioner(".php");
+			 
+//		if (document instanceof IDocumentExtension3) {
+//			IDocumentExtension3 extension3= (IDocumentExtension3) document;
+//			extension3.setDocumentPartitioner(partitioning, partitioner);
+//		} else {
+			document.setDocumentPartitioner(partitioner);
+//		}
+		partitioner.connect(document);
+	}
+	public void setupHTMLDocumentPartitioner(IDocument document, String partitioning, Object element) {
+		IDocumentPartitioner partitioner = createDocumentPartitioner(".html");
+			 
+//		if (document instanceof IDocumentExtension3) {
+//			IDocumentExtension3 extension3= (IDocumentExtension3) document;
+//			extension3.setDocumentPartitioner(partitioning, partitioner);
+//		} else {
+			document.setDocumentPartitioner(partitioner);
+//		}
+		partitioner.connect(document);
+	}
+	public void setupSmartyDocumentPartitioner(IDocument document, String partitioning, Object element) {
+		IDocumentPartitioner partitioner = createDocumentPartitioner(".tpl");
+			 
+//		if (document instanceof IDocumentExtension3) {
+//			IDocumentExtension3 extension3= (IDocumentExtension3) document;
+//			extension3.setDocumentPartitioner(partitioning, partitioner);
+//		} else {
 			document.setDocumentPartitioner(partitioner);
-		}
+//		}
 		partitioner.connect(document);
 	}
-	
   /**
    * Returns the names of the document position categories used by the document
    * partitioners created by this object to manage their partition information.
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/html/HTMLFormatter.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/html/HTMLFormatter.java
index 30ed71c..7e4c33c 100644
--- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/html/HTMLFormatter.java
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/html/HTMLFormatter.java
@@ -5,11 +5,11 @@ import java.util.HashSet;
 import java.util.Set;
 
 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
-import net.sourceforge.phpeclipse.phpeditor.PHPEditor;
 import net.sourceforge.phpeclipse.phpeditor.PHPSourceViewerConfiguration;
 
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.jface.text.source.SourceViewer;
+import org.eclipse.ui.texteditor.ITextEditor;
 
 /**
  * Modified from the XMLFormatter.  Some tags in HTML do not indent.
@@ -43,7 +43,7 @@ public class HTMLFormatter implements IHTMLConstants {
 	private PHPSourceViewerConfiguration fConfig;
 	private SourceViewer fViewer;
 	//
-	private PHPEditor fEditor;
+	private ITextEditor fEditor;
 	private String fFilename;
 
 	////////////////////////////////////////////////////////////////////////
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/html/HTMLFormattingStrategy.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/html/HTMLFormattingStrategy.java
index e3d00d4..2781272 100644
--- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/html/HTMLFormattingStrategy.java
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/html/HTMLFormattingStrategy.java
@@ -1,6 +1,5 @@
 package net.sourceforge.phpeclipse.phpeditor.html;
 
-import net.sourceforge.phpeclipse.phpeditor.PHPEditor;
 import net.sourceforge.phpeclipse.phpeditor.PHPSourceViewerConfiguration;
 
 import org.eclipse.jface.text.BadLocationException;
@@ -8,6 +7,7 @@ import org.eclipse.jface.text.IDocument;
 import org.eclipse.jface.text.formatter.IFormattingStrategy;
 import org.eclipse.jface.text.source.ISourceViewer;
 import org.eclipse.jface.text.source.SourceViewer;
+import org.eclipse.ui.texteditor.ITextEditor;
 
 /**
  * @author chrisl
@@ -24,7 +24,7 @@ public class HTMLFormattingStrategy implements IFormattingStrategy, IHTMLConstan
 	private PHPSourceViewerConfiguration fConfig;
 	private ISourceViewer fViewer;
 	//
-	private PHPEditor fEditor;
+	private ITextEditor fEditor;
 	private int fTabWidth;
 
 	////////////////////////////////////////////////////////////////////////