KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > ui > text > JavaReconciler


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11
12 package org.eclipse.jdt.internal.ui.text;
13
14
15 import org.eclipse.core.runtime.Assert;
16 import org.eclipse.core.runtime.CoreException;
17
18 import org.eclipse.core.resources.IMarker;
19 import org.eclipse.core.resources.IMarkerDelta;
20 import org.eclipse.core.resources.IResource;
21 import org.eclipse.core.resources.IResourceChangeEvent;
22 import org.eclipse.core.resources.IResourceChangeListener;
23 import org.eclipse.core.resources.IResourceDelta;
24 import org.eclipse.core.resources.IWorkspace;
25
26 import org.eclipse.swt.events.ShellAdapter;
27 import org.eclipse.swt.events.ShellEvent;
28 import org.eclipse.swt.events.ShellListener;
29 import org.eclipse.swt.widgets.Control;
30 import org.eclipse.swt.widgets.Shell;
31
32 import org.eclipse.jface.util.IPropertyChangeListener;
33 import org.eclipse.jface.util.PropertyChangeEvent;
34
35 import org.eclipse.jface.text.IDocument;
36 import org.eclipse.jface.text.ITextViewer;
37 import org.eclipse.jface.text.reconciler.DirtyRegion;
38 import org.eclipse.jface.text.reconciler.MonoReconciler;
39
40 import org.eclipse.ui.IEditorInput;
41 import org.eclipse.ui.IFileEditorInput;
42 import org.eclipse.ui.IPartListener;
43 import org.eclipse.ui.IWorkbenchPart;
44 import org.eclipse.ui.IWorkbenchPartSite;
45 import org.eclipse.ui.IWorkbenchWindow;
46 import org.eclipse.ui.texteditor.ITextEditor;
47 import org.eclipse.ui.texteditor.spelling.SpellingService;
48
49 import org.eclipse.jdt.core.ElementChangedEvent;
50 import org.eclipse.jdt.core.IElementChangedListener;
51 import org.eclipse.jdt.core.IJavaElementDelta;
52 import org.eclipse.jdt.core.JavaCore;
53
54 import org.eclipse.jdt.internal.ui.JavaPlugin;
55 import org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor;
56
57
58 /**
59  * A reconciler that is also activated on editor activation.
60  */

61 public class JavaReconciler extends MonoReconciler {
62
63     /**
64      * Internal part listener for activating the reconciler.
65      */

66     private class PartListener implements IPartListener {
67
68         /*
69          * @see org.eclipse.ui.IPartListener#partActivated(org.eclipse.ui.IWorkbenchPart)
70          */

71         public void partActivated(IWorkbenchPart part) {
72             if (part == fTextEditor) {
73                 if (hasJavaModelChanged())
74                     JavaReconciler.this.forceReconciling();
75                 setEditorActive(true);
76             }
77         }
78
79         /*
80          * @see org.eclipse.ui.IPartListener#partBroughtToTop(org.eclipse.ui.IWorkbenchPart)
81          */

82         public void partBroughtToTop(IWorkbenchPart part) {
83         }
84
85         /*
86          * @see org.eclipse.ui.IPartListener#partClosed(org.eclipse.ui.IWorkbenchPart)
87          */

88         public void partClosed(IWorkbenchPart part) {
89         }
90
91         /*
92          * @see org.eclipse.ui.IPartListener#partDeactivated(org.eclipse.ui.IWorkbenchPart)
93          */

94         public void partDeactivated(IWorkbenchPart part) {
95             if (part == fTextEditor) {
96                 setJavaModelChanged(false);
97                 setEditorActive(false);
98             }
99         }
100
101         /*
102          * @see org.eclipse.ui.IPartListener#partOpened(org.eclipse.ui.IWorkbenchPart)
103          */

104         public void partOpened(IWorkbenchPart part) {
105         }
106     }
107
108     /**
109      * Internal Shell activation listener for activating the reconciler.
110      */

111     private class ActivationListener extends ShellAdapter {
112
113         private Control fControl;
114
115         public ActivationListener(Control control) {
116             Assert.isNotNull(control);
117             fControl= control;
118         }
119
120         /*
121          * @see org.eclipse.swt.events.ShellListener#shellActivated(org.eclipse.swt.events.ShellEvent)
122          */

123         public void shellActivated(ShellEvent e) {
124             if (!fControl.isDisposed() && fControl.isVisible()) {
125                 if (hasJavaModelChanged())
126                     JavaReconciler.this.forceReconciling();
127                 setEditorActive(true);
128             }
129         }
130
131         /*
132          * @see org.eclipse.swt.events.ShellListener#shellDeactivated(org.eclipse.swt.events.ShellEvent)
133          */

134         public void shellDeactivated(ShellEvent e) {
135             if (!fControl.isDisposed() && fControl.getShell() == e.getSource()) {
136                 setJavaModelChanged(false);
137                 setEditorActive(false);
138             }
139         }
140     }
141
142     /**
143      * Internal Java element changed listener
144      *
145      * @since 3.0
146      */

147     private class ElementChangedListener implements IElementChangedListener {
148         /*
149          * @see org.eclipse.jdt.core.IElementChangedListener#elementChanged(org.eclipse.jdt.core.ElementChangedEvent)
150          */

151         public void elementChanged(ElementChangedEvent event) {
152             if (event.getDelta().getFlags() == IJavaElementDelta.F_AST_AFFECTED)
153                 return;
154             setJavaModelChanged(true);
155             if (!fIsReconciling && isEditorActive() )
156                 JavaReconciler.this.forceReconciling();
157         }
158     }
159
160     /**
161      * Internal resource change listener.
162      *
163      * @since 3.0
164      */

165     class ResourceChangeListener implements IResourceChangeListener {
166
167         private IResource getResource() {
168             IEditorInput input= fTextEditor.getEditorInput();
169             if (input instanceof IFileEditorInput) {
170                 IFileEditorInput fileInput= (IFileEditorInput) input;
171                 return fileInput.getFile();
172             }
173             return null;
174         }
175
176         /*
177          * @see IResourceChangeListener#resourceChanged(org.eclipse.core.resources.IResourceChangeEvent)
178          */

179         public void resourceChanged(IResourceChangeEvent e) {
180             IResourceDelta delta= e.getDelta();
181             IResource resource= getResource();
182             if (delta != null && resource != null) {
183                 IResourceDelta child= delta.findMember(resource.getFullPath());
184                 if (child != null) {
185                     IMarkerDelta[] deltas= child.getMarkerDeltas();
186                     int i= deltas.length;
187                     while (--i >= 0) {
188                         try {
189                             if (deltas[i].getMarker().isSubtypeOf(IMarker.PROBLEM)) {
190                                 forceReconciling();
191                                 return;
192                             }
193                         } catch (CoreException e1) {
194                             // ignore and try next one
195
}
196                     }
197                 }
198             }
199         }
200     }
201
202
203     /** The reconciler's editor */
204     private ITextEditor fTextEditor;
205     /** The part listener */
206     private IPartListener fPartListener;
207     /** The shell listener */
208     private ShellListener fActivationListener;
209     /**
210      * The mutex that keeps us from running multiple reconcilers on one editor.
211      */

212     private Object JavaDoc fMutex;
213     /**
214      * The Java element changed listener.
215      * @since 3.0
216      */

217     private IElementChangedListener fJavaElementChangedListener;
218     /**
219      * Tells whether the Java model sent out a changed event.
220      * @since 3.0
221      */

222     private volatile boolean fHasJavaModelChanged= true;
223     /**
224      * Tells whether this reconciler's editor is active.
225      * @since 3.1
226      */

227     private volatile boolean fIsEditorActive= true;
228     /**
229      * The resource change listener.
230      * @since 3.0
231      */

232     private IResourceChangeListener fResourceChangeListener;
233     /**
234      * The property change listener.
235      * @since 3.3
236      */

237     private IPropertyChangeListener fPropertyChangeListener;
238     /**
239      * Tells whether a reconcile is in progress.
240      * @since 3.1
241      */

242     private volatile boolean fIsReconciling= false;
243     
244     private boolean fIninitalProcessDone= false;
245
246     /**
247      * Creates a new reconciler.
248      *
249      * @param editor the editor
250      * @param strategy the reconcile strategy
251      * @param isIncremental <code>true</code> if this is an incremental reconciler
252      */

253     public JavaReconciler(ITextEditor editor, JavaCompositeReconcilingStrategy strategy, boolean isIncremental) {
254         super(strategy, isIncremental);
255         fTextEditor= editor;
256
257         // https://bugs.eclipse.org/bugs/show_bug.cgi?id=63898
258
// when re-using editors, a new reconciler is set up by the source viewer
259
// and the old one uninstalled. However, the old reconciler may still be
260
// running.
261
// To avoid having to reconcilers calling CompilationUnitEditor.reconciled,
262
// we synchronized on a lock object provided by the editor.
263
// The critical section is really the entire run() method of the reconciler
264
// thread, but synchronizing process() only will keep JavaReconcilingStrategy
265
// from running concurrently on the same editor.
266
// TODO remove once we have ensured that there is only one reconciler per editor.
267
if (editor instanceof CompilationUnitEditor)
268             fMutex= ((CompilationUnitEditor) editor).getReconcilerLock();
269         else
270             fMutex= new Object JavaDoc(); // Null Object
271
}
272
273     /*
274      * @see org.eclipse.jface.text.reconciler.IReconciler#install(org.eclipse.jface.text.ITextViewer)
275      */

276     public void install(ITextViewer textViewer) {
277         super.install(textViewer);
278
279         fPartListener= new PartListener();
280         IWorkbenchPartSite site= fTextEditor.getSite();
281         IWorkbenchWindow window= site.getWorkbenchWindow();
282         window.getPartService().addPartListener(fPartListener);
283
284         fActivationListener= new ActivationListener(textViewer.getTextWidget());
285         Shell shell= window.getShell();
286         shell.addShellListener(fActivationListener);
287
288         fJavaElementChangedListener= new ElementChangedListener();
289         JavaCore.addElementChangedListener(fJavaElementChangedListener);
290
291         fResourceChangeListener= new ResourceChangeListener();
292         IWorkspace workspace= JavaPlugin.getWorkspace();
293         workspace.addResourceChangeListener(fResourceChangeListener);
294         
295         fPropertyChangeListener= new IPropertyChangeListener() {
296             public void propertyChange(PropertyChangeEvent event) {
297                 if (SpellingService.PREFERENCE_SPELLING_ENABLED.equals(event.getProperty()) || SpellingService.PREFERENCE_SPELLING_ENGINE.equals(event.getProperty()))
298                     forceReconciling();
299             }
300         };
301         JavaPlugin.getDefault().getCombinedPreferenceStore().addPropertyChangeListener(fPropertyChangeListener);
302     }
303
304     /*
305      * @see org.eclipse.jface.text.reconciler.IReconciler#uninstall()
306      */

307     public void uninstall() {
308
309         IWorkbenchPartSite site= fTextEditor.getSite();
310         IWorkbenchWindow window= site.getWorkbenchWindow();
311         window.getPartService().removePartListener(fPartListener);
312         fPartListener= null;
313
314         Shell shell= window.getShell();
315         if (shell != null && !shell.isDisposed())
316             shell.removeShellListener(fActivationListener);
317         fActivationListener= null;
318
319         JavaCore.removeElementChangedListener(fJavaElementChangedListener);
320         fJavaElementChangedListener= null;
321
322         IWorkspace workspace= JavaPlugin.getWorkspace();
323         workspace.removeResourceChangeListener(fResourceChangeListener);
324         fResourceChangeListener= null;
325         
326         JavaPlugin.getDefault().getCombinedPreferenceStore().removePropertyChangeListener(fPropertyChangeListener);
327         fPropertyChangeListener= null;
328
329         super.uninstall();
330     }
331
332     /*
333      * @see org.eclipse.jface.text.reconciler.AbstractReconciler#forceReconciling()
334      */

335     protected void forceReconciling() {
336         if (!fIninitalProcessDone)
337             return;
338
339         super.forceReconciling();
340         JavaCompositeReconcilingStrategy strategy= (JavaCompositeReconcilingStrategy) getReconcilingStrategy(IDocument.DEFAULT_CONTENT_TYPE);
341         strategy.notifyListeners(false);
342     }
343
344     /*
345      * @see org.eclipse.jface.text.reconciler.AbstractReconciler#aboutToReconcile()
346      * @since 3.0
347      */

348     protected void aboutToBeReconciled() {
349         JavaCompositeReconcilingStrategy strategy= (JavaCompositeReconcilingStrategy) getReconcilingStrategy(IDocument.DEFAULT_CONTENT_TYPE);
350         strategy.aboutToBeReconciled();
351     }
352
353     /*
354      * @see org.eclipse.jface.text.reconciler.AbstractReconciler#reconcilerReset()
355      */

356     protected void reconcilerReset() {
357         super.reconcilerReset();
358         JavaCompositeReconcilingStrategy strategy= (JavaCompositeReconcilingStrategy) getReconcilingStrategy(IDocument.DEFAULT_CONTENT_TYPE);
359         strategy.notifyListeners(true);
360     }
361
362     /*
363      * @see org.eclipse.jface.text.reconciler.MonoReconciler#initialProcess()
364      */

365     protected void initialProcess() {
366         synchronized (fMutex) {
367             super.initialProcess();
368         }
369         fIninitalProcessDone= true;
370     }
371
372     /*
373      * @see org.eclipse.jface.text.reconciler.MonoReconciler#process(org.eclipse.jface.text.reconciler.DirtyRegion)
374      */

375     protected void process(DirtyRegion dirtyRegion) {
376         synchronized (fMutex) {
377             fIsReconciling= true;
378             super.process(dirtyRegion);
379             fIsReconciling= false;
380         }
381     }
382
383     /**
384      * Tells whether the Java Model has changed or not.
385      *
386      * @return <code>true</code> iff the Java Model has changed
387      * @since 3.0
388      */

389     private synchronized boolean hasJavaModelChanged() {
390         return fHasJavaModelChanged;
391     }
392
393     /**
394      * Sets whether the Java Model has changed or not.
395      *
396      * @param state <code>true</code> iff the java model has changed
397      * @since 3.0
398      */

399     private synchronized void setJavaModelChanged(boolean state) {
400         fHasJavaModelChanged= state;
401     }
402     
403     /**
404      * Tells whether this reconciler's editor is active.
405      *
406      * @return <code>true</code> iff the editor is active
407      * @since 3.1
408      */

409     private synchronized boolean isEditorActive() {
410         return fIsEditorActive;
411     }
412
413     
414     /**
415      * Sets whether this reconciler's editor is active.
416      *
417      * @param state <code>true</code> iff the editor is active
418      * @since 3.1
419      */

420     private synchronized void setEditorActive(boolean state) {
421         fIsEditorActive= state;
422     }
423 }
424
Popular Tags