X-Git-Url: http://git.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/JavaReconciler.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/JavaReconciler.java index 880922e..11bf1c3 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/JavaReconciler.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/JavaReconciler.java @@ -11,125 +11,452 @@ package net.sourceforge.phpdt.internal.ui.text; +import net.sourceforge.phpdt.core.ElementChangedEvent; +import net.sourceforge.phpdt.core.IElementChangedListener; +import net.sourceforge.phpdt.core.JavaCore; +import net.sourceforge.phpeclipse.PHPeclipsePlugin; +import net.sourceforge.phpeclipse.phpeditor.PHPUnitEditor; -import net.sourceforge.phpdt.internal.ui.text.java.JavaReconcilingStrategy; - +import org.eclipse.core.resources.IMarkerDelta; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceChangeEvent; +import org.eclipse.core.resources.IResourceChangeListener; +import org.eclipse.core.resources.IResourceDelta; +import org.eclipse.core.resources.IWorkspace; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.ITextViewer; -import org.eclipse.jface.text.reconciler.IReconcilingStrategy; +import org.eclipse.jface.text.reconciler.DirtyRegion; import org.eclipse.jface.text.reconciler.MonoReconciler; +import org.eclipse.swt.events.ShellAdapter; +import org.eclipse.swt.events.ShellEvent; +import org.eclipse.swt.events.ShellListener; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IFileEditorInput; import org.eclipse.ui.IPartListener; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchPartSite; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.texteditor.ITextEditor; - - /** * A reconciler that is also activated on editor activation. */ public class JavaReconciler extends MonoReconciler { - + /** * Internal part listener for activating the reconciler. */ - class PartListener implements IPartListener { - + private class PartListener implements IPartListener { + /* - * @see IPartListener#partActivated(IWorkbenchPart) + * @see org.eclipse.ui.IPartListener#partActivated(org.eclipse.ui.IWorkbenchPart) */ public void partActivated(IWorkbenchPart part) { - if (part == fTextEditor) + if (part == fTextEditor && hasJavaModelChanged()) JavaReconciler.this.forceReconciling(); } /* - * @see IPartListener#partBroughtToTop(IWorkbenchPart) + * @see org.eclipse.ui.IPartListener#partBroughtToTop(org.eclipse.ui.IWorkbenchPart) */ public void partBroughtToTop(IWorkbenchPart part) { } /* - * @see IPartListener#partClosed(IWorkbenchPart) + * @see org.eclipse.ui.IPartListener#partClosed(org.eclipse.ui.IWorkbenchPart) */ public void partClosed(IWorkbenchPart part) { } /* - * @see IPartListener#partDeactivated(IWorkbenchPart) + * @see org.eclipse.ui.IPartListener#partDeactivated(org.eclipse.ui.IWorkbenchPart) */ public void partDeactivated(IWorkbenchPart part) { + if (part == fTextEditor) + setJavaModelChanged(false); } /* - * @see IPartListener#partOpened(IWorkbenchPart) + * @see org.eclipse.ui.IPartListener#partOpened(org.eclipse.ui.IWorkbenchPart) */ public void partOpened(IWorkbenchPart part) { } - }; - - + } + + /** + * Internal Shell activation listener for activating the reconciler. + */ + private class ActivationListener extends ShellAdapter { + + private Control fControl; + + public ActivationListener(Control control) { + fControl = control; + } + + /* + * @see org.eclipse.swt.events.ShellListener#shellActivated(org.eclipse.swt.events.ShellEvent) + */ + public void shellActivated(ShellEvent e) { + if (!fControl.isDisposed() && fControl.isVisible() + && hasJavaModelChanged()) + JavaReconciler.this.forceReconciling(); + } + + /* + * @see org.eclipse.swt.events.ShellListener#shellDeactivated(org.eclipse.swt.events.ShellEvent) + */ + public void shellDeactivated(ShellEvent e) { + setJavaModelChanged(false); + } + } + + /** + * Internal Java element changed listener + * + * @since 3.0 + */ + private class ElementChangedListener implements IElementChangedListener { + /* + * @see net.sourceforge.phpdt.core.IElementChangedListener#elementChanged(net.sourceforge.phpdt.core.ElementChangedEvent) + */ + public void elementChanged(ElementChangedEvent event) { + setJavaModelChanged(true); + } + } + + /** + * Internal resource change listener. + * + * @since 3.0 + */ + class ResourceChangeListener implements IResourceChangeListener { + + private IResource getResource() { + IEditorInput input = fTextEditor.getEditorInput(); + if (input instanceof IFileEditorInput) { + IFileEditorInput fileInput = (IFileEditorInput) input; + return fileInput.getFile(); + } + return null; + } + + /* + * @see IResourceChangeListener#resourceChanged(org.eclipse.core.resources.IResourceChangeEvent) + */ + public void resourceChanged(IResourceChangeEvent e) { + IResourceDelta delta = e.getDelta(); + IResource resource = getResource(); + if (delta != null && resource != null) { + IResourceDelta child = delta.findMember(resource.getFullPath()); + if (child != null) { + IMarkerDelta[] deltas = child.getMarkerDeltas(); + if (deltas.length > 0) + forceReconciling(); + } + } + } + } + /** The reconciler's editor */ private ITextEditor fTextEditor; + /** The part listener */ private IPartListener fPartListener; - - + + /** The shell listener */ + private ShellListener fActivationListener; + + /** + * The mutex that keeps us from running multiple reconcilers on one editor. + * TODO remove once we have ensured that there is only one reconciler per + * editor. + */ + private Object fMutex; + + /** + * The Java element changed listener. + * + * @since 3.0 + */ + private IElementChangedListener fJavaElementChangedListener; + + /** + * Tells whether the Java model sent out a changed event. + * + * @since 3.0 + */ + private volatile boolean fHasJavaModelChanged = true; + + /** + * The resource change listener. + * + * @since 3.0 + */ + private IResourceChangeListener fResourceChangeListener; + + private boolean fIninitalProcessDone = false; + /** * Creates a new reconciler. */ - public JavaReconciler(ITextEditor editor, IReconcilingStrategy strategy, boolean isIncremental) { + public JavaReconciler(ITextEditor editor, + JavaCompositeReconcilingStrategy strategy, boolean isIncremental) { super(strategy, isIncremental); - fTextEditor= editor; + fTextEditor = editor; + + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=63898 + // when re-using editors, a new reconciler is set up by the source + // viewer + // and the old one uninstalled. However, the old reconciler may still be + // running. + // To avoid having to reconcilers calling + // CompilationUnitEditor.reconciled, + // we synchronized on a lock object provided by the editor. + // The critical section is really the entire run() method of the + // reconciler + // thread, but synchronizing process() only will keep + // JavaReconcilingStrategy + // from running concurrently on the same editor. + // TODO remove once we have ensured that there is only one reconciler + // per editor. + if (editor instanceof PHPUnitEditor) + fMutex = ((PHPUnitEditor) editor).getReconcilerLock(); + else + fMutex = new Object(); // Null Object } - + /* - * @see IReconciler#install(ITextViewer) + * @see org.eclipse.jface.text.reconciler.IReconciler#install(org.eclipse.jface.text.ITextViewer) */ public void install(ITextViewer textViewer) { super.install(textViewer); - - fPartListener= new PartListener(); - IWorkbenchPartSite site= fTextEditor.getSite(); - IWorkbenchWindow window= site.getWorkbenchWindow(); + + fPartListener = new PartListener(); + IWorkbenchPartSite site = fTextEditor.getSite(); + IWorkbenchWindow window = site.getWorkbenchWindow(); window.getPartService().addPartListener(fPartListener); + + fActivationListener = new ActivationListener(textViewer.getTextWidget()); + Shell shell = window.getShell(); + shell.addShellListener(fActivationListener); + + fJavaElementChangedListener = new ElementChangedListener(); + JavaCore.addElementChangedListener(fJavaElementChangedListener); + + fResourceChangeListener = new ResourceChangeListener(); + IWorkspace workspace = PHPeclipsePlugin.getWorkspace(); + workspace.addResourceChangeListener(fResourceChangeListener); } /* - * @see IReconciler#uninstall() + * @see org.eclipse.jface.text.reconciler.IReconciler#uninstall() */ public void uninstall() { - - IWorkbenchPartSite site= fTextEditor.getSite(); - IWorkbenchWindow window= site.getWorkbenchWindow(); + + IWorkbenchPartSite site = fTextEditor.getSite(); + IWorkbenchWindow window = site.getWorkbenchWindow(); window.getPartService().removePartListener(fPartListener); - fPartListener= null; - + fPartListener = null; + + Shell shell = window.getShell(); + if (shell != null && !shell.isDisposed()) + shell.removeShellListener(fActivationListener); + fActivationListener = null; + + JavaCore.removeElementChangedListener(fJavaElementChangedListener); + fJavaElementChangedListener = null; + + IWorkspace workspace = PHPeclipsePlugin.getWorkspace(); + workspace.removeResourceChangeListener(fResourceChangeListener); + fResourceChangeListener = null; + super.uninstall(); } - - /* - * @see AbstractReconciler#forceReconciling() + + /* + * @see org.eclipse.jface.text.reconciler.AbstractReconciler#forceReconciling() */ protected void forceReconciling() { + if (!fIninitalProcessDone) + return; + super.forceReconciling(); - IReconcilingStrategy strategy= getReconcilingStrategy(IDocument.DEFAULT_CONTENT_TYPE); - if (strategy instanceof JavaReconcilingStrategy) { - JavaReconcilingStrategy java= (JavaReconcilingStrategy) strategy; - java.notifyParticipants(false); - } + JavaCompositeReconcilingStrategy strategy = (JavaCompositeReconcilingStrategy) getReconcilingStrategy(IDocument.DEFAULT_CONTENT_TYPE); + strategy.notifyListeners(false); + } + + /* + * @see org.eclipse.jface.text.reconciler.AbstractReconciler#aboutToReconcile() + * @since 3.0 + */ + protected void aboutToBeReconciled() { + JavaCompositeReconcilingStrategy strategy = (JavaCompositeReconcilingStrategy) getReconcilingStrategy(IDocument.DEFAULT_CONTENT_TYPE); + strategy.aboutToBeReconciled(); } - + /* - * @see AbstractReconciler#reconcilerReset() + * @see org.eclipse.jface.text.reconciler.AbstractReconciler#reconcilerReset() */ protected void reconcilerReset() { super.reconcilerReset(); - IReconcilingStrategy strategy= getReconcilingStrategy(IDocument.DEFAULT_CONTENT_TYPE); - if (strategy instanceof JavaReconcilingStrategy) { - JavaReconcilingStrategy java= (JavaReconcilingStrategy) strategy; - java.notifyParticipants(true); + JavaCompositeReconcilingStrategy strategy = (JavaCompositeReconcilingStrategy) getReconcilingStrategy(IDocument.DEFAULT_CONTENT_TYPE); + strategy.notifyListeners(true); + } + + /* + * @see org.eclipse.jface.text.reconciler.MonoReconciler#initialProcess() + */ + protected void initialProcess() { + // TODO remove once we have ensured that there is only one reconciler + // per editor. + synchronized (fMutex) { + super.initialProcess(); } + fIninitalProcessDone = true; + } + + /* + * @see org.eclipse.jface.text.reconciler.MonoReconciler#process(org.eclipse.jface.text.reconciler.DirtyRegion) + */ + protected void process(DirtyRegion dirtyRegion) { + // TODO remove once we have ensured that there is only one reconciler + // per editor. + synchronized (fMutex) { + super.process(dirtyRegion); + } + } + + /** + * Tells whether the Java Model has changed or not. + * + * @return true iff the Java Model has changed + * @since 3.0 + */ + private synchronized boolean hasJavaModelChanged() { + return fHasJavaModelChanged; + } + + /** + * Sets whether the Java Model has changed or not. + * + * @param state + * true iff the java model has changed + * @since 3.0 + */ + private synchronized void setJavaModelChanged(boolean state) { + fHasJavaModelChanged = state; } } +// /** +// * A reconciler that is also activated on editor activation. +// */ +// public class JavaReconciler extends MonoReconciler { +// +// /** +// * Internal part listener for activating the reconciler. +// */ +// class PartListener implements IPartListener { +// +// /* +// * @see IPartListener#partActivated(IWorkbenchPart) +// */ +// public void partActivated(IWorkbenchPart part) { +// if (part == fTextEditor) +// JavaReconciler.this.forceReconciling(); +// } +// +// /* +// * @see IPartListener#partBroughtToTop(IWorkbenchPart) +// */ +// public void partBroughtToTop(IWorkbenchPart part) { +// } +// +// /* +// * @see IPartListener#partClosed(IWorkbenchPart) +// */ +// public void partClosed(IWorkbenchPart part) { +// } +// +// /* +// * @see IPartListener#partDeactivated(IWorkbenchPart) +// */ +// public void partDeactivated(IWorkbenchPart part) { +// } +// +// /* +// * @see IPartListener#partOpened(IWorkbenchPart) +// */ +// public void partOpened(IWorkbenchPart part) { +// } +// }; +// +// +// /** The reconciler's editor */ +// private ITextEditor fTextEditor; +// /** The part listener */ +// private IPartListener fPartListener; +// +// +// /** +// * Creates a new reconciler. +// */ +// public JavaReconciler(ITextEditor editor, IReconcilingStrategy strategy, +// boolean isIncremental) { +// super(strategy, isIncremental); +// fTextEditor= editor; +// } +// +// /* +// * @see IReconciler#install(ITextViewer) +// */ +// public void install(ITextViewer textViewer) { +// super.install(textViewer); +// +// fPartListener= new PartListener(); +// IWorkbenchPartSite site= fTextEditor.getSite(); +// IWorkbenchWindow window= site.getWorkbenchWindow(); +// window.getPartService().addPartListener(fPartListener); +// } +// +// /* +// * @see IReconciler#uninstall() +// */ +// public void uninstall() { +// +// IWorkbenchPartSite site= fTextEditor.getSite(); +// IWorkbenchWindow window= site.getWorkbenchWindow(); +// window.getPartService().removePartListener(fPartListener); +// fPartListener= null; +// +// super.uninstall(); +// } +// +// /* +// * @see AbstractReconciler#forceReconciling() +// */ +// protected void forceReconciling() { +// super.forceReconciling(); +// IReconcilingStrategy strategy= +// getReconcilingStrategy(IDocument.DEFAULT_CONTENT_TYPE); +// if (strategy instanceof JavaReconcilingStrategy) { +// JavaReconcilingStrategy java= (JavaReconcilingStrategy) strategy; +// java.notifyParticipants(false); +// } +// } +// +// /* +// * @see AbstractReconciler#reconcilerReset() +// */ +// protected void reconcilerReset() { +// super.reconcilerReset(); +// IReconcilingStrategy strategy= +// getReconcilingStrategy(IDocument.DEFAULT_CONTENT_TYPE); +// if (strategy instanceof JavaReconcilingStrategy) { +// JavaReconcilingStrategy java= (JavaReconcilingStrategy) strategy; +// java.notifyParticipants(true); +// } +// } +// }