blob: 7e66e7b01139877506c32c80bd833a3190dd3ed4 [file] [log] [blame]
/*********************************************************************
* Copyright (c) 2009, 2012 SpringSource, a division of VMware, Inc.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
package org.eclipse.virgo.ide.jdt.internal.ui.decoration;
import org.eclipse.jdt.core.ElementChangedEvent;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.IClasspathAttribute;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IElementChangedListener;
import org.eclipse.jdt.core.IJavaElementDelta;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.ui.packageview.ClassPathContainer;
import org.eclipse.jface.viewers.IDecoration;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ILightweightLabelDecorator;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.LabelProviderChangedEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.widgets.Display;
import org.eclipse.virgo.ide.facet.core.FacetUtils;
import org.eclipse.virgo.ide.jdt.internal.core.classpath.ServerClasspathContainer;
import org.eclipse.virgo.ide.manifest.core.BundleManifestCorePlugin;
/**
* {@link ILightweightLabelDecorator} that decorates non-accessible packages in the class path container.
*
* @author Christian Dupuis
* @since 1.0.0
*/
@SuppressWarnings("restriction")
public class JdtClasspathContainerElementDecorator extends LabelProvider implements ILightweightLabelDecorator {
/** A JDT model listener that gets notified if a class path changed */
private IElementChangedListener changeListener = null;
public JdtClasspathContainerElementDecorator() {
// {@link IElementChangedListener} JDT listener that detects changes to the project's class
// path and triggers a decorator refresh.
changeListener = new IElementChangedListener() {
/**
* Flag indicating a change in the resolved class path. This entry is copied from Eclipse 3.4 in order to
* make this compatible with 3.3.
*/
private static final int F_RESOLVED_CLASSPATH_CHANGED = 0x200000;
public void elementChanged(ElementChangedEvent event) {
boolean refresh = false;
for (IJavaElementDelta delta : event.getDelta().getAffectedChildren()) {
if ((delta.getFlags() & F_RESOLVED_CLASSPATH_CHANGED) != 0 || (delta.getFlags() & IJavaElementDelta.F_CLASSPATH_CHANGED) != 0) {
refresh = true;
}
}
if (refresh) {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
fireLabelProviderChanged(new LabelProviderChangedEvent(JdtClasspathContainerElementDecorator.this));
}
});
}
}
};
JavaCore.addElementChangedListener(changeListener, ElementChangedEvent.POST_CHANGE);
}
/**
* Decorates the given <code>element</code>.
*/
public void decorate(Object element, IDecoration decoration) {
// package fragments are the first elements below the JAR file
if (element instanceof IPackageFragment) {
IPackageFragment packageFragment = (IPackageFragment) element;
if (shouldDecorateImportedPackageFragment(packageFragment)) {
// make light gray and lock icon decoration
decoration.setForegroundColor(ColorMap.GRAY_LIGHT);
decoration.addOverlay(JdtUiImages.DESC_OVR_LOCKED, IDecoration.TOP_LEFT);
} else if (shouldDecorateExportedPackageFragment(packageFragment)) {
decoration.addOverlay(JdtUiImages.DESC_OVR_EXPORTED, IDecoration.TOP_RIGHT);
}
}
// jar package fragments roots; decorate those that come from a test dependency
else if (element instanceof IPackageFragmentRoot) {
IPackageFragmentRoot root = (IPackageFragmentRoot) element;
try {
if (ServerClasspathContainer.CLASSPATH_CONTAINER_PATH.equals(root.getRawClasspathEntry().getPath())
&& root.getJavaProject().getProject().isAccessible() && root.getJavaProject().isOpen()) {
ServerClasspathContainer cpContainer = (ServerClasspathContainer) JavaCore.getClasspathContainer(
ServerClasspathContainer.CLASSPATH_CONTAINER_PATH, root.getJavaProject());
if (cpContainer != null) {
for (IClasspathEntry entry : cpContainer.getClasspathEntries()) {
if (entry.getPath().equals(root.getPath()) && entry.getExtraAttributes() != null) {
for (IClasspathAttribute attribute : entry.getExtraAttributes()) {
if (attribute.getName().equals(ServerClasspathContainer.TEST_CLASSPATH_ATTRIBUTE_VALUE)) {
decoration.setForegroundColor(ColorMap.GRAY_LIGHT);
decoration.addOverlay(JdtUiImages.DESC_OVR_LOCKED, IDecoration.TOP_LEFT);
}
}
break;
}
}
}
}
} catch (JavaModelException e) {
}
}
// class files represent a single type file in a JAR
else if (element instanceof IClassFile) {
IClassFile classFile = (IClassFile) element;
if (classFile.getParent() instanceof IPackageFragment) {
if (shouldDecorateImportedPackageFragment((IPackageFragment) classFile.getParent())) {
// make light gray
decoration.setForegroundColor(ColorMap.GRAY_LIGHT);
}
}
}
// decorate the class path container and add the originating target runtime
else if (element instanceof ClassPathContainer) {
ClassPathContainer container = (ClassPathContainer) element;
if (container.getClasspathEntry().getPath().equals(ServerClasspathContainer.CLASSPATH_CONTAINER_PATH)) {
try {
if (container.getJavaProject().getProject().isAccessible() && container.getJavaProject().isOpen()) {
ServerClasspathContainer cpContainer = (ServerClasspathContainer) JavaCore.getClasspathContainer(
ServerClasspathContainer.CLASSPATH_CONTAINER_PATH, container.getJavaProject());
decoration.addSuffix(cpContainer.getDescriptionSuffix());
}
} catch (JavaModelException e) {
}
}
}
}
/**
* Checks if a given {@link IPackageFragment} is in the list of exported packages for the current
* {@link IJavaProject}.
*
* @return true if the {@link IPackageFragment} is in the list of exported packages
*/
private boolean shouldDecorateExportedPackageFragment(IPackageFragment packageFragment) {
IJavaProject lavaProject = packageFragment.getJavaProject();
return FacetUtils.isBundleProject(lavaProject.getProject())
&& BundleManifestCorePlugin.getBundleManifestManager().getPackageExports(lavaProject).contains(packageFragment.getElementName());
}
/**
* Checks if a given {@link IPackageFragment} is in the list of resolved imports for the current
* {@link IJavaProject}.
*
* @return true if the {@link IPackageFragment} is not accessible from the java project
*/
private boolean shouldDecorateImportedPackageFragment(IPackageFragment packageFragment) {
IPackageFragmentRoot root = (IPackageFragmentRoot) packageFragment.getParent();
IJavaProject javaProject = packageFragment.getJavaProject();
if (!(javaProject.getProject().isAccessible() && javaProject.isOpen())) {
return false;
}
// Only decorate in bundle projects
if (!FacetUtils.isBundleProject(javaProject.getProject())) {
return false;
}
try {
IClasspathEntry entry = root.getRawClasspathEntry();
if (entry.getPath().equals(ServerClasspathContainer.CLASSPATH_CONTAINER_PATH)) {
if (!BundleManifestCorePlugin.getBundleManifestManager().getResolvedPackageImports(root.getJavaProject()).contains(
packageFragment.getElementName())) {
return true;
}
}
} catch (JavaModelException e) {
}
return false;
}
public void addListener(ILabelProviderListener listener) {
// Don't care
}
public void dispose() {
ColorMap.dispose();
JavaCore.removeElementChangedListener(changeListener);
}
public boolean isLabelProperty(Object element, String property) {
return false;
}
public void removeListener(ILabelProviderListener listener) {
// Don't care
}
/**
* Internal class used for creating {@link Color} instances.
*/
private static class ColorMap {
public static final Color GRAY_LIGHT = new Color(Display.getDefault(), 145, 145, 145);
public static void dispose() {
GRAY_LIGHT.dispose();
}
}
}