| /******************************************************************************* |
| * Copyright (c) 2013, 2015 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.emf.compare.diagram.internal.factories.extensions; |
| |
| import static com.google.common.base.Predicates.and; |
| import static com.google.common.base.Predicates.instanceOf; |
| import static org.eclipse.emf.compare.utils.EMFComparePredicates.fromSide; |
| import static org.eclipse.emf.compare.utils.EMFComparePredicates.ofKind; |
| |
| import com.google.common.base.Predicate; |
| import com.google.common.collect.Collections2; |
| |
| import java.util.Collection; |
| import java.util.LinkedHashSet; |
| import java.util.Set; |
| |
| import org.eclipse.emf.compare.Comparison; |
| import org.eclipse.emf.compare.Diff; |
| import org.eclipse.emf.compare.DifferenceKind; |
| import org.eclipse.emf.compare.ReferenceChange; |
| import org.eclipse.emf.compare.diagram.internal.extensions.DiagramDiff; |
| import org.eclipse.emf.compare.diagram.internal.extensions.ExtensionsFactory; |
| import org.eclipse.emf.compare.diagram.internal.extensions.NodeChange; |
| import org.eclipse.emf.compare.diagram.internal.factories.AbstractDiagramChangeFactory; |
| import org.eclipse.emf.compare.utils.EMFComparePredicates; |
| import org.eclipse.emf.compare.utils.ReferenceUtil; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.gmf.runtime.notation.Node; |
| import org.eclipse.gmf.runtime.notation.NotationPackage; |
| import org.eclipse.gmf.runtime.notation.View; |
| |
| /** |
| * Factory of node changes. |
| * |
| * @author <a href="mailto:cedric.notot@obeo.fr">Cedric Notot</a> |
| */ |
| public class NodeChangeFactory extends AbstractDiagramChangeFactory { |
| |
| /** |
| * Constructor. |
| */ |
| public NodeChangeFactory() { |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.compare.internal.postprocessor.factories.AbstractChangeFactory#getExtensionKind() |
| */ |
| @Override |
| public Class<? extends Diff> getExtensionKind() { |
| return NodeChange.class; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.compare.internal.postprocessor.factories.AbstractChangeFactory#createExtension() |
| */ |
| @Override |
| public DiagramDiff createExtension() { |
| return ExtensionsFactory.eINSTANCE.createNodeChange(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.compare.internal.postprocessor.factories.AbstractChangeFactory#setRefiningChanges(org.eclipse.emf.compare.diagram.internal.extensions.DiagramDiff, |
| * org.eclipse.emf.compare.DifferenceKind, org.eclipse.emf.compare.Diff) |
| */ |
| @Override |
| public void setRefiningChanges(Diff extension, DifferenceKind extensionKind, Diff refiningDiff) { |
| if (refiningDiff.getSource() == extension.getSource()) { |
| // Macroscopic change on a node is refined by the unit main change and unit children related |
| // changes. |
| extension.getRefinedBy().add(refiningDiff); |
| extension.getRefinedBy().addAll(Collections2.filter(getAllContainedDifferences(refiningDiff), |
| EMFComparePredicates.fromSide(extension.getSource()))); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.compare.internal.postprocessor.factories.AbstractChangeFactory#fillRequiredDifferences(org.eclipse.emf.compare.Comparison, |
| * org.eclipse.emf.compare.Diff) |
| */ |
| @Override |
| public void fillRequiredDifferences(Comparison comparison, Diff extension) { |
| super.fillRequiredDifferences(comparison, extension); |
| fillRequiredDifferencesForMove(comparison, extension); |
| } |
| |
| /** |
| * MOVE case: The MOVE of a Node requires the MOVE of the semantic object. |
| * |
| * @see NodeChangeFactory#fillRequiredDifferences(Comparison, Diff). |
| * @param comparison |
| * the comparison. |
| * @param extension |
| * the node change. |
| */ |
| private void fillRequiredDifferencesForMove(Comparison comparison, Diff extension) { |
| Set<Diff> requiredExtensions = new LinkedHashSet<Diff>(); |
| Set<Diff> requiringExtensions = new LinkedHashSet<Diff>(); |
| final Predicate<Diff> moveReference = and(instanceOf(ReferenceChange.class), |
| ofKind(DifferenceKind.MOVE), fromSide(extension.getSource())); |
| Collection<Diff> refiningMoves = Collections2.filter(extension.getRefinedBy(), moveReference); |
| for (Diff diff : refiningMoves) { |
| EObject target = ((ReferenceChange)diff).getValue(); |
| if (target instanceof View) { |
| EObject semanticTarget = ((View)target).getElement(); |
| Collection<Diff> requiredDiffs = Collections2 |
| .filter(comparison.getDifferences(semanticTarget), moveReference); |
| requiredExtensions.addAll(requiredDiffs); |
| // The graphical object and the semantic one are linked, they change their container both |
| // (difference case of ADD/DELETE) |
| requiringExtensions.addAll(requiredDiffs); |
| } |
| } |
| extension.getRequires().addAll(requiredExtensions); |
| extension.getRequiredBy().addAll(requiringExtensions); |
| } |
| |
| /** |
| * Predicate to check that the given difference is the main unit difference for this macroscopic add or |
| * delete of node. |
| * |
| * @return The predicate. |
| */ |
| public static Predicate<Diff> isMainDiffForAddOrDeleteNode() { |
| return new Predicate<Diff>() { |
| public boolean apply(Diff difference) { |
| return difference instanceof ReferenceChange |
| && (isRelatedToAnAddNode((ReferenceChange)difference) |
| || isRelatedToADeleteNode((ReferenceChange)difference)); |
| } |
| }; |
| } |
| |
| /** |
| * Predicate to check that the given difference is the main unit difference for this macroscopic move of |
| * node. |
| * |
| * @return The predicate. |
| */ |
| public static Predicate<Diff> isMainDiffForMoveNode() { |
| return new Predicate<Diff>() { |
| public boolean apply(Diff difference) { |
| return difference instanceof ReferenceChange |
| && isRelatedToAMoveNode((ReferenceChange)difference); |
| } |
| }; |
| } |
| |
| /** |
| * Get all the changes for the object containing them, from one of them: the given one. |
| * |
| * @param input |
| * one of the changes to get. |
| * @return The list of the related changes. |
| */ |
| protected Collection<Diff> getAllDifferencesForChange(Diff input) { |
| return input.getMatch().getDifferences(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.compare.internal.postprocessor.factories.AbstractChangeFactory#isRelatedToAnExtensionAdd(org.eclipse.emf.compare.ReferenceChange) |
| */ |
| @Override |
| protected boolean isRelatedToAnExtensionAdd(ReferenceChange input) { |
| return isExclusive() && isRelatedToAnAddNode(input); |
| } |
| |
| /** |
| * It checks that the given reference change concerns the add of a node. |
| * |
| * @param input |
| * The reference change. |
| * @return True if it concerns the add of a node, False otherwise. |
| */ |
| protected static boolean isRelatedToAnAddNode(ReferenceChange input) { |
| return isContainmentOnSemanticNode(input) && input.getKind() == DifferenceKind.ADD; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.compare.internal.postprocessor.factories.AbstractChangeFactory#isRelatedToAnExtensionDelete(org.eclipse.emf.compare.ReferenceChange) |
| */ |
| @Override |
| protected boolean isRelatedToAnExtensionDelete(ReferenceChange input) { |
| return isExclusive() && isRelatedToADeleteNode(input); |
| } |
| |
| /** |
| * It checks that the given reference change concerns the delete of a node. |
| * |
| * @param input |
| * The reference change. |
| * @return True if it concerns the delete of a node, False otherwise. |
| */ |
| protected static boolean isRelatedToADeleteNode(ReferenceChange input) { |
| return isContainmentOnSemanticNode(input) && input.getKind() == DifferenceKind.DELETE; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.compare.internal.postprocessor.factories.AbstractChangeFactory#isRelatedToAnExtensionMove(org.eclipse.emf.compare.ReferenceChange) |
| */ |
| @Override |
| protected boolean isRelatedToAnExtensionMove(ReferenceChange input) { |
| return isExclusive() && isRelatedToAMoveNode(input); |
| } |
| |
| /** |
| * It checks that the given reference change concerns the move of a node. |
| * |
| * @param input |
| * The reference change. |
| * @return True if it concerns the move of a node, False otherwise. |
| */ |
| protected static boolean isRelatedToAMoveNode(ReferenceChange input) { |
| return isContainmentOnSemanticNode(input) && input.getKind() == DifferenceKind.MOVE; |
| } |
| |
| /** |
| * It checks that the predicate applies on only this factory and not on potential children factories. |
| * |
| * @return true if the predicate applies only on this factory. |
| */ |
| protected boolean isExclusive() { |
| return getExtensionKind() == NodeChange.class; |
| } |
| |
| /** |
| * It checks that the given difference is on a containment link to a Node attached to a semantic object. |
| * |
| * @param input |
| * The difference. |
| * @return True if the difference matches with the predicate. |
| */ |
| private static boolean isContainmentOnSemanticNode(ReferenceChange input) { |
| return input.getReference().isContainment() && input.getValue() instanceof Node |
| && ReferenceUtil.safeEGet(input.getValue(), NotationPackage.Literals.VIEW__ELEMENT) != null; |
| } |
| |
| /** |
| * It returns the predicate to check that the given difference is an instance of this |
| * {@link #getExtensionKind()} and of the specified <code>diffKind</code>. |
| * |
| * @param diffKind |
| * The difference kind. |
| * @return The predicate. |
| */ |
| public Predicate<? super Diff> isExtensionKind(DifferenceKind diffKind) { |
| return and(instanceOf(getExtensionKind()), ofKind(diffKind)); |
| } |
| |
| } |