| /******************************************************************************* |
| * Copyright (c) 2013, 2015 Obeo and others. |
| * 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.rcp.ui.internal.mergeviewer.item.impl; |
| |
| import static com.google.common.collect.Iterables.filter; |
| import static com.google.common.collect.Iterables.getFirst; |
| import static com.google.common.collect.Lists.newArrayList; |
| |
| import com.google.common.base.Predicate; |
| import com.google.common.collect.Lists; |
| |
| import java.util.List; |
| |
| import org.eclipse.emf.common.notify.AdapterFactory; |
| import org.eclipse.emf.common.util.EList; |
| import org.eclipse.emf.compare.Comparison; |
| import org.eclipse.emf.compare.ConflictKind; |
| import org.eclipse.emf.compare.Diff; |
| import org.eclipse.emf.compare.DifferenceKind; |
| import org.eclipse.emf.compare.DifferenceSource; |
| import org.eclipse.emf.compare.DifferenceState; |
| import org.eclipse.emf.compare.Match; |
| import org.eclipse.emf.compare.ResourceAttachmentChange; |
| import org.eclipse.emf.compare.internal.utils.DiffUtil; |
| import org.eclipse.emf.compare.rcp.ui.internal.util.MergeViewerUtil; |
| import org.eclipse.emf.compare.rcp.ui.mergeviewer.IMergeViewer; |
| import org.eclipse.emf.compare.rcp.ui.mergeviewer.IMergeViewer.MergeViewerSide; |
| import org.eclipse.emf.compare.rcp.ui.mergeviewer.item.IMergeViewerItem; |
| import org.eclipse.emf.compare.rcp.ui.structuremergeviewer.groups.IDifferenceGroupProvider; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.resource.Resource; |
| |
| /** |
| * A specific {@link MergeViewerItem} for {@link ResourceAttachmentChange}. |
| * |
| * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a> |
| */ |
| public class ResourceAttachmentChangeMergeViewerItem extends MergeViewerItem.Container { |
| |
| /** |
| * @see org.eclipse.emf.compare.rcp.ui.internal.mergeviewer.item.impl.MergeViewerItem.Container#Container(Comparison |
| * comparison, Diff diff, Object left, Object right, Object ancestor, MergeViewerSide side, |
| * AdapterFactory adapterFactory) |
| */ |
| public ResourceAttachmentChangeMergeViewerItem(Comparison comparison, Diff diff, Resource left, |
| Resource right, Resource ancestor, IMergeViewer.MergeViewerSide side, |
| AdapterFactory adapterFactory) { |
| super(comparison, diff, left, right, ancestor, side, adapterFactory); |
| } |
| |
| /** |
| * @see org.eclipse.emf.compare.rcp.ui.internal.mergeviewer.item.impl.MergeViewerItem.Container#Container(Comparison, |
| * Diff, Match, MergeViewerSide, AdapterFactory) |
| */ |
| public ResourceAttachmentChangeMergeViewerItem(Comparison comparison, Diff diff, Match match, |
| IMergeViewer.MergeViewerSide side, AdapterFactory adapterFactory) { |
| super(comparison, diff, match, side, adapterFactory); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.compare.rcp.ui.internal.mergeviewer.item.impl.MergeViewerItem.Container#hasChildren(IDifferenceGroupProvider, |
| * Predicate) |
| */ |
| @Override |
| public boolean hasChildren(IDifferenceGroupProvider groupProvider, Predicate<? super EObject> predicate) { |
| return getChildren(groupProvider, predicate).length > 0; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.compare.rcp.ui.internal.mergeviewer.item.impl.MergeViewerItem.Container#getChildren(IDifferenceGroupProvider, |
| * Predicate) |
| */ |
| @SuppressWarnings("unchecked") |
| @Override |
| public IMergeViewerItem[] getChildren(IDifferenceGroupProvider group, Predicate<? super EObject> filters) { |
| Object sideValue = getSideValue(getSide()); |
| Object bestSideValue = getBestSideValue(); |
| |
| List<IMergeViewerItem> ret = newArrayList(); |
| |
| if (bestSideValue instanceof Resource) { |
| List<IMergeViewerItem> mergeViewerItems = newArrayList(); |
| if (sideValue instanceof Resource) { |
| mergeViewerItems = createMergeViewerItemFrom(((Resource)sideValue).getContents()); |
| } |
| |
| if (getSide() != IMergeViewer.MergeViewerSide.ANCESTOR) { |
| EList<Diff> differences = getComparison().getDifferences(); |
| Iterable<ResourceAttachmentChange> racs = filter(differences, ResourceAttachmentChange.class); |
| List<ResourceAttachmentChange> resourceAttachmentChanges = Lists.newArrayList(racs); |
| Object left = getLeft(); |
| Object right = getRight(); |
| Object ancestor = getAncestor(); |
| for (ResourceAttachmentChange resourceAttachmentChange : racs) { |
| // filter out merged reference changes |
| if (resourceAttachmentChange.getState() == DifferenceState.MERGED) { |
| // Remove resource attachment changes that are not linked with the current resources. |
| resourceAttachmentChanges.remove(resourceAttachmentChange); |
| } else if (isUnrelated(resourceAttachmentChange, left) |
| && isUnrelated(resourceAttachmentChange, right) |
| && isUnrelated(resourceAttachmentChange, ancestor)) { |
| resourceAttachmentChanges.remove(resourceAttachmentChange); |
| } |
| } |
| ret.addAll(createInsertionPoints(mergeViewerItems, |
| (List<ResourceAttachmentChange>)filteredDiffs(resourceAttachmentChanges, filters, |
| group))); |
| } else { |
| ret.addAll(mergeViewerItems); |
| } |
| |
| } |
| |
| return ret.toArray(getNoItemsArr()); |
| } |
| |
| private boolean isUnrelated(ResourceAttachmentChange change, Object resource) { |
| return resource == null |
| || (resource instanceof Resource && !change.getResourceURI().equals( |
| ((Resource)resource).getURI().toString())); |
| } |
| |
| /** |
| * Creates an IMergeViewerItem from an EObject. |
| * |
| * @param eObject |
| * the given eObject. |
| * @return an IMergeViewerItem. |
| */ |
| @Override |
| protected IMergeViewerItem createMergeViewerItemFrom(EObject eObject) { |
| |
| Match match = getComparison().getMatch(eObject); |
| |
| if (match != null) { |
| ResourceAttachmentChange rac = getFirst(filter(match.getDifferences(), |
| ResourceAttachmentChange.class), null); |
| if (rac != null) { |
| Object left = match.getLeft(); |
| Object right = match.getRight(); |
| Object ancestor = match.getOrigin(); |
| // Manage case where the resource attachment change is between an existing resource and an |
| // unknown resource |
| if (MergeViewerUtil.getResource(getComparison(), MergeViewerSide.LEFT, rac) == null) { |
| left = null; |
| } |
| if (MergeViewerUtil.getResource(getComparison(), MergeViewerSide.RIGHT, rac) == null) { |
| right = null; |
| } |
| if (MergeViewerUtil.getResource(getComparison(), MergeViewerSide.ANCESTOR, rac) == null) { |
| ancestor = null; |
| } |
| |
| return new MergeViewerItem.Container(getComparison(), rac, left, right, ancestor, getSide(), |
| getAdapterFactory()); |
| } |
| } |
| return null; |
| |
| } |
| |
| /** |
| * Creates insertion points for the given list of IMergeViewerItem corresponding to the given list of |
| * ResourceAttachmentChange. |
| * |
| * @param values |
| * the given list of IMergeViewerItem. |
| * @param racs |
| * the givel list of ResourceAttachmentChange |
| * @return the given list of IMergeViewerItem with additional insertion points. |
| */ |
| private List<? extends IMergeViewerItem> createInsertionPoints( |
| final List<? extends IMergeViewerItem> values, final List<ResourceAttachmentChange> racs) { |
| List<IMergeViewerItem> ret = newArrayList(values); |
| for (ResourceAttachmentChange diff : Lists.reverse(racs)) { |
| boolean rightToLeft = (getSide() == IMergeViewer.MergeViewerSide.LEFT); |
| Comparison comparison = getComparison(); |
| Object left = MergeViewerUtil.getValueFromResourceAttachmentChange(diff, comparison, |
| IMergeViewer.MergeViewerSide.LEFT); |
| Object right = MergeViewerUtil.getValueFromResourceAttachmentChange(diff, comparison, |
| IMergeViewer.MergeViewerSide.RIGHT); |
| |
| DifferenceSource source = diff.getSource(); |
| DifferenceKind kind = diff.getKind(); |
| DifferenceState state = diff.getState(); |
| boolean b1 = source == DifferenceSource.LEFT && kind == DifferenceKind.DELETE |
| && getSide() == MergeViewerSide.LEFT && DifferenceState.MERGED != state; |
| boolean b2 = source == DifferenceSource.LEFT && kind == DifferenceKind.ADD |
| && getSide() == MergeViewerSide.RIGHT && DifferenceState.MERGED != state; |
| boolean b3 = source == DifferenceSource.RIGHT && kind == DifferenceKind.ADD |
| && getSide() == MergeViewerSide.LEFT && DifferenceState.MERGED != state; |
| boolean b4 = source == DifferenceSource.RIGHT && kind == DifferenceKind.DELETE |
| && getSide() == MergeViewerSide.RIGHT && DifferenceState.MERGED != state; |
| |
| boolean b5 = DifferenceState.MERGED == state && source == DifferenceSource.LEFT |
| && kind == DifferenceKind.ADD && right == null; |
| boolean b6 = DifferenceState.MERGED == state && source == DifferenceSource.LEFT |
| && kind == DifferenceKind.DELETE && left == null; |
| boolean b7 = DifferenceState.MERGED == state && source == DifferenceSource.RIGHT |
| && kind == DifferenceKind.ADD && left == null; |
| boolean b8 = DifferenceState.MERGED == state && source == DifferenceSource.RIGHT |
| && kind == DifferenceKind.DELETE && right == null; |
| // do not duplicate insertion point for pseudo add conflict |
| // so we must only create one for pseudo delete conflict |
| boolean b9 = diff.getConflict() == null |
| || (diff.getConflict().getKind() != ConflictKind.PSEUDO || kind == DifferenceKind.DELETE); |
| |
| if ((b1 || b2 || b3 || b4 || b5 || b6 || b7 || b8) && b9) { |
| Object ancestor = MergeViewerUtil.getValueFromResourceAttachmentChange(diff, comparison, |
| IMergeViewer.MergeViewerSide.ANCESTOR); |
| if (left != null |
| && MergeViewerUtil.getResource(comparison, IMergeViewer.MergeViewerSide.LEFT, diff) == null) { |
| left = null; |
| } |
| if (right != null |
| && MergeViewerUtil.getResource(comparison, IMergeViewer.MergeViewerSide.RIGHT, diff) == null) { |
| right = null; |
| } |
| if (ancestor != null |
| && MergeViewerUtil.getResource(comparison, IMergeViewer.MergeViewerSide.ANCESTOR, |
| diff) == null) { |
| ancestor = null; |
| } |
| if (b5 || b8) { |
| left = null; |
| } |
| if (b6 || b7) { |
| right = null; |
| } |
| IMergeViewerItem insertionPoint = new MergeViewerItem.Container(comparison, diff, left, |
| right, ancestor, getSide(), getAdapterFactory()); |
| |
| final int insertionIndex; |
| if (left == null && right == null && ancestor != null) { |
| Resource resource = MergeViewerUtil.getResource(comparison, |
| IMergeViewer.MergeViewerSide.ANCESTOR, diff); |
| List<EObject> contents = resource.getContents(); |
| insertionIndex = contents.indexOf(ancestor); |
| } else { |
| insertionIndex = Math.min(findInsertionIndex(diff, rightToLeft), ret.size()); |
| } |
| |
| // offset the insertion by the number of previous insertion points in the list |
| // Can not b improved by keeping the number of created insertion points because the given |
| // "values" parameter may already contains some insertion points. |
| int realIndex = 0; |
| for (int index = 0; index < insertionIndex && realIndex < ret.size(); realIndex++) { |
| if (!ret.get(realIndex).isInsertionPoint()) { |
| index++; |
| } |
| } |
| ret.add(realIndex, insertionPoint); |
| } |
| } |
| return ret; |
| } |
| |
| /** |
| * Find an insertion index for the given diff. |
| * |
| * @param diff |
| * the given diff. |
| * @param rightToLeft |
| * the way of merge. |
| * @return an insertion index for the given diff. |
| */ |
| private int findInsertionIndex(Diff diff, boolean rightToLeft) { |
| final Match valueMatch = diff.getMatch(); |
| final Comparison comparison = getComparison(); |
| |
| final EObject expectedValue; |
| if (valueMatch.getLeft() != null) { |
| expectedValue = valueMatch.getLeft(); |
| } else { |
| expectedValue = valueMatch.getRight(); |
| } |
| |
| final Resource initialResource; |
| final Resource expectedResource; |
| if (rightToLeft) { |
| initialResource = MergeViewerUtil.getResource(comparison, IMergeViewer.MergeViewerSide.RIGHT, |
| diff); |
| expectedResource = MergeViewerUtil.getResource(comparison, IMergeViewer.MergeViewerSide.LEFT, |
| diff); |
| } else { |
| initialResource = MergeViewerUtil |
| .getResource(comparison, IMergeViewer.MergeViewerSide.LEFT, diff); |
| expectedResource = MergeViewerUtil.getResource(comparison, IMergeViewer.MergeViewerSide.RIGHT, |
| diff); |
| } |
| if (expectedResource != null) { |
| final List<EObject> sourceList = initialResource.getContents(); |
| final List<EObject> targetList = expectedResource.getContents(); |
| |
| return DiffUtil.findInsertionIndex(comparison, sourceList, targetList, expectedValue); |
| } else { |
| return 0; |
| } |
| } |
| |
| } |