blob: 6f16bbf42282eee6710c5095dcf49b37141aa14a [file] [log] [blame]
/*******************************************************************************
* 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));
}
}