Bug 886811
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpeclipse / phpeditor / PHPDocumentProvider.java
1 package net.sourceforge.phpeclipse.phpeditor;
2
3 /**********************************************************************
4 Copyright (c) 2000, 2002 IBM Corp. and others.
5 All rights reserved. This program and the accompanying materials
6 are made available under the terms of the Common Public License v1.0
7 which accompanies this distribution, and is available at
8 http://www.eclipse.org/legal/cpl-v10.html
9
10 Contributors:
11     IBM Corporation - Initial implementation
12     Klaus Hartlage - www.eclipseproject.de
13 **********************************************************************/
14
15 import java.io.ByteArrayInputStream;
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.util.ArrayList;
19 import java.util.Iterator;
20 import java.util.List;
21
22 import net.sourceforge.phpdt.core.IBuffer;
23 import net.sourceforge.phpdt.core.IBufferFactory;
24 import net.sourceforge.phpdt.core.ICompilationUnit;
25 import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
26 import net.sourceforge.phpdt.core.IOpenable;
27 import net.sourceforge.phpdt.core.IProblemRequestor;
28 import net.sourceforge.phpdt.core.JavaModelException;
29 import net.sourceforge.phpdt.core.compiler.IProblem;
30 import net.sourceforge.phpdt.internal.ui.PHPStatusConstants;
31 import net.sourceforge.phpdt.internal.ui.PHPUIStatus;
32 import net.sourceforge.phpdt.internal.ui.text.java.IProblemRequestorExtension;
33 import net.sourceforge.phpdt.ui.PreferenceConstants;
34 import net.sourceforge.phpdt.ui.text.JavaTextTools;
35 import net.sourceforge.phpeclipse.PHPCore;
36 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
37
38 import org.eclipse.core.resources.IFile;
39 import org.eclipse.core.resources.IMarker;
40 import org.eclipse.core.resources.IMarkerDelta;
41 import org.eclipse.core.resources.IResource;
42 import org.eclipse.core.resources.ResourcesPlugin;
43 import org.eclipse.core.runtime.CoreException;
44 import org.eclipse.core.runtime.IProgressMonitor;
45 import org.eclipse.core.runtime.IStatus;
46 import org.eclipse.core.runtime.Status;
47 import org.eclipse.jface.preference.IPreferenceStore;
48 import org.eclipse.jface.text.BadLocationException;
49 import org.eclipse.jface.text.DefaultLineTracker;
50 import org.eclipse.jface.text.Document;
51 import org.eclipse.jface.text.IDocument;
52 import org.eclipse.jface.text.IDocumentPartitioner;
53 import org.eclipse.jface.text.ILineTracker;
54 import org.eclipse.jface.text.Position;
55 import org.eclipse.jface.text.source.Annotation;
56 import org.eclipse.jface.text.source.AnnotationModelEvent;
57 import org.eclipse.jface.text.source.IAnnotationModel;
58 import org.eclipse.jface.text.source.IAnnotationModelListener;
59 import org.eclipse.jface.text.source.IAnnotationModelListenerExtension;
60 import org.eclipse.jface.util.IPropertyChangeListener;
61 import org.eclipse.jface.util.ListenerList;
62 import org.eclipse.jface.util.PropertyChangeEvent;
63 import org.eclipse.swt.SWT;
64 import org.eclipse.swt.graphics.GC;
65 import org.eclipse.swt.graphics.Image;
66 import org.eclipse.swt.graphics.Rectangle;
67 import org.eclipse.swt.widgets.Canvas;
68 import org.eclipse.swt.widgets.Display;
69 import org.eclipse.ui.IEditorInput;
70 import org.eclipse.ui.IFileEditorInput;
71 import org.eclipse.ui.editors.text.FileDocumentProvider;
72 import org.eclipse.ui.part.FileEditorInput;
73 import org.eclipse.ui.texteditor.AbstractMarkerAnnotationModel;
74 import org.eclipse.ui.texteditor.DefaultAnnotation;
75 import org.eclipse.ui.texteditor.IAnnotationExtension;
76 import org.eclipse.ui.texteditor.MarkerAnnotation;
77 import org.eclipse.ui.texteditor.ResourceMarkerAnnotationModel;
78
79 /** 
80  * The PHPDocumentProvider provides the IDocuments used by java editors.
81  */
82
83 public class PHPDocumentProvider extends FileDocumentProvider {
84   /**
85                          * Here for visibility issues only.
86                          */
87   protected class _FileSynchronizer extends FileSynchronizer {
88     public _FileSynchronizer(IFileEditorInput fileEditorInput) {
89       super(fileEditorInput);
90     }
91   };
92   /**
93                  * Bundle of all required informations to allow working copy management. 
94                  */
95   protected class CompilationUnitInfo extends FileInfo {
96
97     ICompilationUnit fCopy;
98
99     public CompilationUnitInfo(
100       IDocument document,
101       IAnnotationModel model,
102       _FileSynchronizer fileSynchronizer,
103       ICompilationUnit copy) {
104       super(document, model, fileSynchronizer);
105       fCopy = copy;
106     }
107
108     public void setModificationStamp(long timeStamp) {
109       fModificationStamp = timeStamp;
110     }
111   };
112   /**
113                  * Annotation model dealing with java marker annotations and temporary problems.
114                  * Also acts as problem requestor for its compilation unit. Initialiy inactive. Must explicitly be
115                  * activated.
116                  */
117   protected class CompilationUnitAnnotationModel
118     extends ResourceMarkerAnnotationModel
119     implements IProblemRequestor, IProblemRequestorExtension {
120     private List fCollectedProblems;
121     private List fCurrentlyOverlaid = new ArrayList();
122     private List fGeneratedAnnotations;
123
124     private IFileEditorInput fInput;
125     private boolean fIsActive = false;
126     private List fPreviouslyOverlaid = null;
127     private IProgressMonitor fProgressMonitor;
128
129     private ReverseMap fReverseMap = new ReverseMap();
130
131     public CompilationUnitAnnotationModel(IFileEditorInput input) {
132       super(input.getFile());
133       fInput = input;
134     }
135
136     /*
137      * @see IProblemRequestor#acceptProblem(IProblem)
138      */
139     public void acceptProblem(IProblem problem) {
140       if (isActive())
141         fCollectedProblems.add(problem);
142     }
143
144     /*
145      * @see AnnotationModel#addAnnotation(Annotation, Position, boolean)
146      */
147     protected void addAnnotation(Annotation annotation, Position position, boolean fireModelChanged) throws BadLocationException {
148       super.addAnnotation(annotation, position, fireModelChanged);
149
150       Object cached = fReverseMap.get(position);
151       if (cached == null)
152         fReverseMap.put(position, annotation);
153       else if (cached instanceof List) {
154         List list = (List) cached;
155         list.add(annotation);
156       } else if (cached instanceof Annotation) {
157         List list = new ArrayList(2);
158         list.add(cached);
159         list.add(annotation);
160         fReverseMap.put(position, list);
161       }
162     }
163
164     /*
165      * @see IProblemRequestor#beginReporting()
166      */
167     public void beginReporting() {
168       ICompilationUnit unit = getWorkingCopy(fInput);
169       if (unit != null) // && unit.getJavaProject().isOnClasspath(unit))
170         fCollectedProblems = new ArrayList();
171       else
172         fCollectedProblems = null;
173     }
174
175     protected MarkerAnnotation createMarkerAnnotation(IMarker marker) {
176       return new JavaMarkerAnnotation(marker);
177     }
178
179     protected Position createPositionFromProblem(IProblem problem) {
180       int start = problem.getSourceStart();
181       if (start < 0)
182         return null;
183
184       int length = problem.getSourceEnd() - problem.getSourceStart() + 1;
185       if (length < 0)
186         return null;
187
188       return new Position(start, length);
189     }
190     /*
191      * @see IProblemRequestor#endReporting()
192      */
193     public void endReporting() {
194       if (!isActive())
195         return;
196       
197       if (fProgressMonitor != null && fProgressMonitor.isCanceled())
198         return;
199       
200       
201       boolean isCanceled= false;
202       boolean temporaryProblemsChanged= false;
203       
204       synchronized (fAnnotations) {
205         
206         fPreviouslyOverlaid= fCurrentlyOverlaid;
207         fCurrentlyOverlaid= new ArrayList();
208
209         if (fGeneratedAnnotations.size() > 0) {
210           temporaryProblemsChanged= true;       
211           removeAnnotations(fGeneratedAnnotations, false, true);
212           fGeneratedAnnotations.clear();
213         }
214         
215         if (fCollectedProblems != null && fCollectedProblems.size() > 0) {
216           
217           ICompilationUnit cu= getWorkingCopy(fInput);
218           Iterator e= fCollectedProblems.iterator();
219           while (e.hasNext()) {
220             
221             IProblem problem= (IProblem) e.next();
222             
223             if (fProgressMonitor != null && fProgressMonitor.isCanceled()) {
224               isCanceled= true;
225               break;
226             }
227             
228             Position position= createPositionFromProblem(problem);
229             if (position != null) {
230               try {
231                 ProblemAnnotation annotation= new ProblemAnnotation(problem, cu);
232                 addAnnotation(annotation, position, false);
233                 overlayMarkers(position, annotation);                                                           
234                 fGeneratedAnnotations.add(annotation);
235                 
236                 temporaryProblemsChanged= true;
237               } catch (BadLocationException x) {
238                 // ignore invalid position
239               }
240             }
241           }
242           
243           fCollectedProblems.clear();
244         }
245         
246         removeMarkerOverlays(isCanceled);
247         fPreviouslyOverlaid.clear();
248         fPreviouslyOverlaid= null;
249       }
250       
251       if (temporaryProblemsChanged)
252         fireModelChanged();
253     }
254     /*
255      * @see IProblemRequestor#endReporting()
256      */
257 //    public void endReporting() {
258 //      if (!isActive())
259 //        return;
260 //
261 //      if (fProgressMonitor != null && fProgressMonitor.isCanceled())
262 //        return;
263 //
264 //      boolean isCanceled = false;
265 //      boolean temporaryProblemsChanged = false;
266 //      fPreviouslyOverlaid = fCurrentlyOverlaid;
267 //      fCurrentlyOverlaid = new ArrayList();
268 //
269 //      synchronized (fAnnotations) {
270 //
271 //        if (fGeneratedAnnotations.size() > 0) {
272 //          temporaryProblemsChanged = true;
273 //          removeAnnotations(fGeneratedAnnotations, false, true);
274 //          fGeneratedAnnotations.clear();
275 //        }
276 //
277 //        if (fCollectedProblems != null && fCollectedProblems.size() > 0) {
278 //
279 //          Iterator e = fCollectedProblems.iterator();
280 //          while (e.hasNext()) {
281 //
282 //            IProblem problem = (IProblem) e.next();
283 //
284 //            if (fProgressMonitor != null && fProgressMonitor.isCanceled()) {
285 //              isCanceled = true;
286 //              break;
287 //            }
288 //
289 //            Position position = createPositionFromProblem(problem);
290 //            if (position != null) {
291 //
292 //              ProblemAnnotation annotation = new ProblemAnnotation(problem);
293 //              overlayMarkers(position, annotation);
294 //              fGeneratedAnnotations.add(annotation);
295 //              addAnnotation(annotation, position, false);
296 //
297 //              temporaryProblemsChanged = true;
298 //            }
299 //          }
300 //
301 //          fCollectedProblems.clear();
302 //        }
303 //
304 //        removeMarkerOverlays(isCanceled);
305 //        fPreviouslyOverlaid.clear();
306 //        fPreviouslyOverlaid = null;
307 //      }
308 //
309 //      if (temporaryProblemsChanged)
310 //        fireModelChanged(new CompilationUnitAnnotationModelEvent(this, getResource(), false));
311 //    }
312
313     private Object getAnnotations(Position position) {
314       return fReverseMap.get(position);
315     }
316
317     /*
318      * @see AnnotationModel#fireModelChanged()
319      */
320     protected void fireModelChanged() {
321       fireModelChanged(new CompilationUnitAnnotationModelEvent(this, getResource(), true));
322     }
323
324     /*
325      * @see IProblemRequestor#isActive()
326      */
327     public boolean isActive() {
328       return fIsActive && (fCollectedProblems != null);
329     }
330
331     /*
332      * @see AnnotationModel#removeAllAnnotations(boolean)
333      */
334     protected void removeAllAnnotations(boolean fireModelChanged) {
335       super.removeAllAnnotations(fireModelChanged);
336       fReverseMap.clear();
337     }
338
339     /*
340      * @see AnnotationModel#removeAnnotation(Annotation, boolean)
341      */
342     protected void removeAnnotation(Annotation annotation, boolean fireModelChanged) {
343       Position position = getPosition(annotation);
344       Object cached = fReverseMap.get(position);
345       if (cached instanceof List) {
346         List list = (List) cached;
347         list.remove(annotation);
348         if (list.size() == 1) {
349           fReverseMap.put(position, list.get(0));
350           list.clear();
351         }
352       } else if (cached instanceof Annotation) {
353         fReverseMap.remove(position);
354       }
355
356       super.removeAnnotation(annotation, fireModelChanged);
357     }
358
359     private void removeMarkerOverlays(boolean isCanceled) {
360       if (isCanceled) {
361         fCurrentlyOverlaid.addAll(fPreviouslyOverlaid);
362       } else if (fPreviouslyOverlaid != null) {
363         Iterator e = fPreviouslyOverlaid.iterator();
364         while (e.hasNext()) {
365           JavaMarkerAnnotation annotation = (JavaMarkerAnnotation) e.next();
366           annotation.setOverlay(null);
367         }
368       }
369     }
370
371     /*
372      * @see IProblemRequestorExtension#setIsActive(boolean)
373      */
374     public void setIsActive(boolean isActive) {
375       if (fIsActive != isActive) {
376         fIsActive = isActive;
377         if (fIsActive)
378           startCollectingProblems();
379         else
380           stopCollectingProblems();
381       }
382     }
383
384     /*
385      * @see IProblemRequestorExtension#setProgressMonitor(IProgressMonitor)
386      */
387     public void setProgressMonitor(IProgressMonitor monitor) {
388       fProgressMonitor = monitor;
389     }
390
391     /**
392      * Overlays value with problem annotation.
393      * @param problemAnnotation
394      */
395     private void setOverlay(Object value, ProblemAnnotation problemAnnotation) {
396       if (value instanceof JavaMarkerAnnotation) {
397         JavaMarkerAnnotation annotation = (JavaMarkerAnnotation) value;
398         if (annotation.isProblem()) {
399           annotation.setOverlay(problemAnnotation);
400           fPreviouslyOverlaid.remove(annotation);
401           fCurrentlyOverlaid.add(annotation);
402         }
403       }
404     }
405
406     private void overlayMarkers(Position position, ProblemAnnotation problemAnnotation) {
407       Object value = getAnnotations(position);
408       if (value instanceof List) {
409         List list = (List) value;
410         for (Iterator e = list.iterator(); e.hasNext();)
411           setOverlay(e.next(), problemAnnotation);
412       } else {
413         setOverlay(value, problemAnnotation);
414       }
415     }
416
417     /**
418      * Tells this annotation model to collect temporary problems from now on.
419      */
420     private void startCollectingProblems() {
421       fCollectedProblems = new ArrayList();
422       fGeneratedAnnotations = new ArrayList();
423     }
424
425     /**
426      * Tells this annotation model to no longer collect temporary problems.
427      */
428     private void stopCollectingProblems() {
429       if (fGeneratedAnnotations != null) {
430         removeAnnotations(fGeneratedAnnotations, true, true);
431         fGeneratedAnnotations.clear();
432       }
433       fCollectedProblems = null;
434       fGeneratedAnnotations = null;
435     }
436
437     protected void update(IMarkerDelta[] markerDeltas) {
438
439       super.update(markerDeltas);
440
441       if (markerDeltas != null && markerDeltas.length > 0) {
442         try {
443           ICompilationUnit workingCopy = getWorkingCopy(fInput);
444           if (workingCopy != null)
445             workingCopy.reconcile(true, null);
446         } catch (JavaModelException ex) {
447           handleCoreException(ex, ex.getMessage());
448         }
449       }
450     }
451   }
452   /**
453                  * Creates <code>IBuffer</code>s based on documents.
454                  */
455   protected class BufferFactory implements IBufferFactory {
456
457     private IDocument internalGetDocument(IFileEditorInput input) throws CoreException {
458       IDocument document = getDocument(input);
459       if (document != null)
460         return document;
461       return PHPDocumentProvider.this.createDocument(input);
462     }
463
464     public IBuffer createBuffer(IOpenable owner) {
465       if (owner instanceof ICompilationUnit) {
466
467         ICompilationUnit unit = (ICompilationUnit) owner;
468         ICompilationUnit original = (ICompilationUnit) unit.getOriginalElement();
469         IResource resource = original.getResource();
470         if (resource instanceof IFile) {
471           IFileEditorInput providerKey = new FileEditorInput((IFile) resource);
472
473           IDocument document = null;
474           IStatus status = null;
475
476           try {
477             document = internalGetDocument(providerKey);
478           } catch (CoreException x) {
479             status = x.getStatus();
480             document = new Document();
481             initializeDocument(document, providerKey);
482           }
483
484           DocumentAdapter adapter =
485             new DocumentAdapter(unit, document, new DefaultLineTracker(), PHPDocumentProvider.this, providerKey);
486           adapter.setStatus(status);
487           return adapter;
488         }
489
490       }
491       return DocumentAdapter.NULL;
492     }
493   };
494
495   protected static class GlobalAnnotationModelListener implements IAnnotationModelListener, IAnnotationModelListenerExtension {
496
497     private ListenerList fListenerList;
498
499     public GlobalAnnotationModelListener() {
500       fListenerList = new ListenerList();
501     }
502
503     public void addListener(IAnnotationModelListener listener) {
504       fListenerList.add(listener);
505     }
506
507     /**
508      * @see IAnnotationModelListenerExtension#modelChanged(AnnotationModelEvent)
509      */
510     public void modelChanged(AnnotationModelEvent event) {
511       Object[] listeners = fListenerList.getListeners();
512       for (int i = 0; i < listeners.length; i++) {
513         Object curr = listeners[i];
514         if (curr instanceof IAnnotationModelListenerExtension) {
515           ((IAnnotationModelListenerExtension) curr).modelChanged(event);
516         }
517       }
518     }
519
520     /**
521      * @see IAnnotationModelListener#modelChanged(IAnnotationModel)
522      */
523     public void modelChanged(IAnnotationModel model) {
524       Object[] listeners = fListenerList.getListeners();
525       for (int i = 0; i < listeners.length; i++) {
526         ((IAnnotationModelListener) listeners[i]).modelChanged(model);
527       }
528     }
529
530     public void removeListener(IAnnotationModelListener listener) {
531       fListenerList.remove(listener);
532     }
533   }
534
535   /**
536                  * Annotation representating an <code>IProblem</code>.
537                  */
538   static protected class ProblemAnnotation extends Annotation implements IJavaAnnotation, IAnnotationExtension{
539
540     private static final String TASK_ANNOTATION_TYPE= "org.eclipse.ui.workbench.texteditor.task"; //$NON-NLS-1$
541     private static final String ERROR_ANNOTATION_TYPE= "org.eclipse.ui.workbench.texteditor.error"; //$NON-NLS-1$
542     private static final String WARNING_ANNOTATION_TYPE= "org.eclipse.ui.workbench.texteditor.warning"; //$NON-NLS-1$
543     private static final String INFO_ANNOTATION_TYPE= "org.eclipse.ui.workbench.texteditor.info"; //$NON-NLS-1$
544     
545     //    private static Image fgQuickFixImage;
546     //    private static Image fgQuickFixErrorImage;
547     //    private static boolean fgQuickFixImagesInitialized = false;
548
549     private ICompilationUnit fCompilationUnit;
550     private List fOverlaids;
551     private IProblem fProblem;
552     private Image fImage;
553     //    private boolean fQuickFixImagesInitialized = false;
554 //    private AnnotationType fType;
555     private String fType;
556
557     public ProblemAnnotation(IProblem problem, ICompilationUnit cu) {
558       fProblem= problem;
559       fCompilationUnit= cu;
560       
561       if (IProblem.Task == fProblem.getID()) {
562         fType= TASK_ANNOTATION_TYPE;
563         setLayer(DefaultAnnotation.TASK_LAYER + 1);
564       } else if (fProblem.isWarning()) {
565         fType= WARNING_ANNOTATION_TYPE;
566         setLayer(DefaultAnnotation.WARNING_LAYER + 1);
567       } else if (fProblem.isError()) {
568         fType= ERROR_ANNOTATION_TYPE;
569         setLayer(DefaultAnnotation.ERROR_LAYER + 1);
570       } else {
571         fType= INFO_ANNOTATION_TYPE;
572         setLayer(DefaultAnnotation.INFO_LAYER + 1);
573       }
574     }
575 //    public ProblemAnnotation(IProblem problem) {
576 //
577 //      fProblem = problem;
578 //      setLayer(MarkerAnnotation.PROBLEM_LAYER + 1);
579 //
580 //      if (IProblem.Task == fProblem.getID())
581 //        fType = AnnotationType.TASK;
582 //      else if (fProblem.isWarning())
583 //        fType = AnnotationType.WARNING;
584 //      else
585 //        fType = AnnotationType.ERROR;
586 //    }
587
588     private void initializeImages() {
589       // http://bugs.eclipse.org/bugs/show_bug.cgi?id=18936
590       //      if (!fQuickFixImagesInitialized) {
591       //        if (indicateQuixFixableProblems() && JavaCorrectionProcessor.hasCorrections(fProblem.getID())) {
592       //          if (!fgQuickFixImagesInitialized) {
593       //            fgQuickFixImage = JavaPluginImages.get(JavaPluginImages.IMG_OBJS_FIXABLE_PROBLEM);
594       //            fgQuickFixErrorImage = JavaPluginImages.get(JavaPluginImages.IMG_OBJS_FIXABLE_ERROR);
595       //            fgQuickFixImagesInitialized = true;
596       //          }
597       //          if (fType == AnnotationType.ERROR)
598       //            fImage = fgQuickFixErrorImage;
599       //          else
600       //            fImage = fgQuickFixImage;
601       //        }
602       //        fQuickFixImagesInitialized = true;
603       //      }
604     }
605
606     private boolean indicateQuixFixableProblems() {
607       return PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_CORRECTION_INDICATION);
608     }
609
610     /*
611      * @see Annotation#paint
612      */
613     public void paint(GC gc, Canvas canvas, Rectangle r) {
614       initializeImages();
615       if (fImage != null)
616         drawImage(fImage, gc, canvas, r, SWT.CENTER, SWT.TOP);
617     }
618
619     /*
620      * @see IJavaAnnotation#getImage(Display)
621      */
622     public Image getImage(Display display) {
623       initializeImages();
624       return fImage;
625     }
626
627     /*
628      * @see IJavaAnnotation#getMessage()
629      */
630     public String getMessage() {
631       return fProblem.getMessage();
632     }
633
634     /*
635      * @see IJavaAnnotation#isTemporary()
636      */
637     public boolean isTemporary() {
638       return true;
639     }
640
641     /*
642      * @see IJavaAnnotation#getArguments()
643      */
644     public String[] getArguments() {
645       return isProblem() ? fProblem.getArguments() : null;
646     }
647
648     /*
649      * @see IJavaAnnotation#getId()
650      */
651     public int getId() {
652       return isProblem() ? fProblem.getID() : -1;
653     }
654
655 //    /*
656 //     * @see IJavaAnnotation#isProblem()
657 //     */
658 //    public boolean isProblem() {
659 //      return fType == AnnotationType.WARNING || fType == AnnotationType.ERROR;
660 //    }
661     /*
662      * @see IJavaAnnotation#isProblem()
663      */
664     public boolean isProblem() {
665       return  WARNING_ANNOTATION_TYPE.equals(fType)  || ERROR_ANNOTATION_TYPE.equals(fType);
666     }
667
668     /*
669      * @see IJavaAnnotation#isRelevant()
670      */
671     public boolean isRelevant() {
672       return true;
673     }
674
675     /*
676      * @see IJavaAnnotation#hasOverlay()
677      */
678     public boolean hasOverlay() {
679       return false;
680     }
681
682     /*
683      * @see IJavaAnnotation#addOverlaid(IJavaAnnotation)
684      */
685     public void addOverlaid(IJavaAnnotation annotation) {
686       if (fOverlaids == null)
687         fOverlaids = new ArrayList(1);
688       fOverlaids.add(annotation);
689     }
690
691     /*
692      * @see IJavaAnnotation#removeOverlaid(IJavaAnnotation)
693      */
694     public void removeOverlaid(IJavaAnnotation annotation) {
695       if (fOverlaids != null) {
696         fOverlaids.remove(annotation);
697         if (fOverlaids.size() == 0)
698           fOverlaids = null;
699       }
700     }
701
702     /*
703      * @see IJavaAnnotation#getOverlaidIterator()
704      */
705     public Iterator getOverlaidIterator() {
706       if (fOverlaids != null)
707         return fOverlaids.iterator();
708       return null;
709     }
710
711     
712     public AnnotationType getAnnotationType() {
713       if (ERROR_ANNOTATION_TYPE.equals(fType)) {
714         return AnnotationType.ERROR;
715       }
716       if (WARNING_ANNOTATION_TYPE.equals(fType)) {
717         return AnnotationType.WARNING;
718       }
719       if (TASK_ANNOTATION_TYPE.equals(fType)) {
720         return AnnotationType.TASK;
721       }
722 //      if (INFO_ANNOTATION_TYPE.equals(fType)) {
723 //        return AnnotationType.INFO;
724 //      }
725       return AnnotationType.UNKNOWN;
726     }
727     
728     /*
729      * @see IAnnotationExtension#getMarkerType()
730      */
731     public String getMarkerType() {
732       if (isProblem() || INFO_ANNOTATION_TYPE.equals(fType))
733         return IMarker.PROBLEM;
734       else
735         return IMarker.TASK;
736     }
737     /*
738      * @see IAnnotationExtension#getSeverity()
739      */
740     public int getSeverity() {
741       if (ERROR_ANNOTATION_TYPE.equals(fType))
742         return IMarker.SEVERITY_ERROR;
743       if (WARNING_ANNOTATION_TYPE.equals(fType))
744         return IMarker.SEVERITY_WARNING;
745       return IMarker.SEVERITY_INFO;
746     }
747
748     /*
749      * @see org.eclipse.jdt.internal.ui.javaeditor.IJavaAnnotation#getCompilationUnit()
750      */
751     public ICompilationUnit getCompilationUnit() {
752       return fCompilationUnit;
753     }
754   };
755   /**
756                  * Internal structure for mapping positions to some value. 
757                  * The reason for this specific structure is that positions can
758                  * change over time. Thus a lookup is based on value and not
759                  * on hash value.
760                  */
761   protected static class ReverseMap {
762
763     static class Entry {
764       Position fPosition;
765       Object fValue;
766     }
767     private int fAnchor = 0;
768
769     private List fList = new ArrayList(2);
770
771     public ReverseMap() {
772     }
773
774     public void clear() {
775       fList.clear();
776     }
777
778     public Object get(Position position) {
779
780       Entry entry;
781
782       // behind anchor
783       int length = fList.size();
784       for (int i = fAnchor; i < length; i++) {
785         entry = (Entry) fList.get(i);
786         if (entry.fPosition.equals(position)) {
787           fAnchor = i;
788           return entry.fValue;
789         }
790       }
791
792       // before anchor
793       for (int i = 0; i < fAnchor; i++) {
794         entry = (Entry) fList.get(i);
795         if (entry.fPosition.equals(position)) {
796           fAnchor = i;
797           return entry.fValue;
798         }
799       }
800
801       return null;
802     }
803
804     private int getIndex(Position position) {
805       Entry entry;
806       int length = fList.size();
807       for (int i = 0; i < length; i++) {
808         entry = (Entry) fList.get(i);
809         if (entry.fPosition.equals(position))
810           return i;
811       }
812       return -1;
813     }
814
815     public void put(Position position, Object value) {
816       int index = getIndex(position);
817       if (index == -1) {
818         Entry entry = new Entry();
819         entry.fPosition = position;
820         entry.fValue = value;
821         fList.add(entry);
822       } else {
823         Entry entry = (Entry) fList.get(index);
824         entry.fValue = value;
825       }
826     }
827
828     public void remove(Position position) {
829       int index = getIndex(position);
830       if (index > -1)
831         fList.remove(index);
832     }
833   }
834
835   /**
836                  * Document that can also be used by a background reconciler.
837                  */
838   protected static class PartiallySynchronizedDocument extends Document {
839
840     /*
841      * @see IDocumentExtension#startSequentialRewrite(boolean)
842      */
843     synchronized public void startSequentialRewrite(boolean normalized) {
844       super.startSequentialRewrite(normalized);
845     }
846
847     /*
848      * @see IDocumentExtension#stopSequentialRewrite()
849      */
850     synchronized public void stopSequentialRewrite() {
851       super.stopSequentialRewrite();
852     }
853
854     /*
855      * @see IDocument#get()
856      */
857     synchronized public String get() {
858       return super.get();
859     }
860
861     /*
862      * @see IDocument#get(int, int)
863      */
864     synchronized public String get(int offset, int length) throws BadLocationException {
865       return super.get(offset, length);
866     }
867
868     /*
869      * @see IDocument#getChar(int)
870      */
871     synchronized public char getChar(int offset) throws BadLocationException {
872       return super.getChar(offset);
873     }
874
875     /*
876      * @see IDocument#replace(int, int, String)
877      */
878     synchronized public void replace(int offset, int length, String text) throws BadLocationException {
879       super.replace(offset, length, text);
880     }
881
882     /*
883      * @see IDocument#set(String)
884      */
885     synchronized public void set(String text) {
886       super.set(text);
887     }
888   };
889   //
890   //  private static PHPPartitionScanner HTML_PARTITION_SCANNER = null;
891   //
892   //  private static PHPPartitionScanner PHP_PARTITION_SCANNER = null;
893   //  private static PHPPartitionScanner SMARTY_PARTITION_SCANNER = null;
894   //
895   //  // private final static String[] TYPES= new String[] { PHPPartitionScanner.PHP, PHPPartitionScanner.JAVA_DOC, PHPPartitionScanner.JAVA_MULTILINE_COMMENT };
896   //  private final static String[] TYPES =
897   //    new String[] {
898   //      IPHPPartitionScannerConstants.PHP,
899   //      IPHPPartitionScannerConstants.PHP_MULTILINE_COMMENT,
900   //      IPHPPartitionScannerConstants.HTML,
901   //      IPHPPartitionScannerConstants.HTML_MULTILINE_COMMENT,
902   //      IPHPPartitionScannerConstants.JAVASCRIPT,
903   //      IPHPPartitionScannerConstants.CSS,
904   //      IPHPPartitionScannerConstants.SMARTY,
905   //      IPHPPartitionScannerConstants.SMARTY_MULTILINE_COMMENT };
906   //  private static PHPPartitionScanner XML_PARTITION_SCANNER = null;
907
908   /* Preference key for temporary problems */
909   private final static String HANDLE_TEMPORARY_PROBLEMS = PreferenceConstants.EDITOR_EVALUTE_TEMPORARY_PROBLEMS;
910
911   /** The buffer factory */
912   private IBufferFactory fBufferFactory = new BufferFactory();
913   /** Indicates whether the save has been initialized by this provider */
914   private boolean fIsAboutToSave = false;
915   /** The save policy used by this provider */
916   private ISavePolicy fSavePolicy;
917   /** Internal property changed listener */
918   private IPropertyChangeListener fPropertyListener;
919
920   /** annotation model listener added to all created CU annotation models */
921   private GlobalAnnotationModelListener fGlobalAnnotationModelListener;
922
923   public PHPDocumentProvider() {
924
925     fPropertyListener = new IPropertyChangeListener() {
926       public void propertyChange(PropertyChangeEvent event) {
927         if (HANDLE_TEMPORARY_PROBLEMS.equals(event.getProperty()))
928           enableHandlingTemporaryProblems();
929       }
930     };
931
932     fGlobalAnnotationModelListener = new GlobalAnnotationModelListener();
933
934     PHPeclipsePlugin.getDefault().getPreferenceStore().addPropertyChangeListener(fPropertyListener);
935
936   }
937
938   /**
939    * Sets the document provider's save policy.
940    */
941   public void setSavePolicy(ISavePolicy savePolicy) {
942     fSavePolicy = savePolicy;
943   }
944
945   /**
946    * Creates a compilation unit from the given file.
947    * 
948    * @param file the file from which to create the compilation unit
949    */
950   protected ICompilationUnit createCompilationUnit(IFile file) {
951     Object element = PHPCore.create(file);
952     if (element instanceof ICompilationUnit)
953       return (ICompilationUnit) element;
954     return null;
955   }
956
957   /*
958          * @see AbstractDocumentProvider#createElementInfo(Object)
959          */
960   protected ElementInfo createElementInfo(Object element) throws CoreException {
961
962     if (!(element instanceof IFileEditorInput))
963       return super.createElementInfo(element);
964
965     IFileEditorInput input = (IFileEditorInput) element;
966     ICompilationUnit original = createCompilationUnit(input.getFile());
967     if (original != null) {
968
969       try {
970
971         try {
972           refreshFile(input.getFile());
973         } catch (CoreException x) {
974           handleCoreException(x, PHPEditorMessages.getString("PHPDocumentProvider.error.createElementInfo")); //$NON-NLS-1$
975         }
976
977         IAnnotationModel m = createCompilationUnitAnnotationModel(input);
978         IProblemRequestor r = m instanceof IProblemRequestor ? (IProblemRequestor) m : null;
979         ICompilationUnit c = (ICompilationUnit) original.getSharedWorkingCopy(getProgressMonitor(), fBufferFactory, r);
980
981         DocumentAdapter a = null;
982         try {
983           a = (DocumentAdapter) c.getBuffer();
984         } catch (ClassCastException x) {
985           IStatus status = new Status(IStatus.ERROR, PHPeclipsePlugin.PLUGIN_ID, PHPStatusConstants.TEMPLATE_IO_EXCEPTION, "Shared working copy has wrong buffer", x); //$NON-NLS-1$
986           throw new CoreException(status);
987         }
988
989         _FileSynchronizer f = new _FileSynchronizer(input);
990         f.install();
991
992         CompilationUnitInfo info = new CompilationUnitInfo(a.getDocument(), m, f, c);
993         info.setModificationStamp(computeModificationStamp(input.getFile()));
994         info.fStatus = a.getStatus();
995         info.fEncoding = getPersistedEncoding(input);
996
997         if (r instanceof IProblemRequestorExtension) {
998           IProblemRequestorExtension extension = (IProblemRequestorExtension) r;
999           extension.setIsActive(isHandlingTemporaryProblems());
1000         }
1001         m.addAnnotationModelListener(fGlobalAnnotationModelListener);
1002
1003         return info;
1004
1005       } catch (JavaModelException x) {
1006         throw new CoreException(x.getStatus());
1007       }
1008     } else {
1009       return super.createElementInfo(element);
1010     }
1011   }
1012
1013   /*
1014    * @see AbstractDocumentProvider#disposeElementInfo(Object, ElementInfo)
1015    */
1016   protected void disposeElementInfo(Object element, ElementInfo info) {
1017
1018     if (info instanceof CompilationUnitInfo) {
1019       CompilationUnitInfo cuInfo = (CompilationUnitInfo) info;
1020       cuInfo.fCopy.destroy();
1021       cuInfo.fModel.removeAnnotationModelListener(fGlobalAnnotationModelListener);
1022     }
1023
1024     super.disposeElementInfo(element, info);
1025   }
1026
1027   /*
1028          * @see AbstractDocumentProvider#doSaveDocument(IProgressMonitor, Object, IDocument, boolean)
1029          */
1030   protected void doSaveDocument(IProgressMonitor monitor, Object element, IDocument document, boolean overwrite)
1031     throws CoreException {
1032
1033     ElementInfo elementInfo = getElementInfo(element);
1034     if (elementInfo instanceof CompilationUnitInfo) {
1035       CompilationUnitInfo info = (CompilationUnitInfo) elementInfo;
1036
1037       // update structure, assumes lock on info.fCopy
1038       info.fCopy.reconcile();
1039
1040       ICompilationUnit original = (ICompilationUnit) info.fCopy.getOriginalElement();
1041       IResource resource = original.getResource();
1042
1043       if (resource == null) {
1044         // underlying resource has been deleted, just recreate file, ignore the rest
1045         super.doSaveDocument(monitor, element, document, overwrite);
1046         return;
1047       }
1048
1049       if (resource != null && !overwrite)
1050         checkSynchronizationState(info.fModificationStamp, resource);
1051
1052       if (fSavePolicy != null)
1053         fSavePolicy.preSave(info.fCopy);
1054
1055       // inform about the upcoming content change
1056       fireElementStateChanging(element);
1057       try {
1058         fIsAboutToSave = true;
1059         // commit working copy
1060         info.fCopy.commit(overwrite, monitor);
1061       } catch (CoreException x) {
1062         // inform about the failure
1063         fireElementStateChangeFailed(element);
1064         throw x;
1065       } catch (RuntimeException x) {
1066         // inform about the failure
1067         fireElementStateChangeFailed(element);
1068         throw x;
1069       } finally {
1070         fIsAboutToSave = false;
1071       }
1072
1073       // If here, the dirty state of the editor will change to "not dirty".
1074       // Thus, the state changing flag will be reset.
1075
1076       AbstractMarkerAnnotationModel model = (AbstractMarkerAnnotationModel) info.fModel;
1077       model.updateMarkers(info.fDocument);
1078
1079       if (resource != null)
1080         info.setModificationStamp(computeModificationStamp(resource));
1081
1082       if (fSavePolicy != null) {
1083         ICompilationUnit unit = fSavePolicy.postSave(original);
1084         if (unit != null) {
1085           IResource r = unit.getResource();
1086           IMarker[] markers = r.findMarkers(IMarker.MARKER, true, IResource.DEPTH_ZERO);
1087           if (markers != null && markers.length > 0) {
1088             for (int i = 0; i < markers.length; i++)
1089               model.updateMarker(markers[i], info.fDocument, null);
1090           }
1091         }
1092       }
1093
1094     } else {
1095       super.doSaveDocument(monitor, element, document, overwrite);
1096     }
1097   }
1098
1099   /**
1100    * Replaces createAnnotionModel of the super class.
1101    */
1102   protected IAnnotationModel createCompilationUnitAnnotationModel(Object element) throws CoreException {
1103                 if ( !(element instanceof IFileEditorInput))
1104                         throw new CoreException(PHPUIStatus.createError(
1105                                 IJavaModelStatusConstants.INVALID_RESOURCE_TYPE, "", null)); //$NON-NLS-1$
1106                 
1107                 IFileEditorInput input= (IFileEditorInput) element;
1108                 return new CompilationUnitAnnotationModel(input);
1109   }
1110
1111   //  private IDocumentPartitioner createCSSPartitioner() {
1112   //    return new DefaultPartitioner(getHTMLPartitionScanner(), TYPES);
1113   //  }
1114
1115   /* (non-Javadoc)
1116    * Method declared on AbstractDocumentProvider
1117    */
1118   protected IDocument createDocument(Object element) throws CoreException {
1119     if (element instanceof IEditorInput) {
1120       Document document = new PartiallySynchronizedDocument();
1121       if (setDocumentContent(document, (IEditorInput) element, getEncoding(element))) {
1122         initializeDocument(document, (IEditorInput) element);
1123
1124         //      
1125         //    IDocument document = super.createDocument(element);
1126         //    if (document != null) {
1127         //        IDocumentPartitioner partitioner = null;
1128         //        if (element instanceof FileEditorInput) {
1129         //          IFile file = (IFile) ((FileEditorInput) element).getAdapter(IFile.class);
1130         //          String filename = file.getLocation().toString();
1131         //          String extension = filename.substring(filename.lastIndexOf("."), filename.length());
1132         //          //   System.out.println(extension);
1133         //          if (extension.equalsIgnoreCase(".html") || extension.equalsIgnoreCase(".htm")) {
1134         //            // html
1135         //            partitioner = createHTMLPartitioner();
1136         //          } else if (extension.equalsIgnoreCase(".xml")) {
1137         //            // xml
1138         //            partitioner = createXMLPartitioner();
1139         //          } else if (extension.equalsIgnoreCase(".js")) {
1140         //            // javascript
1141         //            partitioner = createJavaScriptPartitioner();
1142         //          } else if (extension.equalsIgnoreCase(".css")) {
1143         //            // cascading style sheets
1144         //            partitioner = createCSSPartitioner();
1145         //          } else if (extension.equalsIgnoreCase(".tpl")) {
1146         //            // smarty ?
1147         //            partitioner = createSmartyPartitioner();
1148         //          } else if (extension.equalsIgnoreCase(".inc")) {
1149         //            // php include files ?
1150         //            partitioner = createIncludePartitioner();
1151         //          }
1152         //        }
1153         //
1154         //        if (partitioner == null) {
1155         //          partitioner = createPHPPartitioner();
1156         //        }
1157         //        document.setDocumentPartitioner(partitioner);
1158         //        partitioner.connect(document);
1159       }
1160       return document;
1161     }
1162     return null;
1163   }
1164
1165   //  /**
1166   //   * Return a partitioner for .html files.
1167   //   */
1168   //  private IDocumentPartitioner createHTMLPartitioner() {
1169   //    return new DefaultPartitioner(getHTMLPartitionScanner(), TYPES);
1170   //  }
1171   //
1172   //  private IDocumentPartitioner createIncludePartitioner() {
1173   //    return new DefaultPartitioner(getPHPPartitionScanner(), TYPES);
1174   //  }
1175   //
1176   //  private IDocumentPartitioner createJavaScriptPartitioner() {
1177   //    return new DefaultPartitioner(getHTMLPartitionScanner(), TYPES);
1178   //  }
1179
1180   /**
1181    * Creates a line tracker working with the same line delimiters as the document
1182    * of the given element. Assumes the element to be managed by this document provider.
1183    * 
1184    * @param element the element serving as blue print
1185    * @return a line tracker based on the same line delimiters as the element's document
1186    */
1187   public ILineTracker createLineTracker(Object element) {
1188     return new DefaultLineTracker();
1189   }
1190
1191   //  /**
1192   //   * Return a partitioner for .php files.
1193   //   */
1194   //  private IDocumentPartitioner createPHPPartitioner() {
1195   //    return new DefaultPartitioner(getPHPPartitionScanner(), TYPES);
1196   //  }
1197   //
1198   //  private IDocumentPartitioner createSmartyPartitioner() {
1199   //    return new DefaultPartitioner(getSmartyPartitionScanner(), TYPES);
1200   //  }
1201   //
1202   //  private IDocumentPartitioner createXMLPartitioner() {
1203   //    return new DefaultPartitioner(getXMLPartitionScanner(), TYPES);
1204   //  }
1205   //
1206   //  /**
1207   //   * Return a scanner for creating html partitions.
1208   //   */
1209   //  private PHPPartitionScanner getHTMLPartitionScanner() {
1210   //    if (HTML_PARTITION_SCANNER == null)
1211   //      HTML_PARTITION_SCANNER = new PHPPartitionScanner(IPHPPartitionScannerConstants.HTML_FILE);
1212   //    return HTML_PARTITION_SCANNER;
1213   //  }
1214   //  /**
1215   //   * Return a scanner for creating php partitions.
1216   //   */
1217   //  private PHPPartitionScanner getPHPPartitionScanner() {
1218   //    if (PHP_PARTITION_SCANNER == null)
1219   //      PHP_PARTITION_SCANNER = new PHPPartitionScanner(IPHPPartitionScannerConstants.PHP_FILE);
1220   //    return PHP_PARTITION_SCANNER;
1221   //  }
1222   //
1223   //  /**
1224   //   * Return a scanner for creating smarty partitions.
1225   //   */
1226   //  private PHPPartitionScanner getSmartyPartitionScanner() {
1227   //    if (SMARTY_PARTITION_SCANNER == null)
1228   //      SMARTY_PARTITION_SCANNER = new PHPPartitionScanner(IPHPPartitionScannerConstants.SMARTY_FILE);
1229   //    return SMARTY_PARTITION_SCANNER;
1230   //  }
1231   //
1232   //  /**
1233   //   * Return a scanner for creating xml partitions.
1234   //   */
1235   //  private PHPPartitionScanner getXMLPartitionScanner() {
1236   //    if (XML_PARTITION_SCANNER == null)
1237   //      XML_PARTITION_SCANNER = new PHPPartitionScanner(IPHPPartitionScannerConstants.XML_FILE);
1238   //    return XML_PARTITION_SCANNER;
1239   //  }
1240
1241   protected void initializeDocument(IDocument document, IEditorInput editorInput) {
1242     if (document != null) {
1243       JavaTextTools tools = PHPeclipsePlugin.getDefault().getJavaTextTools();
1244       IDocumentPartitioner partitioner = null;
1245       if (editorInput != null && editorInput instanceof FileEditorInput) {
1246         IFile file = (IFile) ((FileEditorInput) editorInput).getAdapter(IFile.class);
1247         String filename = file.getLocation().toString();
1248         String extension = filename.substring(filename.lastIndexOf("."), filename.length());
1249         partitioner = tools.createDocumentPartitioner(extension);
1250       } else {
1251         partitioner = tools.createDocumentPartitioner(".php");
1252       }
1253       document.setDocumentPartitioner(partitioner);
1254       partitioner.connect(document);
1255     }
1256   }
1257
1258   /*
1259    * @see org.eclipse.ui.texteditor.AbstractDocumentProvider#doResetDocument(java.lang.Object, org.eclipse.core.runtime.IProgressMonitor)
1260    */
1261   protected void doResetDocument(Object element, IProgressMonitor monitor) throws CoreException {
1262     if (element == null)
1263       return;
1264     
1265     ElementInfo elementInfo= getElementInfo(element);           
1266     if (elementInfo instanceof CompilationUnitInfo) {
1267       CompilationUnitInfo info= (CompilationUnitInfo) elementInfo;
1268       
1269       IDocument document;
1270       IStatus status= null;
1271       
1272       try {
1273         
1274         ICompilationUnit original= (ICompilationUnit) info.fCopy.getOriginalElement();
1275         IResource resource= original.getResource();
1276         if (resource instanceof IFile) {
1277           
1278           IFile file= (IFile) resource;
1279           
1280           try {
1281             refreshFile(file, monitor);
1282           } catch (CoreException x) {
1283             handleCoreException(x, PHPEditorMessages.getString("CompilationUnitDocumentProvider.error.resetDocument")); //$NON-NLS-1$
1284           }
1285           
1286           IFileEditorInput input= new FileEditorInput(file);
1287           document= super.createDocument(input);
1288           
1289         } else {
1290           document= createEmptyDocument();
1291         }
1292         
1293       } catch (CoreException x) {
1294         document= createEmptyDocument();
1295         status= x.getStatus();
1296       }
1297       
1298       fireElementContentAboutToBeReplaced(element);
1299       
1300       removeUnchangedElementListeners(element, info);
1301       info.fDocument.set(document.get());
1302       info.fCanBeSaved= false;
1303       info.fStatus= status;
1304       addUnchangedElementListeners(element, info);
1305       
1306       fireElementContentReplaced(element);
1307       fireElementDirtyStateChanged(element, false);
1308       
1309     } else {
1310       super.doResetDocument(element, monitor);
1311     }
1312   }
1313   
1314   /*
1315    * @see AbstractDocumentProvider#resetDocument(Object)
1316    */
1317 //  public void resetDocument(Object element) throws CoreException {
1318 //    if (element == null)
1319 //      return;
1320 //
1321 //    ElementInfo elementInfo = getElementInfo(element);
1322 //    if (elementInfo instanceof CompilationUnitInfo) {
1323 //      CompilationUnitInfo info = (CompilationUnitInfo) elementInfo;
1324 //
1325 //      IDocument document;
1326 //      IStatus status = null;
1327 //
1328 //      try {
1329 //
1330 //        ICompilationUnit original = (ICompilationUnit) info.fCopy.getOriginalElement();
1331 //        IResource resource = original.getResource();
1332 //        if (resource instanceof IFile) {
1333 //
1334 //          IFile file = (IFile) resource;
1335 //
1336 //          try {
1337 //            refreshFile(file);
1338 //          } catch (CoreException x) {
1339 //            handleCoreException(x, PHPEditorMessages.getString("PHPDocumentProvider.error.resetDocument")); //$NON-NLS-1$
1340 //          }
1341 //
1342 //          IFileEditorInput input = new FileEditorInput(file);
1343 //          document = super.createDocument(input);
1344 //
1345 //        } else {
1346 //          document = new Document();
1347 //        }
1348 //
1349 //      } catch (CoreException x) {
1350 //        document = new Document();
1351 //        status = x.getStatus();
1352 //      }
1353 //
1354 //      fireElementContentAboutToBeReplaced(element);
1355 //
1356 //      removeUnchangedElementListeners(element, info);
1357 //      info.fDocument.set(document.get());
1358 //      info.fCanBeSaved = false;
1359 //      info.fStatus = status;
1360 //      addUnchangedElementListeners(element, info);
1361 //
1362 //      fireElementContentReplaced(element);
1363 //      fireElementDirtyStateChanged(element, false);
1364 //
1365 //    } else {
1366 //      super.resetDocument(element);
1367 //    }
1368 //  }
1369   /**
1370          * Saves the content of the given document to the given element.
1371          * This is only performed when this provider initiated the save.
1372          * 
1373          * @param monitor the progress monitor
1374          * @param element the element to which to save
1375          * @param document the document to save
1376          * @param overwrite <code>true</code> if the save should be enforced
1377          */
1378   public void saveDocumentContent(IProgressMonitor monitor, Object element, IDocument document, boolean overwrite)
1379     throws CoreException {
1380
1381     if (!fIsAboutToSave)
1382       return;
1383
1384     if (element instanceof IFileEditorInput) {
1385       IFileEditorInput input = (IFileEditorInput) element;
1386       try {
1387         String encoding = getEncoding(element);
1388         if (encoding == null)
1389           encoding = ResourcesPlugin.getEncoding();
1390         InputStream stream = new ByteArrayInputStream(document.get().getBytes(encoding));
1391         IFile file = input.getFile();
1392         file.setContents(stream, overwrite, true, monitor);
1393       } catch (IOException x) {
1394         IStatus s = new Status(IStatus.ERROR, PHPeclipsePlugin.PLUGIN_ID, IStatus.OK, x.getMessage(), x);
1395         throw new CoreException(s);
1396       }
1397     }
1398   }
1399   /**
1400    * Returns the underlying resource for the given element.
1401    * 
1402    * @param the element
1403    * @return the underlying resource of the given element
1404    */
1405   public IResource getUnderlyingResource(Object element) {
1406     if (element instanceof IFileEditorInput) {
1407       IFileEditorInput input = (IFileEditorInput) element;
1408       return input.getFile();
1409     }
1410     return null;
1411   }
1412
1413   /**
1414    * Returns the working copy this document provider maintains for the given
1415    * element.
1416    * 
1417    * @param element the given element
1418    * @return the working copy for the given element
1419    */
1420   ICompilationUnit getWorkingCopy(IEditorInput element) {
1421
1422     ElementInfo elementInfo = getElementInfo(element);
1423     if (elementInfo instanceof CompilationUnitInfo) {
1424       CompilationUnitInfo info = (CompilationUnitInfo) elementInfo;
1425       return info.fCopy;
1426     }
1427
1428     return null;
1429   }
1430
1431   /**
1432    * Gets the BufferFactory.
1433    */
1434   public IBufferFactory getBufferFactory() {
1435     return fBufferFactory;
1436   }
1437
1438   /**
1439    * Shuts down this document provider.
1440    */
1441   public void shutdown() {
1442
1443     PHPeclipsePlugin.getDefault().getPreferenceStore().removePropertyChangeListener(fPropertyListener);
1444
1445     Iterator e = getConnectedElements();
1446     while (e.hasNext())
1447       disconnect(e.next());
1448   }
1449
1450   /**
1451    * Returns the preference whether handling temporary problems is enabled.
1452    */
1453   protected boolean isHandlingTemporaryProblems() {
1454     IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
1455     return store.getBoolean(HANDLE_TEMPORARY_PROBLEMS);
1456   }
1457
1458   /**
1459    * Switches the state of problem acceptance according to the value in the preference store.
1460    */
1461   protected void enableHandlingTemporaryProblems() {
1462     boolean enable = isHandlingTemporaryProblems();
1463     for (Iterator iter = getConnectedElements(); iter.hasNext();) {
1464       ElementInfo element = getElementInfo(iter.next());
1465       if (element instanceof CompilationUnitInfo) {
1466         CompilationUnitInfo info = (CompilationUnitInfo) element;
1467         if (info.fModel instanceof IProblemRequestorExtension) {
1468           IProblemRequestorExtension extension = (IProblemRequestorExtension) info.fModel;
1469           extension.setIsActive(enable);
1470         }
1471       }
1472     }
1473   }
1474
1475   /**
1476    * Adds a listener that reports changes from all compilation unit annotation models.
1477    */
1478   public void addGlobalAnnotationModelListener(IAnnotationModelListener listener) {
1479     fGlobalAnnotationModelListener.addListener(listener);
1480   }
1481
1482   /**
1483    * Removes the listener.
1484    */
1485   public void removeGlobalAnnotationModelListener(IAnnotationModelListener listener) {
1486     fGlobalAnnotationModelListener.removeListener(listener);
1487   }
1488
1489   /**
1490    * Returns whether the given element is connected to this document provider.
1491    * 
1492    * @param element the element
1493    * @return <code>true</code> if the element is connected, <code>false</code> otherwise
1494    */
1495   boolean isConnected(Object element) {
1496     return getElementInfo(element) != null;
1497   }
1498 }