/******************************************************************************* * Copyright (C) 2012, Robin Stocker <robin@nibor.org> * Copyright (C) 2016, Thomas Wolf <thomas.wolf@paranor.ch> * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html *******************************************************************************/ package org.eclipse.egit.ui.internal.decorators; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import org.eclipse.core.resources.IMarker; 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.ResourcesPlugin; import org.eclipse.egit.core.AdapterUtils; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.resource.LocalResourceManager; import org.eclipse.jface.resource.ResourceManager; import org.eclipse.jface.viewers.BaseLabelProvider; import org.eclipse.jface.viewers.DecorationOverlayIcon; import org.eclipse.jface.viewers.IDecoration; import org.eclipse.jface.viewers.ILabelDecorator; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.LabelProviderChangedEvent; import org.eclipse.jface.viewers.StructuredViewer; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Display; import org.eclipse.team.ui.ISharedImages; import org.eclipse.team.ui.TeamImages; /** * Label decorator for warning/error problem markers (used in Staging View and * Commit Dialog). * <p> * Users must make the decoratable element implement {@link IProblemDecoratable}. */ public class ProblemLabelDecorator extends BaseLabelProvider implements ILabelDecorator, IResourceChangeListener { private final StructuredViewer viewer; private final ResourceManager resourceManager = new LocalResourceManager( JFaceResources.getResources()); /** * @param viewer * the viewer to use for label updates because of changed * resources, or null for none */ public ProblemLabelDecorator(StructuredViewer viewer) { this.viewer = viewer; if (this.viewer != null) ResourcesPlugin.getWorkspace().addResourceChangeListener(this); } @Override public void dispose() { super.dispose(); resourceManager.dispose(); if (this.viewer != null) ResourcesPlugin.getWorkspace().removeResourceChangeListener(this); } @Override public Image decorateImage(Image image, Object element) { IProblemDecoratable decoratable = getProblemDecoratable(element); if (decoratable != null) { int problemSeverity = decoratable.getProblemSeverity(); if (problemSeverity == IMarker.SEVERITY_ERROR) return getDecoratedImage(image, ISharedImages.IMG_ERROR_OVR); else if (problemSeverity == IMarker.SEVERITY_WARNING) return getDecoratedImage(image, ISharedImages.IMG_WARNING_OVR); } return null; } @Override public String decorateText(String text, Object element) { // No decoration return null; } private IProblemDecoratable getProblemDecoratable(Object element) { if (element instanceof IProblemDecoratable) return (IProblemDecoratable) element; else return null; } private Image getDecoratedImage(Image base, String teamImageId) { ImageDescriptor overlay = TeamImages.getImageDescriptor(teamImageId); DecorationOverlayIcon decorated = new DecorationOverlayIcon(base, overlay, IDecoration.BOTTOM_LEFT); return (Image) this.resourceManager.get(decorated); } @Override public void resourceChanged(IResourceChangeEvent event) { Set<IResource> resources = new HashSet<>(); IMarkerDelta[] markerDeltas = event.findMarkerDeltas(IMarker.PROBLEM, true); for (IMarkerDelta delta : markerDeltas) { // Also add parents IResource resource = delta.getResource(); while (resource.getType() != IResource.ROOT && resources.add(resource)) { resource = resource.getParent(); } } if (!resources.isEmpty()) { updateLabels(resources); } } private void updateLabels(Set<IResource> changedResources) { List<Object> elements = getAffectedElements(changedResources); if (!elements.isEmpty()) { final Object[] updateElements = elements.toArray(new Object[elements.size()]); Display display = viewer.getControl().getDisplay(); display.asyncExec(new Runnable() { @Override public void run() { fireLabelProviderChanged(new LabelProviderChangedEvent( ProblemLabelDecorator.this, updateElements)); } }); } } private List<Object> getAffectedElements(Set<IResource> resources) { List<Object> result = new ArrayList<>(); if (viewer.getContentProvider() instanceof IStructuredContentProvider) { IStructuredContentProvider contentProvider = (IStructuredContentProvider) viewer.getContentProvider(); getAffectedElements(resources, contentProvider.getElements(null), contentProvider, result); } return result; } private void getAffectedElements(Set<IResource> resources, Object[] elements, IStructuredContentProvider contentProvider, List<Object> result) { for (Object element : elements) { IResource resource = AdapterUtils.adapt(element, IResource.class); if (resource != null && resources.contains(resource)) { result.add(element); if (contentProvider instanceof ITreeContentProvider) { getAffectedElements(resources, ((ITreeContentProvider) contentProvider) .getChildren(element), contentProvider, result); } } } } }