129837be8874f0f224a35747fb7661ce469b8719
[phpeclipse.git] / net.sourceforge.phpeclipse.ui / src / net / sourceforge / phpdt / internal / ui / viewsupport / ProblemMarkerManager.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.ui.viewsupport;
12
13 import java.util.HashSet;
14
15 import net.sourceforge.phpdt.internal.ui.util.SWTUtil;
16 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
17 import net.sourceforge.phpeclipse.phpeditor.CompilationUnitAnnotationModelEvent;
18 import net.sourceforge.phpeclipse.ui.WebUI;
19
20 import org.eclipse.core.resources.IMarker;
21 import org.eclipse.core.resources.IMarkerDelta;
22 import org.eclipse.core.resources.IProject;
23 import org.eclipse.core.resources.IResource;
24 import org.eclipse.core.resources.IResourceChangeEvent;
25 import org.eclipse.core.resources.IResourceChangeListener;
26 import org.eclipse.core.resources.IResourceDelta;
27 import org.eclipse.core.resources.IResourceDeltaVisitor;
28 import org.eclipse.core.runtime.CoreException;
29 import org.eclipse.jface.text.source.AnnotationModelEvent;
30 import org.eclipse.jface.text.source.IAnnotationModel;
31 import org.eclipse.jface.text.source.IAnnotationModelListener;
32 import org.eclipse.jface.text.source.IAnnotationModelListenerExtension;
33 import org.eclipse.jface.util.ListenerList;
34 import org.eclipse.swt.widgets.Display;
35
36 /**
37  * Listens to resource deltas and filters for marker changes of type
38  * IMarker.PROBLEM Viewers showing error ticks should register as listener to
39  * this type.
40  */
41 public class ProblemMarkerManager implements IResourceChangeListener,
42                 IAnnotationModelListener, IAnnotationModelListenerExtension {
43
44         /**
45          * Visitors used to look if the element change delta containes a marker
46          * change.
47          */
48         private static class ProjectErrorVisitor implements IResourceDeltaVisitor {
49
50                 private HashSet fChangedElements;
51
52                 public ProjectErrorVisitor(HashSet changedElements) {
53                         fChangedElements = changedElements;
54                 }
55
56                 public boolean visit(IResourceDelta delta) throws CoreException {
57                         IResource res = delta.getResource();
58                         if (res instanceof IProject
59                                         && delta.getKind() == IResourceDelta.CHANGED) {
60                                 try {
61                                         IProject project = (IProject) res;
62                                         if (!project.isAccessible()
63                                                         || !project
64                                                                         .hasNature(PHPeclipsePlugin.PHP_NATURE_ID)) {
65                                                 // only track open Java projects
66                                                 return false;
67                                         }
68                                 } catch (CoreException e) {
69                                         PHPeclipsePlugin.log(e);
70                                         return false;
71                                 }
72                         }
73                         checkInvalidate(delta, res);
74                         return true;
75                 }
76
77                 private void checkInvalidate(IResourceDelta delta, IResource resource) {
78                         int kind = delta.getKind();
79                         if (kind == IResourceDelta.REMOVED || kind == IResourceDelta.ADDED
80                                         || (kind == IResourceDelta.CHANGED && isErrorDelta(delta))) {
81                                 // invalidate the resource and all parents
82                                 while (resource.getType() != IResource.ROOT
83                                                 && fChangedElements.add(resource)) {
84                                         resource = resource.getParent();
85                                 }
86                         }
87                 }
88
89                 private boolean isErrorDelta(IResourceDelta delta) {
90                         if ((delta.getFlags() & IResourceDelta.MARKERS) != 0) {
91                                 IMarkerDelta[] markerDeltas = delta.getMarkerDeltas();
92                                 for (int i = 0; i < markerDeltas.length; i++) {
93                                         if (markerDeltas[i].isSubtypeOf(IMarker.PROBLEM)) {
94                                                 int kind = markerDeltas[i].getKind();
95                                                 if (kind == IResourceDelta.ADDED
96                                                                 || kind == IResourceDelta.REMOVED)
97                                                         return true;
98                                                 int severity = markerDeltas[i].getAttribute(
99                                                                 IMarker.SEVERITY, -1);
100                                                 int newSeverity = markerDeltas[i].getMarker()
101                                                                 .getAttribute(IMarker.SEVERITY, -1);
102                                                 if (newSeverity != severity)
103                                                         return true;
104                                         }
105                                 }
106                         }
107                         return false;
108                 }
109         }
110
111         private ListenerList fListeners;
112
113         public ProblemMarkerManager() {
114                 fListeners = new ListenerList(10);
115         }
116
117         /*
118          * @see IResourceChangeListener#resourceChanged
119          */
120         public void resourceChanged(IResourceChangeEvent event) {
121                 HashSet changedElements = new HashSet();
122
123                 try {
124                         IResourceDelta delta = event.getDelta();
125                         if (delta != null)
126                                 delta.accept(new ProjectErrorVisitor(changedElements));
127                 } catch (CoreException e) {
128                         PHPeclipsePlugin.log(e.getStatus());
129                 }
130
131                 if (!changedElements.isEmpty()) {
132                         IResource[] changes = (IResource[]) changedElements
133                                         .toArray(new IResource[changedElements.size()]);
134                         fireChanges(changes, true);
135                 }
136         }
137
138         /*
139          * (non-Javadoc)
140          * 
141          * @see IAnnotationModelListener#modelChanged(IAnnotationModel)
142          */
143         public void modelChanged(IAnnotationModel model) {
144                 // no action
145         }
146
147         /*
148          * (non-Javadoc)
149          * 
150          * @see IAnnotationModelListenerExtension#modelChanged(AnnotationModelEvent)
151          */
152         public void modelChanged(AnnotationModelEvent event) {
153                 if (event instanceof CompilationUnitAnnotationModelEvent) {
154                         CompilationUnitAnnotationModelEvent cuEvent = (CompilationUnitAnnotationModelEvent) event;
155                         if (cuEvent.includesProblemMarkerAnnotationChanges()) {
156                                 IResource[] changes = new IResource[] { cuEvent
157                                                 .getUnderlyingResource() };
158                                 fireChanges(changes, false);
159                         }
160                 }
161         }
162
163         /**
164          * Adds a listener for problem marker changes.
165          */
166         public void addListener(IProblemChangedListener listener) {
167                 if (fListeners.isEmpty()) {
168                         PHPeclipsePlugin.getWorkspace().addResourceChangeListener(this);
169                         WebUI.getDefault().getCompilationUnitDocumentProvider()
170                                         .addGlobalAnnotationModelListener(this);
171                 }
172                 fListeners.add(listener);
173         }
174
175         /**
176          * Removes a <code>IProblemChangedListener</code>.
177          */
178         public void removeListener(IProblemChangedListener listener) {
179                 fListeners.remove(listener);
180                 if (fListeners.isEmpty()) {
181                         PHPeclipsePlugin.getWorkspace().removeResourceChangeListener(this);
182                         WebUI.getDefault().getCompilationUnitDocumentProvider()
183                                         .removeGlobalAnnotationModelListener(this);
184                 }
185         }
186
187         private void fireChanges(final IResource[] changes,
188                         final boolean isMarkerChange) {
189                 Display display = SWTUtil.getStandardDisplay();
190                 if (display != null && !display.isDisposed()) {
191                         display.asyncExec(new Runnable() {
192                                 public void run() {
193                                         Object[] listeners = fListeners.getListeners();
194                                         for (int i = 0; i < listeners.length; i++) {
195                                                 IProblemChangedListener curr = (IProblemChangedListener) listeners[i];
196                                                 curr.problemsChanged(changes, isMarkerChange);
197                                         }
198                                 }
199                         });
200                 }
201         }
202
203 }