From c01f56d36d84172ff43aaa5ca6a22c9bcfde660a Mon Sep 17 00:00:00 2001 From: Laurent Delaigue Date: Tue, 6 Sep 2016 11:27:53 +0200 Subject: Fix cascading filter for special cases To allow group extenders to properly modify the tree structure, this filter must use the TreeNode hierarchy instead of the match hierarchy, otherwise it will not filter the relevant elements. It's also important to take into account the refining diffs of the diff to filter in case they contain containment RefChanges of parent matches. Change-Id: I431429520816073b4fd73e8e8367337d04be10c8 Signed-off-by: Laurent Delaigue --- .../filters/impl/CascadingDifferencesFilter.java | 88 ++++++++++++++++------ 1 file changed, 65 insertions(+), 23 deletions(-) diff --git a/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/filters/impl/CascadingDifferencesFilter.java b/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/filters/impl/CascadingDifferencesFilter.java index eb9be9869..fe4d421de 100644 --- a/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/filters/impl/CascadingDifferencesFilter.java +++ b/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/filters/impl/CascadingDifferencesFilter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2013, 2015 Obeo. + * Copyright (c) 2013, 2016 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 @@ -18,13 +18,19 @@ import static org.eclipse.emf.compare.DifferenceKind.MOVE; import static org.eclipse.emf.compare.DifferenceSource.LEFT; import static org.eclipse.emf.compare.DifferenceSource.RIGHT; import static org.eclipse.emf.compare.utils.EMFComparePredicates.CONTAINMENT_REFERENCE_CHANGE; +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.Iterables; +import com.google.common.collect.Iterators; + +import java.util.Iterator; import org.eclipse.emf.compare.Diff; import org.eclipse.emf.compare.DifferenceSource; import org.eclipse.emf.compare.Match; +import org.eclipse.emf.compare.ReferenceChange; import org.eclipse.emf.compare.ResourceAttachmentChange; import org.eclipse.emf.compare.rcp.ui.structuremergeviewer.filters.AbstractDifferenceFilter; import org.eclipse.emf.compare.utils.MatchUtil; @@ -32,8 +38,16 @@ import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.edit.tree.TreeNode; /** - * A filter used by default that filtered out cascading differences (differences located under differences, - * also known as sub differences). The MOVE differences are not hidden by this filter. + * A filter used by default that filters out cascading differences (differences located under a Match that is + * either ADDed or DELETEd on the diff's side). The MOVE differences are not hidden by this filter. + * Differences hidden are all those that match the following criteria: + * * * @author Axel Richard * @since 4.0 @@ -41,7 +55,7 @@ import org.eclipse.emf.edit.tree.TreeNode; public class CascadingDifferencesFilter extends AbstractDifferenceFilter { /** - * The predicate use by this filter when it is selected. + * The predicate used by this filter when it is selected. */ private static final Predicate PREDICATE_WHEN_SELECTED = new Predicate() { public boolean apply(EObject input) { @@ -51,20 +65,12 @@ public class CascadingDifferencesFilter extends AbstractDifferenceFilter { EObject data = treeNode.getData(); if (data instanceof Diff && !(data instanceof ResourceAttachmentChange)) { Diff diff = (Diff)data; - if (diff.getKind() != MOVE && (diff.getConflict() == null)) { + if (diff.getKind() != MOVE && diff.getConflict() == null && diff.getRefines().isEmpty()) { TreeNode parent = treeNode.getParent(); if (parent != null && parent.getData() instanceof Match) { - Match match = (Match)parent.getData(); - if (match.eContainer() instanceof Match) { - Match parentMatch = (Match)match.eContainer(); - if (isAddOrDeleteMatch(parentMatch, diff.getSource())) { - ret = true; - } else if (isAddOrDeleteMatch(match, diff.getSource())) { - ret = !and(or(CONTAINMENT_REFERENCE_CHANGE, - REFINED_BY_CONTAINMENT_REF_CHANGE), ofKind(ADD, DELETE)) - .apply(diff); - } - } else if (isAddOrDeleteMatch(match, diff.getSource())) { + Match parentMatch = (Match)parent.getData(); + ret = isInsideAddOrDeleteTreeNode(diff, parent); + if (!ret && isAddOrDeleteMatch(parentMatch, diff.getSource())) { ret = !and( or(CONTAINMENT_REFERENCE_CHANGE, REFINED_BY_CONTAINMENT_REF_CHANGE), ofKind(ADD, DELETE)).apply(diff); @@ -76,6 +82,44 @@ public class CascadingDifferencesFilter extends AbstractDifferenceFilter { return ret; } + private boolean isInsideAddOrDeleteTreeNode(Diff diff, TreeNode parent) { + boolean ret = false; + DifferenceSource side = diff.getSource(); + TreeNode grandParent = parent.getParent(); + Match grandParentMatch = null; + if (grandParent != null && grandParent.getData() instanceof Match) { + grandParentMatch = (Match)grandParent.getData(); + } + if (isAddOrDeleteMatch(grandParentMatch, side)) { + // The ancestor has been added/deleted, we must filter the current diff + // _unless_ it is refined by the diff that represents the grand-parent + // add/delete + ReferenceChange addOrDeleteDiff = findAddOrDeleteDiff(grandParentMatch, side); + if (addOrDeleteDiff != null) { + if (diff.getRefinedBy().contains(addOrDeleteDiff)) { + // recurse + ret = isInsideAddOrDeleteTreeNode(diff, grandParent); + } else { + ret = true; + } + } + } + return ret; + } + + private ReferenceChange findAddOrDeleteDiff(Match match, DifferenceSource side) { + EObject container = match.eContainer(); + if (container instanceof Match) { + @SuppressWarnings("unchecked") + Iterator candidates = Iterators.filter(((Match)container).getDifferences().iterator(), + and(fromSide(side), CONTAINMENT_REFERENCE_CHANGE, ofKind(ADD, DELETE))); + if (candidates.hasNext()) { + return (ReferenceChange)candidates.next(); + } + } + return null; + } + /** * Indicate whether a Match is that of an object that was either added or deleted on the given side. * @@ -84,8 +128,12 @@ public class CascadingDifferencesFilter extends AbstractDifferenceFilter { * @param side * The side * @return true if the matched object is present on side but not on origin or vice-versa. + * false if match is null. */ protected boolean isAddOrDeleteMatch(Match match, DifferenceSource side) { + if (match == null) { + return false; + } if (match.getComparison().isThreeWay()) { return (MatchUtil.getMatchedObject(match, side) == null) != (match.getOrigin() == null); } @@ -107,16 +155,10 @@ public class CascadingDifferencesFilter extends AbstractDifferenceFilter { private static final Predicate REFINED_BY_CONTAINMENT_REF_CHANGE = new Predicate() { public boolean apply(Diff input) { - return input.getPrimeRefining() != null - && CONTAINMENT_REFERENCE_CHANGE.apply(input.getPrimeRefining()); + return Iterables.any(input.getRefinedBy(), CONTAINMENT_REFERENCE_CHANGE); } }; - /** - * {@inheritDoc} - * - * @see org.eclipse.emf.compare.rcp.ui.structuremergeviewer.filters.IDifferenceFilter#getPredicateWhenSelected() - */ @Override public Predicate getPredicateWhenSelected() { return PREDICATE_WHEN_SELECTED; -- cgit v1.2.3