blob: 7b843b5a4863a478ab2cf6b68e2d92644722829a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015 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 java.util.List;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.compare.Diff;
import org.eclipse.emf.compare.internal.utils.ComparisonUtil;
import org.eclipse.emf.compare.rcp.ui.internal.contentmergeviewer.IModelUpdateStrategy;
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.uml2.internal.postprocessor.util.UMLCompareUtil;
import org.eclipse.emf.compare.utils.IEqualityHelper;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.edit.command.ChangeCommand;
import org.eclipse.uml2.uml.UMLPackage;
/**
* The model update strategy for {@link OpaqueElementBodyChange opaque element body changes}.
* <p>
* As this update strategy is intended to be used only by the EMFCompareTextMergeViewer (or subclasses) for
* changes of body values, this update strategy copes only with actual changes of body values where the
* EMFCompareTextMergeViewer is used (i.e., for changes, deletions, and additions; not for moves). In case of
* additions or deletions, only the side, in which the body is still present, is editable. The other side, on
* which the body is not present anymore or not yet, is not editable.
* </p>
*
* @author Philip Langer <planger@eclipsesource.com>
*/
public class OpaqueElementBodyChangeUpdateStrategy implements IModelUpdateStrategy {
/** The datatype of the body EAttribute of OpaqueAction (expression and behavior have the same). */
private static final EDataType BODY_ATTRIBUTE_TYPE = UMLPackage.eINSTANCE.getOpaqueAction_Body()
.getEAttributeType();
/**
* {@inheritDoc}
*
* @see IModelUpdateStrategy#canUpdate(Diff, MergeViewerSide)
*/
public boolean canUpdate(Diff diff, MergeViewerSide side) {
if (diff instanceof OpaqueElementBodyChange) {
final EObject targetObject = MergeViewerUtil.getEObject(diff.getMatch(), side);
final List<String> languages = UMLCompareUtil.getOpaqueElementLanguages(targetObject);
final List<String> bodies = UMLCompareUtil.getOpaqueElementBodies(targetObject);
final OpaqueElementBodyChange bodyChange = (OpaqueElementBodyChange)diff;
return languages.contains(bodyChange.getLanguage())
&& languages.indexOf(bodyChange.getLanguage()) < bodies.size();
}
return false;
}
/**
* Returns the body value from the underlying model.
*
* @param bodyChange
* The change indicating the language at which the body value shall be obtained.
* @param side
* The side from which to obtain the value.
* @return The body value; if the body value does not exist, this method returns an empty string.
*/
private String getOldBodyValue(OpaqueElementBodyChange bodyChange, MergeViewerSide side) {
final EObject targetObject = MergeViewerUtil.getEObject(bodyChange.getMatch(), side);
final int index = getIndexOfLanguage(bodyChange.getLanguage(), targetObject);
final List<String> bodies = UMLCompareUtil.getOpaqueElementBodies(targetObject);
if (index >= 0 && index < bodies.size()) {
return bodies.get(index);
} else {
return ""; //$NON-NLS-1$
}
}
/**
* Returns the index of the given {@code language} of the given {@code object}.
*
* @param language
* The language to get the index of.
* @param object
* The object to get all language values from.
* @return The index of {@code language}; -1 if {@code language} does not exist.
*/
private int getIndexOfLanguage(String language, final EObject object) {
final List<String> languages = UMLCompareUtil.getOpaqueElementLanguages(object);
return languages.indexOf(language);
}
/**
* {@inheritDoc}
*
* @see IModelUpdateStrategy#getModelUpdateCommand(Diff, Object, MergeViewerSide)
*/
public Command getModelUpdateCommand(final Diff diff, final Object newValue, final MergeViewerSide side) {
final EObject targetObject = MergeViewerUtil.getEObject(diff.getMatch(), side);
return new ChangeCommand(targetObject) {
@Override
public boolean canExecute() {
return canUpdate(diff, side) && needsUpdate(diff, newValue, side) && super.canExecute();
}
@Override
protected void doExecute() {
final List<String> bodies = UMLCompareUtil.getOpaqueElementBodies(targetObject);
final OpaqueElementBodyChange bodyChange = (OpaqueElementBodyChange)diff;
final int index = getIndexOfLanguage(bodyChange.getLanguage(), targetObject);
final String newStringValue = EcoreUtil.convertToString(BODY_ATTRIBUTE_TYPE, newValue);
bodies.set(index, newStringValue);
}
};
}
/**
* Specifies whether the value in the model needs to be updated with the given {@code newValue} on the
* given {@code side}.
*
* @param diff
* The diff acting as context of the potential model update.
* @param newValue
* The potentially changed new value to be checked against.
* @param side
* The side to check.
* @return <code>true</code> if an update is necessary, <code>false</code> otherwise.
*/
private boolean needsUpdate(Diff diff, Object newValue, MergeViewerSide side) {
final OpaqueElementBodyChange bodyChange = (OpaqueElementBodyChange)diff;
final String oldValue = getOldBodyValue(bodyChange, side);
final IEqualityHelper equalityHelper = ComparisonUtil.getComparison(diff).getEqualityHelper();
return !equalityHelper.matchingAttributeValues(newValue, oldValue);
}
}