misc changes
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / ui / text / JavaReconciler.java
index 880922e..a2f5b2c 100644 (file)
 package net.sourceforge.phpdt.internal.ui.text;
 
 
-import net.sourceforge.phpdt.internal.ui.text.java.JavaReconcilingStrategy;
+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 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;
@@ -25,7 +42,6 @@ import org.eclipse.ui.IWorkbenchWindow;
 import org.eclipse.ui.texteditor.ITextEditor;
 
 
 /**
  * A reconciler that is also activated on editor activation.
  */
@@ -34,58 +50,171 @@ 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 org.eclipse.jdt.core.IElementChangedListener#elementChanged(org.eclipse.jdt.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;
+               
+               // 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);
@@ -94,10 +223,21 @@ public class JavaReconciler extends MonoReconciler {
                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() {
                
@@ -106,30 +246,196 @@ public class JavaReconciler extends MonoReconciler {
                window.getPartService().removePartListener(fPartListener);
                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 AbstractReconciler#reconcilerReset()
+        * @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 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 <code>true</code> 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 <code>true</code> 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);
+//             }
+//     }
+//}