| /******************************************************************************* |
| * Copyright (c) 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.sirius.internal; |
| |
| import static com.google.common.collect.Collections2.filter; |
| import static org.eclipse.emf.compare.utils.EMFComparePredicates.CONTAINMENT_REFERENCE_CHANGE; |
| import static org.eclipse.emf.compare.utils.EMFComparePredicates.fromSide; |
| |
| import com.google.common.base.Function; |
| import com.google.common.base.Predicate; |
| import com.google.common.collect.Iterables; |
| import com.google.common.collect.Iterators; |
| import com.google.common.collect.Multimap; |
| import com.google.common.collect.Multimaps; |
| import com.google.common.collect.Sets; |
| |
| import java.util.Iterator; |
| import java.util.Set; |
| |
| import org.eclipse.emf.common.util.Monitor; |
| 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.postprocessor.IPostProcessor; |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.gmf.runtime.notation.NotationPackage; |
| import org.eclipse.gmf.runtime.notation.View; |
| import org.eclipse.sirius.diagram.DNode; |
| import org.eclipse.sirius.diagram.DiagramPackage; |
| import org.eclipse.sirius.diagram.description.NodeMapping; |
| import org.eclipse.sirius.viewpoint.DSemanticDecorator; |
| import org.eclipse.sirius.viewpoint.ViewpointPackage; |
| |
| /** |
| * A post processor to refine the differences found on a Sirius model. |
| * |
| * @author <a href="mailto:cedric.brun@obeo.fr">Cedric Brun</a> |
| */ |
| @SuppressWarnings("restriction") |
| public class SiriusDiffPostProcessor implements IPostProcessor { |
| /** |
| * Create a new predicate to check whether the value of a {@link ReferenceChange} is of a given type. |
| * |
| * @param clazz |
| * an EClass. |
| * @return true if the value of the {@link ReferenceChange} is of the given type. |
| */ |
| private static Predicate<ReferenceChange> valueIsKindOf(final EClass clazz) { |
| return new Predicate<ReferenceChange>() { |
| public boolean apply(ReferenceChange diff) { |
| return clazz.isSuperTypeOf(diff.getValue().eClass()); |
| } |
| }; |
| } |
| |
| private static Function<? super ReferenceChange, EObject> getReferenceChangeValue() { |
| return new Function<ReferenceChange, EObject>() { |
| public EObject apply(ReferenceChange diff) { |
| return diff.getValue(); |
| } |
| }; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void postMatch(Comparison comparison, Monitor monitor) { |
| |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void postDiff(Comparison comparison, Monitor monitor) { |
| |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void postRequirements(Comparison comparison, Monitor monitor) { |
| /* |
| * Any added/deleted DSemanticDecorator must require the corresponding getTarget() addition/removal |
| */ |
| Iterable<ReferenceChange> allContainmentRefChanges = Iterables.filter( |
| Iterables.filter(comparison.getDifferences(), ReferenceChange.class), |
| CONTAINMENT_REFERENCE_CHANGE); |
| |
| Iterable<ReferenceChange> addedOrRemovedSemanticDecorators = Iterables.filter( |
| allContainmentRefChanges, valueIsKindOf(ViewpointPackage.eINSTANCE.getDSemanticDecorator())); |
| |
| Multimap<EObject, ReferenceChange> diffsByValue = Multimaps.index(allContainmentRefChanges, |
| getReferenceChangeValue()); |
| |
| /* |
| * Any added or removed semantic decorator should have a dependency to the corresponding |
| * addition/removal of semantic element. |
| */ |
| for (ReferenceChange referenceChange : addedOrRemovedSemanticDecorators) { |
| DSemanticDecorator value = (DSemanticDecorator)referenceChange.getValue(); |
| if (value.getTarget() != null) { |
| EObject semanticTarget = value.getTarget(); |
| addRequiresToDecoratedElement(diffsByValue, referenceChange, semanticTarget); |
| } |
| /* |
| * A DNode should always have its actualMapping reference set. |
| */ |
| if (value instanceof DNode) { |
| NodeMapping map = ((DNode)value).getActualMapping(); |
| if (map != null) { |
| for (ReferenceChange actualMappingChange : Iterables |
| .filter(comparison.getDifferences(map), ReferenceChange.class)) { |
| if (actualMappingChange.getReference() == DiagramPackage.eINSTANCE |
| .getDNode_ActualMapping() |
| && fromSide(referenceChange.getSource()).apply(actualMappingChange)) { |
| referenceChange.getImplies().add(actualMappingChange); |
| } |
| } |
| } |
| } |
| } |
| /* |
| * Any added or removed gmf Node should have a dependency to the corresponding addition/removal of a |
| * DSemantic decorator. |
| */ |
| |
| Iterable<ReferenceChange> addedOrRemovedGmfView = Iterables.filter(allContainmentRefChanges, |
| valueIsKindOf(NotationPackage.eINSTANCE.getView())); |
| |
| for (ReferenceChange referenceChange : addedOrRemovedGmfView) { |
| View value = (View)referenceChange.getValue(); |
| |
| /* |
| * beware here, GMF do som trick in getElement() and will return it's container element if the |
| * element is null.. |
| */ |
| if (value.getElement() != null) { |
| EObject semanticTarget = value.getElement(); |
| addRequiresToDecoratedElement(diffsByValue, referenceChange, semanticTarget); |
| } |
| } |
| } |
| |
| /** |
| * Add diff requires for every change related to the semantic target. |
| * |
| * @param diffsByValue |
| * {@link ReferenceChange} differences indexed by value. |
| * @param referenceChange |
| * a given {@link ReferenceChange}. |
| * @param semanticTarget |
| * the semantic target. |
| */ |
| private void addRequiresToDecoratedElement(Multimap<EObject, ReferenceChange> diffsByValue, |
| ReferenceChange referenceChange, EObject semanticTarget) { |
| for (Diff valueDiff : diffsByValue.get(semanticTarget)) { |
| if (referenceChange.getKind() == DifferenceKind.ADD) { |
| if (valueDiff.getKind() == DifferenceKind.ADD |
| && fromSide(referenceChange.getSource()).apply(valueDiff)) { |
| referenceChange.getRequires().add(valueDiff); |
| } |
| |
| } else if (referenceChange.getKind() == DifferenceKind.DELETE) { |
| if (valueDiff.getKind() == DifferenceKind.DELETE |
| && fromSide(referenceChange.getSource()).apply(valueDiff)) { |
| referenceChange.getRequires().add(valueDiff); |
| } |
| } |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void postEquivalences(Comparison comparison, Monitor monitor) { |
| |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void postConflicts(Comparison comparison, Monitor monitor) { |
| |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void postComparison(Comparison comparison, Monitor monitor) { |
| /* |
| * We re-refine the refinements already setup by |
| * org.eclipse.emf.compare.diagram.internal.CompareDiagramPostProcessor |
| */ |
| Iterator<DiagramDiff> it = Iterators.filter(comparison.eAllContents(), DiagramDiff.class); |
| while (it.hasNext()) { |
| DiagramDiff next = it.next(); |
| Set<Diff> refinesToAdd = Sets.newLinkedHashSet(); |
| for (Diff refined : next.getRefinedBy()) { |
| collectDifferenceRefines(comparison, refinesToAdd, refined.getMatch().getLeft()); |
| collectDifferenceRefines(comparison, refinesToAdd, refined.getMatch().getRight()); |
| } |
| next.getRefinedBy().addAll(filter(refinesToAdd, fromSide(next.getSource()))); |
| } |
| } |
| |
| /** |
| * Collect the differences which have to be added as a refinment of the current DiagramDiff. |
| * |
| * @param comparison |
| * the current comparison. |
| * @param refinesToAdd |
| * the set of differences to add as refinement. |
| * @param changedEObject |
| * any changed EObject. |
| */ |
| private void collectDifferenceRefines(Comparison comparison, Set<Diff> refinesToAdd, |
| EObject changedEObject) { |
| if (changedEObject instanceof View) { |
| View gmfView = (View)changedEObject; |
| if (gmfView.getElement() instanceof DSemanticDecorator) { |
| for (Diff diffOnSemanticDecorator : comparison.getDifferences(gmfView.getElement())) { |
| refinesToAdd.add(diffOnSemanticDecorator); |
| } |
| } |
| } |
| } |
| |
| } |