diff options
2 files changed, 180 insertions, 38 deletions
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/OpaqueElementBodyChangeMergeTest.java b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/OpaqueElementBodyChangeMergeTest.java index 78c576dc1..5ba901019 100644 --- a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/OpaqueElementBodyChangeMergeTest.java +++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/OpaqueElementBodyChangeMergeTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014 EclipseSource Muenchen GmbH and others. + * Copyright (c) 2014, 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 @@ -185,6 +185,36 @@ public class OpaqueElementBodyChangeMergeTest extends AbstractUMLTest { } @Test + public void testA1UseCase_ApplyLeftRevertRightChangeThreeWay() throws IOException { + Resource origin = input.getA1Origin(); + Resource left = input.getA1Left(); + Resource right = input.getA1Right(); + + OpaqueAction leftAction = (OpaqueAction)left.getEObject(OPAQUE_ACTION1_ID); + String leftBody = leftAction.getBodies().get(0); + + Comparison comparison = compare(left, right, origin); + applyLeftOpaqueElementBodyChangesToRight(comparison); + revertRightOpaqueElementBodyChanges(comparison); + assertOneBodyWithContents(right, leftBody); + } + + @Test + public void testA1UseCase_ApplyRightRevertLeftChangeThreeWay() throws IOException { + Resource origin = input.getA1Origin(); + Resource left = input.getA1Left(); + Resource right = input.getA1Right(); + + OpaqueAction rightAction = (OpaqueAction)right.getEObject(OPAQUE_ACTION1_ID); + String rightBody = rightAction.getBodies().get(0); + + Comparison comparison = compare(left, right, origin); + applyRightOpaqueElementBodyChangesToLeft(comparison); + revertLeftOpaqueElementBodyChanges(comparison); + assertOneBodyWithContents(left, rightBody); + } + + @Test public void testA2UseCase() throws IOException { Resource origin = input.getA2Origin(); Resource left = input.getA2Left(); diff --git a/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/merge/OpaqueElementBodyChangeMerger.java b/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/merge/OpaqueElementBodyChangeMerger.java index b8ddc79af..3d9defefd 100644 --- a/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/merge/OpaqueElementBodyChangeMerger.java +++ b/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/merge/OpaqueElementBodyChangeMerger.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014 EclipseSource Muenchen GmbH and others. + * Copyright (c) 2014, 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 @@ -238,39 +238,74 @@ public class OpaqueElementBodyChangeMerger extends AttributeChangeMerger { * The direction of merging. */ private void changeElement(OpaqueElementBodyChange bodyChange, boolean rightToLeft) { - final Match match = bodyChange.getMatch(); - final Comparison comparison = match.getComparison(); - final String language = bodyChange.getLanguage(); + final EObject targetContainer = getTargetContainer(bodyChange.getMatch(), rightToLeft); + final String targetValue = getTargetBodyValue(bodyChange, rightToLeft); - final EObject leftContainer = match.getLeft(); - final EObject rightContainer = match.getRight(); + setBody(targetContainer, targetValue, bodyChange.getLanguage()); + + // we merge the body change as a whole, so set all refining to merged too + setRefiningDiffsMerged(bodyChange); + } - final String leftBody = UMLCompareUtil.getOpaqueElementBody(leftContainer, language); - final String rightBody = UMLCompareUtil.getOpaqueElementBody(rightContainer, language); + /** + * Sets {@code newBody} as the contents of the body for the given {@code language} in the given + * {@code container}. + * + * @param container + * The {@link EObject} to set the body. + * @param newBody + * The content of the body to set. + * @param language + * The language at which the body shall be set. + */ + private void setBody(EObject container, String newBody, String language) { + final List<String> languages = UMLCompareUtil.getOpaqueElementLanguages(container); + final List<String> bodies = UMLCompareUtil.getOpaqueElementBodies(container); + final int index = languages.indexOf(language); + bodies.set(index, newBody); + } + /** + * Returns the target value, that is, the value to be set when merging the given {@code bodyChange} in the + * direction indicated by {@code rightToLeft}. + * + * @param bodyChange + * The bodyChange we are currently merging. + * @param rightToLeft + * Direction of the merge. + * @return The target value to be set when merging. + */ + private String getTargetBodyValue(OpaqueElementBodyChange bodyChange, boolean rightToLeft) { final String newBody; - if (comparison.isThreeWay()) { - final EObject originContainer = match.getOrigin(); - final String originBody = UMLCompareUtil.getOpaqueElementBody(originContainer, language); - if (isAcceptingChange(bodyChange, rightToLeft)) { - newBody = performThreeWayTextMerge(leftBody, rightBody, originBody); - } else { - newBody = originBody; - } + if (bodyChange.getMatch().getComparison().isThreeWay()) { + newBody = performThreeWayTextMerge(bodyChange, rightToLeft); } else if (rightToLeft) { - newBody = rightBody; + newBody = getRightBodyValue(bodyChange); } else { - newBody = leftBody; + newBody = getLeftBodyValue(bodyChange); } + return newBody; + } - if (rightToLeft) { - setBody(leftContainer, newBody, language); + /** + * Performs a three-way text merge for the given {@code bodyChange} and returns the merged text. + * <p> + * Depending on whether the given {@code bodyChange} is an accept or reject in the context of the merge + * direction indicated by {@code rightToLeft}, this method will perform different strategies of merging. + * </p> + * + * @param bodyChange + * The bodyChange for which a three-way text diff is to be performed. + * @param rightToLeft + * The direction of applying the {@code diff}. + * @return The merged text. + */ + private String performThreeWayTextMerge(OpaqueElementBodyChange bodyChange, boolean rightToLeft) { + if (isAcceptingChange(bodyChange, rightToLeft)) { + return performAcceptingThreeWayTextMerge(bodyChange); } else { - setBody(rightContainer, newBody, language); + return performRejectingThreeWayTextMerge(bodyChange); } - - // we merged the body change as a whole, so set all refining to merged too - setRefiningDiffsMerged(bodyChange); } /** @@ -289,21 +324,98 @@ public class OpaqueElementBodyChangeMerger extends AttributeChangeMerger { } /** - * Sets {@code newBody} as the contents of the body for the given {@code language} in the given - * {@code container}. + * Performs a three-way text merge accepting the given {@code bodyChange} and returns the merged text. * - * @param container - * The {@link EObject} to set the body. - * @param newBody - * The content of the body to set. - * @param language - * The language at which the body shall be set. + * @param bodyChange + * The bodyChange for which a three-way text diff is to be performed. + * @return The merged text. */ - private void setBody(EObject container, String newBody, String language) { - final List<String> languages = UMLCompareUtil.getOpaqueElementLanguages(container); - final List<String> bodies = UMLCompareUtil.getOpaqueElementBodies(container); - final int index = languages.indexOf(language); - bodies.set(index, newBody); + private String performAcceptingThreeWayTextMerge(OpaqueElementBodyChange bodyChange) { + final String leftBodyValue = getLeftBodyValue(bodyChange); + final String rightBodyValue = getRightBodyValue(bodyChange); + final String originBodyValue = getOriginBodyValue(bodyChange); + return performThreeWayTextMerge(leftBodyValue, rightBodyValue, originBodyValue); + } + + /** + * Performs a three-way text merge rejecting the given {@code bodyChange} and returns the merged text. + * <p> + * The implementation of rejecting a body value change is based on a three-way diff corresponding to + * {@link AttributeChangeMerger#performRejectingThreeWayTextMerge(AttributeChange, boolean)}. + * </p> + * + * @param bodyChange + * The bodyChange for which a three-way text diff is to be performed. + * @param rightToLeft + * The direction of applying the {@code bodyChange}. + * @return The merged text. + */ + private String performRejectingThreeWayTextMerge(OpaqueElementBodyChange bodyChange) { + final String originBodyValue = getOriginBodyValue(bodyChange); + final AttributeChange bodyValueAddition = getBodyValueAddition(bodyChange).get(); + final String changedValueFromDiff = (String)bodyValueAddition.getValue(); + + final String changedValueFromModel; + if (DifferenceSource.LEFT.equals(bodyValueAddition.getSource())) { + changedValueFromModel = getLeftBodyValue(bodyChange); + } else { + changedValueFromModel = getRightBodyValue(bodyChange); + } + + return performThreeWayTextMerge(changedValueFromModel, originBodyValue, changedValueFromDiff); + } + + /** + * Returns the attribute change that adds a body value from the refining differences of the given + * {@code bodyChange}. + * + * @param bodyChange + * The body change to get the body value addition from. + * @return The attribute change adding a body value. + */ + private Optional<AttributeChange> getBodyValueAddition(OpaqueElementBodyChange bodyChange) { + for (Diff diff : bodyChange.getRefinedBy()) { + if (isChangeOfOpaqueElementBodyAttribute(diff) && DifferenceKind.ADD.equals(diff.getKind())) { + return Optional.of((AttributeChange)diff); + } + } + return Optional.absent(); + } + + /** + * Returns the body value of the left-hand side that is affected by the given {@code bodyChange}. + * + * @param bodyChange + * The body change to get the left-hand side body value for. + * @return The left-hand side body value. + */ + private String getLeftBodyValue(OpaqueElementBodyChange bodyChange) { + final EObject leftContainer = bodyChange.getMatch().getLeft(); + return UMLCompareUtil.getOpaqueElementBody(leftContainer, bodyChange.getLanguage()); + } + + /** + * Returns the body value of the right-hand side that is affected by the given {@code bodyChange}. + * + * @param bodyChange + * The body change to get the right-hand side body value for. + * @return The right-hand side body value. + */ + private String getRightBodyValue(OpaqueElementBodyChange bodyChange) { + final EObject rightContainer = bodyChange.getMatch().getRight(); + return UMLCompareUtil.getOpaqueElementBody(rightContainer, bodyChange.getLanguage()); + } + + /** + * Returns the body value of the origin that is affected by the given {@code bodyChange}. + * + * @param bodyChange + * The body change to get the origin body value for. + * @return The origin body value. + */ + private String getOriginBodyValue(OpaqueElementBodyChange bodyChange) { + final EObject originContainer = bodyChange.getMatch().getOrigin(); + return UMLCompareUtil.getOpaqueElementBody(originContainer, bodyChange.getLanguage()); } /** |