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