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