* Added browser like links (Ctrl+Mouseclick on identifier; same as F3 shortcut)
authoraxelcl <axelcl>
Wed, 26 Jan 2005 22:47:47 +0000 (22:47 +0000)
committeraxelcl <axelcl>
Wed, 26 Jan 2005 22:47:47 +0000 (22:47 +0000)
* Added pref page for PHP Editor-Navigation (i.e. browser like links)
* search for task-tags now in multi line comments
* fixed bug #996193 (wrong Display.synExec() at startup)
* improved handling for subword shortcuts (ARROW_KEY_LEFT, ARROW_KEY_RIGHT, CTRL+ARROW_KEY_LEFT, CTRL+ARROW_KEY_RIGHT)

39 files changed:
net.sourceforge.phpeclipse/plugin.properties
net.sourceforge.phpeclipse/plugin.xml
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/CompletionProposal.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/CompletionRequestor.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/Flags.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ICodeAssist.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ICodeCompletionRequestor.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/Parser.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/Scanner.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/util/CommentRecorderScanner.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/refactoring/util/ResourceUtil.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/formatter/CodeFormatter.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/ActionUtil.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/AddBlockCommentAction.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/BlockCommentAction.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/IndentAction.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/RemoveBlockCommentAction.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/preferences/JavaEditorPreferencePage.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/DocumentCharacterIterator.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/JavaBreakIterator.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/JavaWordIterator.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/SequenceCharacterIterator.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/java/JavaExpandHover.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/java/JavaHoverMessages.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/java/JavaHoverMessages.properties [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/PreferenceConstants.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/actions/OpenEditorActionGroup.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/actions/PHPEditorActionDefinitionIds.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/actions/IncludesScanner.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/actions/OpenDeclarationEditorAction.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/actions/PHPOpenDeclarationAction.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/actions/PHPOpenDeclarationEditorAction.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/builder/IdentifierIndexManager.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/internal/compiler/ast/CompilationUnitDeclaration.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/BasicJavaEditorActionContributor.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/CompilationUnitEditorActionContributor.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPEditor.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPEditorActionDefinitionIds.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPUnitEditor.java

index dab4d83..ae1bd78 100644 (file)
@@ -23,6 +23,8 @@ newWizardHTMLFile.name=HTML file
 NewPHPClass.label= Class
 NewPHPClass.description=Create a PHP class
 
+OpenActionSet.label=Open Declaration/Include
+OpenActionSet.description=Open a PHP Declaration or Include
 OpenDeclaration=Open Declaration/Include
 ExportWizards.Obfuscator = Obfuscate PHP Project to File system
 ExportWizards.ObfuscatorDescription = Obfuscate PHP resources to the local file system
index 57699a0..663efab 100644 (file)
                id="net.sourceforge.phpeclipse.phpeditor.ShiftRight">
          </action>
          <action
-               definitionId="net.sourceforge.phpeclipse.remove.block.comment"
+               definitionId="net.sourceforge.phpeclipse.phpeditor.remove.block.comment"
                label="%RemoveBlockCommentAction.label"
                retarget="true"
                menubarPath="net.sourceforge.phpeclipse.ui.source.menu/editGroup"
                id="net.sourceforge.phpeclipse.ui.actions.RemoveBlockComment">
          </action>
          <action
-               definitionId="net.sourceforge.phpeclipse.add.block.comment"
+               definitionId="net.sourceforge.phpeclipse.phpeditor.add.block.comment"
                label="%AddBlockCommentAction.label"
                retarget="true"
                menubarPath="net.sourceforge.phpeclipse.ui.source.menu/editGroup"
                id="net.sourceforge.phpeclipse.actions.PHPOpenDeclarationEditorAction">
          </action>
       </viewerContribution>
-      
       <viewerContribution
             targetID="#PHPRulerContext"
             id="net.sourceforge.phpdt.ui.PHPEditorPopupActions">
          </action>
       </viewerContribution>
    </extension>
-   
+   <extension
+         point="org.eclipse.ui.actionSets">
+      <actionSet
+            label="%OpenActionSet.label"
+            description="%OpenActionSet.description"
+            visible="false"
+            id="net.sourceforge.phpeclipse.ui.A_OpenActionSet">
+         <action
+               definitionId="net.sourceforge.phpeclipse.ui.edit.text.java.open.editor"
+               label="%OpenDeclaration"
+               tooltip="%OpenDeclaration"
+               retarget="true"
+               menubarPath="navigate/open.ext" 
+               allowLabelUpdate="true"
+               id="net.sourceforge.phpeclipse.ui.actions.Open">
+         </action>
+      </actionSet>
+   </extension> 
    <extension
          point="org.eclipse.ui.editorActions">
       <editorContribution
                class="net.sourceforge.phpeclipse.actions.PHPOpenDeclarationEditorAction"
                id="net.sourceforge.phpeclipse.actions.PHPOpenDeclarationEditorAction">
          </action>
-      </editorContribution>
+      </editorContribution>   
    </extension>
    <extension
          point="org.eclipse.ui.popupMenus">
             platform="carbon"
             string="Ctrl+/"
             scope="net.sourceforge.phpdt.ui.phpEditorScope"
-            command=""
+            command="net.sourceforge.phpeclipse.phpeditor.toggle.comment"
             configuration="org.eclipse.ui.defaultAcceleratorConfiguration">
       </keyBinding>
       <keyBinding
       
       <!-- navigate -->
       <command
+            name="%ActionDefinition.gotoNextMember.name"
+            description="%ActionDefinition.gotoNextMember.description"
+            category="org.eclipse.ui.category.navigate"
+            id="net.sourceforge.phpeclipse.ui.edit.text.php.goto.next.member">
+      </command>
+      <keyBinding
+            string="Ctrl+Shift+ARROW_DOWN"
+            scope="net.sourceforge.phpdt.ui.phpEditorScope"
+            command="net.sourceforge.phpeclipse.ui.edit.text.php.goto.next.member"
+            configuration="org.eclipse.ui.defaultAcceleratorConfiguration">
+      </keyBinding>
+      <keyBinding
+            platform="carbon"
+            string="Ctrl+Shift+ARROW_DOWN"
+            scope="net.sourceforge.phpdt.ui.phpEditorScope"
+            command=""
+            configuration="org.eclipse.ui.defaultAcceleratorConfiguration">
+      </keyBinding>
+      <keyBinding
+            platform="carbon"
+            string="Command+Shift+ARROW_DOWN"
+            scope="net.sourceforge.phpdt.ui.phpEditorScope"
+            command="net.sourceforge.phpeclipse.ui.edit.text.php.goto.next.member"
+            configuration="org.eclipse.ui.defaultAcceleratorConfiguration">
+      </keyBinding>
+      <command
+            name="%ActionDefinition.gotoPreviousMember.name"
+            description="%ActionDefinition.gotoPreviousMember.description"
+            category="org.eclipse.ui.category.navigate"
+            id="net.sourceforge.phpeclipse.ui.edit.text.php.goto.previous.member">
+      </command>
+      <keyBinding
+            string="Ctrl+Shift+ARROW_UP"
+            scope="net.sourceforge.phpdt.ui.phpEditorScope"
+            command="net.sourceforge.phpeclipse.ui.edit.text.php.goto.previous.member"
+            configuration="org.eclipse.ui.defaultAcceleratorConfiguration">
+      </keyBinding>
+      <keyBinding
+            platform="carbon"
+            string="Ctrl+Shift+ARROW_UP"
+            scope="net.sourceforge.phpdt.ui.phpEditorScope"
+            command=""
+            configuration="org.eclipse.ui.defaultAcceleratorConfiguration">
+      </keyBinding>
+      <keyBinding
+            platform="carbon"
+            string="Command+Shift+ARROW_UP"
+            scope="net.sourceforge.phpdt.ui.phpEditorScope"
+            command="net.sourceforge.phpeclipse.ui.edit.text.php.goto.previous.member"
+            configuration="org.eclipse.ui.defaultAcceleratorConfiguration">
+      </keyBinding>
+      <keyBinding
+            string=""
+            scope="net.sourceforge.phpdt.ui.phpEditorScope"
+            command="org.eclipse.jdt.ui.edit.text.java.show.next.problem"
+            configuration="org.eclipse.ui.defaultAcceleratorConfiguration">
+      </keyBinding>
+      <command
             name="%ActionDefinition.gotoMatchingBracket.name"
             description="%ActionDefinition.gotoMatchingBracket.description"
             category="org.eclipse.ui.category.navigate"
             command="net.sourceforge.phpeclipse.ui.edit.text.php.goto.matching.bracket"
             configuration="org.eclipse.ui.defaultAcceleratorConfiguration">
       </keyBinding>
-      
       <command
             name="%OpenDeclaration" 
             description="%OpenDeclaration"
             scope="net.sourceforge.phpdt.ui.phpEditorScope"
             command="net.sourceforge.phpeclipse.actions.opendeclaration"
             configuration="org.eclipse.ui.defaultAcceleratorConfiguration">
-      </keyBinding>
-   </extension>
+      </keyBinding> 
+   </extension>  
    <extension
          id="net.sourceforge.phpeclipse.JavaDocumentSetupParticipant"
          name="%javaDocumentSetupParticipant"
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/CompletionProposal.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/CompletionProposal.java
new file mode 100644 (file)
index 0000000..dbaf2d9
--- /dev/null
@@ -0,0 +1,905 @@
+/*******************************************************************************
+ * Copyright (c) 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.core;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import net.sourceforge.phpdt.core.compiler.CharOperation;
+
+/**
+ * Completion proposal.
+ * <p>
+ * In typical usage, the user working in a Java code editor issues
+ * a code assist command. This command results in a call to
+ * <code>ICodeAssist.codeComplete(position, completionRequestor)</code>
+ * passing the current position in the source code. The code assist
+ * engine analyzes the code in the buffer, determines what kind of
+ * Java language construct is at that position, and proposes ways
+ * to complete that construct. These proposals are instances of
+ * subclasses of <code>CompletionProposal</code>. These proposals,
+ * perhaps after sorting and filtering, are presented to the user
+ * to make a choice.
+ * </p>
+ * <p>
+ * The proposal is as follows: insert
+ * the {@linkplain #getCompletion() completion string} into the
+ * source file buffer, replacing the characters between 
+ * {@linkplain #getReplaceStart() the start}
+ * and {@linkplain #getReplaceEnd() end}. The string
+ * can be arbitrary; for example, it might include not only the 
+ * name of a method but a set of parentheses. Moreover, the source
+ * range may include source positions before or after the source
+ * position where <code>ICodeAssist.codeComplete</code> was invoked.
+ * The rest of the information associated with the proposal is
+ * to provide context that may help a user to choose from among
+ * competing proposals.
+ * </p>
+ * <p>
+ * The completion engine creates instances of this class; it is not
+ * intended to be used by other clients.
+ * </p>
+ * 
+ * @see ICodeAssist#codeComplete(int, CompletionRequestor)
+ * @since 3.0
+ */
+public final class CompletionProposal {
+
+       /**
+        * Completion is a declaration of an anonymous class.
+        * This kind of completion might occur in a context like
+        * <code>"new List^;"</code> and complete it to
+        * <code>"new List() {}"</code>.
+        * <p>
+        * The following additional context information is available
+        * for this kind of completion proposal at little extra cost:
+        * <ul>
+        * <li>{@link #getDeclarationSignature()} -
+        * the type signature of the type being implemented or subclassed
+        * </li>
+        * </li>
+        * <li>{@link #getSignature()} -
+        * the method signature of the constructor that is referenced
+        * </li>
+        * <li>{@link #getFlags()} -
+        * the modifiers flags of the constructor that is referenced
+        * </li>
+        * </ul>
+        * </p>
+        * 
+        * @see #getKind()
+        */
+       public static final int ANONYMOUS_CLASS_DECLARATION = 1;
+
+       /**
+        * Completion is a reference to a field.
+        * This kind of completion might occur in a context like
+        * <code>"this.ref^ = 0;"</code> and complete it to
+        * <code>"this.refcount = 0;"</code>.
+        * <p>
+        * The following additional context information is available
+        * for this kind of completion proposal at little extra cost:
+        * <ul>
+        * <li>{@link #getDeclarationSignature()} -
+        * the type signature of the type that declares the field that is referenced
+        * </li>
+        * <li>{@link #getFlags()} -
+        * the modifiers flags (including ACC_ENUM) of the field that is referenced
+        * </li>
+        * <li>{@link #getName()} -
+        * the simple name of the field that is referenced
+        * </li>
+        * <li>{@link #getSignature()} -
+        * the type signature of the field's type (as opposed to the
+        * signature of the type in which the referenced field
+        * is declared)
+        * </li>
+        * </ul>
+        * </p>
+        * 
+        * @see #getKind()
+        */
+       public static final int FIELD_REF = 2;
+
+       /**
+        * Completion is a keyword.
+        * This kind of completion might occur in a context like
+        * <code>"public cl^ Foo {}"</code> and complete it to
+        * <code>"public class Foo {}"</code>.
+        * <p>
+        * The following additional context information is available
+        * for this kind of completion proposal at little extra cost:
+        * <ul>
+        * <li>{@link #getName()} -
+        * the keyword token
+        * </li>
+        * <li>{@link #getFlags()} -
+        * the corresponding modifier flags if the keyword is a modifier
+        * </li>
+        * </ul>
+        * </p>
+        * 
+        * @see #getKind()
+        */
+       public static final int KEYWORD = 3;
+
+       /**
+        * Completion is a reference to a label.
+        * This kind of completion might occur in a context like
+        * <code>"break lo^;"</code> and complete it to
+        * <code>"break loop;"</code>.
+        * <p>
+        * The following additional context information is available
+        * for this kind of completion proposal at little extra cost:
+        * <ul>
+        * <li>{@link #getName()} -
+        * the simple name of the label that is referenced
+        * </li>
+        * </ul>
+        * </p>
+        * 
+        * @see #getKind()
+        */
+       public static final int LABEL_REF = 4;
+
+       /**
+        * Completion is a reference to a local variable.
+        * This kind of completion might occur in a context like
+        * <code>"ke^ = 4;"</code> and complete it to
+        * <code>"keys = 4;"</code>.
+        * <p>
+        * The following additional context information is available
+        * for this kind of completion proposal at little extra cost:
+        * <ul>
+        * <li>{@link #getFlags()} -
+        * the modifiers flags of the local variable that is referenced
+        * </li>
+        * <li>{@link #getName()} -
+        * the simple name of the local variable that is referenced
+        * </li>
+        * <li>{@link #getSignature()} -
+        * the type signature of the local variable's type
+        * </li>
+        * </ul>
+        * </p>
+        * 
+        * @see #getKind()
+        */
+       public static final int LOCAL_VARIABLE_REF = 5;
+
+       /**
+        * Completion is a reference to a method.
+        * This kind of completion might occur in a context like
+        * <code>"System.out.pr^();"</code> and complete it to
+        * <code>""System.out.println();"</code>.
+        * <p>
+        * The following additional context information is available
+        * for this kind of completion proposal at little extra cost:
+        * <ul>
+        * <li>{@link #getDeclarationSignature()} -
+        * the type signature of the type that declares the method that is referenced
+        * </li>
+        * <li>{@link #getFlags()} -
+        * the modifiers flags of the method that is referenced
+        * </li>
+        * <li>{@link #getName()} -
+        * the simple name of the method that is referenced
+        * </li>
+        * <li>{@link #getSignature()} -
+        * the method signature of the method that is referenced
+        * </li>
+        * </ul>
+        * </p>
+        * 
+        * @see #getKind()
+        */
+       public static final int METHOD_REF = 6;
+
+       /**
+        * Completion is a declaration of a method.
+        * This kind of completion might occur in a context like
+        * <code>"new List() {si^};"</code> and complete it to
+        * <code>"new List() {public int size() {} };"</code>.
+        * <p>
+        * The following additional context information is available
+        * for this kind of completion proposal at little extra cost:
+        * <ul>
+        * <li>{@link #getDeclarationSignature()} -
+        * the type signature of the type that declares the
+        * method that is being overridden or implemented
+        * </li>
+        * <li>{@link #getName()} -
+        * the simple name of the method that is being overridden
+        * or implemented
+        * </li>
+        * <li>{@link #getSignature()} -
+        * the method signature of the method that is being
+        * overridden or implemented
+        * </li>
+        * <li>{@link #getFlags()} -
+        * the modifiers flags of the method that is being
+        * overridden or implemented
+        * </li>
+        * </ul>
+        * </p>
+        * 
+        * @see #getKind()
+        */
+       public static final int METHOD_DECLARATION = 7;
+
+       /**
+        * Completion is a reference to a package.
+        * This kind of completion might occur in a context like
+        * <code>"import java.u^.*;"</code> and complete it to
+        * <code>"import java.util.*;"</code>.
+        * <p>
+        * The following additional context information is available
+        * for this kind of completion proposal at little extra cost:
+        * <ul>
+        * <li>{@link #getDeclarationSignature()} -
+        * the dot-based package signature of the package that is referenced
+        * </li>
+        * </ul>
+        * </p>
+        * 
+        * @see #getKind()
+        */
+       public static final int PACKAGE_REF = 8;
+
+       /**
+        * Completion is a reference to a type. Any kind of type
+        * is allowed, including primitive types, reference types,
+        * array types, parameterized types, and type variables.
+        * This kind of completion might occur in a context like
+        * <code>"public static Str^ key;"</code> and complete it to
+        * <code>"public static String key;"</code>.
+        * <p>
+        * The following additional context information is available
+        * for this kind of completion proposal at little extra cost:
+        * <ul>
+        * <li>{@link #getDeclarationSignature()} -
+        * the dot-based package signature of the package that contains
+        * the type that is referenced
+        * </li>
+        * <li>{@link #getSignature()} -
+        * the type signature of the type that is referenced
+        * </li>
+        * <li>{@link #getFlags()} -
+        * the modifiers flags (including Flags.AccInterface, AccEnum,
+        * and AccAnnotation) of the type that is referenced
+        * </li>
+        * </ul>
+        * </p>
+        * 
+        * @see #getKind()
+        */
+       public static final int TYPE_REF = 9;
+
+       /**
+        * Completion is a declaration of a variable (locals, parameters,
+        * fields, etc.).
+        * <p>
+        * The following additional context information is available
+        * for this kind of completion proposal at little extra cost:
+        * <ul>
+        * <li>{@link #getName()} -
+        * the simple name of the variable being declared
+        * </li>
+        * <li>{@link #getSignature()} -
+        * the type signature of the type of the variable
+        * being declared
+        * </li>
+        * <li>{@link #getFlags()} -
+        * the modifiers flags of the variable being declared
+        * </li>
+        * </ul>
+        * </p>
+        * @see #getKind()
+        */
+       public static final int VARIABLE_DECLARATION = 10;
+       
+       /**
+        * Kind of completion request.
+        */
+       private int completionKind;
+       
+       /**
+        * Offset in original buffer where ICodeAssist.codeComplete() was
+        * requested.
+        */
+       private int completionLocation;
+       
+       /**
+        * Start position (inclusive) of source range in original buffer 
+        * containing the relevant token
+        * defaults to empty subrange at [0,0).
+        */
+       private int tokenStart = 0;
+       
+       /**
+        * End position (exclusive) of source range in original buffer 
+        * containing the relevant token;
+        * defaults to empty subrange at [0,0).
+        */
+       private int tokenEnd = 0;
+       
+       /**
+        * Completion string; defaults to empty string.
+        */
+       private char[] completion = CharOperation.NO_CHAR;
+       
+       /**
+        * Start position (inclusive) of source range in original buffer 
+        * to be replaced by completion string; 
+        * defaults to empty subrange at [0,0).
+        */
+       private int replaceStart = 0;
+       
+       /**
+        * End position (exclusive) of source range in original buffer 
+        * to be replaced by completion string;
+        * defaults to empty subrange at [0,0).
+        */
+       private int replaceEnd = 0;
+       
+       /**
+        * Relevance rating; positive; higher means better;
+        * defaults to minimum rating.
+        */
+       private int relevance = 1;
+       
+       /**
+        * Signature of the relevant package or type declaration
+        * in the context, or <code>null</code> if none.
+        * Defaults to null.
+        */
+       private char[] declarationSignature = null;
+       
+       /**
+        * Simple name of the method, field,
+        * member, or variable relevant in the context, or
+        * <code>null</code> if none.
+        * Defaults to null.
+        */
+       private char[] name = null;
+       
+       /**
+        * Signature of the method, field type, member type,
+        * relevant in the context, or <code>null</code> if none.
+        * Defaults to null.
+        */
+       private char[] signature = null;
+       
+       /**
+        * Modifier flags relevant in the context, or
+        * <code>Flags.AccDefault</code> if none.
+        * Defaults to <code>Flags.AccDefault</code>.
+        */
+       private int flags = Flags.AccDefault;
+       
+       /**
+        * Parameter names (for method completions), or
+        * <code>null</code> if none. Lazily computed.
+        * Defaults to <code>null</code>.
+        */
+       private char[][] parameterNames = null;
+       
+       /**
+        * Indicates whether parameter names have been computed.
+        */
+       private boolean parameterNamesComputed = false;
+       
+       /**
+        * Creates a basic completion proposal. All instance
+        * field have plausible default values unless otherwise noted.
+        * <p>
+        * Note that the constructors for this class are internal to the
+        * Java model implementation. Clients cannot directly create
+        * CompletionProposal objects.
+        * </p>
+        * 
+        * @param kind one of the kind constants declared on this class
+        * @param completionOffset original offset of code completion request
+        * @return a new completion proposal
+        */
+       public static CompletionProposal create(int kind, int completionOffset) {
+               return new CompletionProposal(kind, completionOffset);
+       }
+       
+       /**
+        * Creates a basic completion proposal. All instance
+        * field have plausible default values unless otherwise noted.
+        * <p>
+        * Note that the constructors for this class are internal to the
+        * Java model implementation. Clients cannot directly create
+        * CompletionProposal objects.
+        * </p>
+        * 
+        * @param kind one of the kind constants declared on this class
+        * @param completionLocation original offset of code completion request
+        */
+       CompletionProposal(int kind, int completionLocation) {
+               if ((kind < CompletionProposal.ANONYMOUS_CLASS_DECLARATION)
+                               || (kind > CompletionProposal.VARIABLE_DECLARATION)) {
+                       throw new IllegalArgumentException();
+               }
+               if (this.completion == null || completionLocation < 0) {
+                       throw new IllegalArgumentException();
+               }
+               this.completionKind = kind;
+               this.completionLocation = completionLocation;
+       }
+       
+       /**
+        * Returns the kind of completion being proposed.
+        * <p>
+        * The set of different kinds of completion proposals is
+        * expected to change over time. It is strongly recommended
+        * that clients do <b>not</b> assume that the kind is one of the
+        * ones they know about, and code defensively for the
+        * possibility of unexpected future growth.
+        * </p>
+        * 
+        * @return the kind; one of the kind constants
+        * declared on this class, or possibly a kind unknown
+        * to the caller
+        */
+       public int getKind() {
+               return this.completionKind;
+       }
+       
+       /**
+        * Returns the character index in the source file buffer
+        * where source completion was requested (the 
+        * <code>offset</code>parameter to
+        * <code>ICodeAssist.codeComplete</code>.
+        * 
+        * @return character index in source file buffer
+        * @see ICodeAssist#codeComplete(int,CompletionRequestor)
+        */
+       public int getCompletionLocation() {
+               return this.completionLocation;
+       }
+       
+       /**
+        * Returns the character index of the start of the
+        * subrange in the source file buffer containing the
+        * relevant token being completed. This
+        * token is either the identifier or Java language keyword
+        * under, or immediately preceding, the original request 
+        * offset. If the original request offset is not within
+        * or immediately after an identifier or keyword, then the
+        * position returned is original request offset and the
+        * token range is empty.
+        * 
+        * @return character index of token start position (inclusive)
+        */
+       public int getTokenStart() {
+               return this.tokenStart;
+       }
+       
+       /**
+        * Returns the character index of the end (exclusive) of the subrange
+        * in the source file buffer containing the
+        * relevant token. When there is no relevant token, the
+        * range is empty
+        * (<code>getEndToken() == getStartToken()</code>).
+        * 
+        * @return character index of token end position (exclusive)
+        */
+       public int getTokenEnd() {
+               return this.tokenEnd;
+       }
+       
+       /**
+        * Sets the character indices of the subrange in the
+        * source file buffer containing the relevant token being
+        * completed. This token is either the identifier or
+        * Java language keyword under, or immediately preceding,
+        * the original request offset. If the original request
+        * offset is not within or immediately after an identifier
+        * or keyword, then the source range begins at original
+        * request offset and is empty.
+        * <p>
+        * If not set, defaults to empty subrange at [0,0).
+        * </p>
+        * 
+        * @param startIndex character index of token start position (inclusive)
+        * @param endIndex character index of token end position (exclusive)
+        */
+       public void setTokenRange(int startIndex, int endIndex) {
+               if (startIndex < 0 || endIndex < startIndex) {
+                       throw new IllegalArgumentException();
+               }
+               this.tokenStart = startIndex;
+               this.tokenEnd = endIndex;
+       }
+       
+       /**
+        * Returns the proposed sequence of characters to insert into the
+        * source file buffer, replacing the characters at the specified
+        * source range. The string can be arbitrary; for example, it might
+        * include not only the name of a method but a set of parentheses.
+        * <p>
+        * The client must not modify the array returned.
+        * </p>
+        * 
+        * @return the completion string
+        */
+       public char[] getCompletion() {
+               return this.completion;
+       }
+       
+       /**
+        * Sets the proposed sequence of characters to insert into the
+        * source file buffer, replacing the characters at the specified
+        * source range. The string can be arbitrary; for example, it might
+        * include not only the name of a method but a set of parentheses.
+        * <p>
+        * If not set, defaults to an empty character array.
+        * </p>
+        * <p>
+        * The completion engine creates instances of this class and sets
+        * its properties; this method is not intended to be used by other clients.
+        * </p>
+        * 
+        * @param completion the completion string
+        */
+       public void setCompletion(char[] completion) {
+               this.completion = completion;
+       }
+       
+       /**
+        * Returns the character index of the start of the
+        * subrange in the source file buffer to be replaced
+        * by the completion string. If the subrange is empty
+        * (<code>getReplaceEnd() == getReplaceStart()</code>),
+        * the completion string is to be inserted at this
+        * index.
+        * <p>
+        * Note that while the token subrange is precisely 
+        * specified, the replacement range is loosely
+        * constrained and may not bear any direct relation
+        * to the original request offset. For example, a
+        * it would be possible for a type completion to 
+        * propose inserting an import declaration at the
+        * top of the compilation unit; or the completion
+        * might include trailing parentheses and
+        * punctuation for a method completion.
+        * </p>
+        * 
+        * @return replacement start position (inclusive)
+        */
+       public int getReplaceStart() {
+               return this.replaceStart;
+       }
+       
+       /**
+        * Returns the character index of the end of the
+        * subrange in the source file buffer to be replaced
+        * by the completion string. If the subrange is empty
+        * (<code>getReplaceEnd() == getReplaceStart()</code>),
+        * the completion string is to be inserted at this
+        * index.
+        * 
+        * @return replacement end position (exclusive)
+        */
+       public int getReplaceEnd() {
+               return this.replaceEnd;
+       }
+       
+       /**
+        * Sets the character indices of the subrange in the
+        * source file buffer to be replaced by the completion
+        * string. If the subrange is empty
+        * (<code>startIndex == endIndex</code>),
+        * the completion string is to be inserted at this
+        * index.
+        * <p>
+        * If not set, defaults to empty subrange at [0,0).
+        * </p>
+        * <p>
+        * The completion engine creates instances of this class and sets
+        * its properties; this method is not intended to be used by other clients.
+        * </p>
+        * 
+        * @param startIndex character index of replacement start position (inclusive)
+        * @param endIndex character index of replacement end position (exclusive)
+        */
+       public void setReplaceRange(int startIndex, int endIndex) {
+               if (startIndex < 0 || endIndex < startIndex) {
+                       throw new IllegalArgumentException();
+               }
+               this.replaceStart = startIndex;
+               this.replaceEnd = endIndex;
+       }
+       
+       /**
+        * Returns the relative relevance rating of this proposal.
+        * 
+        * @return relevance rating of this proposal; ratings are positive; higher means better
+        */
+       public int getRelevance() {
+               return this.relevance;
+       }
+       
+       /**
+        * Sets the relative relevance rating of this proposal.
+        * <p>
+        * If not set, defaults to the lowest possible rating (1).
+        * </p>
+        * <p>
+        * The completion engine creates instances of this class and sets
+        * its properties; this method is not intended to be used by other clients.
+        * </p>
+        * 
+        * @param rating relevance rating of this proposal; ratings are positive; higher means better
+        */
+       public void setRelevance(int rating) {
+               if (rating <= 0) {
+                       throw new IllegalArgumentException();
+               }
+               this.relevance = rating;
+       }
+       
+       /**
+        * Returns the type or package signature of the relevant
+        * declaration in the context, or <code>null</code> if none.
+        * <p>
+        * This field is available for the following kinds of
+        * completion proposals:
+        * <ul>
+        * <li><code>ANONYMOUS_CLASS_DECLARATION</code> - type signature
+        * of the type that is being subclassed or implemented</li>
+        *      <li><code>FIELD_REF</code> - type signature
+        * of the type that declares the field that is referenced</li>
+        *      <li><code>METHOD_REF</code> - type signature
+        * of the type that declares the method that is referenced</li>
+        *      <li><code>METHOD_DECLARATION</code> - type signature
+        * of the type that declares the method that is being
+        * implemented or overridden</li>
+        *      <li><code>PACKAGE_REF</code> - dot-based package 
+        * signature of the package that is referenced</li>
+        *      <li><code>TYPE_REF</code> - dot-based package 
+        * signature of the package containing the type that is referenced</li>
+        * </ul>
+        * For kinds of completion proposals, this method returns
+        * <code>null</code>. Clients must not modify the array
+        * returned.
+        * </p>
+        * 
+        * @return the declaration signature, or
+        * <code>null</code> if none
+        * @see Signature
+        */
+       public char[] getDeclarationSignature() {
+               return this.declarationSignature;
+       }
+       
+       /**
+        * Sets the type or package signature of the relevant
+        * declaration in the context, or <code>null</code> if none.
+        * <p>
+        * If not set, defaults to none.
+        * </p>
+        * <p>
+        * The completion engine creates instances of this class and sets
+        * its properties; this method is not intended to be used by other clients.
+        * </p>
+        * 
+        * @param signature the type or package signature, or
+        * <code>null</code> if none
+        */
+       public void setDeclarationSignature(char[] signature) {
+               this.declarationSignature = signature;
+       }
+       
+       /**
+        * Returns the simple name of the method, field,
+        * member, or variable relevant in the context, or
+        * <code>null</code> if none.
+        * <p>
+        * This field is available for the following kinds of
+        * completion proposals:
+        * <ul>
+        *      <li><code>FIELD_REF</code> - the name of the field</li>
+        *      <li><code>KEYWORD</code> - the keyword</li>
+        *      <li><code>LABEL_REF</code> - the name of the label</li>
+        *      <li><code>LOCAL_VARIABLE_REF</code> - the name of the local variable</li>
+        *      <li><code>METHOD_REF</code> - the name of the method</li>
+        *      <li><code>METHOD_DECLARATION</code> - the name of the method</li>
+        *      <li><code>VARIABLE_DECLARATION</code> - the name of the variable</li>
+        * </ul>
+        * For kinds of completion proposals, this method returns
+        * <code>null</code>. Clients must not modify the array
+        * returned.
+        * </p>
+        * 
+        * @return the keyword, field, method, local variable, or member
+        * name, or <code>null</code> if none
+        */
+       public char[] getName() {
+               return this.name;
+       }
+       
+       
+       /**
+        * Sets the simple name of the method, field,
+        * member, or variable relevant in the context, or
+        * <code>null</code> if none.
+        * <p>
+        * If not set, defaults to none.
+        * </p>
+        * <p>
+        * The completion engine creates instances of this class and sets
+        * its properties; this method is not intended to be used by other clients.
+        * </p>
+        * 
+        * @param name the keyword, field, method, local variable,
+        * or member name, or <code>null</code> if none
+        */
+       public void setName(char[] name) {
+               this.name = name;
+       }
+       
+       /**
+        * Returns the signature of the method or type
+        * relevant in the context, or <code>null</code> if none.
+        * <p>
+        * This field is available for the following kinds of
+        * completion proposals:
+        * <ul>
+        * <li><code>ANONYMOUS_CLASS_DECLARATION</code> - method signature
+        * of the constructor that is being invoked</li>
+        *      <li><code>FIELD_REF</code> - the type signature
+        * of the referenced field's type</li>
+        *      <li><code>LOCAL_VARIABLE_REF</code> - the type signature
+        * of the referenced local variable's type</li>
+        *      <li><code>METHOD_REF</code> - method signature
+        * of the method that is referenced</li>
+        *      <li><code>METHOD_DECLARATION</code> - method signature
+        * of the method that is being implemented or overridden</li>
+        *      <li><code>TYPE_REF</code> - type signature
+        * of the type that is referenced</li>
+        *      <li><code>VARIABLE_DECLARATION</code> - the type signature
+        * of the type of the variable being declared</li>
+        * </ul>
+        * For kinds of completion proposals, this method returns
+        * <code>null</code>. Clients must not modify the array
+        * returned.
+        * </p>
+        * 
+        * @return the signature, or <code>null</code> if none
+        * @see Signature
+        */
+       public char[] getSignature() {
+               return this.signature;
+       }
+       
+       /**
+        * Sets the signature of the method, field type, member type,
+        * relevant in the context, or <code>null</code> if none.
+        * <p>
+        * If not set, defaults to none.
+        * </p>
+        * <p>
+        * The completion engine creates instances of this class and sets
+        * its properties; this method is not intended to be used by other clients.
+        * </p>
+        * 
+        * @param signature the signature, or <code>null</code> if none
+        */
+       public void setSignature(char[] signature) {
+               this.signature = signature;
+       }
+       
+       /**
+        * Returns the modifier flags relevant in the context, or
+        * <code>Flags.AccDefault</code> if none.
+        * <p>
+        * This field is available for the following kinds of
+        * completion proposals:
+        * <ul>
+        * <li><code>ANONYMOUS_CLASS_DECLARATION</code> - modifier flags
+        * of the constructor that is referenced</li>
+        *      <li><code>FIELD_REF</code> - modifier flags
+        * of the field that is referenced; 
+        * <code>Flags.AccEnum</code> can be used to recognize
+        * references to enum constants
+        * </li>
+        *      <li><code>KEYWORD</code> - modifier flag
+        * corrresponding to the modifier keyword</li>
+        *      <li><code>LOCAL_VARIABLE_REF</code> - modifier flags
+        * of the local variable that is referenced</li>
+        *      <li><code>METHOD_REF</code> - modifier flags
+        * of the method that is referenced;
+        * <code>Flags.AccAnnotation</code> can be used to recognize
+        * references to annotation type members
+        * </li>
+        *      <li><code>METHOD_DECLARATION</code> - modifier flags
+        * for the method that is being implemented or overridden</li>
+        *      <li><code>TYPE_REF</code> - modifier flags
+        * of the type that is referenced; <code>Flags.AccInterface</code>
+        * can be used to recognize references to interfaces, 
+        * <code>Flags.AccEnum</code> enum types,
+        * and <code>Flags.AccAnnotation</code> annotation types
+        * </li>
+        *      <li><code>VARIABLE_DECLARATION</code> - modifier flags
+        * for the variable being declared</li>
+        * </ul>
+        * For kinds of completion proposals, this method returns
+        * <code>Flags.AccDefault</code>.
+        * </p>
+        * 
+        * @return the modifier flags, or
+        * <code>Flags.AccDefault</code> if none
+        * @see Flags
+        */
+       public int getFlags() {
+               return this.flags;
+       }
+       
+       /**
+        * Sets the modifier flags relevant in the context.
+        * <p>
+        * If not set, defaults to none.
+        * </p>
+        * <p>
+        * The completion engine creates instances of this class and sets
+        * its properties; this method is not intended to be used by other clients.
+        * </p>
+        * 
+        * @param flags the modifier flags, or
+        * <code>Flags.AccDefault</code> if none
+        */
+       public void setFlags(int flags) {
+               this.flags = flags;
+       }
+       
+       /**
+        * Finds the method parameter names.
+        * This information is relevant to method reference (and
+        * method declaration proposals). Returns <code>null</code>
+        * if not available or not relevant.
+        * <p>
+        * The client must not modify the array returned.
+        * </p>
+        * <p>
+        * <b>Note that this is an expensive thing to compute, which may require
+        * parsing Java source files, etc. Use sparingly.
+        * </p>
+        * 
+        * @param monitor the progress monitor, or <code>null</code> if none
+        * @return the parameter names, or <code>null</code> if none
+        * or not available or not relevant
+        */
+       public char[][] findParameterNames(IProgressMonitor monitor) {
+               if (!this.parameterNamesComputed) {
+                       this.parameterNamesComputed = true;
+                       // TODO (jerome) - Missing implementation
+               }
+               return this.parameterNames;
+       }
+       
+       /**
+        * Sets the method parameter names.
+        * This information is relevant to method reference (and
+        * method declaration proposals).
+        * <p>
+        * The completion engine creates instances of this class and sets
+        * its properties; this method is not intended to be used by other clients.
+        * </p>
+        * 
+        * @param parameterNames the parameter names, or <code>null</code> if none
+        */
+       public void setParameterNames(char[][] parameterNames) {
+               this.parameterNames = parameterNames;
+               this.parameterNamesComputed = true;
+       }
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/CompletionRequestor.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/CompletionRequestor.java
new file mode 100644 (file)
index 0000000..2195c82
--- /dev/null
@@ -0,0 +1,165 @@
+/*******************************************************************************
+ * Copyright (c) 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.core;
+
+import net.sourceforge.phpdt.core.compiler.IProblem;
+
+/**
+ * Abstract base class for a completion requestor which is passed completion
+ * proposals as they are generated in response to a code assist request.
+ * <p>
+ * This class is intended to be subclassed by clients.
+ * </p>
+ * <p>
+ * The code assist engine normally invokes methods on completion
+ * requestors in the following sequence:
+ * <pre>
+ * requestor.beginReporting();
+ * requestor.accept(proposal_1);
+ * requestor.accept(proposal_2);
+ * ...
+ * requestor.endReporting();
+ * </pre>
+ * If, however, the engine is unable to offer completion proposals
+ * for whatever reason, <code>completionFailure</code> is called
+ * with a problem object describing why completions were unavailable.
+ * In this case, the sequence of calls is:
+ * <pre>
+ * requestor.beginReporting();
+ * requestor.completionFailure(problem);
+ * requestor.endReporting();
+ * </pre>
+ * In either case, the bracketing <code>beginReporting</code>
+ * <code>endReporting</code> calls are always made.
+ * </p>
+ * <p>
+ * The class was introduced in 3.0 as a more evolvable replacement
+ * for the <code>ICompletionRequestor</code> interface.
+ * </p>
+ * 
+ * @see ICodeAssist
+ * @since 3.0
+ */
+public abstract class CompletionRequestor {
+
+       /**
+        * The set of CompletionProposal kinds that this requestor
+        * ignores; <code>0</code> means the set is empty.
+        * 1 << completionProposalKind
+        */
+       private int ignoreSet = 0;
+
+       /**
+        * Creates a new completion requestor.
+        * The requestor is interested in all kinds of completion
+        * proposals; none will be ignored.
+        */
+       public CompletionRequestor() {
+               // do nothing
+       }
+
+       /**
+        * Returns whether the given kind of completion proposal is ignored.
+        * 
+        * @param completionProposalKind one of the kind constants declared
+        * on <code>CompletionProposal</code>
+        * @return <code>true</code> if the given kind of completion proposal
+        * is ignored by this requestor, and <code>false</code> if it is of
+        * interest
+        * @see #setIgnored(int, boolean)
+        * @see CompletionProposal#getKind()
+        */
+       public final boolean isIgnored(int completionProposalKind) {
+               if (completionProposalKind < CompletionProposal.ANONYMOUS_CLASS_DECLARATION
+                       || completionProposalKind > CompletionProposal.VARIABLE_DECLARATION) {
+                               throw new IllegalArgumentException();
+               }
+               return 0 != (this.ignoreSet & (1 << completionProposalKind));
+       }
+       
+       /**
+        * Sets whether the given kind of completion proposal is ignored.
+        * 
+        * @param completionProposalKind one of the kind constants declared
+        * on <code>CompletionProposal</code>
+        * @param ignore <code>true</code> if the given kind of completion proposal
+        * is ignored by this requestor, and <code>false</code> if it is of
+        * interest
+        * @see #isIgnored(int)
+        * @see CompletionProposal#getKind()
+        */
+       public final void setIgnored(int completionProposalKind, boolean ignore) {
+               if (completionProposalKind < CompletionProposal.ANONYMOUS_CLASS_DECLARATION
+                       || completionProposalKind > CompletionProposal.VARIABLE_DECLARATION) {
+                               throw new IllegalArgumentException();
+               }
+               if (ignore) {
+                       this.ignoreSet |= (1 << completionProposalKind);
+               } else {
+                       this.ignoreSet &= ~(1 << completionProposalKind);
+               }
+       }
+       
+       /**
+        * Pro forma notification sent before reporting a batch of
+        * completion proposals.
+        * <p>
+        * The default implementation of this method does nothing.
+        * Clients may override.
+        * </p>
+        */
+       public void beginReporting() {
+               // do nothing
+       }
+
+       /**
+        * Pro forma notification sent after reporting a batch of
+        * completion proposals.
+        * <p>
+        * The default implementation of this method does nothing.
+        * Clients may override.
+        * </p>
+        */
+       public void endReporting() {
+               // do nothing
+       }
+
+       /**
+        * Notification of failure to produce any completions.
+        * The problem object explains what prevented completing.
+        * <p>
+        * The default implementation of this method does nothing.
+        * Clients may override to receive this kind of notice.
+        * </p>
+        * 
+        * @param problem the problem object
+        */
+       public void completionFailure(IProblem problem) {
+               // default behavior is to ignore
+       }
+
+       /**
+        * Proposes a completion. Has no effect if the kind of proposal
+        * is being ignored by this requestor. Callers should consider
+        * checking {@link #isIgnored(int)} before avoid creating proposal
+        * objects that would only be ignored.
+        * <p>
+        * Similarly, implementers should check 
+        * {@link #isIgnored(int) isIgnored(proposal.getKind())} 
+        * and ignore proposals that have been declared as uninteresting.
+        * The proposal object passed in only valid for the duration of
+        * this call; implementors must not hang on to these objects.
+        * 
+        * @param proposal the completion proposal
+        * @exception IllegalArgumentException if the proposal is null
+        */
+       public abstract void accept(CompletionProposal proposal);
+}
index fefe486..a9ccaae 100644 (file)
@@ -30,7 +30,11 @@ import net.sourceforge.phpdt.internal.compiler.env.IConstants;
  * @see IMember#getFlags
  */
 public final class Flags {
-
+  /**
+        * Constant representing the absence of any flag
+        * @since 3.0
+        */
+       public static final int AccDefault = 0;
        /**
         * Public access flag. See The Java Virtual Machine Specification for more details.
         * @since 2.0
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ICodeAssist.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ICodeAssist.java
new file mode 100644 (file)
index 0000000..a0d7654
--- /dev/null
@@ -0,0 +1,198 @@
+/*******************************************************************************
+ * 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.core;
+
+/**
+ * Common protocol for Java elements that support source code assist and code
+ * resolve.
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ */
+public interface ICodeAssist {
+
+       /**
+        * Performs code completion at the given offset position in this compilation unit,
+        * reporting results to the given completion requestor. The <code>offset</code>
+        * is the 0-based index of the character, after which code assist is desired.
+        * An <code>offset</code> of -1 indicates to code assist at the beginning of this
+        * compilation unit.
+        * 
+        * @param offset the given offset position
+        * @param requestor the given completion requestor
+        *
+        * @exception JavaModelException if code assist could not be performed. Reasons include:<ul>
+        *  <li>This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+        *  <li> The position specified is < -1 or is greater than this compilation unit's
+        *      source length (INDEX_OUT_OF_BOUNDS)
+        * </ul>
+        *
+        * @exception IllegalArgumentException if <code>requestor</code> is <code>null</code>
+        * @deprecated Use {@link #codeComplete(int, ICompletionRequestor)} instead.
+        */
+       void codeComplete(int offset, ICodeCompletionRequestor requestor)
+               throws JavaModelException;
+       /**
+        * Performs code completion at the given offset position in this compilation unit,
+        * reporting results to the given completion requestor. The <code>offset</code>
+        * is the 0-based index of the character, after which code assist is desired.
+        * An <code>offset</code> of -1 indicates to code assist at the beginning of this
+        * compilation unit.
+        *
+        * @param offset the given offset position
+        * @param requestor the given completion requestor
+        * @exception JavaModelException if code assist could not be performed. Reasons include:<ul>
+        *  <li>This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+        *  <li> The position specified is < -1 or is greater than this compilation unit's
+        *      source length (INDEX_OUT_OF_BOUNDS)
+        * </ul>
+        *
+        * @exception IllegalArgumentException if <code>requestor</code> is <code>null</code>
+        * @since 2.0
+        */
+       // TODO (jerome - once CompletionRequestor is working) @ deprecated Use {@link #codeComplete(int, CompletionRequestor)} instead.
+       void codeComplete(int offset, ICompletionRequestor requestor)
+               throws JavaModelException;
+       
+       /**
+        * <b>DO NOT USE</b>: This API element was added in anticipation of J2SE
+        * 1.5 support, which is planned for the next release of Eclipse after 3.0.
+        * It is currently unimplemented, and the API may change slightly before
+        * reaching its final form.
+        * <p>
+        * Performs code completion at the given offset position in this compilation unit,
+        * reporting results to the given completion requestor. The <code>offset</code>
+        * is the 0-based index of the character, after which code assist is desired.
+        * An <code>offset</code> of -1 indicates to code assist at the beginning of this
+        * compilation unit.
+        * <p>
+        *
+        * @param offset the given offset position
+        * @param requestor the given completion requestor
+        * @exception JavaModelException if code assist could not be performed. Reasons include:<ul>
+        *  <li>This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+        *  <li> The position specified is < -1 or is greater than this compilation unit's
+        *      source length (INDEX_OUT_OF_BOUNDS)
+        * </ul>
+        *
+        * @exception IllegalArgumentException if <code>requestor</code> is <code>null</code>
+        * @since 3.0
+        */
+       void codeComplete(int offset, CompletionRequestor requestor)
+               throws JavaModelException;
+       
+       /**
+        * Performs code completion at the given offset position in this compilation unit,
+        * reporting results to the given completion requestor. The <code>offset</code>
+        * is the 0-based index of the character, after which code assist is desired.
+        * An <code>offset</code> of -1 indicates to code assist at the beginning of this
+        * compilation unit.
+        * It considers types in the working copies with the given owner first. In other words, 
+        * the owner's working copies will take precedence over their original compilation units
+        * in the workspace.
+        * <p>
+        * Note that if a working copy is empty, it will be as if the original compilation
+        * unit had been deleted.
+        * </p>
+        *
+        * @param offset the given offset position
+        * @param requestor the given completion requestor
+        * @param owner the owner of working copies that take precedence over their original compilation units
+        * @exception JavaModelException if code assist could not be performed. Reasons include:<ul>
+        *  <li>This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+        *  <li> The position specified is < -1 or is greater than this compilation unit's
+        *      source length (INDEX_OUT_OF_BOUNDS)
+        * </ul>
+        *
+        * @exception IllegalArgumentException if <code>requestor</code> is <code>null</code>
+        * @since 3.0
+        */
+    // TODO (jerome - once CompletionRequestor is working) @ deprecated Use {@link #codeComplete(int, CompletionRequestor, WorkingCopyOwner)} instead.
+       void codeComplete(int offset, ICompletionRequestor requestor, WorkingCopyOwner owner)
+               throws JavaModelException;
+
+       /**
+        * <b>DO NOT USE</b>: This API element was added in anticipation of J2SE
+        * 1.5 support, which is planned for the next release of Eclipse after 3.0.
+        * It is currently unimplemented, and the API may change slightly before
+        * reaching its final form.
+        * <p>
+        * Performs code completion at the given offset position in this compilation unit,
+        * reporting results to the given completion requestor. The <code>offset</code>
+        * is the 0-based index of the character, after which code assist is desired.
+        * An <code>offset</code> of -1 indicates to code assist at the beginning of this
+        * compilation unit.
+        * It considers types in the working copies with the given owner first. In other words, 
+        * the owner's working copies will take precedence over their original compilation units
+        * in the workspace.
+        * <p>
+        * Note that if a working copy is empty, it will be as if the original compilation
+        * unit had been deleted.
+        * </p>
+        *
+        * @param offset the given offset position
+        * @param requestor the given completion requestor
+        * @param owner the owner of working copies that take precedence over their original compilation units
+        * @exception JavaModelException if code assist could not be performed. Reasons include:<ul>
+        *  <li>This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+        *  <li> The position specified is < -1 or is greater than this compilation unit's
+        *      source length (INDEX_OUT_OF_BOUNDS)
+        * </ul>
+        *
+        * @exception IllegalArgumentException if <code>requestor</code> is <code>null</code>
+        * @since 3.0
+        */
+       void codeComplete(int offset, CompletionRequestor requestor, WorkingCopyOwner owner)
+               throws JavaModelException;
+
+       /**
+        * Returns the Java elements correspondiing to the given selected text in this compilation unit. 
+        * The <code>offset</code> is the 0-based index of the first selected character. 
+        * The <code>length</code> is the number of selected characters.
+        * 
+        * @param offset the given offset position
+        * @param length the number of selected characters
+        * @return the Java elements correspondiing to the given selected text
+        *
+        * @exception JavaModelException if code resolve could not be performed. Reasons include:
+        *  <li>This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+        *  <li> The range specified is not within this element's
+        *      source range (INDEX_OUT_OF_BOUNDS)
+        * </ul>
+        *
+        */
+       IJavaElement[] codeSelect(int offset, int length) throws JavaModelException;
+       /**
+        * Returns the Java elements correspondiing to the given selected text in this compilation unit. 
+        * The <code>offset</code> is the 0-based index of the first selected character. 
+        * The <code>length</code> is the number of selected characters.
+        * It considers types in the working copies with the given owner first. In other words, 
+        * the owner's working copies will take precedence over their original compilation units
+        * in the workspace.
+        * <p>
+        * Note that if a working copy is empty, it will be as if the original compilation
+        * unit had been deleted.
+        * </p>
+        * 
+        * @param offset the given offset position
+        * @param length the number of selected characters
+        * @param owner the owner of working copies that take precedence over their original compilation units
+        * @return the Java elements correspondiing to the given selected text
+        *
+        * @exception JavaModelException if code resolve could not be performed. Reasons include:
+        *  <li>This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+        *  <li> The range specified is not within this element's
+        *      source range (INDEX_OUT_OF_BOUNDS)
+        * </ul>
+        * @since 3.0
+        */
+       IJavaElement[] codeSelect(int offset, int length, WorkingCopyOwner owner) throws JavaModelException;
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ICodeCompletionRequestor.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ICodeCompletionRequestor.java
new file mode 100644 (file)
index 0000000..26a923f
--- /dev/null
@@ -0,0 +1,263 @@
+/*******************************************************************************
+ * 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.core;
+
+import org.eclipse.core.resources.IMarker;
+
+/**
+ * A completion requestor accepts results as they are computed and is aware
+ * of source positions to complete the various different results.
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ *
+ * @see ICodeAssist
+ * @deprecated Use {@link CompletionRequestor} instead.
+ */
+public interface ICodeCompletionRequestor {
+/**
+ * Code assist notification of a class completion.
+ * 
+ * @param packageName Declaring package name of the class.
+ * @param className Name of the class.
+ * @param completionName The completion for the class.
+ *   Can include ';' for imported classes.
+ * @param modifiers The modifiers of the class.
+ * @param completionStart The start position of insertion of the name of the class.
+ * @param completionEnd The end position of insertion of the name of the class.
+ *
+ * NOTE - All package and type names are presented in their readable form:
+ *    Package names are in the form "a.b.c".
+ *    Nested type names are in the qualified form "A.M".
+ *    The default package is represented by an empty array.
+ */
+void acceptClass(
+       char[] packageName,
+       char[] className,
+       char[] completionName,
+       int modifiers,
+       int completionStart,
+       int completionEnd);
+/**
+ * Code assist notification of a compilation error detected during completion.
+ *  @param marker Only problems which are categorized as errors are notified to the requestor,
+ *             warnings are silently ignored.
+ *             In case an error got signaled, no other completions might be available,
+ *             therefore the problem message should be presented to the user.
+ *             The source positions of the problem are related to the source where it was
+ *             detected (might be in another compilation unit, if it was indirectly requested
+ *             during the code assist process).
+ *      Note: the problem knows its originating file name.
+ */
+void acceptError(IMarker marker);
+/**
+ * Code assist notification of a field completion.
+ *
+ * @param declaringTypePackageName Name of the package in which the type that contains this field is declared.
+ * 
+ * @param declaringTypeName Name of the type declaring this new field.
+ * 
+ * @param name Name of the field.
+ * 
+ * @param typePackageName Name of the package in which the type of this field is declared.
+ * 
+ * @param typeName Name of the type of this field.
+ * 
+ * @param completionName The completion for the field.
+ * 
+ * @param modifiers The modifiers of this field.
+ * 
+ * @param completionStart The start position of insertion of the name of this field.
+ * 
+ * @param completionEnd The end position of insertion of the name of this field.
+ *
+ * NOTE - All package and type names are presented in their readable form:
+ *    Package names are in the form "a.b.c".
+ *    Base types are in the form "int" or "boolean".
+ *    Array types are in the qualified form "M[]" or "int[]".
+ *    Nested type names are in the qualified form "A.M".
+ *    The default package is represented by an empty array.
+ */
+void acceptField(
+       char[] declaringTypePackageName,
+       char[] declaringTypeName,
+       char[] name,
+       char[] typePackageName,
+       char[] typeName,
+       char[] completionName,
+       int modifiers,
+       int completionStart,
+       int completionEnd);
+/**
+ * Code assist notification of an interface completion.
+ *
+ * @param packageName Declaring package name of the interface.
+ * @param interfaceName Name of the interface.
+ * @param completionName The completion for the interface.
+ *   Can include ';' for imported interfaces.
+ * @param modifiers The modifiers of the interface.
+ * @param completionStart The start position of insertion of the name of the interface.
+ * @param completionEnd The end position of insertion of the name of the interface.
+ *
+ * NOTE - All package and type names are presented in their readable form:
+ *    Package names are in the form "a.b.c".
+ *    Nested type names are in the qualified form "A.M".
+ *    The default package is represented by an empty array.
+ */
+void acceptInterface(
+       char[] packageName,
+       char[] interfaceName,
+       char[] completionName,
+       int modifiers,
+       int completionStart,
+       int completionEnd);
+/**
+ * Code assist notification of a keyword completion.
+ *
+ * @param keywordName The keyword source.
+ * @param completionStart The start position of insertion of the name of this keyword.
+ * @param completionEnd The end position of insertion of the name of this keyword.
+ */
+void acceptKeyword(char[] keywordName, int completionStart, int completionEnd);
+/**
+ * Code assist notification of a label completion.
+ *
+ * @param labelName The label source.
+ * @param completionStart The start position of insertion of the name of this label.
+ * @param completionEnd The end position of insertion of the name of this label.
+ */
+void acceptLabel(char[] labelName, int completionStart, int completionEnd);
+/**
+ * Code assist notification of a local variable completion.
+ *
+ * @param name Name of the new local variable.
+ * 
+ * @param typePackageName Name of the package in which the type of this new local variable is declared.
+ * 
+ * @param typeName Name of the type of this new local variable.
+ * 
+ * @param modifiers The modifiers of this new local variable.
+ * 
+ * @param completionStart The start position of insertion of the name of this new local variable.
+ * 
+ * @param completionEnd The end position of insertion of the name of this new local variable.
+ *
+ * NOTE - All package and type names are presented in their readable form:
+ *    Package names are in the form "a.b.c".
+ *    Base types are in the form "int" or "boolean".
+ *    Array types are in the qualified form "M[]" or "int[]".
+ *    Nested type names are in the qualified form "A.M".
+ *    The default package is represented by an empty array.
+ */
+void acceptLocalVariable(
+       char[] name,
+       char[] typePackageName,
+       char[] typeName,
+       int modifiers,
+       int completionStart,
+       int completionEnd);
+/**
+ * Code assist notification of a method completion.
+ *
+ * @param declaringTypePackageName Name of the package in which the type that contains this new method is declared.
+ * 
+ * @param declaringTypeName Name of the type declaring this new method.
+ * 
+ * @param selector Name of the new method.
+ * 
+ * @param parameterPackageNames Names of the packages in which the parameter types are declared.
+ *     Should contain as many elements as parameterTypeNames.
+ * 
+ * @param parameterTypeNames Names of the parameters types.
+ *     Should contain as many elements as parameterPackageNames.
+ * 
+ * @param returnTypePackageName Name of the package in which the return type is declared.
+ * 
+ * @param returnTypeName Name of the return type of this new method, should be <code>null</code> for a constructor.
+ * 
+ * @param completionName The completion for the method.
+ *     Can include zero, one or two brackets. If the closing bracket is included, then the cursor should be placed before it.
+ * 
+ * @param modifiers The modifiers of this new method.
+ * 
+ * @param completionStart The start position of insertion of the name of this new method.
+ * 
+ * @param completionEnd The end position of insertion of the name of this new method.
+ *
+ * NOTE - All package and type names are presented in their readable form:
+ *    Package names are in the form "a.b.c".
+ *    Base types are in the form "int" or "boolean".
+ *    Array types are in the qualified form "M[]" or "int[]".
+ *    Nested type names are in the qualified form "A.M".
+ *    The default package is represented by an empty array.
+ *
+ * NOTE: parameter names can be retrieved from the source model after the user selects a specific method.
+ */
+void acceptMethod(
+       char[] declaringTypePackageName,
+       char[] declaringTypeName,
+       char[] selector,
+       char[][] parameterPackageNames,
+       char[][] parameterTypeNames,
+       char[] returnTypePackageName,
+       char[] returnTypeName,
+       char[] completionName,
+       int modifiers,
+       int completionStart,
+       int completionEnd);
+/**
+ * Code assist notification of a modifier completion.
+ *
+ * @param modifierName The new modifier.
+ * @param completionStart The start position of insertion of the name of this new modifier.
+ * @param completionEnd The end position of insertion of the name of this new modifier.
+ */
+void acceptModifier(char[] modifierName, int completionStart, int completionEnd);
+/**
+ * Code assist notification of a package completion.
+ *
+ * @param packageName The package name.
+ * @param completionName The completion for the package.
+ *   Can include '.*;' for imports.
+ * @param completionStart The start position of insertion of the name of this new package.
+ * @param completionEnd The end position of insertion of the name of this new package.
+ *
+ * NOTE - All package names are presented in their readable form:
+ *    Package names are in the form "a.b.c".
+ *    The default package is represented by an empty array.
+ */
+void acceptPackage(
+       char[] packageName,
+       char[] completionName,
+       int completionStart,
+       int completionEnd);
+/**
+ * Code assist notification of a type completion.
+ * 
+ * @param packageName Declaring package name of the type.
+ * @param typeName Name of the type.
+ * @param completionName The completion for the type.
+ *   Can include ';' for imported types.
+ * @param completionStart The start position of insertion of the name of the type.
+ * @param completionEnd The end position of insertion of the name of the type.
+ *
+ * NOTE - All package and type names are presented in their readable form:
+ *    Package names are in the form "a.b.c".
+ *    Nested type names are in the qualified form "A.M".
+ *    The default package is represented by an empty array.
+ */
+void acceptType(
+       char[] packageName,
+       char[] typeName,
+       char[] completionName,
+       int completionStart,
+       int completionEnd);
+}
index abb27ea..cc9ce7a 100644 (file)
@@ -167,7 +167,9 @@ public class Parser //extends PHPParserSuperclass
   public void initializeScanner() {
     this.scanner = new Scanner(false /* comment */, false /* whitespace */, this.options
         .getSeverity(CompilerOptions.NonExternalizedString) != ProblemSeverities.Ignore /* nls */, false, false,
-        this.options.taskTags/* taskTags */, this.options.taskPriorites/* taskPriorities */);
+        this.options.taskTags/* taskTags */, 
+        this.options.taskPriorites/* taskPriorities */,
+        true/*isTaskCaseSensitive*/);
   }
 
   /**
@@ -208,6 +210,12 @@ public class Parser //extends PHPParserSuperclass
     throw new SyntaxError(1, 0, " ", error);
   }
 
+  private void reportSyntaxError(String error) {
+    int problemStartPosition = scanner.getCurrentTokenStartPosition();
+    int problemEndPosition = scanner.getCurrentTokenEndPosition();
+    reportSyntaxError(error, problemStartPosition, problemEndPosition + 1);
+  }
+  
   private void reportSyntaxError(String error, int problemStartPosition, int problemEndPosition) {
     problemReporter.phpParsingError(new String[] { error }, problemStartPosition, problemEndPosition, referenceContext,
         compilationUnit.compilationResult);
@@ -1682,7 +1690,7 @@ public class Parser //extends PHPParserSuperclass
         }
       } else { // TokenNamedefault
         getNextToken();
-        if (token == TokenNameCOLON) {
+        if (token == TokenNameCOLON || token == TokenNameSEMICOLON) {
           getNextToken();
           if (token == TokenNameRBRACE) {
             // empty default case
index 655dcef..a1127f5 100644 (file)
@@ -192,21 +192,25 @@ public class Scanner implements IScanner, ITerminalSymbols {
   public char[][] taskTags = null;
 
   public char[][] taskPriorities = null;
-
+  public boolean isTaskCaseSensitive = true;
   public static final boolean DEBUG = false;
 
   public static final boolean TRACE = false;
 
   public ICompilationUnit compilationUnit = null;
   /**
-   * Determines if the specified character is permissible as the first character in a PHP identifier
+   * Determines if the specified character is permissible 
+   * as the first character in a PHP identifier.
+   * 
+   * The '$' character for HP variables isn't regarded as the first character !
    */
   public static boolean isPHPIdentifierStart(char ch) {
     return Character.isLetter(ch) || (ch == '_') || (0x7F <= ch && ch <= 0xFF);
   }
 
   /**
-   * Determines if the specified character may be part of a PHP identifier as other than the first character
+   * Determines if the specified character may be part of a PHP 
+   * identifier as other than the first character
    */
   public static boolean isPHPIdentifierPart(char ch) {
     return Character.isLetterOrDigit(ch) || (ch == '_') || (0x7F <= ch && ch <= 0xFF);
@@ -1751,6 +1755,10 @@ public class Scanner implements IScanner, ITerminalSymbols {
                     return TokenNameCOMMENT_PHPDOC;
                   return TokenNameCOMMENT_BLOCK;
                 }
+                
+                if (this.taskTags != null) {
+                  checkTaskTag(this.startPosition, this.currentPosition);
+                }
               } catch (IndexOutOfBoundsException e) {
                 //                  reset end position for error reporting
                 currentPosition -= 2;
@@ -3984,11 +3992,15 @@ public class Scanner implements IScanner, ITerminalSymbols {
 
   public Scanner(boolean tokenizeComments, boolean tokenizeWhiteSpace, boolean checkNonExternalizedStringLiterals,
       boolean assertMode) {
-    this(tokenizeComments, tokenizeWhiteSpace, checkNonExternalizedStringLiterals, assertMode, false, null, null);
+    this(tokenizeComments, tokenizeWhiteSpace, checkNonExternalizedStringLiterals, assertMode, false, null, null,true);
   }
 
-  public Scanner(boolean tokenizeComments, boolean tokenizeWhiteSpace, boolean checkNonExternalizedStringLiterals,
-      boolean assertMode, boolean tokenizeStrings, char[][] taskTags, char[][] taskPriorities) {
+  public Scanner(boolean tokenizeComments, boolean tokenizeWhiteSpace, 
+      boolean checkNonExternalizedStringLiterals,
+      boolean assertMode, boolean tokenizeStrings, 
+      char[][] taskTags, 
+      char[][] taskPriorities,
+      boolean isTaskCaseSensitive) {
     this.eofPosition = Integer.MAX_VALUE;
     this.tokenizeComments = tokenizeComments;
     this.tokenizeWhiteSpace = tokenizeWhiteSpace;
@@ -4132,86 +4144,203 @@ public class Scanner implements IScanner, ITerminalSymbols {
     }
   }
 
+//chech presence of task: tags
+//TODO (frederic) see if we need to take unicode characters into account...
+public void checkTaskTag(int commentStart, int commentEnd) {
+       char[] src = this.source;
+       
+       // only look for newer task: tags
+       if (this.foundTaskCount > 0
+               && this.foundTaskPositions[this.foundTaskCount - 1][0] >= commentStart) {
+               return;
+       }
+       int foundTaskIndex = this.foundTaskCount;
+       char previous = src[commentStart+1]; // should be '*' or '/'
+       nextChar : for (
+               int i = commentStart + 2; i < commentEnd && i < this.eofPosition; i++) {
+               char[] tag = null;
+               char[] priority = null;
+               // check for tag occurrence only if not ambiguous with javadoc tag
+               if (previous != '@') {
+                       nextTag : for (int itag = 0; itag < this.taskTags.length; itag++) {
+                               tag = this.taskTags[itag];
+                               int tagLength = tag.length;
+                               if (tagLength == 0) continue nextTag;
+       
+                               // ensure tag is not leaded with letter if tag starts with a letter
+                               if (Character.isJavaIdentifierStart(tag[0])) {
+                                       if (Character.isJavaIdentifierPart(previous)) {
+                                               continue nextTag;
+                                       }
+                               }
+       
+                               for (int t = 0; t < tagLength; t++) {
+                                       char sc, tc;
+                                       int x = i+t;
+                                       if (x >= this.eofPosition || x >= commentEnd) continue nextTag;
+                                       if ((sc = src[i + t]) != (tc = tag[t])) {                                                                                                                                                                       // case sensitive check
+                                               if (this.isTaskCaseSensitive || (Character.toLowerCase(sc) != Character.toLowerCase(tc))) {     // case insensitive check
+                                                       continue nextTag;
+                                               }
+                                       }
+                               }
+                               // ensure tag is not followed with letter if tag finishes with a letter
+                               if (i+tagLength < commentEnd && Character.isJavaIdentifierPart(src[i+tagLength-1])) {
+                                       if (Character.isJavaIdentifierPart(src[i + tagLength]))
+                                               continue nextTag;
+                               }
+                               if (this.foundTaskTags == null) {
+                                       this.foundTaskTags = new char[5][];
+                                       this.foundTaskMessages = new char[5][];
+                                       this.foundTaskPriorities = new char[5][];
+                                       this.foundTaskPositions = new int[5][];
+                               } else if (this.foundTaskCount == this.foundTaskTags.length) {
+                                       System.arraycopy(this.foundTaskTags, 0, this.foundTaskTags = new char[this.foundTaskCount * 2][], 0, this.foundTaskCount);
+                                       System.arraycopy(this.foundTaskMessages, 0, this.foundTaskMessages = new char[this.foundTaskCount * 2][], 0, this.foundTaskCount);
+                                       System.arraycopy(this.foundTaskPriorities, 0, this.foundTaskPriorities = new char[this.foundTaskCount * 2][], 0, this.foundTaskCount);
+                                       System.arraycopy(this.foundTaskPositions, 0, this.foundTaskPositions = new int[this.foundTaskCount * 2][], 0, this.foundTaskCount);
+                               }
+                               
+                               priority = this.taskPriorities != null && itag < this.taskPriorities.length
+                                                       ? this.taskPriorities[itag]
+                                                       : null;
+                               
+                               this.foundTaskTags[this.foundTaskCount] = tag;
+                               this.foundTaskPriorities[this.foundTaskCount] = priority;
+                               this.foundTaskPositions[this.foundTaskCount] = new int[] { i, i + tagLength - 1 };
+                               this.foundTaskMessages[this.foundTaskCount] = CharOperation.NO_CHAR;
+                               this.foundTaskCount++;
+                               i += tagLength - 1; // will be incremented when looping
+                               break nextTag;
+                       }
+               }
+               previous = src[i];
+       }
+       for (int i = foundTaskIndex; i < this.foundTaskCount; i++) {
+               // retrieve message start and end positions
+               int msgStart = this.foundTaskPositions[i][0] + this.foundTaskTags[i].length;
+               int max_value = i + 1 < this.foundTaskCount
+                               ? this.foundTaskPositions[i + 1][0] - 1
+                               : commentEnd - 1;
+               // at most beginning of next task
+               if (max_value < msgStart) {
+                       max_value = msgStart; // would only occur if tag is before EOF.
+               }
+               int end = -1;
+               char c;
+               for (int j = msgStart; j < max_value; j++) {
+                       if ((c = src[j]) == '\n' || c == '\r') {
+                               end = j - 1;
+                               break;
+                       }
+               }
+               if (end == -1) {
+                       for (int j = max_value; j > msgStart; j--) {
+                               if ((c = src[j]) == '*') {
+                                       end = j - 1;
+                                       break;
+                               }
+                       }
+                       if (end == -1)
+                               end = max_value;
+               }
+               if (msgStart == end)
+                       continue; // empty
+               // trim the message
+               while (CharOperation.isWhitespace(src[end]) && msgStart <= end)
+                       end--;
+               while (CharOperation.isWhitespace(src[msgStart]) && msgStart <= end)
+                       msgStart++;
+               // update the end position of the task
+               this.foundTaskPositions[i][1] = end;
+               // get the message source
+               final int messageLength = end - msgStart + 1;
+               char[] message = new char[messageLength];
+               System.arraycopy(src, msgStart, message, 0, messageLength);
+               this.foundTaskMessages[i] = message;
+       }
+}
+
   // chech presence of task: tags
-  public void checkTaskTag(int commentStart, int commentEnd) {
-    // only look for newer task: tags
-    if (this.foundTaskCount > 0 && this.foundTaskPositions[this.foundTaskCount - 1][0] >= commentStart) {
-      return;
-    }
-    int foundTaskIndex = this.foundTaskCount;
-    nextChar: for (int i = commentStart; i < commentEnd && i < this.eofPosition; i++) {
-      char[] tag = null;
-      char[] priority = null;
-      // check for tag occurrence
-      nextTag: for (int itag = 0; itag < this.taskTags.length; itag++) {
-        tag = this.taskTags[itag];
-        priority = this.taskPriorities != null && itag < this.taskPriorities.length ? this.taskPriorities[itag] : null;
-        int tagLength = tag.length;
-        for (int t = 0; t < tagLength; t++) {
-          if (this.source[i + t] != tag[t])
-            continue nextTag;
-        }
-        if (this.foundTaskTags == null) {
-          this.foundTaskTags = new char[5][];
-          this.foundTaskMessages = new char[5][];
-          this.foundTaskPriorities = new char[5][];
-          this.foundTaskPositions = new int[5][];
-        } else if (this.foundTaskCount == this.foundTaskTags.length) {
-          System.arraycopy(this.foundTaskTags, 0, this.foundTaskTags = new char[this.foundTaskCount * 2][], 0, this.foundTaskCount);
-          System.arraycopy(this.foundTaskMessages, 0, this.foundTaskMessages = new char[this.foundTaskCount * 2][], 0,
-              this.foundTaskCount);
-          System.arraycopy(this.foundTaskPriorities, 0, this.foundTaskPriorities = new char[this.foundTaskCount * 2][], 0,
-              this.foundTaskCount);
-          System.arraycopy(this.foundTaskPositions, 0, this.foundTaskPositions = new int[this.foundTaskCount * 2][], 0,
-              this.foundTaskCount);
-        }
-        this.foundTaskTags[this.foundTaskCount] = tag;
-        this.foundTaskPriorities[this.foundTaskCount] = priority;
-        this.foundTaskPositions[this.foundTaskCount] = new int[] { i, i + tagLength - 1 };
-        this.foundTaskMessages[this.foundTaskCount] = CharOperation.NO_CHAR;
-        this.foundTaskCount++;
-        i += tagLength - 1; // will be incremented when looping
-      }
-    }
-    for (int i = foundTaskIndex; i < this.foundTaskCount; i++) {
-      // retrieve message start and end positions
-      int msgStart = this.foundTaskPositions[i][0] + this.foundTaskTags[i].length;
-      int max_value = i + 1 < this.foundTaskCount ? this.foundTaskPositions[i + 1][0] - 1 : commentEnd - 1;
-      // at most beginning of next task
-      if (max_value < msgStart)
-        max_value = msgStart; // would only occur if tag is before EOF.
-      int end = -1;
-      char c;
-      for (int j = msgStart; j < max_value; j++) {
-        if ((c = this.source[j]) == '\n' || c == '\r') {
-          end = j - 1;
-          break;
-        }
-      }
-      if (end == -1) {
-        for (int j = max_value; j > msgStart; j--) {
-          if ((c = this.source[j]) == '*') {
-            end = j - 1;
-            break;
-          }
-        }
-        if (end == -1)
-          end = max_value;
-      }
-      if (msgStart == end)
-        continue; // empty
-      // trim the message
-      while (CharOperation.isWhitespace(source[end]) && msgStart <= end)
-        end--;
-      while (CharOperation.isWhitespace(source[msgStart]) && msgStart <= end)
-        msgStart++;
-      // update the end position of the task
-      this.foundTaskPositions[i][1] = end;
-      // get the message source
-      final int messageLength = end - msgStart + 1;
-      char[] message = new char[messageLength];
-      System.arraycopy(source, msgStart, message, 0, messageLength);
-      this.foundTaskMessages[i] = message;
-    }
-  }
+//  public void checkTaskTag(int commentStart, int commentEnd) {
+//    // only look for newer task: tags
+//    if (this.foundTaskCount > 0 && this.foundTaskPositions[this.foundTaskCount - 1][0] >= commentStart) {
+//      return;
+//    }
+//    int foundTaskIndex = this.foundTaskCount;
+//    nextChar: for (int i = commentStart; i < commentEnd && i < this.eofPosition; i++) {
+//      char[] tag = null;
+//      char[] priority = null;
+//      // check for tag occurrence
+//      nextTag: for (int itag = 0; itag < this.taskTags.length; itag++) {
+//        tag = this.taskTags[itag];
+//        priority = this.taskPriorities != null && itag < this.taskPriorities.length ? this.taskPriorities[itag] : null;
+//        int tagLength = tag.length;
+//        for (int t = 0; t < tagLength; t++) {
+//          if (this.source[i + t] != tag[t])
+//            continue nextTag;
+//        }
+//        if (this.foundTaskTags == null) {
+//          this.foundTaskTags = new char[5][];
+//          this.foundTaskMessages = new char[5][];
+//          this.foundTaskPriorities = new char[5][];
+//          this.foundTaskPositions = new int[5][];
+//        } else if (this.foundTaskCount == this.foundTaskTags.length) {
+//          System.arraycopy(this.foundTaskTags, 0, this.foundTaskTags = new char[this.foundTaskCount * 2][], 0, this.foundTaskCount);
+//          System.arraycopy(this.foundTaskMessages, 0, this.foundTaskMessages = new char[this.foundTaskCount * 2][], 0,
+//              this.foundTaskCount);
+//          System.arraycopy(this.foundTaskPriorities, 0, this.foundTaskPriorities = new char[this.foundTaskCount * 2][], 0,
+//              this.foundTaskCount);
+//          System.arraycopy(this.foundTaskPositions, 0, this.foundTaskPositions = new int[this.foundTaskCount * 2][], 0,
+//              this.foundTaskCount);
+//        }
+//        this.foundTaskTags[this.foundTaskCount] = tag;
+//        this.foundTaskPriorities[this.foundTaskCount] = priority;
+//        this.foundTaskPositions[this.foundTaskCount] = new int[] { i, i + tagLength - 1 };
+//        this.foundTaskMessages[this.foundTaskCount] = CharOperation.NO_CHAR;
+//        this.foundTaskCount++;
+//        i += tagLength - 1; // will be incremented when looping
+//      }
+//    }
+//    for (int i = foundTaskIndex; i < this.foundTaskCount; i++) {
+//      // retrieve message start and end positions
+//      int msgStart = this.foundTaskPositions[i][0] + this.foundTaskTags[i].length;
+//      int max_value = i + 1 < this.foundTaskCount ? this.foundTaskPositions[i + 1][0] - 1 : commentEnd - 1;
+//      // at most beginning of next task
+//      if (max_value < msgStart)
+//        max_value = msgStart; // would only occur if tag is before EOF.
+//      int end = -1;
+//      char c;
+//      for (int j = msgStart; j < max_value; j++) {
+//        if ((c = this.source[j]) == '\n' || c == '\r') {
+//          end = j - 1;
+//          break;
+//        }
+//      }
+//      if (end == -1) {
+//        for (int j = max_value; j > msgStart; j--) {
+//          if ((c = this.source[j]) == '*') {
+//            end = j - 1;
+//            break;
+//          }
+//        }
+//        if (end == -1)
+//          end = max_value;
+//      }
+//      if (msgStart == end)
+//        continue; // empty
+//      // trim the message
+//      while (CharOperation.isWhitespace(source[end]) && msgStart <= end)
+//        end--;
+//      while (CharOperation.isWhitespace(source[msgStart]) && msgStart <= end)
+//        msgStart++;
+//      // update the end position of the task
+//      this.foundTaskPositions[i][1] = end;
+//      // get the message source
+//      final int messageLength = end - msgStart + 1;
+//      char[] message = new char[messageLength];
+//      System.arraycopy(source, msgStart, message, 0, messageLength);
+//      this.foundTaskMessages[i] = message;
+//    }
+//  }
 }
\ No newline at end of file
index 7f74c39..ce634b8 100644 (file)
@@ -33,7 +33,7 @@ public class CommentRecorderScanner extends Scanner {
 //                             taskTags, taskPriorities, isTaskCaseSensitive);
                super(tokenizeComments, tokenizeWhiteSpace, 
                                checkNonExternalizedStringLiterals, false, false,
-                               taskTags, taskPriorities);
+                               taskTags, taskPriorities, true /*taskCaseSensitive*/);
        }
        
        /**
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/refactoring/util/ResourceUtil.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/refactoring/util/ResourceUtil.java
new file mode 100644 (file)
index 0000000..673326c
--- /dev/null
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * 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.corext.refactoring.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+
+import net.sourceforge.phpdt.core.ICompilationUnit;
+import net.sourceforge.phpdt.core.IJavaElement;
+import net.sourceforge.phpdt.core.IMember;
+import net.sourceforge.phpdt.core.IOpenable;
+
+import net.sourceforge.phpdt.internal.corext.Assert;
+
+public class ResourceUtil {
+       
+       private ResourceUtil(){
+       }
+       
+       public static IFile[] getFiles(ICompilationUnit[] cus) {
+               List files= new ArrayList(cus.length);
+               for (int i= 0; i < cus.length; i++) {
+                       IResource resource= ResourceUtil.getResource(cus[i]);
+                       if (resource != null && resource.getType() == IResource.FILE)
+                               files.add(resource);
+               }
+               return (IFile[]) files.toArray(new IFile[files.size()]);
+       }
+
+       public static IFile getFile(ICompilationUnit cu) {
+               IResource resource= ResourceUtil.getResource(cu);
+               if (resource != null && resource.getType() == IResource.FILE)
+                       return (IFile)resource;
+               else
+                       return null;
+       }
+
+       //----- other ------------------------------
+                       
+       /**
+        * Finds an <code>IResource</code> for a given <code>ICompilationUnit</code>.
+        * If the parameter is a working copy then the <code>IResource</code> for
+        * the original element is returned.
+        */
+       public static IResource getResource(ICompilationUnit cu) {
+               return cu.getResource();
+       }
+
+
+       /**
+        * Returns the <code>IResource</code> that the given <code>IMember</code> is defined in.
+        * @see #getResource
+        */
+       public static IResource getResource(IMember member) {
+               Assert.isTrue(!member.isBinary());
+               return getResource(member.getCompilationUnit());
+       }
+
+       public static IResource getResource(Object o){
+               if (o instanceof IResource)
+                       return (IResource)o;
+               if (o instanceof IJavaElement)
+                       return getResource((IJavaElement)o);
+               return null;    
+       }
+
+       private static IResource getResource(IJavaElement element){
+               if (element.getElementType() == IJavaElement.COMPILATION_UNIT) 
+                       return getResource((ICompilationUnit) element);
+               else if (element instanceof IOpenable) 
+                       return element.getResource();
+               else    
+                       return null;    
+       }
+}
index 7caa523..fe61f5a 100644 (file)
@@ -2,6 +2,7 @@
  * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
  * All rights reserved. This program and the accompanying materials 
  * are made available under the terms of the Common Public License v0.5 
+ * 
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/cpl-v05.html
  * 
@@ -23,15 +24,8 @@ import net.sourceforge.phpdt.core.compiler.ITerminalSymbols;
 import net.sourceforge.phpdt.core.compiler.InvalidInputException;
 import net.sourceforge.phpdt.internal.compiler.ConfigurableOption;
 import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
-import net.sourceforge.phpdt.internal.corext.codemanipulation.StubUtility;
-import net.sourceforge.phpdt.internal.corext.util.Strings;
 import net.sourceforge.phpdt.internal.formatter.impl.FormatterOptions;
 import net.sourceforge.phpdt.internal.formatter.impl.SplitLine;
-import net.sourceforge.phpdt.internal.ui.preferences.CodeFormatterPreferencePage;
-
-import org.eclipse.jface.text.IDocument;
-import org.eclipse.jface.text.formatter.IContentFormatterExtension;
-import org.eclipse.jface.text.formatter.IFormattingContext;
 
 /**
  * <h2>How to format a piece of code ?</h2>
@@ -166,7 +160,7 @@ public class CodeFormatter implements ITerminalSymbols, ICodeFormatter {
     , false /* nls */
     , false /* assert */
     , true, /* tokenizeStrings */
-    null, null); // regular scanner for forming lines
+    null, null, true /*taskCaseSensitive*/); // regular scanner for forming lines
     scanner.recordLineSeparator = true;
     scanner.ignorePHPOneLiner = true;
     // to remind of the position of the beginning of the line.
@@ -175,7 +169,7 @@ public class CodeFormatter implements ITerminalSymbols, ICodeFormatter {
     , false /* nls */
     , false /* assert */
     , true, /* tokenizeStrings */
-    null, null);
+    null, null, true /*taskCaseSensitive*/);
     splitScanner.ignorePHPOneLiner = true;
     // secondary scanner to split long lines formed by primary scanning
     // initialize current line buffer
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/ActionUtil.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/ActionUtil.java
new file mode 100644 (file)
index 0000000..d526b77
--- /dev/null
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * 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.actions;
+
+import net.sourceforge.phpdt.core.IJavaElement;
+import net.sourceforge.phpdt.core.IJavaProject;
+import net.sourceforge.phpdt.core.IPackageFragment;
+import net.sourceforge.phpdt.core.IPackageFragmentRoot;
+import net.sourceforge.phpdt.internal.corext.refactoring.util.ResourceUtil;
+import net.sourceforge.phpeclipse.PHPeclipsePlugin;
+import net.sourceforge.phpeclipse.phpeditor.PHPEditor;
+
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IProjectNature;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.swt.widgets.Shell;
+
+/*
+ * http://dev.eclipse.org/bugs/show_bug.cgi?id=19104
+ */
+public class ActionUtil {
+       
+       private ActionUtil(){
+       }
+
+       //bug 31998     we will have to disable renaming of linked packages (and cus)
+       public static boolean mustDisableJavaModelAction(Shell shell, Object element) {
+               if (!(element instanceof IPackageFragment) && !(element instanceof IPackageFragmentRoot))
+                       return false;
+               
+               IResource resource= ResourceUtil.getResource(element);
+               if ((resource == null) || (! (resource instanceof IFolder)) || (! resource.isLinked()))
+                       return false;
+                       
+               MessageDialog.openInformation(shell, ActionMessages.getString("ActionUtil.not_possible"), ActionMessages.getString("ActionUtil.no_linked")); //$NON-NLS-1$ //$NON-NLS-2$
+               return true;
+       }
+       
+       public static boolean isProcessable(Shell shell, PHPEditor editor) {
+               if (editor == null)
+                       return true;
+               IJavaElement input= SelectionConverter.getInput(editor);
+               // if a Java editor doesn't have an input of type Java element
+               // then it is for sure not on the build path
+               if (input == null) {
+                       MessageDialog.openInformation(shell, 
+                               ActionMessages.getString("ActionUtil.notOnBuildPath.title"),  //$NON-NLS-1$
+                               ActionMessages.getString("ActionUtil.notOnBuildPath.message")); //$NON-NLS-1$
+                       return false;
+               }
+               return isProcessable(shell, input);
+       }
+       
+       public static boolean isProcessable(Shell shell, Object element) {
+               if (!(element instanceof IJavaElement))
+                       return true;
+                       
+               if (isOnBuildPath((IJavaElement)element))
+                       return true;
+               MessageDialog.openInformation(shell, 
+                       ActionMessages.getString("ActionUtil.notOnBuildPath.title"),  //$NON-NLS-1$
+                       ActionMessages.getString("ActionUtil.notOnBuildPath.message")); //$NON-NLS-1$
+               return false;
+       }
+
+       public static boolean isOnBuildPath(IJavaElement element) {     
+        //fix for bug http://dev.eclipse.org/bugs/show_bug.cgi?id=20051
+        if (element.getElementType() == IJavaElement.JAVA_PROJECT)
+            return true;
+               IJavaProject project= element.getJavaProject();
+               try {
+//                     if (!project.isOnClasspath(element))
+//                             return false;
+                       IProject resourceProject= project.getProject();
+                       if (resourceProject == null)
+                               return false;
+                       IProjectNature nature= resourceProject.getNature(PHPeclipsePlugin.PHP_NATURE_ID);
+                       // We have a Java project
+                       if (nature != null)
+                               return true;
+               } catch (CoreException e) {
+               }
+               return false;
+       }
+}
+
index 28fc336..68c90df 100644 (file)
@@ -1,10 +1,10 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
+ * 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
  *******************************************************************************/
@@ -14,9 +14,10 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.ResourceBundle;
 
-import net.sourceforge.phpdt.internal.corext.Assert;
 import net.sourceforge.phpdt.internal.ui.text.IPHPPartitions;
+import net.sourceforge.phpeclipse.phpeditor.php.PHPDocumentPartitioner;
 
+import org.eclipse.jface.text.Assert;
 import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.BadPartitioningException;
 import org.eclipse.jface.text.IDocument;
@@ -26,174 +27,181 @@ import org.eclipse.jface.text.ITypedRegion;
 import org.eclipse.ui.texteditor.ITextEditor;
 
 /**
- * Action that encloses the editor's current selection with Java block comment terminators
- * (<code>&#47;&#42;</code> and <code>&#42;&#47;</code>).
+ * Action that encloses the editor's current selection with Java block comment terminators (<code>&#47;&#42;</code> and
+ * <code>&#42;&#47;</code>).
  * 
  * @since 3.0
- */
+ */ 
 public class AddBlockCommentAction extends BlockCommentAction {
 
-       /**
-        * Creates a new instance.
-        * 
-        * @param bundle the resource bundle
-        * @param prefix a prefix to be prepended to the various resource keys
-        *   (described in <code>ResourceAction</code> constructor), or 
-        *   <code>null</code> if none
-        * @param editor the text editor
-        */
-       public AddBlockCommentAction(ResourceBundle bundle, String prefix, ITextEditor editor) {
-               super(bundle, prefix, editor);
-       }
-       
-       /*
-        * @see org.eclipse.jdt.internal.ui.actions.BlockCommentAction#runInternal(org.eclipse.jface.text.ITextSelection, org.eclipse.jface.text.IDocumentExtension3, org.eclipse.jdt.internal.ui.actions.BlockCommentAction.Edit.EditFactory)
-        */
-       protected void runInternal(ITextSelection selection, IDocumentExtension3 docExtension, Edit.EditFactory factory) throws BadLocationException, BadPartitioningException {
-               int selectionOffset= selection.getOffset();
-               int selectionEndOffset= selectionOffset + selection.getLength();
-               List edits= new LinkedList();
-               //ITypedRegion partition= docExtension.getPartition(IPHPPartitions.PHP_PARTITIONING, selectionOffset, false);
-               ITypedRegion partition= docExtension.getPartition(IDocumentExtension3.DEFAULT_PARTITIONING, selectionOffset, false);
-               
-               handleFirstPartition(partition, edits, factory, selectionOffset);
-
-               while (partition.getOffset() + partition.getLength() < selectionEndOffset) {
-                       partition= handleInteriorPartition(partition, edits, factory, docExtension);
-               }
-               
-               handleLastPartition(partition, edits, factory, selectionEndOffset);
-               
-               executeEdits(edits);
-       }
-
-       /**
-        * Handle the first partition of the selected text.
-        * 
-        * @param partition
-        * @param edits
-        * @param factory
-        * @param offset
-        */
-       private void handleFirstPartition(ITypedRegion partition, List edits, Edit.EditFactory factory, int offset) throws BadLocationException {
-               
-               int partOffset= partition.getOffset();
-               String partType= partition.getType();
-               
-               Assert.isTrue(partOffset <= offset, "illegal partition"); //$NON-NLS-1$
-               
-               // first partition: mark start of comment
-//             if (partType == IDocument.DEFAULT_CONTENT_TYPE) 
-               if (partType == IPHPPartitions.PHP_PARTITIONING) {
-                       // Java code: right where selection starts
-                       edits.add(factory.createEdit(offset, 0, getCommentStart()));
-               } else if (isSpecialPartition(partType)) {
-                       // special types: include the entire partition
-                       edits.add(factory.createEdit(partOffset, 0, getCommentStart()));
-               }       // javadoc: no mark, will only start after comment
-               
-       }
-
-       /**
-        * Handles the end of the given partition and the start of the next partition, which is returned.
-        * 
-        * @param partition
-        * @param edits
-        * @param factory
-        * @param docExtension
-        * @return
-        * @throws BadLocationException
-        * @throws BadPartitioningException
-        */
-       private ITypedRegion handleInteriorPartition(ITypedRegion partition, List edits, Edit.EditFactory factory, IDocumentExtension3 docExtension) throws BadPartitioningException, BadLocationException {
-
-               // end of previous partition
-               String partType= partition.getType();
-               int partEndOffset= partition.getOffset() + partition.getLength();
-               int tokenLength= getCommentStart().length();
-               
-               boolean wasJavadoc= false; // true if the previous partition is javadoc
-               
-               if (partType == IPHPPartitions.PHP_PHPDOC_COMMENT) {
-                       
-                       wasJavadoc= true;
-                       
-//             } else if (partType == IPHPPartitions.JAVA_MULTI_LINE_COMMENT) {
-//                     
-//                     // already in a comment - remove ending mark
-//                     edits.add(factory.createEdit(partEndOffset - tokenLength, tokenLength, "")); //$NON-NLS-1$
-//                     
-               }
-
-               // advance to next partition
-               partition= docExtension.getPartition(IPHPPartitions.PHP_PARTITIONING, partEndOffset, false);
-               partType= partition.getType();
-
-               // start of next partition
-               if (wasJavadoc) {
-                       
-                       // if previous was javadoc, and the current one is not, then add block comment start
-                       if (partType == IDocument.DEFAULT_CONTENT_TYPE
-                                       || isSpecialPartition(partType)) {
-                               edits.add(factory.createEdit(partition.getOffset(), 0, getCommentStart()));
-                       }
-                       
-               } else { // !wasJavadoc
-               
-                       if (partType == IPHPPartitions.PHP_PHPDOC_COMMENT) {
-                               // if next is javadoc, end block comment before
-                               edits.add(factory.createEdit(partition.getOffset(), 0, getCommentEnd()));
-//                     } else if (partType == IJavaPartitions.JAVA_MULTI_LINE_COMMENT) {
-//                             // already in a comment - remove startToken
-//                             edits.add(factory.createEdit(partition.getOffset(), getCommentStart().length(), "")); //$NON-NLS-1$
-                       }
-               }
-               
-               return partition;
-       }
-
-       /**
-        * Handles the end of the last partition.
-        * 
-        * @param partition
-        * @param edits
-        * @param factory
-        * @param endOffset
-        */
-       private void handleLastPartition(ITypedRegion partition, List edits, Edit.EditFactory factory, int endOffset) throws BadLocationException {
-
-               String partType= partition.getType();
-               
-//             if (partType == IDocument.DEFAULT_CONTENT_TYPE) {
-        if (partType == IPHPPartitions.PHP_PARTITIONING) {
-                       // normal java: end comment where selection ends
-                       edits.add(factory.createEdit(endOffset, 0, getCommentEnd()));
-               } else if (isSpecialPartition(partType)) {
-                       // special types: consume entire partition
-                       edits.add(factory.createEdit(partition.getOffset() + partition.getLength(), 0, getCommentEnd()));
-               }
-               
-       }
-
-       /**
-        * Returns whether <code>partType</code> is special, i.e. a Java <code>String</code>,
-        * <code>Character</code>, or <code>Line End Comment</code> partition.
-        * 
-        * @param partType the partition type to check
-        * @return <code>true</code> if <code>partType</code> is special, <code>false</code> otherwise
-        */
-       private boolean isSpecialPartition(String partType) {
-               return// partType == IPHPPartitions.PHP_CHARACTER
-                               //|| 
-                               partType == IPHPPartitions.PHP_STRING_DQ;
-                               //|| partType == IPHPPartitions.PHP_SINGLE_LINE_COMMENT;
-       }
-
-       /*
-        * @see org.eclipse.jdt.internal.ui.actions.BlockCommentAction#validSelection(org.eclipse.jface.text.ITextSelection)
-        */
-       protected boolean isValidSelection(ITextSelection selection) {
-               return selection != null && !selection.isEmpty() && selection.getLength() > 0;
-       }
-
-}
+  /**
+   * Creates a new instance.
+   * 
+   * @param bundle
+   *          the resource bundle
+   * @param prefix
+   *          a prefix to be prepended to the various resource keys (described in <code>ResourceAction</code> constructor), or
+   *          <code>null</code> if none
+   * @param editor
+   *          the text editor
+   */
+  public AddBlockCommentAction(ResourceBundle bundle, String prefix, ITextEditor editor) {
+    super(bundle, prefix, editor);
+  }
+
+  /*
+   * @see org.eclipse.jdt.internal.ui.actions.BlockCommentAction#runInternal(org.eclipse.jface.text.ITextSelection,
+   *      org.eclipse.jface.text.IDocumentExtension3, org.eclipse.jdt.internal.ui.actions.BlockCommentAction.Edit.EditFactory)
+   */
+  protected void runInternal(ITextSelection selection, IDocumentExtension3 docExtension, Edit.EditFactory factory)
+      throws BadLocationException, BadPartitioningException {
+    int selectionOffset = selection.getOffset();
+    int selectionEndOffset = selectionOffset + selection.getLength();
+    List edits = new LinkedList();
+    ITypedRegion partition = docExtension.getPartition(IPHPPartitions.PHP_PARTITIONING, selectionOffset, false);
+
+    handleFirstPartition(partition, edits, factory, selectionOffset);
+
+    while (partition.getOffset() + partition.getLength() < selectionEndOffset) {
+      partition = handleInteriorPartition(partition, edits, factory, docExtension);
+    }
+
+    handleLastPartition(partition, edits, factory, selectionEndOffset);
+
+    executeEdits(edits);
+  }
+
+  /**
+   * Handle the first partition of the selected text.
+   * 
+   * @param partition
+   * @param edits
+   * @param factory
+   * @param offset
+   */
+  private void handleFirstPartition(ITypedRegion partition, List edits, Edit.EditFactory factory, int offset)
+      throws BadLocationException {
+
+    int partOffset = partition.getOffset();
+    String partType = partition.getType();
+
+    Assert.isTrue(partOffset <= offset, "illegal partition"); //$NON-NLS-1$
+
+    // first partition: mark start of comment
+    if (partType == IDocument.DEFAULT_CONTENT_TYPE ||
+        partType == PHPDocumentPartitioner.PHP_SCRIPT_CODE) {
+      // Java code: right where selection starts
+      edits.add(factory.createEdit(offset, 0, getCommentStart()));
+    } else if (isSpecialPartition(partType)) {
+      // special types: include the entire partition
+      edits.add(factory.createEdit(partOffset, 0, getCommentStart()));
+    } // javadoc: no mark, will only start after comment
+
+  }
+
+  /**
+   * Handles the end of the given partition and the start of the next partition, which is returned.
+   *  
+   * @param partition
+   * @param edits
+   * @param factory
+   * @param docExtension
+   * @return
+   * @throws BadLocationException
+   * @throws BadPartitioningException
+   */
+  private ITypedRegion handleInteriorPartition(ITypedRegion partition, List edits, Edit.EditFactory factory,
+      IDocumentExtension3 docExtension) throws BadPartitioningException, BadLocationException {
+
+    // end of previous partition
+    String partType = partition.getType();
+    int partEndOffset = partition.getOffset() + partition.getLength();
+    int tokenLength = getCommentStart().length();
+
+    boolean wasJavadoc = false; // true if the previous partition is javadoc
+
+    if (partType == IPHPPartitions.PHP_PHPDOC_COMMENT) {
+
+      wasJavadoc = true;
+
+    } else if (partType == IPHPPartitions.PHP_MULTILINE_COMMENT) {
+
+      // already in a comment - remove ending mark
+      edits.add(factory.createEdit(partEndOffset - tokenLength, tokenLength, "")); //$NON-NLS-1$
+
+    }
+
+    // advance to next partition
+    partition = docExtension.getPartition(IPHPPartitions.PHP_PARTITIONING, partEndOffset, false);
+    partType = partition.getType();
+
+    // start of next partition
+    if (wasJavadoc) {
+
+      // if previous was javadoc, and the current one is not, then add block comment start
+      if (partType == IDocument.DEFAULT_CONTENT_TYPE ||  
+          partType == PHPDocumentPartitioner.PHP_SCRIPT_CODE ||
+          isSpecialPartition(partType)) {
+        edits.add(factory.createEdit(partition.getOffset(), 0, getCommentStart()));
+      }
+
+    } else { // !wasJavadoc
+
+      if (partType == IPHPPartitions.PHP_PHPDOC_COMMENT) {
+        // if next is javadoc, end block comment before
+        edits.add(factory.createEdit(partition.getOffset(), 0, getCommentEnd()));
+      } else if (partType == IPHPPartitions.PHP_MULTILINE_COMMENT) {
+        // already in a comment - remove startToken
+        edits.add(factory.createEdit(partition.getOffset(), getCommentStart().length(), "")); //$NON-NLS-1$
+      }
+    }
+
+    return partition;
+  }
+
+  /**
+   * Handles the end of the last partition.
+   * 
+   * @param partition
+   * @param edits
+   * @param factory
+   * @param endOffset
+   */
+  private void handleLastPartition(ITypedRegion partition, List edits, Edit.EditFactory factory, int endOffset)
+      throws BadLocationException {
+
+    String partType = partition.getType();
+
+    if (partType == IDocument.DEFAULT_CONTENT_TYPE  ||
+        partType == PHPDocumentPartitioner.PHP_SCRIPT_CODE) {
+      // normal java: end comment where selection ends
+      edits.add(factory.createEdit(endOffset, 0, getCommentEnd()));
+    } else if (isSpecialPartition(partType)) {
+      // special types: consume entire partition
+      edits.add(factory.createEdit(partition.getOffset() + partition.getLength(), 0, getCommentEnd()));
+    }
+
+  }
+
+  /**
+   * Returns whether <code>partType</code> is special, i.e. a Java <code>String</code>,<code>Character</code>, or
+   * <code>Line End Comment</code> partition.
+   * 
+   * @param partType
+   *          the partition type to check
+   * @return <code>true</code> if <code>partType</code> is special, <code>false</code> otherwise
+   */
+  private boolean isSpecialPartition(String partType) {
+    //         return partType == IJavaPartitions.JAVA_CHARACTER
+    return partType == IPHPPartitions.PHP_STRING_DQ || partType == IPHPPartitions.PHP_STRING_SQ
+        || partType == IPHPPartitions.PHP_SINGLELINE_COMMENT;
+  }
+
+  /*
+   * @see org.eclipse.jdt.internal.ui.actions.BlockCommentAction#validSelection(org.eclipse.jface.text.ITextSelection)
+   */
+  protected boolean isValidSelection(ITextSelection selection) {
+    return selection != null && !selection.isEmpty() && selection.getLength() > 0;
+  }
+
+}
\ No newline at end of file
index 285a373..647800f 100644 (file)
@@ -1,10 +1,10 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
+ * 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
  *******************************************************************************/
@@ -14,21 +14,10 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.ResourceBundle;
 
-import net.sourceforge.phpdt.internal.corext.Assert;
-
-import org.eclipse.jface.text.BadLocationException;
-import org.eclipse.jface.text.BadPartitioningException;
-import org.eclipse.jface.text.BadPositionCategoryException;
-import org.eclipse.jface.text.DefaultPositionUpdater;
-import org.eclipse.jface.text.DocumentEvent;
-import org.eclipse.jface.text.IDocument;
-import org.eclipse.jface.text.IDocumentExtension3;
-import org.eclipse.jface.text.IPositionUpdater;
-import org.eclipse.jface.text.IRewriteTarget;
-import org.eclipse.jface.text.ITextSelection;
-import org.eclipse.jface.text.Position;
+import org.eclipse.jface.text.*;
 import org.eclipse.jface.viewers.ISelection;
 import org.eclipse.jface.viewers.ISelectionProvider;
+
 import org.eclipse.ui.IEditorInput;
 import org.eclipse.ui.texteditor.IDocumentProvider;
 import org.eclipse.ui.texteditor.ITextEditor;
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/IndentAction.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/IndentAction.java
new file mode 100644 (file)
index 0000000..7700f37
--- /dev/null
@@ -0,0 +1,499 @@
+/*******************************************************************************
+ * 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.actions;
+
+import java.util.ResourceBundle;
+
+import net.sourceforge.phpdt.core.JavaCore;
+import net.sourceforge.phpdt.core.formatter.DefaultCodeFormatterConstants;
+import net.sourceforge.phpdt.internal.ui.text.IPHPPartitions;
+import net.sourceforge.phpdt.internal.ui.text.JavaHeuristicScanner;
+import net.sourceforge.phpdt.internal.ui.text.JavaIndenter;
+import net.sourceforge.phpdt.internal.ui.text.SmartBackspaceManager;
+import net.sourceforge.phpdt.internal.ui.text.SmartBackspaceManager.UndoSpec;
+import net.sourceforge.phpdt.internal.ui.text.phpdoc.JavaDocAutoIndentStrategy;
+import net.sourceforge.phpdt.ui.PreferenceConstants;
+import net.sourceforge.phpeclipse.PHPeclipsePlugin;
+import net.sourceforge.phpeclipse.phpeditor.PHPEditor;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.text.Assert;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.DocumentCommand;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.IRewriteTarget;
+import org.eclipse.jface.text.ITextSelection;
+import org.eclipse.jface.text.ITypedRegion;
+import org.eclipse.jface.text.Position;
+import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.TextSelection;
+import org.eclipse.jface.text.TextUtilities;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.text.edits.MalformedTreeException;
+import org.eclipse.text.edits.ReplaceEdit;
+import org.eclipse.text.edits.TextEdit;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants;
+import org.eclipse.ui.texteditor.IDocumentProvider;
+import org.eclipse.ui.texteditor.ITextEditor;
+import org.eclipse.ui.texteditor.ITextEditorExtension3;
+import org.eclipse.ui.texteditor.TextEditorAction;
+
+/**
+ * Indents a line or range of lines in a Java document to its correct position. No complete
+ * AST must be present, the indentation is computed using heuristics. The algorith used is fast for
+ * single lines, but does not store any information and therefore not so efficient for large line
+ * ranges.
+ * 
+ * @see net.sourceforge.phpdt.internal.ui.text.JavaHeuristicScanner
+ * @see net.sourceforge.phpdt.internal.ui.text.JavaIndenter
+ * @since 3.0
+ */
+public class IndentAction extends TextEditorAction {
+       
+       /** The caret offset after an indent operation. */
+       private int fCaretOffset;
+       
+       /** 
+        * Whether this is the action invoked by TAB. When <code>true</code>, indentation behaves 
+        * differently to accomodate normal TAB operation.
+        */
+       private final boolean fIsTabAction;
+       
+       /**
+        * Creates a new instance.
+        * 
+        * @param bundle the resource bundle
+        * @param prefix the prefix to use for keys in <code>bundle</code>
+        * @param editor the text editor
+        * @param isTabAction whether the action should insert tabs if over the indentation
+        */
+       public IndentAction(ResourceBundle bundle, String prefix, ITextEditor editor, boolean isTabAction) {
+               super(bundle, prefix, editor);
+               fIsTabAction= isTabAction;
+       }
+       
+       /*
+        * @see org.eclipse.jface.action.Action#run()
+        */
+       public void run() {
+               // update has been called by the framework
+               if (!isEnabled() || !validateEditorInputState())
+                       return;
+               
+               ITextSelection selection= getSelection();
+               final IDocument document= getDocument();
+               
+               if (document != null) {
+                       
+                       final int offset= selection.getOffset();
+                       final int length= selection.getLength();
+                       final Position end= new Position(offset + length);
+                       final int firstLine, nLines;
+                       fCaretOffset= -1;
+                       
+                       try {
+                               document.addPosition(end);
+                               firstLine= document.getLineOfOffset(offset);
+                               // check for marginal (zero-length) lines
+                               int minusOne= length == 0 ? 0 : 1;
+                               nLines= document.getLineOfOffset(offset + length - minusOne) - firstLine + 1;
+                       } catch (BadLocationException e) {
+                               // will only happen on concurrent modification
+                         PHPeclipsePlugin.log(new Status(IStatus.ERROR, PHPeclipsePlugin.getPluginId(), IStatus.OK, "", e)); //$NON-NLS-1$
+                               return;
+                       }
+                       
+                       Runnable runnable= new Runnable() {
+                               public void run() {
+                                       IRewriteTarget target= (IRewriteTarget)getTextEditor().getAdapter(IRewriteTarget.class);
+                                       if (target != null) {
+                                               target.beginCompoundChange();
+                                               target.setRedraw(false);
+                                       }
+                                       
+                                       try {
+                                               JavaHeuristicScanner scanner= new JavaHeuristicScanner(document);
+                                               JavaIndenter indenter= new JavaIndenter(document, scanner);
+                                               boolean hasChanged= false;
+                                               for (int i= 0; i < nLines; i++) {
+                                                       hasChanged |= indentLine(document, firstLine + i, offset, indenter, scanner);
+                                               }
+                                               
+                                               // update caret position: move to new position when indenting just one line
+                                               // keep selection when indenting multiple
+                                               int newOffset, newLength;
+                                               if (fIsTabAction) {
+                                                       newOffset= fCaretOffset;
+                                                       newLength= 0;
+                                               } else if (nLines > 1) {
+                                                       newOffset= offset;
+                                                       newLength= end.getOffset() - offset;
+                                               } else {
+                                                       newOffset= fCaretOffset;
+                                                       newLength= 0;
+                                               }
+                                               
+                                               // always reset the selection if anything was replaced
+                                               // but not when we had a singleline nontab invocation
+                                               if (newOffset != -1 && (hasChanged || newOffset != offset || newLength != length))
+                                                       selectAndReveal(newOffset, newLength);
+                                               
+                                               document.removePosition(end);
+                                       } catch (BadLocationException e) {
+                                               // will only happen on concurrent modification
+                                         PHPeclipsePlugin.log(new Status(IStatus.ERROR, PHPeclipsePlugin.getPluginId(), IStatus.OK, "ConcurrentModification in IndentAction", e)); //$NON-NLS-1$
+                                               
+                                       } finally {
+                                               
+                                               if (target != null) {
+                                                       target.endCompoundChange();
+                                                       target.setRedraw(true);
+                                               }
+                                       }
+                               }
+                       };
+                       
+                       if (nLines > 50) {
+                               Display display= getTextEditor().getEditorSite().getWorkbenchWindow().getShell().getDisplay();
+                               BusyIndicator.showWhile(display, runnable);
+                       } else
+                               runnable.run();
+                       
+               }
+       }
+       
+       /**
+        * Selects the given range on the editor.
+        * 
+        * @param newOffset the selection offset
+        * @param newLength the selection range
+        */
+       private void selectAndReveal(int newOffset, int newLength) {
+               Assert.isTrue(newOffset >= 0); 
+               Assert.isTrue(newLength >= 0); 
+               ITextEditor editor= getTextEditor();
+               if (editor instanceof PHPEditor) {
+                       ISourceViewer viewer= ((PHPEditor)editor).getViewer();
+                       if (viewer != null)
+                               viewer.setSelectedRange(newOffset, newLength);
+               } else
+                       // this is too intrusive, but will never get called anyway
+                       getTextEditor().selectAndReveal(newOffset, newLength);
+                       
+       }
+
+       /**
+        * Indents a single line using the java heuristic scanner. Javadoc and multiline comments are 
+        * indented as specified by the <code>JavaDocAutoIndentStrategy</code>.
+        * 
+        * @param document the document
+        * @param line the line to be indented
+        * @param caret the caret position
+        * @param indenter the java indenter
+        * @param scanner the heuristic scanner
+        * @return <code>true</code> if <code>document</code> was modified, <code>false</code> otherwise
+        * @throws BadLocationException if the document got changed concurrently 
+        */
+       private boolean indentLine(IDocument document, int line, int caret, JavaIndenter indenter, JavaHeuristicScanner scanner) throws BadLocationException {
+               IRegion currentLine= document.getLineInformation(line);
+               int offset= currentLine.getOffset();
+               int wsStart= offset; // where we start searching for non-WS; after the "//" in single line comments
+               
+               String indent= null;
+               if (offset < document.getLength()) {
+                       ITypedRegion partition= TextUtilities.getPartition(document, IPHPPartitions.PHP_PARTITIONING, offset, true);
+                       String type= partition.getType();
+                       if (type.equals(IPHPPartitions.PHP_PHPDOC_COMMENT) || type.equals(IPHPPartitions.PHP_MULTILINE_COMMENT)) {
+                               
+                               // TODO this is a hack
+                               // what I want to do
+//                             new JavaDocAutoIndentStrategy().indentLineAtOffset(document, offset);
+//                             return;
+
+                               int start= 0;
+                               if (line > 0) {
+
+                                       IRegion previousLine= document.getLineInformation(line - 1);
+                                       start= previousLine.getOffset() + previousLine.getLength();
+                               }
+
+                               DocumentCommand command= new DocumentCommand() {};
+                               command.text= "\n"; //$NON-NLS-1$
+                               command.offset= start;
+                               new JavaDocAutoIndentStrategy(IPHPPartitions.PHP_PARTITIONING).customizeDocumentCommand(document, command);
+                               int to= 1;
+                               while (to < command.text.length() && Character.isWhitespace(command.text.charAt(to)))
+                                       to++;
+                               indent= command.text.substring(1, to);
+                               
+                       } else if (!fIsTabAction && partition.getOffset() == offset && type.equals(IPHPPartitions.PHP_SINGLELINE_COMMENT)) {
+                               
+                               // line comment starting at position 0 -> indent inside
+                               int slashes= 2;
+                               while (slashes < document.getLength() - 1 && document.get(offset + slashes, 2).equals("//")) //$NON-NLS-1$
+                                       slashes+= 2;
+                               
+                               wsStart= offset + slashes;
+                               
+                               StringBuffer computed= indenter.computeIndentation(offset);
+                               int tabSize= PHPeclipsePlugin.getDefault().getPreferenceStore().getInt(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TAB_WIDTH);
+                               while (slashes > 0 && computed.length() > 0) {
+                                       char c= computed.charAt(0);
+                                       if (c == '\t')
+                                               if (slashes > tabSize)
+                                                       slashes-= tabSize;
+                                               else
+                                                       break;
+                                       else if (c == ' ')
+                                               slashes--;
+                                       else break;
+                                       
+                                       computed.deleteCharAt(0);
+                               }
+                               
+                               indent= document.get(offset, wsStart - offset) + computed;
+                               
+                       }
+               } 
+               
+               // standard java indentation
+               if (indent == null) {
+                       StringBuffer computed= indenter.computeIndentation(offset);
+                       if (computed != null)
+                               indent= computed.toString();
+                       else
+                               indent= new String();
+               }
+               
+               // change document:
+               // get current white space
+               int lineLength= currentLine.getLength();
+               int end= scanner.findNonWhitespaceForwardInAnyPartition(wsStart, offset + lineLength);
+               if (end == JavaHeuristicScanner.NOT_FOUND)
+                       end= offset + lineLength;
+               int length= end - offset;
+               String currentIndent= document.get(offset, length);
+               
+               // if we are right before the text start / line end, and already after the insertion point
+               // then just insert a tab.
+               if (fIsTabAction && caret == end && whiteSpaceLength(currentIndent) >= whiteSpaceLength(indent)) {
+                       String tab= getTabEquivalent();
+                       document.replace(caret, 0, tab);
+                       fCaretOffset= caret + tab.length();
+                       return true;
+               }
+               
+               // set the caret offset so it can be used when setting the selection
+               if (caret >= offset && caret <= end)
+                       fCaretOffset= offset + indent.length();
+               else
+                       fCaretOffset= -1;
+               
+               // only change the document if it is a real change
+               if (!indent.equals(currentIndent)) {
+                       String deletedText= document.get(offset, length);
+                       document.replace(offset, length, indent);
+                       
+                       if (fIsTabAction && indent.length() > currentIndent.length() && PHPeclipsePlugin.getDefault().getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_SMART_BACKSPACE)) {
+                               ITextEditor editor= getTextEditor();
+                               if (editor != null) {
+                                       final SmartBackspaceManager manager= (SmartBackspaceManager) editor.getAdapter(SmartBackspaceManager.class);
+                                       if (manager != null) {
+                                               try {
+                                                       // restore smart portion
+                                                       ReplaceEdit smart= new ReplaceEdit(offset, indent.length(), deletedText);
+                                                       
+                                                       final UndoSpec spec= new UndoSpec(
+                                                                       offset + indent.length(),
+                                                                       new Region(caret, 0),
+                                                                       new TextEdit[] { smart },
+                                                                       2,
+                                                                       null);
+                                                       manager.register(spec);
+                                               } catch (MalformedTreeException e) {
+                                                       // log & ignore
+                                                 PHPeclipsePlugin.log(new Status(IStatus.ERROR, PHPeclipsePlugin.getPluginId(), IStatus.OK, "Illegal smart backspace action", e)); //$NON-NLS-1$
+                                               }
+                                       }
+                               }
+                       }
+
+                       
+                       return true;
+               } else
+                       return false;
+       }
+       
+       /**
+        * Returns the size in characters of a string. All characters count one, tabs count the editor's
+        * preference for the tab display 
+        * 
+        * @param indent the string to be measured.
+        * @return
+        */
+       private int whiteSpaceLength(String indent) {
+               if (indent == null)
+                       return 0;
+               else {
+                       int size= 0;
+                       int l= indent.length();
+                       int tabSize= PHPeclipsePlugin.getDefault().getPreferenceStore().getInt(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TAB_WIDTH);
+                       
+                       for (int i= 0; i < l; i++)
+                               size += indent.charAt(i) == '\t' ? tabSize : 1;
+                       return size;
+               }
+       }
+
+       /**
+        * Returns a tab equivalent, either as a tab character or as spaces, depending on the editor and
+        * formatter preferences.
+        * 
+        * @return a string representing one tab in the editor, never <code>null</code>
+        */
+       private String getTabEquivalent() {
+               String tab;
+               if (PHPeclipsePlugin.getDefault().getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_SPACES_FOR_TABS)) {
+                       int size= JavaCore.getPlugin().getPluginPreferences().getInt(DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE);
+                       StringBuffer buf= new StringBuffer();
+                       for (int i= 0; i< size; i++)
+                               buf.append(' ');
+                       tab= buf.toString();
+               } else
+                       tab= "\t"; //$NON-NLS-1$
+       
+               return tab;
+       }
+
+       /**
+        * Returns the editor's selection provider.
+        * 
+        * @return the editor's selection provider or <code>null</code>
+        */
+       private ISelectionProvider getSelectionProvider() {
+               ITextEditor editor= getTextEditor();
+               if (editor != null) {
+                       return editor.getSelectionProvider();
+               }
+               return null;
+       }
+       
+       /*
+        * @see org.eclipse.ui.texteditor.IUpdate#update()
+        */
+       public void update() {
+               super.update();
+               
+               if (isEnabled())
+                       if (fIsTabAction)
+                               setEnabled(canModifyEditor() && isSmartMode() && isValidSelection());
+                       else
+                               setEnabled(canModifyEditor() && !getSelection().isEmpty());
+       }
+       
+       /**
+        * Returns if the current selection is valid, i.e. whether it is empty and the caret in the 
+        * whitespace at the start of a line, or covers multiple lines.
+        * 
+        * @return <code>true</code> if the selection is valid for an indent operation
+        */
+       private boolean isValidSelection() {
+               ITextSelection selection= getSelection();
+               if (selection.isEmpty())
+                       return false;
+               
+               int offset= selection.getOffset();
+               int length= selection.getLength();
+               
+               IDocument document= getDocument();
+               if (document == null)
+                       return false;
+               
+               try {
+                       IRegion firstLine= document.getLineInformationOfOffset(offset);
+                       int lineOffset= firstLine.getOffset();
+                       
+                       // either the selection has to be empty and the caret in the WS at the line start
+                       // or the selection has to extend over multiple lines
+                       if (length == 0)
+                               return document.get(lineOffset, offset - lineOffset).trim().length() == 0;
+                       else
+//                             return lineOffset + firstLine.getLength() < offset + length;
+                               return false; // only enable for empty selections for now
+                       
+               } catch (BadLocationException e) {
+               }
+               
+               return false;
+       }
+       
+       /**
+        * Returns the smart preference state.
+        * 
+        * @return <code>true</code> if smart mode is on, <code>false</code> otherwise
+        */
+       private boolean isSmartMode() {
+               ITextEditor editor= getTextEditor();
+               
+               if (editor instanceof ITextEditorExtension3)
+                       return ((ITextEditorExtension3) editor).getInsertMode() == ITextEditorExtension3.SMART_INSERT;
+               
+               return false;
+       }
+       
+       /**
+        * Returns the document currently displayed in the editor, or <code>null</code> if none can be 
+        * obtained.
+        * 
+        * @return the current document or <code>null</code>
+        */
+       private IDocument getDocument() {
+               
+               ITextEditor editor= getTextEditor();
+               if (editor != null) {
+                       
+                       IDocumentProvider provider= editor.getDocumentProvider();
+                       IEditorInput input= editor.getEditorInput();
+                       if (provider != null && input != null)
+                               return provider.getDocument(input);
+                       
+               }
+               return null;
+       }
+       
+       /**
+        * Returns the selection on the editor or an invalid selection if none can be obtained. Returns
+        * never <code>null</code>.
+        * 
+        * @return the current selection, never <code>null</code>
+        */
+       private ITextSelection getSelection() {
+               ISelectionProvider provider= getSelectionProvider();
+               if (provider != null) {
+                       
+                       ISelection selection= provider.getSelection();
+                       if (selection instanceof ITextSelection)
+                               return (ITextSelection) selection;
+               }
+               
+               // null object
+               return TextSelection.emptySelection();
+       }
+       
+}
index 38c0291..ea5e0b2 100644 (file)
@@ -1,10 +1,10 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
+ * 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
  *******************************************************************************/
@@ -14,15 +14,15 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.ResourceBundle;
 
-import net.sourceforge.phpdt.internal.ui.text.IPHPPartitions;
-
 import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.BadPartitioningException;
 import org.eclipse.jface.text.IDocumentExtension3;
 import org.eclipse.jface.text.ITextSelection;
 import org.eclipse.jface.text.ITypedRegion;
+
 import org.eclipse.ui.texteditor.ITextEditor;
 
+import net.sourceforge.phpdt.internal.ui.text.IPHPPartitions;
 
 /**
  * Action that removes the enclosing comment marks from a Java block comment.
@@ -30,8 +30,7 @@ import org.eclipse.ui.texteditor.ITextEditor;
  * @since 3.0
  */
 public class RemoveBlockCommentAction extends BlockCommentAction {
-    final static String DEFAULT_PARTITIONING_CONTENT_TYPE = "__dftl_partition_content_type"; //$NON-NLS-1$
-       
+
        /**
         * Creates a new instance.
         * 
@@ -55,28 +54,23 @@ public class RemoveBlockCommentAction extends BlockCommentAction {
                int offset= selection.getOffset();
                int endOffset= offset + selection.getLength();
 
-//             ITypedRegion partition= docExtension.getPartition(IPHPPartitions.PHP_PARTITIONING, offset, false);
-               ITypedRegion partition= docExtension.getPartition(IDocumentExtension3.DEFAULT_PARTITIONING, offset, false);
-               
+               ITypedRegion partition= docExtension.getPartition(IPHPPartitions.PHP_PARTITIONING, offset, false);
                int partOffset= partition.getOffset();
                int partEndOffset= partOffset + partition.getLength();
                
                while (partEndOffset < endOffset) {
                        
-                       if (partition.getType() == IPHPPartitions.PHP_PHPDOC_COMMENT) {
+                       if (partition.getType() == IPHPPartitions.PHP_MULTILINE_COMMENT) {
                                edits.add(factory.createEdit(partOffset, tokenLength, "")); //$NON-NLS-1$
                                edits.add(factory.createEdit(partEndOffset - tokenLength, tokenLength, "")); //$NON-NLS-1$
                        }
                        
-//                     partition= docExtension.getPartition(IPHPPartitions.PHP_PARTITIONING, partEndOffset, false);
-                       partition= docExtension.getPartition(IDocumentExtension3.DEFAULT_PARTITIONING, partEndOffset, false);
-                       
+                       partition= docExtension.getPartition(IPHPPartitions.PHP_PARTITIONING, partEndOffset, false);
                        partOffset= partition.getOffset();
                        partEndOffset= partOffset + partition.getLength();
                }
 
-//             if (partition.getType() == IPHPPartitions.PHP_PHPDOC_COMMENT) {
-               if (partition.getType() ==   DEFAULT_PARTITIONING_CONTENT_TYPE) {
+               if (partition.getType() == IPHPPartitions.PHP_MULTILINE_COMMENT) {
                        edits.add(factory.createEdit(partOffset, tokenLength, "")); //$NON-NLS-1$
                        edits.add(factory.createEdit(partEndOffset - tokenLength, tokenLength, "")); //$NON-NLS-1$
                }
index 73543a2..61abec9 100644 (file)
@@ -40,6 +40,7 @@ import net.sourceforge.phpeclipse.preferences.ColorEditor;
 
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Preferences;
+import org.eclipse.jface.action.Action;
 import org.eclipse.jface.dialogs.Dialog;
 import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.jface.preference.PreferenceConverter;
@@ -49,12 +50,15 @@ import org.eclipse.jface.text.Document;
 import org.eclipse.jface.text.IDocument;
 import org.eclipse.jface.text.source.SourceViewer;
 import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
 import org.eclipse.swt.events.ModifyEvent;
 import org.eclipse.swt.events.ModifyListener;
 import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.events.SelectionListener;
 import org.eclipse.swt.graphics.Color;
 import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Point;
 import org.eclipse.swt.graphics.RGB;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
@@ -271,9 +275,9 @@ public class JavaEditorPreferencePage extends PreferencePage implements IWorkben
 
   private Button fShowInVerticalRulerCheckBox;
 
-  //   private Text fBrowserLikeLinksKeyModifierText;
-  //   private Button fBrowserLikeLinksCheckBox;
-  //   private StatusInfo fBrowserLikeLinksKeyModifierStatus;
+       private Text fBrowserLikeLinksKeyModifierText;
+       private Button fBrowserLikeLinksCheckBox;
+       private StatusInfo fBrowserLikeLinksKeyModifierStatus;
   //   private Button fCompletionInsertsRadioButton;
   //   private Button fCompletionOverwritesRadioButton;
   //   private Button fStickyOccurrencesButton;
@@ -1195,124 +1199,124 @@ public class JavaEditorPreferencePage extends PreferencePage implements IWorkben
     GridLayout layout = new GridLayout();
     layout.numColumns = 2;
     composite.setLayout(layout);
-    //         String text=
-    // PreferencesMessages.getString("JavaEditorPreferencePage.navigation.browserLikeLinks");
-    // //$NON-NLS-1$
-    //         fBrowserLikeLinksCheckBox= addCheckBox(composite, text,
-    // PreferenceConstants.EDITOR_BROWSER_LIKE_LINKS, 0);
-    //         fBrowserLikeLinksCheckBox.addSelectionListener(new SelectionListener() {
-    //                 public void widgetSelected(SelectionEvent e) {
-    //                         boolean state= fBrowserLikeLinksCheckBox.getSelection();
-    //                         fBrowserLikeLinksKeyModifierText.setEnabled(state);
-    //                         handleBrowserLikeLinksKeyModifierModified();
-    //                 }
-    //                 public void widgetDefaultSelected(SelectionEvent e) {
-    //                 }
-    //         });
-    // Text field for modifier string
-    //         text=
-    // PreferencesMessages.getString("JavaEditorPreferencePage.navigation.browserLikeLinksKeyModifier");
-    // //$NON-NLS-1$
-    //         fBrowserLikeLinksKeyModifierText= addTextField(composite, text,
-    // PreferenceConstants.EDITOR_BROWSER_LIKE_LINKS_KEY_MODIFIER, 20, 0,
-    // false);
-    //         fBrowserLikeLinksKeyModifierText.setTextLimit(Text.LIMIT);
-    //         
-    //         if
-    // (computeStateMask(fOverlayStore.getString(PreferenceConstants.EDITOR_BROWSER_LIKE_LINKS_KEY_MODIFIER))
-    // == -1) {
-    //                 // Fix possible illegal modifier string
-    //                 int stateMask=
-    // fOverlayStore.getInt(PreferenceConstants.EDITOR_BROWSER_LIKE_LINKS_KEY_MODIFIER_MASK);
-    //                 if (stateMask == -1)
-    //                         fBrowserLikeLinksKeyModifierText.setText(""); //$NON-NLS-1$
-    //                 else
-    //                         fBrowserLikeLinksKeyModifierText.setText(EditorUtility.getModifierString(stateMask));
-    //         }
-    //         fBrowserLikeLinksKeyModifierText.addKeyListener(new KeyListener() {
-    //                 private boolean isModifierCandidate;
-    //                 public void keyPressed(KeyEvent e) {
-    //                         isModifierCandidate= e.keyCode > 0 && e.character == 0 && e.stateMask ==
-    // 0;
-    //                 }
-    //         
-    //                 public void keyReleased(KeyEvent e) {
-    //                         if (isModifierCandidate && e.stateMask > 0 && e.stateMask == e.stateMask
-    // && e.character == 0) {// && e.time -time < 1000) {
-    //                                 String modifierString= fBrowserLikeLinksKeyModifierText.getText();
-    //                                 Point selection= fBrowserLikeLinksKeyModifierText.getSelection();
-    //                                 int i= selection.x - 1;
-    //                                 while (i > -1 && Character.isWhitespace(modifierString.charAt(i))) {
-    //                                         i--;
-    //                                 }
-    //                                 boolean needsPrefixDelimiter= i > -1 &&
-    // !String.valueOf(modifierString.charAt(i)).equals(DELIMITER);
-    //
-    //                                 i= selection.y;
-    //                                 while (i < modifierString.length() &&
-    // Character.isWhitespace(modifierString.charAt(i))) {
-    //                                         i++;
-    //                                 }
-    //                                 boolean needsPostfixDelimiter= i < modifierString.length() &&
-    // !String.valueOf(modifierString.charAt(i)).equals(DELIMITER);
-    //
-    //                                 String insertString;
-    //
-    //                                 if (needsPrefixDelimiter && needsPostfixDelimiter)
-    //                                         insertString=
-    // PreferencesMessages.getFormattedString("JavaEditorPreferencePage.navigation.insertDelimiterAndModifierAndDelimiter",
-    // new String[] {Action.findModifierString(e.stateMask)}); //$NON-NLS-1$
-    //                                 else if (needsPrefixDelimiter)
-    //                                         insertString=
-    // PreferencesMessages.getFormattedString("JavaEditorPreferencePage.navigation.insertDelimiterAndModifier",
-    // new String[] {Action.findModifierString(e.stateMask)}); //$NON-NLS-1$
-    //                                 else if (needsPostfixDelimiter)
-    //                                         insertString=
-    // PreferencesMessages.getFormattedString("JavaEditorPreferencePage.navigation.insertModifierAndDelimiter",
-    // new String[] {Action.findModifierString(e.stateMask)}); //$NON-NLS-1$
-    //                                 else
-    //                                         insertString= Action.findModifierString(e.stateMask);
-    //
-    //                                 fBrowserLikeLinksKeyModifierText.insert(insertString);
-    //                         }
-    //                 }
-    //         });
-    //
-    //         fBrowserLikeLinksKeyModifierText.addModifyListener(new ModifyListener()
-    // {
-    //                 public void modifyText(ModifyEvent e) {
-    //                         handleBrowserLikeLinksKeyModifierModified();
-    //                 }
-    //         });
+               String text=
+     PreferencesMessages.getString("JavaEditorPreferencePage.navigation.browserLikeLinks");
+     //$NON-NLS-1$
+               fBrowserLikeLinksCheckBox= addCheckBox(composite, text,
+     PreferenceConstants.EDITOR_BROWSER_LIKE_LINKS, 0);
+               fBrowserLikeLinksCheckBox.addSelectionListener(new SelectionListener() {
+                       public void widgetSelected(SelectionEvent e) {
+                               boolean state= fBrowserLikeLinksCheckBox.getSelection();
+                               fBrowserLikeLinksKeyModifierText.setEnabled(state);
+                               handleBrowserLikeLinksKeyModifierModified();
+                       }
+                       public void widgetDefaultSelected(SelectionEvent e) {
+                       }
+               });
+//     Text field for modifier string
+               text=
+     PreferencesMessages.getString("JavaEditorPreferencePage.navigation.browserLikeLinksKeyModifier");
+     //$NON-NLS-1$
+               fBrowserLikeLinksKeyModifierText= addTextField(composite, text,
+     PreferenceConstants.EDITOR_BROWSER_LIKE_LINKS_KEY_MODIFIER, 20, 0,
+     false);
+               fBrowserLikeLinksKeyModifierText.setTextLimit(Text.LIMIT);
+               
+               if
+     (computeStateMask(fOverlayStore.getString(PreferenceConstants.EDITOR_BROWSER_LIKE_LINKS_KEY_MODIFIER))
+     == -1) {
+                       // Fix possible illegal modifier string
+                       int stateMask=
+     fOverlayStore.getInt(PreferenceConstants.EDITOR_BROWSER_LIKE_LINKS_KEY_MODIFIER_MASK);
+                       if (stateMask == -1)
+                               fBrowserLikeLinksKeyModifierText.setText(""); //$NON-NLS-1$
+                       else
+                               fBrowserLikeLinksKeyModifierText.setText(EditorUtility.getModifierString(stateMask));
+               }
+               fBrowserLikeLinksKeyModifierText.addKeyListener(new KeyListener() {
+                       private boolean isModifierCandidate;
+                       public void keyPressed(KeyEvent e) {
+                               isModifierCandidate= e.keyCode > 0 && e.character == 0 && e.stateMask ==
+     0;
+                       }
+               
+                       public void keyReleased(KeyEvent e) {
+                               if (isModifierCandidate && e.stateMask > 0 && e.stateMask == e.stateMask
+     && e.character == 0) {// && e.time -time < 1000) {
+                                       String modifierString= fBrowserLikeLinksKeyModifierText.getText();
+                                       Point selection= fBrowserLikeLinksKeyModifierText.getSelection();
+                                       int i= selection.x - 1;
+                                       while (i > -1 && Character.isWhitespace(modifierString.charAt(i))) {
+                                               i--;
+                                       }
+                                       boolean needsPrefixDelimiter= i > -1 &&
+     !String.valueOf(modifierString.charAt(i)).equals(DELIMITER);
+    
+                                       i= selection.y;
+                                       while (i < modifierString.length() &&
+     Character.isWhitespace(modifierString.charAt(i))) {
+                                               i++;
+                                       }
+                                       boolean needsPostfixDelimiter= i < modifierString.length() &&
+     !String.valueOf(modifierString.charAt(i)).equals(DELIMITER);
+    
+                                       String insertString;
+    
+                                       if (needsPrefixDelimiter && needsPostfixDelimiter)
+                                               insertString=
+     PreferencesMessages.getFormattedString("JavaEditorPreferencePage.navigation.insertDelimiterAndModifierAndDelimiter",
+     new String[] {Action.findModifierString(e.stateMask)}); //$NON-NLS-1$
+                                       else if (needsPrefixDelimiter)
+                                               insertString=
+     PreferencesMessages.getFormattedString("JavaEditorPreferencePage.navigation.insertDelimiterAndModifier",
+     new String[] {Action.findModifierString(e.stateMask)}); //$NON-NLS-1$
+                                       else if (needsPostfixDelimiter)
+                                               insertString=
+     PreferencesMessages.getFormattedString("JavaEditorPreferencePage.navigation.insertModifierAndDelimiter",
+     new String[] {Action.findModifierString(e.stateMask)}); //$NON-NLS-1$
+                                       else
+                                               insertString= Action.findModifierString(e.stateMask);
+    
+                                       fBrowserLikeLinksKeyModifierText.insert(insertString);
+                               }
+                       }
+               });
+    
+               fBrowserLikeLinksKeyModifierText.addModifyListener(new ModifyListener()
+     {
+                       public void modifyText(ModifyEvent e) {
+                               handleBrowserLikeLinksKeyModifierModified();
+                       }
+               });
     return composite;
   }
 
   private void handleBrowserLikeLinksKeyModifierModified() {
-    //         String modifiers= fBrowserLikeLinksKeyModifierText.getText();
-    //         int stateMask= computeStateMask(modifiers);
-    //         if (fBrowserLikeLinksCheckBox.getSelection() && (stateMask == -1 ||
-    // (stateMask & SWT.SHIFT) != 0)) {
-    //                 if (stateMask == -1)
-    //                         fBrowserLikeLinksKeyModifierStatus= new StatusInfo(IStatus.ERROR,
-    // PreferencesMessages.getFormattedString("JavaEditorPreferencePage.navigation.modifierIsNotValid",
-    // modifiers)); //$NON-NLS-1$
-    //                 else
-    //                         fBrowserLikeLinksKeyModifierStatus= new StatusInfo(IStatus.ERROR,
-    // PreferencesMessages.getString("JavaEditorPreferencePage.navigation.shiftIsDisabled"));
-    // //$NON-NLS-1$
-    //                 setValid(false);
-    //                 StatusUtil.applyToStatusLine(this, fBrowserLikeLinksKeyModifierStatus);
-    //         } else {
-    //                 fBrowserLikeLinksKeyModifierStatus= new StatusInfo();
-    //                 updateStatus(fBrowserLikeLinksKeyModifierStatus);
-    //         }
+               String modifiers= fBrowserLikeLinksKeyModifierText.getText();
+               int stateMask= computeStateMask(modifiers);
+               if (fBrowserLikeLinksCheckBox.getSelection() && (stateMask == -1 ||
+     (stateMask & SWT.SHIFT) != 0)) {
+                       if (stateMask == -1)
+                               fBrowserLikeLinksKeyModifierStatus= new StatusInfo(IStatus.ERROR,
+     PreferencesMessages.getFormattedString("JavaEditorPreferencePage.navigation.modifierIsNotValid",
+     modifiers)); //$NON-NLS-1$
+                       else
+                               fBrowserLikeLinksKeyModifierStatus= new StatusInfo(IStatus.ERROR,
+     PreferencesMessages.getString("JavaEditorPreferencePage.navigation.shiftIsDisabled"));
+     //$NON-NLS-1$
+                       setValid(false);
+                       StatusUtil.applyToStatusLine(this, fBrowserLikeLinksKeyModifierStatus);
+               } else {
+                       fBrowserLikeLinksKeyModifierStatus= new StatusInfo();
+                       updateStatus(fBrowserLikeLinksKeyModifierStatus);
+               }
   }
 
-  //   private IStatus getBrowserLikeLinksKeyModifierStatus() {
-  //           if (fBrowserLikeLinksKeyModifierStatus == null)
-  //           fBrowserLikeLinksKeyModifierStatus= new StatusInfo();
-  //           return fBrowserLikeLinksKeyModifierStatus;
-  //   }
+       private IStatus getBrowserLikeLinksKeyModifierStatus() {
+               if (fBrowserLikeLinksKeyModifierStatus == null)
+               fBrowserLikeLinksKeyModifierStatus= new StatusInfo();
+               return fBrowserLikeLinksKeyModifierStatus;
+       }
   /**
    * Computes the state mask for the given modifier string.
    * 
@@ -1369,10 +1373,10 @@ public class JavaEditorPreferencePage extends PreferencePage implements IWorkben
     //$NON-NLS-1$
     fJavaEditorHoverConfigurationBlock = new JavaEditorHoverConfigurationBlock(this, fOverlayStore);
     item.setControl(fJavaEditorHoverConfigurationBlock.createControl(folder));
-    //                 item= new TabItem(folder, SWT.NONE);
-    //                 item.setText(PreferencesMessages.getString("JavaEditorPreferencePage.navigationTab.title"));
+    item = new TabItem(folder, SWT.NONE);
+    item.setText(PreferencesMessages.getString("JavaEditorPreferencePage.navigationTab.title"));
     // //$NON-NLS-1$
-    //                 item.setControl(createNavigationPage(folder));
+    item.setControl(createNavigationPage(folder));
     item = new TabItem(folder, SWT.NONE);
     item.setText(PreferencesMessages.getString("JavaEditorPreferencePage.folding.title")); //$NON-NLS-1$
     item.setControl(fFoldingConfigurationBlock.createControl(folder));
@@ -1467,7 +1471,7 @@ public class JavaEditorPreferencePage extends PreferencePage implements IWorkben
     //         fCompletionInsertsRadioButton.setSelection(completionInserts);
     //         fCompletionOverwritesRadioButton.setSelection(! completionInserts);
     //         
-    //         fBrowserLikeLinksKeyModifierText.setEnabled(fBrowserLikeLinksCheckBox.getSelection());
+    fBrowserLikeLinksKeyModifierText.setEnabled(fBrowserLikeLinksCheckBox.getSelection());
     //         boolean markOccurrences=
     // fOverlayStore.getBoolean(PreferenceConstants.EDITOR_MARK_OCCURRENCES);
     //         fStickyOccurrencesButton.setEnabled(markOccurrences);
@@ -1505,8 +1509,8 @@ public class JavaEditorPreferencePage extends PreferencePage implements IWorkben
   public boolean performOk() {
     //         fJavaEditorHoverConfigurationBlock.performOk();
     fFoldingConfigurationBlock.performOk();
-    //         fOverlayStore.setValue(PreferenceConstants.EDITOR_BROWSER_LIKE_LINKS_KEY_MODIFIER_MASK,
-    // computeStateMask(fBrowserLikeLinksKeyModifierText.getText()));
+    fOverlayStore.setValue(PreferenceConstants.EDITOR_BROWSER_LIKE_LINKS_KEY_MODIFIER_MASK,
+    computeStateMask(fBrowserLikeLinksKeyModifierText.getText()));
     fOverlayStore.propagate();
     PHPeclipsePlugin.getDefault().savePluginPreferences();
     return true;
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/DocumentCharacterIterator.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/DocumentCharacterIterator.java
new file mode 100644 (file)
index 0000000..1aabb54
--- /dev/null
@@ -0,0 +1,200 @@
+/*******************************************************************************
+ * 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 java.text.CharacterIterator;
+
+import org.eclipse.jface.text.Assert;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+
+
+/**
+ * An <code>IDocument</code> based implementation of <code>CharacterIterator</code>.
+ * 
+ * @since 3.0
+ */
+public class DocumentCharacterIterator implements CharacterIterator, CharSequence {
+
+       private int fIndex= -1;
+       private final IDocument fDocument;
+       private final int fFirst;
+       private final int fLast;
+       
+       private void invariant() {
+               Assert.isTrue(fIndex >= fFirst);
+               Assert.isTrue(fIndex <= fLast);
+       }
+       
+       /**
+        * Creates an iterator for the entire sequence.
+        * 
+        * @param sequence the sequence backing this iterator
+        */
+       public DocumentCharacterIterator(IDocument sequence) {
+               this(sequence, 0);
+       }
+       
+       /**
+        * Creates an iterator.
+        * 
+        * @param sequence the sequence backing this iterator
+        * @param first the first character to consider
+        * @throws IllegalArgumentException if the indices are out of bounds
+        */
+       public DocumentCharacterIterator(IDocument sequence, int first) throws IllegalArgumentException {
+               this(sequence, first, sequence.getLength());
+       }
+
+       /**
+        * Creates an iterator.
+        * 
+        * @param sequence the sequence backing this iterator
+        * @param first the first character to consider
+        * @param last the last character index to consider
+        * @throws IllegalArgumentException if the indices are out of bounds
+        */
+       public DocumentCharacterIterator(IDocument sequence, int first, int last) throws IllegalArgumentException {
+               if (sequence == null)
+                       throw new NullPointerException();
+               if (first < 0 || first > last)
+                       throw new IllegalArgumentException();
+               if (last > sequence.getLength())
+                       throw new IllegalArgumentException();
+               fDocument= sequence;
+               fFirst= first;
+               fLast= last;
+               fIndex= first;
+               invariant();
+       }
+
+       /*
+        * @see java.text.CharacterIterator#first()
+        */
+       public char first() {
+               return setIndex(getBeginIndex());
+       }
+
+       /*
+        * @see java.text.CharacterIterator#last()
+        */
+       public char last() {
+               if (fFirst == fLast)
+                       return setIndex(getEndIndex());
+               else
+                       return setIndex(getEndIndex() - 1);
+       }
+
+       /*
+        * @see java.text.CharacterIterator#current()
+        */
+       public char current() {
+               if (fIndex >= fFirst && fIndex < fLast)
+                       try {
+                               return fDocument.getChar(fIndex);
+                       } catch (BadLocationException e) {
+                               // ignore
+                       }
+               return DONE;
+       }
+
+       /*
+        * @see java.text.CharacterIterator#next()
+        */
+       public char next() {
+               return setIndex(Math.min(fIndex + 1, getEndIndex()));
+       }
+
+       /*
+        * @see java.text.CharacterIterator#previous()
+        */
+       public char previous() {
+               if (fIndex > getBeginIndex()) {
+                       return setIndex(fIndex - 1);
+               } else {
+                       return DONE;
+               }
+       }
+
+       /*
+        * @see java.text.CharacterIterator#setIndex(int)
+        */
+       public char setIndex(int position) {
+               if (position >= getBeginIndex() && position <= getEndIndex())
+                       fIndex= position;
+               else
+                       throw new IllegalArgumentException();
+               
+               invariant();
+               return current();
+       }
+
+       /*
+        * @see java.text.CharacterIterator#getBeginIndex()
+        */
+       public int getBeginIndex() {
+               return fFirst;
+       }
+
+       /*
+        * @see java.text.CharacterIterator#getEndIndex()
+        */
+       public int getEndIndex() {
+               return fLast;
+       }
+
+       /*
+        * @see java.text.CharacterIterator#getIndex()
+        */
+       public int getIndex() {
+               return fIndex;
+       }
+
+       /*
+        * @see java.text.CharacterIterator#clone()
+        */
+       public Object clone() {
+               try {
+                       return super.clone();
+               } catch (CloneNotSupportedException e) {
+                       throw new InternalError();
+               }
+       }
+
+       /*
+        * @see java.lang.CharSequence#length()
+        */
+       public int length() {
+               return getEndIndex() - getBeginIndex();
+       }
+
+       /*
+        * @see java.lang.CharSequence#charAt(int)
+        */
+       public char charAt(int index) {
+               if (index >= getBeginIndex() && index <= getEndIndex())
+                       try {
+                               return fDocument.getChar(index);
+                       } catch (BadLocationException e) {
+                               // ignore and return DONE
+                               return DONE;
+                       }
+               else
+                       throw new IllegalArgumentException();
+       }
+
+       /*
+        * @see java.lang.CharSequence#subSequence(int, int)
+        */
+       public CharSequence subSequence(int start, int end) {
+               return new DocumentCharacterIterator(fDocument, getBeginIndex() + start, getBeginIndex() + start + end);
+       }
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/JavaBreakIterator.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/JavaBreakIterator.java
new file mode 100644 (file)
index 0000000..14a9b0b
--- /dev/null
@@ -0,0 +1,418 @@
+/*******************************************************************************
+ * 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 java.text.BreakIterator;
+import java.text.CharacterIterator;
+
+import org.eclipse.jface.text.Assert;
+
+
+/**
+ * A java break iterator. It returns all breaks, including before and after 
+ * whitespace, and it returns all camelcase breaks.
+ * <p>
+ * A line break may be any of "\n", "\r", "\r\n", "\n\r".
+ * </p>
+ * 
+ * @since 3.0
+ */
+public class JavaBreakIterator extends BreakIterator {
+
+       /**
+        * A run of common characters.
+        */
+       protected static abstract class Run {
+               /** The length of this run. */
+               protected int length;
+               
+               public Run() {
+                       init();
+               }
+               
+               /**
+                * Returns <code>true</code> if this run consumes <code>ch</code>,
+                * <code>false</code> otherwise. If <code>true</code> is returned,
+                * the length of the receiver is adjusted accordingly.
+                * 
+                * @param ch the character to test
+                * @return <code>true</code> if <code>ch</code> was consumed
+                */
+               protected boolean consume(char ch) {
+                       if (isValid(ch)) {
+                               length++;
+                               return true;
+                       }
+                       return false;
+               }
+               
+               /**
+                * Whether this run accepts that character; does not update state. Called
+                * from the default implementation of <code>consume</code>.
+                * 
+                * @param ch the character to test
+                * @return <code>true</code> if <code>ch</code> is accepted
+                */
+               protected abstract boolean isValid(char ch);
+               
+               /**
+                * Resets this run to the initial state.
+                */
+               protected void init() {
+                       length= 0;
+               }
+       }
+       
+       static final class Whitespace extends Run {
+               protected boolean isValid(char ch) {
+                       return Character.isWhitespace(ch) && ch != '\n' && ch != '\r';
+               }
+       }
+       
+       static final class LineDelimiter extends Run {
+               /** State: INIT -> delimiter -> EXIT. */
+               private char fState;
+               private static final char INIT= '\0';
+               private static final char EXIT= '\1';
+               
+               /*
+                * @see org.eclipse.jdt.internal.ui.text.JavaBreakIterator.Run#init()
+                */
+               protected void init() {
+                       super.init();
+                       fState= INIT;
+               }
+               
+               /*
+                * @see org.eclipse.jdt.internal.ui.text.JavaBreakIterator.Run#consume(char)
+                */
+               protected boolean consume(char ch) {
+                       if (!isValid(ch) || fState == EXIT)
+                               return false;
+                       
+                       if (fState == INIT) {
+                               fState= ch;
+                               length++;
+                               return true;
+                       } else if (fState != ch) {
+                               fState= EXIT;
+                               length++;
+                               return true;
+                       } else {
+                               return false;
+                       }
+               }
+               
+               protected boolean isValid(char ch) {
+                       return ch == '\n' || ch == '\r';
+               }
+       }
+       
+       static final class Identifier extends Run {
+               /*
+                * @see org.eclipse.jdt.internal.ui.text.JavaBreakIterator.Run#isValid(char)
+                */
+               protected boolean isValid(char ch) {
+                       return Character.isJavaIdentifierPart(ch);
+               }
+       }
+       
+       static final class CamelCaseIdentifier extends Run {
+               /* states */
+               private static final int S_INIT= 0;
+               private static final int S_LOWER= 1;
+               private static final int S_ONE_CAP= 2;
+               private static final int S_ALL_CAPS= 3;
+               private static final int S_EXIT= 4;
+               private static final int S_EXIT_MINUS_ONE= 5;
+
+               /* character types */
+               private static final int K_INVALID= 0;
+               private static final int K_LOWER= 1;
+               private static final int K_UPPER= 2;
+               private static final int K_OTHER= 3;
+               
+               private int fState;
+               
+               private final static int[][] MATRIX= new int[][] {
+                               // K_INVALID, K_LOWER,           K_UPPER,    K_OTHER
+                               {  S_EXIT,    S_LOWER,           S_ONE_CAP,  S_LOWER }, // S_INIT
+                               {  S_EXIT,    S_LOWER,           S_EXIT,     S_LOWER }, // S_LOWER
+                               {  S_EXIT,    S_LOWER,           S_ALL_CAPS, S_LOWER }, // S_ONE_CAP
+                               {  S_EXIT,    S_EXIT_MINUS_ONE,  S_ALL_CAPS, S_LOWER }, // S_ALL_CAPS
+               };
+               
+               /*
+                * @see org.eclipse.jdt.internal.ui.text.JavaBreakIterator.Run#init()
+                */
+               protected void init() {
+                       super.init();
+                       fState= S_INIT;
+               }
+               
+               /*
+                * @see org.eclipse.jdt.internal.ui.text.JavaBreakIterator.Run#consumes(char)
+                */
+               protected boolean consume(char ch) {
+                       int kind= getKind(ch);
+                       fState= MATRIX[fState][kind];
+                       switch (fState) {
+                               case S_LOWER:
+                               case S_ONE_CAP:
+                               case S_ALL_CAPS:
+                                       length++;
+                                       return true;
+                               case S_EXIT:
+                                       return false;
+                               case S_EXIT_MINUS_ONE:
+                                       length--;
+                                       return false;
+                               default:
+                                       Assert.isTrue(false);
+                                       return false;
+                       }
+               }
+               
+               /**
+                * Determines the kind of a character.
+                * 
+                * @param ch the character to test
+                */
+               private int getKind(char ch) {
+                       if (Character.isUpperCase(ch))
+                               return K_UPPER;
+                       if (Character.isLowerCase(ch))
+                               return K_LOWER;
+                       if (Character.isJavaIdentifierPart(ch)) // _, digits...
+                               return K_OTHER;
+                       return K_INVALID;
+               }
+
+               /*
+                * @see org.eclipse.jdt.internal.ui.text.JavaBreakIterator.Run#isValid(char)
+                */
+               protected boolean isValid(char ch) {
+                       return Character.isJavaIdentifierPart(ch);
+               }
+       }
+
+       static final class Other extends Run {
+               /*
+                * @see org.eclipse.jdt.internal.ui.text.JavaBreakIterator.Run#isValid(char)
+                */
+               protected boolean isValid(char ch) {
+                       return !Character.isWhitespace(ch) && !Character.isJavaIdentifierPart(ch);
+               }
+       }
+       
+       private static final Run WHITESPACE= new Whitespace();
+       private static final Run DELIMITER= new LineDelimiter();
+       private static final Run CAMELCASE= new CamelCaseIdentifier(); // new Identifier();
+       private static final Run OTHER= new Other();
+       
+       /** The platform break iterator (word instance) used as a base. */ 
+       protected final BreakIterator fIterator;
+       /** The text we operate on. */
+       protected CharSequence fText;
+       /** our current position for the stateful methods. */
+       private int fIndex;
+       
+       
+       /**
+        * Creates a new break iterator.
+        */
+       public JavaBreakIterator() {
+               fIterator= BreakIterator.getWordInstance();
+               fIndex= fIterator.current();
+       }
+
+       /*
+        * @see java.text.BreakIterator#current()
+        */
+       public int current() {
+               return fIndex;
+       }
+
+       /*
+        * @see java.text.BreakIterator#first()
+        */
+       public int first() {
+               fIndex= fIterator.first();
+               return fIndex;
+       }
+
+       /*
+        * @see java.text.BreakIterator#following(int)
+        */
+       public int following(int offset) {
+               // work around too eager IAEs in standard impl
+               if (offset == getText().getEndIndex())
+                       return DONE;
+               
+               int next= fIterator.following(offset);
+               if (next == DONE)
+                       return DONE;
+               
+               // TODO deal with complex script word boundaries
+               // Math.min(offset + run.length, next) does not work
+               // since wordinstance considers _ as boundaries
+               // seems to work fine, however
+               Run run= consumeRun(offset);
+               return offset + run.length;
+               
+       }
+
+       /**
+        * Consumes a run of characters at the limits of which we introduce a break.
+        * @param offset the offset to start at
+        * @return the run that was consumed
+        */
+       private Run consumeRun(int offset) {
+               // assert offset < length
+               
+               char ch= fText.charAt(offset);
+               int length= fText.length();
+               Run run= getRun(ch);
+               while (run.consume(ch) && offset < length - 1) {
+                       offset++;
+                       ch= fText.charAt(offset);
+               }
+               
+               return run;
+       }
+
+       /**
+        * Retunrs a run based on a character.
+        * 
+        * @param ch the character to test
+        * @return the correct character given <code>ch</code>
+        */
+       private Run getRun(char ch) {
+               Run run;
+               if (WHITESPACE.isValid(ch))
+                       run= WHITESPACE;
+               else if (DELIMITER.isValid(ch))
+                       run= DELIMITER;
+               else if (CAMELCASE.isValid(ch))
+                       run= CAMELCASE;
+               else if (OTHER.isValid(ch))
+                       run= OTHER;
+               else {
+                       Assert.isTrue(false);
+                       return null;
+               }
+               
+               run.init();
+               return run;
+       }
+       
+       /*
+        * @see java.text.BreakIterator#getText()
+        */
+       public CharacterIterator getText() {
+               return fIterator.getText();
+       }
+
+       /*
+        * @see java.text.BreakIterator#isBoundary(int)
+        */
+       public boolean isBoundary(int offset) {
+        if (offset == getText().getBeginIndex())
+            return true;
+        else
+            return following(offset - 1) == offset;
+       }
+
+       /*
+        * @see java.text.BreakIterator#last()
+        */
+       public int last() {
+               fIndex= fIterator.last();
+               return fIndex;
+       }
+
+       /*
+        * @see java.text.BreakIterator#next()
+        */
+       public int next() {
+               fIndex= following(fIndex);
+               return fIndex;
+       }
+
+       /*
+        * @see java.text.BreakIterator#next(int)
+        */
+       public int next(int n) {
+               return fIterator.next(n);
+       }
+       
+       /*
+        * @see java.text.BreakIterator#preceding(int)
+        */
+       public int preceding(int offset) {
+               if (offset == getText().getBeginIndex())
+                       return DONE;
+               
+               if (isBoundary(offset - 1))
+                       return offset - 1;
+
+               int previous= offset - 1;
+               do {
+                       previous= fIterator.preceding(previous);
+               } while (!isBoundary(previous));
+               
+               int last= DONE;
+               while (previous < offset) {
+                       last= previous;
+                       previous= following(previous);
+               }
+               
+               return last;
+       }
+
+       /*
+        * @see java.text.BreakIterator#previous()
+        */
+       public int previous() {
+               fIndex= preceding(fIndex);
+               return fIndex;
+       }
+
+       /*
+        * @see java.text.BreakIterator#setText(java.lang.String)
+        */
+       public void setText(String newText) {
+               setText((CharSequence) newText);
+       }
+
+       /**
+        * Creates a break iterator given a char sequence.
+        * @param newText the new text
+        */
+       public void setText(CharSequence newText) {
+               fText= newText;
+               fIterator.setText(new SequenceCharacterIterator(newText));
+               first();
+       }
+
+       /*
+        * @see java.text.BreakIterator#setText(java.text.CharacterIterator)
+        */
+       public void setText(CharacterIterator newText) {
+               if (newText instanceof CharSequence) {
+                       fText= (CharSequence) newText;
+                       fIterator.setText(newText);
+                       first();
+               } else {
+                       throw new UnsupportedOperationException("CharacterIterator not supported"); //$NON-NLS-1$
+               }
+       }
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/JavaWordIterator.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/JavaWordIterator.java
new file mode 100644 (file)
index 0000000..cca37ca
--- /dev/null
@@ -0,0 +1,221 @@
+/*******************************************************************************
+ * 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 java.text.BreakIterator;
+import java.text.CharacterIterator;
+
+import org.eclipse.jface.text.Assert;
+
+
+/**
+ * Breaks java text into word starts, also stops at line start and end. No 
+ * direction dependency.
+ *  
+ * @since 3.0
+ */
+public class JavaWordIterator extends BreakIterator {
+       
+       /** 
+        * The underlying java break iterator. It returns all breaks, including
+        * before and after every whitespace.
+        */
+       private JavaBreakIterator fIterator;
+       /** The current index for the stateful operations. */
+       private int fIndex;
+       
+       /**
+        * Creates a new word iterator.
+        */
+       public JavaWordIterator() {
+               fIterator= new JavaBreakIterator();
+               first();
+       }
+
+       /*
+        * @see java.text.BreakIterator#first()
+        */
+       public int first() {
+               fIndex= fIterator.first();
+               return fIndex;
+       }
+
+       /*
+        * @see java.text.BreakIterator#last()
+        */
+       public int last() {
+               fIndex= fIterator.last();
+               return fIndex;
+       }
+
+       /*
+        * @see java.text.BreakIterator#next(int)
+        */
+       public int next(int n) {
+               int next= 0;
+               while (--n > 0 && next != DONE) {
+                       next= next();
+               }
+               return next;
+       }
+
+       /*
+        * @see java.text.BreakIterator#next()
+        */
+       public int next() {
+               fIndex= following(fIndex);
+               return fIndex;
+       }
+
+       /*
+        * @see java.text.BreakIterator#previous()
+        */
+       public int previous() {
+               fIndex= preceding(fIndex);
+               return fIndex;
+       }
+       
+       
+       /*
+        * @see java.text.BreakIterator#preceding(int)
+        */
+       public int preceding(int offset) {
+               int first= fIterator.preceding(offset);
+               if (isWhitespace(first, offset)) {
+                       int second= fIterator.preceding(first);
+                       if (second != DONE && !isDelimiter(second, first))
+                               return second;
+               }
+               return first;
+       }
+
+       /*
+        * @see java.text.BreakIterator#following(int)
+        */
+       public int following(int offset) {
+               int first= fIterator.following(offset);
+               if (eatFollowingWhitespace(offset, first)) {
+                       int second= fIterator.following(first);
+                       if (isWhitespace(first, second))
+                               return second;
+               }
+               return first;
+       }
+       
+       private boolean eatFollowingWhitespace(int offset, int exclusiveEnd) {
+               if (exclusiveEnd == DONE || offset == DONE)
+                       return false;
+               
+               if (isWhitespace(offset, exclusiveEnd))
+                       return false;
+               if (isDelimiter(offset, exclusiveEnd))
+                       return false;
+               
+               return true;
+       }
+       
+       /**
+        * Returns <code>true</code> if the given sequence into the underlying text
+        * represents a delimiter, <code>false</code> otherwise.
+        * 
+        * @param offset the offset
+        * @param exclusiveEnd the end offset
+        * @return <code>true</code> if the given range is a delimiter
+        */
+       private boolean isDelimiter(int offset, int exclusiveEnd) {
+               if (exclusiveEnd == DONE || offset == DONE)
+                       return false;
+               
+               Assert.isTrue(offset >= 0);
+               Assert.isTrue(exclusiveEnd <= getText().getEndIndex());
+               Assert.isTrue(exclusiveEnd > offset);
+               
+               CharSequence seq= fIterator.fText;
+               
+               while (offset < exclusiveEnd) {
+                       char ch= seq.charAt(offset);
+                       if (ch != '\n' && ch != '\r')
+                               return false;
+                       offset++;
+               }
+               
+               return true;
+       }
+
+       /**
+        * Returns <code>true</code> if the given sequence into the underlying text
+        * represents whitespace, but not a delimiter, <code>false</code> otherwise.
+        * 
+        * @param offset the offset
+        * @param exclusiveEnd the end offset
+        * @return <code>true</code> if the given range is whitespace
+        */
+       private boolean isWhitespace(int offset, int exclusiveEnd) {
+               if (exclusiveEnd == DONE || offset == DONE)
+                       return false;
+               
+               Assert.isTrue(offset >= 0);
+               Assert.isTrue(exclusiveEnd <= getText().getEndIndex());
+               Assert.isTrue(exclusiveEnd > offset);
+               
+               CharSequence seq= fIterator.fText;
+               
+               while (offset < exclusiveEnd) {
+                       char ch= seq.charAt(offset);
+                       if (!Character.isWhitespace(ch))
+                               return false;
+                       if (ch == '\n' || ch == '\r')
+                               return false;
+                       offset++;
+               }
+               
+               return true;
+       }
+
+       /*
+        * @see java.text.BreakIterator#current()
+        */
+       public int current() {
+               return fIndex;
+       }
+
+       /*
+        * @see java.text.BreakIterator#getText()
+        */
+       public CharacterIterator getText() {
+               return fIterator.getText();
+       }
+       
+       /**
+        * Sets the text as <code>CharSequence</code>.
+        * @param newText the new text
+        */
+       public void setText(CharSequence newText) {
+               fIterator.setText(newText);
+               first();
+       }
+
+       /*
+        * @see java.text.BreakIterator#setText(java.text.CharacterIterator)
+        */
+       public void setText(CharacterIterator newText) {
+               fIterator.setText(newText);
+               first();
+       }
+       
+       /*
+        * @see java.text.BreakIterator#setText(java.lang.String)
+        */
+       public void setText(String newText) {
+               setText((CharSequence) newText);
+       }
+
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/SequenceCharacterIterator.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/SequenceCharacterIterator.java
new file mode 100644 (file)
index 0000000..7613b77
--- /dev/null
@@ -0,0 +1,166 @@
+/*******************************************************************************
+ * 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 java.text.CharacterIterator;
+
+import org.eclipse.jface.text.Assert;
+
+
+/**
+ * A <code>CharSequence</code> based implementation of <code>CharacterIterator</code>.
+ * 
+ * @since 3.0
+ */
+public class SequenceCharacterIterator implements CharacterIterator {
+
+       private int fIndex= -1;
+       private final CharSequence fSequence;
+       private final int fFirst;
+       private final int fLast;
+       
+       private void invariant() {
+               Assert.isTrue(fIndex >= fFirst);
+               Assert.isTrue(fIndex <= fLast);
+       }
+       
+       /**
+        * Creates an iterator for the entire sequence.
+        * 
+        * @param sequence the sequence backing this iterator
+        */
+       public SequenceCharacterIterator(CharSequence sequence) {
+               this(sequence, 0);
+       }
+       
+       /**
+        * Creates an iterator.
+        * 
+        * @param sequence the sequence backing this iterator
+        * @param first the first character to consider
+        * @throws IllegalArgumentException if the indices are out of bounds
+        */
+       public SequenceCharacterIterator(CharSequence sequence, int first) throws IllegalArgumentException {
+               this(sequence, first, sequence.length());
+       }
+
+       /**
+        * Creates an iterator.
+        * 
+        * @param sequence the sequence backing this iterator
+        * @param first the first character to consider
+        * @param last the last character index to consider
+        * @throws IllegalArgumentException if the indices are out of bounds
+        */
+       public SequenceCharacterIterator(CharSequence sequence, int first, int last) throws IllegalArgumentException {
+               if (sequence == null)
+                       throw new NullPointerException();
+               if (first < 0 || first > last)
+                       throw new IllegalArgumentException();
+               if (last > sequence.length())
+                       throw new IllegalArgumentException();
+               fSequence= sequence;
+               fFirst= first;
+               fLast= last;
+               fIndex= first;
+               invariant();
+       }
+
+       /*
+        * @see java.text.CharacterIterator#first()
+        */
+       public char first() {
+               return setIndex(getBeginIndex());
+       }
+
+       /*
+        * @see java.text.CharacterIterator#last()
+        */
+       public char last() {
+               if (fFirst == fLast)
+                       return setIndex(getEndIndex());
+               else
+                       return setIndex(getEndIndex() - 1);
+       }
+
+       /*
+        * @see java.text.CharacterIterator#current()
+        */
+       public char current() {
+               if (fIndex >= fFirst && fIndex < fLast)
+                       return fSequence.charAt(fIndex);
+               else
+                       return DONE;
+       }
+
+       /*
+        * @see java.text.CharacterIterator#next()
+        */
+       public char next() {
+               return setIndex(Math.min(fIndex + 1, getEndIndex()));
+       }
+
+       /*
+        * @see java.text.CharacterIterator#previous()
+        */
+       public char previous() {
+               if (fIndex > getBeginIndex()) {
+                       return setIndex(fIndex - 1);
+               } else {
+                       return DONE;
+               }
+       }
+
+       /*
+        * @see java.text.CharacterIterator#setIndex(int)
+        */
+       public char setIndex(int position) {
+               if (position >= getBeginIndex() && position <= getEndIndex())
+                       fIndex= position;
+               else
+                       throw new IllegalArgumentException();
+               
+               invariant();
+               return current();
+       }
+
+       /*
+        * @see java.text.CharacterIterator#getBeginIndex()
+        */
+       public int getBeginIndex() {
+               return fFirst;
+       }
+
+       /*
+        * @see java.text.CharacterIterator#getEndIndex()
+        */
+       public int getEndIndex() {
+               return fLast;
+       }
+
+       /*
+        * @see java.text.CharacterIterator#getIndex()
+        */
+       public int getIndex() {
+               return fIndex;
+       }
+
+       /*
+        * @see java.text.CharacterIterator#clone()
+        */
+       public Object clone() {
+               try {
+                       return super.clone();
+               } catch (CloneNotSupportedException e) {
+                       throw new InternalError();
+               }
+       }
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/java/JavaExpandHover.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/java/JavaExpandHover.java
new file mode 100644 (file)
index 0000000..fc4e006
--- /dev/null
@@ -0,0 +1,188 @@
+/*******************************************************************************
+ * 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 java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+import net.sourceforge.phpdt.internal.ui.PHPUiImages;
+import net.sourceforge.phpeclipse.PHPeclipsePlugin;
+import net.sourceforge.phpeclipse.phpeditor.JavaMarkerAnnotation;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IInformationControlExtension2;
+import org.eclipse.jface.text.Position;
+import org.eclipse.jface.text.source.Annotation;
+import org.eclipse.jface.text.source.CompositeRuler;
+import org.eclipse.jface.text.source.IAnnotationAccess;
+import org.eclipse.jface.text.source.IAnnotationAccessExtension;
+import org.eclipse.jface.text.source.IAnnotationModel;
+import org.eclipse.jface.text.source.IAnnotationPresentation;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.jface.text.source.ImageUtilities;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.ui.internal.texteditor.AnnotationExpandHover;
+import org.eclipse.ui.internal.texteditor.AnnotationExpansionControl;
+import org.eclipse.ui.internal.texteditor.AnnotationExpansionControl.AnnotationHoverInput;
+import org.eclipse.ui.texteditor.AnnotationPreference;
+import org.eclipse.ui.texteditor.AnnotationPreferenceLookup;
+
+/**
+ * 
+ * 
+ * @since 3.0
+ */
+public class JavaExpandHover extends AnnotationExpandHover {
+       
+       /** Id of the no breakpoint fake annotation */
+       public static final String NO_BREAKPOINT_ANNOTATION= "org.eclipse.jdt.internal.ui.NoBreakpointAnnotation"; //$NON-NLS-1$
+
+       private static class NoBreakpointAnnotation extends Annotation implements IAnnotationPresentation {
+               
+               public NoBreakpointAnnotation() {
+                       super(NO_BREAKPOINT_ANNOTATION, false, JavaHoverMessages.getString("NoBreakpointAnnotation.addBreakpoint")); //$NON-NLS-1$
+               }
+               
+               /*
+                * @see org.eclipse.jface.text.source.IAnnotationPresentation#paint(org.eclipse.swt.graphics.GC, org.eclipse.swt.widgets.Canvas, org.eclipse.swt.graphics.Rectangle)
+                */
+               public void paint(GC gc, Canvas canvas, Rectangle bounds) {
+                       // draw affordance so the user know she can click here to get a breakpoint
+                       Image fImage= PHPUiImages.get(PHPUiImages.IMG_FIELD_PUBLIC);
+                       ImageUtilities.drawImage(fImage, gc, canvas, bounds, SWT.CENTER);
+               }
+               
+               /*
+                * @see org.eclipse.jface.text.source.IAnnotationPresentation#getLayer()
+                */
+               public int getLayer() {
+                       return IAnnotationPresentation.DEFAULT_LAYER;
+               }
+       }
+       
+       private AnnotationPreferenceLookup fLookup= new AnnotationPreferenceLookup();
+       private IPreferenceStore fStore= PHPeclipsePlugin.getDefault().getCombinedPreferenceStore();
+       
+       public JavaExpandHover(CompositeRuler ruler, IAnnotationAccess access, IDoubleClickListener doubleClickListener) {
+               super(ruler, access, doubleClickListener);
+       }
+       
+       /*
+        * @see org.eclipse.ui.internal.texteditor.AnnotationExpandHover#getHoverInfoForLine(org.eclipse.jface.text.source.ISourceViewer, int)
+        */
+       protected Object getHoverInfoForLine(final ISourceViewer viewer, final int line) {
+               IAnnotationModel model= viewer.getAnnotationModel();
+               IDocument document= viewer.getDocument();
+               
+               if (model == null)
+                       return null;
+               
+               List exact= new ArrayList();
+               HashMap messagesAtPosition= new HashMap();
+               
+               Iterator e= model.getAnnotationIterator();
+               while (e.hasNext()) {
+                       Annotation annotation= (Annotation) e.next();
+                       
+                       // don't prune deleted ones as we don't get many errors this way
+//                     if (annotation.isMarkedDeleted())
+//                             continue;
+                       
+                       if (fAnnotationAccess instanceof IAnnotationAccessExtension)
+                               if (!((IAnnotationAccessExtension)fAnnotationAccess).isPaintable(annotation))
+                                       continue;
+                               
+// TODO need a new check the this one is not OK
+//
+//                     if (annotation instanceof IJavaAnnotation && annotation instanceof IAnnotationPresentation)
+//                             if (((IJavaAnnotation) annotation).getImage(display) == null)
+//                                     continue;
+                               
+                       AnnotationPreference pref= fLookup.getAnnotationPreference(annotation);
+                       if (pref != null) {
+                               String key= pref.getVerticalRulerPreferenceKey();
+                               if (key != null && !fStore.getBoolean(key))
+                                       continue;
+                       }
+                       
+                       Position position= model.getPosition(annotation);
+                       if (position == null)
+                               continue;
+                       
+                       if (compareRulerLine(position, document, line) == 1) {
+                               
+                               if (isDuplicateMessage(messagesAtPosition, position, annotation.getText()))
+                                       continue;
+                               
+                               exact.add(annotation);
+                       }
+               }
+               
+               sort(exact, model);
+               
+               if (exact.size() > 0)
+                       setLastRulerMouseLocation(viewer, line);
+               
+               if (exact.size() > 0) {
+                       Annotation first= (Annotation) exact.get(0);
+                       if (!isBreakpointAnnotation(first))
+                               exact.add(0, new NoBreakpointAnnotation());
+               }
+               
+               if (exact.size() <= 1)
+//             if (exact.size() < 1)
+                       return null;
+               
+               AnnotationHoverInput input= new AnnotationHoverInput();
+               input.fAnnotations= (Annotation[]) exact.toArray(new Annotation[0]);
+               input.fViewer= viewer;
+               input.fRulerInfo= fCompositeRuler;
+               input.fAnnotationListener= fgListener;
+               input.fDoubleClickListener= fDblClickListener;
+               input.redoAction= new AnnotationExpansionControl.ICallback() {
+
+                       public void run(IInformationControlExtension2 control) {
+                               control.setInput(getHoverInfoForLine(viewer, line));
+                       }
+                       
+               };
+               input.model= model;
+               
+               return input;
+       }
+       
+       /*
+        * @see org.eclipse.ui.internal.texteditor.AnnotationExpandHover#getOrder(org.eclipse.jface.text.source.Annotation)
+        */
+       protected int getOrder(Annotation annotation) {
+               if (isBreakpointAnnotation(annotation)) //$NON-NLS-1$
+                       return 1000;
+               else
+                       return super.getOrder(annotation);
+       }
+
+       private boolean isBreakpointAnnotation(Annotation a) {
+               if (a instanceof JavaMarkerAnnotation) {
+                       JavaMarkerAnnotation jma= (JavaMarkerAnnotation) a;
+                       // HACK to get breakpoints to show up first
+                       return jma.getType().equals("org.eclipse.debug.core.breakpoint"); //$NON-NLS-1$
+               }
+               return false;
+       }
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/java/JavaHoverMessages.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/java/JavaHoverMessages.java
new file mode 100644 (file)
index 0000000..c4f9335
--- /dev/null
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * 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 java.text.MessageFormat;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+class JavaHoverMessages {
+
+       private static final String RESOURCE_BUNDLE= JavaHoverMessages.class.getName();
+
+       private static ResourceBundle fgResourceBundle= ResourceBundle.getBundle(RESOURCE_BUNDLE);
+
+       private JavaHoverMessages() {
+       }
+
+       public static String getString(String key) {
+               try {
+                       return fgResourceBundle.getString(key);
+               } catch (MissingResourceException e) {
+                       return "!" + key + "!";//$NON-NLS-2$ //$NON-NLS-1$
+               }
+       }
+       /**
+        * Gets a string from the resource bundle and formats it with the argument
+        * 
+        * @param key   the string used to get the bundle value, must not be null
+        * @since 3.0
+        */
+       public static String getFormattedString(String key, Object arg) {
+               String format= null;
+               try {
+                       format= fgResourceBundle.getString(key);
+               } catch (MissingResourceException e) {
+                       return "!" + key + "!";//$NON-NLS-2$ //$NON-NLS-1$
+               }
+               if (arg == null)
+                       arg= ""; //$NON-NLS-1$
+               return MessageFormat.format(format, new Object[] { arg });
+       }
+       /**
+        * Gets a string from the resource bundle and formats it with the arguments
+        * 
+        * @param key   the string used to get the bundle value, must not be null
+        * @since 3.0
+        */
+       public static String getFormattedString(String key, Object arg1, Object arg2) {
+               String format= null;
+               try {
+                       format= fgResourceBundle.getString(key);
+               } catch (MissingResourceException e) {
+                       return "!" + key + "!";//$NON-NLS-2$ //$NON-NLS-1$
+               }
+               if (arg1 == null)
+                       arg1= ""; //$NON-NLS-1$
+               if (arg2 == null)
+                       arg2= ""; //$NON-NLS-1$
+               return MessageFormat.format(format, new Object[] { arg1, arg2 });
+       }
+       
+       /**
+        * Gets a string from the resource bundle and formats it with the argument
+        * 
+        * @param key   the string used to get the bundle value, must not be null
+        * @since 3.0
+        */
+       public static String getFormattedString(String key, boolean arg) {
+               String format= null;
+               try {
+                       format= fgResourceBundle.getString(key);
+               } catch (MissingResourceException e) {
+                       return "!" + key + "!";//$NON-NLS-2$ //$NON-NLS-1$
+               }
+               return MessageFormat.format(format, new Object[] { new Boolean(arg) });
+       }
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/java/JavaHoverMessages.properties b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/java/JavaHoverMessages.properties
new file mode 100644 (file)
index 0000000..01f64aa
--- /dev/null
@@ -0,0 +1,18 @@
+###############################################################################
+# 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
+###############################################################################
+
+TypeHover.more_to_come=\ ...
+
+JavaTextHover.createTextHover= Could not create PHP text hover
+
+JavaTextHover.makeStickyHint= Press ''{0}'' for focus.
+
+NoBreakpointAnnotation.addBreakpoint= Add a breakpoint
index 01b7157..c2b5815 100644 (file)
@@ -514,7 +514,8 @@ public class PreferenceConstants {
    * Value is of type <code>Int</code>: positive int value specifying the number of spaces per tab.
    * </p>
    */
-  public final static String EDITOR_TAB_WIDTH = AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TAB_WIDTH; //"net.sourceforge.phpdt.ui.editor.tab.width"; //$NON-NLS-1$
+  public final static String EDITOR_TAB_WIDTH = AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TAB_WIDTH; //"net.sourceforge.phpdt.ui.editor.tab.width";
+                                                                                                                 // //$NON-NLS-1$
 
   /**
    * A named preference that controls whether the outline view selection should stay in sync with with the element at the current
@@ -2107,6 +2108,17 @@ public class PreferenceConstants {
   public static final String TEMPLATES_USE_CODEFORMATTER = "net.sourceforge.phpdt.ui.template.format"; //$NON-NLS-1$
 
   /**
+   * A named preference that controls whether annotation roll over is used or not.
+   * <p>
+   * Value is of type <code>Boolean</code>. If <code>true<code> the annotation ruler column
+   * uses a roll over to display multiple annotations
+   * </p>
+   * 
+   * @since 3.0
+   */
+  public static final String EDITOR_ANNOTATION_ROLL_OVER = "editor_annotation_roll_over"; //$NON-NLS-1$
+
+  /**
    * A named preference that controls the key modifier mask for browser like links. The value is only used if the value of
    * <code>EDITOR_BROWSER_LIKE_LINKS</code> cannot be resolved to valid SWT modifier bits.
    * <p>
@@ -2240,25 +2252,8 @@ public class PreferenceConstants {
     // must add here to guarantee that it is the first in the listener list
     store.addPropertyChangeListener(PHPeclipsePlugin.getDefault().getMemberOrderPreferenceCache());
 
-    // PHPEditorPreferencePage
-    /*
-     * Ensure that the display is accessed only in the UI thread. Ensure that there are no side effects of switching the thread.
-     */
-    final RGB[] rgbs = new RGB[3];
-    final Display display = Display.getDefault();
-    display.syncExec(new Runnable() {
-      public void run() {
-        Color c = display.getSystemColor(SWT.COLOR_GRAY);
-        rgbs[0] = c.getRGB();
-        c = display.getSystemColor(SWT.COLOR_LIST_FOREGROUND);
-        rgbs[1] = c.getRGB();
-        c = display.getSystemColor(SWT.COLOR_LIST_BACKGROUND);
-        rgbs[2] = c.getRGB();
-      }
-    });
-
     store.setDefault(PreferenceConstants.EDITOR_MATCHING_BRACKETS, true);
-    PreferenceConverter.setDefault(store, PreferenceConstants.EDITOR_MATCHING_BRACKETS_COLOR, rgbs[0]);
+    PreferenceConverter.setDefault(store, PreferenceConstants.EDITOR_MATCHING_BRACKETS_COLOR, new RGB(192, 192,192));
 
     store.setDefault(PreferenceConstants.EDITOR_CURRENT_LINE, true);
     PreferenceConverter.setDefault(store, PreferenceConstants.EDITOR_CURRENT_LINE_COLOR, new RGB(225, 235, 224));
@@ -2308,10 +2303,8 @@ public class PreferenceConstants {
     PreferenceConverter.setDefault(store, PreferenceConstants.EDITOR_LINKED_POSITION_COLOR, new RGB(0, 200, 100));
     PreferenceConverter.setDefault(store, PreferenceConstants.EDITOR_LINK_COLOR, new RGB(0, 0, 255));
 
-    PreferenceConverter.setDefault(store, PreferenceConstants.EDITOR_FOREGROUND_COLOR, rgbs[1]);
     store.setDefault(PreferenceConstants.EDITOR_FOREGROUND_DEFAULT_COLOR, true);
 
-    PreferenceConverter.setDefault(store, PreferenceConstants.EDITOR_BACKGROUND_COLOR, rgbs[2]);
     store.setDefault(PreferenceConstants.EDITOR_BACKGROUND_DEFAULT_COLOR, true);
 
     store.setDefault(PreferenceConstants.EDITOR_TAB_WIDTH, 4);
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/actions/OpenEditorActionGroup.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/actions/OpenEditorActionGroup.java
new file mode 100644 (file)
index 0000000..067a9f1
--- /dev/null
@@ -0,0 +1,155 @@
+/*******************************************************************************
+ * 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.ui.actions;
+
+import net.sourceforge.phpdt.internal.ui.actions.ActionMessages;
+import net.sourceforge.phpdt.ui.IContextMenuConstants;
+import net.sourceforge.phpeclipse.actions.PHPOpenDeclarationAction;
+import net.sourceforge.phpeclipse.actions.PHPOpenDeclarationEditorAction;
+import net.sourceforge.phpeclipse.phpeditor.PHPEditor;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbenchSite;
+import org.eclipse.ui.actions.ActionGroup;
+import org.eclipse.ui.actions.OpenWithMenu;
+
+/**
+ * Action group that adds the actions opening a new editor to the 
+ * context menu and the action bar's navigate menu.
+ *
+ * <p>
+ * This class may be instantiated; it is not intended to be subclassed.
+ * </p>
+ * 
+ * @since 2.0
+ */
+public class OpenEditorActionGroup extends ActionGroup {
+
+       private IWorkbenchSite fSite;
+       private boolean fIsEditorOwner;
+       private PHPOpenDeclarationAction fOpen;
+
+       /**
+        * Creates a new <code>OpenActionGroup</code>. The group requires
+        * that the selection provided by the part's selection provider is of type <code>
+        * org.eclipse.jface.viewers.IStructuredSelection</code>.
+        * 
+        * @param part the view part that owns this action group
+        */
+       public OpenEditorActionGroup(IViewPart part) {
+               fSite= part.getSite();
+               fOpen= new PHPOpenDeclarationAction(fSite);
+               fOpen.setActionDefinitionId(PHPEditorActionDefinitionIds.OPEN_EDITOR);
+               initialize(fSite.getSelectionProvider());
+       }
+       
+       /**
+        * Note: This constructor is for internal use only. Clients should not call this constructor.
+        */
+       public OpenEditorActionGroup(PHPEditor part) {
+               fIsEditorOwner= true;
+               fOpen= new PHPOpenDeclarationAction(part);
+               fOpen.setActionDefinitionId(PHPEditorActionDefinitionIds.OPEN_EDITOR);
+               part.setAction("OpenEditor", fOpen); //$NON-NLS-1$
+               fSite= part.getEditorSite();
+               initialize(fSite.getSelectionProvider());
+       }
+
+       /**
+        * Returns the open action managed by this action group. 
+        * 
+        * @return the open action. Returns <code>null</code> if the group
+        *      doesn't provide any open action
+        */
+       public IAction getOpenAction() {
+               return fOpen;
+       }
+
+       private void initialize(ISelectionProvider provider) {
+               ISelection selection= provider.getSelection();
+               fOpen.update(selection);
+               if (!fIsEditorOwner) {
+                       provider.addSelectionChangedListener(fOpen);
+               }
+       }
+
+       /* (non-Javadoc)
+        * Method declared in ActionGroup
+        */
+       public void fillActionBars(IActionBars actionBar) {
+               super.fillActionBars(actionBar);
+               setGlobalActionHandlers(actionBar);
+       }
+       
+       /* (non-Javadoc)
+        * Method declared in ActionGroup
+        */
+       public void fillContextMenu(IMenuManager menu) {
+               super.fillContextMenu(menu);
+               appendToGroup(menu, fOpen);
+               if (!fIsEditorOwner) {
+                       addOpenWithMenu(menu);
+               }
+       }
+
+       /*
+        * @see ActionGroup#dispose()
+        */
+       public void dispose() {
+               ISelectionProvider provider= fSite.getSelectionProvider();
+               provider.removeSelectionChangedListener(fOpen);
+               super.dispose();
+       }
+       
+       private void setGlobalActionHandlers(IActionBars actionBars) {
+               actionBars.setGlobalActionHandler(PHPdtActionConstants.OPEN, fOpen);
+       }
+       
+       private void appendToGroup(IMenuManager menu, IAction action) {
+               if (action.isEnabled())
+                       menu.appendToGroup(IContextMenuConstants.GROUP_OPEN, action);
+       }
+       
+       private void addOpenWithMenu(IMenuManager menu) {
+               ISelection selection= getContext().getSelection();
+               if (selection.isEmpty() || !(selection instanceof IStructuredSelection))
+                       return;
+               IStructuredSelection ss= (IStructuredSelection)selection;
+               if (ss.size() != 1)
+                       return;
+
+               Object o= ss.getFirstElement();
+               if (!(o instanceof IAdaptable))
+                       return;
+
+               IAdaptable element= (IAdaptable)o;
+               Object resource= element.getAdapter(IResource.class);
+               if (!(resource instanceof IFile))
+                       return; 
+
+               // Create a menu flyout.
+               IMenuManager submenu= new MenuManager(ActionMessages.getString("OpenWithMenu.label")); //$NON-NLS-1$
+               submenu.add(new OpenWithMenu(fSite.getPage(), (IFile) resource));
+
+               // Add the submenu.
+               menu.appendToGroup(IContextMenuConstants.GROUP_OPEN, submenu);
+       }
+}
index 1e70b6f..324b300 100644 (file)
@@ -17,7 +17,7 @@ public interface PHPEditorActionDefinitionIds {
    * Action definition ID of the navigate -> open action
    * (value <code>"org.phpeclipse.phpdt.ui.edit.text.php.open.editor"</code>).
    */
-  public static final String OPEN_EDITOR = "net.sourceforge.phpeclipse.ui.edit.text.php.open.editor"; //$NON-NLS-1$
+  public static final String OPEN_EDITOR = "net.sourceforge.phpeclipse.ui.edit.text.java.open.editor"; //$NON-NLS-1$
   /**
         * Action definition ID of the toggle presentation toolbar button action
         * (value <code>"org.eclipse.jdt.ui.edit.text.java.toggle.presentation"</code>).
index 3f48e2b..a556aef 100644 (file)
@@ -90,7 +90,7 @@ public class IncludesScanner implements ITerminalSymbols {
     String identifier;
     int counter = 0;
 
-    Scanner scanner = new Scanner(false, false, false, false, true, null, null);
+    Scanner scanner = new Scanner(false, false, false, false, true, null, null, true /*taskCaseSensitive*/);
     scanner.setSource(charArray);
     scanner.setPHPMode(false);
     int token = getNextToken(scanner);
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/actions/OpenDeclarationEditorAction.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/actions/OpenDeclarationEditorAction.java
new file mode 100644 (file)
index 0000000..aa7e725
--- /dev/null
@@ -0,0 +1,263 @@
+/***********************************************************************************************************************************
+ * Copyright (c) 2000, 2002 IBM Corp. 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: www.phpeclipse.de
+ **********************************************************************************************************************************/
+package net.sourceforge.phpeclipse.actions;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import net.sourceforge.phpdt.internal.ui.util.PHPFileUtil;
+import net.sourceforge.phpeclipse.PHPeclipsePlugin;
+import net.sourceforge.phpeclipse.builder.IdentifierIndexManager;
+import net.sourceforge.phpeclipse.builder.PHPIdentifierLocation;
+import net.sourceforge.phpeclipse.phpeditor.PHPEditor;
+import net.sourceforge.phpeclipse.phpeditor.php.PHPWordExtractor;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.ITextSelection;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.ui.IFileEditorInput;
+import org.eclipse.ui.dialogs.ListSelectionDialog;
+import org.eclipse.ui.internal.dialogs.ListContentProvider;
+
+public class OpenDeclarationEditorAction {
+
+  private PHPEditor fEditor;
+
+  private IProject fProject;
+
+  private boolean isIncludeString;
+
+  public OpenDeclarationEditorAction(PHPEditor editor) {
+    fEditor = editor;
+    fProject = null;
+    isIncludeString = false;
+  }
+
+  /**
+   * @param selection
+   */
+  protected void openSelectedElement(ITextSelection selection) {
+    IDocument doc = fEditor.getDocumentProvider().getDocument(fEditor.getEditorInput());
+    int pos = selection.getOffset();
+    openSelectedPosition(doc, pos);
+  }
+
+  protected void openSelectedPosition(IDocument doc, int position) {
+    IFile f = ((IFileEditorInput) fEditor.getEditorInput()).getFile();
+    fProject = f.getProject();
+    //  System.out.println(selection.getText());
+    String identifierOrInclude = getIdentifierOrInclude(doc, position);
+    //      System.out.println(word);
+    if (identifierOrInclude != null && !identifierOrInclude.equals("")) {
+      if (isIncludeString) {
+        openIncludeFile(identifierOrInclude);
+      } else {
+        openIdentifierDeclaration(f, identifierOrInclude);
+      }
+    }
+  }
+  
+  /**
+   * @param filename
+   */
+  private void openIncludeFile(String filename) {
+    if (filename != null && !filename.equals("")) {
+      try {
+        IFile currentFile = ((IFileEditorInput) fEditor.getEditorInput()).getFile();
+        IPath path = PHPFileUtil.determineFilePath(filename, currentFile, fProject);
+        if (path != null) {
+         IFile file = PHPFileUtil.createFile(path, fProject);
+          if (file != null && file.exists()) {
+            PHPeclipsePlugin.getDefault().openFileInTextEditor(file.getLocation().toString());
+            return;
+          }
+        }
+      } catch (Exception e) {
+        // ignore
+      }
+
+      try {
+
+        IdentifierIndexManager indexManager = PHPeclipsePlugin.getDefault().getIndexManager(fProject);
+        //            filename = StringUtil.replaceRegExChars(filename);
+        List list = indexManager.getFileList(filename);
+        if (list != null && list.size() > 0) {
+          //String workspaceLocation = PHPeclipsePlugin.getWorkspace().getRoot().getLocation().toString();
+          String workspaceLocation = fProject.getLocation().toString() + java.io.File.separatorChar;
+
+          ListSelectionDialog listSelectionDialog = new ListSelectionDialog(PHPeclipsePlugin.getDefault().getWorkbench()
+              .getActiveWorkbenchWindow().getShell(), list, new ListContentProvider(), new LabelProvider(),
+              "Select the includes to open.");
+          listSelectionDialog.setTitle("Multiple includes found");
+          if (listSelectionDialog.open() == Window.OK) {
+            Object[] locations = listSelectionDialog.getResult();
+            if (locations != null) {
+              try {
+                for (int i = 0; i < locations.length; i++) {
+                  //                    PHPIdentifierLocation location = (PHPIdentifierLocation)
+                  // locations[i];
+                  String openFilename = workspaceLocation + ((String) locations[i]);
+                  PHPeclipsePlugin.getDefault().openFileInTextEditor(openFilename);
+                }
+              } catch (CoreException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+              }
+            }
+          }
+
+        }
+      } catch (Exception e) {
+      }
+
+    }
+    return;
+  }
+
+  /**
+   * @param f
+   * @param identiifer
+   */
+  private void openIdentifierDeclaration(IFile f, String identiifer) {
+    if (identiifer != null && !identiifer.equals("")) {
+      IdentifierIndexManager indexManager = PHPeclipsePlugin.getDefault().getIndexManager(fProject);
+      List locationsList = indexManager.getLocations(identiifer);
+      if (locationsList != null && locationsList.size() > 0) {
+
+        //          String workspaceLocation = PHPeclipsePlugin.getWorkspace().getRoot()
+        //              .getLocation().toString();
+
+        String workspaceLocation = fProject.getLocation().toString() + java.io.File.separatorChar;
+        // TODO show all entries of the list in a dialog box
+        // at the moment always the first entry will be opened
+        if (locationsList.size() > 1) {
+          // determine all includes:
+          IncludesScanner includesScanner = new IncludesScanner(fProject, (IFileEditorInput) fEditor.getEditorInput());
+          includesScanner.addFile(f);
+          Set exactIncludeSet = includesScanner.getSet();
+
+          PHPIdentifierLocation includeName;
+          for (int i = 0; i < locationsList.size(); i++) {
+            includeName = (PHPIdentifierLocation) locationsList.get(i);
+            if (exactIncludeSet.contains(includeName.getFilename())) {
+              includeName.setMatch(PHPIdentifierLocation.EXACT_MATCH);
+            } else {
+              includeName.setMatch(PHPIdentifierLocation.UNDEFINED_MATCH);
+            }
+          }
+          Collections.sort(locationsList);
+
+          ListSelectionDialog listSelectionDialog = new ListSelectionDialog(PHPeclipsePlugin.getDefault().getWorkbench()
+              .getActiveWorkbenchWindow().getShell(), locationsList, new ListContentProvider(), new LabelProvider(),
+              "Select the resources to open.");
+          listSelectionDialog.setTitle("Multiple declarations found");
+          if (listSelectionDialog.open() == Window.OK) {
+            Object[] locations = listSelectionDialog.getResult();
+            if (locations != null) {
+              try {
+                for (int i = 0; i < locations.length; i++) {
+                  PHPIdentifierLocation location = (PHPIdentifierLocation) locations[i];
+                  String filename = workspaceLocation + location.getFilename();
+                  //                                   System.out.println(filename);
+                  if (location.getOffset() >= 0) {
+                    PHPeclipsePlugin.getDefault().openFileAndGotoOffset(filename, location.getOffset(), identiifer.length());
+                  } else {
+                    PHPeclipsePlugin.getDefault().openFileAndFindString(filename, identiifer);
+                  }
+                }
+              } catch (CoreException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+              }
+            }
+          }
+        } else {
+          try {
+            PHPIdentifierLocation location = (PHPIdentifierLocation) locationsList.get(0);
+            String filename = workspaceLocation + location.getFilename();
+            //                                 System.out.println(filename);
+            if (location.getOffset() >= 0) {
+              PHPeclipsePlugin.getDefault().openFileAndGotoOffset(filename, location.getOffset(), identiifer.length());
+            } else {
+              PHPeclipsePlugin.getDefault().openFileAndFindString(filename, identiifer);
+            }
+          } catch (CoreException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+          }
+        }
+      }
+    }
+  }
+
+  private String getIdentifierOrInclude(IDocument doc, int pos) {
+    //    private String getPHPIncludeText(IDocument doc, int pos) {
+    Point word = null;
+    int start = -1;
+    int end = -1;
+    isIncludeString = false;
+    try {
+      //    try to find an include string
+      int position = pos;
+      char character = ' ';
+
+      while (position >= 0) {
+        character = doc.getChar(position);
+        if ((character == '\"') || (character == '\'') || (character == '\r') || (character == '\n'))
+          break;
+        --position;
+      }
+      if ((character == '\"') || (character == '\'')) {
+        start = position;
+
+        position = pos;
+        int length = doc.getLength();
+        character = ' ';
+        while (position < length) {
+          character = doc.getChar(position);
+          if ((character == '\"') || (character == '\'') || (character == '\r') || (character == '\n'))
+            break;
+          ++position;
+        }
+        if ((character == '\"') || (character == '\'')) {
+          start++;
+          end = position;
+
+          if (end > start) {
+            word = new Point(start, end - start); // include name found
+            isIncludeString = true;
+          }
+        }
+      }
+
+      // try to find an identifier
+      if (word == null) {
+        word = PHPWordExtractor.findWord(doc, pos); // identifier found
+        isIncludeString = false;
+      }
+    } catch (BadLocationException x) {
+    }
+
+    if (word != null) {
+      try {
+        return doc.get(word.x, word.y);
+      } catch (BadLocationException e) {
+      }
+    }
+    return "";
+  }
+
+}
\ No newline at end of file
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/actions/PHPOpenDeclarationAction.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/actions/PHPOpenDeclarationAction.java
new file mode 100644 (file)
index 0000000..7fc1dae
--- /dev/null
@@ -0,0 +1,103 @@
+/***********************************************************************************************************************************
+ * Copyright (c) 2000, 2002 IBM Corp. 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: www.phpeclipse.de
+ **********************************************************************************************************************************/
+package net.sourceforge.phpeclipse.actions;
+
+import net.sourceforge.phpdt.internal.ui.actions.ActionUtil;
+import net.sourceforge.phpdt.internal.ui.actions.SelectionConverter;
+import net.sourceforge.phpdt.ui.actions.SelectionDispatchAction;
+import net.sourceforge.phpeclipse.phpeditor.PHPEditor;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.ITextSelection;
+import org.eclipse.jface.text.TextSelection;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.IWorkbenchSite;
+import org.eclipse.ui.IWorkbenchWindow;
+
+public class PHPOpenDeclarationAction extends SelectionDispatchAction {
+  private IWorkbenchWindow fWindow;
+
+  private PHPEditor fEditor;
+
+  public void dispose() {
+  }
+
+  public PHPOpenDeclarationAction(IWorkbenchSite site) {
+    super(site);
+    // setText(ActionMessages.getString("OpenAction.label")); //$NON-NLS-1$
+    // setToolTipText(ActionMessages.getString("OpenAction.tooltip")); //$NON-NLS-1$
+    // setDescription(ActionMessages.getString("OpenAction.description")); //$NON-NLS-1$
+    // WorkbenchHelp.setHelp(this, IJavaHelpContextIds.OPEN_ACTION);
+  }
+  
+  /**
+   * Note: This constructor is for internal use only. Clients should not call this constructor.
+   */
+  public PHPOpenDeclarationAction(PHPEditor editor) {
+    this(editor.getEditorSite());
+    fEditor = editor;
+    //         setText(ActionMessages.getString("OpenAction.declaration.label")); //$NON-NLS-1$
+    setEnabled(SelectionConverter.canOperateOn(fEditor));
+  }
+  
+  public void init(IWorkbenchWindow window) {
+    this.fWindow = window;
+  }
+
+  public void selectionChanged(IAction action, ISelection selection) {
+    if (!selection.isEmpty()) {
+      if (selection instanceof TextSelection) {
+        action.setEnabled(true);
+      } else if (fWindow.getActivePage() != null && fWindow.getActivePage().getActivePart() != null) {
+        //
+      }
+    }
+  }
+
+  private boolean checkEnabled(IStructuredSelection selection) {
+    if (selection.isEmpty())
+      return false;
+    return true;
+  }
+
+  /*
+   * (non-Javadoc) Method declared on SelectionDispatchAction.
+   */
+  public void run(ITextSelection selection) {
+    if (!ActionUtil.isProcessable(getShell(), fEditor))
+      return;
+    OpenDeclarationEditorAction openAction = new OpenDeclarationEditorAction(fEditor);
+    openAction.openSelectedElement(selection);
+  }
+
+  /*
+   * (non-Javadoc) Method declared on SelectionDispatchAction.
+   */
+  public void run(IStructuredSelection selection) {
+    if (!checkEnabled(selection))
+      return;
+    run(selection.toArray());
+  }
+
+  /**
+   * Note: this method is for internal use only. Clients should not call this method.
+   */
+  public void run(Object[] elements) {
+    if (elements != null && elements.length > 0) {
+      ITextSelection selection = (ITextSelection) fEditor.getSelectionProvider().getSelection();
+      IDocument doc = fEditor.getDocumentProvider().getDocument(fEditor.getEditorInput());
+      int pos = selection.getOffset();
+
+      OpenDeclarationEditorAction openAction = new OpenDeclarationEditorAction(fEditor);
+      openAction.openSelectedPosition(doc, pos);
+    }
+  }
+
+}
\ No newline at end of file
index 486f7cf..e689c33 100644 (file)
@@ -7,53 +7,23 @@
  **********************************************************************************************************************************/
 package net.sourceforge.phpeclipse.actions;
 
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-
-import net.sourceforge.phpdt.internal.ui.util.PHPFileUtil;
-import net.sourceforge.phpeclipse.PHPeclipsePlugin;
-import net.sourceforge.phpeclipse.builder.IdentifierIndexManager;
-import net.sourceforge.phpeclipse.builder.PHPIdentifierLocation;
 import net.sourceforge.phpeclipse.phpeditor.PHPEditor;
-import net.sourceforge.phpeclipse.phpeditor.php.PHPWordExtractor;
 
-import org.eclipse.core.resources.IContainer;
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.internal.resources.File;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IPath;
 import org.eclipse.jface.action.IAction;
-import org.eclipse.jface.text.BadLocationException;
-import org.eclipse.jface.text.IDocument;
 import org.eclipse.jface.text.ITextSelection;
 import org.eclipse.jface.text.TextSelection;
 import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.LabelProvider;
-import org.eclipse.jface.window.Window;
-import org.eclipse.swt.graphics.Point;
+import org.eclipse.jface.viewers.IStructuredSelection;
 import org.eclipse.ui.IEditorActionDelegate;
 import org.eclipse.ui.IEditorPart;
-import org.eclipse.ui.IFileEditorInput;
 import org.eclipse.ui.IWorkbenchWindow;
 import org.eclipse.ui.actions.ActionDelegate;
-import org.eclipse.ui.dialogs.ListSelectionDialog;
-import org.eclipse.ui.internal.dialogs.ListContentProvider;
 
 public class PHPOpenDeclarationEditorAction extends ActionDelegate implements IEditorActionDelegate {
-
   private IWorkbenchWindow fWindow;
 
   private PHPEditor fEditor;
 
-  private IProject fProject;
-
-  private boolean isIncludeString;
-
-  public void dispose() {
-  }
-
   public void init(IWorkbenchWindow window) {
     this.fWindow = window;
   }
@@ -68,6 +38,12 @@ public class PHPOpenDeclarationEditorAction extends ActionDelegate implements IE
     }
   }
 
+  private boolean checkEnabled(IStructuredSelection selection) {
+    if (selection.isEmpty())
+      return false;
+    return true;
+  }
   public void run(IAction action) {
     if (fEditor == null) {
       IEditorPart targetEditor = fWindow.getActivePage().getActiveEditor();
@@ -76,161 +52,9 @@ public class PHPOpenDeclarationEditorAction extends ActionDelegate implements IE
       }
     }
     if (fEditor != null) {
-      // determine the current Project from a (file-based) Editor
-      IFile f = ((IFileEditorInput) fEditor.getEditorInput()).getFile();
-      fProject = f.getProject();
-      //      System.out.println(fProject.toString());
-
       ITextSelection selection = (ITextSelection) fEditor.getSelectionProvider().getSelection();
-      IDocument doc = fEditor.getDocumentProvider().getDocument(fEditor.getEditorInput());
-      int pos = selection.getOffset();
-      //  System.out.println(selection.getText());
-      String identifierOrInclude = getIdentifierOrInclude(doc, pos);
-      //      System.out.println(word);
-      if (identifierOrInclude != null && !identifierOrInclude.equals("")) {
-        if (isIncludeString) {
-          openIncludeFile(identifierOrInclude);
-        } else {
-          openIdentifierDeclaration(f, identifierOrInclude);
-        }
-      }
-    }
-  }
-
-  /**
-   * @param filename
-   */
-  private void openIncludeFile(String filename) {
-    if (filename != null && !filename.equals("")) {
-      try {
-        IFile currentFile = ((IFileEditorInput) fEditor.getEditorInput()).getFile();
-        IPath path = PHPFileUtil.determineFilePath(filename, currentFile, fProject);
-        if (path != null) { 
-//          String projectPath = fProject.getLocation().toString();
-//          String filePath = path.toString().substring(projectPath.length()+1);
-//          IFile file = fProject.getFile(filePath);
-          IFile file = PHPFileUtil.createFile(path, fProject);
-          //        IFile file = getIncludeFile(fProject, (IFileEditorInput) fEditor.getEditorInput(), filename);
-          if (file != null && file.exists()) {
-            PHPeclipsePlugin.getDefault().openFileInTextEditor(file.getLocation().toString());
-            return;
-          }
-        }
-      } catch (Exception e) {
-        // ignore
-      }
-
-      try {
-
-        IdentifierIndexManager indexManager = PHPeclipsePlugin.getDefault().getIndexManager(fProject);
-        //            filename = StringUtil.replaceRegExChars(filename);
-        List list = indexManager.getFileList(filename);
-        if (list != null && list.size() > 0) {
-          //String workspaceLocation = PHPeclipsePlugin.getWorkspace().getRoot().getLocation().toString();
-          String workspaceLocation = fProject.getLocation().toString() + java.io.File.separatorChar;
-
-          ListSelectionDialog listSelectionDialog = new ListSelectionDialog(PHPeclipsePlugin.getDefault().getWorkbench()
-              .getActiveWorkbenchWindow().getShell(), list, new ListContentProvider(), new LabelProvider(),
-              "Select the includes to open.");
-          listSelectionDialog.setTitle("Multiple includes found");
-          if (listSelectionDialog.open() == Window.OK) {
-            Object[] locations = listSelectionDialog.getResult();
-            if (locations != null) {
-              try {
-                for (int i = 0; i < locations.length; i++) {
-                  //                    PHPIdentifierLocation location = (PHPIdentifierLocation)
-                  // locations[i];
-                  String openFilename = workspaceLocation + ((String) locations[i]);
-                  PHPeclipsePlugin.getDefault().openFileInTextEditor(openFilename);
-                }
-              } catch (CoreException e) {
-                // TODO Auto-generated catch block
-                e.printStackTrace();
-              }
-            }
-          }
-
-        }
-      } catch (Exception e) {
-      }
-
-    }
-    return;
-  }
-
-  /**
-   * @param f
-   * @param identiifer
-   */
-  private void openIdentifierDeclaration(IFile f, String identiifer) {
-    if (identiifer != null && !identiifer.equals("")) {
-      IdentifierIndexManager indexManager = PHPeclipsePlugin.getDefault().getIndexManager(fProject);
-      List locationsList = indexManager.getLocations(identiifer);
-      if (locationsList != null && locationsList.size() > 0) {
-
-        //          String workspaceLocation = PHPeclipsePlugin.getWorkspace().getRoot()
-        //              .getLocation().toString();
-
-        String workspaceLocation = fProject.getLocation().toString() + java.io.File.separatorChar;
-        // TODO show all entries of the list in a dialog box
-        // at the moment always the first entry will be opened
-        if (locationsList.size() > 1) {
-          // determine all includes:
-          IncludesScanner includesScanner = new IncludesScanner(fProject, (IFileEditorInput) fEditor.getEditorInput());
-          includesScanner.addFile(f);
-          Set exactIncludeSet = includesScanner.getSet();
-
-          PHPIdentifierLocation includeName;
-          for (int i = 0; i < locationsList.size(); i++) {
-            includeName = (PHPIdentifierLocation) locationsList.get(i);
-            if (exactIncludeSet.contains(includeName.getFilename())) {
-              includeName.setMatch(PHPIdentifierLocation.EXACT_MATCH);
-            } else {
-              includeName.setMatch(PHPIdentifierLocation.UNDEFINED_MATCH);
-            }
-          }
-          Collections.sort(locationsList);
-
-          ListSelectionDialog listSelectionDialog = new ListSelectionDialog(PHPeclipsePlugin.getDefault().getWorkbench()
-              .getActiveWorkbenchWindow().getShell(), locationsList, new ListContentProvider(), new LabelProvider(),
-              "Select the resources to open.");
-          listSelectionDialog.setTitle("Multiple declarations found");
-          if (listSelectionDialog.open() == Window.OK) {
-            Object[] locations = listSelectionDialog.getResult();
-            if (locations != null) {
-              try {
-                for (int i = 0; i < locations.length; i++) {
-                  PHPIdentifierLocation location = (PHPIdentifierLocation) locations[i];
-                  String filename = workspaceLocation + location.getFilename();
-                  //                                   System.out.println(filename);
-                  if (location.getOffset() >= 0) {
-                    PHPeclipsePlugin.getDefault().openFileAndGotoOffset(filename, location.getOffset(), identiifer.length());
-                  } else {
-                    PHPeclipsePlugin.getDefault().openFileAndFindString(filename, identiifer);
-                  }
-                }
-              } catch (CoreException e) {
-                // TODO Auto-generated catch block
-                e.printStackTrace();
-              }
-            }
-          }
-        } else {
-          try {
-            PHPIdentifierLocation location = (PHPIdentifierLocation) locationsList.get(0);
-            String filename = workspaceLocation + location.getFilename();
-            //                                 System.out.println(filename);
-            if (location.getOffset() >= 0) {
-              PHPeclipsePlugin.getDefault().openFileAndGotoOffset(filename, location.getOffset(), identiifer.length());
-            } else {
-              PHPeclipsePlugin.getDefault().openFileAndFindString(filename, identiifer);
-            }
-          } catch (CoreException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-          }
-        }
-      }
+      OpenDeclarationEditorAction openAction = new OpenDeclarationEditorAction(fEditor);
+      openAction.openSelectedElement(selection);
     }
   }
 
@@ -240,103 +64,4 @@ public class PHPOpenDeclarationEditorAction extends ActionDelegate implements IE
     }
   }
 
-  private String getIdentifierOrInclude(IDocument doc, int pos) {
-    //    private String getPHPIncludeText(IDocument doc, int pos) {
-    Point word = null;
-    int start = -1;
-    int end = -1;
-    isIncludeString = false;
-    try {
-      //    try to find an include string
-      int position = pos;
-      char character = ' ';
-
-      while (position >= 0) {
-        character = doc.getChar(position);
-        if ((character == '\"') || (character == '\'') || (character == '\r') || (character == '\n'))
-          break;
-        --position;
-      }
-      if ((character == '\"') || (character == '\'')) {
-        start = position;
-
-        position = pos;
-        int length = doc.getLength();
-        character = ' ';
-        while (position < length) {
-          character = doc.getChar(position);
-          if ((character == '\"') || (character == '\'') || (character == '\r') || (character == '\n'))
-            break;
-          ++position;
-        }
-        if ((character == '\"') || (character == '\'')) {
-          start++;
-          end = position;
-
-          if (end > start) {
-            word = new Point(start, end - start); // include name found
-            isIncludeString = true;
-          }
-        }
-      }
-
-      // try to find an identifier
-      if (word == null) {
-        word = PHPWordExtractor.findWord(doc, pos); // identifier found
-        isIncludeString = false;
-      }
-    } catch (BadLocationException x) {
-    }
-
-    if (word != null) {
-      try {
-        return doc.get(word.x, word.y);
-      } catch (BadLocationException e) {
-      }
-    }
-    return "";
-  }
-
-  //    
-  //    
-  //    Point word = PHPWordExtractor.findWord(doc, pos);
-  //    if (word != null) {
-  //      try {
-  //        return doc.get(word.x, word.y);
-  //      } catch (BadLocationException e) {
-  //      }
-  //    }
-  //    return "";
-  //  }
-  private IContainer getWorkingLocation(IFileEditorInput editorInput) {
-    if (editorInput == null || editorInput.getFile() == null) {
-      return null;
-    }
-    return editorInput.getFile().getParent();
-  }
-
-  //  private IFile getIncludeFile(IProject project, IFileEditorInput editorInput, String relativeFilename) {
-  //    IContainer container = getWorkingLocation(editorInput);
-  //    String fullPath = project.getLocation().toString();
-  //    IFile file = null;
-  //    if (relativeFilename.startsWith("../")) {
-  //      Path path = new Path(relativeFilename);
-  //      file = container.getFile(path);
-  //      return file;
-  //    }
-  //    int index = relativeFilename.lastIndexOf('/');
-  //
-  //    if (index >= 0) {
-  //      Path path = new Path(relativeFilename);
-  //      file = project.getFile(path);
-  //      if (file.exists()) {
-  //        return file;
-  //      }
-  //    }
-  //
-  //    Path path = new Path(relativeFilename);
-  //    file = container.getFile(path);
-  //
-  //    return file;
-  //  }
 }
\ No newline at end of file
index 2769154..cd647e3 100644 (file)
@@ -41,7 +41,7 @@ public class IdentifierIndexManager {
     private int fToken;
 
     public LineCreator() {
-      fScanner = new Scanner(true, false, false, false, true, null, null);
+      fScanner = new Scanner(true, false, false, false, true, null, null, true /*taskCaseSensitive*/);
     }
 
     /**
index 87c7ee5..f6852b8 100644 (file)
@@ -9,7 +9,6 @@
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
 package net.sourceforge.phpeclipse.internal.compiler.ast;
-
 import java.util.ArrayList;
 
 import net.sourceforge.phpdt.core.compiler.CharOperation;
@@ -30,6 +29,7 @@ public class CompilationUnitDeclaration extends ASTNode implements ProblemSeveri
   public ImportReference[] imports;
   //  public TypeDeclaration[] types;
   public ArrayList types;
+  
   //public char[][] name;
   public int[][] comments;
 
index d79c30d..c179005 100644 (file)
@@ -57,8 +57,8 @@ public class BasicJavaEditorActionContributor extends BasicTextEditorActionContr
 //     private RetargetTextEditorAction fStructureSelectPreviousAction;
 //     private RetargetTextEditorAction fStructureSelectHistoryAction; 
 
-//     private RetargetTextEditorAction fGotoNextMemberAction; 
-//     private RetargetTextEditorAction fGotoPreviousMemberAction;
+       private RetargetTextEditorAction fGotoNextMemberAction; 
+       private RetargetTextEditorAction fGotoPreviousMemberAction;
 //
 //     private RetargetTextEditorAction fRemoveOccurrenceAnnotationsAction;    
        
@@ -102,10 +102,10 @@ public class BasicJavaEditorActionContributor extends BasicTextEditorActionContr
 //             fStructureSelectHistoryAction= new RetargetTextEditorAction(b, "StructureSelectHistory."); //$NON-NLS-1$
 //             fStructureSelectHistoryAction.setActionDefinitionId(PHPEditorActionDefinitionIds.SELECT_LAST);
 //             
-//             fGotoNextMemberAction= new RetargetTextEditorAction(b, "GotoNextMember."); //$NON-NLS-1$
-//             fGotoNextMemberAction.setActionDefinitionId(PHPEditorActionDefinitionIds.GOTO_NEXT_MEMBER);
-//             fGotoPreviousMemberAction= new RetargetTextEditorAction(b, "GotoPreviousMember."); //$NON-NLS-1$
-//             fGotoPreviousMemberAction.setActionDefinitionId(PHPEditorActionDefinitionIds.GOTO_PREVIOUS_MEMBER);             
+               fGotoNextMemberAction= new RetargetTextEditorAction(b, "GotoNextMember."); //$NON-NLS-1$
+               fGotoNextMemberAction.setActionDefinitionId(PHPEditorActionDefinitionIds.GOTO_NEXT_MEMBER);
+               fGotoPreviousMemberAction= new RetargetTextEditorAction(b, "GotoPreviousMember."); //$NON-NLS-1$
+               fGotoPreviousMemberAction.setActionDefinitionId(PHPEditorActionDefinitionIds.GOTO_PREVIOUS_MEMBER);             
 //
 //             fRemoveOccurrenceAnnotationsAction= new RetargetTextEditorAction(b, "RemoveOccurrenceAnnotations."); //$NON-NLS-1$
 //             fRemoveOccurrenceAnnotationsAction.setActionDefinitionId(PHPEditorActionDefinitionIds.REMOVE_OCCURRENCE_ANNOTATIONS);
@@ -168,8 +168,8 @@ public class BasicJavaEditorActionContributor extends BasicTextEditorActionContr
                IMenuManager gotoMenu= menu.findMenuUsingPath("navigate/goTo"); //$NON-NLS-1$
                if (gotoMenu != null) {
                        gotoMenu.add(new Separator("additions2"));  //$NON-NLS-1$
-//                     gotoMenu.appendToGroup("additions2", fGotoPreviousMemberAction); //$NON-NLS-1$
-//                     gotoMenu.appendToGroup("additions2", fGotoNextMemberAction); //$NON-NLS-1$
+                       gotoMenu.appendToGroup("additions2", fGotoPreviousMemberAction); //$NON-NLS-1$
+                       gotoMenu.appendToGroup("additions2", fGotoNextMemberAction); //$NON-NLS-1$
                        gotoMenu.appendToGroup("additions2", fGotoMatchingBracket); //$NON-NLS-1$
                }
        }
@@ -209,7 +209,6 @@ public class BasicJavaEditorActionContributor extends BasicTextEditorActionContr
 //             fGotoPreviousMemberAction.setAction(getAction(textEditor, GoToNextPreviousMemberAction.PREVIOUS_MEMBER));
                
 //             fRemoveOccurrenceAnnotationsAction.setAction(getAction(textEditor, "RemoveOccurrenceAnnotations")); //$NON-NLS-1$
-               
                if (part instanceof PHPEditor) {
                    PHPEditor javaEditor= (PHPEditor) part;
                        javaEditor.getActionGroup().fillActionBars(getActionBars());
index e6708e6..f5af618 100644 (file)
@@ -12,8 +12,6 @@ import net.sourceforge.phpeclipse.PHPeclipsePlugin;
 import net.sourceforge.phpeclipse.ui.editor.ShowExternalPreviewAction;
 
 import org.eclipse.core.resources.IFile;
-import org.eclipse.jface.action.IAction;
-import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.ui.IActionBars;
 import org.eclipse.ui.IEditorInput;
 import org.eclipse.ui.IEditorPart;
@@ -41,10 +39,8 @@ public class CompilationUnitEditorActionContributor extends BasicEditorActionCon
     bars.setGlobalActionHandler(PHPdtActionConstants.UNCOMMENT, getAction(textEditor, "Uncomment")); //$NON-NLS-1$
     bars.setGlobalActionHandler(PHPdtActionConstants.TOGGLE_COMMENT, getAction(textEditor, "ToggleComment")); //$NON-NLS-1$
     bars.setGlobalActionHandler(PHPdtActionConstants.FORMAT, getAction(textEditor, "Format")); //$NON-NLS-1$
-    //         bars.setGlobalActionHandler(PHPdtActionConstants.ADD_BLOCK_COMMENT,
-    //                         getAction(textEditor, "AddBlockComment")); //$NON-NLS-1$
-    //         bars.setGlobalActionHandler(PHPdtActionConstants.REMOVE_BLOCK_COMMENT,
-    //                         getAction(textEditor, "RemoveBlockComment")); //$NON-NLS-1$
+    bars.setGlobalActionHandler(PHPdtActionConstants.ADD_BLOCK_COMMENT, getAction(textEditor, "AddBlockComment")); //$NON-NLS-1$
+    bars.setGlobalActionHandler(PHPdtActionConstants.REMOVE_BLOCK_COMMENT, getAction(textEditor, "RemoveBlockComment")); //$NON-NLS-1$
     //         bars.setGlobalActionHandler(PHPdtActionConstants.INDENT, getAction(
     //                         textEditor, "Indent")); //$NON-NLS-1$ //$NON-NLS-2$
 
index d5eeb74..ade4363 100644 (file)
@@ -13,6 +13,8 @@ package net.sourceforge.phpeclipse.phpeditor;
  **********************************************************************/
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.text.BreakIterator;
+import java.text.CharacterIterator;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -31,18 +33,24 @@ import net.sourceforge.phpdt.core.ISourceRange;
 import net.sourceforge.phpdt.core.ISourceReference;
 import net.sourceforge.phpdt.core.JavaCore;
 import net.sourceforge.phpdt.core.JavaModelException;
+import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
 import net.sourceforge.phpdt.internal.ui.actions.CompositeActionGroup;
 import net.sourceforge.phpdt.internal.ui.actions.FoldingActionGroup;
+import net.sourceforge.phpdt.internal.ui.actions.SelectionConverter;
 import net.sourceforge.phpdt.internal.ui.text.CustomSourceInformationControl;
+import net.sourceforge.phpdt.internal.ui.text.DocumentCharacterIterator;
 import net.sourceforge.phpdt.internal.ui.text.HTMLTextPresenter;
 import net.sourceforge.phpdt.internal.ui.text.IPHPPartitions;
+import net.sourceforge.phpdt.internal.ui.text.JavaWordIterator;
 import net.sourceforge.phpdt.internal.ui.text.PHPPairMatcher;
 import net.sourceforge.phpdt.internal.ui.text.PreferencesAdapter;
+import net.sourceforge.phpdt.internal.ui.text.java.JavaExpandHover;
 import net.sourceforge.phpdt.internal.ui.viewsupport.IViewPartInputProvider;
 import net.sourceforge.phpdt.ui.IContextMenuConstants;
 import net.sourceforge.phpdt.ui.JavaUI;
 import net.sourceforge.phpdt.ui.PreferenceConstants;
 import net.sourceforge.phpdt.ui.actions.GotoMatchingBracketAction;
+import net.sourceforge.phpdt.ui.actions.OpenEditorActionGroup;
 import net.sourceforge.phpdt.ui.text.JavaTextTools;
 import net.sourceforge.phpdt.ui.text.PHPSourceViewerConfiguration;
 import net.sourceforge.phpdt.ui.text.folding.IJavaFoldingStructureProvider;
@@ -74,23 +82,30 @@ import org.eclipse.jface.text.IRegion;
 import org.eclipse.jface.text.ISynchronizable;
 import org.eclipse.jface.text.ITextHover;
 import org.eclipse.jface.text.ITextInputListener;
+import org.eclipse.jface.text.ITextPresentationListener;
 import org.eclipse.jface.text.ITextSelection;
 import org.eclipse.jface.text.ITextViewer;
 import org.eclipse.jface.text.ITextViewerExtension2;
 import org.eclipse.jface.text.ITextViewerExtension3;
+import org.eclipse.jface.text.ITextViewerExtension4;
 import org.eclipse.jface.text.ITextViewerExtension5;
 import org.eclipse.jface.text.ITypedRegion;
 import org.eclipse.jface.text.Position;
 import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.TextPresentation;
 import org.eclipse.jface.text.TextSelection;
+import org.eclipse.jface.text.TextUtilities;
 import org.eclipse.jface.text.information.IInformationProvider;
 import org.eclipse.jface.text.information.InformationPresenter;
 import org.eclipse.jface.text.reconciler.IReconciler;
 import org.eclipse.jface.text.source.Annotation;
+import org.eclipse.jface.text.source.AnnotationRulerColumn;
+import org.eclipse.jface.text.source.CompositeRuler;
 import org.eclipse.jface.text.source.IAnnotationModel;
 import org.eclipse.jface.text.source.IAnnotationModelExtension;
 import org.eclipse.jface.text.source.IOverviewRuler;
 import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.jface.text.source.ISourceViewerExtension2;
 import org.eclipse.jface.text.source.IVerticalRuler;
 import org.eclipse.jface.text.source.OverviewRuler;
 import org.eclipse.jface.text.source.SourceViewerConfiguration;
@@ -99,6 +114,8 @@ import org.eclipse.jface.text.source.projection.ProjectionViewer;
 import org.eclipse.jface.util.IPropertyChangeListener;
 import org.eclipse.jface.util.ListenerList;
 import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
 import org.eclipse.jface.viewers.IPostSelectionProvider;
 import org.eclipse.jface.viewers.ISelection;
 import org.eclipse.jface.viewers.ISelectionChangedListener;
@@ -109,6 +126,7 @@ import org.eclipse.jface.viewers.StructuredSelection;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.custom.BidiSegmentEvent;
 import org.eclipse.swt.custom.BidiSegmentListener;
+import org.eclipse.swt.custom.ST;
 import org.eclipse.swt.custom.StyleRange;
 import org.eclipse.swt.custom.StyledText;
 import org.eclipse.swt.events.FocusEvent;
@@ -133,6 +151,7 @@ import org.eclipse.swt.widgets.Shell;
 import org.eclipse.ui.IEditorInput;
 import org.eclipse.ui.IPageLayout;
 import org.eclipse.ui.IPartService;
+import org.eclipse.ui.ISelectionListener;
 import org.eclipse.ui.IViewPart;
 import org.eclipse.ui.IWorkbenchPage;
 import org.eclipse.ui.IWorkbenchPart;
@@ -149,16 +168,18 @@ import org.eclipse.ui.texteditor.ChainedPreferenceStore;
 import org.eclipse.ui.texteditor.IDocumentProvider;
 import org.eclipse.ui.texteditor.IEditorStatusLine;
 import org.eclipse.ui.texteditor.ITextEditorActionConstants;
+import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
+import org.eclipse.ui.texteditor.IUpdate;
 import org.eclipse.ui.texteditor.MarkerAnnotation;
 import org.eclipse.ui.texteditor.ResourceAction;
 import org.eclipse.ui.texteditor.SourceViewerDecorationSupport;
 import org.eclipse.ui.texteditor.TextEditorAction;
+import org.eclipse.ui.texteditor.TextNavigationAction;
 import org.eclipse.ui.texteditor.TextOperationAction;
 import org.eclipse.ui.views.contentoutline.ContentOutline;
 import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
 import org.eclipse.ui.views.tasklist.TaskList;
 
-
 /**
  * PHP specific text editor.
  */
@@ -229,37 +250,36 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
   /**
    * "Smart" runnable for updating the outline page's selection.
    */
-  class OutlinePageSelectionUpdater implements Runnable {
-
-    /** Has the runnable already been posted? */
-    private boolean fPosted = false;
-
-    public OutlinePageSelectionUpdater() {
-    }
-
-    /*
-     * @see Runnable#run()
-     */
-    public void run() {
-      synchronizeOutlinePageSelection();
-      fPosted = false;
-    }
-
-    /**
-     * Posts this runnable into the event queue.
-     */
-    public void post() {
-      if (fPosted)
-        return;
-
-      Shell shell = getSite().getShell();
-      if (shell != null & !shell.isDisposed()) {
-        fPosted = true;
-        shell.getDisplay().asyncExec(this);
-      }
-    }
-  };
-
+  //  class OutlinePageSelectionUpdater implements Runnable {
+  //
+  //    /** Has the runnable already been posted? */
+  //    private boolean fPosted = false;
+  //
+  //    public OutlinePageSelectionUpdater() {
+  //    }
+  //
+  //    /*
+  //     * @see Runnable#run()
+  //     */
+  //    public void run() {
+  //      synchronizeOutlinePageSelection();
+  //      fPosted = false;
+  //    }
+  //
+  //    /**
+  //     * Posts this runnable into the event queue.
+  //     */
+  //    public void post() {
+  //      if (fPosted)
+  //        return;
+  //
+  //      Shell shell = getSite().getShell();
+  //      if (shell != null & !shell.isDisposed()) {
+  //        fPosted = true;
+  //        shell.getDisplay().asyncExec(this);
+  //      }
+  //    }
+  //  };
   class SelectionChangedListener implements ISelectionChangedListener {
     public void selectionChanged(SelectionChangedEvent event) {
       doSelectionChanged(event);
@@ -656,8 +676,672 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
   /*
    * Link mode.
    */
+  //  class MouseClickListener implements KeyListener, MouseListener, MouseMoveListener, FocusListener, PaintListener,
+  //      IPropertyChangeListener, IDocumentListener, ITextInputListener {
+  //
+  //    /** The session is active. */
+  //    private boolean fActive;
+  //
+  //    /** The currently active style range. */
+  //    private IRegion fActiveRegion;
+  //
+  //    /** The currently active style range as position. */
+  //    private Position fRememberedPosition;
+  //
+  //    /** The hand cursor. */
+  //    private Cursor fCursor;
+  //
+  //    /** The link color. */
+  //    private Color fColor;
+  //
+  //    /** The key modifier mask. */
+  //    private int fKeyModifierMask;
+  //
+  //    public void deactivate() {
+  //      deactivate(false);
+  //    }
+  //
+  //    public void deactivate(boolean redrawAll) {
+  //      if (!fActive)
+  //        return;
+  //
+  //      repairRepresentation(redrawAll);
+  //      fActive = false;
+  //    }
+  //
+  //    public void install() {
+  //
+  //      ISourceViewer sourceViewer = getSourceViewer();
+  //      if (sourceViewer == null)
+  //        return;
+  //
+  //      StyledText text = sourceViewer.getTextWidget();
+  //      if (text == null || text.isDisposed())
+  //        return;
+  //
+  //      updateColor(sourceViewer);
+  //
+  //      sourceViewer.addTextInputListener(this);
+  //
+  //      IDocument document = sourceViewer.getDocument();
+  //      if (document != null)
+  //        document.addDocumentListener(this);
+  //
+  //      text.addKeyListener(this);
+  //      text.addMouseListener(this);
+  //      text.addMouseMoveListener(this);
+  //      text.addFocusListener(this);
+  //      text.addPaintListener(this);
+  //
+  //      updateKeyModifierMask();
+  //
+  //      IPreferenceStore preferenceStore = getPreferenceStore();
+  //      preferenceStore.addPropertyChangeListener(this);
+  //    }
+  //
+  //    private void updateKeyModifierMask() {
+  //      String modifiers = getPreferenceStore().getString(BROWSER_LIKE_LINKS_KEY_MODIFIER);
+  //      fKeyModifierMask = computeStateMask(modifiers);
+  //      if (fKeyModifierMask == -1) {
+  //        // Fallback to stored state mask
+  //        fKeyModifierMask = getPreferenceStore().getInt(BROWSER_LIKE_LINKS_KEY_MODIFIER_MASK);
+  //      }
+  //      ;
+  //    }
+  //
+  //    private int computeStateMask(String modifiers) {
+  //      if (modifiers == null)
+  //        return -1;
+  //
+  //      if (modifiers.length() == 0)
+  //        return SWT.NONE;
+  //
+  //      int stateMask = 0;
+  //      StringTokenizer modifierTokenizer = new StringTokenizer(modifiers, ",;.:+-* "); //$NON-NLS-1$
+  //      while (modifierTokenizer.hasMoreTokens()) {
+  //        int modifier = EditorUtility.findLocalizedModifier(modifierTokenizer.nextToken());
+  //        if (modifier == 0 || (stateMask & modifier) == modifier)
+  //          return -1;
+  //        stateMask = stateMask | modifier;
+  //      }
+  //      return stateMask;
+  //    }
+  //
+  //    public void uninstall() {
+  //
+  //      if (fColor != null) {
+  //        fColor.dispose();
+  //        fColor = null;
+  //      }
+  //
+  //      if (fCursor != null) {
+  //        fCursor.dispose();
+  //        fCursor = null;
+  //      }
+  //
+  //      ISourceViewer sourceViewer = getSourceViewer();
+  //      if (sourceViewer == null)
+  //        return;
+  //
+  //      sourceViewer.removeTextInputListener(this);
+  //
+  //      IDocument document = sourceViewer.getDocument();
+  //      if (document != null)
+  //        document.removeDocumentListener(this);
+  //
+  //      IPreferenceStore preferenceStore = getPreferenceStore();
+  //      if (preferenceStore != null)
+  //        preferenceStore.removePropertyChangeListener(this);
+  //
+  //      StyledText text = sourceViewer.getTextWidget();
+  //      if (text == null || text.isDisposed())
+  //        return;
+  //
+  //      text.removeKeyListener(this);
+  //      text.removeMouseListener(this);
+  //      text.removeMouseMoveListener(this);
+  //      text.removeFocusListener(this);
+  //      text.removePaintListener(this);
+  //    }
+  //
+  //    /*
+  //     * @see IPropertyChangeListener#propertyChange(PropertyChangeEvent)
+  //     */
+  //    public void propertyChange(PropertyChangeEvent event) {
+  //      if (event.getProperty().equals(PHPEditor.LINK_COLOR)) {
+  //        ISourceViewer viewer = getSourceViewer();
+  //        if (viewer != null)
+  //          updateColor(viewer);
+  //      } else if (event.getProperty().equals(BROWSER_LIKE_LINKS_KEY_MODIFIER)) {
+  //        updateKeyModifierMask();
+  //      }
+  //    }
+  //
+  //    private void updateColor(ISourceViewer viewer) {
+  //      if (fColor != null)
+  //        fColor.dispose();
+  //
+  //      StyledText text = viewer.getTextWidget();
+  //      if (text == null || text.isDisposed())
+  //        return;
+  //
+  //      Display display = text.getDisplay();
+  //      fColor = createColor(getPreferenceStore(), PHPEditor.LINK_COLOR, display);
+  //    }
+  //
+  //    /**
+  //     * Creates a color from the information stored in the given preference store. Returns <code>null</code> if there is no such
+  //     * information available.
+  //     */
+  //    private Color createColor(IPreferenceStore store, String key, Display display) {
+  //
+  //      RGB rgb = null;
+  //
+  //      if (store.contains(key)) {
+  //
+  //        if (store.isDefault(key))
+  //          rgb = PreferenceConverter.getDefaultColor(store, key);
+  //        else
+  //          rgb = PreferenceConverter.getColor(store, key);
+  //
+  //        if (rgb != null)
+  //          return new Color(display, rgb);
+  //      }
+  //
+  //      return null;
+  //    }
+  //
+  //    private void repairRepresentation() {
+  //      repairRepresentation(false);
+  //    }
+  //
+  //    private void repairRepresentation(boolean redrawAll) {
+  //
+  //      if (fActiveRegion == null)
+  //        return;
+  //
+  //      ISourceViewer viewer = getSourceViewer();
+  //      if (viewer != null) {
+  //        resetCursor(viewer);
+  //
+  //        int offset = fActiveRegion.getOffset();
+  //        int length = fActiveRegion.getLength();
+  //
+  //        // remove style
+  //        if (!redrawAll && viewer instanceof ITextViewerExtension2)
+  //          ((ITextViewerExtension2) viewer).invalidateTextPresentation(offset, length);
+  //        else
+  //          viewer.invalidateTextPresentation();
+  //
+  //        // remove underline
+  //        if (viewer instanceof ITextViewerExtension3) {
+  //          ITextViewerExtension3 extension = (ITextViewerExtension3) viewer;
+  //          offset = extension.modelOffset2WidgetOffset(offset);
+  //        } else {
+  //          offset -= viewer.getVisibleRegion().getOffset();
+  //        }
+  //
+  //        StyledText text = viewer.getTextWidget();
+  //        try {
+  //          text.redrawRange(offset, length, true);
+  //        } catch (IllegalArgumentException x) {
+  //          PHPeclipsePlugin.log(x);
+  //        }
+  //      }
+  //
+  //      fActiveRegion = null;
+  //    }
+  //
+  //    // will eventually be replaced by a method provided by jdt.core
+  //    private IRegion selectWord(IDocument document, int anchor) {
+  //
+  //      try {
+  //        int offset = anchor;
+  //        char c;
+  //
+  //        while (offset >= 0) {
+  //          c = document.getChar(offset);
+  //          if (!Character.isJavaIdentifierPart(c))
+  //            break;
+  //          --offset;
+  //        }
+  //
+  //        int start = offset;
+  //
+  //        offset = anchor;
+  //        int length = document.getLength();
+  //
+  //        while (offset < length) {
+  //          c = document.getChar(offset);
+  //          if (!Character.isJavaIdentifierPart(c))
+  //            break;
+  //          ++offset;
+  //        }
+  //
+  //        int end = offset;
+  //
+  //        if (start == end)
+  //          return new Region(start, 0);
+  //        else
+  //          return new Region(start + 1, end - start - 1);
+  //
+  //      } catch (BadLocationException x) {
+  //        return null;
+  //      }
+  //    }
+  //
+  //    IRegion getCurrentTextRegion(ISourceViewer viewer) {
+  //
+  //      int offset = getCurrentTextOffset(viewer);
+  //      if (offset == -1)
+  //        return null;
+  //
+  //      return null;
+  //      // IJavaElement input= SelectionConverter.getInput(PHPEditor.this);
+  //      // if (input == null)
+  //      // return null;
+  //      //
+  //      // try {
+  //      //
+  //      // IJavaElement[] elements= null;
+  //      // synchronized (input) {
+  //      // elements= ((ICodeAssist) input).codeSelect(offset, 0);
+  //      // }
+  //      //
+  //      // if (elements == null || elements.length == 0)
+  //      // return null;
+  //      //
+  //      // return selectWord(viewer.getDocument(), offset);
+  //      //
+  //      // } catch (JavaModelException e) {
+  //      // return null;
+  //      // }
+  //    }
+  //
+  //    private int getCurrentTextOffset(ISourceViewer viewer) {
+  //
+  //      try {
+  //        StyledText text = viewer.getTextWidget();
+  //        if (text == null || text.isDisposed())
+  //          return -1;
+  //
+  //        Display display = text.getDisplay();
+  //        Point absolutePosition = display.getCursorLocation();
+  //        Point relativePosition = text.toControl(absolutePosition);
+  //
+  //        int widgetOffset = text.getOffsetAtLocation(relativePosition);
+  //        if (viewer instanceof ITextViewerExtension3) {
+  //          ITextViewerExtension3 extension = (ITextViewerExtension3) viewer;
+  //          return extension.widgetOffset2ModelOffset(widgetOffset);
+  //        } else {
+  //          return widgetOffset + viewer.getVisibleRegion().getOffset();
+  //        }
+  //
+  //      } catch (IllegalArgumentException e) {
+  //        return -1;
+  //      }
+  //    }
+  //
+  //    private void highlightRegion(ISourceViewer viewer, IRegion region) {
+  //
+  //      if (region.equals(fActiveRegion))
+  //        return;
+  //
+  //      repairRepresentation();
+  //
+  //      StyledText text = viewer.getTextWidget();
+  //      if (text == null || text.isDisposed())
+  //        return;
+  //
+  //      // highlight region
+  //      int offset = 0;
+  //      int length = 0;
+  //
+  //      if (viewer instanceof ITextViewerExtension3) {
+  //        ITextViewerExtension3 extension = (ITextViewerExtension3) viewer;
+  //        IRegion widgetRange = extension.modelRange2WidgetRange(region);
+  //        if (widgetRange == null)
+  //          return;
+  //
+  //        offset = widgetRange.getOffset();
+  //        length = widgetRange.getLength();
+  //
+  //      } else {
+  //        offset = region.getOffset() - viewer.getVisibleRegion().getOffset();
+  //        length = region.getLength();
+  //      }
+  //
+  //      StyleRange oldStyleRange = text.getStyleRangeAtOffset(offset);
+  //      Color foregroundColor = fColor;
+  //      Color backgroundColor = oldStyleRange == null ? text.getBackground() : oldStyleRange.background;
+  //      StyleRange styleRange = new StyleRange(offset, length, foregroundColor, backgroundColor);
+  //      text.setStyleRange(styleRange);
+  //
+  //      // underline
+  //      text.redrawRange(offset, length, true);
+  //
+  //      fActiveRegion = region;
+  //    }
+  //
+  //    private void activateCursor(ISourceViewer viewer) {
+  //      StyledText text = viewer.getTextWidget();
+  //      if (text == null || text.isDisposed())
+  //        return;
+  //      Display display = text.getDisplay();
+  //      if (fCursor == null)
+  //        fCursor = new Cursor(display, SWT.CURSOR_HAND);
+  //      text.setCursor(fCursor);
+  //    }
+  //
+  //    private void resetCursor(ISourceViewer viewer) {
+  //      StyledText text = viewer.getTextWidget();
+  //      if (text != null && !text.isDisposed())
+  //        text.setCursor(null);
+  //
+  //      if (fCursor != null) {
+  //        fCursor.dispose();
+  //        fCursor = null;
+  //      }
+  //    }
+  //
+  //    /*
+  //     * @see org.eclipse.swt.events.KeyListener#keyPressed(org.eclipse.swt.events.KeyEvent)
+  //     */
+  //    public void keyPressed(KeyEvent event) {
+  //
+  //      if (fActive) {
+  //        deactivate();
+  //        return;
+  //      }
+  //
+  //      if (event.keyCode != fKeyModifierMask) {
+  //        deactivate();
+  //        return;
+  //      }
+  //
+  //      fActive = true;
+  //
+  //      // removed for #25871
+  //      //
+  //      // ISourceViewer viewer= getSourceViewer();
+  //      // if (viewer == null)
+  //      // return;
+  //      //
+  //      // IRegion region= getCurrentTextRegion(viewer);
+  //      // if (region == null)
+  //      // return;
+  //      //
+  //      // highlightRegion(viewer, region);
+  //      // activateCursor(viewer);
+  //    }
+  //
+  //    /*
+  //     * @see org.eclipse.swt.events.KeyListener#keyReleased(org.eclipse.swt.events.KeyEvent)
+  //     */
+  //    public void keyReleased(KeyEvent event) {
+  //
+  //      if (!fActive)
+  //        return;
+  //
+  //      deactivate();
+  //    }
+  //
+  //    /*
+  //     * @see org.eclipse.swt.events.MouseListener#mouseDoubleClick(org.eclipse.swt.events.MouseEvent)
+  //     */
+  //    public void mouseDoubleClick(MouseEvent e) {
+  //    }
+  //
+  //    /*
+  //     * @see org.eclipse.swt.events.MouseListener#mouseDown(org.eclipse.swt.events.MouseEvent)
+  //     */
+  //    public void mouseDown(MouseEvent event) {
+  //
+  //      if (!fActive)
+  //        return;
+  //
+  //      if (event.stateMask != fKeyModifierMask) {
+  //        deactivate();
+  //        return;
+  //      }
+  //
+  //      if (event.button != 1) {
+  //        deactivate();
+  //        return;
+  //      }
+  //    }
+  //
+  //    /*
+  //     * @see org.eclipse.swt.events.MouseListener#mouseUp(org.eclipse.swt.events.MouseEvent)
+  //     */
+  //    public void mouseUp(MouseEvent e) {
+  //
+  //      if (!fActive)
+  //        return;
+  //
+  //      if (e.button != 1) {
+  //        deactivate();
+  //        return;
+  //      }
+  //
+  //      boolean wasActive = fCursor != null;
+  //
+  //      deactivate();
+  //
+  //      if (wasActive) {
+  //        IAction action = getAction("OpenEditor"); //$NON-NLS-1$
+  //        if (action != null)
+  //          action.run();
+  //      }
+  //    }
+  //
+  //    /*
+  //     * @see org.eclipse.swt.events.MouseMoveListener#mouseMove(org.eclipse.swt.events.MouseEvent)
+  //     */
+  //    public void mouseMove(MouseEvent event) {
+  //
+  //      if (event.widget instanceof Control && !((Control) event.widget).isFocusControl()) {
+  //        deactivate();
+  //        return;
+  //      }
+  //
+  //      if (!fActive) {
+  //        if (event.stateMask != fKeyModifierMask)
+  //          return;
+  //        // modifier was already pressed
+  //        fActive = true;
+  //      }
+  //
+  //      ISourceViewer viewer = getSourceViewer();
+  //      if (viewer == null) {
+  //        deactivate();
+  //        return;
+  //      }
+  //
+  //      StyledText text = viewer.getTextWidget();
+  //      if (text == null || text.isDisposed()) {
+  //        deactivate();
+  //        return;
+  //      }
+  //
+  //      if ((event.stateMask & SWT.BUTTON1) != 0 && text.getSelectionCount() != 0) {
+  //        deactivate();
+  //        return;
+  //      }
+  //
+  //      IRegion region = getCurrentTextRegion(viewer);
+  //      if (region == null || region.getLength() == 0) {
+  //        repairRepresentation();
+  //        return;
+  //      }
+  //
+  //      highlightRegion(viewer, region);
+  //      activateCursor(viewer);
+  //    }
+  //
+  //    /*
+  //     * @see org.eclipse.swt.events.FocusListener#focusGained(org.eclipse.swt.events.FocusEvent)
+  //     */
+  //    public void focusGained(FocusEvent e) {
+  //    }
+  //
+  //    /*
+  //     * @see org.eclipse.swt.events.FocusListener#focusLost(org.eclipse.swt.events.FocusEvent)
+  //     */
+  //    public void focusLost(FocusEvent event) {
+  //      deactivate();
+  //    }
+  //
+  //    /*
+  //     * @see org.eclipse.jface.text.IDocumentListener#documentAboutToBeChanged(org.eclipse.jface.text.DocumentEvent)
+  //     */
+  //    public void documentAboutToBeChanged(DocumentEvent event) {
+  //      if (fActive && fActiveRegion != null) {
+  //        fRememberedPosition = new Position(fActiveRegion.getOffset(), fActiveRegion.getLength());
+  //        try {
+  //          event.getDocument().addPosition(fRememberedPosition);
+  //        } catch (BadLocationException x) {
+  //          fRememberedPosition = null;
+  //        }
+  //      }
+  //    }
+  //
+  //    /*
+  //     * @see org.eclipse.jface.text.IDocumentListener#documentChanged(org.eclipse.jface.text.DocumentEvent)
+  //     */
+  //    public void documentChanged(DocumentEvent event) {
+  //      if (fRememberedPosition != null && !fRememberedPosition.isDeleted()) {
+  //        event.getDocument().removePosition(fRememberedPosition);
+  //        fActiveRegion = new Region(fRememberedPosition.getOffset(), fRememberedPosition.getLength());
+  //      }
+  //      fRememberedPosition = null;
+  //
+  //      ISourceViewer viewer = getSourceViewer();
+  //      if (viewer != null) {
+  //        StyledText widget = viewer.getTextWidget();
+  //        if (widget != null && !widget.isDisposed()) {
+  //          widget.getDisplay().asyncExec(new Runnable() {
+  //            public void run() {
+  //              deactivate();
+  //            }
+  //          });
+  //        }
+  //      }
+  //    }
+  //
+  //    /*
+  //     * @see org.eclipse.jface.text.ITextInputListener#inputDocumentAboutToBeChanged(org.eclipse.jface.text.IDocument,
+  //     * org.eclipse.jface.text.IDocument)
+  //     */
+  //    public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) {
+  //      if (oldInput == null)
+  //        return;
+  //      deactivate();
+  //      oldInput.removeDocumentListener(this);
+  //    }
+  //
+  //    /*
+  //     * @see org.eclipse.jface.text.ITextInputListener#inputDocumentChanged(org.eclipse.jface.text.IDocument,
+  //     * org.eclipse.jface.text.IDocument)
+  //     */
+  //    public void inputDocumentChanged(IDocument oldInput, IDocument newInput) {
+  //      if (newInput == null)
+  //        return;
+  //      newInput.addDocumentListener(this);
+  //    }
+  //
+  //    /*
+  //     * @see PaintListener#paintControl(PaintEvent)
+  //     */
+  //    public void paintControl(PaintEvent event) {
+  //      if (fActiveRegion == null)
+  //        return;
+  //
+  //      ISourceViewer viewer = getSourceViewer();
+  //      if (viewer == null)
+  //        return;
+  //
+  //      StyledText text = viewer.getTextWidget();
+  //      if (text == null || text.isDisposed())
+  //        return;
+  //
+  //      int offset = 0;
+  //      int length = 0;
+  //
+  //      if (viewer instanceof ITextViewerExtension3) {
+  //
+  //        ITextViewerExtension3 extension = (ITextViewerExtension3) viewer;
+  //        IRegion widgetRange = extension.modelRange2WidgetRange(new Region(offset, length));
+  //        if (widgetRange == null)
+  //          return;
+  //
+  //        offset = widgetRange.getOffset();
+  //        length = widgetRange.getLength();
+  //
+  //      } else {
+  //
+  //        IRegion region = viewer.getVisibleRegion();
+  //        if (!includes(region, fActiveRegion))
+  //          return;
+  //
+  //        offset = fActiveRegion.getOffset() - region.getOffset();
+  //        length = fActiveRegion.getLength();
+  //      }
+  //
+  //      // support for bidi
+  //      Point minLocation = getMinimumLocation(text, offset, length);
+  //      Point maxLocation = getMaximumLocation(text, offset, length);
+  //
+  //      int x1 = minLocation.x;
+  //      int x2 = minLocation.x + maxLocation.x - minLocation.x - 1;
+  //      int y = minLocation.y + text.getLineHeight() - 1;
+  //
+  //      GC gc = event.gc;
+  //      if (fColor != null && !fColor.isDisposed())
+  //        gc.setForeground(fColor);
+  //      gc.drawLine(x1, y, x2, y);
+  //    }
+  //
+  //    private boolean includes(IRegion region, IRegion position) {
+  //      return position.getOffset() >= region.getOffset()
+  //          && position.getOffset() + position.getLength() <= region.getOffset() + region.getLength();
+  //    }
+  //
+  //    private Point getMinimumLocation(StyledText text, int offset, int length) {
+  //      Point minLocation = new Point(Integer.MAX_VALUE, Integer.MAX_VALUE);
+  //
+  //      for (int i = 0; i <= length; i++) {
+  //        Point location = text.getLocationAtOffset(offset + i);
+  //
+  //        if (location.x < minLocation.x)
+  //          minLocation.x = location.x;
+  //        if (location.y < minLocation.y)
+  //          minLocation.y = location.y;
+  //      }
+  //
+  //      return minLocation;
+  //    }
+  //
+  //    private Point getMaximumLocation(StyledText text, int offset, int length) {
+  //      Point maxLocation = new Point(Integer.MIN_VALUE, Integer.MIN_VALUE);
+  //
+  //      for (int i = 0; i <= length; i++) {
+  //        Point location = text.getLocationAtOffset(offset + i);
+  //
+  //        if (location.x > maxLocation.x)
+  //          maxLocation.x = location.x;
+  //        if (location.y > maxLocation.y)
+  //          maxLocation.y = location.y;
+  //      }
+  //
+  //      return maxLocation;
+  //    }
+  //  };
+  /*
+   * Link mode.
+   */
   class MouseClickListener implements KeyListener, MouseListener, MouseMoveListener, FocusListener, PaintListener,
-      IPropertyChangeListener, IDocumentListener, ITextInputListener {
+      IPropertyChangeListener, IDocumentListener, ITextInputListener, ITextPresentationListener {
 
     /** The session is active. */
     private boolean fActive;
@@ -690,7 +1374,6 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
     }
 
     public void install() {
-
       ISourceViewer sourceViewer = getSourceViewer();
       if (sourceViewer == null)
         return;
@@ -713,6 +1396,8 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
       text.addFocusListener(this);
       text.addPaintListener(this);
 
+      ((ITextViewerExtension4) sourceViewer).addTextPresentationListener(this);
+
       updateKeyModifierMask();
 
       IPreferenceStore preferenceStore = getPreferenceStore();
@@ -723,10 +1408,9 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
       String modifiers = getPreferenceStore().getString(BROWSER_LIKE_LINKS_KEY_MODIFIER);
       fKeyModifierMask = computeStateMask(modifiers);
       if (fKeyModifierMask == -1) {
-        // Fallback to stored state mask
+        // Fall back to stored state mask
         fKeyModifierMask = getPreferenceStore().getInt(BROWSER_LIKE_LINKS_KEY_MODIFIER_MASK);
       }
-      ;
     }
 
     private int computeStateMask(String modifiers) {
@@ -760,19 +1444,23 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
       }
 
       ISourceViewer sourceViewer = getSourceViewer();
-      if (sourceViewer == null)
-        return;
-
-      sourceViewer.removeTextInputListener(this);
+      if (sourceViewer != null)
+        sourceViewer.removeTextInputListener(this);
 
-      IDocument document = sourceViewer.getDocument();
-      if (document != null)
-        document.removeDocumentListener(this);
+      IDocumentProvider documentProvider = getDocumentProvider();
+      if (documentProvider != null) {
+        IDocument document = documentProvider.getDocument(getEditorInput());
+        if (document != null)
+          document.removeDocumentListener(this);
+      }
 
       IPreferenceStore preferenceStore = getPreferenceStore();
       if (preferenceStore != null)
         preferenceStore.removePropertyChangeListener(this);
 
+      if (sourceViewer == null)
+        return;
+
       StyledText text = sourceViewer.getTextWidget();
       if (text == null || text.isDisposed())
         return;
@@ -782,6 +1470,8 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
       text.removeMouseMoveListener(this);
       text.removeFocusListener(this);
       text.removePaintListener(this);
+
+      ((ITextViewerExtension4) sourceViewer).removeTextPresentationListener(this);
     }
 
     /*
@@ -810,8 +1500,15 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
     }
 
     /**
-     * Creates a color from the information stored in the given preference store. Returns <code>null</code> if there is no such
-     * information available.
+     * Creates a color from the information stored in the given preference store.
+     * 
+     * @param store
+     *          the preference store
+     * @param key
+     *          the key
+     * @param display
+     *          the display
+     * @return the color or <code>null</code> if there is no such information available
      */
     private Color createColor(IPreferenceStore store, String key, Display display) {
 
@@ -840,36 +1537,36 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
       if (fActiveRegion == null)
         return;
 
+      int offset = fActiveRegion.getOffset();
+      int length = fActiveRegion.getLength();
+      fActiveRegion = null;
+
       ISourceViewer viewer = getSourceViewer();
       if (viewer != null) {
-        resetCursor(viewer);
 
-        int offset = fActiveRegion.getOffset();
-        int length = fActiveRegion.getLength();
+        resetCursor(viewer);
 
-        // remove style
+        // Invalidate ==> remove applied text presentation
         if (!redrawAll && viewer instanceof ITextViewerExtension2)
           ((ITextViewerExtension2) viewer).invalidateTextPresentation(offset, length);
         else
           viewer.invalidateTextPresentation();
 
-        // remove underline
-        if (viewer instanceof ITextViewerExtension3) {
-          ITextViewerExtension3 extension = (ITextViewerExtension3) viewer;
+        // Remove underline
+        if (viewer instanceof ITextViewerExtension5) {
+          ITextViewerExtension5 extension = (ITextViewerExtension5) viewer;
           offset = extension.modelOffset2WidgetOffset(offset);
         } else {
           offset -= viewer.getVisibleRegion().getOffset();
         }
-
-        StyledText text = viewer.getTextWidget();
         try {
-          text.redrawRange(offset, length, true);
+          StyledText text = viewer.getTextWidget();
+
+          text.redrawRange(offset, length, false);
         } catch (IllegalArgumentException x) {
-          PHPeclipsePlugin.log(x);
+          //                                   JavaPlugin.log(x);
         }
       }
-
-      fActiveRegion = null;
     }
 
     // will eventually be replaced by a method provided by jdt.core
@@ -881,7 +1578,8 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
 
         while (offset >= 0) {
           c = document.getChar(offset);
-          if (!Character.isJavaIdentifierPart(c))
+          //                                   if (!Character.isJavaIdentifierPart(c)&&c!='$')
+          if (!Scanner.isPHPIdentifierPart(c) && c != '$')
             break;
           --offset;
         }
@@ -893,7 +1591,8 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
 
         while (offset < length) {
           c = document.getChar(offset);
-          if (!Character.isJavaIdentifierPart(c))
+          //                                   if (!Character.isJavaIdentifierPart(c)&&c!='$')
+          if (!Scanner.isPHPIdentifierPart(c) && c != '$')
             break;
           ++offset;
         }
@@ -916,26 +1615,25 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
       if (offset == -1)
         return null;
 
-      return null;
-      //                               IJavaElement input= SelectionConverter.getInput(PHPEditor.this);
-      //                               if (input == null)
-      //                                       return null;
-      //      
-      //                               try {
-      //                               
-      //                                       IJavaElement[] elements= null;
-      //                                       synchronized (input) {
-      //                                               elements= ((ICodeAssist) input).codeSelect(offset, 0);
-      //                                       }
-      //                               
-      //                                       if (elements == null || elements.length == 0)
-      //                                               return null;
-      //                                       
-      //                                       return selectWord(viewer.getDocument(), offset);
-      //                                       
-      //                               } catch (JavaModelException e) {
-      //                                       return null;
-      //                               }
+      IJavaElement input = SelectionConverter.getInput(PHPEditor.this);
+      if (input == null)
+        return null;
+
+      //                       try {
+
+      //                               IJavaElement[] elements= null;
+      //                               synchronized (input) {
+      //                                       elements= ((ICodeAssist) input).codeSelect(offset, 0);
+      //                               }
+      //                               
+      //                               if (elements == null || elements.length == 0)
+      //                                       return null;
+
+      return selectWord(viewer.getDocument(), offset);
+
+      //                       } catch (JavaModelException e) {
+      //                               return null;
+      //                       }
     }
 
     private int getCurrentTextOffset(ISourceViewer viewer) {
@@ -950,8 +1648,8 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
         Point relativePosition = text.toControl(absolutePosition);
 
         int widgetOffset = text.getOffsetAtLocation(relativePosition);
-        if (viewer instanceof ITextViewerExtension3) {
-          ITextViewerExtension3 extension = (ITextViewerExtension3) viewer;
+        if (viewer instanceof ITextViewerExtension5) {
+          ITextViewerExtension5 extension = (ITextViewerExtension5) viewer;
           return extension.widgetOffset2ModelOffset(widgetOffset);
         } else {
           return widgetOffset + viewer.getVisibleRegion().getOffset();
@@ -962,6 +1660,15 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
       }
     }
 
+    public void applyTextPresentation(TextPresentation textPresentation) {
+      if (fActiveRegion == null)
+        return;
+      IRegion region = textPresentation.getExtent();
+      if (fActiveRegion.getOffset() + fActiveRegion.getLength() >= region.getOffset()
+          && region.getOffset() + region.getLength() > fActiveRegion.getOffset())
+        textPresentation.mergeStyleRange(new StyleRange(fActiveRegion.getOffset(), fActiveRegion.getLength(), fColor, null));
+    }
+
     private void highlightRegion(ISourceViewer viewer, IRegion region) {
 
       if (region.equals(fActiveRegion))
@@ -973,12 +1680,11 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
       if (text == null || text.isDisposed())
         return;
 
-      // highlight region
+      // Underline
       int offset = 0;
       int length = 0;
-
-      if (viewer instanceof ITextViewerExtension3) {
-        ITextViewerExtension3 extension = (ITextViewerExtension3) viewer;
+      if (viewer instanceof ITextViewerExtension5) {
+        ITextViewerExtension5 extension = (ITextViewerExtension5) viewer;
         IRegion widgetRange = extension.modelRange2WidgetRange(region);
         if (widgetRange == null)
           return;
@@ -990,17 +1696,14 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
         offset = region.getOffset() - viewer.getVisibleRegion().getOffset();
         length = region.getLength();
       }
+      text.redrawRange(offset, length, false);
 
-      StyleRange oldStyleRange = text.getStyleRangeAtOffset(offset);
-      Color foregroundColor = fColor;
-      Color backgroundColor = oldStyleRange == null ? text.getBackground() : oldStyleRange.background;
-      StyleRange styleRange = new StyleRange(offset, length, foregroundColor, backgroundColor);
-      text.setStyleRange(styleRange);
-
-      // underline
-      text.redrawRange(offset, length, true);
-
+      // Invalidate region ==> apply text presentation
       fActiveRegion = region;
+      if (viewer instanceof ITextViewerExtension2)
+        ((ITextViewerExtension2) viewer).invalidateTextPresentation(region.getOffset(), region.getLength());
+      else
+        viewer.invalidateTextPresentation();
     }
 
     private void activateCursor(ISourceViewer viewer) {
@@ -1041,18 +1744,18 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
 
       fActive = true;
 
-      //                               removed for #25871
+      //                       removed for #25871
       //
-      //                               ISourceViewer viewer= getSourceViewer();
-      //                               if (viewer == null)
-      //                                       return;
+      //                       ISourceViewer viewer= getSourceViewer();
+      //                       if (viewer == null)
+      //                               return;
       //                       
-      //                               IRegion region= getCurrentTextRegion(viewer);
-      //                               if (region == null)
-      //                                       return;
+      //                       IRegion region= getCurrentTextRegion(viewer);
+      //                       if (region == null)
+      //                               return;
       //                       
-      //                               highlightRegion(viewer, region);
-      //                               activateCursor(viewer);
+      //                       highlightRegion(viewer, region);
+      //                       activateCursor(viewer);
     }
 
     /*
@@ -1190,21 +1893,29 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
      * @see org.eclipse.jface.text.IDocumentListener#documentChanged(org.eclipse.jface.text.DocumentEvent)
      */
     public void documentChanged(DocumentEvent event) {
-      if (fRememberedPosition != null && !fRememberedPosition.isDeleted()) {
-        event.getDocument().removePosition(fRememberedPosition);
-        fActiveRegion = new Region(fRememberedPosition.getOffset(), fRememberedPosition.getLength());
-      }
-      fRememberedPosition = null;
+      if (fRememberedPosition != null) {
+        if (!fRememberedPosition.isDeleted()) {
 
-      ISourceViewer viewer = getSourceViewer();
-      if (viewer != null) {
-        StyledText widget = viewer.getTextWidget();
-        if (widget != null && !widget.isDisposed()) {
-          widget.getDisplay().asyncExec(new Runnable() {
-            public void run() {
-              deactivate();
+          event.getDocument().removePosition(fRememberedPosition);
+          fActiveRegion = new Region(fRememberedPosition.getOffset(), fRememberedPosition.getLength());
+          fRememberedPosition = null;
+
+          ISourceViewer viewer = getSourceViewer();
+          if (viewer != null) {
+            StyledText widget = viewer.getTextWidget();
+            if (widget != null && !widget.isDisposed()) {
+              widget.getDisplay().asyncExec(new Runnable() {
+                public void run() {
+                  deactivate();
+                }
+              });
             }
-          });
+          }
+
+        } else {
+          fActiveRegion = null;
+          fRememberedPosition = null;
+          deactivate();
         }
       }
     }
@@ -1248,10 +1959,10 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
       int offset = 0;
       int length = 0;
 
-      if (viewer instanceof ITextViewerExtension3) {
+      if (viewer instanceof ITextViewerExtension5) {
 
-        ITextViewerExtension3 extension = (ITextViewerExtension3) viewer;
-        IRegion widgetRange = extension.modelRange2WidgetRange(new Region(offset, length));
+        ITextViewerExtension5 extension = (ITextViewerExtension5) viewer;
+        IRegion widgetRange = extension.modelRange2WidgetRange(fActiveRegion);
         if (widgetRange == null)
           return;
 
@@ -1316,7 +2027,7 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
 
       return maxLocation;
     }
-  };
+  }
 
   /**
    * This action dispatches into two behaviours: If there is no current text hover, the javadoc is displayed using information
@@ -1431,6 +2142,416 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
     }
   };
 
+  /**
+   * This action implements smart home.
+   * 
+   * Instead of going to the start of a line it does the following:
+   *  - if smart home/end is enabled and the caret is after the line's first non-whitespace then the caret is moved directly before
+   * it, taking JavaDoc and multi-line comments into account. - if the caret is before the line's first non-whitespace the caret is
+   * moved to the beginning of the line - if the caret is at the beginning of the line see first case.
+   * 
+   * @since 3.0
+   */
+  protected class SmartLineStartAction extends LineStartAction {
+
+    /**
+     * Creates a new smart line start action
+     * 
+     * @param textWidget
+     *          the styled text widget
+     * @param doSelect
+     *          a boolean flag which tells if the text up to the beginning of the line should be selected
+     */
+    public SmartLineStartAction(final StyledText textWidget, final boolean doSelect) {
+      super(textWidget, doSelect);
+    }
+
+    /*
+     * @see org.eclipse.ui.texteditor.AbstractTextEditor.LineStartAction#getLineStartPosition(java.lang.String, int,
+     *      java.lang.String)
+     */
+    protected int getLineStartPosition(final IDocument document, final String line, final int length, final int offset) {
+
+      String type = IDocument.DEFAULT_CONTENT_TYPE;
+      try {
+        type = TextUtilities.getContentType(document, IPHPPartitions.PHP_PARTITIONING, offset, true);
+      } catch (BadLocationException exception) {
+        // Should not happen
+      }
+
+      int index = super.getLineStartPosition(document, line, length, offset);
+      if (type.equals(IPHPPartitions.PHP_PHPDOC_COMMENT) || type.equals(IPHPPartitions.PHP_MULTILINE_COMMENT)) {
+        if (index < length - 1 && line.charAt(index) == '*' && line.charAt(index + 1) != '/') {
+          do {
+            ++index;
+          } while (index < length && Character.isWhitespace(line.charAt(index)));
+        }
+      } else {
+        if (index < length - 1 && line.charAt(index) == '/' && line.charAt(index + 1) == '/') {
+          index++;
+          do {
+            ++index;
+          } while (index < length && Character.isWhitespace(line.charAt(index)));
+        }
+      }
+      return index;
+    }
+  }
+
+  /**
+   * Text navigation action to navigate to the next sub-word.
+   * 
+   * @since 3.0
+   */
+  protected abstract class NextSubWordAction extends TextNavigationAction {
+
+    protected JavaWordIterator fIterator = new JavaWordIterator();
+
+    /**
+     * Creates a new next sub-word action.
+     * 
+     * @param code
+     *          Action code for the default operation. Must be an action code from
+     * @see org.eclipse.swt.custom.ST.
+     */
+    protected NextSubWordAction(int code) {
+      super(getSourceViewer().getTextWidget(), code);
+    }
+
+    /*
+     * @see org.eclipse.jface.action.IAction#run()
+     */
+    public void run() {
+      // Check whether we are in a java code partition and the preference is enabled
+      final IPreferenceStore store = getPreferenceStore();
+      if (!store.getBoolean(PreferenceConstants.EDITOR_SUB_WORD_NAVIGATION)) {
+        super.run();
+        return;
+      }
+
+      final ISourceViewer viewer = getSourceViewer();
+      final IDocument document = viewer.getDocument();
+      fIterator.setText((CharacterIterator) new DocumentCharacterIterator(document));
+      int position = widgetOffset2ModelOffset(viewer, viewer.getTextWidget().getCaretOffset());
+      if (position == -1)
+        return;
+
+      int next = findNextPosition(position);
+      if (next != BreakIterator.DONE) {
+        setCaretPosition(next);
+        getTextWidget().showSelection();
+        fireSelectionChanged();
+      }
+
+    }
+
+    /**
+     * Finds the next position after the given position.
+     * 
+     * @param position
+     *          the current position
+     * @return the next position
+     */
+    protected int findNextPosition(int position) {
+      ISourceViewer viewer = getSourceViewer();
+      int widget = -1;
+      while (position != BreakIterator.DONE && widget == -1) { // TODO: optimize
+        position = fIterator.following(position);
+        if (position != BreakIterator.DONE)
+          widget = modelOffset2WidgetOffset(viewer, position);
+      }
+      return position;
+    }
+
+    /**
+     * Sets the caret position to the sub-word boundary given with <code>position</code>.
+     * 
+     * @param position
+     *          Position where the action should move the caret
+     */
+    protected abstract void setCaretPosition(int position);
+  }
+
+  /**
+   * Text navigation action to navigate to the next sub-word.
+   * 
+   * @since 3.0
+   */
+  protected class NavigateNextSubWordAction extends NextSubWordAction {
+
+    /**
+     * Creates a new navigate next sub-word action.
+     */
+    public NavigateNextSubWordAction() {
+      super(ST.WORD_NEXT);
+    }
+
+    /*
+     * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.NextSubWordAction#setCaretPosition(int)
+     */
+    protected void setCaretPosition(final int position) {
+      getTextWidget().setCaretOffset(modelOffset2WidgetOffset(getSourceViewer(), position));
+    }
+  }
+
+  /**
+   * Text operation action to delete the next sub-word.
+   * 
+   * @since 3.0
+   */
+  protected class DeleteNextSubWordAction extends NextSubWordAction implements IUpdate {
+
+    /**
+     * Creates a new delete next sub-word action.
+     */
+    public DeleteNextSubWordAction() {
+      super(ST.DELETE_WORD_NEXT);
+    }
+
+    /*
+     * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.NextSubWordAction#setCaretPosition(int)
+     */
+    protected void setCaretPosition(final int position) {
+      if (!validateEditorInputState())
+        return;
+
+      final ISourceViewer viewer = getSourceViewer();
+      final int caret = widgetOffset2ModelOffset(viewer, viewer.getTextWidget().getCaretOffset());
+
+      try {
+        viewer.getDocument().replace(caret, position - caret, ""); //$NON-NLS-1$
+      } catch (BadLocationException exception) {
+        // Should not happen
+      }
+    }
+
+    /*
+     * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.NextSubWordAction#findNextPosition(int)
+     */
+    protected int findNextPosition(int position) {
+      return fIterator.following(position);
+    }
+
+    /*
+     * @see org.eclipse.ui.texteditor.IUpdate#update()
+     */
+    public void update() {
+      setEnabled(isEditorInputModifiable());
+    }
+  }
+
+  /**
+   * Text operation action to select the next sub-word.
+   * 
+   * @since 3.0
+   */
+  protected class SelectNextSubWordAction extends NextSubWordAction {
+
+    /**
+     * Creates a new select next sub-word action.
+     */
+    public SelectNextSubWordAction() {
+      super(ST.SELECT_WORD_NEXT);
+    }
+
+    /*
+     * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.NextSubWordAction#setCaretPosition(int)
+     */
+    protected void setCaretPosition(final int position) {
+      final ISourceViewer viewer = getSourceViewer();
+
+      final StyledText text = viewer.getTextWidget();
+      if (text != null && !text.isDisposed()) {
+
+        final Point selection = text.getSelection();
+        final int caret = text.getCaretOffset();
+        final int offset = modelOffset2WidgetOffset(viewer, position);
+
+        if (caret == selection.x)
+          text.setSelectionRange(selection.y, offset - selection.y);
+        else
+          text.setSelectionRange(selection.x, offset - selection.x);
+      }
+    }
+  }
+
+  /**
+   * Text navigation action to navigate to the previous sub-word.
+   * 
+   * @since 3.0
+   */
+  protected abstract class PreviousSubWordAction extends TextNavigationAction {
+
+    protected JavaWordIterator fIterator = new JavaWordIterator();
+
+    /**
+     * Creates a new previous sub-word action.
+     * 
+     * @param code
+     *          Action code for the default operation. Must be an action code from
+     * @see org.eclipse.swt.custom.ST.
+     */
+    protected PreviousSubWordAction(final int code) {
+      super(getSourceViewer().getTextWidget(), code);
+    }
+
+    /*
+     * @see org.eclipse.jface.action.IAction#run()
+     */
+    public void run() {
+      // Check whether we are in a java code partition and the preference is enabled
+      final IPreferenceStore store = getPreferenceStore();
+      if (!store.getBoolean(PreferenceConstants.EDITOR_SUB_WORD_NAVIGATION)) {
+        super.run();
+        return;
+      }
+
+      final ISourceViewer viewer = getSourceViewer();
+      final IDocument document = viewer.getDocument();
+      fIterator.setText((CharacterIterator) new DocumentCharacterIterator(document));
+      int position = widgetOffset2ModelOffset(viewer, viewer.getTextWidget().getCaretOffset());
+      if (position == -1)
+        return;
+
+      int previous = findPreviousPosition(position);
+      if (previous != BreakIterator.DONE) {
+        setCaretPosition(previous);
+        getTextWidget().showSelection();
+        fireSelectionChanged();
+      }
+
+    }
+
+    /**
+     * Finds the previous position before the given position.
+     * 
+     * @param position
+     *          the current position
+     * @return the previous position
+     */
+    protected int findPreviousPosition(int position) {
+      ISourceViewer viewer = getSourceViewer();
+      int widget = -1;
+      while (position != BreakIterator.DONE && widget == -1) { // TODO: optimize
+        position = fIterator.preceding(position);
+        if (position != BreakIterator.DONE)
+          widget = modelOffset2WidgetOffset(viewer, position);
+      }
+      return position;
+    }
+
+    /**
+     * Sets the caret position to the sub-word boundary given with <code>position</code>.
+     * 
+     * @param position
+     *          Position where the action should move the caret
+     */
+    protected abstract void setCaretPosition(int position);
+  }
+
+  /**
+   * Text navigation action to navigate to the previous sub-word.
+   * 
+   * @since 3.0
+   */
+  protected class NavigatePreviousSubWordAction extends PreviousSubWordAction {
+
+    /**
+     * Creates a new navigate previous sub-word action.
+     */
+    public NavigatePreviousSubWordAction() {
+      super(ST.WORD_PREVIOUS);
+    }
+
+    /*
+     * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.PreviousSubWordAction#setCaretPosition(int)
+     */
+    protected void setCaretPosition(final int position) {
+      getTextWidget().setCaretOffset(modelOffset2WidgetOffset(getSourceViewer(), position));
+    }
+  }
+
+  /**
+   * Text operation action to delete the previous sub-word.
+   * 
+   * @since 3.0
+   */
+  protected class DeletePreviousSubWordAction extends PreviousSubWordAction implements IUpdate {
+
+    /**
+     * Creates a new delete previous sub-word action.
+     */
+    public DeletePreviousSubWordAction() {
+      super(ST.DELETE_WORD_PREVIOUS);
+    }
+
+    /*
+     * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.PreviousSubWordAction#setCaretPosition(int)
+     */
+    protected void setCaretPosition(final int position) {
+      if (!validateEditorInputState())
+        return;
+
+      final ISourceViewer viewer = getSourceViewer();
+      final int caret = widgetOffset2ModelOffset(viewer, viewer.getTextWidget().getCaretOffset());
+
+      try {
+        viewer.getDocument().replace(position, caret - position, ""); //$NON-NLS-1$
+      } catch (BadLocationException exception) {
+        // Should not happen
+      }
+    }
+
+    /*
+     * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.PreviousSubWordAction#findPreviousPosition(int)
+     */
+    protected int findPreviousPosition(int position) {
+      return fIterator.preceding(position);
+    }
+
+    /*
+     * @see org.eclipse.ui.texteditor.IUpdate#update()
+     */
+    public void update() {
+      setEnabled(isEditorInputModifiable());
+    }
+  }
+
+  /**
+   * Text operation action to select the previous sub-word.
+   * 
+   * @since 3.0
+   */
+  protected class SelectPreviousSubWordAction extends PreviousSubWordAction {
+
+    /**
+     * Creates a new select previous sub-word action.
+     */
+    public SelectPreviousSubWordAction() {
+      super(ST.SELECT_WORD_PREVIOUS);
+    }
+
+    /*
+     * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.PreviousSubWordAction#setCaretPosition(int)
+     */
+    protected void setCaretPosition(final int position) {
+      final ISourceViewer viewer = getSourceViewer();
+
+      final StyledText text = viewer.getTextWidget();
+      if (text != null && !text.isDisposed()) {
+
+        final Point selection = text.getSelection();
+        final int caret = text.getCaretOffset();
+        final int offset = modelOffset2WidgetOffset(viewer, position);
+
+        if (caret == selection.x)
+          text.setSelectionRange(selection.y, offset - selection.y);
+        else
+          text.setSelectionRange(selection.x, offset - selection.x);
+      }
+    }
+  }
+
   //  static protected class AnnotationAccess implements IAnnotationAccess {
   //    /*
   //     * @see
@@ -1633,10 +2754,8 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
   private int fIgnoreOutlinePageSelection;
 
   /** The outline page selection updater */
-  private OutlinePageSelectionUpdater fUpdater;
-
+  //  private OutlinePageSelectionUpdater fUpdater;
   //  protected PHPSyntaxParserThread fValidationThread = null;
-
   // private IPreferenceStore fPHPPrefStore;
   /** The selection changed listener */
   //  protected ISelectionChangedListener fSelectionChangedListener = new
@@ -1906,11 +3025,14 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
     fEditorSelectionChangedListener = new EditorSelectionChangedListener();
     fEditorSelectionChangedListener.install(getSelectionProvider());
 
+    if (isBrowserLikeLinks())
+      enableBrowserLikeLinks();
+
     if (PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_DISABLE_OVERWRITE_MODE))
       enableOverwriteMode(false);
-    
+
     setWordWrap();
-    // getEditorSite().getShell().addShellListener(fActivationListener);
+    //    getEditorSite().getShell().addShellListener(fActivationListener);
   }
 
   private void setWordWrap() {
@@ -2054,6 +3176,15 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
   protected void createActions() {
     super.createActions();
 
+    ActionGroup oeg, ovg, jsg, sg;
+    fActionGroups = new CompositeActionGroup(new ActionGroup[] { oeg = new OpenEditorActionGroup(this),
+    //         sg= new ShowActionGroup(this),
+        //             ovg= new OpenViewActionGroup(this),
+        //             jsg= new JavaSearchActionGroup(this)
+        });
+    fContextMenuGroup = new CompositeActionGroup(new ActionGroup[] { oeg });
+    //, ovg, sg, jsg});
+
     fFoldingGroup = new FoldingActionGroup(this, getViewer());
 
     ResourceAction resAction = new TextOperationAction(PHPEditorMessages.getResourceBundle(),
@@ -2316,18 +3447,36 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
    */
   //  protected void doSetInput(IEditorInput input) throws CoreException {
   //    super.doSetInput(input);
-  //
   //    if (fEncodingSupport != null)
   //      fEncodingSupport.reset();
-  //    if (fOutlinePage != null)
-  //      fOutlinePage.setInput(input);
-  //    // setOutlinePageInput(fOutlinePage, input);
+  //    setOutlinePageInput(fOutlinePage, input);
   //  }
+  /*
+   * @see AbstractTextEditor#doSetInput
+   */
   protected void doSetInput(IEditorInput input) throws CoreException {
-    super.doSetInput(input);
-    if (fEncodingSupport != null)
-      fEncodingSupport.reset();
-    setOutlinePageInput(fOutlinePage, input);
+    ISourceViewer sourceViewer = getSourceViewer();
+    if (!(sourceViewer instanceof ISourceViewerExtension2)) {
+      setPreferenceStore(createCombinedPreferenceStore(input));
+      internalDoSetInput(input);
+      return;
+    }
+
+    // uninstall & unregister preference store listener
+    if (isBrowserLikeLinks())
+      disableBrowserLikeLinks();
+    getSourceViewerDecorationSupport(sourceViewer).uninstall();
+    ((ISourceViewerExtension2) sourceViewer).unconfigure();
+
+    setPreferenceStore(createCombinedPreferenceStore(input));
+
+    // install & register preference store listener
+    sourceViewer.configure(getSourceViewerConfiguration());
+    getSourceViewerDecorationSupport(sourceViewer).install(getPreferenceStore());
+    if (isBrowserLikeLinks())
+      enableBrowserLikeLinks();
+
+    internalDoSetInput(input);
   }
 
   /*
@@ -2747,7 +3896,7 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
         } else if (value instanceof String) {
           try {
             sourceViewer.getTextWidget().setTabs(Integer.parseInt((String) value));
-          } catch (NumberFormatException e){
+          } catch (NumberFormatException e) {
             // bug #1038071 - set default tab:
             sourceViewer.getTextWidget().setTabs(80);
           }
@@ -3013,12 +4162,11 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
   /*
    * @see AbstractTextEditor#handleCursorPositionChanged()
    */
-  protected void handleCursorPositionChanged() {
-    super.handleCursorPositionChanged();
-    if (!isEditingScriptRunning() && fUpdater != null)
-      fUpdater.post();
-  }
-
+  //  protected void handleCursorPositionChanged() {
+  //    super.handleCursorPositionChanged();
+  //    if (!isEditingScriptRunning() && fUpdater != null)
+  //      fUpdater.post();
+  //  }
   /*
    * @see org.eclipse.ui.texteditor.AbstractTextEditor#handleElementContentReplaced()
    */
@@ -3915,6 +5063,88 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
     return key != null && store.getBoolean(key);
   }
 
+  protected boolean isPrefQuickDiffAlwaysOn() {
+    return false; // never show change ruler for the non-editable java editor. Overridden in subclasses like PHPUnitEditor
+  }
+
+  /*
+   * @see org.eclipse.ui.texteditor.AbstractTextEditor#createNavigationActions()
+   */
+  protected void createNavigationActions() {
+    super.createNavigationActions();
+
+    final StyledText textWidget = getSourceViewer().getTextWidget();
+
+    IAction action = new SmartLineStartAction(textWidget, false);
+    action.setActionDefinitionId(ITextEditorActionDefinitionIds.LINE_START);
+    setAction(ITextEditorActionDefinitionIds.LINE_START, action);
+
+    action = new SmartLineStartAction(textWidget, true);
+    action.setActionDefinitionId(ITextEditorActionDefinitionIds.SELECT_LINE_START);
+    setAction(ITextEditorActionDefinitionIds.SELECT_LINE_START, action);
+
+    action = new NavigatePreviousSubWordAction();
+    action.setActionDefinitionId(ITextEditorActionDefinitionIds.WORD_PREVIOUS);
+    setAction(ITextEditorActionDefinitionIds.WORD_PREVIOUS, action);
+    textWidget.setKeyBinding(SWT.CTRL | SWT.ARROW_LEFT, SWT.NULL);
+
+    action = new NavigateNextSubWordAction();
+    action.setActionDefinitionId(ITextEditorActionDefinitionIds.WORD_NEXT);
+    setAction(ITextEditorActionDefinitionIds.WORD_NEXT, action);
+    textWidget.setKeyBinding(SWT.CTRL | SWT.ARROW_RIGHT, SWT.NULL);
+
+    action = new SelectPreviousSubWordAction();
+    action.setActionDefinitionId(ITextEditorActionDefinitionIds.SELECT_WORD_PREVIOUS);
+    setAction(ITextEditorActionDefinitionIds.SELECT_WORD_PREVIOUS, action);
+    textWidget.setKeyBinding(SWT.CTRL | SWT.SHIFT | SWT.ARROW_LEFT, SWT.NULL);
+
+    action = new SelectNextSubWordAction();
+    action.setActionDefinitionId(ITextEditorActionDefinitionIds.SELECT_WORD_NEXT);
+    setAction(ITextEditorActionDefinitionIds.SELECT_WORD_NEXT, action);
+    textWidget.setKeyBinding(SWT.CTRL | SWT.SHIFT | SWT.ARROW_RIGHT, SWT.NULL);
+  }
+
+  /*
+   * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#createCompositeRuler()
+   */
+  protected CompositeRuler createCompositeRuler() {
+    if (!getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_ANNOTATION_ROLL_OVER))
+      return super.createCompositeRuler();
+
+    CompositeRuler ruler = new CompositeRuler();
+    AnnotationRulerColumn column = new AnnotationRulerColumn(VERTICAL_RULER_WIDTH, getAnnotationAccess());
+    column.setHover(new JavaExpandHover(ruler, getAnnotationAccess(), new IDoubleClickListener() {
+
+      public void doubleClick(DoubleClickEvent event) {
+        // for now: just invoke ruler double click action
+        triggerAction(ITextEditorActionConstants.RULER_DOUBLE_CLICK);
+      }
+
+      private void triggerAction(String actionID) {
+        IAction action = getAction(actionID);
+        if (action != null) {
+          if (action instanceof IUpdate)
+            ((IUpdate) action).update();
+          // hack to propagate line change
+          if (action instanceof ISelectionListener) {
+            ((ISelectionListener) action).selectionChanged(null, null);
+          }
+          if (action.isEnabled())
+            action.run();
+        }
+      }
+
+    }));
+    ruler.addDecorator(0, column);
+
+    if (isLineNumberRulerVisible())
+      ruler.addDecorator(1, createLineNumberRulerColumn());
+    else if (isPrefQuickDiffAlwaysOn())
+      ruler.addDecorator(1, createChangeRulerColumn());
+
+    return ruler;
+  }
+
   /**
    * Returns the folding action group, or <code>null</code> if there is none.
    * 
@@ -3925,6 +5155,34 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
     return fFoldingGroup;
   }
 
+  /*
+   * @see org.eclipse.ui.texteditor.AbstractTextEditor#performRevert()
+   */
+  protected void performRevert() {
+    ProjectionViewer projectionViewer = (ProjectionViewer) getSourceViewer();
+    projectionViewer.setRedraw(false);
+    try {
+
+      boolean projectionMode = projectionViewer.isProjectionMode();
+      if (projectionMode) {
+        projectionViewer.disableProjection();
+        if (fProjectionModelUpdater != null)
+          fProjectionModelUpdater.uninstall();
+      }
+
+      super.performRevert();
+
+      if (projectionMode) {
+        if (fProjectionModelUpdater != null)
+          fProjectionModelUpdater.install(this, projectionViewer);
+        projectionViewer.enableProjection();
+      }
+
+    } finally {
+      projectionViewer.setRedraw(true);
+    }
+  }
+
   /**
    * React to changed selection.
    * 
index 6605410..5ee914e 100644 (file)
@@ -10,6 +10,21 @@ public interface PHPEditorActionDefinitionIds  extends ITextEditorActionDefiniti
    * @since 2.1
    */
   public static final String GOTO_MATCHING_BRACKET = "net.sourceforge.phpeclipse.ui.edit.text.php.goto.matching.bracket"; //$NON-NLS-1$
+  /**
+        * Action definition ID of the edit -> go to next member action
+        * (value <code>"org.eclipse.jdt.ui.edit.text.java.goto.next.member"</code>).
+        *
+        * @since 2.1
+        */
+       public static final String GOTO_NEXT_MEMBER= "net.sourceforge.phpeclipse.ui.edit.text.php.goto.next.member"; //$NON-NLS-1$
+
+       /**
+        * Action definition ID of the edit -> go to previous member action
+        * (value <code>"org.eclipse.jdt.ui.edit.text.java.goto.previous.member"</code>).
+        *
+        * @since 2.1
+        */
+       public static final String GOTO_PREVIOUS_MEMBER= "net.sourceforge.phpeclipse.ui.edit.text.php.goto.previous.member"; //$NON-NLS-1$
 
   /**
    * Value: net.sourceforge.phpeclipse.phpeditor.comment
@@ -60,5 +75,4 @@ public interface PHPEditorActionDefinitionIds  extends ITextEditorActionDefiniti
         */
 //  public static final String CONTENT_ASSIST_PROPOSALS = "net.sourceforge.phpeclipse.ui.edit.text.php.content.assist.proposals"; //$NON-NLS-1$
   
-  
 }
index ac33467..d1a3355 100644 (file)
@@ -17,7 +17,10 @@ import net.sourceforge.phpdt.core.JavaCore;
 import net.sourceforge.phpdt.core.JavaModelException;
 import net.sourceforge.phpdt.core.dom.CompilationUnit;
 import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
+import net.sourceforge.phpdt.internal.ui.actions.AddBlockCommentAction;
 import net.sourceforge.phpdt.internal.ui.actions.CompositeActionGroup;
+import net.sourceforge.phpdt.internal.ui.actions.IndentAction;
+import net.sourceforge.phpdt.internal.ui.actions.RemoveBlockCommentAction;
 import net.sourceforge.phpdt.internal.ui.text.ContentAssistPreference;
 import net.sourceforge.phpdt.internal.ui.text.IPHPPartitions;
 import net.sourceforge.phpdt.internal.ui.text.PHPPairMatcher;
@@ -44,7 +47,6 @@ import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Preferences;
-import net.sourceforge.phpeclipse.phpeditor.ICompilationUnitDocumentProvider;
 import org.eclipse.jface.action.Action;
 import org.eclipse.jface.action.IAction;
 import org.eclipse.jface.action.IMenuManager;
@@ -1516,21 +1518,51 @@ public class PHPUnitEditor extends PHPEditor { //implements
     //         markAsStateDependentAction("IndentOnTab", true); //$NON-NLS-1$
     //         markAsSelectionDependentAction("IndentOnTab", true); //$NON-NLS-1$
     //         
+    
+    action= new AddBlockCommentAction(PHPEditorMessages.getResourceBundle(), "AddBlockComment.", this);  //$NON-NLS-1$
+       action.setActionDefinitionId(PHPEditorActionDefinitionIds.ADD_BLOCK_COMMENT);           
+       setAction("AddBlockComment", action); //$NON-NLS-1$
+       markAsStateDependentAction("AddBlockComment", true); //$NON-NLS-1$
+       markAsSelectionDependentAction("AddBlockComment", true); //$NON-NLS-1$          
+//     WorkbenchHelp.setHelp(action, IJavaHelpContextIds.ADD_BLOCK_COMMENT_ACTION);
+
+       action= new RemoveBlockCommentAction(PHPEditorMessages.getResourceBundle(), "RemoveBlockComment.", this);  //$NON-NLS-1$
+       action.setActionDefinitionId(PHPEditorActionDefinitionIds.REMOVE_BLOCK_COMMENT);                
+       setAction("RemoveBlockComment", action); //$NON-NLS-1$
+       markAsStateDependentAction("RemoveBlockComment", true); //$NON-NLS-1$
+       markAsSelectionDependentAction("RemoveBlockComment", true); //$NON-NLS-1$               
+//     WorkbenchHelp.setHelp(action, IJavaHelpContextIds.REMOVE_BLOCK_COMMENT_ACTION);
+       
+//     action= new IndentAction(PHPEditorMessages.getResourceBundle(), "Indent.", this, false); //$NON-NLS-1$
+//     action.setActionDefinitionId(PHPEditorActionDefinitionIds.INDENT);              
+//     setAction("Indent", action); //$NON-NLS-1$
+//     markAsStateDependentAction("Indent", true); //$NON-NLS-1$
+//     markAsSelectionDependentAction("Indent", true); //$NON-NLS-1$
+////   WorkbenchHelp.setHelp(action, IJavaHelpContextIds.INDENT_ACTION);
+//     
+       action= new IndentAction(PHPEditorMessages.getResourceBundle(), "Indent.", this, true); //$NON-NLS-1$
+       setAction("IndentOnTab", action); //$NON-NLS-1$
+       markAsStateDependentAction("IndentOnTab", true); //$NON-NLS-1$
+       markAsSelectionDependentAction("IndentOnTab", true); //$NON-NLS-1$
+       
     if (getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_SMART_TAB)) {
       // don't replace Shift Right - have to make sure their enablement is
       // mutually exclusive
       //                       removeActionActivationCode(ITextEditorActionConstants.SHIFT_RIGHT);
       setActionActivationCode("IndentOnTab", '\t', -1, SWT.NONE); //$NON-NLS-1$
     }
-    fGenerateActionGroup = new GenerateActionGroup(this, ITextEditorActionConstants.GROUP_EDIT);
-    fActionGroups = new CompositeActionGroup(new ActionGroup[] { fGenerateActionGroup });
-    //   We have to keep the context menu group separate to have better
-    // control
-    // over positioning
-    fContextMenuGroup = new CompositeActionGroup(new ActionGroup[] { fGenerateActionGroup });
-    //      rg,
-    //      new LocalHistoryActionGroup(this,
-    // ITextEditorActionConstants.GROUP_EDIT)});
+    fGenerateActionGroup= new GenerateActionGroup(this, ITextEditorActionConstants.GROUP_EDIT);
+//    ActionGroup rg= new RefactorActionGroup(this, ITextEditorActionConstants.GROUP_EDIT);
+       
+//     fActionGroups.addGroup(rg);
+       fActionGroups.addGroup(fGenerateActionGroup);
+       
+       // We have to keep the context menu group separate to have better control over positioning
+       fContextMenuGroup= new CompositeActionGroup(new ActionGroup[] {
+               fGenerateActionGroup
+//             rg, 
+//             new LocalHistoryActionGroup(this, ITextEditorActionConstants.GROUP_EDIT)
+               });
 
   }
 
@@ -1715,78 +1747,6 @@ public class PHPUnitEditor extends PHPEditor { //implements
 //    return store.getBoolean(PRINT_MARGIN);
 //  }
 
-  //  private void startAnnotationIndication(AnnotationType annotationType) {
-  //    if (fProblemPainter == null) {
-  //      fProblemPainter = new ProblemPainter(this, getSourceViewer());
-  //// fPaintManager.addPainter(fProblemPainter);
-  //    }
-  //    fProblemPainter.setColor(annotationType, getColor(annotationType));
-  //    fProblemPainter.paintAnnotations(annotationType, true);
-  //    fProblemPainter.paint(IPainter.CONFIGURATION);
-  //  }
-  //
-  //  private void shutdownAnnotationIndication() {
-  //    if (fProblemPainter != null) {
-  //
-  //      if (!fProblemPainter.isPaintingAnnotations()) {
-  //// fPaintManager.removePainter(fProblemPainter);
-  //        fProblemPainter.deactivate(true);
-  //        fProblemPainter.dispose();
-  //        fProblemPainter = null;
-  //      } else {
-  //        fProblemPainter.paint(IPainter.CONFIGURATION);
-  //      }
-  //    }
-  //  }
-  //
-  //  private void stopAnnotationIndication(AnnotationType annotationType) {
-  //    if (fProblemPainter != null) {
-  //      fProblemPainter.paintAnnotations(annotationType, false);
-  //      shutdownAnnotationIndication();
-  //    }
-  //  }
-  //
-  //  private boolean isAnnotationIndicationEnabled(AnnotationType
-  // annotationType) {
-  //    IPreferenceStore store = getPreferenceStore();
-  //    AnnotationInfo info = (AnnotationInfo)
-  // ANNOTATION_MAP.get(annotationType);
-  //    if (info != null)
-  //      return store.getBoolean(info.fEditorPreference);
-  //    return false;
-  //  }
-  //
-  //  private boolean
-  // isAnnotationIndicationInOverviewRulerEnabled(AnnotationType
-  // annotationType) {
-  //    IPreferenceStore store = getPreferenceStore();
-  //    AnnotationInfo info = (AnnotationInfo)
-  // ANNOTATION_MAP.get(annotationType);
-  //    if (info != null)
-  //      return store.getBoolean(info.fOverviewRulerPreference);
-  //    return false;
-  //  }
-  //
-  //  private void showAnnotationIndicationInOverviewRuler(AnnotationType
-  // annotationType, boolean show) {
-  //    AdaptedSourceViewer asv = (AdaptedSourceViewer) getSourceViewer();
-  //    OverviewRuler ruler = asv.getOverviewRuler();
-  //    if (ruler != null) {
-  //      ruler.setColor(annotationType, getColor(annotationType));
-  //      ruler.showAnnotation(annotationType, show);
-  //      ruler.update();
-  //    }
-  //  }
-  //
-  //  private void setColorInOverviewRuler(AnnotationType annotationType, Color
-  // color) {
-  //    AdaptedSourceViewer asv = (AdaptedSourceViewer) getSourceViewer();
-  //    OverviewRuler ruler = asv.getOverviewRuler();
-  //    if (ruler != null) {
-  //      ruler.setColor(annotationType, color);
-  //      ruler.update();
-  //    }
-  //  }
 
   private int getTabSize() {
     Preferences preferences = PHPeclipsePlugin.getDefault().getPluginPreferences();
@@ -1798,30 +1758,6 @@ public class PHPUnitEditor extends PHPEditor { //implements
     return store.getBoolean(SPACES_FOR_TABS);
   }
 
-  //  private void showOverviewRuler() {
-  //    AdaptedSourceViewer asv = (AdaptedSourceViewer) getSourceViewer();
-  //    asv.showOverviewRuler();
-  //
-  //    OverviewRuler overviewRuler = asv.getOverviewRuler();
-  //    if (overviewRuler != null) {
-  //      for (int i = 0; i < ANNOTATION_LAYERS.length; i++) {
-  //        AnnotationType type = ANNOTATION_LAYERS[i];
-  //        overviewRuler.setLayer(type, i);
-  //        if (isAnnotationIndicationInOverviewRulerEnabled(type))
-  //          showAnnotationIndicationInOverviewRuler(type, true);
-  //      }
-  //    }
-  //  }
-  //
-  //  private void hideOverviewRuler() {
-  //    AdaptedSourceViewer asv = (AdaptedSourceViewer) getSourceViewer();
-  //    asv.hideOverviewRuler();
-  //  }
-  //
-  //  private boolean isOverviewRulerVisible() {
-  //    IPreferenceStore store = getPreferenceStore();
-  //    return store.getBoolean(OVERVIEW_RULER);
-  //  }
   private Color getColor(String key) {
     RGB rgb = PreferenceConverter.getColor(getPreferenceStore(), key);
     return getColor(rgb);