Improved completion processor
authorkhartlage <khartlage>
Mon, 23 Dec 2002 21:26:23 +0000 (21:26 +0000)
committerkhartlage <khartlage>
Mon, 23 Dec 2002 21:26:23 +0000 (21:26 +0000)
43 files changed:
net.sourceforge.phpeclipse/icons/ctool16/php.gif [new file with mode: 0644]
net.sourceforge.phpeclipse/icons/ctool16/php_page.gif [new file with mode: 0644]
net.sourceforge.phpeclipse/icons/obj16/class_obj.gif [new file with mode: 0644]
net.sourceforge.phpeclipse/icons/obj16/error_obj.gif [new file with mode: 0644]
net.sourceforge.phpeclipse/icons/obj16/fun_obj.gif [new file with mode: 0644]
net.sourceforge.phpeclipse/icons/obj16/info_obj.gif [new file with mode: 0644]
net.sourceforge.phpeclipse/icons/obj16/warning_obj.gif [new file with mode: 0644]
net.sourceforge.phpeclipse/plugin.xml
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/template/default-templates.xml
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/template/java/CompilationUnitContext.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/textmanipulation/TextBuffer.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/textmanipulation/TextBufferFactory.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/PHPStatusConstants.java [moved from net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/JavaStatusConstants.java with 73% similarity]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/PHPUIException.java [moved from net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/JavaUIException.java with 77% similarity]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/PHPUIMessages.java [moved from net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/JavaUIMessages.java with 82% similarity]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/PHPUIMessages.properties [moved from net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/JavaUIMessages.properties with 100% similarity]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/PHPUIStatus.java [moved from net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/JavaUIStatus.java with 60% similarity]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/PHPUiImages.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/dialog/AbstractElementListSelectionDialog.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/dialog/CheckedTreeSelectionDialog.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/dialog/ElementListSelectionDialog.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/dialog/ISelectionValidator.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/dialog/MessageLine.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/dialog/SelectionStatusDialog.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/dialog/StatusDialog.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/dialog/StatusInfo.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/java/JavaCompletionProcessor_NotInUseVersion.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/template/IdentifierEngine.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/template/IdentifierProposal.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/DirectorySelector.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/ExceptionHandler.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/FilteredList.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/PHPElementVisitor.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/PHPFileSelector.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/PHPProjectSelector.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/PixelConverter.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/ResourceSelector.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/SWTUtil.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/StringMatcher.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/TwoArrayQuickSorter.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/viewsupport/ContainerCheckedTreeViewer.java [new file with mode: 0644]
net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/viewsupport/ImageDescriptorRegistry.java [new file with mode: 0644]
net.sourceforge.phpeclipse/templates.xml [new file with mode: 0644]

diff --git a/net.sourceforge.phpeclipse/icons/ctool16/php.gif b/net.sourceforge.phpeclipse/icons/ctool16/php.gif
new file mode 100644 (file)
index 0000000..f01f87e
Binary files /dev/null and b/net.sourceforge.phpeclipse/icons/ctool16/php.gif differ
diff --git a/net.sourceforge.phpeclipse/icons/ctool16/php_page.gif b/net.sourceforge.phpeclipse/icons/ctool16/php_page.gif
new file mode 100644 (file)
index 0000000..dc6de60
Binary files /dev/null and b/net.sourceforge.phpeclipse/icons/ctool16/php_page.gif differ
diff --git a/net.sourceforge.phpeclipse/icons/obj16/class_obj.gif b/net.sourceforge.phpeclipse/icons/obj16/class_obj.gif
new file mode 100644 (file)
index 0000000..2db7604
Binary files /dev/null and b/net.sourceforge.phpeclipse/icons/obj16/class_obj.gif differ
diff --git a/net.sourceforge.phpeclipse/icons/obj16/error_obj.gif b/net.sourceforge.phpeclipse/icons/obj16/error_obj.gif
new file mode 100644 (file)
index 0000000..b04020b
Binary files /dev/null and b/net.sourceforge.phpeclipse/icons/obj16/error_obj.gif differ
diff --git a/net.sourceforge.phpeclipse/icons/obj16/fun_obj.gif b/net.sourceforge.phpeclipse/icons/obj16/fun_obj.gif
new file mode 100644 (file)
index 0000000..b512915
Binary files /dev/null and b/net.sourceforge.phpeclipse/icons/obj16/fun_obj.gif differ
diff --git a/net.sourceforge.phpeclipse/icons/obj16/info_obj.gif b/net.sourceforge.phpeclipse/icons/obj16/info_obj.gif
new file mode 100644 (file)
index 0000000..26c7477
Binary files /dev/null and b/net.sourceforge.phpeclipse/icons/obj16/info_obj.gif differ
diff --git a/net.sourceforge.phpeclipse/icons/obj16/warning_obj.gif b/net.sourceforge.phpeclipse/icons/obj16/warning_obj.gif
new file mode 100644 (file)
index 0000000..cf8d571
Binary files /dev/null and b/net.sourceforge.phpeclipse/icons/obj16/warning_obj.gif differ
index a54447b..b84555d 100644 (file)
                id="net.sourceforge.phpeclipse.actions.showAction">
          </action>
       </objectContribution>
-      <viewerContribution
-            targetID="#PHPEditorContext"
-            id="net.sourceforge.phpeclipse.actions.popup.editor">
-         <action
-               label="PHP Help"
-               class="net.sourceforge.phpeclipse.actions.PHPEclipseShowContextHelp"
-               menubarPath="additions"
-               id="net.sourceforge.phpeclipse.actions.editor.contexthelp">
-         </action>
-      </viewerContribution>
    </extension>
    <extension
          point="org.eclipse.ui.preferencePages">
             id="net.sourceforge.phpeclipse.preference.PHPEclipsePreferencePage">
       </page>
       <page
-            name="PHP Editor"
+            name="Editor"
             category="net.sourceforge.phpeclipse.preference.PHPEclipsePreferencePage"
             class="net.sourceforge.phpeclipse.PHPSyntaxPreferencePage"
             id="net.sourceforge.phpeclipse.preference.PHPSyntaxPreferencePage">
index cd33d19..d635aae 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-
-<!--
-(c) Copyright IBM Corp. 2000, 2001.
-All Rights Reserved.
--->
-
 <templates>
-
-  <!-- php -->
-
-  <template description="iterate over array" name="for" context="php"
->for (int ${index} = 0; ${index} &lt; ${array}.length; ${index}++) {
-       ${cursor}
+<template name="class" description="class template with constructor" context="php" enabled="true">class ${class_name} {
+  function ${class_name}() {
+         ${cursor}
+  }
 }</template>
+<template name="class" description="class with attribute" context="php" enabled="true">class ${class_name} {
+  var $$${attribute};
+  function ${class_name}() {
+         ${cursor}
+  }
+  
+  function set_${attribute}( $$${attr} ) {
+    $$this->${attribute} = $$${attr};
+       }
 
-  <template description="iterate over array w/ temporary variable" name="for" context="php"
->for (int ${index} = 0; ${index} &lt; ${array}.length; ${index}++) {
-       ${array_type} ${array_element} = ${array}[${index}];
-       ${cursor}
+       function get_${attribute}() {
+    return $$this->${attribute};
+       }
 }</template>
-
-  <template description="iterate over collection" name="for" context="php"
->for (Iterator ${iterator} = ${collection}.iterator(); ${iterator}.hasNext(); ) {
-       ${type} ${element} = (${type}) ${iterator}.next();
+<template name="for" description="iterate over array" context="php" enabled="true">for ($$${index} = 0; $$${index} &lt; sizeof($$${array}); $$${index}++) {
        ${cursor}
 }</template>
-
-  <template description="iterate with enumeration" name="while" context="php"
->while (${enumeration}.hasMoreElements()) {
-       ${type} ${element} = (${type}) ${enumeration}.nextElement();
+<template name="for" description="iterate over array w/ temporary variable" context="php" enabled="true">for ($$${index} = 0; $$${index} &lt; sizeof($$${array}); $$${index}++) {
+       $$${array_element} = $$${array}[$$${index}];
        ${cursor}
 }</template>
-
-  <template description="iterate with iterator" name="while" context="php"
->while (${iterator}.hasNext()) {
-       ${type} ${element} = (${type}) ${iterator}.next();
+<template name="function" description="function template" context="php" enabled="true">function ${function_name} () {
        ${cursor}
 }</template>
-
-  <template description="do while statement" name="do" context="php"
->do {
+<template name="function" description="function template with return" context="php" enabled="true">function ${function_name} () {
+       return (${cursor});
+}</template>
+<template name="while" description="while iteration" context="php" enabled="true">while (${condition}) {
        ${cursor}
-} while (${condition});</template>
-
-  <template description="switch case statement" name="switch" context="php"
->switch (${key}) {
+}</template>
+<template name="switch" description="switch case statement" context="php" enabled="true">switch (${key}) {
        case ${value}:
                ${cursor}
                break;
 
        default:
                break;
-}</template>
-
-  <template description="if statement" name="if" context="php"
->if (${condition}) {
+}</template><template name="if" description="if statement" context="php" enabled="true">if (${condition}) {
        ${cursor}
-}</template>
-
-  <template description="if else statement" name="ifelse" context="php"
->if (${condition}) {
+}</template><template name="ifelse" description="if else statement" context="php" enabled="true">if (${condition}) {
        ${cursor}
 } else {
        
-}</template>
-
-  <template description="else if block" name="elseif" context="php"
->else if (${condition}) {
-       ${cursor}
-}</template>
-
-  <template description="else block" name="else" context="php"
->else {
-       ${cursor}
-}</template>
-
-  <template description="try catch block" name="try" context="php"
->try {
+}</template><template name="elseif" description="else if block" context="php" enabled="true">elseif (${condition}) {
        ${cursor}
-} catch (${Exception} e) {
-}</template>
-
-  <template description="catch block" name="catch" context="php"
->catch (${Exception} e) {
-       ${cursor}
-}</template>
-
-  <template description="main method" name="main" context="php"
->
-public static void main(String[] args) {
-       ${cursor}
-}</template>
-
-  <template description="public method" name="public_method" context="php"
->
-public ${return_type} ${name}(${arguments}) {
+}</template><template name="else" description="else block" context="php" enabled="true">else {
        ${cursor}
 }</template>
-
-  <template description="protected method" name="protected_method" context="php"
->protected ${return_type} ${name}(${arguments}) {
-       ${cursor}
-}</template>
-
-  <template description="private method" name="private_method" context="php"
->private ${return_type} ${name}(${arguments}) {
-       ${cursor}
-}</template>
-
-  <template description="private static method" name="private_static_method" context="php"
->private static ${return_type} ${name}(${arguments}) {
-       ${cursor}
-}</template>
-
-  <template description="dynamic type test and cast" name="instanceof" context="php"
->if (${name} instanceof ${type}) {
-       ${type} ${new_name} = (${type})${name};
-       ${cursor}
-}</template>
-
-  <template description="dynamic cast" name="cast" context="php"
->${type} ${new_name} = (${type}) ${name};
-</template>
-
-  <template description="create new object" name="new" context="php"
->${type} ${name} = new ${type}(${arguments});
-</template>
-
-  <template description="lazy creation" name="lazy" context="php"
->if (${name} == null) {
-       ${name} = new ${type}(${arguments});
-       ${cursor}
-}
-
-return ${name};
-</template>
-
-  <template description="convert collection to array" name="toarray" context="php"
-  >(${type}[]) ${collection}.toArray(new ${type}[${collection}.size()]);</template>
-
-  <template context="php" description="file comment used by the class and interface wizards" enabled="true" name="filecomment">/**
- * Created on ${date}
+<template name="filecomment" description="file comment used by the class and interface wizards" context="php" enabled="true">/**
+ * Created on ${date} by ${user}
  *
- * To change this generated comment edit the template variable &quot;filecomment&quot;:
- * Window&gt;Preferences&gt;Java&gt;Templates.
- * To enable and disable the creation of file comments go to
- * Window&gt;Preferences&gt;Java&gt;Code Generation.
- */</template>
-
-<template name="typecomment" description="type comment used by the class and interface wizards" context="php" enabled="true">/**
+ */</template><template name="functioncomment" description="function comment" context="php" enabled="true">/**
  * @author ${user}
  *
- * To change this generated comment edit the template variable &quot;typecomment&quot;:
- * Window&gt;Preferences&gt;Java&gt;Templates.
- * To enable and disable the creation of type comments go to
- * Window&gt;Preferences&gt;Java&gt;Code Generation.
- */</template> 
-
-  <template description="print to standard out" name="stdout" context="php"
-  >System.out.println(${cursor});</template>
-
-  <template description="print to standard error" name="stderr" context="php"
-  >System.err.println(${cursor});</template>
-
-  <!-- html -->
-
-  <template description="&lt;code&gt;&lt;/code&gt;" name="&lt;code&gt;" context="html"
-  >&lt;code&gt;${cursor}&lt;/code&gt;</template>
-
-  <template description="&lt;code&gt;null&lt;/code&gt;" name="&lt;code&gt;" context="html"
-  >&lt;code&gt;null&lt;/code&gt;</template>
-
-  <template description="&lt;pre&gt;&lt;/pre&gt;" name="&lt;pre&gt;" context="html"
-  >&lt;pre&gt;${cursor}&lt;/pre&gt;</template>
-
-  <template description="&lt;b&gt;&lt;/b&gt;" name="&lt;b&gt;" context="html"
-  >&lt;b&gt;${cursor}&lt;/b&gt;</template>
-
-  <template description="&lt;i&gt;&lt;/i&gt;" name="&lt;i&gt;" context="html"
-  >&lt;i&gt;${cursor}&lt;/i&gt;</template>
-
-  <template description="author name" name="@author" context="html"
-  >@author ${user}</template>
-
-</templates>
+ */</template>
+ <template name="echo" description="echo a string" context="php" enabled="true">echo "${string}";
+  ${cursor}</template>
+ </templates>
\ No newline at end of file
index dcc8f00..17f42d6 100644 (file)
@@ -47,6 +47,19 @@ public class CompilationUnitContext extends DocumentTemplateContext {
     return template.matches(getKey(), getContextType().getName());
   }
   
+  /**
+   * Returns <code>true</code> if template matches the prefix and context,
+   * <code>false</code> otherwise.
+   */
+  public boolean canEvaluate(String identifier) {
+    String prefix = getKey();
+    return 
+//      fEnabled &&
+//      fContextTypeName.equals(contextTypeName) &&
+      (prefix.length() != 0) &&
+      identifier.toLowerCase().startsWith(prefix.toLowerCase());
+  }
+  
     /*
    * @see TemplateContext#evaluate(Template template)
    */
@@ -82,11 +95,15 @@ public class CompilationUnitContext extends DocumentTemplateContext {
     try {
       int start= getCompletionPosition();
   
-      while ((start != 0) && Character.isUnicodeIdentifierPart(document.getChar(start - 1)))
+      while ( ((start != 0) && Character.isUnicodeIdentifierPart(document.getChar(start - 1))) ||
+               ((start != 0) && document.getChar(start - 1)=='$') ) {
         start--;
+      }
         
-      if ((start != 0) && Character.isUnicodeIdentifierStart(document.getChar(start - 1)))
+      if ( ((start != 0) && Character.isUnicodeIdentifierStart(document.getChar(start - 1))) ||
+           ((start != 0) && document.getChar(start - 1)=='$')) {
         start--;
+      }
   
       return start;
 
index c7e2476..90884f9 100644 (file)
@@ -14,7 +14,7 @@ import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Status;
 import net.sourceforge.phpdt.internal.corext.util.Strings;
-import net.sourceforge.phpdt.internal.ui.JavaStatusConstants;
+import net.sourceforge.phpdt.internal.ui.PHPStatusConstants;
 import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.DefaultLineTracker;
 import org.eclipse.jface.text.IDocument;
@@ -303,7 +303,7 @@ public class TextBuffer {
                try {
                        fDocument.replace(offset, length, text);
                } catch (BadLocationException e) {
-                       IStatus s = new Status(IStatus.ERROR, PHPeclipsePlugin.getPluginId(), JavaStatusConstants.INTERNAL_ERROR, 
+                       IStatus s = new Status(IStatus.ERROR, PHPeclipsePlugin.getPluginId(), PHPStatusConstants.INTERNAL_ERROR, 
                                TextManipulationMessages.getFormattedString(
                                        "TextBuffer.wrongRange",  //$NON-NLS-1$
                                        new Object[] {new Integer(offset), new Integer(length) } ), e);
index 5d6800b..e596c7e 100644 (file)
@@ -20,7 +20,7 @@ import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Status;
 import net.sourceforge.phpdt.internal.corext.util.IOCloser;
-import net.sourceforge.phpdt.internal.ui.JavaStatusConstants;
+import net.sourceforge.phpdt.internal.ui.PHPStatusConstants;
 import org.eclipse.jface.text.Document;
 import org.eclipse.jface.text.IDocument;
 import org.eclipse.jface.text.source.IAnnotationModel;
@@ -145,7 +145,7 @@ import org.eclipse.ui.texteditor.IDocumentProvider;
                        document.set(buffer.toString());
                        return new TextBuffer(document);
                } catch (IOException x) {
-                       IStatus s= new Status(IStatus.ERROR, PHPeclipsePlugin.getPluginId(), JavaStatusConstants.INTERNAL_ERROR, x.getMessage(), x);
+                       IStatus s= new Status(IStatus.ERROR, PHPeclipsePlugin.getPluginId(), PHPStatusConstants.INTERNAL_ERROR, x.getMessage(), x);
                        throw new CoreException(s);
                } finally {
                        IOCloser.perform(in, stream);
@@ -179,7 +179,7 @@ import org.eclipse.ui.texteditor.IDocumentProvider;
        
        private void throwNotManaged() throws CoreException {
                IStatus s= new Status(IStatus.ERROR, PHPeclipsePlugin.getPluginId(), 
-                       JavaStatusConstants.INTERNAL_ERROR, TextManipulationMessages.getString("TextBufferFactory.bufferNotManaged"), null); //$NON-NLS-1$
+                       PHPStatusConstants.INTERNAL_ERROR, TextManipulationMessages.getString("TextBufferFactory.bufferNotManaged"), null); //$NON-NLS-1$
                throw new CoreException(s);
        }
 }
@@ -5,15 +5,15 @@
 package net.sourceforge.phpdt.internal.ui;
 
 /**
- * Defines status codes relevant to the Java UI plug-in. When a 
+ * Defines status codes relevant to the PHP UI plug-in. When a 
  * Core exception is thrown, it contain a status object describing
  * the cause of the exception. The status objects originating from the
- * Java UI plug-in use the codes defined in this interface.
+ * PHP UI plug-in use the codes defined in this interface.
   */
-public class JavaStatusConstants {
+public class PHPStatusConstants {
        
        // Prevent instantiation
-       private JavaStatusConstants() {
+       private PHPStatusConstants() {
        }
 
        /** Status code describing an internal error */
@@ -13,9 +13,9 @@ import org.eclipse.core.runtime.IStatus;
  * support
  */
 
-public class JavaUIException extends CoreException {
+public class PHPUIException extends CoreException {
        
-       public JavaUIException(IStatus status) {
+       public PHPUIException(IStatus status) {
                super(status);
        }       
 }
\ No newline at end of file
@@ -8,13 +8,13 @@ import java.text.MessageFormat;
 import java.util.MissingResourceException;
 import java.util.ResourceBundle;
 
-public class JavaUIMessages {
+public class PHPUIMessages {
 
-       private static final String RESOURCE_BUNDLE= "org.eclipse.jdt.internal.ui.JavaUIMessages";//$NON-NLS-1$
+       private static final String RESOURCE_BUNDLE = PHPUIMessages.class.getName();//$NON-NLS-1$
 
        private static ResourceBundle fgResourceBundle= ResourceBundle.getBundle(RESOURCE_BUNDLE);
 
-       private JavaUIMessages() {
+       private PHPUIMessages() {
        }
 
        public static String getString(String key) {
@@ -9,19 +9,19 @@ import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Status;
 
 /**
- * Convenience class for error exceptions thrown inside JavaUI plugin.
+ * Convenience class for error exceptions thrown inside PHPUI plugin.
  */
-public class JavaUIStatus extends Status {
+public class PHPUIStatus extends Status {
 
-       public JavaUIStatus(int code, String message, Throwable throwable) {
+       public PHPUIStatus(int code, String message, Throwable throwable) {
                super(IStatus.ERROR, PHPeclipsePlugin.getPluginId(), code, message, throwable);
        }
 
-       public JavaUIStatus(int code, String message) {
+       public PHPUIStatus(int code, String message) {
                this(code, message, null);
        }
 
-       public JavaUIStatus(int code) {
+       public PHPUIStatus(int code) {
                this(code, ""); //$NON-NLS-1$
        }
 }
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/PHPUiImages.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/PHPUiImages.java
new file mode 100644 (file)
index 0000000..4cc1713
--- /dev/null
@@ -0,0 +1,126 @@
+package net.sourceforge.phpdt.internal.ui;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import net.sourceforge.phpeclipse.PHPeclipsePlugin;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.swt.graphics.Image;
+
+public class PHPUiImages {
+
+       protected static final String NAME_PREFIX = "net.sourceforge.phpdt.internal.ui.";
+       protected static final int NAME_PREFIX_LENGTH = NAME_PREFIX.length();
+  
+       protected static URL iconBaseURL;
+
+       static {
+               String pathSuffix = "icons/";
+               try {
+                       iconBaseURL = new URL(PHPeclipsePlugin.getDefault().getDescriptor().getInstallURL(), pathSuffix);
+               } catch (MalformedURLException e) {
+                       PHPeclipsePlugin.log(e);
+               }
+       }
+
+       protected static final ImageRegistry IMAGE_REGISTRY = new ImageRegistry();
+
+       protected static final String OBJ_PREFIX = "obj16";
+       protected static final String OVR_PREFIX = "ovr16";
+       protected static final String CTOOL_PREFIX = "ctool16";
+
+  public static final String IMG_CLASS = NAME_PREFIX + "class_obj.gif";
+  public static final String IMG_FUN = NAME_PREFIX + "fun_obj.gif";
+       public static final String IMG_OBJS_ERROR = NAME_PREFIX + "error_obj.gif";
+       public static final String IMG_OBJS_WARNING = NAME_PREFIX + "warning_obj.gif";
+       public static final String IMG_OBJS_INFO = NAME_PREFIX + "info_obj.gif";
+       public static final String IMG_CTOOLS_PHP_PAGE = NAME_PREFIX + "php_page.gif";
+       public static final String IMG_CTOOLS_PHP = NAME_PREFIX + "php.gif";
+
+  public static final ImageDescriptor DESC_CLASS = createManaged(OBJ_PREFIX, IMG_CLASS);
+  public static final ImageDescriptor DESC_FUN = createManaged(OBJ_PREFIX, IMG_FUN);
+       public static final ImageDescriptor DESC_OBJS_ERROR = createManaged(OBJ_PREFIX, IMG_OBJS_ERROR);
+       public static final ImageDescriptor DESC_OBJS_WARNING = createManaged(OBJ_PREFIX, IMG_OBJS_WARNING);
+       public static final ImageDescriptor DESC_OBJS_INFO = createManaged(OBJ_PREFIX, IMG_OBJS_INFO);
+       public static final ImageDescriptor DESC_CTOOL_PHP_PAGE = createManaged(CTOOL_PREFIX, IMG_CTOOLS_PHP_PAGE);
+       public static final ImageDescriptor DESC_CTOOL_PHP = createManaged(CTOOL_PREFIX, IMG_CTOOLS_PHP);
+
+       /**
+        * Returns the image managed under the given key in this registry.
+        * 
+        * @param key the image's key
+        * @return the image managed under the given key
+        */
+       public static Image get(String key) {
+               return IMAGE_REGISTRY.get(key);
+       }
+
+       /**
+        * Sets the three image descriptors for enabled, disabled, and hovered to an action. The actions
+        * are retrieved from the *tool16 folders.
+        */
+       public static void setToolImageDescriptors(IAction action, String iconName) {
+               setImageDescriptors(action, "tool16", iconName);
+       }
+
+       /**
+        * Sets the three image descriptors for enabled, disabled, and hovered to an action. The actions
+        * are retrieved from the *lcl16 folders.
+        */
+       public static void setLocalImageDescriptors(IAction action, String iconName) {
+               setImageDescriptors(action, "lcl16", iconName);
+       }
+
+       public static ImageRegistry getImageRegistry() {
+               return IMAGE_REGISTRY;
+       }
+
+       //---- Helper methods to access icons on the file system --------------------------------------
+
+       protected static void setImageDescriptors(IAction action, String type, String relPath) {
+
+               try {
+                       ImageDescriptor id = ImageDescriptor.createFromURL(makeIconFileURL("d" + type, relPath));
+                       if (id != null)
+                               action.setDisabledImageDescriptor(id);
+               } catch (MalformedURLException e) {}
+
+               try {
+                       ImageDescriptor id = ImageDescriptor.createFromURL(makeIconFileURL("c" + type, relPath));
+                       if (id != null)
+                               action.setHoverImageDescriptor(id);
+               } catch (MalformedURLException e) {}
+
+               action.setImageDescriptor(create("e" + type, relPath));
+       }
+
+       protected static ImageDescriptor createManaged(String prefix, String name) {
+               try {
+                       ImageDescriptor result = ImageDescriptor.createFromURL(makeIconFileURL(prefix, name.substring(NAME_PREFIX_LENGTH)));
+                       IMAGE_REGISTRY.put(name, result);
+                       return result;
+               } catch (MalformedURLException e) {
+                       return ImageDescriptor.getMissingImageDescriptor();
+               }
+       }
+
+       protected static ImageDescriptor create(String prefix, String name) {
+               try {
+                       return ImageDescriptor.createFromURL(makeIconFileURL(prefix, name));
+               } catch (MalformedURLException e) {
+                       return ImageDescriptor.getMissingImageDescriptor();
+               }
+       }
+
+       protected static URL makeIconFileURL(String prefix, String name) throws MalformedURLException {
+               if (iconBaseURL == null)
+                       throw new MalformedURLException();
+
+               StringBuffer buffer = new StringBuffer(prefix);
+               buffer.append('/');
+               buffer.append(name);
+               return new URL(iconBaseURL, buffer.toString());
+       }
+}
\ No newline at end of file
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/dialog/AbstractElementListSelectionDialog.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/dialog/AbstractElementListSelectionDialog.java
new file mode 100644 (file)
index 0000000..751a75d
--- /dev/null
@@ -0,0 +1,420 @@
+package net.sourceforge.phpdt.internal.ui.dialog;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.util.Assert;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import net.sourceforge.phpdt.internal.ui.util.FilteredList;
+
+/**
+ * An abstract class to select elements out of a list of elements.
+ */
+public abstract class AbstractElementListSelectionDialog extends SelectionStatusDialog {
+       
+       private ILabelProvider fRenderer;
+       private boolean fIgnoreCase= true;
+       private boolean fIsMultipleSelection= false;
+       private boolean fMatchEmptyString= true;
+       private boolean fAllowDuplicates= true;
+       
+       private Label fMessage;
+
+       protected FilteredList fFilteredList;
+       private Text fFilterText;
+       
+       private ISelectionValidator fValidator; 
+       private String fFilter= null;
+       
+       private String fEmptyListMessage= ""; //$NON-NLS-1$
+       private String fEmptySelectionMessage= ""; //$NON-NLS-1$
+               
+       private int fWidth= 60;
+       private int fHeight= 18;
+       
+       private Object[] fSelection= new Object[0];
+       
+       /**
+        * Constructs a list selection dialog.
+        * @param renderer The label renderer used
+        * @param ignoreCase Decides if the match string ignores lower/upppr case
+        * @param multipleSelection Allow multiple selection     
+        */
+       protected AbstractElementListSelectionDialog(Shell parent, ILabelProvider renderer)
+       {
+               super(parent);          
+               fRenderer= renderer;
+               
+               int shellStyle= getShellStyle();
+               setShellStyle(shellStyle | SWT.MAX | SWT.RESIZE);
+       }
+
+       /**
+        * Handles default selection (double click).
+        * By default, the OK button is pressed.
+        */     
+       protected void handleDefaultSelected() {
+               if (validateCurrentSelection())
+                       buttonPressed(IDialogConstants.OK_ID);
+       }
+       
+       /**
+        * Specifies if sorting, filtering and folding is case sensitive.
+        */
+       public void setIgnoreCase(boolean ignoreCase) {
+               fIgnoreCase= ignoreCase;
+       }
+       
+       /**
+        * Returns if sorting, filtering and folding is case sensitive.
+        */
+       public boolean isCaseIgnored() {
+               return fIgnoreCase;
+       }
+       
+       /**
+        * Specifies whether everything or nothing should be filtered on
+        * empty filter string.
+        */
+       public void setMatchEmptyString(boolean matchEmptyString) {
+               fMatchEmptyString= matchEmptyString;
+       }
+       
+       /**
+        * Specifies if multiple selection is allowed.
+        */
+       public void setMultipleSelection(boolean multipleSelection) {
+               fIsMultipleSelection= multipleSelection;
+       }
+
+       /**
+        * Specifies whether duplicate entries are displayed or not.
+        */
+       public void setAllowDuplicates(boolean allowDuplicates) {
+               fAllowDuplicates= allowDuplicates;
+       }
+       
+       /**
+        * Sets the list size in unit of characters.
+        * @param width  the width of the list.
+        * @param height the height of the list.
+        */
+       public void setSize(int width, int height) {
+               fWidth= width;
+               fHeight= height;
+       }
+       
+       /**
+        * Sets the message to be displayed if the list is empty.
+        * @param message the message to be displayed.
+        */
+       public void setEmptyListMessage(String message) {
+               fEmptyListMessage= message;
+       }
+
+       /**
+        * Sets the message to be displayed if the selection is empty.
+        * @param message the message to be displayed.
+        */
+       public void setEmptySelectionMessage(String message) {
+               fEmptySelectionMessage= message;
+       }
+       
+       /**
+        * Sets an optional validator to check if the selection is valid.
+        * The validator is invoked whenever the selection changes.
+        * @param validator the validator to validate the selection.
+        */
+       public void setValidator(ISelectionValidator validator) {
+               fValidator= validator;
+       }       
+       
+       /**
+        * Sets the elements of the list (widget).
+        * To be called within open().
+        * @param elements the elements of the list.
+        */
+       protected void setListElements(Object[] elements) {
+               Assert.isNotNull(fFilteredList);
+               fFilteredList.setElements(elements);
+       }
+
+       /**
+        * Sets the filter pattern.
+        * @param filter the filter pattern.
+        */
+       public void setFilter(String filter) {
+               if (fFilterText == null)
+                       fFilter= filter;
+               else
+                       fFilterText.setText(filter);
+       } 
+       
+       /**
+        * Returns the current filter pattern.
+        * @return returns the current filter pattern or <code>null<code> if filter was not set.
+        */
+       public String getFilter() {
+               if (fFilteredList == null)
+                       return fFilter;
+               else
+                       return fFilteredList.getFilter();
+       }
+
+       /**
+        * Returns the indices referring the current selection.
+        * To be called within open().
+        * @return returns the indices of the current selection.
+        */
+       protected int[] getSelectionIndices() {
+               Assert.isNotNull(fFilteredList);
+               return fFilteredList.getSelectionIndices();
+       }
+
+       /**
+        * Returns an index referring the first current selection.
+        * To be called within open().
+        * @return returns the indices of the current selection.
+        */
+       protected int getSelectionIndex() {
+               Assert.isNotNull(fFilteredList);
+               return fFilteredList.getSelectionIndex();
+       }
+       
+       /**
+        * Sets the selection referenced by an array of elements.
+        * To be called within open().
+        * @param selection the indices of the selection.
+        */
+       protected void setSelection(Object[] selection) {
+               Assert.isNotNull(fFilteredList);
+               fFilteredList.setSelection(selection);
+       }
+       
+       /**
+        * Returns an array of the currently selected elements.
+        * To be called within or after open().
+        * @return returns an array of the currently selected elements.
+        */     
+       protected Object[] getSelectedElements() {
+               Assert.isNotNull(fFilteredList);
+               return fFilteredList.getSelection();
+       }
+
+       /**
+        * Returns all elements which are folded together to one entry in the list.
+        * @param  index the index selecting the entry in the list.
+        * @return returns an array of elements folded together.
+        */
+       public Object[] getFoldedElements(int index) {
+               Assert.isNotNull(fFilteredList);
+               return fFilteredList.getFoldedElements(index);
+       }
+                
+       /**
+        * Creates the message text widget and sets layout data.
+        * @param composite the parent composite of the message area.
+        */
+       protected Label createMessageArea(Composite composite) {
+               Label label= super.createMessageArea(composite);
+
+               GridData data= new GridData();
+               data.grabExcessVerticalSpace= false;
+               data.grabExcessHorizontalSpace= true;
+               data.horizontalAlignment= GridData.FILL;
+               data.verticalAlignment= GridData.BEGINNING;
+               label.setLayoutData(data);
+               
+               fMessage= label;
+               
+               return label;
+       }       
+
+       /**
+        * Handles a selection changed event.
+        * By default, the current selection is validated.
+        */
+       protected void handleSelectionChanged() {
+               validateCurrentSelection();
+       }
+       
+       /**
+        * Validates the current selection and updates the status line
+        * accordingly.
+        */
+       protected boolean validateCurrentSelection() {
+               Assert.isNotNull(fFilteredList);
+
+               IStatus status;
+               Object[] elements= getSelectedElements();
+
+               if (elements.length > 0) {
+                       if (fValidator != null) {
+                               status= fValidator.validate(elements);
+                       } else {
+                               status= new StatusInfo();
+                       }
+               } else {                        
+                       if (fFilteredList.isEmpty()) {
+                               status= new StatusInfo(IStatus.ERROR, fEmptyListMessage);
+                       } else {
+                               status= new StatusInfo(IStatus.ERROR, fEmptySelectionMessage);
+                       }
+               }
+
+               updateStatus(status);
+               
+               return status.isOK();
+       }
+
+       /*
+        * @see Dialog#cancelPressed
+        */
+       protected void cancelPressed() {
+               setResult(null);
+               super.cancelPressed();
+       }       
+
+       /**
+        * Creates a filtered list.
+        * @param parent the parent composite.
+        * @return returns the filtered list widget.
+        */
+       protected FilteredList createFilteredList(Composite parent) {
+               int flags= SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL |
+                       (fIsMultipleSelection ? SWT.MULTI : SWT.SINGLE);
+                       
+               FilteredList list= new FilteredList(parent, flags, fRenderer,
+                       fIgnoreCase, fAllowDuplicates, fMatchEmptyString);
+
+               GridData data= new GridData();
+               data.widthHint= convertWidthInCharsToPixels(fWidth);
+               data.heightHint= convertHeightInCharsToPixels(fHeight);
+               data.grabExcessVerticalSpace= true;
+               data.grabExcessHorizontalSpace= true;
+               data.horizontalAlignment= GridData.FILL;
+               data.verticalAlignment= GridData.FILL;
+               list.setLayoutData(data);
+               
+               list.setFilter((fFilter == null ? "" : fFilter)); //$NON-NLS-1$         
+
+               list.addSelectionListener(new SelectionListener() {
+                       public void widgetDefaultSelected(SelectionEvent e) {
+                               handleDefaultSelected();
+                       }
+                       public void widgetSelected(SelectionEvent e) {
+                               handleWidgetSelected();
+                       }
+               });
+
+               fFilteredList= list;            
+
+               return list;            
+       }
+
+       // 3515 
+       private void handleWidgetSelected() {
+               Object[] newSelection= fFilteredList.getSelection();
+               
+               if (newSelection.length != fSelection.length) {
+                       fSelection= newSelection;
+                       handleSelectionChanged();
+               } else {
+                       for (int i= 0; i != newSelection.length; i++) {
+                               if (!newSelection[i].equals(fSelection[i])) {
+                                       fSelection= newSelection;
+                                       handleSelectionChanged();
+                                       break;
+                               }
+                       }
+               }               
+       }
+
+       protected Text createFilterText(Composite parent) {
+               Text text= new Text(parent, SWT.BORDER);
+
+               GridData data= new GridData();
+               data.grabExcessVerticalSpace= false;
+               data.grabExcessHorizontalSpace= true;
+               data.horizontalAlignment= GridData.FILL;
+               data.verticalAlignment= GridData.BEGINNING;
+               text.setLayoutData(data);
+
+               text.setText((fFilter == null ? "" : fFilter)); //$NON-NLS-1$
+               
+               Listener listener= new Listener() {
+                       public void handleEvent(Event e) {
+                               fFilteredList.setFilter(fFilterText.getText());
+                       }
+               };              
+               text.addListener(SWT.Modify, listener);
+
+               text.addKeyListener(new KeyListener() {
+                       public void keyPressed(KeyEvent e) {
+                               if (e.keyCode == SWT.ARROW_DOWN)
+                                       fFilteredList.setFocus();
+                       }
+                       
+                       public void keyReleased(KeyEvent e) {}
+               });
+
+               fFilterText= text;
+                               
+               return text;
+       }
+
+       /*
+        * @see Window#open()
+        */
+       public int open() {
+               BusyIndicator.showWhile(null, new Runnable() {
+                       public void run() {
+                               access$superOpen();
+                       }
+               });
+               return getReturnCode();
+       }
+       
+       private void access$superOpen() {
+               super.open();
+       } 
+       
+       /*
+        * @see Window#create(Shell)
+        */
+       public void create() {
+               super.create();
+
+               Assert.isNotNull(fFilteredList);
+
+       if (fFilteredList.isEmpty()) {
+               handleEmptyList();
+       } else {
+               validateCurrentSelection();
+                       fFilterText.selectAll();
+                       fFilterText.setFocus();
+       }
+       }
+       
+       /**
+        * Handles empty list by disabling widgets.
+        */
+       protected void handleEmptyList() {
+       fMessage.setEnabled(false);
+       fFilterText.setEnabled(false);
+       fFilteredList.setEnabled(false);                
+       }
+       
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/dialog/CheckedTreeSelectionDialog.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/dialog/CheckedTreeSelectionDialog.java
new file mode 100644 (file)
index 0000000..eea9ec7
--- /dev/null
@@ -0,0 +1,319 @@
+package net.sourceforge.phpdt.internal.ui.dialog;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.viewers.CheckStateChangedEvent;
+import org.eclipse.jface.viewers.CheckboxTreeViewer;
+import org.eclipse.jface.viewers.ICheckStateListener;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.jface.viewers.ViewerSorter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Tree;
+import net.sourceforge.phpdt.internal.ui.viewsupport.ContainerCheckedTreeViewer;
+
+/**
+ * A class to select elements out of a tree structure.
+ */
+public class CheckedTreeSelectionDialog extends SelectionStatusDialog {
+
+       private CheckboxTreeViewer fViewer;
+
+       private ILabelProvider fLabelProvider;
+       private ITreeContentProvider fContentProvider;
+
+       private ISelectionValidator fValidator = null;
+       private ViewerSorter fSorter;
+       private String fEmptyListMessage = "No entries available";
+
+       private IStatus fCurrStatus = new StatusInfo();
+       private List fFilters;
+       private Object fInput;
+       private boolean fIsEmpty;
+
+       private int fWidth = 60;
+       private int fHeight = 18;
+
+       private boolean fContainerMode;
+       private Object[] fExpandedElements;
+
+       /**
+        * Constructs an instance of <code>ElementTreeSelectionDialog</code>.
+        * @param labelProvider   the label provider to render the entries
+        * @param contentProvider the content provider to evaluate the tree structure
+        */
+       public CheckedTreeSelectionDialog(Shell parent, ILabelProvider labelProvider, ITreeContentProvider contentProvider) {
+               super(parent);
+
+               fLabelProvider = labelProvider;
+               fContentProvider = contentProvider;
+
+               setResult(new ArrayList(0));
+               setStatusLineAboveButtons(true);
+
+               fContainerMode = false;
+               fExpandedElements = null;
+
+               int shellStyle = getShellStyle();
+               setShellStyle(shellStyle | SWT.MAX | SWT.RESIZE);
+       }
+
+       /**
+        * If set, the checked /gray state of containers (inner nodes) is derived from the checked state of its 
+        * leaf nodes.
+        * @param containerMode The containerMode to set
+        */
+       public void setContainerMode(boolean containerMode) {
+               fContainerMode = containerMode;
+       }
+
+       /**
+        * Sets the initial selection.
+        * Convenience method.
+        * @param selection the initial selection.
+        */
+       public void setInitialSelection(Object selection) {
+               setInitialSelections(new Object[] { selection });
+       }
+
+       /**
+        * Sets the message to be displayed if the list is empty.
+        * @param message the message to be displayed.
+        */
+       public void setEmptyListMessage(String message) {
+               fEmptyListMessage = message;
+       }
+
+       /**
+        * Sets the sorter used by the tree viewer.
+        */
+       public void setSorter(ViewerSorter sorter) {
+               fSorter = sorter;
+       }
+
+       /**
+        * Adds a filter to the tree viewer.
+        * @param filter a filter.
+        */
+       public void addFilter(ViewerFilter filter) {
+               if (fFilters == null)
+                       fFilters = new ArrayList(4);
+
+               fFilters.add(filter);
+       }
+
+       /**
+        * Sets an optional validator to check if the selection is valid.
+        * The validator is invoked whenever the selection changes.
+        * @param validator the validator to validate the selection.
+        */
+       public void setValidator(ISelectionValidator validator) {
+               fValidator = validator;
+       }
+
+       /**
+        * Sets the tree input.
+        * @param input the tree input.
+        */
+       public void setInput(Object input) {
+               fInput = input;
+       }
+
+       /**
+        * Expands the tree
+        */
+       public void setExpandedElements(Object[] elements) {
+               fExpandedElements = elements;
+       }
+
+       /**
+        * Sets the size of the tree in unit of characters.
+        * @param width  the width of the tree.
+        * @param height the height of the tree.
+        */
+       public void setSize(int width, int height) {
+               fWidth = width;
+               fHeight = height;
+       }
+
+       protected void updateOKStatus() {
+               if (!fIsEmpty) {
+                       if (fValidator != null) {
+                               fCurrStatus = fValidator.validate(fViewer.getCheckedElements());
+                               updateStatus(fCurrStatus);
+                       } else if (!fCurrStatus.isOK()) {
+                               fCurrStatus = new StatusInfo();
+                       }
+               } else {
+                       fCurrStatus = new StatusInfo(IStatus.ERROR, fEmptyListMessage);
+               }
+               updateStatus(fCurrStatus);
+       }
+
+       /*
+        * @see Window#open()
+        */
+       public int open() {
+               fIsEmpty = evaluateIfTreeEmpty(fInput);
+               BusyIndicator.showWhile(null, new Runnable() {
+                       public void run() {
+                               access$superOpen();
+                       }
+               });
+
+               return getReturnCode();
+       }
+
+       private void access$superOpen() {
+               super.open();
+       }
+
+       /**
+        * Handles cancel button pressed event.
+        */
+       protected void cancelPressed() {
+               setResult(null);
+               super.cancelPressed();
+       }
+
+       /*
+        * @see SelectionStatusDialog#computeResult()
+        */
+       protected void computeResult() {
+               setResult(Arrays.asList(fViewer.getCheckedElements()));
+       }
+
+       /*
+        * @see Window#create()
+        */
+       public void create() {
+               super.create();
+
+               List initialSelections = getInitialSelections();
+               if (initialSelections != null) {
+                       fViewer.setCheckedElements(initialSelections.toArray());
+               }
+
+               if (fExpandedElements != null) {
+                       fViewer.setExpandedElements(fExpandedElements);
+               }
+
+               updateOKStatus();
+       }
+
+       /*
+        * @see Dialog#createDialogArea(Composite)
+        */
+       protected Control createDialogArea(Composite parent) {
+               Composite composite = (Composite) super.createDialogArea(parent);
+
+               Label messageLabel = createMessageArea(composite);
+               Control treeWidget = createTreeViewer(composite);
+               Control buttonComposite = createSelectionButtons(composite);
+
+               GridData data = new GridData(GridData.FILL_BOTH);
+               data.widthHint = convertWidthInCharsToPixels(fWidth);
+               data.heightHint = convertHeightInCharsToPixels(fHeight);
+               treeWidget.setLayoutData(data);
+
+               if (fIsEmpty) {
+                       messageLabel.setEnabled(false);
+                       treeWidget.setEnabled(false);
+                       buttonComposite.setEnabled(false);
+               }
+
+               return composite;
+       }
+
+       private Tree createTreeViewer(Composite parent) {
+               if (fContainerMode) {
+                       fViewer = new ContainerCheckedTreeViewer(parent, SWT.BORDER);
+               } else {
+                       fViewer = new CheckboxTreeViewer(parent, SWT.BORDER);
+               }
+
+               fViewer.setContentProvider(fContentProvider);
+               fViewer.setLabelProvider(fLabelProvider);
+               fViewer.addCheckStateListener(new ICheckStateListener() {
+                       public void checkStateChanged(CheckStateChangedEvent event) {
+                               updateOKStatus();
+                       }
+               });
+
+               fViewer.setSorter(fSorter);
+               if (fFilters != null) {
+                       for (int i = 0; i != fFilters.size(); i++)
+                               fViewer.addFilter((ViewerFilter) fFilters.get(i));
+               }
+
+               fViewer.setInput(fInput);
+
+               return fViewer.getTree();
+       }
+
+       /**
+        * Add the selection and deselection buttons to the dialog.
+        * @param composite org.eclipse.swt.widgets.Composite
+        */
+       private Composite createSelectionButtons(Composite composite) {
+
+               Composite buttonComposite = new Composite(composite, SWT.RIGHT);
+               GridLayout layout = new GridLayout();
+               layout.numColumns = 2;
+               buttonComposite.setLayout(layout);
+               GridData data = new GridData(GridData.HORIZONTAL_ALIGN_END | GridData.GRAB_HORIZONTAL);
+               data.grabExcessHorizontalSpace = true;
+               composite.setData(data);
+
+               Button selectButton = createButton(buttonComposite, IDialogConstants.SELECT_ALL_ID, "Select &All", false);
+
+               SelectionListener listener = new SelectionAdapter() {
+                       public void widgetSelected(SelectionEvent e) {
+                               fViewer.setCheckedElements(fContentProvider.getElements(fInput));
+                               updateOKStatus();
+                       }
+               };
+               selectButton.addSelectionListener(listener);
+
+               Button deselectButton = createButton(buttonComposite, IDialogConstants.DESELECT_ALL_ID, "&Deselect All", false);
+
+               listener = new SelectionAdapter() {
+                       public void widgetSelected(SelectionEvent e) {
+                               fViewer.setCheckedElements(new Object[0]);
+                               updateOKStatus();
+                       }
+               };
+               deselectButton.addSelectionListener(listener);
+               return buttonComposite;
+       }
+
+       private boolean evaluateIfTreeEmpty(Object input) {
+               Object[] elements = fContentProvider.getElements(input);
+               if (elements.length > 0) {
+                       if (fFilters != null) {
+                               for (int i = 0; i < fFilters.size(); i++) {
+                                       ViewerFilter curr = (ViewerFilter) fFilters.get(i);
+                                       elements = curr.filter(fViewer, input, elements);
+                               }
+                       }
+               }
+               return elements.length == 0;
+       }
+
+}
\ No newline at end of file
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/dialog/ElementListSelectionDialog.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/dialog/ElementListSelectionDialog.java
new file mode 100644 (file)
index 0000000..b6e9808
--- /dev/null
@@ -0,0 +1,61 @@
+package net.sourceforge.phpdt.internal.ui.dialog;
+
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+
+import java.util.List;
+import java.util.Arrays;
+import org.eclipse.jface.viewers.ILabelProvider;
+
+/**
+ * A class to select elements out of a list of elements.
+ */
+public class ElementListSelectionDialog extends AbstractElementListSelectionDialog {
+       
+       private Object[] fElements;
+       
+       /**
+        * Creates a list selection dialog.
+        * @param parent   the parent widget.
+        * @param renderer the label renderer.
+        */     
+       public ElementListSelectionDialog(Shell parent, ILabelProvider renderer) {
+               super(parent, renderer);
+       }
+
+       /**
+        * Sets the elements of the list.
+        * @param elements the elements of the list.
+        */
+       public void setElements(Object[] elements) {
+               fElements= elements;
+       }
+
+       /*
+        * @see SelectionStatusDialog#computeResult()
+        */
+       protected void computeResult() {
+               setResult(Arrays.asList(getSelectedElements()));
+       }
+       
+       /*
+        * @see Dialog#createDialogArea(Composite)
+        */
+       protected Control createDialogArea(Composite parent) {
+               Composite contents= (Composite) super.createDialogArea(parent);
+               
+               createMessageArea(contents);
+               createFilterText(contents);
+               createFilteredList(contents);
+
+               setListElements(fElements);
+
+               List initialSelections= getInitialSelections();
+               if (initialSelections != null)
+                       setSelection(initialSelections.toArray());
+                                       
+               return contents;
+       }
+
+}
\ No newline at end of file
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/dialog/ISelectionValidator.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/dialog/ISelectionValidator.java
new file mode 100644 (file)
index 0000000..d0ae472
--- /dev/null
@@ -0,0 +1,9 @@
+package net.sourceforge.phpdt.internal.ui.dialog;
+
+import org.eclipse.core.runtime.IStatus;
+
+public interface ISelectionValidator {
+
+       IStatus validate(Object[] selection);
+
+}
\ No newline at end of file
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/dialog/MessageLine.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/dialog/MessageLine.java
new file mode 100644 (file)
index 0000000..78a2907
--- /dev/null
@@ -0,0 +1,84 @@
+package net.sourceforge.phpdt.internal.ui.dialog;
+
+import net.sourceforge.phpdt.internal.ui.PHPUiImages;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CLabel;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * A message line displaying a status.
+ */
+public class MessageLine extends CLabel {
+       
+       private static final RGB ERROR_BACKGROUND_RGB = new RGB(230, 226, 221);
+       
+       private Color fNormalMsgAreaBackground;
+       private Color fErrorMsgAreaBackground;
+
+       /**
+        * Creates a new message line as a child of the given parent.
+        */
+       public MessageLine(Composite parent) {
+               this(parent, SWT.LEFT);
+       }
+
+       /**
+        * Creates a new message line as a child of the parent and with the given SWT stylebits.
+        */
+       public MessageLine(Composite parent, int style) {
+               super(parent, style);
+               fNormalMsgAreaBackground= getBackground();
+               fErrorMsgAreaBackground= null;
+       }
+
+       
+       private Image findImage(IStatus status) {
+               if (status.isOK()) {
+                       return null;
+               } else if (status.matches(IStatus.ERROR)) {
+                       return PHPUiImages.get(PHPUiImages.IMG_OBJS_ERROR);
+               } else if (status.matches(IStatus.WARNING)) {
+                       return PHPUiImages.get(PHPUiImages.IMG_OBJS_WARNING);
+               } else if (status.matches(IStatus.INFO)) {
+                       return PHPUiImages.get(PHPUiImages.IMG_OBJS_INFO);
+               }
+               return null;
+       }
+
+       /**
+        * Sets the message and image to the given status.
+        * <code>null</code> is a valid argument and will set the empty text and no image
+        */
+       public void setErrorStatus(IStatus status) {
+               if (status != null) {
+                       String message= status.getMessage();
+                       if (message != null && message.length() > 0) {
+                               setText(message);
+                               setImage(findImage(status));
+                               if (fErrorMsgAreaBackground == null) {
+                                       fErrorMsgAreaBackground= new Color(getDisplay(), ERROR_BACKGROUND_RGB);
+                               }
+                               setBackground(fErrorMsgAreaBackground);
+                               return;
+                       }
+               }               
+               setText("");
+               setImage(null);
+               setBackground(fNormalMsgAreaBackground);        
+       }
+       
+       /*
+        * @see Widget#dispose()
+        */
+       public void dispose() {
+               if (fErrorMsgAreaBackground != null) {
+                       fErrorMsgAreaBackground.dispose();
+                       fErrorMsgAreaBackground= null;
+               }
+               super.dispose();
+       }
+}
\ No newline at end of file
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/dialog/SelectionStatusDialog.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/dialog/SelectionStatusDialog.java
new file mode 100644 (file)
index 0000000..1f5e3ad
--- /dev/null
@@ -0,0 +1,148 @@
+package net.sourceforge.phpdt.internal.ui.dialog;
+
+import java.util.Arrays;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.dialogs.SelectionDialog;
+
+
+/**
+ * An abstract base class for dialogs with a status bar and ok/cancel buttons.
+ * The status message must be passed over as StatusInfo object and can be
+ * an error, warning or ok. The OK button is enabled or disabled depending
+ * on the status.
+ */ 
+public abstract class SelectionStatusDialog extends SelectionDialog  {
+       
+       private MessageLine fStatusLine;
+       private IStatus fLastStatus;
+       private Image fImage;
+       private boolean fStatusLineAboveButtons= false; 
+
+       /**
+        * Creates an instance of a <code>SelectionStatusDialog</code>.
+        */     
+       public SelectionStatusDialog(Shell parent) {
+               super(parent);
+       }
+       
+       /**
+        * Controls whether status line appears to the left of the buttons (default)
+        * or above them.
+        *
+        * @param aboveButtons if <code>true</code> status line is placed above buttons; if
+        *      <code>false</code> to the right
+        */
+       public void setStatusLineAboveButtons(boolean aboveButtons) {
+               fStatusLineAboveButtons= aboveButtons;
+       }
+       
+       /**
+        * Sets the image for this dialog.
+        * @param image the image.
+        */
+       public void setImage(Image image) {
+               fImage= image;
+       }
+       
+       /**
+        * Returns the first element from the list of results. Returns <code>null</code>
+        * if no element has been selected.
+        *
+        * @return the first result element if one exists. Otherwise <code>null</code> is
+        *  returned.
+        */     
+       public Object getFirstResult() {
+               Object[] result= getResult();
+               if (result == null || result.length == 0)
+                       return null;
+               return result[0];       
+       }
+       
+       /**
+        * Sets a result element at the given position.
+        */
+       protected void setResult(int position, Object element) {
+               Object[] result= getResult();
+               result[position]= element;
+               setResult(Arrays.asList(result));
+       }
+
+       /**
+        * Compute the result and return it.
+        */
+       protected abstract void computeResult();
+         
+       protected void configureShell(Shell shell) {
+               super.configureShell(shell);
+               if (fImage != null)
+                       shell.setImage(fImage);
+       }
+       
+       /**
+        * Update the dialog's status line to reflect the given status. It is safe to call
+        * this method before the dialog has been opened.
+        */
+       protected void updateStatus(IStatus status) {
+               fLastStatus= status;
+               if (fStatusLine != null && !fStatusLine.isDisposed()) {
+                   updateButtonsEnableState(status);
+                   fStatusLine.setErrorStatus(status);
+               }
+       }       
+
+       /**
+        * Update the status of the ok button to reflect the given status. Subclasses
+        * may override this method to update additional buttons.
+        */
+       protected void updateButtonsEnableState(IStatus status) {
+               Button okButton= getOkButton();
+               if (okButton != null && !okButton.isDisposed())
+                       okButton.setEnabled(!status.matches(IStatus.ERROR));
+       }
+       
+       protected void okPressed() {
+               computeResult();
+               super.okPressed();
+       }
+
+       public void create() {
+               super.create();
+               if (fLastStatus != null)
+                       updateStatus(fLastStatus);
+       }
+
+       protected Control createButtonBar(Composite parent) {
+               Composite composite= new Composite(parent, SWT.NULL);
+               GridLayout layout= new GridLayout();
+               if (fStatusLineAboveButtons) {
+                       layout.marginWidth= 5;
+               } else {
+                       layout.numColumns= 2;
+               }
+               layout.marginHeight= 0; layout.marginWidth= 0;
+               composite.setLayout(layout);
+               composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+               
+               fStatusLine= new MessageLine(composite);
+               fStatusLine.setAlignment(SWT.LEFT);
+               fStatusLine.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+               fStatusLine.setErrorStatus(null);
+               
+               GridData gd= new GridData(GridData.FILL_HORIZONTAL);
+               gd.horizontalIndent= convertWidthInCharsToPixels(1);
+               fStatusLine.setLayoutData(gd);
+               
+               super.createButtonBar(composite);
+               return composite;
+       }
+       
+}
\ No newline at end of file
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/dialog/StatusDialog.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/dialog/StatusDialog.java
new file mode 100644 (file)
index 0000000..f0ff756
--- /dev/null
@@ -0,0 +1,155 @@
+package net.sourceforge.phpdt.internal.ui.dialog;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * An abstract base class for dialogs with a status bar and ok/cancel buttons.
+ * The status message must be passed over as StatusInfo object and can be
+ * an error, warning or ok. The OK button is enabled or disabled depending
+ * on the status.
+ */ 
+public abstract class StatusDialog extends Dialog  {
+       
+       private Button fOkButton;
+       private MessageLine fStatusLine;
+       private IStatus fLastStatus;
+       private String fTitle;
+       private Image fImage;
+       
+       private boolean fStatusLineAboveButtons;
+       
+       /**
+        * Creates an instane of a status dialog.
+        */
+       public StatusDialog(Shell parent) {
+               super(parent);
+               fStatusLineAboveButtons= false;
+       }
+       
+       /**
+        * Specifies whether status line appears to the left of the buttons (default)
+        * or above them.
+        *
+        * @param aboveButtons if <code>true</code> status line is placed above buttons; if
+        *      <code>false</code> to the right
+        */
+       public void setStatusLineAboveButtons(boolean aboveButtons) {
+               fStatusLineAboveButtons= aboveButtons;
+       }       
+       
+       /**
+        * Update the dialog's status line to reflect the given status.
+        * It is save to call this method before the dialog has been opened.
+        */
+       protected void updateStatus(IStatus status) {
+               fLastStatus= status;
+               if (fStatusLine != null && !fStatusLine.isDisposed()) {
+                       updateButtonsEnableState(status);
+                       fStatusLine.setErrorStatus(status);
+               }
+       }
+       
+       /**
+        * Returns the last status.
+        */
+       public IStatus getStatus() {
+               return fLastStatus;
+       }
+
+       /**
+        * Updates the status of the ok button to reflect the given status.
+        * Subclasses may override this method to update additional buttons.
+        * @param status the status.
+        */
+       protected void updateButtonsEnableState(IStatus status) {
+               if (fOkButton != null && !fOkButton.isDisposed())
+                       fOkButton.setEnabled(!status.matches(IStatus.ERROR));
+       }
+       
+       /* 
+        * @see Window#create(Shell)
+        */
+       protected void configureShell(Shell shell) {
+               super.configureShell(shell);
+               if (fTitle != null)
+                       shell.setText(fTitle);
+       }
+
+       /*
+        * @see Window#create()
+        */     
+       public void create() {
+               super.create();
+               if (fLastStatus != null) {
+                       // policy: dialogs are not allowed to come up with an error message
+                       if (fLastStatus.matches(IStatus.ERROR)) {
+                               StatusInfo status= new StatusInfo();
+                               status.setError(""); //$NON-NLS-1$
+                               fLastStatus= status;
+                       }
+                       updateStatus(fLastStatus);
+               }
+       }
+
+       /*
+        * @see Dialog#createButtonsForButtonBar(Composite)
+        */
+       protected void createButtonsForButtonBar(Composite parent) {
+               fOkButton= createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
+               createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
+       }
+       
+       /*
+        * @see Dialog#createButtonBar(Composite)
+        */                             
+       protected Control createButtonBar(Composite parent) {
+               Composite composite= new Composite(parent, SWT.NULL);
+               GridLayout layout= new GridLayout();
+               layout.numColumns= 1;
+               layout.marginHeight= 0;
+               layout.marginWidth= convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
+               composite.setLayout(layout);
+               composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+               
+               fStatusLine= new MessageLine(composite);
+               fStatusLine.setAlignment(SWT.LEFT);
+               fStatusLine.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+               fStatusLine.setErrorStatus(null); //$NON-NLS-1$
+
+               super.createButtonBar(composite);
+               return composite;
+       }
+       
+       /**
+        * Sets the title for this dialog.
+        * @param title the title.
+        */
+       public void setTitle(String title) {
+               fTitle= title != null ? title : ""; //$NON-NLS-1$
+               Shell shell= getShell();
+               if ((shell != null) && !shell.isDisposed())
+                       shell.setText(fTitle);
+       }
+
+       /**
+        * Sets the image for this dialog.
+        * @param image the image.
+        */
+       public void setImage(Image image) {
+               fImage= image;
+               Shell shell= getShell();
+               if ((shell != null) && !shell.isDisposed())
+                       shell.setImage(fImage);
+       }       
+       
+}
\ No newline at end of file
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/dialog/StatusInfo.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/dialog/StatusInfo.java
new file mode 100644 (file)
index 0000000..5c668b8
--- /dev/null
@@ -0,0 +1,161 @@
+package net.sourceforge.phpdt.internal.ui.dialog;
+
+import net.sourceforge.phpeclipse.PHPeclipsePlugin;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.util.Assert;
+
+/**
+ * A settable IStatus. 
+ * Can be an error, warning, info or ok. For error, info and warning states,
+ * a message describes the problem.
+ */
+public class StatusInfo implements IStatus {
+
+       private String fStatusMessage;
+       private int fSeverity;
+
+       /**
+        * Creates a status set to OK (no message)
+        */
+       public StatusInfo() {
+               this(OK, null);
+       }
+
+       /**
+        * Creates a status .
+        * @param severity The status severity: ERROR, WARNING, INFO and OK.
+        * @param message The message of the status. Applies only for ERROR,
+        * WARNING and INFO.
+        */
+       public StatusInfo(int severity, String message) {
+               fStatusMessage = message;
+               fSeverity = severity;
+       }
+
+       /**
+        *  Returns if the status' severity is OK.
+        */
+       public boolean isOK() {
+               return fSeverity == IStatus.OK;
+       }
+
+       /**
+        *  Returns if the status' severity is WARNING.
+        */
+       public boolean isWarning() {
+               return fSeverity == IStatus.WARNING;
+       }
+
+       /**
+        *  Returns if the status' severity is INFO.
+        */
+       public boolean isInfo() {
+               return fSeverity == IStatus.INFO;
+       }
+
+       /**
+        *  Returns if the status' severity is ERROR.
+        */
+       public boolean isError() {
+               return fSeverity == IStatus.ERROR;
+       }
+
+       /**
+        * @see IStatus#getMessage
+        */
+       public String getMessage() {
+               return fStatusMessage;
+       }
+
+       /**
+        * Sets the status to ERROR.
+        * @param The error message (can be empty, but not null)
+        */
+       public void setError(String errorMessage) {
+               Assert.isNotNull(errorMessage);
+               fStatusMessage = errorMessage;
+               fSeverity = IStatus.ERROR;
+       }
+
+       /**
+        * Sets the status to WARNING.
+        * @param The warning message (can be empty, but not null)
+        */
+       public void setWarning(String warningMessage) {
+               Assert.isNotNull(warningMessage);
+               fStatusMessage = warningMessage;
+               fSeverity = IStatus.WARNING;
+       }
+
+       /**
+        * Sets the status to INFO.
+        * @param The info message (can be empty, but not null)
+        */
+       public void setInfo(String infoMessage) {
+               Assert.isNotNull(infoMessage);
+               fStatusMessage = infoMessage;
+               fSeverity = IStatus.INFO;
+       }
+
+       /**
+        * Sets the status to OK.
+        */
+       public void setOK() {
+               fStatusMessage = null;
+               fSeverity = IStatus.OK;
+       }
+
+       /*
+        * @see IStatus#matches(int)
+        */
+       public boolean matches(int severityMask) {
+               return (fSeverity & severityMask) != 0;
+       }
+
+       /**
+        * Returns always <code>false</code>.
+        * @see IStatus#isMultiStatus()
+        */
+       public boolean isMultiStatus() {
+               return false;
+       }
+
+       /*
+        * @see IStatus#getSeverity()
+        */
+       public int getSeverity() {
+               return fSeverity;
+       }
+
+       /*
+        * @see IStatus#getPlugin()
+        */
+       public String getPlugin() {
+               return PHPeclipsePlugin.PLUGIN_ID;
+       }
+
+       /**
+        * Returns always <code>null</code>.
+        * @see IStatus#getException()
+        */
+       public Throwable getException() {
+               return null;
+       }
+
+       /**
+        * Returns always the error severity.
+        * @see IStatus#getCode()
+        */
+       public int getCode() {
+               return fSeverity;
+       }
+
+       /**
+        * Returns always <code>null</code>.
+        * @see IStatus#getChildren()
+        */
+       public IStatus[] getChildren() {
+               return new IStatus[0];
+       }
+
+}
\ No newline at end of file
index 6d168b5..745bdee 100644 (file)
@@ -37,7 +37,7 @@ import org.eclipse.ui.IEditorPart;
 import net.sourceforge.phpdt.internal.corext.template.ContextType;
 import net.sourceforge.phpdt.internal.corext.template.ContextTypeRegistry;
 //import org.eclipse.jdt.internal.ui.JavaPlugin;
-import net.sourceforge.phpdt.internal.ui.JavaUIMessages;
+import net.sourceforge.phpdt.internal.ui.PHPUIMessages;
 //import org.eclipse.jdt.internal.ui.text.JavaCodeReader;
 import net.sourceforge.phpdt.internal.ui.text.template.TemplateEngine;
 
@@ -186,7 +186,7 @@ public class JavaCompletionProcessor_NotInUseVersion implements IContentAssistPr
         */  
        public String getErrorMessage() {
        //      if (fNumberOfComputedResults == 0)
-                       return JavaUIMessages.getString("JavaEditor.codeassist.noCompletions"); //$NON-NLS-1$
+                       return PHPUIMessages.getString("JavaEditor.codeassist.noCompletions"); //$NON-NLS-1$
 //             return fCollector.getErrorMessage();
        }
 
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/template/IdentifierEngine.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/template/IdentifierEngine.java
new file mode 100644 (file)
index 0000000..66a315c
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+package net.sourceforge.phpdt.internal.ui.text.template;
+
+import java.util.ArrayList;
+
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.Region;
+
+//import org.eclipse.jdt.core.ICompilationUnit;
+//import org.eclipse.jdt.core.JavaModelException;
+
+//import org.eclipse.jdt.internal.corext.Assert;
+import net.sourceforge.phpdt.internal.corext.template.ContextType;
+import net.sourceforge.phpdt.internal.corext.template.Template;
+import net.sourceforge.phpdt.internal.corext.template.Templates;
+import net.sourceforge.phpdt.internal.corext.template.java.CompilationUnitContext;
+import net.sourceforge.phpdt.internal.corext.template.java.CompilationUnitContextType;
+//import org.eclipse.jdt.internal.ui.JavaPluginImages;
+import net.sourceforge.phpdt.internal.ui.text.java.IJavaCompletionProposal;
+//import org.eclipse.jdt.internal.ui.text.link.LinkedPositionManager;
+
+public class IdentifierEngine {
+
+       /** The context type. */
+       private ContextType fContextType;
+       /** The result proposals. */
+       private ArrayList fProposals= new ArrayList();
+
+       /**
+        * Creates the template engine for a particular context type.
+        * See <code>TemplateContext</code> for supported context types.
+        */
+       public IdentifierEngine(ContextType contextType) {
+       //      Assert.isNotNull(contextType);
+               fContextType= contextType;
+       }
+
+       /**
+        * Empties the collector.
+        * 
+        * @param viewer the text viewer  
+        * @param unit   the compilation unit (may be <code>null</code>)
+        */
+       public void reset() {
+               fProposals.clear();
+       }
+
+       /**
+        * Returns the array of matching templates.
+        */
+       public IJavaCompletionProposal[] getResults() {
+               return (IJavaCompletionProposal[]) fProposals.toArray(new IJavaCompletionProposal[fProposals.size()]);
+       }
+
+       /**
+        * Inspects the context of the compilation unit around <code>completionPosition</code>
+        * and feeds the collector with proposals.
+        * @param viewer the text viewer
+        * @param completionPosition the context position in the document of the text viewer
+        * @param compilationUnit the compilation unit (may be <code>null</code>)
+        */
+       public void complete(ITextViewer viewer, int completionPosition, Object[] identifiers)
+  //,ICompilationUnit compilationUnit)
+       //hrows JavaModelException
+       {
+           IDocument document= viewer.getDocument();
+           
+               // prohibit recursion
+//             if (LinkedPositionManager.hasActiveManager(document))
+//                     return;
+
+               if (!(fContextType instanceof CompilationUnitContextType))
+                       return;
+               
+               ((CompilationUnitContextType) fContextType).setContextParameters(document, completionPosition);//mpilationUnit);
+               CompilationUnitContext context= (CompilationUnitContext) fContextType.createContext();
+               int start= context.getStart();
+               int end= context.getEnd();
+               IRegion region= new Region(start, end - start);
+
+//             Template[] templates= Templates.getInstance().getTemplates();
+    String identifier = null;
+               for (int i= 0; i != identifiers.length; i++) {
+      identifier = (String) identifiers[i];
+                       if (context.canEvaluate(identifier)) {
+                               fProposals.add(new IdentifierProposal(identifier, context, region, viewer)); //luginImages.get(JavaPluginImages.IMG_OBJS_TEMPLATE)));
+      }
+    }
+       }
+
+}
+
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/template/IdentifierProposal.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/template/IdentifierProposal.java
new file mode 100644 (file)
index 0000000..39b98e3
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+package net.sourceforge.phpdt.internal.ui.text.template;
+
+import net.sourceforge.phpdt.internal.corext.template.Template;
+import net.sourceforge.phpdt.internal.corext.template.TemplateBuffer;
+import net.sourceforge.phpdt.internal.corext.template.TemplateContext;
+import net.sourceforge.phpdt.internal.corext.template.TemplateMessages;
+import net.sourceforge.phpdt.internal.corext.template.TemplatePosition;
+import net.sourceforge.phpdt.internal.corext.template.java.CompilationUnitContext;
+import net.sourceforge.phpdt.internal.corext.template.java.JavaTemplateMessages;
+import net.sourceforge.phpdt.internal.ui.text.java.IJavaCompletionProposal;
+import net.sourceforge.phpeclipse.PHPeclipsePlugin;
+import org.eclipse.core.runtime.CoreException;
+import net.sourceforge.phpdt.internal.ui.text.link.LinkedPositionManager;
+import net.sourceforge.phpdt.internal.ui.text.link.LinkedPositionUI;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.contentassist.IContextInformation;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Shell;
+//import org.eclipse.jdt.internal.ui.text.link.LinkedPositionManager;
+//import org.eclipse.jdt.internal.ui.text.link.LinkedPositionUI;
+//import org.eclipse.jdt.internal.ui.util.ExceptionHandler;
+
+/**
+ * A PHP identifier proposal.
+ */
+public class IdentifierProposal implements IJavaCompletionProposal {
+
+  private final String fTemplate;
+  private final TemplateContext fContext;
+  private final ITextViewer fViewer;
+  //   private final Image fImage;
+  private final IRegion fRegion;
+
+  //private TemplateBuffer fTemplateBuffer;
+  private String fOldText;
+  private IRegion fSelectedRegion; // initialized by apply()
+
+  /**
+   * Creates a template proposal with a template and its context.
+   * @param template  the template
+   * @param context   the context in which the template was requested.
+   * @param image     the icon of the proposal.
+   */
+  public IdentifierProposal(String template, TemplateContext context, IRegion region, ITextViewer viewer) { //, Image image) {
+    //         Assert.isNotNull(template);
+    //         Assert.isNotNull(context);
+    //         Assert.isNotNull(region);
+    //         Assert.isNotNull(viewer);
+
+    fTemplate = template;
+    fContext = context;
+    fViewer = viewer;
+    //         fImage= image;
+    fRegion = region;
+  }
+
+  /*
+   * @see ICompletionProposal#apply(IDocument)
+   */
+  public void apply(IDocument document) {
+    try {
+      //                   if (fTemplateBuffer == null)
+      //                               fTemplateBuffer= fContext.evaluate(fTemplate);
+
+      int start = fRegion.getOffset();
+      int end = fRegion.getOffset() + fRegion.getLength();
+
+      // insert template string
+    //  String templateString = fTemplate; // fTemplateBuffer.getString();     
+      document.replace(start, end - start, fTemplate);
+
+      // translate positions
+      LinkedPositionManager manager = new LinkedPositionManager(document);
+      //                       TemplatePosition[] variables= fTemplateBuffer.getVariables();
+      //                       for (int i= 0; i != variables.length; i++) {
+      //                               TemplatePosition variable= variables[i];
+      //
+      //                               if (variable.isResolved())
+      //                                       continue;
+      //                               
+      //                               int[] offsets= variable.getOffsets();
+      //                               int length= variable.getLength();
+      //                               
+      //                               for (int j= 0; j != offsets.length; j++)
+      //                                       manager.addPosition(offsets[j] + start, length);
+      //                       }
+
+      LinkedPositionUI editor = new LinkedPositionUI(fViewer, manager);
+      editor.setFinalCaretOffset(fTemplate.length()+start);
+   //   editor.setFinalCaretOffset(getCaretOffset(fTemplateBuffer) + start);
+      editor.enter();
+
+      fSelectedRegion = editor.getSelectedRegion();
+
+    } catch (BadLocationException e) {
+      PHPeclipsePlugin.log(e);
+      openErrorDialog(e);
+
+    }
+    //      catch (CoreException e) {
+    //                 handleException(e);
+    //     }       
+  }
+
+//  private static int getCaretOffset(TemplateBuffer buffer) {
+//    TemplatePosition[] variables = buffer.getVariables();
+//    for (int i = 0; i != variables.length; i++) {
+//      TemplatePosition variable = variables[i];
+//
+//      if (variable.getName().equals(JavaTemplateMessages.getString("GlobalVariables.variable.name.cursor"))) //$NON-NLS-1$
+//        return variable.getOffsets()[0];
+//    }
+//
+//    return buffer.getString().length();
+//  }
+
+  /*
+   * @see ICompletionProposal#getSelection(IDocument)
+   */
+  public Point getSelection(IDocument document) {
+    return new Point(fSelectedRegion.getOffset(), fSelectedRegion.getLength());
+    //   return null;
+  }
+
+  /*
+   * @see ICompletionProposal#getAdditionalProposalInfo()
+   */
+  public String getAdditionalProposalInfo() {
+    //     try {
+    //                 if (fTemplateBuffer == null)
+    //                         fTemplateBuffer= fContext.evaluate(fTemplate);
+
+    return textToHTML(fTemplate); // fTemplateBuffer.getString());
+
+    //     } catch (CoreException e) {
+    //                 handleException(e);                 
+    //                 return null;
+    //     }
+  }
+
+  /*
+   * @see ICompletionProposal#getDisplayString()
+   */
+  public String getDisplayString() {
+    return fTemplate + TemplateMessages.getString("TemplateProposal.delimiter") + fTemplate; // $NON-NLS-1$ //$NON-NLS-1$
+    //         return fTemplate.getName() + TemplateMessages.getString("TemplateProposal.delimiter") + fTemplate.getDescription(); // $NON-NLS-1$ //$NON-NLS-1$
+  }
+
+  /*
+   * @see ICompletionProposal#getImage()
+   */
+  public Image getImage() {
+    //         return fImage;
+    return null;
+  }
+
+  /*
+   * @see ICompletionProposal#getContextInformation()
+   */
+  public IContextInformation getContextInformation() {
+    return null;
+  }
+
+  private static String textToHTML(String string) {
+    StringBuffer buffer = new StringBuffer(string.length());
+    buffer.append("<pre>"); //$NON-NLS-1$
+
+    for (int i = 0; i != string.length(); i++) {
+      char ch = string.charAt(i);
+
+      switch (ch) {
+        case '&' :
+          buffer.append("&amp;"); //$NON-NLS-1$
+          break;
+
+        case '<' :
+          buffer.append("&lt;"); //$NON-NLS-1$
+          break;
+
+        case '>' :
+          buffer.append("&gt;"); //$NON-NLS-1$
+          break;
+
+        case '\t' :
+          buffer.append("    "); //$NON-NLS-1$
+          break;
+
+        case '\n' :
+          buffer.append("<br>"); //$NON-NLS-1$
+          break;
+
+        default :
+          buffer.append(ch);
+          break;
+      }
+    }
+
+    buffer.append("</pre>"); //$NON-NLS-1$
+    return buffer.toString();
+  }
+
+  private void openErrorDialog(BadLocationException e) {
+    Shell shell = fViewer.getTextWidget().getShell();
+    MessageDialog.openError(shell, TemplateMessages.getString("TemplateEvaluator.error.title"), e.getMessage()); //$NON-NLS-1$
+  }
+
+  private void handleException(CoreException e) {
+    Shell shell = fViewer.getTextWidget().getShell();
+    PHPeclipsePlugin.log(e);
+    //         ExceptionHandler.handle(e, shell, TemplateMessages.getString("TemplateEvaluator.error.title"), null); //$NON-NLS-1$
+  }
+
+  /*
+   * @see IJavaCompletionProposal#getRelevance()
+   */
+  public int getRelevance() {
+
+    if (fContext instanceof CompilationUnitContext) {
+      CompilationUnitContext context = (CompilationUnitContext) fContext;
+      switch (context.getCharacterBeforeStart()) {
+        // high relevance after whitespace
+        case ' ' :
+        case '\r' :
+        case '\n' :
+        case '\t' :
+          return 90;
+
+        default :
+          return 0;
+      }
+    } else {
+      return 90;
+    }
+  }
+
+}
\ No newline at end of file
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/DirectorySelector.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/DirectorySelector.java
new file mode 100644 (file)
index 0000000..91c24a3
--- /dev/null
@@ -0,0 +1,38 @@
+package net.sourceforge.phpdt.internal.ui.util;
+
+import java.io.File;
+
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.DirectoryDialog;
+
+public class DirectorySelector extends ResourceSelector {
+
+       public DirectorySelector(Composite parent) {
+               super(parent);
+       }
+
+       protected void handleBrowseSelected() {
+               DirectoryDialog dialog = new DirectoryDialog(getShell());
+               dialog.setMessage(browseDialogMessage);
+               String currentWorkingDir = textField.getText();
+               if (!currentWorkingDir.trim().equals("")) {
+                       File path = new File(currentWorkingDir);
+                       if (path.exists()) {
+                               dialog.setFilterPath(currentWorkingDir);
+                       }                       
+               }
+               
+               String selectedDirectory = dialog.open();
+               if (selectedDirectory != null) {
+                       textField.setText(selectedDirectory);
+               }               
+       }
+
+       protected String validateResourceSelection() {
+               String directory = textField.getText();
+               File directoryFile = new File(directory);
+               if (directoryFile.exists() && directoryFile.isDirectory())
+                       return directory;
+               return EMPTY_STRING;
+       }
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/ExceptionHandler.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/ExceptionHandler.java
new file mode 100644 (file)
index 0000000..2adc896
--- /dev/null
@@ -0,0 +1,76 @@
+package net.sourceforge.phpdt.internal.ui.util;
+
+import java.io.StringWriter;
+import java.lang.reflect.InvocationTargetException;
+
+import net.sourceforge.phpdt.internal.ui.PHPUIMessages;
+import net.sourceforge.phpeclipse.PHPeclipsePlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.swt.widgets.Shell;
+
+public class ExceptionHandler {
+       private static ExceptionHandler fgInstance= new ExceptionHandler();
+       
+       public static void log(Throwable t, String message) {
+               PHPeclipsePlugin.getDefault().getLog().log(new Status(IStatus.ERROR, PHPeclipsePlugin.PLUGIN_ID, 
+                       IStatus.ERROR, message, t));
+       }
+       
+       public static void handle(CoreException e, String title, String message) {
+               handle(e, PHPeclipsePlugin.getActiveWorkbenchShell(), title, message);
+       }
+       
+       public static void handle(CoreException e, Shell parent, String title, String message) {
+               fgInstance.perform(e, parent, title, message);
+       }
+       
+       public static void handle(InvocationTargetException e, String title, String message) {
+               handle(e, PHPeclipsePlugin.getActiveWorkbenchShell(), title, message);
+       }
+       
+       public static void handle(InvocationTargetException e, Shell parent, String title, String message) {
+               fgInstance.perform(e, parent, title, message);
+       }
+
+       protected void perform(CoreException e, Shell shell, String title, String message) {
+               PHPeclipsePlugin.log(e);
+               IStatus status= e.getStatus();
+               if (status != null) {
+                       ErrorDialog.openError(shell, title, message, status);
+               } else {
+                       displayMessageDialog(e, e.getMessage(), shell, title, message);
+               }
+       }
+
+       protected void perform(InvocationTargetException e, Shell shell, String title, String message) {
+               Throwable target= e.getTargetException();
+               if (target instanceof CoreException) {
+                       perform((CoreException)target, shell, title, message);
+               } else {
+                       PHPeclipsePlugin.log(e);
+                       if (e.getMessage() != null && e.getMessage().length() > 0) {
+                               displayMessageDialog(e, e.getMessage(), shell, title, message);
+                       } else {
+                               displayMessageDialog(e, target.getMessage(), shell, title, message);
+                       }
+               }
+       }
+
+       private void displayMessageDialog(Throwable t, String exceptionMessage, Shell shell, String title, String message) {
+               StringWriter msg= new StringWriter();
+               if (message != null) {
+                       msg.write(message);
+                       msg.write("\n\n");
+               }
+               if (exceptionMessage == null || exceptionMessage.length() == 0)
+                       msg.write(PHPUIMessages.getString("ExceptionDialog.seeErrorLogMessage"));
+               else
+                       msg.write(exceptionMessage);
+               MessageDialog.openError(shell, title, msg.toString());                  
+       }       
+}
\ No newline at end of file
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/FilteredList.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/FilteredList.java
new file mode 100644 (file)
index 0000000..892c2df
--- /dev/null
@@ -0,0 +1,456 @@
+package net.sourceforge.phpdt.internal.ui.util;
+
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Vector;
+
+import org.eclipse.jface.util.Assert;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
+
+/**
+ * A composite widget which holds a list of elements for user selection.
+ * The elements are sorted alphabetically.
+ * Optionally, the elements can be filtered and duplicate entries can
+ * be hidden (folding).
+ */
+public class FilteredList extends Composite {
+
+       public interface FilterMatcher {
+               /**
+                * Sets the filter.
+                * 
+                * @param pattern         the filter pattern.
+                * @param ignoreCase      a flag indicating whether pattern matching is case insensitive or not.
+                * @param ignoreWildCards a flag indicating whether wildcard characters are interpreted or not.
+                */
+               void setFilter(String pattern, boolean ignoreCase, boolean ignoreWildCards);
+
+               /**
+                * Returns <code>true</code> if the object matches the pattern, <code>false</code> otherwise.
+                * <code>setFilter()</code> must have been called at least once prior to a call to this method.
+                */
+               boolean match(Object element);  
+       }
+       
+       private class DefaultFilterMatcher implements FilterMatcher {
+               private StringMatcher fMatcher;
+               
+               public void setFilter(String pattern, boolean ignoreCase, boolean ignoreWildCards) {
+                       fMatcher= new StringMatcher(pattern + '*', ignoreCase, ignoreWildCards);
+               }
+               
+               public boolean match(Object element) {
+                       return fMatcher.match(fRenderer.getText(element));
+               }       
+       }
+
+       private Table fList;
+       private ILabelProvider fRenderer;
+       private boolean fMatchEmtpyString= true;
+       private boolean fIgnoreCase;
+       private boolean fAllowDuplicates;
+       private String fFilter= ""; //$NON-NLS-1$
+       private TwoArrayQuickSorter fSorter;
+       
+       private Object[] fElements= new Object[0];
+       private Label[] fLabels;
+       private Vector fImages= new Vector();
+
+       private int[] fFoldedIndices;
+       private int fFoldedCount;
+       
+       private int[] fFilteredIndices;
+       private int fFilteredCount;
+       
+       private FilterMatcher fFilterMatcher= new DefaultFilterMatcher();
+       private Comparator fComparator;
+
+       private static class Label {
+               public final String string;
+               public final Image image;
+
+               public Label(String string, Image image) {
+                       this.string= string;
+                       this.image= image;
+               }
+               
+               public boolean equals(Label label) {
+                       if (label == null)
+                               return false;
+                               
+                       return                  
+                               string.equals(label.string) &&
+                               image.equals(label.image);
+               }
+       }
+
+       private final class LabelComparator implements Comparator {
+               private boolean fIgnoreCase;
+       
+               LabelComparator(boolean ignoreCase) {
+                       fIgnoreCase= ignoreCase;
+               }
+       
+               public int compare(Object left, Object right) {
+                       Label leftLabel= (Label) left;
+                       Label rightLabel= (Label) right;                        
+
+                       int value;
+                       
+                       if (fComparator == null) {
+                               value= fIgnoreCase
+                                       ? leftLabel.string.compareToIgnoreCase(rightLabel.string)
+                                       : leftLabel.string.compareTo(rightLabel.string);
+                       } else {
+                           value= fComparator.compare(leftLabel.string, rightLabel.string);
+                       }
+
+                       if (value != 0)
+                               return value;
+
+                       // images are allowed to be null
+                       if (leftLabel.image == null) {
+                               return (rightLabel.image == null) ? 0 : -1;
+                       } else if (rightLabel.image == null) {
+                               return +1;                              
+                       } else {
+                               return
+                                       fImages.indexOf(leftLabel.image) -
+                                       fImages.indexOf(rightLabel.image);
+                       }
+               }
+               
+       }       
+       
+       /**
+        * Constructs a new instance of a filtered list.
+        * @param parent           the parent composite.
+        * @param style            the widget style.
+        * @param renderer         the label renderer.
+        * @param ignoreCase       specifies whether sorting and folding is case sensitive.
+        * @param allowDuplicates  specifies whether folding of duplicates is desired.
+        * @param matchEmptyString specifies whether empty filter strings should filter everything or nothing.
+        */
+       public FilteredList(Composite parent, int style, ILabelProvider renderer,
+               boolean ignoreCase, boolean allowDuplicates, boolean matchEmptyString)
+       {
+               super(parent, SWT.NONE);
+
+               GridLayout layout= new GridLayout();
+               layout.marginHeight= 0;
+               layout.marginWidth= 0;
+               setLayout(layout);
+               
+               fList= new Table(this, style);
+               fList.setLayoutData(new GridData(GridData.FILL_BOTH));
+               fList.addDisposeListener(new DisposeListener() {
+                       public void widgetDisposed(DisposeEvent e) {
+                               fRenderer.dispose();
+                       }
+               });
+               
+               fRenderer= renderer;
+               fIgnoreCase= ignoreCase;                
+               fSorter= new TwoArrayQuickSorter(new LabelComparator(ignoreCase));
+               fAllowDuplicates= allowDuplicates;
+               fMatchEmtpyString= matchEmptyString;
+       }
+
+       /**
+        * Sets the list of elements.
+        * @param elements the elements to be shown in the list.
+        */
+       public void setElements(Object[] elements) {
+               if (elements == null) {
+                       fElements= new Object[0];
+               } else {
+                       // copy list for sorting
+                       fElements= new Object[elements.length];
+                       System.arraycopy(elements, 0, fElements, 0, elements.length);
+               }
+                       
+               int length= fElements.length;
+
+               // fill labels                  
+               fLabels= new Label[length];
+               Set imageSet= new HashSet();
+               for (int i= 0; i != length; i++) {
+                       String text= fRenderer.getText(fElements[i]);
+                       Image image= fRenderer.getImage(fElements[i]);
+                       
+                       fLabels[i]= new Label(text, image);                             
+                       imageSet.add(image);
+               }
+               fImages.clear();
+               fImages.addAll(imageSet);
+
+               fSorter.sort(fLabels, fElements);
+
+               fFilteredIndices= new int[length];
+               fFilteredCount= filter();
+               
+               fFoldedIndices= new int[length];
+               fFoldedCount= fold();
+
+               updateList();
+       }
+
+       /**
+        * Tests if the list (before folding and filtering) is empty.
+        * @return returns <code>true</code> if the list is empty, <code>false</code> otherwise.
+        */
+       public boolean isEmpty() {
+               return (fElements == null) || (fElements.length == 0);
+       }
+
+       /**
+        * Sets the filter matcher.
+        */
+       public void setFilterMatcher(FilterMatcher filterMatcher) {
+               Assert.isNotNull(filterMatcher);
+               fFilterMatcher= filterMatcher;
+       }
+       
+       /**
+        * Sets a custom comparator for sorting the list.
+        */
+       public void setComparator(Comparator comparator) {
+           Assert.isNotNull(comparator);
+           fComparator= comparator;
+       }
+
+    /**
+     * Adds a selection listener to the list.
+     * @param listener the selection listener to be added.
+     */
+       public void addSelectionListener(SelectionListener listener) {
+               fList.addSelectionListener(listener);
+       }
+
+    /**
+     * Removes a selection listener from the list.
+     * @param listener the selection listener to be removed.
+     */
+       public void removeSelectionListener(SelectionListener listener) {
+               fList.removeSelectionListener(listener);
+       }       
+
+    /**
+     * Sets the selection of the list.
+     * @param selection an array of indices specifying the selection.
+     */
+       public void setSelection(int[] selection) {
+               fList.setSelection(selection);
+       }
+       
+       /**
+        * Returns the selection of the list.
+        * @return returns an array of indices specifying the current selection.
+        */
+       public int[] getSelectionIndices() {
+               return fList.getSelectionIndices();
+       }
+       
+       /**
+        * Returns the selection of the list.
+        * This is a convenience function for <code>getSelectionIndices()</code>.
+        * @return returns the index of the selection, -1 for no selection.
+        */
+       public int getSelectionIndex() {
+               return fList.getSelectionIndex();               
+       }
+       
+       /**
+        * Sets the selection of the list.
+        * @param elements the array of elements to be selected.
+        */
+       public void setSelection(Object[] elements) {
+               if ((elements == null) || (fElements == null))
+                       return;                 
+               
+               // fill indices
+               int[] indices= new int[elements.length];
+               for (int i= 0; i != elements.length; i++) {
+                       int j;                  
+                       for (j= 0; j != fFoldedCount; j++) {
+                               int max= (j == fFoldedCount - 1)
+                                       ? fFilteredCount
+                                       : fFoldedIndices[j + 1];
+
+                               int l;                                  
+                               for (l= fFoldedIndices[j]; l != max; l++) {
+                                       // found matching element?
+                                       if (fElements[fFilteredIndices[l]].equals(elements[i])) {
+                                               indices[i]= j;
+                                               break;  
+                                       }
+                               }
+                               
+                               if (l != max)
+                                       break;
+                       }
+                       
+                       // not found
+                       if (j == fFoldedCount)
+                               indices[i] = 0;
+               }
+               
+               fList.setSelection(indices);
+       }
+       
+       /**
+        * Returns an array of the selected elements. The type of the elements
+        * returned in the list are the same as the ones passed with
+        * <code>setElements</code>. The array does not contain the rendered strings.
+        * @return returns the array of selected elements.
+        */
+       public Object[] getSelection() {
+               if (fList.isDisposed() || (fList.getSelectionCount() == 0))
+                       return new Object[0];
+
+               int[] indices= fList.getSelectionIndices();
+               Object[] elements= new Object[indices.length];
+               
+               for (int i= 0; i != indices.length; i++)
+                       elements[i]= fElements[fFilteredIndices[fFoldedIndices[indices[i]]]];
+               
+               return elements;                
+       }
+
+       /**
+        * Sets the filter pattern. Current only prefix filter patterns are supported.
+        * @param filter the filter pattern.
+        */
+       public void setFilter(String filter) {
+               fFilter= (filter == null) ? "" : filter; //$NON-NLS-1$
+
+               fFilteredCount= filter();
+               fFoldedCount= fold();
+               updateList();
+       }
+       
+       /**
+        * Returns the filter pattern.
+        * @return returns the filter pattern.
+        */
+       public String getFilter() {
+               return fFilter;
+       }
+
+       /**
+        * Returns all elements which are folded together to one entry in the list.
+        * @param  index the index selecting the entry in the list.
+        * @return returns an array of elements folded together, <code>null</code> if index is out of range.
+        */
+       public Object[] getFoldedElements(int index) {
+               if ((index < 0) || (index >= fFoldedCount))
+                       return null;
+               
+               int start= fFoldedIndices[index];                       
+               int count= (index == fFoldedCount - 1)
+                       ? fFilteredCount - start
+                       : fFoldedIndices[index + 1] - start;
+                       
+               Object[] elements= new Object[count];
+               for (int i= 0; i != count; i++)
+                       elements[i]= fElements[fFilteredIndices[start + i]];
+                               
+               return elements;
+       }
+
+    /*
+     * Folds duplicate entries. Two elements are considered as a pair of
+     * duplicates if they coiincide in the rendered string and image.
+     * @return returns the number of elements after folding.
+     */
+       private int fold() {
+               if (fAllowDuplicates) {
+                       for (int i= 0; i != fFilteredCount; i++)                
+                               fFoldedIndices[i]= i; // identity mapping
+
+                       return fFilteredCount;                  
+               
+               } else {
+                       int k= 0;
+                       Label last= null;
+                       for (int i= 0; i != fFilteredCount; i++) {
+                               int j= fFilteredIndices[i];
+                               
+                               Label current= fLabels[j];
+                               if (! current.equals(last)) {
+                                       fFoldedIndices[k]= i;
+                                       k++;
+                                       last= current;
+                               }
+                       }
+                       return k;
+               }
+       }
+
+       /*
+        * Filters the list with the filter pattern.
+     * @return returns the number of elements after filtering.
+        */
+       private int filter() {
+               if (((fFilter == null) || (fFilter.length() == 0)) && !fMatchEmtpyString)
+                       return 0;
+               
+               fFilterMatcher.setFilter(fFilter.trim(), fIgnoreCase, false);
+
+               int k= 0;
+               for (int i= 0; i != fElements.length; i++) {
+                       if (fFilterMatcher.match(fElements[i]))
+                               fFilteredIndices[k++]= i;
+               }                       
+                                               
+               return k;
+       }       
+
+       /*
+        * Updates the list widget.
+        */      
+       private void updateList() {
+               if (fList.isDisposed())
+                       return;
+                       
+               fList.setRedraw(false);
+               
+               // resize table
+               int itemCount= fList.getItemCount();
+               if (fFoldedCount < itemCount)
+                       fList.remove(0, itemCount - fFoldedCount - 1);
+               else if (fFoldedCount > itemCount)
+                       for (int i= 0; i != fFoldedCount - itemCount; i++)
+                               new TableItem(fList, SWT.NONE);
+
+               // fill table
+               TableItem[] items= fList.getItems();
+               for (int i= 0; i != fFoldedCount; i++) {
+                       TableItem item= items[i];
+                       Label label= fLabels[fFilteredIndices[fFoldedIndices[i]]];
+                       
+                       item.setText(label.string);
+                       item.setImage(label.image);
+               }
+
+               // select first item if any
+               if (fList.getItemCount() > 0)
+                       fList.setSelection(0);
+                       
+               fList.setRedraw(true);          
+               fList.notifyListeners(SWT.Selection, new Event());
+       }
+       
+}
\ No newline at end of file
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/PHPElementVisitor.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/PHPElementVisitor.java
new file mode 100644 (file)
index 0000000..54db23d
--- /dev/null
@@ -0,0 +1,44 @@
+package net.sourceforge.phpdt.internal.ui.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceVisitor;
+import org.eclipse.core.runtime.CoreException;
+
+public class PHPElementVisitor implements IResourceVisitor {
+       protected List phpFiles = new ArrayList();
+
+       public PHPElementVisitor() {
+               super();
+       }
+
+       public boolean visit(IResource resource) throws CoreException {
+               switch (resource.getType()) {
+                       case IResource.PROJECT :
+                               return true;
+
+                       case IResource.FOLDER :
+                               return true;
+
+                       case IResource.FILE :
+                               IFile fileResource = (IFile) resource;
+                               if ( "php".equals(fileResource.getFileExtension()) ||
+             "php3".equals(fileResource.getFileExtension()) ||
+             "php4".equals(fileResource.getFileExtension()) ) {
+                                       phpFiles.add(fileResource);
+                                       return true;
+                               }
+
+                       default :
+                               return false;
+               }
+       }
+       
+       public Object[] getCollectedPHPFiles() {
+               return phpFiles.toArray();
+       }
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/PHPFileSelector.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/PHPFileSelector.java
new file mode 100644 (file)
index 0000000..f83ffd3
--- /dev/null
@@ -0,0 +1,67 @@
+package net.sourceforge.phpdt.internal.ui.util;
+
+import net.sourceforge.phpeclipse.PHPeclipsePlugin;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jface.util.Assert;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.model.WorkbenchLabelProvider;
+import net.sourceforge.phpdt.internal.ui.dialog.ElementListSelectionDialog;
+
+public class PHPFileSelector extends ResourceSelector {
+       protected PHPProjectSelector phpProjectSelector;
+
+       public PHPFileSelector(Composite parent, PHPProjectSelector aProjectSelector) {
+               super(parent);
+               Assert.isNotNull(aProjectSelector);
+               phpProjectSelector = aProjectSelector;
+               
+               browseDialogTitle = "File Selection";
+       }
+
+       protected Object[] getPHPFiles() {
+               IProject phpProject = phpProjectSelector.getSelection();
+               if (phpProject == null)
+                       return new Object[0];
+
+               PHPElementVisitor visitor = new PHPElementVisitor();
+               try {
+                       phpProject.accept(visitor);
+               } catch(CoreException e) {
+                       PHPeclipsePlugin.log(e);
+               }
+               return visitor.getCollectedPHPFiles();
+       }
+
+       public IFile getSelection() {
+               String fileName = getSelectionText();
+               if (fileName != null && !fileName.equals("")) {
+                       IPath filePath = new Path(fileName);
+                       IProject project = phpProjectSelector.getSelection();
+                       if (project != null && project.exists(filePath))
+                               return project.getFile(filePath);
+               }
+                       
+               return null;
+       }
+
+       protected void handleBrowseSelected() {
+               ElementListSelectionDialog dialog = new ElementListSelectionDialog(getShell(), new WorkbenchLabelProvider());
+               dialog.setTitle(browseDialogTitle);
+               dialog.setMessage(browseDialogMessage);
+               dialog.setElements(getPHPFiles());
+
+               if (dialog.open() == dialog.OK) {
+                       textField.setText(((IResource) dialog.getFirstResult()).getProjectRelativePath().toString());
+               }
+       }
+
+       protected String validateResourceSelection() {
+               IFile selection = getSelection();
+               return selection == null ? EMPTY_STRING : selection.getProjectRelativePath().toString();
+       }
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/PHPProjectSelector.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/PHPProjectSelector.java
new file mode 100644 (file)
index 0000000..e7c21b2
--- /dev/null
@@ -0,0 +1,41 @@
+package net.sourceforge.phpdt.internal.ui.util;
+
+import net.sourceforge.phpeclipse.PHPCore;
+import net.sourceforge.phpeclipse.PHPeclipsePlugin;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.model.WorkbenchLabelProvider;
+import net.sourceforge.phpdt.internal.ui.dialog.ElementListSelectionDialog;
+
+public class PHPProjectSelector extends ResourceSelector {
+
+       public PHPProjectSelector(Composite parent) {
+               super(parent);
+               
+               browseDialogTitle = "Project Selection";
+       } 
+
+       public IProject getSelection() {
+               String projectName = getSelectionText();
+               if (projectName != null && !projectName.equals(""))
+                       return PHPeclipsePlugin.getWorkspace().getRoot().getProject(projectName);
+                       
+               return null;
+       }
+
+       protected void handleBrowseSelected() {
+               ElementListSelectionDialog dialog = new ElementListSelectionDialog(getShell(), new WorkbenchLabelProvider());
+               dialog.setTitle(browseDialogTitle);
+               dialog.setMessage(browseDialogMessage);
+               dialog.setElements(PHPCore.getPHPProjects());
+
+               if (dialog.open() == dialog.OK) {
+                       textField.setText(((IProject) dialog.getFirstResult()).getName());
+               }
+       }
+
+       protected String validateResourceSelection() {
+               IProject project = getSelection();
+               return project == null ? EMPTY_STRING : project.getName();
+       }
+}
\ No newline at end of file
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/PixelConverter.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/PixelConverter.java
new file mode 100644 (file)
index 0000000..04deaba
--- /dev/null
@@ -0,0 +1,50 @@
+package net.sourceforge.phpdt.internal.ui.util;
+
+import org.eclipse.swt.graphics.FontMetrics;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.widgets.Control;
+
+import org.eclipse.jface.dialogs.Dialog;
+
+public class PixelConverter {
+       
+       private FontMetrics fFontMetrics;
+       
+       public PixelConverter(Control control) {
+               GC gc = new GC(control);
+               gc.setFont(control.getFont());
+               fFontMetrics= gc.getFontMetrics();
+               gc.dispose();
+       }
+       
+       private FontMetrics fgFontMetrics;
+               
+       /**
+        * @see org.eclipse.jface.dialogs.DialogPage#convertHeightInCharsToPixels(int)
+        */
+       public int convertHeightInCharsToPixels(int chars) {
+               return Dialog.convertHeightInCharsToPixels(fFontMetrics, chars);
+       }
+
+       /**
+        * @see org.eclipse.jface.dialogs.DialogPage#convertHorizontalDLUsToPixels(int)
+        */
+       public int convertHorizontalDLUsToPixels(int dlus) {
+               return Dialog.convertHorizontalDLUsToPixels(fFontMetrics, dlus);
+       }
+
+       /**
+        * @see org.eclipse.jface.dialogs.DialogPage#convertVerticalDLUsToPixels(int)
+        */
+       public int convertVerticalDLUsToPixels(int dlus) {
+               return Dialog.convertVerticalDLUsToPixels(fFontMetrics, dlus);
+       }
+       
+       /**
+        * @see org.eclipse.jface.dialogs.DialogPage#convertWidthInCharsToPixels(int)
+        */
+       public int convertWidthInCharsToPixels(int chars) {
+               return Dialog.convertWidthInCharsToPixels(fFontMetrics, chars);
+       }       
+
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/ResourceSelector.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/ResourceSelector.java
new file mode 100644 (file)
index 0000000..cb28566
--- /dev/null
@@ -0,0 +1,89 @@
+package net.sourceforge.phpdt.internal.ui.util;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+public abstract class ResourceSelector {
+       protected final static String EMPTY_STRING = "";
+       protected Composite composite;
+       protected Button browseButton;
+       protected Text textField;
+       protected String browseDialogMessage = EMPTY_STRING;
+       protected String browseDialogTitle = EMPTY_STRING;
+       protected String validatedSelectionText = EMPTY_STRING;
+
+       public ResourceSelector(Composite parent) {
+               composite = new Composite(parent, SWT.NONE);
+               GridLayout compositeLayout = new GridLayout();
+               compositeLayout.marginWidth = 0;
+               compositeLayout.marginHeight = 0;
+               compositeLayout.numColumns = 2;
+               composite.setLayout(compositeLayout);
+
+               textField = new Text(composite, SWT.SINGLE | SWT.BORDER);
+               textField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+               textField.addModifyListener(new ModifyListener() {
+                       public void modifyText(ModifyEvent e) {
+                               validatedSelectionText = validateResourceSelection();
+                       }
+               });
+
+               browseButton = new Button(composite, SWT.PUSH);
+               browseButton.setText("Browse...");
+               browseButton.addSelectionListener(new SelectionAdapter() {
+                       public void widgetSelected(SelectionEvent e) {
+                               handleBrowseSelected();
+                       }
+               });
+       }
+
+       protected abstract void handleBrowseSelected();
+       protected abstract String validateResourceSelection();
+
+       protected Shell getShell() {
+               return composite.getShell();
+       }
+
+       public void setLayoutData(Object layoutData) {
+               composite.setLayoutData(layoutData);
+       }
+
+       public void addModifyListener(ModifyListener aListener) {
+               textField.addModifyListener(aListener);
+       }
+
+       public void setBrowseDialogMessage(String aMessage) {
+               browseDialogMessage = aMessage;
+       }
+
+       public void setBrowseDialogTitle(String aTitle) {
+               browseDialogTitle = aTitle;
+       }
+
+       public void setEnabled(boolean enabled) {
+               composite.setEnabled(enabled);
+               textField.setEnabled(enabled);
+               browseButton.setEnabled(enabled);
+       }
+
+       public String getSelectionText() {
+               return textField.getText();
+       }
+
+       public String getValidatedSelectionText() {
+               return validatedSelectionText;
+       }
+
+       public void setSelectionText(String newText) {
+               textField.setText(newText);
+       }
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/SWTUtil.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/SWTUtil.java
new file mode 100644 (file)
index 0000000..a5dc609
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+package net.sourceforge.phpdt.internal.ui.util;
+
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.dnd.DragSource;
+import org.eclipse.swt.dnd.DropTarget;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Caret;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.ScrollBar;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Widget;
+
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.util.Assert;
+
+/**
+ * Utility class to simplify access to some SWT resources. 
+ */
+public class SWTUtil {
+       
+       /**
+        * Returns the standard display to be used. The method first checks, if
+        * the thread calling this method has an associated disaply. If so, this
+        * display is returned. Otherwise the method returns the default display.
+        */
+       public static Display getStandardDisplay() {
+               Display display;
+               display= Display.getCurrent();
+               if (display == null)
+                       display= Display.getDefault();
+               return display;         
+       }
+       
+       /**
+        * Returns the shell for the given widget. If the widget doesn't represent
+        * a SWT object that manage a shell, <code>null</code> is returned.
+        * 
+        * @return the shell for the given widget
+        */
+       public static Shell getShell(Widget widget) {
+               if (widget instanceof Control)
+                       return ((Control)widget).getShell();
+               if (widget instanceof Caret)
+                       return ((Caret)widget).getParent().getShell();
+               if (widget instanceof DragSource)
+                       return ((DragSource)widget).getControl().getShell();
+               if (widget instanceof DropTarget)
+                       return ((DropTarget)widget).getControl().getShell();
+               if (widget instanceof Menu)
+                       return ((Menu)widget).getParent().getShell();
+               if (widget instanceof ScrollBar)
+                       return ((ScrollBar)widget).getParent().getShell();
+                                                       
+               return null;    
+       }
+
+
+       /**
+        * Returns a width hint for a button control.
+        */
+       public static int getButtonWidthHint(Button button) {
+               PixelConverter converter= new PixelConverter(button);
+               int widthHint= converter.convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
+               return Math.max(widthHint, button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x);
+       }
+
+       /**
+        * Returns a height hint for a button control.
+        */             
+       public static int getButtonHeigthHint(Button button) {
+               PixelConverter converter= new PixelConverter(button);
+               return converter.convertVerticalDLUsToPixels(IDialogConstants.BUTTON_HEIGHT);
+       }       
+
+       
+       /**
+        * Sets width and height hint for the button control.
+        * <b>Note:</b> This is a NOP if the button's layout data is not
+        * an instance of <code>GridData</code>.
+        * 
+        * @param       the button for which to set the dimension hint
+        */             
+       public static void setButtonDimensionHint(Button button) {
+               Assert.isNotNull(button);
+               Object gd= button.getLayoutData();
+               if (gd instanceof GridData) {
+                       ((GridData)gd).heightHint= getButtonHeigthHint(button);
+                       ((GridData)gd).widthHint= getButtonWidthHint(button);            
+               }
+       }               
+       
+
+}
\ No newline at end of file
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/StringMatcher.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/StringMatcher.java
new file mode 100644 (file)
index 0000000..1649b11
--- /dev/null
@@ -0,0 +1,381 @@
+package net.sourceforge.phpdt.internal.ui.util;
+
+import java.util.*;
+
+
+/**
+ * A string pattern matcher, suppporting * and ? wildcards.
+ */
+public class StringMatcher  {
+       protected String fPattern;
+       protected int fLength; // pattern length
+       protected boolean fIgnoreWildCards;
+       protected boolean fIgnoreCase;
+       protected boolean fHasLeadingStar;
+       protected boolean fHasTrailingStar;
+       protected String fSegments[]; //the given pattern is split into * separated segments
+
+       /* boundary value beyond which we don't need to search in the text */
+       protected int fBound= 0;
+       
+
+       protected static final char fSingleWildCard= '\u0000';
+       
+       public static class Position {
+               int start; //inclusive
+               int end; //exclusive
+               public Position(int start, int end) {
+                       this.start= start;
+                       this.end= end;
+               }
+               public int getStart() {
+                       return start;
+               }
+               public int getEnd() {
+                       return end;
+               }
+       }
+       /**
+        * StringMatcher constructor takes in a String object that is a simple 
+        * pattern which may contain Â‘*Â’ for 0 and many characters and
+        * Â‘?Â’ for exactly one character.  
+        *
+        * Literal '*' and '?' characters must be escaped in the pattern 
+        * e.g., "\*" means literal "*", etc.
+        *
+        * Escaping any other character (including the escape character itself), 
+        * just results in that character in the pattern.
+        * e.g., "\a" means "a" and "\\" means "\"
+        *
+        * If invoking the StringMatcher with string literals in Java, don't forget
+        * escape characters are represented by "\\".
+        *
+        * @param pattern the pattern to match text against
+        * @param ignoreCase if true, case is ignored
+        * @param ignoreWildCards if true, wild cards and their escape sequences are ignored
+        *                (everything is taken literally).
+        */
+       public StringMatcher(String pattern, boolean ignoreCase, boolean ignoreWildCards) {
+               if (pattern == null)
+                       throw new IllegalArgumentException();
+               fIgnoreCase= ignoreCase;
+               fIgnoreWildCards= ignoreWildCards;
+               fPattern= pattern;
+               fLength= pattern.length();
+               
+               if (fIgnoreWildCards) {
+                       parseNoWildCards();
+               } else {
+                       parseWildCards();
+               }
+       }
+       /**
+        * Find the first occurrence of the pattern between <code>start</code)(inclusive) 
+        * and <code>end</code>(exclusive).  
+        * @param <code>text</code>, the String object to search in 
+        * @param <code>start</code>, the starting index of the search range, inclusive
+        * @param <code>end</code>, the ending index of the search range, exclusive
+        * @return an <code>StringMatcher.Position</code> object that keeps the starting 
+        * (inclusive) and ending positions (exclusive) of the first occurrence of the 
+        * pattern in the specified range of the text; return null if not found or subtext
+        * is empty (start==end). A pair of zeros is returned if pattern is empty string
+        * Note that for pattern like "*abc*" with leading and trailing stars, position of "abc"
+        * is returned. For a pattern like"*??*" in text "abcdf", (1,3) is returned
+        */
+       public StringMatcher.Position find(String text, int start, int end) {
+               if (text == null)
+                       throw new IllegalArgumentException();
+                       
+               int tlen= text.length();
+               if (start < 0)
+                       start= 0;
+               if (end > tlen)
+                       end= tlen;
+               if (end < 0 ||start >= end )
+                       return null;
+               if (fLength == 0)
+                       return new Position(start, start);
+               if (fIgnoreWildCards) {
+                       int x= posIn(text, start, end);
+                       if (x < 0)
+                               return null;
+                       return new Position(x, x+fLength);
+               }
+
+               int segCount= fSegments.length;
+               if (segCount == 0)//pattern contains only '*'(s)
+                       return new Position (start, end);
+                                       
+               int curPos= start;
+               int matchStart= -1;
+               int i;
+               for (i= 0; i < segCount && curPos < end; ++i) {
+                       String current= fSegments[i];
+                       int nextMatch= regExpPosIn(text, curPos, end, current);
+                       if (nextMatch < 0 )
+                               return null;
+                       if(i == 0)
+                               matchStart= nextMatch;
+                       curPos= nextMatch + current.length();
+               }
+               if (i < segCount)
+                       return null;
+               return new Position(matchStart, curPos);
+       }
+       /**
+        * match the given <code>text</code> with the pattern 
+        * @return true if matched eitherwise false
+        * @param <code>text</code>, a String object 
+        */
+       public boolean match(String text) {
+               return match(text, 0, text.length());
+       }
+       /**
+        * Given the starting (inclusive) and the ending (exclusive) positions in the   
+        * <code>text</code>, determine if the given substring matches with aPattern  
+        * @return true if the specified portion of the text matches the pattern
+        * @param String <code>text</code>, a String object that contains the substring to match 
+        * @param int <code>start<code> marks the starting position (inclusive) of the substring
+        * @param int <code>end<code> marks the ending index (exclusive) of the substring 
+        */
+       public boolean match(String text, int start, int end) {
+               if (null == text)
+                       throw new IllegalArgumentException();
+                       
+               if (start > end)
+                       return false;
+               
+               if (fIgnoreWildCards)
+                       return (end - start == fLength) && fPattern.regionMatches(fIgnoreCase, 0, text, start, fLength);
+               int segCount= fSegments.length;
+               if (segCount == 0 && (fHasLeadingStar || fHasTrailingStar))  // pattern contains only '*'(s)
+                       return true;
+               if (start == end)
+                       return fLength == 0;
+               if (fLength == 0)
+                       return start == end;    
+                
+               int tlen= text.length();
+               if (start < 0)
+                       start= 0;
+               if (end > tlen)
+                       end= tlen; 
+                                       
+               int tCurPos= start;
+               int bound= end - fBound;
+               if ( bound < 0)
+                       return false;
+               int i=0;
+               String current= fSegments[i];
+               int segLength= current.length();
+
+               /* process first segment */
+               if (!fHasLeadingStar){ 
+                       if(!regExpRegionMatches(text, start, current, 0, segLength)) {
+                               return false;
+                       } else {
+                               ++i;
+                               tCurPos= tCurPos + segLength;
+                       }
+               }
+
+               /* process middle segments */   
+               while (i < segCount) {
+                       current= fSegments[i];
+                       int currentMatch;
+                       int k= current.indexOf(fSingleWildCard);
+                       if (k < 0) {
+                               currentMatch= textPosIn(text, tCurPos, end, current);
+                               if (currentMatch < 0)
+                                       return false;
+                       } else { 
+                               currentMatch= regExpPosIn(text, tCurPos, end, current);
+                               if (currentMatch < 0)
+                                       return false;
+                       }
+                       tCurPos= currentMatch + current.length();
+                       i++;
+               }
+
+               /* process final segment */
+               if (!fHasTrailingStar && tCurPos != end) {
+                       int clen= current.length();
+                       return regExpRegionMatches(text, end - clen, current, 0, clen);
+               }
+               return i == segCount ;
+       }
+       /**
+        * This method parses the given pattern into segments seperated by wildcard '*' characters.
+        * Since wildcards are not being used in this case, the pattern consists of a single segment.
+        */
+       private void parseNoWildCards() {
+               fSegments= new String[1];
+               fSegments[0]= fPattern;
+               fBound= fLength;
+       }
+       /**
+        * Parses the given pattern into segments seperated by wildcard '*' characters.
+        * @param p, a String object that is a simple regular expression with Â‘*Â’ and/or Â‘?Â’
+        */
+       private void parseWildCards() {
+               if(fPattern.startsWith("*"))//$NON-NLS-1$
+                       fHasLeadingStar= true;
+               if(fPattern.endsWith("*")) {//$NON-NLS-1$
+                       /* make sure it's not an escaped wildcard */
+                       if (fLength > 1 && fPattern.charAt(fLength - 2) != '\\') {
+                               fHasTrailingStar= true;
+                       }
+               }
+
+               Vector temp= new Vector();
+
+               int pos= 0;
+               StringBuffer buf= new StringBuffer();
+               while (pos < fLength) {
+                       char c= fPattern.charAt(pos++);
+                       switch (c) {
+                               case '\\':
+                                       if (pos >= fLength) {
+                                               buf.append(c);
+                                       } else {
+                                               char next= fPattern.charAt(pos++);
+                                               /* if it's an escape sequence */
+                                               if (next == '*' || next == '?' || next == '\\') {
+                                                       buf.append(next);
+                                               } else {
+                                                       /* not an escape sequence, just insert literally */
+                                                       buf.append(c);
+                                                       buf.append(next);
+                                               }
+                                       }
+                               break;
+                               case '*':
+                                       if (buf.length() > 0) {
+                                               /* new segment */
+                                               temp.addElement(buf.toString());
+                                               fBound += buf.length();
+                                               buf.setLength(0);
+                                       }
+                               break;
+                               case '?':
+                                       /* append special character representing single match wildcard */
+                                       buf.append(fSingleWildCard);
+                               break;
+                               default:
+                                       buf.append(c);
+                       }
+               }
+
+               /* add last buffer to segment list */
+               if (buf.length() > 0) {
+                       temp.addElement(buf.toString());
+                       fBound += buf.length();
+               }
+                       
+               fSegments= new String[temp.size()];
+               temp.copyInto(fSegments);
+       }
+       /** 
+        * @param <code>text</code>, a string which contains no wildcard
+        * @param <code>start</code>, the starting index in the text for search, inclusive
+        * @param <code>end</code>, the stopping point of search, exclusive
+        * @return the starting index in the text of the pattern , or -1 if not found 
+        */
+       protected int posIn(String text, int start, int end) {//no wild card in pattern
+               int max= end - fLength;
+               
+               if (!fIgnoreCase) {
+                       int i= text.indexOf(fPattern, start);
+                       if (i == -1 || i > max)
+                               return -1;
+                       return i;
+               }
+               
+               for (int i= start; i <= max; ++i) {
+                       if (text.regionMatches(true, i, fPattern, 0, fLength))
+                               return i;
+               }
+               
+               return -1;
+       }
+       /** 
+        * @param <code>text</code>, a simple regular expression that may only contain '?'(s)
+        * @param <code>start</code>, the starting index in the text for search, inclusive
+        * @param <code>end</code>, the stopping point of search, exclusive
+        * @param <code>p</code>, a simple regular expression that may contains '?'
+        * @param <code>caseIgnored</code>, wether the pattern is not casesensitive
+        * @return the starting index in the text of the pattern , or -1 if not found 
+        */
+       protected int regExpPosIn(String text, int start, int end, String p) {
+               int plen= p.length();
+               
+               int max= end - plen;
+               for (int i= start; i <= max; ++i) {
+                       if (regExpRegionMatches(text, i, p, 0, plen))
+                               return i;
+               }
+               return -1;
+       }
+       /**
+        * 
+        * @return boolean
+        * @param <code>text</code>, a String to match
+        * @param <code>start</code>, int that indicates the starting index of match, inclusive
+        * @param <code>end</code> int that indicates the ending index of match, exclusive
+        * @param <code>p</code>, String,  String, a simple regular expression that may contain '?'
+        * @param <code>ignoreCase</code>, boolean indicating wether code>p</code> is case sensitive
+        */
+       protected boolean regExpRegionMatches(String text, int tStart, String p, int pStart, int plen) {
+               while (plen-- > 0) {
+                       char tchar= text.charAt(tStart++);
+                       char pchar= p.charAt(pStart++);
+
+                       /* process wild cards */
+                       if (!fIgnoreWildCards) {
+                               /* skip single wild cards */
+                               if (pchar == fSingleWildCard) {
+                                       continue;
+                               }
+                       }
+                       if (pchar == tchar)
+                               continue;
+                       if (fIgnoreCase) {
+                               if (Character.toUpperCase(tchar) == Character.toUpperCase(pchar))
+                                       continue;
+                               // comparing after converting to upper case doesn't handle all cases;
+                               // also compare after converting to lower case
+                               if (Character.toLowerCase(tchar) == Character.toLowerCase(pchar))
+                                       continue;
+                       }
+                       return false;
+               }
+               return true;
+       }
+       /** 
+        * @param <code>text</code>, the string to match
+        * @param <code>start</code>, the starting index in the text for search, inclusive
+        * @param <code>end</code>, the stopping point of search, exclusive
+        * @param code>p</code>, a string that has no wildcard
+        * @param <code>ignoreCase</code>, boolean indicating wether code>p</code> is case sensitive
+        * @return the starting index in the text of the pattern , or -1 if not found 
+        */
+       protected int textPosIn(String text, int start, int end, String p) { 
+               
+               int plen= p.length();
+               int max= end - plen;
+               
+               if (!fIgnoreCase) {
+                       int i= text.indexOf(p, start);
+                       if (i == -1 || i > max)
+                               return -1;
+                       return i;
+               }
+               
+               for (int i= start; i <= max; ++i) {
+                       if (text.regionMatches(true, i, p, 0, plen))
+                               return i;
+               }
+               
+               return -1;
+       }
+}
\ No newline at end of file
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/TwoArrayQuickSorter.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/TwoArrayQuickSorter.java
new file mode 100644 (file)
index 0000000..49e6e84
--- /dev/null
@@ -0,0 +1,101 @@
+package net.sourceforge.phpdt.internal.ui.util;
+
+import java.util.Comparator;
+import org.eclipse.jface.util.Assert;
+
+/**
+ * Quick sort to sort key-value pairs. The keys and arrays are specified
+ * in separate arrays.
+ */
+public class TwoArrayQuickSorter {
+       
+       private Comparator fComparator;
+
+       /**
+        * Default comparator.
+        */
+       public static final class StringComparator implements Comparator {
+               private boolean fIgnoreCase;
+       
+               StringComparator(boolean ignoreCase) {
+                       fIgnoreCase= ignoreCase;
+               }
+       
+               public int compare(Object left, Object right) {
+                       return fIgnoreCase
+                               ? ((String) left).compareToIgnoreCase((String) right)
+                               : ((String) left).compareTo((String) right);
+               }
+       }               
+
+       /**
+        * Creates a sorter with default string comparator.
+        * The keys are assumed to be strings.
+        * @param ignoreCase specifies whether sorting is case sensitive or not.
+        */                             
+       public TwoArrayQuickSorter(boolean ignoreCase) {
+               fComparator= new StringComparator(ignoreCase);
+       }
+
+       /**
+        * Creates a sorter with a comparator.
+        * @param comparator the comparator to order the elements. The comparator must not be <code>null</code>.
+        */
+       public TwoArrayQuickSorter(Comparator comparator) {
+               fComparator= comparator;
+       }
+       
+       /**
+        * Sorts keys and values in parallel.
+        * @param keys   the keys to use for sorting.
+        * @param values the values associated with the keys.
+        */
+       public void sort(Object[] keys, Object[] values) {
+               if ((keys == null) || (values == null)) {
+                       Assert.isTrue(false, "Either keys or values in null"); //$NON-NLS-1$
+                       return;
+               }
+
+               if (keys.length <= 1)
+                       return;
+                       
+               internalSort(keys, values, 0, keys.length - 1); 
+       }
+
+       private void internalSort(Object[] keys, Object[] values, int left, int right) {
+               int original_left= left;
+               int original_right= right;
+               
+               Object mid= keys[(left + right) / 2]; 
+               do { 
+                       while (fComparator.compare(keys[left], mid) < 0)
+                               left++; 
+
+                       while (fComparator.compare(mid, keys[right]) < 0)
+                               right--; 
+
+                       if (left <= right) {
+                               swap(keys, left, right);
+                               swap(values, left, right);
+                               left++; 
+                               right--; 
+                       } 
+               } while (left <= right);
+               
+               if (original_left < right)
+                       internalSort(keys , values, original_left, right); 
+
+               if (left < original_right)
+                       internalSort(keys, values, left, original_right); 
+       }
+
+    /*
+     * Swaps x[a] with x[b].
+     */     
+    private static final void swap(Object x[], int a, int b) {
+               Object t = x[a];
+               x[a] = x[b];
+               x[b] = t;
+    }
+    
+}
\ No newline at end of file
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/viewsupport/ContainerCheckedTreeViewer.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/viewsupport/ContainerCheckedTreeViewer.java
new file mode 100644 (file)
index 0000000..deaac0e
--- /dev/null
@@ -0,0 +1,175 @@
+package net.sourceforge.phpdt.internal.ui.viewsupport;
+
+import java.util.ArrayList;
+
+import org.eclipse.jface.viewers.CheckStateChangedEvent;
+import org.eclipse.jface.viewers.CheckboxTreeViewer;
+import org.eclipse.jface.viewers.ICheckStateListener;
+import org.eclipse.jface.viewers.ITreeViewerListener;
+import org.eclipse.jface.viewers.TreeExpansionEvent;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Item;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.swt.widgets.Widget;
+
+/**
+ * CheckboxTreeViewer with special behaviour of the checked / gray state on 
+ * container (non-leaf) nodes:
+ * The grayed state is used to visualize the checked state of its children.
+ * Containers are checked and non-gary if all contained leafs are checked. The
+ * container is grayed if some but not all leafs are checked.
+ */
+public class ContainerCheckedTreeViewer extends CheckboxTreeViewer  {
+
+       /**
+        * Constructor for ContainerCheckedTreeViewer.
+        * @see CheckboxTreeViewer#CheckboxTreeViewer(Composite)
+        */
+       public ContainerCheckedTreeViewer(Composite parent) {
+               super(parent);
+               initViewer();
+       }
+
+       /**
+        * Constructor for ContainerCheckedTreeViewer.
+        * @see CheckboxTreeViewer#CheckboxTreeViewer(Composite,int)
+        */
+       public ContainerCheckedTreeViewer(Composite parent, int style) {
+               super(parent, style);
+               initViewer();
+       }
+
+       /**
+        * Constructor for ContainerCheckedTreeViewer.
+        * @see CheckboxTreeViewer#CheckboxTreeViewer(Tree)
+        */
+       public ContainerCheckedTreeViewer(Tree tree) {
+               super(tree);
+               initViewer();
+       }
+
+       private void initViewer() {
+               setUseHashlookup(true);
+               addCheckStateListener(new ICheckStateListener() {
+                       public void checkStateChanged(CheckStateChangedEvent event) {
+                               doCheckStateChanged(event.getElement());
+                       }
+               });
+               addTreeListener(new ITreeViewerListener() {
+                       public void treeCollapsed(TreeExpansionEvent event) {}
+                       public void treeExpanded(TreeExpansionEvent event) {
+                               Widget item = findItem(event.getElement());
+                               if (item instanceof TreeItem) {
+                                       initializeItem((TreeItem) item);
+                               }
+                       }
+               });
+       }
+
+       protected void doCheckStateChanged(Object element) {
+               Widget item = findItem(element);
+               if (item instanceof TreeItem) {
+                       TreeItem treeItem = (TreeItem) item;
+                       treeItem.setGrayed(false);
+                       updateChildrenItems(treeItem);
+                       updateParentItems(treeItem.getParentItem());
+               }
+       }
+
+       /**
+        * The item has expanded. Updates the checked state of its children. 
+        */
+       private void initializeItem(TreeItem item) {
+               if (item.getChecked() && !item.getGrayed()) {
+                       updateChildrenItems((TreeItem) item);
+               }
+       }
+
+       /**
+        * Updates the check state of all created children
+        */
+       private void updateChildrenItems(TreeItem parent) {
+               Item[] children = getChildren(parent);
+               boolean state = parent.getChecked();
+               for (int i = 0; i < children.length; i++) {
+                       TreeItem curr = (TreeItem) children[i];
+                       if (curr.getData() != null && ((curr.getChecked() != state) || curr.getGrayed())) {
+                               curr.setChecked(state);
+                               curr.setGrayed(false);
+                               updateChildrenItems(curr);
+                       }
+               }
+       }
+
+       /**
+        * Updates the check / gray state of all parent items
+        */
+       private void updateParentItems(TreeItem item) {
+               if (item != null) {
+                       Item[] children = getChildren(item);
+                       boolean containsChecked = false;
+                       boolean containsUnchecked = false;
+                       for (int i = 0; i < children.length; i++) {
+                               TreeItem curr = (TreeItem) children[i];
+                               containsChecked |= curr.getChecked();
+                               containsUnchecked |= (!curr.getChecked() || curr.getGrayed());
+                       }
+                       item.setChecked(containsChecked);
+                       item.setGrayed(containsChecked && containsUnchecked);
+                       updateParentItems(item.getParentItem());
+               }
+       }
+
+       public boolean setChecked(Object element, boolean state) {
+               if (super.setChecked(element, state)) {
+                       doCheckStateChanged(element);
+                       return true;
+               }
+               return false;
+       }
+
+       public void setCheckedElements(Object[] elements) {
+               super.setCheckedElements(elements);
+               for (int i = 0; i < elements.length; i++) {
+                       doCheckStateChanged(elements[i]);
+               }
+       }
+
+       protected void setExpanded(Item item, boolean expand) {
+               super.setExpanded(item, expand);
+               if (expand && item instanceof TreeItem) {
+                       initializeItem((TreeItem) item);
+               }
+       }
+
+       public Object[] getCheckedElements() {
+               Object[] checked = super.getCheckedElements();
+               // add all items that are children of a checked node but not created yet
+               ArrayList result = new ArrayList();
+               for (int i = 0; i < checked.length; i++) {
+                       Object curr = checked[i];
+                       result.add(curr);
+                       Widget item = findItem(curr);
+                       if (item != null) {
+                               Item[] children = getChildren(item);
+                               // check if contains the dummy node
+                               if (children.length == 1 && children[0].getData() == null) {
+                                       // not yet created
+                                       collectChildren(curr, result);
+                               }
+                       }
+               }
+               return result.toArray();
+       }
+
+       private void collectChildren(Object element, ArrayList result) {
+               Object[] filteredChildren = getFilteredChildren(element);
+               for (int i = 0; i < filteredChildren.length; i++) {
+                       Object curr = filteredChildren[i];
+                       result.add(curr);
+                       collectChildren(curr, result);
+               }
+       }
+
+}
\ No newline at end of file
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/viewsupport/ImageDescriptorRegistry.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/viewsupport/ImageDescriptorRegistry.java
new file mode 100644 (file)
index 0000000..ae34a4c
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+package net.sourceforge.phpdt.internal.ui.viewsupport;
+
+import java.util.HashMap;
+import java.util.Iterator;
+
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+
+import net.sourceforge.phpdt.internal.ui.util.SWTUtil;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.util.Assert;
+
+/**
+ * A registry that maps <code>ImageDescriptors</code> to <code>Image</code>.
+ */
+public class ImageDescriptorRegistry {
+
+       private HashMap fRegistry= new HashMap(10);
+       private Display fDisplay;
+       
+       /**
+        * Creates a new image descriptor registry for the current or default display,
+        * respectively.
+        */
+       public ImageDescriptorRegistry() {
+               this(SWTUtil.getStandardDisplay());
+       }
+       
+       /**
+        * Creates a new image descriptor registry for the given display. All images
+        * managed by this registry will be disposed when the display gets disposed.
+        * 
+        * @param diaplay the display the images managed by this registry are allocated for 
+        */
+       public ImageDescriptorRegistry(Display display) {
+               fDisplay= display;
+               Assert.isNotNull(fDisplay);
+               hookDisplay();
+       }
+       
+       /**
+        * Returns the image assiciated with the given image descriptor.
+        * 
+        * @param descriptor the image descriptor for which the registry manages an image
+        * @return the image associated with the image descriptor or <code>null</code>
+        *  if the image descriptor can't create the requested image.
+        */
+       public Image get(ImageDescriptor descriptor) {
+               if (descriptor == null)
+                       descriptor= ImageDescriptor.getMissingImageDescriptor();
+                       
+               Image result= (Image)fRegistry.get(descriptor);
+               if (result != null)
+                       return result;
+       
+               Assert.isTrue(fDisplay == SWTUtil.getStandardDisplay(), "Allocating image for wrong display."); //$NON-NLS-1$
+               result= descriptor.createImage();
+               if (result != null)
+                       fRegistry.put(descriptor, result);
+               return result;
+       }
+
+       /**
+        * Disposes all images managed by this registry.
+        */     
+       public void dispose() {
+               for (Iterator iter= fRegistry.values().iterator(); iter.hasNext(); ) {
+                       Image image= (Image)iter.next();
+                       image.dispose();
+               }
+               fRegistry.clear();
+       }
+       
+       private void hookDisplay() {
+               fDisplay.disposeExec(new Runnable() {
+                       public void run() {
+                               dispose();
+                       }       
+               });
+       }
+}
+
diff --git a/net.sourceforge.phpeclipse/templates.xml b/net.sourceforge.phpeclipse/templates.xml
new file mode 100644 (file)
index 0000000..d635aae
--- /dev/null
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<templates>
+<template name="class" description="class template with constructor" context="php" enabled="true">class ${class_name} {
+  function ${class_name}() {
+         ${cursor}
+  }
+}</template>
+<template name="class" description="class with attribute" context="php" enabled="true">class ${class_name} {
+  var $$${attribute};
+  function ${class_name}() {
+         ${cursor}
+  }
+  
+  function set_${attribute}( $$${attr} ) {
+    $$this->${attribute} = $$${attr};
+       }
+
+       function get_${attribute}() {
+    return $$this->${attribute};
+       }
+}</template>
+<template name="for" description="iterate over array" context="php" enabled="true">for ($$${index} = 0; $$${index} &lt; sizeof($$${array}); $$${index}++) {
+       ${cursor}
+}</template>
+<template name="for" description="iterate over array w/ temporary variable" context="php" enabled="true">for ($$${index} = 0; $$${index} &lt; sizeof($$${array}); $$${index}++) {
+       $$${array_element} = $$${array}[$$${index}];
+       ${cursor}
+}</template>
+<template name="function" description="function template" context="php" enabled="true">function ${function_name} () {
+       ${cursor}
+}</template>
+<template name="function" description="function template with return" context="php" enabled="true">function ${function_name} () {
+       return (${cursor});
+}</template>
+<template name="while" description="while iteration" context="php" enabled="true">while (${condition}) {
+       ${cursor}
+}</template>
+<template name="switch" description="switch case statement" context="php" enabled="true">switch (${key}) {
+       case ${value}:
+               ${cursor}
+               break;
+
+       default:
+               break;
+}</template><template name="if" description="if statement" context="php" enabled="true">if (${condition}) {
+       ${cursor}
+}</template><template name="ifelse" description="if else statement" context="php" enabled="true">if (${condition}) {
+       ${cursor}
+} else {
+       
+}</template><template name="elseif" description="else if block" context="php" enabled="true">elseif (${condition}) {
+       ${cursor}
+}</template><template name="else" description="else block" context="php" enabled="true">else {
+       ${cursor}
+}</template>
+<template name="filecomment" description="file comment used by the class and interface wizards" context="php" enabled="true">/**
+ * Created on ${date} by ${user}
+ *
+ */</template><template name="functioncomment" description="function comment" context="php" enabled="true">/**
+ * @author ${user}
+ *
+ */</template>
+ <template name="echo" description="echo a string" context="php" enabled="true">echo "${string}";
+  ${cursor}</template>
+ </templates>
\ No newline at end of file