Skip to main content
aboutsummaryrefslogblamecommitdiffstats
blob: 6117d20fda74e1a8d033e804b8112a13dc73023c (plain) (tree)


































































































































































































































                                                                                                                      
/*******************************************************************************
 * Copyright (c) 2009, 2011 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
 *******************************************************************************/
package org.eclipse.papyrus.infra.emf.compare.merger;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.emf.compare.diff.merge.DefaultMerger;
import org.eclipse.emf.compare.diff.metamodel.AttributeOrderChange;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EEnumLiteral;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.FeatureMap;

/**
 * Merger for an {@link AttributeOrderChange} operation.
 * 
 * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
 */
@SuppressWarnings("unchecked")
public class AttributeOrderChangeMerger extends DefaultMerger {
	/**
	 * {@inheritDoc}
	 * 
	 * @see org.eclipse.emf.compare.diff.merge.DefaultMerger#doApplyInOrigin()
	 */
	@Override
	public void doApplyInOrigin() {
		final AttributeOrderChange theDiff = (AttributeOrderChange)this.diff;
		final EAttribute attribute = theDiff.getAttribute();
		final EObject leftElement = theDiff.getLeftElement();
		final EObject rightElement = theDiff.getRightElement();

		final List<Object> leftList = (List<Object>)leftElement.eGet(attribute);
		final List<Object> rightList = (List<Object>)rightElement.eGet(attribute);

		/*
		 * We need to transform the "left" list into the "right" list, modulo missing values. In practical
		 * terms, this means that we'll simply leave untouched any element that has no match in the "right"
		 * list (elements that were deleted) while reordering the others in the order they have in the "right"
		 * list.
		 */
		final List<Object> leftCopy = new ArrayList<Object>(leftList);
		final List<Object> result = new ArrayList<Object>(leftList.size());
		// Add all unmatched values in the result list
		for (int i = 0; i < leftList.size(); i++) {
			final Object left = leftList.get(i);

			boolean hasMatch = false;
			for (int j = 0; !hasMatch && j < rightList.size(); j++) {
				hasMatch = !areDistinctValues(left, rightList.get(j));
			}

			if (!hasMatch) {
				leftCopy.remove(left);
				result.add(left);
			}
		}
		// Then reorder according to the right list's order
		for (int i = 0; i < rightList.size(); i++) {
			final Object right = rightList.get(i);

			Object leftMatch = null;
			for (int j = 0; leftMatch == null && j < leftCopy.size(); j++) {
				if (!areDistinctValues(right, leftCopy.get(j))) {
					leftMatch = leftCopy.get(j);
				}
			}

			if (leftMatch != null) {
				leftCopy.remove(leftMatch);
				result.add(leftMatch);
			}
		}
		// Finally, set the value of our attribute to this new list
		leftElement.eSet(attribute, result);
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see org.eclipse.emf.compare.diff.merge.DefaultMerger#doUndoInTarget()
	 */
	@Override
	public void doUndoInTarget() {
		final AttributeOrderChange theDiff = (AttributeOrderChange)this.diff;
		final EAttribute attribute = theDiff.getAttribute();
		final EObject leftElement = theDiff.getLeftElement();
		final EObject rightElement = theDiff.getRightElement();

		final List<Object> leftList = (List<Object>)leftElement.eGet(attribute);
		final List<Object> rightList = (List<Object>)rightElement.eGet(attribute);

		/*
		 * We need to transform the "right" list into the "left" list, modulo missing values. In practical
		 * terms, this means that we'll simply leave untouched any element that has no match in the "left"
		 * list (elements that were added) while reordering the others in the order they have in the "left"
		 * list.
		 */
		final List<Object> rightCopy = new ArrayList<Object>(rightList);
		final List<Object> result = new ArrayList<Object>(rightList.size());
		// Add all unmatched values in the result list
		for (int i = 0; i < rightList.size(); i++) {
			final Object right = rightList.get(i);

			boolean hasMatch = false;
			for (int j = 0; !hasMatch && j < leftList.size(); j++) {
				hasMatch = !areDistinctValues(right, leftList.get(j));
			}

			if (!hasMatch) {
				rightCopy.remove(right);
				result.add(right);
			}
		}
		// Then reorder according to the left list's order
		for (int i = 0; i < leftList.size(); i++) {
			final Object left = leftList.get(i);

			Object rightMatch = null;
			for (int j = 0; rightMatch == null && j < rightCopy.size(); j++) {
				if (!areDistinctValues(left, rightCopy.get(j))) {
					rightMatch = rightCopy.get(j);
				}
			}

			if (rightMatch != null) {
				rightCopy.remove(rightMatch);
				result.add(rightMatch);
			}
		}
		// Finally, set the value of our attribute to this new list
		rightElement.eSet(attribute, result);
	}

	/**
	 * Compare values by equality handling specifics of EMF.
	 * 
	 * @param left
	 *            object 1.
	 * @param right
	 *            object 2
	 * @return true if both objects are not equals.
	 */
	private static boolean areDistinctValues(Object left, Object right) {
		final boolean distinct;
		if (left instanceof EEnumLiteral && right instanceof EEnumLiteral) {
			final StringBuilder value1 = new StringBuilder();
			value1.append(((EEnumLiteral)left).getLiteral()).append(((EEnumLiteral)left).getValue());
			final StringBuilder value2 = new StringBuilder();
			value2.append(((EEnumLiteral)right).getLiteral()).append(((EEnumLiteral)right).getValue());
			distinct = !value1.toString().equals(value2.toString());
		} else if (left != null && left.getClass().isArray()) {
			// [299641] compare arrays by their content instead of instance equality
			distinct = areDistinctArrays(left, right);
		} else if (left instanceof FeatureMap.Entry || right instanceof FeatureMap.Entry) {
			distinct = areDistinctEntries(left, right);
		} else {
			distinct = left != null && !left.equals(right) || left == null && left != right;
		}
		return distinct;
	}

	/**
	 * Compares the two given value while assuming one or both is a {@link FeatureMap.Entry}.
	 * 
	 * @param left
	 *            Left of the two values to compare.
	 * @param right
	 *            Right of the two values to compare.
	 * @return <code>true</code> if the two values are distinct, <code>false</code> otherwise.
	 */
	private static boolean areDistinctEntries(Object left, Object right) {
		final boolean distinct;
		if (left instanceof FeatureMap.Entry && right instanceof FeatureMap.Entry) {
			distinct = areDistinctValues(((FeatureMap.Entry)left).getValue(),
					((FeatureMap.Entry)right).getValue());
		} else if (left instanceof FeatureMap.Entry) {
			distinct = areDistinctValues(((FeatureMap.Entry)left).getValue(), right);
		} else {
			distinct = areDistinctValues(left, ((FeatureMap.Entry)right).getValue());
		}
		return distinct;
	}

	/**
	 * Compares two values as arrays, checking that the length and content of both matches each other.
	 * 
	 * @param left
	 *            The value of the attribute from the left compare resource.
	 * @param right
	 *            The value of the attribute from the right compare resource.
	 * @return <code>true</code> if the <code>left</code> value is distinct from the <code>right</code> value.
	 */
	private static boolean areDistinctArrays(Object left, Object right) {
		boolean distinct = false;
		// we know left is a non-null array.
		if (right == null || !right.getClass().isArray()) {
			distinct = true;
		} else {
			final int leftLength = Array.getLength(left);
			final int rightLength = Array.getLength(right);
			if (leftLength != rightLength) {
				distinct = true;
			} else {
				for (int i = 0; i < leftLength; i++) {
					final Object leftElement = Array.get(left, i);
					final Object rightElement = Array.get(right, i);
					if (areDistinctValues(leftElement, rightElement)) {
						distinct = true;
						break;
					}
				}
			}
		}
		return distinct;
	}
}

Back to the top