1 package net.sourceforge.phpeclipse.phpeditor;
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
11 IBM Corporation - Initial implementation
12 Klaus Hartlage - www.eclipseproject.de
13 **********************************************************************/
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;
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;
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.MarkerAnnotation;
75 import org.eclipse.ui.texteditor.ResourceMarkerAnnotationModel;
78 * The PHPDocumentProvider provides the IDocuments used by java editors.
81 public class PHPDocumentProvider extends FileDocumentProvider {
83 * Here for visibility issues only.
85 protected class _FileSynchronizer extends FileSynchronizer {
86 public _FileSynchronizer(IFileEditorInput fileEditorInput) {
87 super(fileEditorInput);
91 * Bundle of all required informations to allow working copy management.
93 protected class CompilationUnitInfo extends FileInfo {
95 ICompilationUnit fCopy;
97 public CompilationUnitInfo(
99 IAnnotationModel model,
100 _FileSynchronizer fileSynchronizer,
101 ICompilationUnit copy) {
102 super(document, model, fileSynchronizer);
106 public void setModificationStamp(long timeStamp) {
107 fModificationStamp = timeStamp;
111 * Annotation model dealing with java marker annotations and temporary problems.
112 * Also acts as problem requestor for its compilation unit. Initialiy inactive. Must explicitly be
115 protected class CompilationUnitAnnotationModel
116 extends ResourceMarkerAnnotationModel
117 implements IProblemRequestor, IProblemRequestorExtension {
118 private List fCollectedProblems;
119 private List fCurrentlyOverlaid = new ArrayList();
120 private List fGeneratedAnnotations;
122 private IFileEditorInput fInput;
123 private boolean fIsActive = false;
124 private List fPreviouslyOverlaid = null;
125 private IProgressMonitor fProgressMonitor;
127 private ReverseMap fReverseMap = new ReverseMap();
129 public CompilationUnitAnnotationModel(IFileEditorInput input) {
130 super(input.getFile());
135 * @see IProblemRequestor#acceptProblem(IProblem)
137 public void acceptProblem(IProblem problem) {
139 fCollectedProblems.add(problem);
143 * @see AnnotationModel#addAnnotation(Annotation, Position, boolean)
145 protected void addAnnotation(Annotation annotation, Position position, boolean fireModelChanged) {
146 super.addAnnotation(annotation, position, fireModelChanged);
148 Object cached = fReverseMap.get(position);
150 fReverseMap.put(position, annotation);
151 else if (cached instanceof List) {
152 List list = (List) cached;
153 list.add(annotation);
154 } else if (cached instanceof Annotation) {
155 List list = new ArrayList(2);
157 list.add(annotation);
158 fReverseMap.put(position, list);
163 * @see IProblemRequestor#beginReporting()
165 public void beginReporting() {
166 ICompilationUnit unit = getWorkingCopy(fInput);
167 if (unit != null) // && unit.getJavaProject().isOnClasspath(unit))
168 fCollectedProblems = new ArrayList();
170 fCollectedProblems = null;
173 protected MarkerAnnotation createMarkerAnnotation(IMarker marker) {
174 return new JavaMarkerAnnotation(marker);
177 protected Position createPositionFromProblem(IProblem problem) {
178 int start = problem.getSourceStart();
182 int length = problem.getSourceEnd() - problem.getSourceStart() + 1;
186 return new Position(start, length);
190 * @see IProblemRequestor#endReporting()
192 public void endReporting() {
196 if (fProgressMonitor != null && fProgressMonitor.isCanceled())
199 boolean isCanceled = false;
200 boolean temporaryProblemsChanged = false;
201 fPreviouslyOverlaid = fCurrentlyOverlaid;
202 fCurrentlyOverlaid = new ArrayList();
204 synchronized (fAnnotations) {
206 if (fGeneratedAnnotations.size() > 0) {
207 temporaryProblemsChanged = true;
208 removeAnnotations(fGeneratedAnnotations, false, true);
209 fGeneratedAnnotations.clear();
212 if (fCollectedProblems != null && fCollectedProblems.size() > 0) {
214 Iterator e = fCollectedProblems.iterator();
215 while (e.hasNext()) {
217 IProblem problem = (IProblem) e.next();
219 if (fProgressMonitor != null && fProgressMonitor.isCanceled()) {
224 Position position = createPositionFromProblem(problem);
225 if (position != null) {
227 ProblemAnnotation annotation = new ProblemAnnotation(problem);
228 overlayMarkers(position, annotation);
229 fGeneratedAnnotations.add(annotation);
230 addAnnotation(annotation, position, false);
232 temporaryProblemsChanged = true;
236 fCollectedProblems.clear();
239 removeMarkerOverlays(isCanceled);
240 fPreviouslyOverlaid.clear();
241 fPreviouslyOverlaid = null;
244 if (temporaryProblemsChanged)
245 fireModelChanged(new CompilationUnitAnnotationModelEvent(this, getResource(), false));
248 private Object getAnnotations(Position position) {
249 return fReverseMap.get(position);
253 * @see AnnotationModel#fireModelChanged()
255 protected void fireModelChanged() {
256 fireModelChanged(new CompilationUnitAnnotationModelEvent(this, getResource(), true));
260 * @see IProblemRequestor#isActive()
262 public boolean isActive() {
263 return fIsActive && (fCollectedProblems != null);
267 * @see AnnotationModel#removeAllAnnotations(boolean)
269 protected void removeAllAnnotations(boolean fireModelChanged) {
270 super.removeAllAnnotations(fireModelChanged);
275 * @see AnnotationModel#removeAnnotation(Annotation, boolean)
277 protected void removeAnnotation(Annotation annotation, boolean fireModelChanged) {
278 Position position = getPosition(annotation);
279 Object cached = fReverseMap.get(position);
280 if (cached instanceof List) {
281 List list = (List) cached;
282 list.remove(annotation);
283 if (list.size() == 1) {
284 fReverseMap.put(position, list.get(0));
287 } else if (cached instanceof Annotation) {
288 fReverseMap.remove(position);
291 super.removeAnnotation(annotation, fireModelChanged);
294 private void removeMarkerOverlays(boolean isCanceled) {
296 fCurrentlyOverlaid.addAll(fPreviouslyOverlaid);
297 } else if (fPreviouslyOverlaid != null) {
298 Iterator e = fPreviouslyOverlaid.iterator();
299 while (e.hasNext()) {
300 JavaMarkerAnnotation annotation = (JavaMarkerAnnotation) e.next();
301 annotation.setOverlay(null);
307 * @see IProblemRequestorExtension#setIsActive(boolean)
309 public void setIsActive(boolean isActive) {
310 if (fIsActive != isActive) {
311 fIsActive = isActive;
313 startCollectingProblems();
315 stopCollectingProblems();
320 * @see IProblemRequestorExtension#setProgressMonitor(IProgressMonitor)
322 public void setProgressMonitor(IProgressMonitor monitor) {
323 fProgressMonitor = monitor;
327 * Overlays value with problem annotation.
328 * @param problemAnnotation
330 private void setOverlay(Object value, ProblemAnnotation problemAnnotation) {
331 if (value instanceof JavaMarkerAnnotation) {
332 JavaMarkerAnnotation annotation = (JavaMarkerAnnotation) value;
333 if (annotation.isProblem()) {
334 annotation.setOverlay(problemAnnotation);
335 fPreviouslyOverlaid.remove(annotation);
336 fCurrentlyOverlaid.add(annotation);
341 private void overlayMarkers(Position position, ProblemAnnotation problemAnnotation) {
342 Object value = getAnnotations(position);
343 if (value instanceof List) {
344 List list = (List) value;
345 for (Iterator e = list.iterator(); e.hasNext();)
346 setOverlay(e.next(), problemAnnotation);
348 setOverlay(value, problemAnnotation);
353 * Tells this annotation model to collect temporary problems from now on.
355 private void startCollectingProblems() {
356 fCollectedProblems = new ArrayList();
357 fGeneratedAnnotations = new ArrayList();
361 * Tells this annotation model to no longer collect temporary problems.
363 private void stopCollectingProblems() {
364 if (fGeneratedAnnotations != null) {
365 removeAnnotations(fGeneratedAnnotations, true, true);
366 fGeneratedAnnotations.clear();
368 fCollectedProblems = null;
369 fGeneratedAnnotations = null;
372 protected void update(IMarkerDelta[] markerDeltas) {
374 super.update(markerDeltas);
376 if (markerDeltas != null && markerDeltas.length > 0) {
378 ICompilationUnit workingCopy = getWorkingCopy(fInput);
379 if (workingCopy != null)
380 workingCopy.reconcile(true, null);
381 } catch (JavaModelException ex) {
382 handleCoreException(ex, ex.getMessage());
388 * Creates <code>IBuffer</code>s based on documents.
390 protected class BufferFactory implements IBufferFactory {
392 private IDocument internalGetDocument(IFileEditorInput input) throws CoreException {
393 IDocument document = getDocument(input);
394 if (document != null)
396 return PHPDocumentProvider.this.createDocument(input);
399 public IBuffer createBuffer(IOpenable owner) {
400 if (owner instanceof ICompilationUnit) {
402 ICompilationUnit unit = (ICompilationUnit) owner;
403 ICompilationUnit original = (ICompilationUnit) unit.getOriginalElement();
404 IResource resource = original.getResource();
405 if (resource instanceof IFile) {
406 IFileEditorInput providerKey = new FileEditorInput((IFile) resource);
408 IDocument document = null;
409 IStatus status = null;
412 document = internalGetDocument(providerKey);
413 } catch (CoreException x) {
414 status = x.getStatus();
415 document = new Document();
416 initializeDocument(document, providerKey);
419 DocumentAdapter adapter =
420 new DocumentAdapter(unit, document, new DefaultLineTracker(), PHPDocumentProvider.this, providerKey);
421 adapter.setStatus(status);
426 return DocumentAdapter.NULL;
430 protected static class GlobalAnnotationModelListener implements IAnnotationModelListener, IAnnotationModelListenerExtension {
432 private ListenerList fListenerList;
434 public GlobalAnnotationModelListener() {
435 fListenerList = new ListenerList();
438 public void addListener(IAnnotationModelListener listener) {
439 fListenerList.add(listener);
443 * @see IAnnotationModelListenerExtension#modelChanged(AnnotationModelEvent)
445 public void modelChanged(AnnotationModelEvent event) {
446 Object[] listeners = fListenerList.getListeners();
447 for (int i = 0; i < listeners.length; i++) {
448 Object curr = listeners[i];
449 if (curr instanceof IAnnotationModelListenerExtension) {
450 ((IAnnotationModelListenerExtension) curr).modelChanged(event);
456 * @see IAnnotationModelListener#modelChanged(IAnnotationModel)
458 public void modelChanged(IAnnotationModel model) {
459 Object[] listeners = fListenerList.getListeners();
460 for (int i = 0; i < listeners.length; i++) {
461 ((IAnnotationModelListener) listeners[i]).modelChanged(model);
465 public void removeListener(IAnnotationModelListener listener) {
466 fListenerList.remove(listener);
471 * Annotation representating an <code>IProblem</code>.
473 static protected class ProblemAnnotation extends Annotation implements IJavaAnnotation {
475 // private static Image fgQuickFixImage;
476 // private static Image fgQuickFixErrorImage;
477 // private static boolean fgQuickFixImagesInitialized = false;
479 private List fOverlaids;
480 private IProblem fProblem;
481 private Image fImage;
482 // private boolean fQuickFixImagesInitialized = false;
483 private AnnotationType fType;
485 public ProblemAnnotation(IProblem problem) {
488 setLayer(MarkerAnnotation.PROBLEM_LAYER + 1);
490 if (IProblem.Task == fProblem.getID())
491 fType = AnnotationType.TASK;
492 else if (fProblem.isWarning())
493 fType = AnnotationType.WARNING;
495 fType = AnnotationType.ERROR;
498 private void initializeImages() {
499 // http://bugs.eclipse.org/bugs/show_bug.cgi?id=18936
500 // if (!fQuickFixImagesInitialized) {
501 // if (indicateQuixFixableProblems() && JavaCorrectionProcessor.hasCorrections(fProblem.getID())) {
502 // if (!fgQuickFixImagesInitialized) {
503 // fgQuickFixImage = JavaPluginImages.get(JavaPluginImages.IMG_OBJS_FIXABLE_PROBLEM);
504 // fgQuickFixErrorImage = JavaPluginImages.get(JavaPluginImages.IMG_OBJS_FIXABLE_ERROR);
505 // fgQuickFixImagesInitialized = true;
507 // if (fType == AnnotationType.ERROR)
508 // fImage = fgQuickFixErrorImage;
510 // fImage = fgQuickFixImage;
512 // fQuickFixImagesInitialized = true;
516 private boolean indicateQuixFixableProblems() {
517 return PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_CORRECTION_INDICATION);
521 * @see Annotation#paint
523 public void paint(GC gc, Canvas canvas, Rectangle r) {
526 drawImage(fImage, gc, canvas, r, SWT.CENTER, SWT.TOP);
530 * @see IJavaAnnotation#getImage(Display)
532 public Image getImage(Display display) {
538 * @see IJavaAnnotation#getMessage()
540 public String getMessage() {
541 return fProblem.getMessage();
545 * @see IJavaAnnotation#isTemporary()
547 public boolean isTemporary() {
552 * @see IJavaAnnotation#getArguments()
554 public String[] getArguments() {
555 return isProblem() ? fProblem.getArguments() : null;
559 * @see IJavaAnnotation#getId()
562 return isProblem() ? fProblem.getID() : -1;
566 * @see IJavaAnnotation#isProblem()
568 public boolean isProblem() {
569 return fType == AnnotationType.WARNING || fType == AnnotationType.ERROR;
573 * @see IJavaAnnotation#isRelevant()
575 public boolean isRelevant() {
580 * @see IJavaAnnotation#hasOverlay()
582 public boolean hasOverlay() {
587 * @see IJavaAnnotation#addOverlaid(IJavaAnnotation)
589 public void addOverlaid(IJavaAnnotation annotation) {
590 if (fOverlaids == null)
591 fOverlaids = new ArrayList(1);
592 fOverlaids.add(annotation);
596 * @see IJavaAnnotation#removeOverlaid(IJavaAnnotation)
598 public void removeOverlaid(IJavaAnnotation annotation) {
599 if (fOverlaids != null) {
600 fOverlaids.remove(annotation);
601 if (fOverlaids.size() == 0)
607 * @see IJavaAnnotation#getOverlaidIterator()
609 public Iterator getOverlaidIterator() {
610 if (fOverlaids != null)
611 return fOverlaids.iterator();
615 public AnnotationType getAnnotationType() {
620 * Internal structure for mapping positions to some value.
621 * The reason for this specific structure is that positions can
622 * change over time. Thus a lookup is based on value and not
625 protected static class ReverseMap {
631 private int fAnchor = 0;
633 private List fList = new ArrayList(2);
635 public ReverseMap() {
638 public void clear() {
642 public Object get(Position position) {
647 int length = fList.size();
648 for (int i = fAnchor; i < length; i++) {
649 entry = (Entry) fList.get(i);
650 if (entry.fPosition.equals(position)) {
657 for (int i = 0; i < fAnchor; i++) {
658 entry = (Entry) fList.get(i);
659 if (entry.fPosition.equals(position)) {
668 private int getIndex(Position position) {
670 int length = fList.size();
671 for (int i = 0; i < length; i++) {
672 entry = (Entry) fList.get(i);
673 if (entry.fPosition.equals(position))
679 public void put(Position position, Object value) {
680 int index = getIndex(position);
682 Entry entry = new Entry();
683 entry.fPosition = position;
684 entry.fValue = value;
687 Entry entry = (Entry) fList.get(index);
688 entry.fValue = value;
692 public void remove(Position position) {
693 int index = getIndex(position);
700 * Document that can also be used by a background reconciler.
702 protected static class PartiallySynchronizedDocument extends Document {
705 * @see IDocumentExtension#startSequentialRewrite(boolean)
707 synchronized public void startSequentialRewrite(boolean normalized) {
708 super.startSequentialRewrite(normalized);
712 * @see IDocumentExtension#stopSequentialRewrite()
714 synchronized public void stopSequentialRewrite() {
715 super.stopSequentialRewrite();
719 * @see IDocument#get()
721 synchronized public String get() {
726 * @see IDocument#get(int, int)
728 synchronized public String get(int offset, int length) throws BadLocationException {
729 return super.get(offset, length);
733 * @see IDocument#getChar(int)
735 synchronized public char getChar(int offset) throws BadLocationException {
736 return super.getChar(offset);
740 * @see IDocument#replace(int, int, String)
742 synchronized public void replace(int offset, int length, String text) throws BadLocationException {
743 super.replace(offset, length, text);
747 * @see IDocument#set(String)
749 synchronized public void set(String text) {
754 // private static PHPPartitionScanner HTML_PARTITION_SCANNER = null;
756 // private static PHPPartitionScanner PHP_PARTITION_SCANNER = null;
757 // private static PHPPartitionScanner SMARTY_PARTITION_SCANNER = null;
759 // // private final static String[] TYPES= new String[] { PHPPartitionScanner.PHP, PHPPartitionScanner.JAVA_DOC, PHPPartitionScanner.JAVA_MULTILINE_COMMENT };
760 // private final static String[] TYPES =
762 // IPHPPartitionScannerConstants.PHP,
763 // IPHPPartitionScannerConstants.PHP_MULTILINE_COMMENT,
764 // IPHPPartitionScannerConstants.HTML,
765 // IPHPPartitionScannerConstants.HTML_MULTILINE_COMMENT,
766 // IPHPPartitionScannerConstants.JAVASCRIPT,
767 // IPHPPartitionScannerConstants.CSS,
768 // IPHPPartitionScannerConstants.SMARTY,
769 // IPHPPartitionScannerConstants.SMARTY_MULTILINE_COMMENT };
770 // private static PHPPartitionScanner XML_PARTITION_SCANNER = null;
772 /* Preference key for temporary problems */
773 private final static String HANDLE_TEMPORARY_PROBLEMS = PreferenceConstants.EDITOR_EVALUTE_TEMPORARY_PROBLEMS;
775 /** The buffer factory */
776 private IBufferFactory fBufferFactory = new BufferFactory();
777 /** Indicates whether the save has been initialized by this provider */
778 private boolean fIsAboutToSave = false;
779 /** The save policy used by this provider */
780 private ISavePolicy fSavePolicy;
781 /** Internal property changed listener */
782 private IPropertyChangeListener fPropertyListener;
784 /** annotation model listener added to all created CU annotation models */
785 private GlobalAnnotationModelListener fGlobalAnnotationModelListener;
787 public PHPDocumentProvider() {
789 fPropertyListener = new IPropertyChangeListener() {
790 public void propertyChange(PropertyChangeEvent event) {
791 if (HANDLE_TEMPORARY_PROBLEMS.equals(event.getProperty()))
792 enableHandlingTemporaryProblems();
796 fGlobalAnnotationModelListener = new GlobalAnnotationModelListener();
798 PHPeclipsePlugin.getDefault().getPreferenceStore().addPropertyChangeListener(fPropertyListener);
803 * Sets the document provider's save policy.
805 public void setSavePolicy(ISavePolicy savePolicy) {
806 fSavePolicy = savePolicy;
810 * Creates a compilation unit from the given file.
812 * @param file the file from which to create the compilation unit
814 protected ICompilationUnit createCompilationUnit(IFile file) {
815 Object element = PHPCore.create(file);
816 if (element instanceof ICompilationUnit)
817 return (ICompilationUnit) element;
822 * @see AbstractDocumentProvider#createElementInfo(Object)
824 protected ElementInfo createElementInfo(Object element) throws CoreException {
826 if (!(element instanceof IFileEditorInput))
827 return super.createElementInfo(element);
829 IFileEditorInput input = (IFileEditorInput) element;
830 ICompilationUnit original = createCompilationUnit(input.getFile());
831 if (original != null) {
836 refreshFile(input.getFile());
837 } catch (CoreException x) {
838 handleCoreException(x, PHPEditorMessages.getString("PHPDocumentProvider.error.createElementInfo")); //$NON-NLS-1$
841 IAnnotationModel m = createCompilationUnitAnnotationModel(input);
842 IProblemRequestor r = m instanceof IProblemRequestor ? (IProblemRequestor) m : null;
843 ICompilationUnit c = (ICompilationUnit) original.getSharedWorkingCopy(getProgressMonitor(), fBufferFactory, r);
845 DocumentAdapter a = null;
847 a = (DocumentAdapter) c.getBuffer();
848 } catch (ClassCastException x) {
849 IStatus status = new Status(IStatus.ERROR, PHPeclipsePlugin.PLUGIN_ID, PHPStatusConstants.TEMPLATE_IO_EXCEPTION, "Shared working copy has wrong buffer", x); //$NON-NLS-1$
850 throw new CoreException(status);
853 _FileSynchronizer f = new _FileSynchronizer(input);
856 CompilationUnitInfo info = new CompilationUnitInfo(a.getDocument(), m, f, c);
857 info.setModificationStamp(computeModificationStamp(input.getFile()));
858 info.fStatus = a.getStatus();
859 info.fEncoding = getPersistedEncoding(input);
861 if (r instanceof IProblemRequestorExtension) {
862 IProblemRequestorExtension extension = (IProblemRequestorExtension) r;
863 extension.setIsActive(isHandlingTemporaryProblems());
865 m.addAnnotationModelListener(fGlobalAnnotationModelListener);
869 } catch (JavaModelException x) {
870 throw new CoreException(x.getStatus());
873 return super.createElementInfo(element);
878 * @see AbstractDocumentProvider#disposeElementInfo(Object, ElementInfo)
880 protected void disposeElementInfo(Object element, ElementInfo info) {
882 if (info instanceof CompilationUnitInfo) {
883 CompilationUnitInfo cuInfo = (CompilationUnitInfo) info;
884 cuInfo.fCopy.destroy();
885 cuInfo.fModel.removeAnnotationModelListener(fGlobalAnnotationModelListener);
888 super.disposeElementInfo(element, info);
892 * @see AbstractDocumentProvider#doSaveDocument(IProgressMonitor, Object, IDocument, boolean)
894 protected void doSaveDocument(IProgressMonitor monitor, Object element, IDocument document, boolean overwrite)
895 throws CoreException {
897 ElementInfo elementInfo = getElementInfo(element);
898 if (elementInfo instanceof CompilationUnitInfo) {
899 CompilationUnitInfo info = (CompilationUnitInfo) elementInfo;
901 // update structure, assumes lock on info.fCopy
902 info.fCopy.reconcile();
904 ICompilationUnit original = (ICompilationUnit) info.fCopy.getOriginalElement();
905 IResource resource = original.getResource();
907 if (resource == null) {
908 // underlying resource has been deleted, just recreate file, ignore the rest
909 super.doSaveDocument(monitor, element, document, overwrite);
913 if (resource != null && !overwrite)
914 checkSynchronizationState(info.fModificationStamp, resource);
916 if (fSavePolicy != null)
917 fSavePolicy.preSave(info.fCopy);
919 // inform about the upcoming content change
920 fireElementStateChanging(element);
922 fIsAboutToSave = true;
923 // commit working copy
924 info.fCopy.commit(overwrite, monitor);
925 } catch (CoreException x) {
926 // inform about the failure
927 fireElementStateChangeFailed(element);
929 } catch (RuntimeException x) {
930 // inform about the failure
931 fireElementStateChangeFailed(element);
934 fIsAboutToSave = false;
937 // If here, the dirty state of the editor will change to "not dirty".
938 // Thus, the state changing flag will be reset.
940 AbstractMarkerAnnotationModel model = (AbstractMarkerAnnotationModel) info.fModel;
941 model.updateMarkers(info.fDocument);
943 if (resource != null)
944 info.setModificationStamp(computeModificationStamp(resource));
946 if (fSavePolicy != null) {
947 ICompilationUnit unit = fSavePolicy.postSave(original);
949 IResource r = unit.getResource();
950 IMarker[] markers = r.findMarkers(IMarker.MARKER, true, IResource.DEPTH_ZERO);
951 if (markers != null && markers.length > 0) {
952 for (int i = 0; i < markers.length; i++)
953 model.updateMarker(markers[i], info.fDocument, null);
959 super.doSaveDocument(monitor, element, document, overwrite);
964 * Replaces createAnnotionModel of the super class.
966 protected IAnnotationModel createCompilationUnitAnnotationModel(Object element) throws CoreException {
967 if ( !(element instanceof IFileEditorInput))
968 throw new CoreException(PHPUIStatus.createError(
969 IJavaModelStatusConstants.INVALID_RESOURCE_TYPE, "", null)); //$NON-NLS-1$
971 IFileEditorInput input= (IFileEditorInput) element;
972 return new CompilationUnitAnnotationModel(input);
975 // private IDocumentPartitioner createCSSPartitioner() {
976 // return new DefaultPartitioner(getHTMLPartitionScanner(), TYPES);
980 * Method declared on AbstractDocumentProvider
982 protected IDocument createDocument(Object element) throws CoreException {
983 if (element instanceof IEditorInput) {
984 Document document = new PartiallySynchronizedDocument();
985 if (setDocumentContent(document, (IEditorInput) element, getEncoding(element))) {
986 initializeDocument(document, (IEditorInput) element);
989 // IDocument document = super.createDocument(element);
990 // if (document != null) {
991 // IDocumentPartitioner partitioner = null;
992 // if (element instanceof FileEditorInput) {
993 // IFile file = (IFile) ((FileEditorInput) element).getAdapter(IFile.class);
994 // String filename = file.getLocation().toString();
995 // String extension = filename.substring(filename.lastIndexOf("."), filename.length());
996 // // System.out.println(extension);
997 // if (extension.equalsIgnoreCase(".html") || extension.equalsIgnoreCase(".htm")) {
999 // partitioner = createHTMLPartitioner();
1000 // } else if (extension.equalsIgnoreCase(".xml")) {
1002 // partitioner = createXMLPartitioner();
1003 // } else if (extension.equalsIgnoreCase(".js")) {
1005 // partitioner = createJavaScriptPartitioner();
1006 // } else if (extension.equalsIgnoreCase(".css")) {
1007 // // cascading style sheets
1008 // partitioner = createCSSPartitioner();
1009 // } else if (extension.equalsIgnoreCase(".tpl")) {
1011 // partitioner = createSmartyPartitioner();
1012 // } else if (extension.equalsIgnoreCase(".inc")) {
1013 // // php include files ?
1014 // partitioner = createIncludePartitioner();
1018 // if (partitioner == null) {
1019 // partitioner = createPHPPartitioner();
1021 // document.setDocumentPartitioner(partitioner);
1022 // partitioner.connect(document);
1030 // * Return a partitioner for .html files.
1032 // private IDocumentPartitioner createHTMLPartitioner() {
1033 // return new DefaultPartitioner(getHTMLPartitionScanner(), TYPES);
1036 // private IDocumentPartitioner createIncludePartitioner() {
1037 // return new DefaultPartitioner(getPHPPartitionScanner(), TYPES);
1040 // private IDocumentPartitioner createJavaScriptPartitioner() {
1041 // return new DefaultPartitioner(getHTMLPartitionScanner(), TYPES);
1045 * Creates a line tracker working with the same line delimiters as the document
1046 * of the given element. Assumes the element to be managed by this document provider.
1048 * @param element the element serving as blue print
1049 * @return a line tracker based on the same line delimiters as the element's document
1051 public ILineTracker createLineTracker(Object element) {
1052 return new DefaultLineTracker();
1056 // * Return a partitioner for .php files.
1058 // private IDocumentPartitioner createPHPPartitioner() {
1059 // return new DefaultPartitioner(getPHPPartitionScanner(), TYPES);
1062 // private IDocumentPartitioner createSmartyPartitioner() {
1063 // return new DefaultPartitioner(getSmartyPartitionScanner(), TYPES);
1066 // private IDocumentPartitioner createXMLPartitioner() {
1067 // return new DefaultPartitioner(getXMLPartitionScanner(), TYPES);
1071 // * Return a scanner for creating html partitions.
1073 // private PHPPartitionScanner getHTMLPartitionScanner() {
1074 // if (HTML_PARTITION_SCANNER == null)
1075 // HTML_PARTITION_SCANNER = new PHPPartitionScanner(IPHPPartitionScannerConstants.HTML_FILE);
1076 // return HTML_PARTITION_SCANNER;
1079 // * Return a scanner for creating php partitions.
1081 // private PHPPartitionScanner getPHPPartitionScanner() {
1082 // if (PHP_PARTITION_SCANNER == null)
1083 // PHP_PARTITION_SCANNER = new PHPPartitionScanner(IPHPPartitionScannerConstants.PHP_FILE);
1084 // return PHP_PARTITION_SCANNER;
1088 // * Return a scanner for creating smarty partitions.
1090 // private PHPPartitionScanner getSmartyPartitionScanner() {
1091 // if (SMARTY_PARTITION_SCANNER == null)
1092 // SMARTY_PARTITION_SCANNER = new PHPPartitionScanner(IPHPPartitionScannerConstants.SMARTY_FILE);
1093 // return SMARTY_PARTITION_SCANNER;
1097 // * Return a scanner for creating xml partitions.
1099 // private PHPPartitionScanner getXMLPartitionScanner() {
1100 // if (XML_PARTITION_SCANNER == null)
1101 // XML_PARTITION_SCANNER = new PHPPartitionScanner(IPHPPartitionScannerConstants.XML_FILE);
1102 // return XML_PARTITION_SCANNER;
1105 protected void initializeDocument(IDocument document, IEditorInput editorInput) {
1106 if (document != null) {
1107 JavaTextTools tools = PHPeclipsePlugin.getDefault().getJavaTextTools();
1108 IDocumentPartitioner partitioner = null;
1109 if (editorInput != null && editorInput instanceof FileEditorInput) {
1110 IFile file = (IFile) ((FileEditorInput) editorInput).getAdapter(IFile.class);
1111 String filename = file.getLocation().toString();
1112 String extension = filename.substring(filename.lastIndexOf("."), filename.length());
1113 partitioner = tools.createDocumentPartitioner(extension);
1115 partitioner = tools.createDocumentPartitioner(".php");
1117 document.setDocumentPartitioner(partitioner);
1118 partitioner.connect(document);
1123 * @see AbstractDocumentProvider#resetDocument(Object)
1125 public void resetDocument(Object element) throws CoreException {
1126 if (element == null)
1129 ElementInfo elementInfo = getElementInfo(element);
1130 if (elementInfo instanceof CompilationUnitInfo) {
1131 CompilationUnitInfo info = (CompilationUnitInfo) elementInfo;
1134 IStatus status = null;
1138 ICompilationUnit original = (ICompilationUnit) info.fCopy.getOriginalElement();
1139 IResource resource = original.getResource();
1140 if (resource instanceof IFile) {
1142 IFile file = (IFile) resource;
1146 } catch (CoreException x) {
1147 handleCoreException(x, PHPEditorMessages.getString("PHPDocumentProvider.error.resetDocument")); //$NON-NLS-1$
1150 IFileEditorInput input = new FileEditorInput(file);
1151 document = super.createDocument(input);
1154 document = new Document();
1157 } catch (CoreException x) {
1158 document = new Document();
1159 status = x.getStatus();
1162 fireElementContentAboutToBeReplaced(element);
1164 removeUnchangedElementListeners(element, info);
1165 info.fDocument.set(document.get());
1166 info.fCanBeSaved = false;
1167 info.fStatus = status;
1168 addUnchangedElementListeners(element, info);
1170 fireElementContentReplaced(element);
1171 fireElementDirtyStateChanged(element, false);
1174 super.resetDocument(element);
1178 * Saves the content of the given document to the given element.
1179 * This is only performed when this provider initiated the save.
1181 * @param monitor the progress monitor
1182 * @param element the element to which to save
1183 * @param document the document to save
1184 * @param overwrite <code>true</code> if the save should be enforced
1186 public void saveDocumentContent(IProgressMonitor monitor, Object element, IDocument document, boolean overwrite)
1187 throws CoreException {
1189 if (!fIsAboutToSave)
1192 if (element instanceof IFileEditorInput) {
1193 IFileEditorInput input = (IFileEditorInput) element;
1195 String encoding = getEncoding(element);
1196 if (encoding == null)
1197 encoding = ResourcesPlugin.getEncoding();
1198 InputStream stream = new ByteArrayInputStream(document.get().getBytes(encoding));
1199 IFile file = input.getFile();
1200 file.setContents(stream, overwrite, true, monitor);
1201 } catch (IOException x) {
1202 IStatus s = new Status(IStatus.ERROR, PHPeclipsePlugin.PLUGIN_ID, IStatus.OK, x.getMessage(), x);
1203 throw new CoreException(s);
1208 * Returns the underlying resource for the given element.
1210 * @param the element
1211 * @return the underlying resource of the given element
1213 public IResource getUnderlyingResource(Object element) {
1214 if (element instanceof IFileEditorInput) {
1215 IFileEditorInput input = (IFileEditorInput) element;
1216 return input.getFile();
1222 * Returns the working copy this document provider maintains for the given
1225 * @param element the given element
1226 * @return the working copy for the given element
1228 ICompilationUnit getWorkingCopy(IEditorInput element) {
1230 ElementInfo elementInfo = getElementInfo(element);
1231 if (elementInfo instanceof CompilationUnitInfo) {
1232 CompilationUnitInfo info = (CompilationUnitInfo) elementInfo;
1240 * Gets the BufferFactory.
1242 public IBufferFactory getBufferFactory() {
1243 return fBufferFactory;
1247 * Shuts down this document provider.
1249 public void shutdown() {
1251 PHPeclipsePlugin.getDefault().getPreferenceStore().removePropertyChangeListener(fPropertyListener);
1253 Iterator e = getConnectedElements();
1255 disconnect(e.next());
1259 * Returns the preference whether handling temporary problems is enabled.
1261 protected boolean isHandlingTemporaryProblems() {
1262 IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
1263 return store.getBoolean(HANDLE_TEMPORARY_PROBLEMS);
1267 * Switches the state of problem acceptance according to the value in the preference store.
1269 protected void enableHandlingTemporaryProblems() {
1270 boolean enable = isHandlingTemporaryProblems();
1271 for (Iterator iter = getConnectedElements(); iter.hasNext();) {
1272 ElementInfo element = getElementInfo(iter.next());
1273 if (element instanceof CompilationUnitInfo) {
1274 CompilationUnitInfo info = (CompilationUnitInfo) element;
1275 if (info.fModel instanceof IProblemRequestorExtension) {
1276 IProblemRequestorExtension extension = (IProblemRequestorExtension) info.fModel;
1277 extension.setIsActive(enable);
1284 * Adds a listener that reports changes from all compilation unit annotation models.
1286 public void addGlobalAnnotationModelListener(IAnnotationModelListener listener) {
1287 fGlobalAnnotationModelListener.addListener(listener);
1291 * Removes the listener.
1293 public void removeGlobalAnnotationModelListener(IAnnotationModelListener listener) {
1294 fGlobalAnnotationModelListener.removeListener(listener);
1298 * Returns whether the given element is connected to this document provider.
1300 * @param element the element
1301 * @return <code>true</code> if the element is connected, <code>false</code> otherwise
1303 boolean isConnected(Object element) {
1304 return getElementInfo(element) != null;