blob: dd3bf109c0c64371e03bd9dd8f9b6b80e9c9d75a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012, 2016 Obeo.
* 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:
* Obeo - initial API and implementation
* Philip Langer (EclipseSource) - bug 488618
*******************************************************************************/
package org.eclipse.emf.compare.provider.spec;
import static com.google.common.base.Strings.isNullOrEmpty;
import static com.google.common.collect.Iterables.any;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.compare.Diff;
import org.eclipse.emf.compare.DifferenceKind;
import org.eclipse.emf.compare.DifferenceSource;
import org.eclipse.emf.compare.DifferenceState;
import org.eclipse.emf.compare.Match;
import org.eclipse.emf.compare.ReferenceChange;
import org.eclipse.emf.compare.internal.EMFCompareEditMessages;
import org.eclipse.emf.compare.provider.IItemDescriptionProvider;
import org.eclipse.emf.compare.provider.IItemStyledLabelProvider;
import org.eclipse.emf.compare.provider.ISemanticObjectLabelProvider;
import org.eclipse.emf.compare.provider.ReferenceChangeItemProvider;
import org.eclipse.emf.compare.provider.SafeAdapterFactoryItemDelegator;
import org.eclipse.emf.compare.provider.utils.ComposedStyledString;
import org.eclipse.emf.compare.provider.utils.IStyledString;
import org.eclipse.emf.compare.provider.utils.IStyledString.Style;
import org.eclipse.emf.compare.utils.EMFComparePredicates;
import org.eclipse.emf.compare.utils.ReferenceUtil;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.edit.provider.AdapterFactoryItemDelegator;
import org.eclipse.emf.edit.provider.IItemFontProvider;
/**
* Specialized {@link ReferenceChangeItemProvider} returning nice output for {@link #getText(Object)} and
* {@link #getImage(Object)}.
*
* @author <a href="mailto:mikael.barbero@obeo.fr">Mikael Barbero</a>
*/
public class ReferenceChangeItemProviderSpec extends ReferenceChangeItemProvider implements IItemStyledLabelProvider, IItemDescriptionProvider, ISemanticObjectLabelProvider {
/** The elide length. */
private static final int ELIDE_LENGTH = 50;
/** The image provider used with this item provider. */
private final OverlayImageProvider overlayProvider;
/** The item delegator for reference change values. */
private final AdapterFactoryItemDelegator itemDelegator;
/**
* Constructor calling super {@link #ReferenceChangeItemProvider(AdapterFactory)}.
*
* @param adapterFactory
* the adapter factory
*/
public ReferenceChangeItemProviderSpec(AdapterFactory adapterFactory) {
super(adapterFactory);
itemDelegator = new SafeAdapterFactoryItemDelegator(getRootAdapterFactory());
overlayProvider = new OverlayImageProvider(getResourceLocator());
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.edit.provider.ItemProviderAdapter#isAdapterForType(Object)
*/
@Override
public boolean isAdapterForType(Object type) {
if (type == ReferenceChangeItemProviderSpec.class) {
return true;
}
return super.isAdapterForType(type);
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.compare.provider.ReferenceChangeItemProvider#getText(java.lang.Object)
*/
@Override
public String getText(Object object) {
return getStyledText(object).getString();
}
/**
* Returns the change text for the given diff on the given feature.
*
* @param diff
* the diff representing the change.
* @param feature
* the feature that changed.
* @return the change text for the given diff on the given feature.
*/
static String changeText(final Diff diff, EStructuralFeature feature) {
DifferenceSource source = diff.getSource();
Match matchOfInterrest = diff.getMatch();
final EObject sourceSide;
final EObject otherSide;
if (source == DifferenceSource.LEFT) {
sourceSide = matchOfInterrest.getLeft();
otherSide = matchOfInterrest.getRight();
} else { // source == DifferenceSource.RIGHT
sourceSide = matchOfInterrest.getRight();
otherSide = matchOfInterrest.getLeft();
}
String changeText = changeText(feature, sourceSide, otherSide);
return changeText;
}
/**
* Returns the type of change linked to the given {@link EStructuralFeature} ("unset", "set" or
* "changed"), according the the given sides.
*
* @param eStructuralFeature
* the given {@link EStructuralFeature}.
* @param sourceSide
* the source side as an {@link EObject}.
* @param otherSide
* the other side as an {@link EObject}.
* @return a String ("unset", "set" or "changed") containing the type of change linked to the given
* {@link EStructuralFeature}, according the the given sides.
*/
private static String changeText(final EStructuralFeature eStructuralFeature, EObject sourceSide,
EObject otherSide) {
String changeText;
if (sourceSide != null) {
Object leftValue = ReferenceUtil.safeEGet(sourceSide, eStructuralFeature);
if (leftValue == null || isStringAndNullOrEmpty(leftValue)) {
changeText = EMFCompareEditMessages.getString("ReferenceChangeItemProviderSpec.unset"); //$NON-NLS-1$
} else if (otherSide != null) {
Object otherValue = ReferenceUtil.safeEGet(otherSide, eStructuralFeature);
if (otherValue == null || isStringAndNullOrEmpty(otherValue)) {
changeText = EMFCompareEditMessages.getString("ReferenceChangeItemProviderSpec.set"); //$NON-NLS-1$
} else {
changeText = EMFCompareEditMessages.getString("ReferenceChangeItemProviderSpec.changed"); //$NON-NLS-1$
}
} else {
changeText = EMFCompareEditMessages.getString("ReferenceChangeItemProviderSpec.set"); //$NON-NLS-1$
}
} else {
changeText = EMFCompareEditMessages.getString("ReferenceChangeItemProviderSpec.unset"); //$NON-NLS-1$
}
return changeText;
}
/**
* Checks if the given Object is a null or empty String.
*
* @param s
* the given Object.
* @return true if the Object is a null or empty String, false otherwise.
*/
private static boolean isStringAndNullOrEmpty(Object s) {
if (s instanceof String) {
return isNullOrEmpty((String)s);
} else {
return false;
}
}
/**
* Returns the name of the reference linked to the given {@link ReferenceChange}.
*
* @param refChange
* the given {@link ReferenceChange}.
* @return the name of the reference linked to the given {@link ReferenceChange}.
*/
protected String getReferenceText(final ReferenceChange refChange) {
return refChange.getReference().getName();
}
/**
* Converts to text the given {@link ReferenceChange}.
*
* @param refChange
* the given {@link ReferenceChange}.
* @return a nice text from the the given {@link ReferenceChange}.
*/
protected String getValueText(final ReferenceChange refChange) {
EObject refChangeValue = refChange.getValue();
String value = itemDelegator.getText(refChangeValue);
if (isNullOrEmpty(value)) {
if (refChangeValue.eIsProxy()) {
value = "proxy : " + ((InternalEObject)refChangeValue).eProxyURI().toString(); //$NON-NLS-1$
} else {
value = "<null>"; //$NON-NLS-1$
}
} else {
value = org.eclipse.emf.compare.provider.spec.Strings.elide(value, ELIDE_LENGTH, "..."); //$NON-NLS-1$
}
return value;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.compare.provider.ReferenceChangeItemProvider#getImage(java.lang.Object)
*/
@Override
public Object getImage(Object object) {
ReferenceChange refChange = (ReferenceChange)object;
Object refChangeValueImage = itemDelegator.getImage(refChange.getValue());
Object diffImage = overlayProvider.getComposedImage(refChange, refChangeValueImage);
Object ret = overlayImage(object, diffImage);
return ret;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.edit.provider.ItemProviderAdapter#getForeground(java.lang.Object)
*/
@Override
public Object getForeground(Object object) {
ReferenceChange referenceChange = (ReferenceChange)object;
switch (referenceChange.getState()) {
case MERGED:
case DISCARDED:
return URI.createURI("color://rgb/156/156/156"); //$NON-NLS-1$
default:
return super.getForeground(object);
}
}
/* Missing override : only for EMF 2.10 and later. Do not tag. */
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.compare.provider.IItemStyledLabelProvider#getStyledText(java.lang.Object)
*/
@Override
public IStyledString.IComposedStyledString getStyledText(Object object) {
final ReferenceChange refChange = (ReferenceChange)object;
final String valueText = getValueText(refChange);
final String referenceText = getReferenceText(refChange);
ComposedStyledString ret = new ComposedStyledString();
if (refChange.getReference().isContainment()) {
EObject value = refChange.getValue();
Match match = refChange.getMatch().getComparison().getMatch(value);
if (match != null) {
Iterable<Diff> subDifferences = match.getAllDifferences();
if (refChange.getState() != DifferenceState.UNRESOLVED
&& any(subDifferences, EMFComparePredicates.hasState(DifferenceState.UNRESOLVED))) {
ret.append("> ", Style.DECORATIONS_STYLER); //$NON-NLS-1$
}
}
}
final EObject refChangeValue = refChange.getValue();
if (refChangeValue.eIsProxy()) {
Style italic = Style.builder().setFont(IItemFontProvider.ITALIC_FONT).build();
ret.append(valueText, italic);
} else {
ret.append(valueText);
}
ret.append(" [" + referenceText, Style.DECORATIONS_STYLER); //$NON-NLS-1$
switch (refChange.getKind()) {
case ADD:
ret.append(
' ' + EMFCompareEditMessages
.getString("ReferenceChangeItemProviderSpec.decoration.add"), //$NON-NLS-1$
Style.DECORATIONS_STYLER);
break;
case DELETE:
ret.append(
' ' + EMFCompareEditMessages
.getString("ReferenceChangeItemProviderSpec.decoration.delete"), //$NON-NLS-1$
Style.DECORATIONS_STYLER);
break;
case CHANGE:
ret.append(' ' + changeText(refChange, refChange.getReference()), Style.DECORATIONS_STYLER);
break;
case MOVE:
ret.append(
' ' + EMFCompareEditMessages
.getString("ReferenceChangeItemProviderSpec.decoration.move"), //$NON-NLS-1$
Style.DECORATIONS_STYLER);
break;
default:
throw new IllegalStateException("Unsupported " + DifferenceKind.class.getSimpleName() //$NON-NLS-1$
+ " value: " + refChange.getKind()); //$NON-NLS-1$
}
ret.append("]", Style.DECORATIONS_STYLER); //$NON-NLS-1$
return ret;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.compare.provider.ISemanticObjectLabelProvider#getSemanticObjectLabel(java.lang.Object)
* @since 4.2
*/
public String getSemanticObjectLabel(Object object) {
final ReferenceChange refChange = (ReferenceChange)object;
final String valueText = getValueText(refChange);
StringBuilder ret = new StringBuilder();
if (refChange.getReference().isContainment()) {
EObject value = refChange.getValue();
Match match = refChange.getMatch().getComparison().getMatch(value);
if (match != null) {
Iterable<Diff> subDifferences = match.getAllDifferences();
if (refChange.getState() != DifferenceState.UNRESOLVED
&& any(subDifferences, EMFComparePredicates.hasState(DifferenceState.UNRESOLVED))) {
ret.append("> "); //$NON-NLS-1$
}
}
}
ret.append(valueText);
return ret.toString();
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.compare.provider.IItemDescriptionProvider#getDescription(java.lang.Object)
*/
public String getDescription(Object object) {
final ReferenceChange refChange = (ReferenceChange)object;
final String valueText = getValueText(refChange);
final String referenceText = getReferenceText(refChange);
String remotely = ""; //$NON-NLS-1$
if (refChange.getSource() == DifferenceSource.RIGHT) {
remotely = "remotely "; //$NON-NLS-1$
}
String ret = ""; //$NON-NLS-1$
final String hasBeen = " has been "; //$NON-NLS-1$
switch (refChange.getKind()) {
case ADD:
ret = valueText + hasBeen + remotely + "added to " + referenceText; //$NON-NLS-1$
break;
case DELETE:
ret = valueText + hasBeen + remotely + "deleted from " + referenceText; //$NON-NLS-1$
break;
case CHANGE:
String changeText = changeText(refChange, refChange.getReference());
ret = referenceText + " " + valueText + hasBeen + remotely + changeText; //$NON-NLS-1$
break;
case MOVE:
ret = valueText + hasBeen + remotely + "moved in " + referenceText; //$NON-NLS-1$
break;
default:
throw new IllegalStateException("Unsupported " + DifferenceKind.class.getSimpleName() //$NON-NLS-1$
+ " value: " + refChange.getKind()); //$NON-NLS-1$
}
return ret;
}
}