blob: f642efddabeda04ffc404265927097ffe10a545a [file] [log] [blame]
package org.eclipse.ui.internal.decorators;
/************************************************************************
Copyright (c) 2000, 2002 IBM Corporation and others.
All rights reserved. This program and the accompanying materials
are made available under the terms of the Common Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/cpl-v10.html
Contributors:
IBM - Initial implementation
************************************************************************/
import java.util.*;
import org.eclipse.core.runtime.*;
import org.eclipse.jface.util.ListenerList;
import org.eclipse.jface.util.SafeRunnable;
import org.eclipse.jface.viewers.*;
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.IContributorResourceAdapter;
import org.eclipse.ui.IDecoratorManager;
import org.eclipse.ui.internal.*;
/**
* The DecoratorManager is the class that handles all of the
* decorators defined in the image.
*
* @since 2.0
*/
public class DecoratorManager
implements ILabelDecorator, ILabelProviderListener, IDecoratorManager {
private DecorationScheduler scheduler;
private LightweightDecoratorManager lightweightManager;
//Hold onto the list of listeners to be told if a change has occured
private ListenerList listeners = new ListenerList();
//The cachedDecorators are a 1-many mapping of type to full decorator.
private HashMap cachedFullDecorators = new HashMap();
//The full definitions read from the registry
private FullDecoratorDefinition[] fullDefinitions;
private static final FullDecoratorDefinition[] EMPTY_FULL_DEF =
new FullDecoratorDefinition[0];
private final String PREFERENCE_SEPARATOR = ","; //$NON-NLS-1$
private final String VALUE_SEPARATOR = ":"; //$NON-NLS-1$
private final String P_TRUE = "true"; //$NON-NLS-1$
private final String P_FALSE = "false"; //$NON-NLS-1$
/**
* Create a new instance of the receiver and load the
* settings from the installed plug-ins.
*/
public DecoratorManager() {
DecoratorRegistryReader reader = new DecoratorRegistryReader();
Collection values = reader.readRegistry(Platform.getPluginRegistry());
ArrayList full = new ArrayList();
ArrayList lightweight = new ArrayList();
Iterator allDefinitions = values.iterator();
while (allDefinitions.hasNext()) {
DecoratorDefinition nextDefinition =
(DecoratorDefinition) allDefinitions.next();
if (nextDefinition.isFull())
full.add(nextDefinition);
else
lightweight.add(nextDefinition);
}
fullDefinitions = new FullDecoratorDefinition[full.size()];
full.toArray(fullDefinitions);
LightweightDecoratorDefinition[] lightweightDefinitions =
new LightweightDecoratorDefinition[lightweight.size()];
lightweight.toArray(lightweightDefinitions);
lightweightManager =
new LightweightDecoratorManager(lightweightDefinitions);
scheduler = new DecorationScheduler(this);
}
/**
* See if the supplied decorator cache has a value for the
* element. If not calculate it from the enabledDefinitions and
* update the cache.
* @return Collection of DecoratorDefinition.
* @param element. The element being tested.
* @param cachedDecorators. The cache for decorator lookup.
* @param enabledDefinitions. The definitions currently defined for this decorator.
*/
static Collection getDecoratorsFor(
Object element,
DecoratorDefinition[] enabledDefinitions) {
ArrayList decorators = new ArrayList();
for (int i = 0; i < enabledDefinitions.length; i++) {
if (enabledDefinitions[i]
.getEnablement()
.isEnabledForExpression(
element,
ActionExpression.EXP_TYPE_OBJECT_CLASS))
decorators.add(enabledDefinitions[i]);
}
return decorators;
}
/**
* Restore the stored values from the preference
* store and register the receiver as a listener
* for all of the enabled decorators.
*/
public void restoreListeners() {
applyDecoratorsPreference();
}
/**
* Add the listener to the list of listeners.
*/
public void addListener(ILabelProviderListener listener) {
listeners.add(listener);
}
/**
* Remove the listener from the list.
*/
public void removeListener(ILabelProviderListener listener) {
listeners.remove(listener);
}
/**
* Inform all of the listeners that require an update
*/
private void fireListeners(final LabelProviderChangedEvent event) {
Object [] array = listeners.getListeners();
for (int i = 0; i < array.length; i ++) {
final ILabelProviderListener l = (ILabelProviderListener)array[i];
Platform.run(new SafeRunnable() {
public void run() {
l.labelProviderChanged(event);
}
public void handleException(Throwable e) {
super.handleException(e);
//If and unexpected exception happens, remove it
//to make sure the workbench keeps running.
removeListener(l);
}
});
}
}
/**
* Decorate the image provided for the element type.
* Then look for an IResource that adapts to it an apply
* all of the adaptable decorators.
* @return String or null if there are none defined for this type.
* @param Image
* @param Object
*/
public String decorateText(String text, Object element) {
//Get any adaptions to IResource
Object adapted = getResourceAdapter(element);
String result = scheduler.decorateWithText(text, element, adapted);
FullDecoratorDefinition[] decorators = getDecoratorsFor(element);
for (int i = 0; i < decorators.length; i++) {
if (decorators[i].getEnablement().isEnabledFor(element)) {
String newResult = decorators[i].decorateText(result, element);
if (newResult != null)
result = newResult;
}
}
if (adapted != null) {
decorators = getDecoratorsFor(adapted);
for (int i = 0; i < decorators.length; i++) {
if (decorators[i].isAdaptable()
&& decorators[i].getEnablement().isEnabledFor(adapted)) {
String newResult =
decorators[i].decorateText(result, adapted);
if (newResult != null)
result = newResult;
}
}
}
return result;
}
/**
* Decorate the image provided for the element type.
* Then look for an IResource that adapts to it an apply
* all of the adaptable decorators.
* @return Image or null if there are none defined for this type.
* @param Image
* @param Object
*/
public Image decorateImage(Image image, Object element) {
Object adapted = getResourceAdapter(element);
Image result = scheduler.decorateWithOverlays(image, element, adapted);
FullDecoratorDefinition[] decorators = getDecoratorsFor(element);
for (int i = 0; i < decorators.length; i++) {
if (decorators[i].getEnablement().isEnabledFor(element)) {
Image newResult = decorators[i].decorateImage(result, element);
if (newResult != null)
result = newResult;
}
}
//Get any adaptions to IResource
if (adapted != null) {
decorators = getDecoratorsFor(adapted);
for (int i = 0; i < decorators.length; i++) {
if (decorators[i].isAdaptable()
&& decorators[i].getEnablement().isEnabledFor(adapted)) {
Image newResult =
decorators[i].decorateImage(result, adapted);
if (newResult != null)
result = newResult;
}
}
}
return result;
}
/**
* Get the resource adapted object for the supplied
* element. Return null if there isn't one.
*/
private Object getResourceAdapter(Object element) {
//Get any adaptions to IResource
if (element instanceof IAdaptable) {
IAdaptable adaptable = (IAdaptable) element;
Object resourceAdapter =
adaptable.getAdapter(IContributorResourceAdapter.class);
if (resourceAdapter == null)
resourceAdapter =
DefaultContributorResourceAdapter.getDefault();
Object adapted =
(
(
IContributorResourceAdapter) resourceAdapter)
.getAdaptedResource(
adaptable);
if (adapted != element)
return adapted; //Avoid applying decorator twice
}
return null;
}
/**
* Return whether or not the decorator registered for element
* has a label property called property name.
*/
public boolean isLabelProperty(Object element, String property) {
return isLabelProperty(element, property, true);
}
/**
* Return whether or not the decorator registered for element
* has a label property called property name.
* Check for an adapted resource if checkAdapted is true.
*/
public boolean isLabelProperty(
Object element,
String property,
boolean checkAdapted) {
boolean fullCheck =
isLabelProperty(element, property, getDecoratorsFor(element));
if (fullCheck)
return fullCheck;
boolean lightweightCheck =
isLabelProperty(
element,
property,
lightweightManager.getDecoratorsFor(element));
if (lightweightCheck)
return true;
if (checkAdapted) {
//Get any adaptions to IResource
Object adapted = getResourceAdapter(element);
if (adapted == null || adapted == element)
return false;
fullCheck =
isLabelProperty(adapted, property, getDecoratorsFor(adapted));
if (fullCheck)
return fullCheck;
return isLabelProperty(
adapted,
property,
lightweightManager.getDecoratorsFor(adapted));
}
return false;
}
private boolean isLabelProperty(
Object element,
String property,
DecoratorDefinition[] decorators) {
for (int i = 0; i < decorators.length; i++) {
if (decorators[i].getEnablement().isEnabledFor(element)
&& decorators[i].isLabelProperty(element, property))
return true;
}
return false;
}
/**
* Returns the class search order starting with <code>extensibleClass</code>.
* The search order is defined in this class' comment.
*/
private Vector computeClassOrder(Class extensibleClass) {
Vector result = new Vector(4);
Class clazz = extensibleClass;
while (clazz != null) {
result.addElement(clazz);
clazz = clazz.getSuperclass();
}
return result;
}
/**
* Returns the interface search order for the class hierarchy described
* by <code>classList</code>.
* The search order is defined in this class' comment.
*/
private List computeInterfaceOrder(List classList) {
List result = new ArrayList(4);
Map seen = new HashMap(4);
for (Iterator list = classList.iterator(); list.hasNext();) {
Class[] interfaces = ((Class) list.next()).getInterfaces();
internalComputeInterfaceOrder(interfaces, result, seen);
}
return result;
}
/**
* Add interface Class objects to the result list based
* on the class hierarchy. Interfaces will be searched
* based on their position in the result list.
*/
private void internalComputeInterfaceOrder(
Class[] interfaces,
List result,
Map seen) {
List newInterfaces = new ArrayList(seen.size());
for (int i = 0; i < interfaces.length; i++) {
Class interfac = interfaces[i];
if (seen.get(interfac) == null) {
result.add(interfac);
seen.put(interfac, interfac);
newInterfaces.add(interfac);
}
}
for (Iterator newList = newInterfaces.iterator(); newList.hasNext();)
internalComputeInterfaceOrder(
((Class) newList.next()).getInterfaces(),
result,
seen);
}
/**
* Return the enabled full decorator definitions.
* @return FullDecoratorDefinition[]
*/
private FullDecoratorDefinition[] enabledFullDefinitions() {
ArrayList result = new ArrayList();
for (int i = 0; i < fullDefinitions.length; i++) {
if (fullDefinitions[i].isEnabled())
result.add(fullDefinitions[i]);
}
FullDecoratorDefinition[] returnArray =
new FullDecoratorDefinition[result.size()];
result.toArray(returnArray);
return returnArray;
}
/*
* @see IBaseLabelProvider#dispose()
*/
public void dispose() {
//Do nothing as this is not viewer dependant
}
/*
* @see IDecoratorManager.reset()
*/
public void reset() {
cachedFullDecorators = new HashMap();
lightweightManager.reset();
fireListeners(new LabelProviderChangedEvent(this));
writeDecoratorsPreference();
}
/**
* Get the DecoratorDefinitions defined on the receiver.
*/
public DecoratorDefinition[] getAllDecoratorDefinitions() {
LightweightDecoratorDefinition[] lightweightDefinitions =
lightweightManager.getDefinitions();
DecoratorDefinition[] returnValue =
new DecoratorDefinition[fullDefinitions.length
+ lightweightDefinitions.length];
System.arraycopy(
fullDefinitions,
0,
returnValue,
0,
fullDefinitions.length);
System.arraycopy(
lightweightDefinitions,
0,
returnValue,
fullDefinitions.length,
lightweightDefinitions.length);
return returnValue;
}
/*
* @see ILabelProviderListener#labelProviderChanged(LabelProviderChangedEvent)
*/
public void labelProviderChanged(LabelProviderChangedEvent event) {
fireListeners(event);
}
/**
* Store the currently enabled decorators in
* preference store.
*/
private void writeDecoratorsPreference() {
StringBuffer enabledIds = new StringBuffer();
writeDecoratorsPreference(enabledIds, fullDefinitions);
writeDecoratorsPreference(
enabledIds,
lightweightManager.getDefinitions());
WorkbenchPlugin.getDefault().getPreferenceStore().setValue(
IPreferenceConstants.ENABLED_DECORATORS,
enabledIds.toString());
}
private void writeDecoratorsPreference(
StringBuffer enabledIds,
DecoratorDefinition[] definitions) {
for (int i = 0; i < definitions.length; i++) {
enabledIds.append(definitions[i].getId());
enabledIds.append(VALUE_SEPARATOR);
if (definitions[i].isEnabled())
enabledIds.append(P_TRUE);
else
enabledIds.append(P_FALSE);
enabledIds.append(PREFERENCE_SEPARATOR);
}
}
/**
* Get the currently enabled decorators in
* preference store and set the state of the
* current definitions accordingly.
*/
private void applyDecoratorsPreference() {
String preferenceValue =
WorkbenchPlugin.getDefault().getPreferenceStore().getString(
IPreferenceConstants.ENABLED_DECORATORS);
StringTokenizer tokenizer =
new StringTokenizer(preferenceValue, PREFERENCE_SEPARATOR);
Set enabledIds = new HashSet();
Set disabledIds = new HashSet();
while (tokenizer.hasMoreTokens()) {
String nextValuePair = tokenizer.nextToken();
//Strip out the true or false to get the id
String id =
nextValuePair.substring(
0,
nextValuePair.indexOf(VALUE_SEPARATOR));
if (nextValuePair.endsWith(P_TRUE))
enabledIds.add(id);
else
disabledIds.add(id);
}
for (int i = 0; i < fullDefinitions.length; i++) {
String id = fullDefinitions[i].getId();
if (enabledIds.contains(id))
fullDefinitions[i].setEnabledWithErrorHandling(true);
else {
if (disabledIds.contains(id))
fullDefinitions[i].setEnabledWithErrorHandling(false);
}
}
LightweightDecoratorDefinition[] lightweightDefinitions =
lightweightManager.getDefinitions();
for (int i = 0; i < lightweightDefinitions.length; i++) {
String id = lightweightDefinitions[i].getId();
if (enabledIds.contains(id))
lightweightDefinitions[i].setEnabledWithErrorHandling(true);
else {
if (disabledIds.contains(id))
lightweightDefinitions[i].setEnabledWithErrorHandling(
false);
}
}
}
/**
* Shutdown the decorator manager by disabling all
* of the decorators so that dispose() will be called
* on them.
*/
public void shutdown() {
//Disable all fo the enabled decorators
//so as to force a dispose of thier decorators
for (int i = 0; i < fullDefinitions.length; i++) {
if (fullDefinitions[i].isEnabled())
fullDefinitions[i].setEnabledWithErrorHandling(false);
}
lightweightManager.shutdown();
scheduler.shutdown();
}
/**
* @see IDecoratorManager#getEnabled(String)
*/
public boolean getEnabled(String decoratorId) {
DecoratorDefinition definition = getDecoratorDefinition(decoratorId);
if (definition == null)
return false;
else
return definition.isEnabled();
}
/**
* @see IDecoratorManager#getLabelDecorator()
*/
public ILabelDecorator getLabelDecorator() {
return this;
}
/**
* @see IDecoratorManager#setEnabled(String, boolean)
*/
public void setEnabled(String decoratorId, boolean enabled)
throws CoreException {
DecoratorDefinition definition = getDecoratorDefinition(decoratorId);
if (definition != null)
definition.setEnabled(enabled);
}
/*
* @see IDecoratorManager#getBaseLabelProvider(String)
*/
public IBaseLabelProvider getBaseLabelProvider(String decoratorId) {
IBaseLabelProvider fullProvider = getLabelDecorator(decoratorId);
if (fullProvider == null)
return getLightweightLabelDecorator(decoratorId);
else
return fullProvider;
}
/*
* @see IDecoratorManager#getLabelDecorator(String)
*/
public ILabelDecorator getLabelDecorator(String decoratorId) {
FullDecoratorDefinition definition =
getFullDecoratorDefinition(decoratorId);
//Do not return for a disabled decorator
if (definition != null && definition.isEnabled()) {
return definition.getDecorator();
}
return null;
}
/*
* @see IDecoratorManager#getLightweightLabelDecorator(String)
*/
public ILightweightLabelDecorator getLightweightLabelDecorator(String decoratorId) {
LightweightDecoratorDefinition definition =
lightweightManager.getDecoratorDefinition(decoratorId);
//Do not return for a disabled decorator
if (definition != null && definition.isEnabled()) {
return definition.getDecorator();
}
return null;
}
/**
* Get the DecoratorDefinition with the supplied id
* @return DecoratorDefinition or <code>null</code> if it is not found
* @param decoratorId String
*/
private DecoratorDefinition getDecoratorDefinition(String decoratorId) {
DecoratorDefinition returnValue =
getFullDecoratorDefinition(decoratorId);
if (returnValue == null)
return lightweightManager.getDecoratorDefinition(decoratorId);
else
return returnValue;
}
/**
* Get the FullDecoratorDefinition with the supplied id
* @return FullDecoratorDefinition or <code>null</code> if it is not found
* @param decoratorId String
*/
private FullDecoratorDefinition getFullDecoratorDefinition(String decoratorId) {
for (int i = 0; i < fullDefinitions.length; i++) {
if (fullDefinitions[i].getId().equals(decoratorId))
return fullDefinitions[i];
}
return null;
}
/**
* Get the full decorator definitions registered for elements of this type.
*/
private FullDecoratorDefinition[] getDecoratorsFor(Object element) {
if (element == null)
return EMPTY_FULL_DEF;
String className = element.getClass().getName();
FullDecoratorDefinition[] decoratorArray =
(FullDecoratorDefinition[]) cachedFullDecorators.get(className);
if (decoratorArray != null) {
return decoratorArray;
}
Collection decorators =
getDecoratorsFor(element, enabledFullDefinitions());
if (decorators.size() == 0)
decoratorArray = EMPTY_FULL_DEF;
else {
decoratorArray = new FullDecoratorDefinition[decorators.size()];
decorators.toArray(decoratorArray);
}
cachedFullDecorators.put(className, decoratorArray);
return decoratorArray;
}
/**
* Returns the lightweightManager.
* @return LightweightDecoratorManager
*/
LightweightDecoratorManager getLightweightManager() {
return lightweightManager;
}
/**
* @see org.eclipse.ui.IDecoratorManager#update(java.lang.String)
*/
public void update(String decoratorId) {
IBaseLabelProvider provider = getBaseLabelProvider(decoratorId);
if(provider != null)
fireListeners(new LabelProviderChangedEvent(provider));
}
}