1 /*******************************************************************************
2 * Copyright (c) 2000, 2011 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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.ui.viewsupport;
14 import java.util.HashSet;
17 import org.eclipse.swt.widgets.Display;
19 import org.eclipse.core.runtime.CoreException;
20 import org.eclipse.core.runtime.IProgressMonitor;
21 import org.eclipse.core.runtime.IStatus;
22 import org.eclipse.core.runtime.ListenerList;
23 import org.eclipse.core.runtime.Status;
25 import org.eclipse.core.resources.IMarker;
26 import org.eclipse.core.resources.IMarkerDelta;
27 import org.eclipse.core.resources.IProject;
28 import org.eclipse.core.resources.IResource;
29 import org.eclipse.core.resources.IResourceChangeEvent;
30 import org.eclipse.core.resources.IResourceChangeListener;
31 import org.eclipse.core.resources.IResourceDelta;
32 import org.eclipse.core.resources.IResourceDeltaVisitor;
34 import org.eclipse.jface.text.source.AnnotationModelEvent;
35 import org.eclipse.jface.text.source.IAnnotationModel;
36 import org.eclipse.jface.text.source.IAnnotationModelListener;
37 import org.eclipse.jface.text.source.IAnnotationModelListenerExtension;
39 import org.eclipse.ui.PlatformUI;
40 import org.eclipse.ui.progress.UIJob;
42 import org.eclipse.jdt.internal.ui.JavaPlugin;
43 import org.eclipse.jdt.internal.ui.JavaUIMessages;
44 import org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitAnnotationModelEvent;
47 * Listens to resource deltas and filters for marker changes of type IMarker.PROBLEM
48 * Viewers showing error ticks should register as listener to
51 public class ProblemMarkerManager implements IResourceChangeListener, IAnnotationModelListener , IAnnotationModelListenerExtension {
54 * Visitors used to look if the element change delta contains a marker change.
56 private static class ProjectErrorVisitor implements IResourceDeltaVisitor {
58 private HashSet<IResource> fChangedElements;
60 public ProjectErrorVisitor(HashSet<IResource> changedElements) {
61 fChangedElements= changedElements;
64 public boolean visit(IResourceDelta delta) throws CoreException {
65 IResource res= delta.getResource();
66 if (res instanceof IProject && delta.getKind() == IResourceDelta.CHANGED) {
67 IProject project= (IProject) res;
68 if (!project.isAccessible()) {
69 // only track open Java projects
73 checkInvalidate(delta, res);
77 private void checkInvalidate(IResourceDelta delta, IResource resource) {
78 int kind= delta.getKind();
79 if (kind == IResourceDelta.REMOVED || kind == IResourceDelta.ADDED || (kind == IResourceDelta.CHANGED && isErrorDelta(delta))) {
80 // invalidate the resource and all parents
81 while (resource.getType() != IResource.ROOT && fChangedElements.add(resource)) {
82 resource= resource.getParent();
87 private boolean isErrorDelta(IResourceDelta delta) {
88 if ((delta.getFlags() & IResourceDelta.MARKERS) != 0) {
89 IMarkerDelta[] markerDeltas= delta.getMarkerDeltas();
90 for (int i= 0; i < markerDeltas.length; i++) {
91 if (markerDeltas[i].isSubtypeOf(IMarker.PROBLEM)) {
92 int kind= markerDeltas[i].getKind();
93 if (kind == IResourceDelta.ADDED || kind == IResourceDelta.REMOVED)
95 int severity= markerDeltas[i].getAttribute(IMarker.SEVERITY, -1);
96 int newSeverity= markerDeltas[i].getMarker().getAttribute(IMarker.SEVERITY, -1);
97 if (newSeverity != severity)
106 private ListenerList fListeners;
108 private Set<IResource> fResourcesWithMarkerChanges;
109 private Set<IResource> fResourcesWithAnnotationChanges;
111 private UIJob fNotifierJob;
113 public ProblemMarkerManager() {
114 fListeners= new ListenerList();
115 fResourcesWithMarkerChanges= new HashSet<IResource>();
116 fResourcesWithAnnotationChanges= new HashSet<IResource>();
120 * @see IResourceChangeListener#resourceChanged
122 public void resourceChanged(IResourceChangeEvent event) {
123 HashSet<IResource> changedElements= new HashSet<IResource>();
126 IResourceDelta delta= event.getDelta();
128 delta.accept(new ProjectErrorVisitor(changedElements));
129 } catch (CoreException e) {
130 JavaPlugin.log(e.getStatus());
133 if (!changedElements.isEmpty()) {
134 boolean hasChanges= false;
135 synchronized (this) {
136 if (fResourcesWithMarkerChanges.isEmpty()) {
137 fResourcesWithMarkerChanges= changedElements;
140 hasChanges= fResourcesWithMarkerChanges.addAll(changedElements);
150 * @see IAnnotationModelListener#modelChanged(IAnnotationModel)
152 public void modelChanged(IAnnotationModel model) {
157 * @see IAnnotationModelListenerExtension#modelChanged(AnnotationModelEvent)
159 public void modelChanged(AnnotationModelEvent event) {
160 if (event instanceof CompilationUnitAnnotationModelEvent) {
161 CompilationUnitAnnotationModelEvent cuEvent= (CompilationUnitAnnotationModelEvent) event;
162 if (cuEvent.includesProblemMarkerAnnotationChanges()) {
163 boolean hasChanges= false;
164 synchronized (this) {
165 IResource changedResource= cuEvent.getUnderlyingResource();
166 hasChanges= fResourcesWithAnnotationChanges.add(changedResource);
177 * Adds a listener for problem marker changes.
178 * @param listener the listener to add
180 public void addListener(IProblemChangedListener listener) {
181 if (fListeners.isEmpty()) {
182 JavaPlugin.getWorkspace().addResourceChangeListener(this);
183 JavaPlugin.getDefault().getCompilationUnitDocumentProvider().addGlobalAnnotationModelListener(this);
185 fListeners.add(listener);
189 * Removes a <code>IProblemChangedListener</code>.
190 * @param listener the listener to remove
192 public void removeListener(IProblemChangedListener listener) {
193 fListeners.remove(listener);
194 if (fListeners.isEmpty()) {
195 JavaPlugin.getWorkspace().removeResourceChangeListener(this);
196 JavaPlugin.getDefault().getCompilationUnitDocumentProvider().removeGlobalAnnotationModelListener(this);
200 private void fireChanges() {
201 Display display= PlatformUI.getWorkbench().getDisplay();
202 if (display != null && !display.isDisposed()) {
203 postAsyncUpdate(display);
207 private void postAsyncUpdate(final Display display) {
208 if (fNotifierJob == null) {
209 fNotifierJob= new UIJob(display, JavaUIMessages.ProblemMarkerManager_problem_marker_update_job_description) {
211 public IStatus runInUIThread(IProgressMonitor monitor) {
213 return Status.OK_STATUS;
216 fNotifierJob.setSystem(true);
218 fNotifierJob.schedule();
222 * Notify all IProblemChangedListener. Must be called in the display thread.
224 private void runPendingUpdates() {
225 IResource[] markerResources= null;
226 IResource[] annotationResources= null;
227 synchronized (this) {
228 if (!fResourcesWithMarkerChanges.isEmpty()) {
229 markerResources= fResourcesWithMarkerChanges.toArray(new IResource[fResourcesWithMarkerChanges.size()]);
230 fResourcesWithMarkerChanges.clear();
232 if (!fResourcesWithAnnotationChanges.isEmpty()) {
233 annotationResources= fResourcesWithAnnotationChanges.toArray(new IResource[fResourcesWithAnnotationChanges.size()]);
234 fResourcesWithAnnotationChanges.clear();
237 Object[] listeners= fListeners.getListeners();
238 for (int i= 0; i < listeners.length; i++) {
239 IProblemChangedListener curr= (IProblemChangedListener) listeners[i];
240 if (markerResources != null) {
241 curr.problemsChanged(markerResources, true);
243 if (annotationResources != null) {
244 curr.problemsChanged(annotationResources, false);