X-Git-Url: http://secure.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPDocumentProvider.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPDocumentProvider.java index 2fa0115..891f7f2 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPDocumentProvider.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPDocumentProvider.java @@ -12,18 +12,38 @@ Contributors: Klaus Hartlage - www.eclipseproject.de **********************************************************************/ +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import net.sourceforge.phpdt.core.IProblemRequestor; +import net.sourceforge.phpdt.core.compiler.IProblem; +import net.sourceforge.phpdt.internal.ui.text.java.IProblemRequestorExtension; import net.sourceforge.phpeclipse.phpeditor.php.IPHPPartitionScannerConstants; import net.sourceforge.phpeclipse.phpeditor.php.PHPPartitionScanner; import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IMarkerDelta; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.text.DefaultLineTracker; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IDocumentPartitioner; import org.eclipse.jface.text.ILineTracker; +import org.eclipse.jface.text.Position; import org.eclipse.jface.text.rules.DefaultPartitioner; +import org.eclipse.jface.text.source.Annotation; +import org.eclipse.jface.text.source.AnnotationModelEvent; +import org.eclipse.jface.text.source.IAnnotationModel; +import org.eclipse.jface.text.source.IAnnotationModelListener; +import org.eclipse.jface.text.source.IAnnotationModelListenerExtension; +import org.eclipse.jface.util.ListenerList; +import org.eclipse.ui.IFileEditorInput; import org.eclipse.ui.editors.text.FileDocumentProvider; import org.eclipse.ui.part.FileEditorInput; +import org.eclipse.ui.texteditor.MarkerAnnotation; +import org.eclipse.ui.texteditor.ResourceMarkerAnnotationModel; /** * The PHPDocumentProvider provides the IDocuments used by java editors. @@ -39,12 +59,421 @@ public class PHPDocumentProvider extends FileDocumentProvider { IPHPPartitionScannerConstants.HTML, IPHPPartitionScannerConstants.HTML_MULTILINE_COMMENT, IPHPPartitionScannerConstants.JAVASCRIPT, - IPHPPartitionScannerConstants.CSS }; + IPHPPartitionScannerConstants.CSS, + IPHPPartitionScannerConstants.SMARTY, + IPHPPartitionScannerConstants.SMARTY_MULTILINE_COMMENT }; + + private static PHPPartitionScanner PHP_PARTITION_SCANNER = null; + private static PHPPartitionScanner HTML_PARTITION_SCANNER = null; + private static PHPPartitionScanner XML_PARTITION_SCANNER = null; + private static PHPPartitionScanner SMARTY_PARTITION_SCANNER = null; + + /** annotation model listener added to all created CU annotation models */ + // private GlobalAnnotationModelListener fGlobalAnnotationModelListener; + + /** + * Internal structure for mapping positions to some value. + * The reason for this specific structure is that positions can + * change over time. Thus a lookup is based on value and not + * on hash value. + */ + protected static class ReverseMap { + + static class Entry { + Position fPosition; + Object fValue; + }; + + private List fList = new ArrayList(2); + private int fAnchor = 0; + + public ReverseMap() { + } + + public Object get(Position position) { + + Entry entry; + + // behind anchor + int length = fList.size(); + for (int i = fAnchor; i < length; i++) { + entry = (Entry) fList.get(i); + if (entry.fPosition.equals(position)) { + fAnchor = i; + return entry.fValue; + } + } + + // before anchor + for (int i = 0; i < fAnchor; i++) { + entry = (Entry) fList.get(i); + if (entry.fPosition.equals(position)) { + fAnchor = i; + return entry.fValue; + } + } - private static PHPPartitionScanner fgScanner = null; + return null; + } + + private int getIndex(Position position) { + Entry entry; + int length = fList.size(); + for (int i = 0; i < length; i++) { + entry = (Entry) fList.get(i); + if (entry.fPosition.equals(position)) + return i; + } + return -1; + } + + public void put(Position position, Object value) { + int index = getIndex(position); + if (index == -1) { + Entry entry = new Entry(); + entry.fPosition = position; + entry.fValue = value; + fList.add(entry); + } else { + Entry entry = (Entry) fList.get(index); + entry.fValue = value; + } + } + + public void remove(Position position) { + int index = getIndex(position); + if (index > -1) + fList.remove(index); + } + + public void clear() { + fList.clear(); + } + }; + + /** + * Annotation model dealing with java marker annotations and temporary problems. + * Also acts as problem requestor for its compilation unit. Initialiy inactive. Must explicitly be + * activated. + */ + protected class CompilationUnitAnnotationModel + extends ResourceMarkerAnnotationModel + implements IProblemRequestor, IProblemRequestorExtension { + + private IFileEditorInput fInput; + private List fCollectedProblems; + private List fGeneratedAnnotations; + private IProgressMonitor fProgressMonitor; + private boolean fIsActive = false; + + private ReverseMap fReverseMap = new ReverseMap(); + private List fPreviouslyOverlaid = null; + private List fCurrentlyOverlaid = new ArrayList(); + + public CompilationUnitAnnotationModel(IFileEditorInput input) { + super(input.getFile()); + fInput = input; + } + + protected MarkerAnnotation createMarkerAnnotation(IMarker marker) { + return new JavaMarkerAnnotation(marker); + } + + protected Position createPositionFromProblem(IProblem problem) { + int start = problem.getSourceStart(); + if (start < 0) + return null; + + int length = problem.getSourceEnd() - problem.getSourceStart() + 1; + if (length < 0) + return null; + + return new Position(start, length); + } + + protected void update(IMarkerDelta[] markerDeltas) { + + super.update(markerDeltas); + + // if (markerDeltas != null && markerDeltas.length > 0) { + // try { + // ICompilationUnit workingCopy = getWorkingCopy(fInput); + // if (workingCopy != null) + // workingCopy.reconcile(true, null); + // } catch (JavaModelException ex) { + // handleCoreException(ex, ex.getMessage()); + // } + // } + } + + /* + * @see IProblemRequestor#beginReporting() + */ + public void beginReporting() { + // ICompilationUnit unit= getWorkingCopy(fInput); + // if (unit != null && unit.getJavaProject().isOnClasspath(unit)) + // fCollectedProblems= new ArrayList(); + // else + fCollectedProblems = null; + } + + /* + * @see IProblemRequestor#acceptProblem(IProblem) + */ + public void acceptProblem(IProblem problem) { + if (isActive()) + fCollectedProblems.add(problem); + } + + /* + * @see IProblemRequestor#endReporting() + */ + public void endReporting() { + if (!isActive()) + return; + + if (fProgressMonitor != null && fProgressMonitor.isCanceled()) + return; + + boolean isCanceled = false; + boolean temporaryProblemsChanged = false; + fPreviouslyOverlaid = fCurrentlyOverlaid; + fCurrentlyOverlaid = new ArrayList(); + + synchronized (fAnnotations) { + + if (fGeneratedAnnotations.size() > 0) { + temporaryProblemsChanged = true; + removeAnnotations(fGeneratedAnnotations, false, true); + fGeneratedAnnotations.clear(); + } + + if (fCollectedProblems != null && fCollectedProblems.size() > 0) { + + Iterator e = fCollectedProblems.iterator(); + while (e.hasNext()) { + + IProblem problem = (IProblem) e.next(); + + if (fProgressMonitor != null && fProgressMonitor.isCanceled()) { + isCanceled = true; + break; + } + + Position position = createPositionFromProblem(problem); + if (position != null) { + + // ProblemAnnotation annotation= new ProblemAnnotation(problem); + // overlayMarkers(position, annotation); + // fGeneratedAnnotations.add(annotation); + // addAnnotation(annotation, position, false); + + temporaryProblemsChanged = true; + } + } + + fCollectedProblems.clear(); + } + + removeMarkerOverlays(isCanceled); + fPreviouslyOverlaid.clear(); + fPreviouslyOverlaid = null; + } + + // if (temporaryProblemsChanged) + // fireModelChanged(new CompilationUnitAnnotationModelEvent(this, getResource(), false)); + } + + private void removeMarkerOverlays(boolean isCanceled) { + if (isCanceled) { + fCurrentlyOverlaid.addAll(fPreviouslyOverlaid); + } else if (fPreviouslyOverlaid != null) { + Iterator e = fPreviouslyOverlaid.iterator(); + while (e.hasNext()) { + JavaMarkerAnnotation annotation = (JavaMarkerAnnotation) e.next(); + annotation.setOverlay(null); + } + } + } + + /** + * Overlays value with problem annotation. + * @param problemAnnotation + */ + // private void setOverlay(Object value, ProblemAnnotation problemAnnotation) { + // if (value instanceof JavaMarkerAnnotation) { + // JavaMarkerAnnotation annotation= (JavaMarkerAnnotation) value; + // if (annotation.isProblem()) { + // annotation.setOverlay(problemAnnotation); + // fPreviouslyOverlaid.remove(annotation); + // fCurrentlyOverlaid.add(annotation); + // } + // } + // } + + // private void overlayMarkers(Position position, ProblemAnnotation problemAnnotation) { + // Object value= getAnnotations(position); + // if (value instanceof List) { + // List list= (List) value; + // for (Iterator e = list.iterator(); e.hasNext();) + // setOverlay(e.next(), problemAnnotation); + // } else { + // setOverlay(value, problemAnnotation); + // } + // } + + /** + * Tells this annotation model to collect temporary problems from now on. + */ + private void startCollectingProblems() { + fCollectedProblems = new ArrayList(); + fGeneratedAnnotations = new ArrayList(); + } + + /** + * Tells this annotation model to no longer collect temporary problems. + */ + private void stopCollectingProblems() { + if (fGeneratedAnnotations != null) { + removeAnnotations(fGeneratedAnnotations, true, true); + fGeneratedAnnotations.clear(); + } + fCollectedProblems = null; + fGeneratedAnnotations = null; + } + + /* + * @see AnnotationModel#fireModelChanged() + */ + // protected void fireModelChanged() { + // fireModelChanged(new CompilationUnitAnnotationModelEvent(this, getResource(), true)); + // } + + /* + * @see IProblemRequestor#isActive() + */ + public boolean isActive() { + return fIsActive && (fCollectedProblems != null); + } + + /* + * @see IProblemRequestorExtension#setProgressMonitor(IProgressMonitor) + */ + public void setProgressMonitor(IProgressMonitor monitor) { + fProgressMonitor = monitor; + } + + /* + * @see IProblemRequestorExtension#setIsActive(boolean) + */ + public void setIsActive(boolean isActive) { + if (fIsActive != isActive) { + fIsActive = isActive; + if (fIsActive) + startCollectingProblems(); + else + stopCollectingProblems(); + } + } + + private Object getAnnotations(Position position) { + return fReverseMap.get(position); + } + + /* + * @see AnnotationModel#addAnnotation(Annotation, Position, boolean) + */ + protected void addAnnotation(Annotation annotation, Position position, boolean fireModelChanged) { + super.addAnnotation(annotation, position, fireModelChanged); + + Object cached = fReverseMap.get(position); + if (cached == null) + fReverseMap.put(position, annotation); + else if (cached instanceof List) { + List list = (List) cached; + list.add(annotation); + } else if (cached instanceof Annotation) { + List list = new ArrayList(2); + list.add(cached); + list.add(annotation); + fReverseMap.put(position, list); + } + } + + /* + * @see AnnotationModel#removeAllAnnotations(boolean) + */ + protected void removeAllAnnotations(boolean fireModelChanged) { + super.removeAllAnnotations(fireModelChanged); + fReverseMap.clear(); + } + + /* + * @see AnnotationModel#removeAnnotation(Annotation, boolean) + */ + protected void removeAnnotation(Annotation annotation, boolean fireModelChanged) { + Position position = getPosition(annotation); + Object cached = fReverseMap.get(position); + if (cached instanceof List) { + List list = (List) cached; + list.remove(annotation); + if (list.size() == 1) { + fReverseMap.put(position, list.get(0)); + list.clear(); + } + } else if (cached instanceof Annotation) { + fReverseMap.remove(position); + } + + super.removeAnnotation(annotation, fireModelChanged); + } + }; + + protected static class GlobalAnnotationModelListener implements IAnnotationModelListener, IAnnotationModelListenerExtension { + + private ListenerList fListenerList; + + public GlobalAnnotationModelListener() { + fListenerList = new ListenerList(); + } + + /** + * @see IAnnotationModelListener#modelChanged(IAnnotationModel) + */ + public void modelChanged(IAnnotationModel model) { + Object[] listeners = fListenerList.getListeners(); + for (int i = 0; i < listeners.length; i++) { + ((IAnnotationModelListener) listeners[i]).modelChanged(model); + } + } + + /** + * @see IAnnotationModelListenerExtension#modelChanged(AnnotationModelEvent) + */ + public void modelChanged(AnnotationModelEvent event) { + Object[] listeners = fListenerList.getListeners(); + for (int i = 0; i < listeners.length; i++) { + Object curr = listeners[i]; + if (curr instanceof IAnnotationModelListenerExtension) { + ((IAnnotationModelListenerExtension) curr).modelChanged(event); + } + } + } + + public void addListener(IAnnotationModelListener listener) { + fListenerList.add(listener); + } + + public void removeListener(IAnnotationModelListener listener) { + fListenerList.remove(listener); + } + }; public PHPDocumentProvider() { super(); + + // fGlobalAnnotationModelListener= new GlobalAnnotationModelListener(); + } /* (non-Javadoc) @@ -59,7 +488,7 @@ public class PHPDocumentProvider extends FileDocumentProvider { IFile file = (IFile) ((FileEditorInput) element).getAdapter(IFile.class); String filename = file.getLocation().toString(); String extension = filename.substring(filename.lastIndexOf("."), filename.length()); - // System.out.println(extension); + // System.out.println(extension); if (extension.equalsIgnoreCase(".html") || extension.equalsIgnoreCase(".htm")) { // html partitioner = createHTMLPartitioner(); @@ -101,23 +530,23 @@ public class PHPDocumentProvider extends FileDocumentProvider { * Return a partitioner for .html files. */ private IDocumentPartitioner createHTMLPartitioner() { - return new DefaultPartitioner(getPHPPartitionScanner(), TYPES); + return new DefaultPartitioner(getHTMLPartitionScanner(), TYPES); } private IDocumentPartitioner createXMLPartitioner() { - return new DefaultPartitioner(getPHPPartitionScanner(), TYPES); + return new DefaultPartitioner(getXMLPartitionScanner(), TYPES); } private IDocumentPartitioner createJavaScriptPartitioner() { - return new DefaultPartitioner(getPHPPartitionScanner(), TYPES); + return new DefaultPartitioner(getHTMLPartitionScanner(), TYPES); } private IDocumentPartitioner createCSSPartitioner() { - return new DefaultPartitioner(getPHPPartitionScanner(), TYPES); + return new DefaultPartitioner(getHTMLPartitionScanner(), TYPES); } private IDocumentPartitioner createSmartyPartitioner() { - return new DefaultPartitioner(getPHPPartitionScanner(), TYPES); + return new DefaultPartitioner(getSmartyPartitionScanner(), TYPES); } private IDocumentPartitioner createIncludePartitioner() { @@ -127,9 +556,36 @@ public class PHPDocumentProvider extends FileDocumentProvider { * Return a scanner for creating php partitions. */ private PHPPartitionScanner getPHPPartitionScanner() { - if (fgScanner == null) - fgScanner = new PHPPartitionScanner(); - return fgScanner; + if (PHP_PARTITION_SCANNER == null) + PHP_PARTITION_SCANNER = new PHPPartitionScanner(IPHPPartitionScannerConstants.PHP_FILE); + return PHP_PARTITION_SCANNER; + } + + /** + * Return a scanner for creating html partitions. + */ + private PHPPartitionScanner getHTMLPartitionScanner() { + if (HTML_PARTITION_SCANNER == null) + HTML_PARTITION_SCANNER = new PHPPartitionScanner(IPHPPartitionScannerConstants.HTML_FILE); + return HTML_PARTITION_SCANNER; + } + + /** + * Return a scanner for creating xml partitions. + */ + private PHPPartitionScanner getXMLPartitionScanner() { + if (XML_PARTITION_SCANNER == null) + XML_PARTITION_SCANNER = new PHPPartitionScanner(IPHPPartitionScannerConstants.XML_FILE); + return XML_PARTITION_SCANNER; + } + + /** + * Return a scanner for creating smarty partitions. + */ + private PHPPartitionScanner getSmartyPartitionScanner() { + if (SMARTY_PARTITION_SCANNER == null) + SMARTY_PARTITION_SCANNER = new PHPPartitionScanner(IPHPPartitionScannerConstants.SMARTY_FILE); + return SMARTY_PARTITION_SCANNER; } /**