Fix error marker updates in staging view
[egit/eclipse.git] / org.eclipse.egit.ui / src / org / eclipse / egit / ui / internal / decorators / ProblemLabelDecorator.java
blobe5dd1fa39443424332d78508669c3a28b9797a6c
1 /*******************************************************************************
2 * Copyright (C) 2012, Robin Stocker <robin@nibor.org>
3 * Copyright (C) 2016, Thomas Wolf <thomas.wolf@paranor.ch>
5 * All rights reserved. This program and the accompanying materials
6 * are made available under the terms of the Eclipse Public License 2.0
7 * which accompanies this distribution, and is available at
8 * https://www.eclipse.org/legal/epl-2.0/
10 * SPDX-License-Identifier: EPL-2.0
11 *******************************************************************************/
12 package org.eclipse.egit.ui.internal.decorators;
14 import java.io.File;
15 import java.util.ArrayList;
16 import java.util.HashSet;
17 import java.util.List;
18 import java.util.Set;
20 import org.eclipse.core.resources.IMarker;
21 import org.eclipse.core.resources.IMarkerDelta;
22 import org.eclipse.core.resources.IResource;
23 import org.eclipse.core.resources.IResourceChangeEvent;
24 import org.eclipse.core.resources.IResourceChangeListener;
25 import org.eclipse.core.resources.ResourcesPlugin;
26 import org.eclipse.core.runtime.IPath;
27 import org.eclipse.core.runtime.Path;
28 import org.eclipse.egit.core.AdapterUtils;
29 import org.eclipse.egit.core.project.RepositoryMapping;
30 import org.eclipse.jface.resource.ImageDescriptor;
31 import org.eclipse.jface.resource.JFaceResources;
32 import org.eclipse.jface.resource.LocalResourceManager;
33 import org.eclipse.jface.resource.ResourceManager;
34 import org.eclipse.jface.viewers.BaseLabelProvider;
35 import org.eclipse.jface.viewers.DecorationOverlayIcon;
36 import org.eclipse.jface.viewers.IDecoration;
37 import org.eclipse.jface.viewers.ILabelDecorator;
38 import org.eclipse.jface.viewers.IStructuredContentProvider;
39 import org.eclipse.jface.viewers.ITreeContentProvider;
40 import org.eclipse.jface.viewers.LabelProviderChangedEvent;
41 import org.eclipse.jface.viewers.StructuredViewer;
42 import org.eclipse.swt.graphics.Image;
43 import org.eclipse.swt.widgets.Display;
44 import org.eclipse.team.ui.ISharedImages;
45 import org.eclipse.team.ui.TeamImages;
47 /**
48 * Label decorator for warning/error problem markers (used in Staging View and
49 * Commit Dialog).
50 * <p>
51 * Users must make the decoratable element implement {@link IProblemDecoratable}.
53 public class ProblemLabelDecorator extends BaseLabelProvider implements
54 ILabelDecorator, IResourceChangeListener {
56 private final StructuredViewer viewer;
58 private final ResourceManager resourceManager = new LocalResourceManager(
59 JFaceResources.getResources());
61 /**
62 * @param viewer
63 * the viewer to use for label updates because of changed
64 * resources, or null for none
66 public ProblemLabelDecorator(StructuredViewer viewer) {
67 this.viewer = viewer;
68 if (this.viewer != null)
69 ResourcesPlugin.getWorkspace().addResourceChangeListener(this);
72 @Override
73 public void dispose() {
74 super.dispose();
75 resourceManager.dispose();
76 if (this.viewer != null)
77 ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
80 @Override
81 public Image decorateImage(Image image, Object element) {
82 IProblemDecoratable decoratable = getProblemDecoratable(element);
83 if (decoratable != null) {
84 int problemSeverity = decoratable.getProblemSeverity();
85 if (problemSeverity == IMarker.SEVERITY_ERROR)
86 return getDecoratedImage(image, ISharedImages.IMG_ERROR_OVR);
87 else if (problemSeverity == IMarker.SEVERITY_WARNING)
88 return getDecoratedImage(image, ISharedImages.IMG_WARNING_OVR);
90 return null;
93 @Override
94 public String decorateText(String text, Object element) {
95 // No decoration
96 return null;
99 private IProblemDecoratable getProblemDecoratable(Object element) {
100 if (element instanceof IProblemDecoratable)
101 return (IProblemDecoratable) element;
102 else
103 return null;
106 private Image getDecoratedImage(Image base, String teamImageId) {
107 ImageDescriptor overlay = TeamImages.getImageDescriptor(teamImageId);
108 DecorationOverlayIcon decorated = new DecorationOverlayIcon(base,
109 overlay, IDecoration.BOTTOM_LEFT);
110 return (Image) this.resourceManager.get(decorated);
113 @Override
114 public void resourceChanged(IResourceChangeEvent event) {
115 Set<IPath> paths = new HashSet<>();
117 IMarkerDelta[] markerDeltas = event.findMarkerDeltas(IMarker.PROBLEM,
118 true);
119 for (IMarkerDelta delta : markerDeltas) {
120 IResource resource = delta.getResource();
121 if (resource == null) {
122 continue;
124 RepositoryMapping mapping = RepositoryMapping.getMapping(resource);
125 if (mapping == null || mapping.getRepository().isBare()) {
126 continue;
128 IPath path = resource.getLocation();
129 if (path == null) {
130 continue;
132 // Also add parents
133 File workTree = mapping.getWorkTree();
134 if (workTree == null) {
135 continue;
137 int n = new Path(workTree.getAbsolutePath()).segmentCount();
138 for (int i = path.segmentCount(); i > n; i--) {
139 paths.add(path);
140 path = path.removeLastSegments(1);
144 if (!paths.isEmpty()) {
145 updateLabels(paths);
149 private void updateLabels(Set<IPath> changedPaths) {
150 List<Object> elements = getAffectedElements(changedPaths);
151 if (!elements.isEmpty()) {
152 final Object[] updateElements = elements.toArray(new Object[elements.size()]);
153 Display display = viewer.getControl().getDisplay();
154 display.asyncExec(new Runnable() {
155 @Override
156 public void run() {
157 fireLabelProviderChanged(new LabelProviderChangedEvent(
158 ProblemLabelDecorator.this, updateElements));
164 private List<Object> getAffectedElements(Set<IPath> paths) {
165 List<Object> result = new ArrayList<>();
166 if (viewer.getContentProvider() instanceof IStructuredContentProvider) {
167 IStructuredContentProvider contentProvider = (IStructuredContentProvider) viewer.getContentProvider();
168 getAffectedElements(paths, contentProvider.getElements(null),
169 contentProvider, result);
171 return result;
174 private void getAffectedElements(Set<IPath> paths, Object[] elements,
175 IStructuredContentProvider contentProvider, List<Object> result) {
176 for (Object element : elements) {
177 IPath path = AdapterUtils.adapt(element, IPath.class);
178 if (path == null) {
179 IResource resource = AdapterUtils.adapt(element,
180 IResource.class);
181 if (resource != null) {
182 path = resource.getLocation();
185 if (path != null && paths.contains(path)) {
186 result.add(element);
187 if (contentProvider instanceof ITreeContentProvider) {
188 getAffectedElements(paths,
189 ((ITreeContentProvider) contentProvider)
190 .getChildren(element),
191 contentProvider, result);