blob: fdcf0ccebb9773e8003e058b52fac1237a6dd60b [file] [log] [blame]
/**
* <copyright>
*
* Copyright (c) 2008-2010 See4sys and others.
* 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
*
* Contributors:
* See4sys - Initial API and implementation
* itemis - [446576] Add support for providing labels with different fonts and styles for model elements through BasicExplorerLabelProvider
*
* </copyright>
*/
package org.eclipse.sphinx.emf.explorer;
import java.util.Map;
import java.util.WeakHashMap;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.Assert;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.impl.EStructuralFeatureImpl.BasicFeatureMapEntry;
import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
import org.eclipse.emf.edit.provider.FeatureMapEntryWrapperItemProvider;
import org.eclipse.emf.edit.provider.ItemProviderAdapter;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
import org.eclipse.emf.transaction.RunnableWithResult;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.emf.transaction.ui.internal.Tracing;
import org.eclipse.emf.transaction.ui.provider.TransactionalAdapterFactoryLabelProvider;
import org.eclipse.emf.transaction.util.TransactionUtil;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.BaseLabelProvider;
import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider.IStyledLabelProvider;
import org.eclipse.jface.viewers.IFontProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.LabelProviderChangedEvent;
import org.eclipse.jface.viewers.StyledString;
import org.eclipse.osgi.util.NLS;
import org.eclipse.sphinx.emf.explorer.internal.messages.Messages;
import org.eclipse.sphinx.emf.util.WorkspaceEditingDomainUtil;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.navigator.ICommonContentExtensionSite;
import org.eclipse.ui.navigator.ICommonLabelProvider;
@SuppressWarnings("restriction")
public class BasicExplorerLabelProvider extends BaseLabelProvider implements ICommonLabelProvider, IFontProvider, IStyledLabelProvider {
protected Map<TransactionalEditingDomain, AdapterFactoryLabelProvider> modelLabelProviders = new WeakHashMap<TransactionalEditingDomain, AdapterFactoryLabelProvider>();
protected ILabelProviderListener modelLabelProviderListener;
@Override
public void init(ICommonContentExtensionSite aConfig) {
}
@Override
public void saveState(IMemento memento) {
// Do nothing by default
}
@Override
public void restoreState(IMemento memento) {
// Do nothing by default
}
protected AdapterFactoryLabelProvider getModelLabelProvider(Object element) {
// Retrieve editing domain behind specified object
TransactionalEditingDomain editingDomain = WorkspaceEditingDomainUtil.getEditingDomain(element);
if (editingDomain != null) {
// Retrieve model label provider for given editing domain; create new one if not existing yet
AdapterFactoryLabelProvider modelLabelProvider = modelLabelProviders.get(editingDomain);
if (modelLabelProvider == null) {
modelLabelProvider = createModelLabelProvider(editingDomain);
modelLabelProvider.addListener(getModelLabelProviderListener());
modelLabelProviders.put(editingDomain, modelLabelProvider);
}
return modelLabelProvider;
} else if (element instanceof EObject && ((EObject) element).eIsProxy()) {
// Use non-transactional adapter factory label provider to avoid that proxified EObjects end up being
// represented as empty tree nodes
AdapterFactory adapterFactory = getAdapterFactory(editingDomain);
if (adapterFactory != null) {
return new AdapterFactoryLabelProvider(adapterFactory);
}
}
return null;
}
protected AdapterFactoryLabelProvider createModelLabelProvider(final TransactionalEditingDomain editingDomain) {
Assert.isNotNull(editingDomain);
AdapterFactory adapterFactory = getAdapterFactory(editingDomain);
AdapterFactoryLabelProvider labelProvider = new TransactionalAdapterFactoryLabelProvider(editingDomain, adapterFactory) {
@Override
// Overridden to avoid the somewhat annoying logging of Eclipse exceptions resulting from event queue
// dispatching that is done before transaction is acquired and actually starts to run
protected <T> T run(RunnableWithResult<? extends T> run) {
try {
return TransactionUtil.runExclusive(editingDomain, run);
} catch (Exception e) {
Tracing.catching(TransactionalAdapterFactoryLabelProvider.class, "run", e); //$NON-NLS-1$
// propagate interrupt status because we are not throwing
Thread.currentThread().interrupt();
return null;
}
}
};
// Set default font to enable the customized getFont()
Font defaultFont = JFaceResources.getDefaultFont();
labelProvider.setDefaultFont(defaultFont);
return labelProvider;
}
/**
* Returns the {@link AdapterFactory adapter factory} to be used by this {@link BasicExplorerLabelProvider label
* provider} for creating {@link ItemProviderAdapter item provider}s which control the way how {@link EObject model
* element}s from given <code>editingDomain</code> are displayed and can be edited.
* <p>
* This implementation returns the {@link AdapterFactory adapter factory} which is embedded in the given
* <code>editingDomain</code> by default. Clients which want to use an alternative {@link AdapterFactory adapter
* factory} (e.g., an {@link AdapterFactory adapter factory} that creates {@link ItemProviderAdapter item provider}s
* which are specifically designed for the {@link IEditorPart editor} in which this
* {@link BasicExplorerLabelProvider label provider} is used) may override {@link #getCustomAdapterFactory()} and
* return any {@link AdapterFactory adapter factory} of their choice. This custom {@link AdapterFactory adapter
* factory} will then be returned as result by this method.
* </p>
*
* @param editingDomain
* The {@link TransactionalEditingDomain editing domain} whose embedded {@link AdapterFactory adapter
* factory} is to be returned as default. May be left <code>null</code> if
* {@link #getCustomAdapterFactory()} has been overridden and returns a non-<code>null</code> result.
* @return The {@link AdapterFactory adapter factory} that will be used by this {@link BasicExplorerLabelProvider
* label provider}. <code>null</code> if no custom {@link AdapterFactory adapter factory} is provided
* through {@link #getCustomAdapterFactory()} and no <code>editingDomain</code> has been specified.
* @see #getCustomAdapterFactory()
*/
protected AdapterFactory getAdapterFactory(TransactionalEditingDomain editingDomain) {
AdapterFactory customAdapterFactory = getCustomAdapterFactory();
if (customAdapterFactory != null) {
return customAdapterFactory;
} else if (editingDomain != null) {
return ((AdapterFactoryEditingDomain) editingDomain).getAdapterFactory();
}
return null;
}
/**
* Returns a custom {@link AdapterFactory adapter factory} to be used by this {@link BasicExplorerLabelProvider
* label provider} for creating {@link ItemProviderAdapter item provider}s which control the way how {@link EObject
* model element}s from given <code>editingDomain</code> are displayed and can be edited.
* <p>
* This implementation returns <code>null</code> as default. Clients which want to use their own
* {@link AdapterFactory adapter factory} (e.g., an {@link AdapterFactory adapter factory} that creates
* {@link ItemProviderAdapter item provider}s which are specifically designed for the {@link IEditorPart editor} in
* which this {@link BasicExplorerLabelProvider label provider} is used) may override this method and return any
* {@link AdapterFactory adapter factory} of their choice. This custom {@link AdapterFactory adapter factory} will
* then be returned as result by {@link #getAdapterFactory(TransactionalEditingDomain)}.
* </p>
*
* @return The custom {@link AdapterFactory adapter factory} that is to be used by this
* {@link BasicExplorerLabelProvider label provider}. <code>null</code> the default {@link AdapterFactory
* adapter factory} returned by {@link #getAdapterFactory(TransactionalEditingDomain)} should be used
* instead.
* @see #getAdapterFactory(TransactionalEditingDomain)
*/
protected AdapterFactory getCustomAdapterFactory() {
return null;
}
/*
* @see org.eclipse.ui.navigator.IDescriptionProvider#getDescription(java.lang.Object)
*/
@Override
public String getDescription(Object anElement) {
// Don't try to retrieve descriptions for files - leave this to other common label providers which are more
// appropriate
if (!(anElement instanceof IFile)) {
AdapterFactoryLabelProvider labelProvider = getModelLabelProvider(anElement);
if (labelProvider != null) {
String text = labelProvider.getText(anElement);
if (text != null && text.length() != 0) {
return text;
} else {
if (anElement instanceof FeatureMapEntryWrapperItemProvider) {
FeatureMapEntryWrapperItemProvider provider = (FeatureMapEntryWrapperItemProvider) anElement;
Object value = provider.getValue();
if (value instanceof BasicFeatureMapEntry) {
BasicFeatureMapEntry featureMapEntry = (BasicFeatureMapEntry) value;
String label = NLS.bind(Messages.label_EmptyFeatureMapEntryLabel, new String[] {
featureMapEntry.getEStructuralFeature().getName(), provider.getOwner().getClass().getSimpleName() });
return label.replaceFirst("Impl$", ""); //$NON-NLS-1$ //$NON-NLS-2$
}
}
}
}
// Don't return empty String because otherwise the tabbed property sheet's title bar looses its
// background color and becomes entirely blank
return " "; //$NON-NLS-1$
}
return null;
}
@Override
public boolean isLabelProperty(Object element, String property) {
return true;
}
@Override
public String getText(Object element) {
// Don't try to retrieve texts for files - leave this to other common label providers which are more
// appropriate
if (!(element instanceof IFile)) {
AdapterFactoryLabelProvider labelProvider = getModelLabelProvider(element);
if (labelProvider != null) {
return labelProvider.getText(element);
}
return ""; //$NON-NLS-1$
}
return null;
}
@Override
public Image getImage(Object element) {
// Don't try to retrieve images for files - leave this to other common label providers which are more
// appropriate
if (!(element instanceof IFile)) {
AdapterFactoryLabelProvider labelProvider = getModelLabelProvider(element);
if (labelProvider != null) {
return labelProvider.getImage(element);
}
}
return null;
}
@Override
public void dispose() {
for (AdapterFactoryLabelProvider labelProvider : modelLabelProviders.values()) {
labelProvider.removeListener(modelLabelProviderListener);
}
modelLabelProviders.clear();
super.dispose();
}
protected ILabelProviderListener getModelLabelProviderListener() {
if (modelLabelProviderListener == null) {
modelLabelProviderListener = createModelLabelProviderListener();
Assert.isNotNull(modelLabelProviderListener);
}
return modelLabelProviderListener;
}
protected ILabelProviderListener createModelLabelProviderListener() {
return new ILabelProviderListener() {
@Override
public void labelProviderChanged(LabelProviderChangedEvent event) {
// Route LabelProviderChangedEvent from embedded AdapterFactoryLabelProvider to enclosing
// BaseLabelProvider
fireLabelProviderChanged(event);
}
};
}
/*
* @see
* org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider.IStyledLabelProvider#getStyledText(java.lang.Object)
*/
@Override
public StyledString getStyledText(Object element) {
if (!(element instanceof IFile)) {
AdapterFactoryLabelProvider labelProvider = getModelLabelProvider(element);
// FIXME Remove try/catch once we don't need to support Eclipse 4.3 (and EMF 2.9) any longer
try {
if (labelProvider != null) {
return labelProvider.getStyledText(element);
}
} catch (NoSuchMethodError ex) {
String text = labelProvider.getText(element);
if (text != null && text.length() > 0) {
return new StyledString(text);
}
}
}
return null;
}
/*
* @see org.eclipse.jface.viewers.IFontProvider#getFont(java.lang.Object)
*/
@Override
public Font getFont(Object element) {
if (!(element instanceof IFile)) {
AdapterFactoryLabelProvider labelProvider = getModelLabelProvider(element);
if (labelProvider != null) {
return labelProvider.getFont(element);
}
}
return null;
}
}