blob: b1f4d63c81149d0b35ee685736089fe854f846f5 [file] [log] [blame]
/**
* <copyright>
*
* Copyright (c) 2008-2014 See4sys, BMW Car IT, itemis and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
*
* Contributors:
* See4sys - Initial API and implementation
* BMW Car IT - Added/Updated javadoc
* itemis - [446573] BasicExplorerContent/LabelProvider don't get refreshed upon changes on provided referenced elements
* itemis - [450882] Enable navigation to ancestor tree items in Model Explorer kind of model views
* itemis - [459865] Enhance ExtendedItemProviderAdapter to support EDataType elements that are no EEnums but wrap org.eclipse.emf.common.util.Enumerator
*
* </copyright>
*/
package org.eclipse.sphinx.emf.edit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.MissingResourceException;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.command.CommandWrapper;
import org.eclipse.emf.common.command.CompoundCommand;
import org.eclipse.emf.common.command.UnexecutableCommand;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.util.Enumerator;
import org.eclipse.emf.common.util.ResourceLocator;
import org.eclipse.emf.common.util.UniqueEList;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EEnum;
import org.eclipse.emf.ecore.EEnumLiteral;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.util.ExtendedMetaData;
import org.eclipse.emf.ecore.util.FeatureMap;
import org.eclipse.emf.ecore.util.FeatureMapUtil;
import org.eclipse.emf.edit.EMFEditPlugin;
import org.eclipse.emf.edit.command.AddCommand;
import org.eclipse.emf.edit.command.CommandParameter;
import org.eclipse.emf.edit.command.CreateChildCommand;
import org.eclipse.emf.edit.command.RemoveCommand;
import org.eclipse.emf.edit.command.SetCommand;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.edit.provider.AttributeValueWrapperItemProvider;
import org.eclipse.emf.edit.provider.ComposedImage;
import org.eclipse.emf.edit.provider.FeatureMapEntryWrapperItemProvider;
import org.eclipse.emf.edit.provider.ItemPropertyDescriptor;
import org.eclipse.emf.edit.provider.ItemProviderAdapter;
import org.eclipse.sphinx.emf.Activator;
import org.eclipse.sphinx.emf.ecore.DefaultEcoreTraversalHelper;
import org.eclipse.sphinx.emf.ecore.EcoreTraversalHelper;
/**
* Extension of the default {@linkplain ItemProviderAdapter item provider adapter} implementation provided by EMF Edit.
*/
public class ExtendedItemProviderAdapter extends ItemProviderAdapter {
private ITreeItemAncestorProvider treeItemContentProviderHelper = null;
/**
* An instance is created from an adapter factory. The factory is used as a key so that we always know which factory
* created this adapter.
*
* @param adapterFactory
* The factory which created the Adapter.
*/
public ExtendedItemProviderAdapter(AdapterFactory adapterFactory) {
super(adapterFactory);
}
protected ITreeItemAncestorProvider getTreeItemContentProviderHelper() {
if (treeItemContentProviderHelper == null) {
treeItemContentProviderHelper = createTreeItemContentProviderHelper();
}
return treeItemContentProviderHelper;
}
protected ITreeItemAncestorProvider createTreeItemContentProviderHelper() {
return new TreeItemAncestorProvider(this, adapterFactory);
}
public List<Object> getAncestorPath(Object object, boolean unwrap) {
return getTreeItemContentProviderHelper().getAncestorPath(object, unwrap);
}
public List<Object> getAncestorPath(Object beginObject, Class<?> endType, boolean unwrap) {
return getTreeItemContentProviderHelper().getAncestorPath(beginObject, endType, unwrap);
}
public Object findAncestor(Object object, Class<?> ancestorType, boolean unwrap) {
return getTreeItemContentProviderHelper().findAncestor(object, ancestorType, unwrap);
}
/*
* Overridden to enable wrapping of cross-referenced model objects by default. This is required to make sure that
* the latter get represented by instances of org.eclipse.emf.edit.provider.DelegatingWrapperItemProvider and may
* have a parent element that is different from object containing them.
* @see org.eclipse.emf.edit.provider.ItemProviderAdapter#isWrappingNeeded(java.lang.Object)
*/
@Override
protected boolean isWrappingNeeded(Object object) {
if (wrappingNeeded == null) {
wrappingNeeded = Boolean.FALSE;
for (EStructuralFeature feature : getChildrenFeatures(object)) {
if (feature instanceof EAttribute || feature instanceof EReference && !((EReference) feature).isContainment()) {
wrappingNeeded = Boolean.TRUE;
break;
}
}
}
return wrappingNeeded;
}
/*
* Overridden to create StyledDelegatingWrapperItemProvider instead of the default DelegatingWrapperItemProvider, so
* that StyledString-typed strings can be used as labels instead of ordinary text strings.
* @see org.eclipse.emf.edit.provider.ItemProviderAdapter#createWrapper(org.eclipse.emf.ecore.EObject,
* org.eclipse.emf.ecore.EStructuralFeature, java.lang.Object, int)
*/
@Override
protected Object createWrapper(EObject object, EStructuralFeature feature, Object value, int index) {
if (!isWrappingNeeded(object)) {
return value;
}
if (FeatureMapUtil.isFeatureMap(feature)) {
value = new FeatureMapEntryWrapperItemProvider((FeatureMap.Entry) value, object, (EAttribute) feature, index, adapterFactory,
getResourceLocator());
} else if (feature instanceof EAttribute) {
value = new AttributeValueWrapperItemProvider(value, object, (EAttribute) feature, index, adapterFactory, getResourceLocator());
} else if (!((EReference) feature).isContainment()) {
value = new ExtendedDelegatingWrapperItemProvider(value, object, feature, index, adapterFactory);
}
return value;
}
@Override
protected ItemPropertyDescriptor createItemPropertyDescriptor(AdapterFactory adapterFactory, ResourceLocator resourceLocator, String displayName,
String description, EStructuralFeature feature, boolean isSettable, boolean multiLine, boolean sortChoices, Object staticImage,
String category, String[] filterFlags) {
return new ExtendedItemPropertyDescriptor(adapterFactory, resourceLocator, displayName, description, feature, isSettable, multiLine,
sortChoices, staticImage, category, filterFlags);
}
/*
* Overridden for delegating retrieval of reachable objects to EcoreTraveralHelper.
* @see org.eclipse.sphinx.emf.ecore.EcoreTraversalHelper
*/
public Collection<?> getChoiceOfValues(Object object, EReference[] parentReferences, EStructuralFeature feature) {
if (object instanceof EObject) {
EObject eObject = (EObject) object;
if (parentReferences != null) {
Collection<Object> result = new UniqueEList<Object>();
for (EReference parentReference : parentReferences) {
result.addAll(getTraversalHelper().getReachableEObjects(eObject, parentReference));
}
return result;
} else if (feature != null) {
if (feature instanceof EReference) {
Collection<EObject> result = getTraversalHelper().getReachableEObjects(eObject, (EReference) feature);
if (!feature.isMany() && !result.contains(null)) {
result.add(null);
}
return result;
} else if (feature.getEType() instanceof EEnum) {
EEnum eEnum = (EEnum) feature.getEType();
List<Enumerator> enumerators = new ArrayList<Enumerator>();
for (EEnumLiteral eEnumLiteral : eEnum.getELiterals()) {
enumerators.add(eEnumLiteral.getInstance());
}
return enumerators;
} else {
EDataType eDataType = (EDataType) feature.getEType();
List<String> enumeration = ExtendedMetaData.INSTANCE.getEnumerationFacet(eDataType);
if (!enumeration.isEmpty()) {
List<Object> enumerators = new ArrayList<Object>();
for (String enumerator : enumeration) {
enumerators.add(EcoreUtil.createFromString(eDataType, enumerator));
}
return enumerators;
} else {
// Return enum constants from the EDataType's underlying Java enum type in case the latter is
// such one
Object[] javaEnumConstants = eDataType.getInstanceClass().getEnumConstants();
if (javaEnumConstants != null) {
return Arrays.asList(javaEnumConstants);
}
}
}
}
}
return null;
}
/**
* Returns the right traversal helper this item provider must use.
*
* @since 0.7.0
* @return The {@linkplain EcoreTraversalHelper traversal helper}
*/
protected EcoreTraversalHelper getTraversalHelper() {
return new DefaultEcoreTraversalHelper();
}
/*
* Overridden to add support for the case where: (1) collection objects of given command parameter have different
* containers, or the same container but different features and (2) specified owner via CommandParameter
* (commandParameter.getEOwner()) is no EObject. In this case, try to refer to parent or owner of specified owner.
* @see
* org.eclipse.emf.edit.provider.ItemProviderAdapter#factorRemoveCommand(org.eclipse.emf.edit.domain.EditingDomain,
* org.eclipse.emf.edit.command.CommandParameter)
*/
@Override
protected Command factorRemoveCommand(EditingDomain domain, CommandParameter commandParameter) {
if (commandParameter.getCollection() == null || commandParameter.getCollection().isEmpty()) {
return UnexecutableCommand.INSTANCE;
}
EObject eOwner = commandParameter.getEOwner();
// Try to refer to parent or owner in case that owner specified via CommandParameter is no EObject
if (eOwner == null) {
Object parentOfOwner = domain.getParent(commandParameter.getOwner());
if (parentOfOwner instanceof EObject) {
eOwner = (EObject) parentOfOwner;
}
}
final EObject eObject = eOwner;
final List<Object> list = new ArrayList<Object>(commandParameter.getCollection());
CompoundCommand removeCommand = new CompoundCommand(CompoundCommand.MERGE_COMMAND_ALL);
// Iterator over all the child references to factor each child to the right reference.
//
for (EStructuralFeature feature : getChildrenFeatures(commandParameter.getOwner())) {
// If it is a list type value...
//
if (feature.isMany()) {
List<?> value = (List<?>) getFeatureValue(eObject, feature);
// These will be the children belonging to this feature.
//
Collection<Object> childrenOfThisFeature = new ArrayList<Object>();
for (ListIterator<Object> objects = list.listIterator(); objects.hasNext();) {
Object o = objects.next();
// Is this object in this feature...
//
if (value.contains(o)) {
// Add it to the list and remove it from the other list.
//
childrenOfThisFeature.add(o);
objects.remove();
}
}
// If we have children to remove for this feature, create a command for it.
//
if (!childrenOfThisFeature.isEmpty()) {
removeCommand.append(createRemoveCommand(domain, eObject, feature, childrenOfThisFeature));
}
} else {
// It's just a single value
//
final Object value = getFeatureValue(eObject, feature);
for (ListIterator<Object> objects = list.listIterator(); objects.hasNext();) {
Object o = objects.next();
// Is this object in this feature...
//
if (o == value) {
// Create a command to unset this and remove the object from the other list.
//
Command setCommand = createSetCommand(domain, eObject, feature, SetCommand.UNSET_VALUE);
removeCommand.append(new CommandWrapper(setCommand) {
protected Collection<?> affected;
@Override
public void execute() {
super.execute();
affected = Collections.singleton(eObject);
}
@Override
public void undo() {
super.undo();
affected = Collections.singleton(value);
}
@Override
public void redo() {
super.redo();
affected = Collections.singleton(eObject);
}
@Override
public Collection<?> getResult() {
return Collections.singleton(value);
}
@Override
public Collection<?> getAffectedObjects() {
return affected;
}
});
objects.remove();
break;
}
}
}
}
// If all the objects are used up by the above, then we can't do the command.
//
if (list.isEmpty()) {
return removeCommand.unwrap();
} else {
// FIXME File bug to EMF: In the case where objects in the list have different container, or the same
// container but different features we must to iterate over all container features
for (Object object : new ArrayList<Object>(list)) {
if (object instanceof EObject) {
final EObject fallBackOwner = ((EObject) object).eContainer();
EStructuralFeature containingFeature = ((EObject) object).eContainingFeature();
if (containingFeature != null) {
if (containingFeature.isMany()) {
List<?> value = (List<?>) getFeatureValue(fallBackOwner, containingFeature);
// These will be the children belonging to this feature.
//
Collection<Object> childrenOfThisFeature = new ArrayList<Object>();
for (ListIterator<Object> objects = list.listIterator(); objects.hasNext();) {
Object o = objects.next();
// Is this object in this feature...
//
if (value.contains(o)) {
// Add it to the list and remove it from the other list.
//
childrenOfThisFeature.add(o);
objects.remove();
}
}
// If we have children to remove for this feature, create a command for it.
//
if (!childrenOfThisFeature.isEmpty()) {
removeCommand.append(createRemoveCommand(domain, fallBackOwner, containingFeature, childrenOfThisFeature));
}
} else {
// It's just a single value
//
final Object value = getFeatureValue(fallBackOwner, containingFeature);
for (ListIterator<Object> objects = list.listIterator(); objects.hasNext();) {
Object o = objects.next();
// Is this object in this feature...
//
if (o == value) {
// Create a command to set this to null and remove the object from the other list.
//
Command setCommand = domain.createCommand(SetCommand.class, new CommandParameter(fallBackOwner,
containingFeature, null));
removeCommand.append(new CommandWrapper(setCommand) {
protected Collection<?> affected;
@Override
public void execute() {
affected = Collections.singleton(fallBackOwner.eContainer() != null ? fallBackOwner.eContainer()
: fallBackOwner);
super.execute();
}
@Override
public void undo() {
super.undo();
affected = Collections.singleton(value);
}
@Override
public void redo() {
super.redo();
affected = Collections.singleton(fallBackOwner.eContainer() != null ? fallBackOwner.eContainer()
: fallBackOwner);
}
@Override
public Collection<?> getResult() {
return Collections.singleton(value);
}
@Override
public Collection<?> getAffectedObjects() {
return affected;
}
});
objects.remove();
break;
}
}
}
}
}
}
}
if (list.isEmpty()) {
return removeCommand.unwrap();
} else {
removeCommand.dispose();
return UnexecutableCommand.INSTANCE;
}
}
/*
* Overridden to support the case where specified owner via CommandParameter (commandParameter.getEOwner()) is no
* EObject. In this case, try to refer to parent or owner of specified owner.
* @see
* org.eclipse.emf.edit.provider.ItemProviderAdapter#factorAddCommand(org.eclipse.emf.edit.domain.EditingDomain,
* org.eclipse.emf.edit.command.CommandParameter)
*/
@Override
protected Command factorAddCommand(EditingDomain domain, CommandParameter commandParameter) {
if (commandParameter.getCollection() == null || commandParameter.getCollection().isEmpty()) {
return UnexecutableCommand.INSTANCE;
}
EObject eOwner = commandParameter.getEOwner();
// Try to refer to parent or owner in case that owner specified via CommandParameter is no EObject
if (eOwner == null) {
Object parentOfOwner = domain.getParent(commandParameter.getOwner());
if (parentOfOwner instanceof EObject) {
eOwner = (EObject) parentOfOwner;
}
}
final EObject eObject = eOwner;
final List<Object> list = new ArrayList<Object>(commandParameter.getCollection());
int index = commandParameter.getIndex();
CompoundCommand addCommand = new CompoundCommand(CompoundCommand.MERGE_COMMAND_ALL);
while (!list.isEmpty()) {
Iterator<Object> children = list.listIterator();
final Object firstChild = children.next();
EStructuralFeature childFeature = getChildFeature(eObject, firstChild);
if (childFeature == null) {
break;
}
// If it is a list type value...
//
else if (childFeature.isMany()) {
// Correct the index, if necessary.
//
if (index != CommandParameter.NO_INDEX) {
for (EStructuralFeature feature : getChildrenFeatures(commandParameter.getOwner())) {
if (feature == childFeature) {
break;
}
if (feature.isMany()) {
index -= ((List<?>) eObject.eGet(feature)).size();
} else if (eObject.eGet(feature) != null) {
index -= 1;
}
}
if (index < 0) {
break;
}
}
// These will be the children belonging to this feature.
//
Collection<Object> childrenOfThisFeature = new ArrayList<Object>();
childrenOfThisFeature.add(firstChild);
children.remove();
// Consume the rest of the appropriate children.
//
while (children.hasNext()) {
Object child = children.next();
// Is this child in this feature...
//
if (getChildFeature(eObject, child) == childFeature) {
// Add it to the list and remove it from the other list.
//
childrenOfThisFeature.add(child);
children.remove();
}
}
// Create a command for this feature,
//
addCommand.append(createAddCommand(domain, eObject, childFeature, childrenOfThisFeature, index));
if (index >= childrenOfThisFeature.size()) {
index -= childrenOfThisFeature.size();
} else {
index = CommandParameter.NO_INDEX;
}
} else if (eObject.eGet(childFeature) == null) {
Command setCommand = createSetCommand(domain, eObject, childFeature, firstChild);
addCommand.append(new CommandWrapper(setCommand) {
protected Collection<?> affected;
@Override
public void execute() {
super.execute();
affected = Collections.singleton(firstChild);
}
@Override
public void undo() {
super.undo();
affected = Collections.singleton(eObject);
}
@Override
public void redo() {
super.redo();
affected = Collections.singleton(firstChild);
}
@Override
public Collection<?> getResult() {
return Collections.singleton(firstChild);
}
@Override
public Collection<?> getAffectedObjects() {
return affected;
}
});
children.remove();
} else {
break;
}
}
// If all the objects aren't used up by the above, then we can't do the command.
//
if (list.isEmpty()) {
return addCommand.unwrap();
} else {
addCommand.dispose();
return UnexecutableCommand.INSTANCE;
}
}
@Override
protected Command createSetCommand(EditingDomain domain, EObject owner, EStructuralFeature feature, Object value, int index) {
Command setCommand = CustomCommandRegistry.INSTANCE.createCustomCommand(domain, new CommandParameter(owner, feature, value, index),
SetCommand.class);
if (setCommand != null) {
return setCommand;
}
return super.createSetCommand(domain, owner, feature, value, index);
}
@Override
protected Command createAddCommand(EditingDomain domain, EObject owner, EStructuralFeature feature, Collection<?> collection, int index) {
Command addCommand = CustomCommandRegistry.INSTANCE.createCustomCommand(domain, new CommandParameter(owner, feature, collection, index),
AddCommand.class);
if (addCommand != null) {
return addCommand;
}
return super.createAddCommand(domain, owner, feature, collection, index);
}
@Override
protected Command createRemoveCommand(EditingDomain domain, EObject owner, EStructuralFeature feature, Collection<?> collection) {
Command removeCommand = CustomCommandRegistry.INSTANCE.createCustomCommand(domain, new CommandParameter(owner, feature, collection),
RemoveCommand.class);
if (removeCommand != null) {
return removeCommand;
}
return super.createRemoveCommand(domain, owner, feature, collection);
}
/*
* Overridden for delegating to enhanced create child text API.
* @see org.eclipse.sphinx.emf.edit.ExtendedItemProviderAdapter.getCreateChildText(Object, Object, Object,
* Collection<?>, boolean)
* @see org.eclipse.emf.edit.provider.ItemProviderAdapter#getCreateChildText(java.lang.Object, java.lang.Object,
* java.lang.Object, java.util.Collection)
*/
@Override
public String getCreateChildText(Object owner, Object feature, Object child, Collection<?> selection) {
return getCreateChildText(owner, feature, child, selection, false);
}
/**
* Returns the text to be used as label or text of {@link CreateChildCommand} or {@link ExtendedCreateChildCommand}.
* Enables the create child text to be retrieved in qualified form provided that the underlying metamodel's EMF Edit
* implementation includes supports for that (requires the metamodel's EMF Edit implementation to be generated with
* generator model option "Editor > Creation Sub-menus" set to true). Qualified create child texts are expected to
* consist of two segments separated by a vertical bar. The leading segment typically corresponds to the name of
* feature on the owner object that holds the child object and the trailing segment to the type of the child object
* to be created. They are leveraged by
* org.eclipse.sphinx.emf.ui.actions.providers.BasicActionProvider#extractSubmenuActions(Collection<IAction>,
* ISelection) and
* org.eclipse.sphinx.emf.editors.forms.BasicTransactionalEditorActionBarContributor#extractSubmenuActions
* (Collection<IAction>, ISelection) so as to group the corresponding create child actions in submenus according to
* the qualified create child texts' leading segments.
* <p>
* Qualified create child texts are requested by {@link ExtendedCreateChildCommand#getText()} and returned to
* {@link CreateChildAction#configureAction(ISelection)} so as to make their {@link CreateChildAction#getText()
* action text}s qualified and prepare them for being grouped in creation submenus. Simple create child action texts
* are requested by {@link CreateChildCommand#CreateChildCommand(EditingDomain, EObject, EStructuralFeature, Object,
* int, Collection<?>, Helper)} and used to initialize the {@link CreateChildCommand#getLabel() command label} by
* which the command is displayed in any location outside the creation menus or submenus (e.g., undo and redo
* menus).
* </p>
*
* @param owner
* The <code>owner</code> object to which the new <code>child</code> object will be added.
* @param feature
* The <code>feature</code> of the <code>owner</code> object that is going to hold the new
* <code>child</code> object.
* @param child
* The new, i.e., still unassigned <code>child</code> object that will be added to the <code>owner</code>
* object.
* @param qualified
* <code>true</code> if a qualified create child text should be returned for metamodels whose EMF Edit
* implementation support that, <code>false</code> otherwise.
* @return The qualified or simple text to be used as label or text of {@link CreateChildCommand} or
* {@link ExtendedCreateChildCommand}.
*/
public String getCreateChildText(Object owner, Object feature, Object child, Collection<?> selection, boolean qualified) {
if (feature instanceof EStructuralFeature && FeatureMapUtil.isFeatureMap((EStructuralFeature) feature)) {
FeatureMap.Entry entry = (FeatureMap.Entry) child;
feature = entry.getEStructuralFeature();
child = entry.getValue();
}
String featureText = getFeatureText(feature);
String childTypeText = feature instanceof EAttribute ? getTypeText((EAttribute) feature) : getTypeText(child);
// Attribute feature?
if (feature instanceof EAttribute) {
// Use feature name as action text
return getResourceLocator().getString("_UI_CreateChild_text3", //$NON-NLS-1$
new Object[] { childTypeText, featureText });
}
// Reference feature whose name is different from target type
else if (!childTypeText.equals(featureText) && qualified) {
// The try/catch provides backwards compatibility with metamodels whose Edit support has no
// extra _UI_CreateChild_text1 key
try {
// Use combination of feature name and target type name as action text
return getResourceLocator().getString("_UI_CreateChild_text1", //$NON-NLS-1$
new Object[] { childTypeText, featureText });
} catch (MissingResourceException e) {
return getResourceLocator().getString("_UI_CreateChild_text", //$NON-NLS-1$
new Object[] { childTypeText, featureText });
}
}
// Reference feature whose name is equal to target type
else {
// Use only target type name as action text
return getResourceLocator().getString("_UI_CreateChild_text", //$NON-NLS-1$
new Object[] { childTypeText, featureText });
}
}
/*
* Overriden to avoid NullPointerException upon retrieval of image for XMLTypeDocumentRoot#processingInstruction
* entry in mixed attributes.
* @see org.eclipse.emf.edit.provider.ItemProviderAdapter#getCreateChildImage(java.lang.Object, java.lang.Object,
* java.lang.Object, java.util.Collection)
*/
@Override
public Object getCreateChildImage(Object owner, Object feature, Object child, Collection<?> selection) {
// FIXME File bug to EMF: NPE is raised on attempt to retrieve image for
// XMLTypeDocumentRoot#processingInstruction entry in mixed attributes
try {
return super.getCreateChildImage(owner, feature, child, selection);
} catch (NullPointerException ex) {
// Ignore exception
}
return EMFEditPlugin.INSTANCE.getImage("full/ctool16/CreateChild"); //$NON-NLS-1$
}
@Override
protected Command createCreateChildCommand(EditingDomain domain, EObject owner, EStructuralFeature feature, Object value, int index,
Collection<?> collection) {
return new ExtendedCreateChildCommand(domain, owner, feature, value, index, collection, this);
}
/*
* Overridden to add an exclamation mark as overlay to icons of EObjects that are proxies so as to facilitate their
* identification in the UI.
* @see org.eclipse.emf.edit.provider.ItemProviderAdapter#overlayImage(java.lang.Object, java.lang.Object)
*/
@Override
protected Object overlayImage(Object object, Object image) {
if (object instanceof EObject && ((EObject) object).eIsProxy()) {
List<Object> images = new ArrayList<Object>(2);
images.add(image);
images.add(Activator.INSTANCE.getImage("full/ovr16/exclampt_ovr")); //$NON-NLS-1$
image = new ComposedImage(images);
return image;
}
return super.overlayImage(object, image);
}
}