new version with WorkingCopy Management
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpeclipse / phpeditor / PHPDocumentProvider.java
index 891f7f2..fb4f623 100644 (file)
@@ -12,36 +12,65 @@ Contributors:
     Klaus Hartlage - www.eclipseproject.de
 **********************************************************************/
 
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 
+import net.sourceforge.phpdt.core.IBuffer;
+import net.sourceforge.phpdt.core.IBufferFactory;
+import net.sourceforge.phpdt.core.ICompilationUnit;
+import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
+import net.sourceforge.phpdt.core.IOpenable;
 import net.sourceforge.phpdt.core.IProblemRequestor;
+import net.sourceforge.phpdt.core.JavaModelException;
 import net.sourceforge.phpdt.core.compiler.IProblem;
+import net.sourceforge.phpdt.internal.ui.PHPStatusConstants;
+import net.sourceforge.phpdt.internal.ui.PHPUIStatus;
 import net.sourceforge.phpdt.internal.ui.text.java.IProblemRequestorExtension;
-import net.sourceforge.phpeclipse.phpeditor.php.IPHPPartitionScannerConstants;
-import net.sourceforge.phpeclipse.phpeditor.php.PHPPartitionScanner;
+import net.sourceforge.phpdt.ui.PreferenceConstants;
+import net.sourceforge.phpdt.ui.text.JavaTextTools;
+import net.sourceforge.phpeclipse.PHPCore;
+import net.sourceforge.phpeclipse.PHPeclipsePlugin;
 
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IMarker;
 import org.eclipse.core.resources.IMarkerDelta;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.DefaultLineTracker;
+import org.eclipse.jface.text.Document;
 import org.eclipse.jface.text.IDocument;
 import org.eclipse.jface.text.IDocumentPartitioner;
 import org.eclipse.jface.text.ILineTracker;
 import org.eclipse.jface.text.Position;
-import org.eclipse.jface.text.rules.DefaultPartitioner;
 import org.eclipse.jface.text.source.Annotation;
 import org.eclipse.jface.text.source.AnnotationModelEvent;
 import org.eclipse.jface.text.source.IAnnotationModel;
 import org.eclipse.jface.text.source.IAnnotationModelListener;
 import org.eclipse.jface.text.source.IAnnotationModelListenerExtension;
+import org.eclipse.jface.util.IPropertyChangeListener;
 import org.eclipse.jface.util.ListenerList;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IEditorInput;
 import org.eclipse.ui.IFileEditorInput;
 import org.eclipse.ui.editors.text.FileDocumentProvider;
 import org.eclipse.ui.part.FileEditorInput;
+import org.eclipse.ui.texteditor.AbstractMarkerAnnotationModel;
 import org.eclipse.ui.texteditor.MarkerAnnotation;
 import org.eclipse.ui.texteditor.ResourceMarkerAnnotationModel;
 
@@ -50,107 +79,34 @@ import org.eclipse.ui.texteditor.ResourceMarkerAnnotationModel;
  */
 
 public class PHPDocumentProvider extends FileDocumentProvider {
-
-  // private final static String[] TYPES= new String[] { PHPPartitionScanner.PHP, PHPPartitionScanner.JAVA_DOC, PHPPartitionScanner.JAVA_MULTILINE_COMMENT };
-  private final static String[] TYPES =
-    new String[] {
-      IPHPPartitionScannerConstants.PHP,
-      IPHPPartitionScannerConstants.PHP_MULTILINE_COMMENT,
-      IPHPPartitionScannerConstants.HTML,
-      IPHPPartitionScannerConstants.HTML_MULTILINE_COMMENT,
-      IPHPPartitionScannerConstants.JAVASCRIPT,
-      IPHPPartitionScannerConstants.CSS,
-                       IPHPPartitionScannerConstants.SMARTY,
-                       IPHPPartitionScannerConstants.SMARTY_MULTILINE_COMMENT };
-
-  private static PHPPartitionScanner PHP_PARTITION_SCANNER = null;
-  private static PHPPartitionScanner HTML_PARTITION_SCANNER = null;
-  private static PHPPartitionScanner XML_PARTITION_SCANNER = null;
-  private static PHPPartitionScanner SMARTY_PARTITION_SCANNER = null;
-
-  /** annotation model listener added to all created CU annotation models */
-  //           private GlobalAnnotationModelListener fGlobalAnnotationModelListener;   
-
   /**
-                * Internal structure for mapping positions to some value. 
-                * The reason for this specific structure is that positions can
-                * change over time. Thus a lookup is based on value and not
-                * on hash value.
-                */
-  protected static class ReverseMap {
-
-    static class Entry {
-      Position fPosition;
-      Object fValue;
-    };
-
-    private List fList = new ArrayList(2);
-    private int fAnchor = 0;
-
-    public ReverseMap() {
-    }
-
-    public Object get(Position position) {
-
-      Entry entry;
-
-      // behind anchor
-      int length = fList.size();
-      for (int i = fAnchor; i < length; i++) {
-        entry = (Entry) fList.get(i);
-        if (entry.fPosition.equals(position)) {
-          fAnchor = i;
-          return entry.fValue;
-        }
-      }
-
-      // before anchor
-      for (int i = 0; i < fAnchor; i++) {
-        entry = (Entry) fList.get(i);
-        if (entry.fPosition.equals(position)) {
-          fAnchor = i;
-          return entry.fValue;
-        }
-      }
-
-      return null;
+                        * Here for visibility issues only.
+                        */
+  protected class _FileSynchronizer extends FileSynchronizer {
+    public _FileSynchronizer(IFileEditorInput fileEditorInput) {
+      super(fileEditorInput);
     }
+  };
+  /**
+                * Bundle of all required informations to allow working copy management. 
+                */
+  protected class CompilationUnitInfo extends FileInfo {
 
-    private int getIndex(Position position) {
-      Entry entry;
-      int length = fList.size();
-      for (int i = 0; i < length; i++) {
-        entry = (Entry) fList.get(i);
-        if (entry.fPosition.equals(position))
-          return i;
-      }
-      return -1;
-    }
+    ICompilationUnit fCopy;
 
-    public void put(Position position, Object value) {
-      int index = getIndex(position);
-      if (index == -1) {
-        Entry entry = new Entry();
-        entry.fPosition = position;
-        entry.fValue = value;
-        fList.add(entry);
-      } else {
-        Entry entry = (Entry) fList.get(index);
-        entry.fValue = value;
-      }
+    public CompilationUnitInfo(
+      IDocument document,
+      IAnnotationModel model,
+      _FileSynchronizer fileSynchronizer,
+      ICompilationUnit copy) {
+      super(document, model, fileSynchronizer);
+      fCopy = copy;
     }
 
-    public void remove(Position position) {
-      int index = getIndex(position);
-      if (index > -1)
-        fList.remove(index);
-    }
-
-    public void clear() {
-      fList.clear();
+    public void setModificationStamp(long timeStamp) {
+      fModificationStamp = timeStamp;
     }
   };
-
   /**
                 * Annotation model dealing with java marker annotations and temporary problems.
                 * Also acts as problem requestor for its compilation unit. Initialiy inactive. Must explicitly be
@@ -159,22 +115,61 @@ public class PHPDocumentProvider extends FileDocumentProvider {
   protected class CompilationUnitAnnotationModel
     extends ResourceMarkerAnnotationModel
     implements IProblemRequestor, IProblemRequestorExtension {
-
-    private IFileEditorInput fInput;
     private List fCollectedProblems;
+    private List fCurrentlyOverlaid = new ArrayList();
     private List fGeneratedAnnotations;
-    private IProgressMonitor fProgressMonitor;
+
+    private IFileEditorInput fInput;
     private boolean fIsActive = false;
+    private List fPreviouslyOverlaid = null;
+    private IProgressMonitor fProgressMonitor;
 
     private ReverseMap fReverseMap = new ReverseMap();
-    private List fPreviouslyOverlaid = null;
-    private List fCurrentlyOverlaid = new ArrayList();
 
     public CompilationUnitAnnotationModel(IFileEditorInput input) {
       super(input.getFile());
       fInput = input;
     }
 
+    /*
+     * @see IProblemRequestor#acceptProblem(IProblem)
+     */
+    public void acceptProblem(IProblem problem) {
+      if (isActive())
+        fCollectedProblems.add(problem);
+    }
+
+    /*
+     * @see AnnotationModel#addAnnotation(Annotation, Position, boolean)
+     */
+    protected void addAnnotation(Annotation annotation, Position position, boolean fireModelChanged) {
+      super.addAnnotation(annotation, position, fireModelChanged);
+
+      Object cached = fReverseMap.get(position);
+      if (cached == null)
+        fReverseMap.put(position, annotation);
+      else if (cached instanceof List) {
+        List list = (List) cached;
+        list.add(annotation);
+      } else if (cached instanceof Annotation) {
+        List list = new ArrayList(2);
+        list.add(cached);
+        list.add(annotation);
+        fReverseMap.put(position, list);
+      }
+    }
+
+    /*
+     * @see IProblemRequestor#beginReporting()
+     */
+    public void beginReporting() {
+      ICompilationUnit unit = getWorkingCopy(fInput);
+      if (unit != null) // && unit.getJavaProject().isOnClasspath(unit))
+        fCollectedProblems = new ArrayList();
+      else
+        fCollectedProblems = null;
+    }
+
     protected MarkerAnnotation createMarkerAnnotation(IMarker marker) {
       return new JavaMarkerAnnotation(marker);
     }
@@ -191,40 +186,6 @@ public class PHPDocumentProvider extends FileDocumentProvider {
       return new Position(start, length);
     }
 
-    protected void update(IMarkerDelta[] markerDeltas) {
-
-      super.update(markerDeltas);
-
-      //                                       if (markerDeltas != null && markerDeltas.length > 0) {
-      //                                               try {
-      //                                                       ICompilationUnit workingCopy = getWorkingCopy(fInput);
-      //                                                       if (workingCopy != null)
-      //                                                               workingCopy.reconcile(true, null);
-      //                                               } catch (JavaModelException ex) {
-      //                                                       handleCoreException(ex, ex.getMessage());
-      //                                               }
-      //                                       }
-    }
-
-    /*
-     * @see IProblemRequestor#beginReporting()
-     */
-    public void beginReporting() {
-      //                                       ICompilationUnit unit= getWorkingCopy(fInput);
-      //                                       if (unit != null && unit.getJavaProject().isOnClasspath(unit))
-      //                                               fCollectedProblems= new ArrayList();
-      //                                       else
-      fCollectedProblems = null;
-    }
-
-    /*
-     * @see IProblemRequestor#acceptProblem(IProblem)
-     */
-    public void acceptProblem(IProblem problem) {
-      if (isActive())
-        fCollectedProblems.add(problem);
-    }
-
     /*
      * @see IProblemRequestor#endReporting()
      */
@@ -263,10 +224,10 @@ public class PHPDocumentProvider extends FileDocumentProvider {
             Position position = createPositionFromProblem(problem);
             if (position != null) {
 
-              //                                                                       ProblemAnnotation annotation= new ProblemAnnotation(problem);
-              //                                                                       overlayMarkers(position, annotation);                                                           
-              //                                                                       fGeneratedAnnotations.add(annotation);
-              //                                                                       addAnnotation(annotation, position, false);
+              ProblemAnnotation annotation = new ProblemAnnotation(problem);
+              overlayMarkers(position, annotation);
+              fGeneratedAnnotations.add(annotation);
+              addAnnotation(annotation, position, false);
 
               temporaryProblemsChanged = true;
             }
@@ -280,8 +241,54 @@ public class PHPDocumentProvider extends FileDocumentProvider {
         fPreviouslyOverlaid = null;
       }
 
-      //                                       if (temporaryProblemsChanged)
-      //                                               fireModelChanged(new CompilationUnitAnnotationModelEvent(this, getResource(), false));
+      if (temporaryProblemsChanged)
+        fireModelChanged(new CompilationUnitAnnotationModelEvent(this, getResource(), false));
+    }
+
+    private Object getAnnotations(Position position) {
+      return fReverseMap.get(position);
+    }
+
+    /*
+     * @see AnnotationModel#fireModelChanged()
+     */
+    protected void fireModelChanged() {
+      fireModelChanged(new CompilationUnitAnnotationModelEvent(this, getResource(), true));
+    }
+
+    /*
+     * @see IProblemRequestor#isActive()
+     */
+    public boolean isActive() {
+      return fIsActive && (fCollectedProblems != null);
+    }
+
+    /*
+     * @see AnnotationModel#removeAllAnnotations(boolean)
+     */
+    protected void removeAllAnnotations(boolean fireModelChanged) {
+      super.removeAllAnnotations(fireModelChanged);
+      fReverseMap.clear();
+    }
+
+    /*
+     * @see AnnotationModel#removeAnnotation(Annotation, boolean)
+     */
+    protected void removeAnnotation(Annotation annotation, boolean fireModelChanged) {
+      Position position = getPosition(annotation);
+      Object cached = fReverseMap.get(position);
+      if (cached instanceof List) {
+        List list = (List) cached;
+        list.remove(annotation);
+        if (list.size() == 1) {
+          fReverseMap.put(position, list.get(0));
+          list.clear();
+        }
+      } else if (cached instanceof Annotation) {
+        fReverseMap.remove(position);
+      }
+
+      super.removeAnnotation(annotation, fireModelChanged);
     }
 
     private void removeMarkerOverlays(boolean isCanceled) {
@@ -296,31 +303,51 @@ public class PHPDocumentProvider extends FileDocumentProvider {
       }
     }
 
+    /*
+     * @see IProblemRequestorExtension#setIsActive(boolean)
+     */
+    public void setIsActive(boolean isActive) {
+      if (fIsActive != isActive) {
+        fIsActive = isActive;
+        if (fIsActive)
+          startCollectingProblems();
+        else
+          stopCollectingProblems();
+      }
+    }
+
+    /*
+     * @see IProblemRequestorExtension#setProgressMonitor(IProgressMonitor)
+     */
+    public void setProgressMonitor(IProgressMonitor monitor) {
+      fProgressMonitor = monitor;
+    }
+
     /**
      * Overlays value with problem annotation.
      * @param problemAnnotation
      */
-    //                         private void setOverlay(Object value, ProblemAnnotation problemAnnotation) {
-    //                                 if (value instanceof  JavaMarkerAnnotation) {
-    //                                         JavaMarkerAnnotation annotation= (JavaMarkerAnnotation) value;
-    //                                         if (annotation.isProblem()) {
-    //                                                 annotation.setOverlay(problemAnnotation);
-    //                                                 fPreviouslyOverlaid.remove(annotation);
-    //                                                 fCurrentlyOverlaid.add(annotation);
-    //                                         }
-    //                                 }
-    //                         }
-
-    //                         private void  overlayMarkers(Position position, ProblemAnnotation problemAnnotation) {
-    //                                 Object value= getAnnotations(position);
-    //                                 if (value instanceof List) {
-    //                                         List list= (List) value;
-    //                                         for (Iterator e = list.iterator(); e.hasNext();)
-    //                                                 setOverlay(e.next(), problemAnnotation);
-    //                                 } else {
-    //                                         setOverlay(value, problemAnnotation);
-    //                                 }
-    //                         }
+    private void setOverlay(Object value, ProblemAnnotation problemAnnotation) {
+      if (value instanceof JavaMarkerAnnotation) {
+        JavaMarkerAnnotation annotation = (JavaMarkerAnnotation) value;
+        if (annotation.isProblem()) {
+          annotation.setOverlay(problemAnnotation);
+          fPreviouslyOverlaid.remove(annotation);
+          fCurrentlyOverlaid.add(annotation);
+        }
+      }
+    }
+
+    private void overlayMarkers(Position position, ProblemAnnotation problemAnnotation) {
+      Object value = getAnnotations(position);
+      if (value instanceof List) {
+        List list = (List) value;
+        for (Iterator e = list.iterator(); e.hasNext();)
+          setOverlay(e.next(), problemAnnotation);
+      } else {
+        setOverlay(value, problemAnnotation);
+      }
+    }
 
     /**
      * Tells this annotation model to collect temporary problems from now on.
@@ -342,260 +369,938 @@ public class PHPDocumentProvider extends FileDocumentProvider {
       fGeneratedAnnotations = null;
     }
 
+    protected void update(IMarkerDelta[] markerDeltas) {
+
+      super.update(markerDeltas);
+
+      if (markerDeltas != null && markerDeltas.length > 0) {
+        try {
+          ICompilationUnit workingCopy = getWorkingCopy(fInput);
+          if (workingCopy != null)
+            workingCopy.reconcile(true, null);
+        } catch (JavaModelException ex) {
+          handleCoreException(ex, ex.getMessage());
+        }
+      }
+    }
+  }
+  /**
+                * Creates <code>IBuffer</code>s based on documents.
+                */
+  protected class BufferFactory implements IBufferFactory {
+
+    private IDocument internalGetDocument(IFileEditorInput input) throws CoreException {
+      IDocument document = getDocument(input);
+      if (document != null)
+        return document;
+      return PHPDocumentProvider.this.createDocument(input);
+    }
+
+    public IBuffer createBuffer(IOpenable owner) {
+      if (owner instanceof ICompilationUnit) {
+
+        ICompilationUnit unit = (ICompilationUnit) owner;
+        ICompilationUnit original = (ICompilationUnit) unit.getOriginalElement();
+        IResource resource = original.getResource();
+        if (resource instanceof IFile) {
+          IFileEditorInput providerKey = new FileEditorInput((IFile) resource);
+
+          IDocument document = null;
+          IStatus status = null;
+
+          try {
+            document = internalGetDocument(providerKey);
+          } catch (CoreException x) {
+            status = x.getStatus();
+            document = new Document();
+            initializeDocument(document, providerKey);
+          }
+
+          DocumentAdapter adapter =
+            new DocumentAdapter(unit, document, new DefaultLineTracker(), PHPDocumentProvider.this, providerKey);
+          adapter.setStatus(status);
+          return adapter;
+        }
+
+      }
+      return DocumentAdapter.NULL;
+    }
+  };
+
+  protected static class GlobalAnnotationModelListener implements IAnnotationModelListener, IAnnotationModelListenerExtension {
+
+    private ListenerList fListenerList;
+
+    public GlobalAnnotationModelListener() {
+      fListenerList = new ListenerList();
+    }
+
+    public void addListener(IAnnotationModelListener listener) {
+      fListenerList.add(listener);
+    }
+
+    /**
+     * @see IAnnotationModelListenerExtension#modelChanged(AnnotationModelEvent)
+     */
+    public void modelChanged(AnnotationModelEvent event) {
+      Object[] listeners = fListenerList.getListeners();
+      for (int i = 0; i < listeners.length; i++) {
+        Object curr = listeners[i];
+        if (curr instanceof IAnnotationModelListenerExtension) {
+          ((IAnnotationModelListenerExtension) curr).modelChanged(event);
+        }
+      }
+    }
+
+    /**
+     * @see IAnnotationModelListener#modelChanged(IAnnotationModel)
+     */
+    public void modelChanged(IAnnotationModel model) {
+      Object[] listeners = fListenerList.getListeners();
+      for (int i = 0; i < listeners.length; i++) {
+        ((IAnnotationModelListener) listeners[i]).modelChanged(model);
+      }
+    }
+
+    public void removeListener(IAnnotationModelListener listener) {
+      fListenerList.remove(listener);
+    }
+  }
+
+  /**
+                * Annotation representating an <code>IProblem</code>.
+                */
+  static protected class ProblemAnnotation extends Annotation implements IJavaAnnotation {
+
+    //    private static Image fgQuickFixImage;
+    //    private static Image fgQuickFixErrorImage;
+    //    private static boolean fgQuickFixImagesInitialized = false;
+
+    private List fOverlaids;
+    private IProblem fProblem;
+    private Image fImage;
+    //    private boolean fQuickFixImagesInitialized = false;
+    private AnnotationType fType;
+
+    public ProblemAnnotation(IProblem problem) {
+
+      fProblem = problem;
+      setLayer(MarkerAnnotation.PROBLEM_LAYER + 1);
+
+      if (IProblem.Task == fProblem.getID())
+        fType = AnnotationType.TASK;
+      else if (fProblem.isWarning())
+        fType = AnnotationType.WARNING;
+      else
+        fType = AnnotationType.ERROR;
+    }
+
+    private void initializeImages() {
+      // http://bugs.eclipse.org/bugs/show_bug.cgi?id=18936
+      //      if (!fQuickFixImagesInitialized) {
+      //        if (indicateQuixFixableProblems() && JavaCorrectionProcessor.hasCorrections(fProblem.getID())) {
+      //          if (!fgQuickFixImagesInitialized) {
+      //            fgQuickFixImage = JavaPluginImages.get(JavaPluginImages.IMG_OBJS_FIXABLE_PROBLEM);
+      //            fgQuickFixErrorImage = JavaPluginImages.get(JavaPluginImages.IMG_OBJS_FIXABLE_ERROR);
+      //            fgQuickFixImagesInitialized = true;
+      //          }
+      //          if (fType == AnnotationType.ERROR)
+      //            fImage = fgQuickFixErrorImage;
+      //          else
+      //            fImage = fgQuickFixImage;
+      //        }
+      //        fQuickFixImagesInitialized = true;
+      //      }
+    }
+
+    private boolean indicateQuixFixableProblems() {
+      return PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_CORRECTION_INDICATION);
+    }
+
     /*
-     * @see AnnotationModel#fireModelChanged()
+     * @see Annotation#paint
      */
-    //                         protected void fireModelChanged() {
-    //                                 fireModelChanged(new CompilationUnitAnnotationModelEvent(this, getResource(), true));
-    //                         }
+    public void paint(GC gc, Canvas canvas, Rectangle r) {
+      initializeImages();
+      if (fImage != null)
+        drawImage(fImage, gc, canvas, r, SWT.CENTER, SWT.TOP);
+    }
 
     /*
-     * @see IProblemRequestor#isActive()
+     * @see IJavaAnnotation#getImage(Display)
      */
-    public boolean isActive() {
-      return fIsActive && (fCollectedProblems != null);
+    public Image getImage(Display display) {
+      initializeImages();
+      return fImage;
     }
 
     /*
-     * @see IProblemRequestorExtension#setProgressMonitor(IProgressMonitor)
+     * @see IJavaAnnotation#getMessage()
      */
-    public void setProgressMonitor(IProgressMonitor monitor) {
-      fProgressMonitor = monitor;
+    public String getMessage() {
+      return fProblem.getMessage();
     }
 
     /*
-     * @see IProblemRequestorExtension#setIsActive(boolean)
+     * @see IJavaAnnotation#isTemporary()
      */
-    public void setIsActive(boolean isActive) {
-      if (fIsActive != isActive) {
-        fIsActive = isActive;
-        if (fIsActive)
-          startCollectingProblems();
-        else
-          stopCollectingProblems();
-      }
+    public boolean isTemporary() {
+      return true;
     }
 
-    private Object getAnnotations(Position position) {
-      return fReverseMap.get(position);
+    /*
+     * @see IJavaAnnotation#getArguments()
+     */
+    public String[] getArguments() {
+      return isProblem() ? fProblem.getArguments() : null;
     }
 
     /*
-     * @see AnnotationModel#addAnnotation(Annotation, Position, boolean)
+     * @see IJavaAnnotation#getId()
      */
-    protected void addAnnotation(Annotation annotation, Position position, boolean fireModelChanged) {
-      super.addAnnotation(annotation, position, fireModelChanged);
+    public int getId() {
+      return isProblem() ? fProblem.getID() : -1;
+    }
 
-      Object cached = fReverseMap.get(position);
-      if (cached == null)
-        fReverseMap.put(position, annotation);
-      else if (cached instanceof List) {
-        List list = (List) cached;
-        list.add(annotation);
-      } else if (cached instanceof Annotation) {
-        List list = new ArrayList(2);
-        list.add(cached);
-        list.add(annotation);
-        fReverseMap.put(position, list);
-      }
+    /*
+     * @see IJavaAnnotation#isProblem()
+     */
+    public boolean isProblem() {
+      return fType == AnnotationType.WARNING || fType == AnnotationType.ERROR;
     }
 
     /*
-     * @see AnnotationModel#removeAllAnnotations(boolean)
+     * @see IJavaAnnotation#isRelevant()
      */
-    protected void removeAllAnnotations(boolean fireModelChanged) {
-      super.removeAllAnnotations(fireModelChanged);
-      fReverseMap.clear();
+    public boolean isRelevant() {
+      return true;
     }
 
     /*
-     * @see AnnotationModel#removeAnnotation(Annotation, boolean)
+     * @see IJavaAnnotation#hasOverlay()
      */
-    protected void removeAnnotation(Annotation annotation, boolean fireModelChanged) {
-      Position position = getPosition(annotation);
-      Object cached = fReverseMap.get(position);
-      if (cached instanceof List) {
-        List list = (List) cached;
-        list.remove(annotation);
-        if (list.size() == 1) {
-          fReverseMap.put(position, list.get(0));
-          list.clear();
-        }
-      } else if (cached instanceof Annotation) {
-        fReverseMap.remove(position);
+    public boolean hasOverlay() {
+      return false;
+    }
+
+    /*
+     * @see IJavaAnnotation#addOverlaid(IJavaAnnotation)
+     */
+    public void addOverlaid(IJavaAnnotation annotation) {
+      if (fOverlaids == null)
+        fOverlaids = new ArrayList(1);
+      fOverlaids.add(annotation);
+    }
+
+    /*
+     * @see IJavaAnnotation#removeOverlaid(IJavaAnnotation)
+     */
+    public void removeOverlaid(IJavaAnnotation annotation) {
+      if (fOverlaids != null) {
+        fOverlaids.remove(annotation);
+        if (fOverlaids.size() == 0)
+          fOverlaids = null;
       }
+    }
 
-      super.removeAnnotation(annotation, fireModelChanged);
+    /*
+     * @see IJavaAnnotation#getOverlaidIterator()
+     */
+    public Iterator getOverlaidIterator() {
+      if (fOverlaids != null)
+        return fOverlaids.iterator();
+      return null;
+    }
+
+    public AnnotationType getAnnotationType() {
+      return fType;
     }
   };
+  /**
+                * Internal structure for mapping positions to some value. 
+                * The reason for this specific structure is that positions can
+                * change over time. Thus a lookup is based on value and not
+                * on hash value.
+                */
+  protected static class ReverseMap {
 
-  protected static class GlobalAnnotationModelListener implements IAnnotationModelListener, IAnnotationModelListenerExtension {
+    static class Entry {
+      Position fPosition;
+      Object fValue;
+    }
+    private int fAnchor = 0;
 
-    private ListenerList fListenerList;
+    private List fList = new ArrayList(2);
 
-    public GlobalAnnotationModelListener() {
-      fListenerList = new ListenerList();
+    public ReverseMap() {
     }
 
-    /**
-     * @see IAnnotationModelListener#modelChanged(IAnnotationModel)
-     */
-    public void modelChanged(IAnnotationModel model) {
-      Object[] listeners = fListenerList.getListeners();
-      for (int i = 0; i < listeners.length; i++) {
-        ((IAnnotationModelListener) listeners[i]).modelChanged(model);
-      }
+    public void clear() {
+      fList.clear();
     }
 
-    /**
-     * @see IAnnotationModelListenerExtension#modelChanged(AnnotationModelEvent)
-     */
-    public void modelChanged(AnnotationModelEvent event) {
-      Object[] listeners = fListenerList.getListeners();
-      for (int i = 0; i < listeners.length; i++) {
-        Object curr = listeners[i];
-        if (curr instanceof IAnnotationModelListenerExtension) {
-          ((IAnnotationModelListenerExtension) curr).modelChanged(event);
+    public Object get(Position position) {
+
+      Entry entry;
+
+      // behind anchor
+      int length = fList.size();
+      for (int i = fAnchor; i < length; i++) {
+        entry = (Entry) fList.get(i);
+        if (entry.fPosition.equals(position)) {
+          fAnchor = i;
+          return entry.fValue;
         }
       }
+
+      // before anchor
+      for (int i = 0; i < fAnchor; i++) {
+        entry = (Entry) fList.get(i);
+        if (entry.fPosition.equals(position)) {
+          fAnchor = i;
+          return entry.fValue;
+        }
+      }
+
+      return null;
+    }
+
+    private int getIndex(Position position) {
+      Entry entry;
+      int length = fList.size();
+      for (int i = 0; i < length; i++) {
+        entry = (Entry) fList.get(i);
+        if (entry.fPosition.equals(position))
+          return i;
+      }
+      return -1;
     }
 
-    public void addListener(IAnnotationModelListener listener) {
-      fListenerList.add(listener);
+    public void put(Position position, Object value) {
+      int index = getIndex(position);
+      if (index == -1) {
+        Entry entry = new Entry();
+        entry.fPosition = position;
+        entry.fValue = value;
+        fList.add(entry);
+      } else {
+        Entry entry = (Entry) fList.get(index);
+        entry.fValue = value;
+      }
     }
 
-    public void removeListener(IAnnotationModelListener listener) {
-      fListenerList.remove(listener);
+    public void remove(Position position) {
+      int index = getIndex(position);
+      if (index > -1)
+        fList.remove(index);
+    }
+  }
+
+  /**
+                * Document that can also be used by a background reconciler.
+                */
+  protected static class PartiallySynchronizedDocument extends Document {
+
+    /*
+     * @see IDocumentExtension#startSequentialRewrite(boolean)
+     */
+    synchronized public void startSequentialRewrite(boolean normalized) {
+      super.startSequentialRewrite(normalized);
+    }
+
+    /*
+     * @see IDocumentExtension#stopSequentialRewrite()
+     */
+    synchronized public void stopSequentialRewrite() {
+      super.stopSequentialRewrite();
+    }
+
+    /*
+     * @see IDocument#get()
+     */
+    synchronized public String get() {
+      return super.get();
+    }
+
+    /*
+     * @see IDocument#get(int, int)
+     */
+    synchronized public String get(int offset, int length) throws BadLocationException {
+      return super.get(offset, length);
+    }
+
+    /*
+     * @see IDocument#getChar(int)
+     */
+    synchronized public char getChar(int offset) throws BadLocationException {
+      return super.getChar(offset);
+    }
+
+    /*
+     * @see IDocument#replace(int, int, String)
+     */
+    synchronized public void replace(int offset, int length, String text) throws BadLocationException {
+      super.replace(offset, length, text);
+    }
+
+    /*
+     * @see IDocument#set(String)
+     */
+    synchronized public void set(String text) {
+      super.set(text);
     }
   };
+  //
+  //  private static PHPPartitionScanner HTML_PARTITION_SCANNER = null;
+  //
+  //  private static PHPPartitionScanner PHP_PARTITION_SCANNER = null;
+  //  private static PHPPartitionScanner SMARTY_PARTITION_SCANNER = null;
+  //
+  //  // private final static String[] TYPES= new String[] { PHPPartitionScanner.PHP, PHPPartitionScanner.JAVA_DOC, PHPPartitionScanner.JAVA_MULTILINE_COMMENT };
+  //  private final static String[] TYPES =
+  //    new String[] {
+  //      IPHPPartitionScannerConstants.PHP,
+  //      IPHPPartitionScannerConstants.PHP_MULTILINE_COMMENT,
+  //      IPHPPartitionScannerConstants.HTML,
+  //      IPHPPartitionScannerConstants.HTML_MULTILINE_COMMENT,
+  //      IPHPPartitionScannerConstants.JAVASCRIPT,
+  //      IPHPPartitionScannerConstants.CSS,
+  //      IPHPPartitionScannerConstants.SMARTY,
+  //      IPHPPartitionScannerConstants.SMARTY_MULTILINE_COMMENT };
+  //  private static PHPPartitionScanner XML_PARTITION_SCANNER = null;
+
+  /* Preference key for temporary problems */
+  private final static String HANDLE_TEMPORARY_PROBLEMS = PreferenceConstants.EDITOR_EVALUTE_TEMPORARY_PROBLEMS;
+
+  /** The buffer factory */
+  private IBufferFactory fBufferFactory = new BufferFactory();
+  /** Indicates whether the save has been initialized by this provider */
+  private boolean fIsAboutToSave = false;
+  /** The save policy used by this provider */
+  private ISavePolicy fSavePolicy;
+  /** Internal property changed listener */
+  private IPropertyChangeListener fPropertyListener;
+
+  /** annotation model listener added to all created CU annotation models */
+  private GlobalAnnotationModelListener fGlobalAnnotationModelListener;
 
   public PHPDocumentProvider() {
-    super();
 
-    //         fGlobalAnnotationModelListener= new GlobalAnnotationModelListener();
+    fPropertyListener = new IPropertyChangeListener() {
+      public void propertyChange(PropertyChangeEvent event) {
+        if (HANDLE_TEMPORARY_PROBLEMS.equals(event.getProperty()))
+          enableHandlingTemporaryProblems();
+      }
+    };
+
+    fGlobalAnnotationModelListener = new GlobalAnnotationModelListener();
 
+    PHPeclipsePlugin.getDefault().getPreferenceStore().addPropertyChangeListener(fPropertyListener);
+
+  }
+
+  /**
+   * Sets the document provider's save policy.
+   */
+  public void setSavePolicy(ISavePolicy savePolicy) {
+    fSavePolicy = savePolicy;
   }
 
+  /**
+   * Creates a compilation unit from the given file.
+   * 
+   * @param file the file from which to create the compilation unit
+   */
+  protected ICompilationUnit createCompilationUnit(IFile file) {
+    Object element = PHPCore.create(file);
+    if (element instanceof ICompilationUnit)
+      return (ICompilationUnit) element;
+    return null;
+  }
+
+  /*
+        * @see AbstractDocumentProvider#createElementInfo(Object)
+        */
+  protected ElementInfo createElementInfo(Object element) throws CoreException {
+
+    if (!(element instanceof IFileEditorInput))
+      return super.createElementInfo(element);
+
+    IFileEditorInput input = (IFileEditorInput) element;
+    ICompilationUnit original = createCompilationUnit(input.getFile());
+    if (original != null) {
+
+      try {
+
+        try {
+          refreshFile(input.getFile());
+        } catch (CoreException x) {
+          handleCoreException(x, PHPEditorMessages.getString("PHPDocumentProvider.error.createElementInfo")); //$NON-NLS-1$
+        }
+
+        IAnnotationModel m = createCompilationUnitAnnotationModel(input);
+        IProblemRequestor r = m instanceof IProblemRequestor ? (IProblemRequestor) m : null;
+        ICompilationUnit c = (ICompilationUnit) original.getSharedWorkingCopy(getProgressMonitor(), fBufferFactory, r);
+
+        DocumentAdapter a = null;
+        try {
+          a = (DocumentAdapter) c.getBuffer();
+        } catch (ClassCastException x) {
+          IStatus status = new Status(IStatus.ERROR, PHPeclipsePlugin.PLUGIN_ID, PHPStatusConstants.TEMPLATE_IO_EXCEPTION, "Shared working copy has wrong buffer", x); //$NON-NLS-1$
+          throw new CoreException(status);
+        }
+
+        _FileSynchronizer f = new _FileSynchronizer(input);
+        f.install();
+
+        CompilationUnitInfo info = new CompilationUnitInfo(a.getDocument(), m, f, c);
+        info.setModificationStamp(computeModificationStamp(input.getFile()));
+        info.fStatus = a.getStatus();
+        info.fEncoding = getPersistedEncoding(input);
+
+        if (r instanceof IProblemRequestorExtension) {
+          IProblemRequestorExtension extension = (IProblemRequestorExtension) r;
+          extension.setIsActive(isHandlingTemporaryProblems());
+        }
+        m.addAnnotationModelListener(fGlobalAnnotationModelListener);
+
+        return info;
+
+      } catch (JavaModelException x) {
+        throw new CoreException(x.getStatus());
+      }
+    } else {
+      return super.createElementInfo(element);
+    }
+  }
+
+  /*
+   * @see AbstractDocumentProvider#disposeElementInfo(Object, ElementInfo)
+   */
+  protected void disposeElementInfo(Object element, ElementInfo info) {
+
+    if (info instanceof CompilationUnitInfo) {
+      CompilationUnitInfo cuInfo = (CompilationUnitInfo) info;
+      cuInfo.fCopy.destroy();
+      cuInfo.fModel.removeAnnotationModelListener(fGlobalAnnotationModelListener);
+    }
+
+    super.disposeElementInfo(element, info);
+  }
+
+  /*
+        * @see AbstractDocumentProvider#doSaveDocument(IProgressMonitor, Object, IDocument, boolean)
+        */
+  protected void doSaveDocument(IProgressMonitor monitor, Object element, IDocument document, boolean overwrite)
+    throws CoreException {
+
+    ElementInfo elementInfo = getElementInfo(element);
+    if (elementInfo instanceof CompilationUnitInfo) {
+      CompilationUnitInfo info = (CompilationUnitInfo) elementInfo;
+
+      // update structure, assumes lock on info.fCopy
+      info.fCopy.reconcile();
+
+      ICompilationUnit original = (ICompilationUnit) info.fCopy.getOriginalElement();
+      IResource resource = original.getResource();
+
+      if (resource == null) {
+        // underlying resource has been deleted, just recreate file, ignore the rest
+        super.doSaveDocument(monitor, element, document, overwrite);
+        return;
+      }
+
+      if (resource != null && !overwrite)
+        checkSynchronizationState(info.fModificationStamp, resource);
+
+      if (fSavePolicy != null)
+        fSavePolicy.preSave(info.fCopy);
+
+      // inform about the upcoming content change
+      fireElementStateChanging(element);
+      try {
+        fIsAboutToSave = true;
+        // commit working copy
+        info.fCopy.commit(overwrite, monitor);
+      } catch (CoreException x) {
+        // inform about the failure
+        fireElementStateChangeFailed(element);
+        throw x;
+      } catch (RuntimeException x) {
+        // inform about the failure
+        fireElementStateChangeFailed(element);
+        throw x;
+      } finally {
+        fIsAboutToSave = false;
+      }
+
+      // If here, the dirty state of the editor will change to "not dirty".
+      // Thus, the state changing flag will be reset.
+
+      AbstractMarkerAnnotationModel model = (AbstractMarkerAnnotationModel) info.fModel;
+      model.updateMarkers(info.fDocument);
+
+      if (resource != null)
+        info.setModificationStamp(computeModificationStamp(resource));
+
+      if (fSavePolicy != null) {
+        ICompilationUnit unit = fSavePolicy.postSave(original);
+        if (unit != null) {
+          IResource r = unit.getResource();
+          IMarker[] markers = r.findMarkers(IMarker.MARKER, true, IResource.DEPTH_ZERO);
+          if (markers != null && markers.length > 0) {
+            for (int i = 0; i < markers.length; i++)
+              model.updateMarker(markers[i], info.fDocument, null);
+          }
+        }
+      }
+
+    } else {
+      super.doSaveDocument(monitor, element, document, overwrite);
+    }
+  }
+
+  /**
+   * Replaces createAnnotionModel of the super class.
+   */
+  protected IAnnotationModel createCompilationUnitAnnotationModel(Object element) throws CoreException {
+               if ( !(element instanceof IFileEditorInput))
+                       throw new CoreException(PHPUIStatus.createError(
+                               IJavaModelStatusConstants.INVALID_RESOURCE_TYPE, "", null)); //$NON-NLS-1$
+               
+               IFileEditorInput input= (IFileEditorInput) element;
+               return new CompilationUnitAnnotationModel(input);
+  }
+
+  //  private IDocumentPartitioner createCSSPartitioner() {
+  //    return new DefaultPartitioner(getHTMLPartitionScanner(), TYPES);
+  //  }
+
   /* (non-Javadoc)
    * Method declared on AbstractDocumentProvider
    */
   protected IDocument createDocument(Object element) throws CoreException {
-    IDocument document = super.createDocument(element);
+    if (element instanceof IEditorInput) {
+      Document document = new PartiallySynchronizedDocument();
+      if (setDocumentContent(document, (IEditorInput) element, getEncoding(element))) {
+        initializeDocument(document, (IEditorInput) element);
+
+        //     
+        //    IDocument document = super.createDocument(element);
+        //    if (document != null) {
+        //        IDocumentPartitioner partitioner = null;
+        //        if (element instanceof FileEditorInput) {
+        //          IFile file = (IFile) ((FileEditorInput) element).getAdapter(IFile.class);
+        //          String filename = file.getLocation().toString();
+        //          String extension = filename.substring(filename.lastIndexOf("."), filename.length());
+        //          //   System.out.println(extension);
+        //          if (extension.equalsIgnoreCase(".html") || extension.equalsIgnoreCase(".htm")) {
+        //            // html
+        //            partitioner = createHTMLPartitioner();
+        //          } else if (extension.equalsIgnoreCase(".xml")) {
+        //            // xml
+        //            partitioner = createXMLPartitioner();
+        //          } else if (extension.equalsIgnoreCase(".js")) {
+        //            // javascript
+        //            partitioner = createJavaScriptPartitioner();
+        //          } else if (extension.equalsIgnoreCase(".css")) {
+        //            // cascading style sheets
+        //            partitioner = createCSSPartitioner();
+        //          } else if (extension.equalsIgnoreCase(".tpl")) {
+        //            // smarty ?
+        //            partitioner = createSmartyPartitioner();
+        //          } else if (extension.equalsIgnoreCase(".inc")) {
+        //            // php include files ?
+        //            partitioner = createIncludePartitioner();
+        //          }
+        //        }
+        //
+        //        if (partitioner == null) {
+        //          partitioner = createPHPPartitioner();
+        //        }
+        //        document.setDocumentPartitioner(partitioner);
+        //        partitioner.connect(document);
+      }
+      return document;
+    }
+    return null;
+  }
+
+  //  /**
+  //   * Return a partitioner for .html files.
+  //   */
+  //  private IDocumentPartitioner createHTMLPartitioner() {
+  //    return new DefaultPartitioner(getHTMLPartitionScanner(), TYPES);
+  //  }
+  //
+  //  private IDocumentPartitioner createIncludePartitioner() {
+  //    return new DefaultPartitioner(getPHPPartitionScanner(), TYPES);
+  //  }
+  //
+  //  private IDocumentPartitioner createJavaScriptPartitioner() {
+  //    return new DefaultPartitioner(getHTMLPartitionScanner(), TYPES);
+  //  }
+
+  /**
+   * Creates a line tracker working with the same line delimiters as the document
+   * of the given element. Assumes the element to be managed by this document provider.
+   * 
+   * @param element the element serving as blue print
+   * @return a line tracker based on the same line delimiters as the element's document
+   */
+  public ILineTracker createLineTracker(Object element) {
+    return new DefaultLineTracker();
+  }
+
+  //  /**
+  //   * Return a partitioner for .php files.
+  //   */
+  //  private IDocumentPartitioner createPHPPartitioner() {
+  //    return new DefaultPartitioner(getPHPPartitionScanner(), TYPES);
+  //  }
+  //
+  //  private IDocumentPartitioner createSmartyPartitioner() {
+  //    return new DefaultPartitioner(getSmartyPartitionScanner(), TYPES);
+  //  }
+  //
+  //  private IDocumentPartitioner createXMLPartitioner() {
+  //    return new DefaultPartitioner(getXMLPartitionScanner(), TYPES);
+  //  }
+  //
+  //  /**
+  //   * Return a scanner for creating html partitions.
+  //   */
+  //  private PHPPartitionScanner getHTMLPartitionScanner() {
+  //    if (HTML_PARTITION_SCANNER == null)
+  //      HTML_PARTITION_SCANNER = new PHPPartitionScanner(IPHPPartitionScannerConstants.HTML_FILE);
+  //    return HTML_PARTITION_SCANNER;
+  //  }
+  //  /**
+  //   * Return a scanner for creating php partitions.
+  //   */
+  //  private PHPPartitionScanner getPHPPartitionScanner() {
+  //    if (PHP_PARTITION_SCANNER == null)
+  //      PHP_PARTITION_SCANNER = new PHPPartitionScanner(IPHPPartitionScannerConstants.PHP_FILE);
+  //    return PHP_PARTITION_SCANNER;
+  //  }
+  //
+  //  /**
+  //   * Return a scanner for creating smarty partitions.
+  //   */
+  //  private PHPPartitionScanner getSmartyPartitionScanner() {
+  //    if (SMARTY_PARTITION_SCANNER == null)
+  //      SMARTY_PARTITION_SCANNER = new PHPPartitionScanner(IPHPPartitionScannerConstants.SMARTY_FILE);
+  //    return SMARTY_PARTITION_SCANNER;
+  //  }
+  //
+  //  /**
+  //   * Return a scanner for creating xml partitions.
+  //   */
+  //  private PHPPartitionScanner getXMLPartitionScanner() {
+  //    if (XML_PARTITION_SCANNER == null)
+  //      XML_PARTITION_SCANNER = new PHPPartitionScanner(IPHPPartitionScannerConstants.XML_FILE);
+  //    return XML_PARTITION_SCANNER;
+  //  }
+
+  protected void initializeDocument(IDocument document, IEditorInput editorInput) {
     if (document != null) {
-      //  int fileType = 0; // PHP 
+      JavaTextTools tools = PHPeclipsePlugin.getDefault().getJavaTextTools();
       IDocumentPartitioner partitioner = null;
-      if (element instanceof FileEditorInput) {
-        IFile file = (IFile) ((FileEditorInput) element).getAdapter(IFile.class);
+      if (editorInput != null && editorInput instanceof FileEditorInput) {
+        IFile file = (IFile) ((FileEditorInput) editorInput).getAdapter(IFile.class);
         String filename = file.getLocation().toString();
         String extension = filename.substring(filename.lastIndexOf("."), filename.length());
-        //   System.out.println(extension);
-        if (extension.equalsIgnoreCase(".html") || extension.equalsIgnoreCase(".htm")) {
-          // html
-          partitioner = createHTMLPartitioner();
-        } else if (extension.equalsIgnoreCase(".xml")) {
-          // xml
-          partitioner = createXMLPartitioner();
-        } else if (extension.equalsIgnoreCase(".js")) {
-          // javascript
-          partitioner = createJavaScriptPartitioner();
-        } else if (extension.equalsIgnoreCase(".css")) {
-          // cascading style sheets
-          partitioner = createCSSPartitioner();
-        } else if (extension.equalsIgnoreCase(".tpl")) {
-          // smarty ?
-          partitioner = createSmartyPartitioner();
-        } else if (extension.equalsIgnoreCase(".inc")) {
-          // php include files ?
-          partitioner = createIncludePartitioner();
-        }
-      }
-
-      if (partitioner == null) {
-        partitioner = createPHPPartitioner();
+        partitioner = tools.createDocumentPartitioner(extension);
+      } else {
+        partitioner = tools.createDocumentPartitioner(".php");
       }
       document.setDocumentPartitioner(partitioner);
       partitioner.connect(document);
     }
-    return document;
   }
 
+  /*
+   * @see AbstractDocumentProvider#resetDocument(Object)
+   */
+  public void resetDocument(Object element) throws CoreException {
+    if (element == null)
+      return;
+
+    ElementInfo elementInfo = getElementInfo(element);
+    if (elementInfo instanceof CompilationUnitInfo) {
+      CompilationUnitInfo info = (CompilationUnitInfo) elementInfo;
+
+      IDocument document;
+      IStatus status = null;
+
+      try {
+
+        ICompilationUnit original = (ICompilationUnit) info.fCopy.getOriginalElement();
+        IResource resource = original.getResource();
+        if (resource instanceof IFile) {
+
+          IFile file = (IFile) resource;
+
+          try {
+            refreshFile(file);
+          } catch (CoreException x) {
+            handleCoreException(x, PHPEditorMessages.getString("PHPDocumentProvider.error.resetDocument")); //$NON-NLS-1$
+          }
+
+          IFileEditorInput input = new FileEditorInput(file);
+          document = super.createDocument(input);
+
+        } else {
+          document = new Document();
+        }
+
+      } catch (CoreException x) {
+        document = new Document();
+        status = x.getStatus();
+      }
+
+      fireElementContentAboutToBeReplaced(element);
+
+      removeUnchangedElementListeners(element, info);
+      info.fDocument.set(document.get());
+      info.fCanBeSaved = false;
+      info.fStatus = status;
+      addUnchangedElementListeners(element, info);
+
+      fireElementContentReplaced(element);
+      fireElementDirtyStateChanged(element, false);
+
+    } else {
+      super.resetDocument(element);
+    }
+  }
   /**
-   * Return a partitioner for .php files.
+        * Saves the content of the given document to the given element.
+        * This is only performed when this provider initiated the save.
+        * 
+        * @param monitor the progress monitor
+        * @param element the element to which to save
+        * @param document the document to save
+        * @param overwrite <code>true</code> if the save should be enforced
+        */
+  public void saveDocumentContent(IProgressMonitor monitor, Object element, IDocument document, boolean overwrite)
+    throws CoreException {
+
+    if (!fIsAboutToSave)
+      return;
+
+    if (element instanceof IFileEditorInput) {
+      IFileEditorInput input = (IFileEditorInput) element;
+      try {
+        String encoding = getEncoding(element);
+        if (encoding == null)
+          encoding = ResourcesPlugin.getEncoding();
+        InputStream stream = new ByteArrayInputStream(document.get().getBytes(encoding));
+        IFile file = input.getFile();
+        file.setContents(stream, overwrite, true, monitor);
+      } catch (IOException x) {
+        IStatus s = new Status(IStatus.ERROR, PHPeclipsePlugin.PLUGIN_ID, IStatus.OK, x.getMessage(), x);
+        throw new CoreException(s);
+      }
+    }
+  }
+  /**
+   * Returns the underlying resource for the given element.
+   * 
+   * @param the element
+   * @return the underlying resource of the given element
    */
-  private IDocumentPartitioner createPHPPartitioner() {
-    return new DefaultPartitioner(getPHPPartitionScanner(), TYPES);
+  public IResource getUnderlyingResource(Object element) {
+    if (element instanceof IFileEditorInput) {
+      IFileEditorInput input = (IFileEditorInput) element;
+      return input.getFile();
+    }
+    return null;
   }
 
   /**
-   * Return a partitioner for .html files.
+   * Returns the working copy this document provider maintains for the given
+   * element.
+   * 
+   * @param element the given element
+   * @return the working copy for the given element
    */
-  private IDocumentPartitioner createHTMLPartitioner() {
-    return new DefaultPartitioner(getHTMLPartitionScanner(), TYPES);
-  }
+  ICompilationUnit getWorkingCopy(IEditorInput element) {
 
-  private IDocumentPartitioner createXMLPartitioner() {
-    return new DefaultPartitioner(getXMLPartitionScanner(), TYPES);
-  }
+    ElementInfo elementInfo = getElementInfo(element);
+    if (elementInfo instanceof CompilationUnitInfo) {
+      CompilationUnitInfo info = (CompilationUnitInfo) elementInfo;
+      return info.fCopy;
+    }
 
-  private IDocumentPartitioner createJavaScriptPartitioner() {
-    return new DefaultPartitioner(getHTMLPartitionScanner(), TYPES);
+    return null;
   }
 
-  private IDocumentPartitioner createCSSPartitioner() {
-    return new DefaultPartitioner(getHTMLPartitionScanner(), TYPES);
+  /**
+   * Gets the BufferFactory.
+   */
+  public IBufferFactory getBufferFactory() {
+    return fBufferFactory;
   }
 
-  private IDocumentPartitioner createSmartyPartitioner() {
-    return new DefaultPartitioner(getSmartyPartitionScanner(), TYPES);
-  }
+  /**
+   * Shuts down this document provider.
+   */
+  public void shutdown() {
 
-  private IDocumentPartitioner createIncludePartitioner() {
-    return new DefaultPartitioner(getPHPPartitionScanner(), TYPES);
+    PHPeclipsePlugin.getDefault().getPreferenceStore().removePropertyChangeListener(fPropertyListener);
+
+    Iterator e = getConnectedElements();
+    while (e.hasNext())
+      disconnect(e.next());
   }
+
   /**
-   * Return a scanner for creating php partitions.
+   * Returns the preference whether handling temporary problems is enabled.
    */
-  private PHPPartitionScanner getPHPPartitionScanner() {
-    if (PHP_PARTITION_SCANNER == null)
-      PHP_PARTITION_SCANNER = new PHPPartitionScanner(IPHPPartitionScannerConstants.PHP_FILE);
-    return PHP_PARTITION_SCANNER;
+  protected boolean isHandlingTemporaryProblems() {
+    IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
+    return store.getBoolean(HANDLE_TEMPORARY_PROBLEMS);
   }
 
   /**
-   * Return a scanner for creating html partitions.
+   * Switches the state of problem acceptance according to the value in the preference store.
    */
-  private PHPPartitionScanner getHTMLPartitionScanner() {
-    if (HTML_PARTITION_SCANNER == null)
-      HTML_PARTITION_SCANNER = new PHPPartitionScanner(IPHPPartitionScannerConstants.HTML_FILE);
-    return HTML_PARTITION_SCANNER;
+  protected void enableHandlingTemporaryProblems() {
+    boolean enable = isHandlingTemporaryProblems();
+    for (Iterator iter = getConnectedElements(); iter.hasNext();) {
+      ElementInfo element = getElementInfo(iter.next());
+      if (element instanceof CompilationUnitInfo) {
+        CompilationUnitInfo info = (CompilationUnitInfo) element;
+        if (info.fModel instanceof IProblemRequestorExtension) {
+          IProblemRequestorExtension extension = (IProblemRequestorExtension) info.fModel;
+          extension.setIsActive(enable);
+        }
+      }
+    }
   }
 
   /**
-   * Return a scanner for creating xml partitions.
+   * Adds a listener that reports changes from all compilation unit annotation models.
    */
-  private PHPPartitionScanner getXMLPartitionScanner() {
-    if (XML_PARTITION_SCANNER == null)
-      XML_PARTITION_SCANNER = new PHPPartitionScanner(IPHPPartitionScannerConstants.XML_FILE);
-    return XML_PARTITION_SCANNER;
+  public void addGlobalAnnotationModelListener(IAnnotationModelListener listener) {
+    fGlobalAnnotationModelListener.addListener(listener);
   }
 
   /**
-   * Return a scanner for creating smarty partitions.
+   * Removes the listener.
    */
-  private PHPPartitionScanner getSmartyPartitionScanner() {
-    if (SMARTY_PARTITION_SCANNER == null)
-      SMARTY_PARTITION_SCANNER = new PHPPartitionScanner(IPHPPartitionScannerConstants.SMARTY_FILE);
-    return SMARTY_PARTITION_SCANNER;
+  public void removeGlobalAnnotationModelListener(IAnnotationModelListener listener) {
+    fGlobalAnnotationModelListener.removeListener(listener);
   }
 
   /**
-   * Creates a line tracker working with the same line delimiters as the document
-   * of the given element. Assumes the element to be managed by this document provider.
+   * Returns whether the given element is connected to this document provider.
    * 
-   * @param element the element serving as blue print
-   * @return a line tracker based on the same line delimiters as the element's document
+   * @param element the element
+   * @return <code>true</code> if the element is connected, <code>false</code> otherwise
    */
-  public ILineTracker createLineTracker(Object element) {
-    return new DefaultLineTracker();
+  boolean isConnected(Object element) {
+    return getElementInfo(element) != null;
   }
 }