/******************************************************************************* * Copyright (c) 2014 EclipseSource Muenchen GmbH 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: * Philip Langer - initial API and implementation *******************************************************************************/ package org.eclipse.emf.compare.uml2.rcp.ui.internal.accessor; import com.google.common.base.Optional; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.util.Collections; import java.util.List; import org.eclipse.core.runtime.CoreException; import org.eclipse.emf.common.notify.AdapterFactory; import org.eclipse.emf.compare.DifferenceKind; import org.eclipse.emf.compare.rcp.ui.contentmergeviewer.accessor.legacy.IStreamContentAccessor; import org.eclipse.emf.compare.rcp.ui.contentmergeviewer.accessor.legacy.impl.AbstractTypedElementAdapter; import org.eclipse.emf.compare.rcp.ui.internal.contentmergeviewer.TypeConstants; import org.eclipse.emf.compare.rcp.ui.internal.util.MergeViewerUtil; import org.eclipse.emf.compare.rcp.ui.mergeviewer.IMergeViewer.MergeViewerSide; import org.eclipse.emf.compare.uml2.internal.OpaqueElementBodyChange; import org.eclipse.emf.compare.utils.ReferenceUtil; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.edit.ui.provider.ExtendedImageRegistry; import org.eclipse.swt.graphics.Image; import org.eclipse.uml2.uml.OpaqueAction; import org.eclipse.uml2.uml.OpaqueBehavior; import org.eclipse.uml2.uml.OpaqueExpression; import org.eclipse.uml2.uml.UMLPackage; /** * An accessor for {@link OpaqueElementBodyChange opaque element body changes} that represent <i>additions</i> * , <i>deletions</i>, and <i>changes</i> (that is, everything except for moves) of body values of * {@link OpaqueAction}, {@link OpaqueBehavior}, and {@link OpaqueExpression}. For such changes of body * values, we show the added/deleted/changed body value of the left-hand side and the right-hand side in a * textual diff viewer. * * @author Philip Langer <planger@eclipsesource.com> */ public class OpaqueElementBodyChangeAccessor extends AbstractTypedElementAdapter implements IStreamContentAccessor { /** The change to be accessed by this accessor. */ private OpaqueElementBodyChange bodyChange; /** The current side's object affected by {@link #bodyChange}. */ private final EObject eObject; /** * Creates a new accessor for {@link OpaqueElementBodyChange opaque element body changes} that represent * additions, deletions, and changes of body values. * * @param adapterFactory * the adapater factory used to create the accessor. * @param bodyChange * The change to be accessed by this accessor. * @param side * The side of this accessor. */ public OpaqueElementBodyChangeAccessor(AdapterFactory adapterFactory, OpaqueElementBodyChange bodyChange, MergeViewerSide side) { super(adapterFactory); this.bodyChange = bodyChange; this.eObject = MergeViewerUtil.getEObject(bodyChange.getMatch(), side); if (DifferenceKind.MOVE.equals(bodyChange.getKind())) { throw new IllegalArgumentException( "This accessor handles only additions, deletions, and changes of body values."); //$NON-NLS-1$ } } /** * {@inheritDoc} * * @see org.eclipse.emf.compare.rcp.ui.contentmergeviewer.accessor.legacy.IStreamContentAccessor#getContents() */ public InputStream getContents() throws CoreException { final String language = bodyChange.getLanguage(); final byte[] contents = getBodyAsByte(language).or(new byte[0]); return new ByteArrayInputStream(contents); } /** * Returns the optional body value of {@link #eObject} for the given {@code language} as a byte array. * * @param language * The language to get the body value for. * @return The optional body value of {@link #eObject} for {@code language}. */ private Optional<byte[]> getBodyAsByte(String language) { final Optional<byte[]> body; final List<String> languages = getLanguageValues(); final List<String> bodies = getBodyValues(); if (languages.contains(language) && bodies.size() > languages.indexOf(language)) { body = Optional.of(bodies.get(languages.indexOf(language)).getBytes()); } else { body = Optional.absent(); } return body; } /** * Returns the values of the {@link #getLanguageFeature() language feature} of {@link #eObject}. * * @return The values of the language feature of {@link #eObject}. */ @SuppressWarnings("unchecked") private List<String> getLanguageValues() { if (eObject == null) { return Collections.emptyList(); } return (List<String>)ReferenceUtil.safeEGet(eObject, getLanguageFeature()); } /** * Returns the values of the {@link #getBodyFeature() body feature} of {@link #eObject}. * * @return The values of the body feature of {@link #eObject}. */ @SuppressWarnings("unchecked") private List<String> getBodyValues() { if (eObject == null) { return Collections.emptyList(); } return (List<String>)ReferenceUtil.safeEGet(eObject, getBodyFeature()); } /** * {@inheritDoc} * * @see org.eclipse.emf.compare.rcp.ui.contentmergeviewer.accessor.legacy.ITypedElement#getName() */ public String getName() { return this.getClass().getName(); } /** * {@inheritDoc} * * @see org.eclipse.emf.compare.rcp.ui.contentmergeviewer.accessor.legacy.ITypedElement#getImage() */ public Image getImage() { return ExtendedImageRegistry.INSTANCE.getImage(getItemDelegator().getImage(getBodyFeature())); } /** * Returns the body feature of {@link #eObject} depending on whether it is an {@link OpaqueAction}, * {@link OpaqueBehavior}, or {@link OpaqueExpression}. * <p> * If {@link #eObject} is not any of those types, an {@link IllegalArgumentException} is thrown, since * this must never happen and something beforehand went horribly wrong. * </p> * * @return The body feature of {@link #eObject}. */ private EStructuralFeature getBodyFeature() { final EStructuralFeature bodyFeature; if (eObject instanceof OpaqueAction) { bodyFeature = UMLPackage.eINSTANCE.getOpaqueAction_Body(); } else if (eObject instanceof OpaqueBehavior) { bodyFeature = UMLPackage.eINSTANCE.getOpaqueBehavior_Body(); } else if (eObject instanceof OpaqueExpression) { bodyFeature = UMLPackage.eINSTANCE.getOpaqueExpression_Body(); } else { throw new IllegalArgumentException("Cannot get body feature of the class " //$NON-NLS-1$ + eObject.eClass().getName()); } return bodyFeature; } /** * Returns the language feature of {@link #eObject} depending on whether it is an {@link OpaqueAction}, * {@link OpaqueBehavior}, or {@link OpaqueExpression}. * <p> * If {@link #eObject} is not any of those types, an {@link IllegalArgumentException} is thrown, since * this must never happen and something beforehand went horribly wrong. * </p> * * @return The language feature of {@link #eObject}. */ private EStructuralFeature getLanguageFeature() { return getLanguageFeature(eObject); } /** * Returns the language feature of the given {@code object} depending on whether it is an * {@link OpaqueAction}, {@link OpaqueBehavior}, or {@link OpaqueExpression}. * <p> * If {@code object} is not any of those types, an {@link IllegalArgumentException} is thrown, since this * must never happen and something beforehand went horribly wrong. * </p> * * @param object * The instance of {@link OpaqueAction}, {@link OpaqueBehavior}, or {@link OpaqueExpression} to * get the language feature for. * @return The language feature of {@link #eObject}. */ private EStructuralFeature getLanguageFeature(final EObject object) { final EStructuralFeature languageFeature; if (object instanceof OpaqueAction) { languageFeature = UMLPackage.eINSTANCE.getOpaqueAction_Language(); } else if (object instanceof OpaqueBehavior) { languageFeature = UMLPackage.eINSTANCE.getOpaqueBehavior_Language(); } else if (object instanceof OpaqueExpression) { languageFeature = UMLPackage.eINSTANCE.getOpaqueExpression_Language(); } else { throw new IllegalArgumentException("Cannot get language feature of the class " //$NON-NLS-1$ + object.eClass().getName()); } return languageFeature; } /** * {@inheritDoc} * * @see org.eclipse.emf.compare.rcp.ui.contentmergeviewer.accessor.legacy.ITypedElement#getType() */ public String getType() { return TypeConstants.TYPE_ETEXT_DIFF; } }