blob: 5f82ccad9ab62b3e5a1768c7e9b12c7ea917f26f [file] [log] [blame]
/*****************************************************************************
* Copyright (c) 2019 CEA LIST, and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Nicolas FAUVERGUE (CEA LIST) nicolas.fauvergue@cea.fr - Initial API and implementation
*
*****************************************************************************/
package org.eclipse.papyrus.gitlight.compare.ui.contentmergeviewer.provider;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.compare.Comparison;
import org.eclipse.emf.compare.Diff;
import org.eclipse.emf.compare.ResourceAttachmentChange;
import org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.tree.provider.TreeMergeViewerItemContentProvider;
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.mergeviewer.item.provider.IMergeViewerItemProviderConfiguration;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.edit.provider.ITreeItemContentProvider;
import org.eclipse.gmf.runtime.notation.Diagram;
/**
* Modifies the {@link TreeMergeViewerItemContentProvider} for the Papyrus Facet mechanism.
*/
@SuppressWarnings("restriction")
public class PapyrusMergeViewerItemContentProvider extends TreeMergeViewerItemContentProvider {
@Override
public boolean hasChildren(Object object, IMergeViewerItemProviderConfiguration configuration) {
// Filter children of diagrams
if (object instanceof IMergeViewerItem) {
Object bestSideObject = getBestSideValue(IMergeViewerItem.class.cast(object),
configuration.getSide());
if (Diagram.class.isInstance(bestSideObject)) {
return false;
}
}
return super.hasChildren(object, configuration);
}
@Override
protected IMergeViewerItem createMergeViewerItemFrom(EObject eObject, IMergeViewerItem parent,
IMergeViewerItemProviderConfiguration configuration) {
IMergeViewerItem createdItem = super.createMergeViewerItemFrom(eObject, parent, configuration);
if (PapyrusMergeViewerItem.class.isInstance(createdItem)) {
PapyrusMergeViewerItem.class.cast(createdItem).setPapyrusParent(parent);
}
return createdItem;
}
@Override
protected IMergeViewerItem createMergeViewerItem(Comparison comparison, Diff diff, Object left,
Object right, Object ancestor, MergeViewerSide side, AdapterFactory adapterFactory) {
return new PapyrusMergeViewerItem(comparison, diff, left, right, ancestor, side, adapterFactory);
}
@Override
public Object getParent(Object object, IMergeViewerItemProviderConfiguration configuration) {
// Mimic Facet mechanism
if (PapyrusMergeViewerItem.class.isInstance(object)) {
PapyrusMergeViewerItem item = PapyrusMergeViewerItem.class.cast(object);
if (item.getPapyrusParent() != null) {
return item.getPapyrusParent();
}
}
IMergeViewerItem mergeViewerItem = (IMergeViewerItem)object;
if (mergeViewerItem.getDiff() instanceof ResourceAttachmentChange) {
// fallback to parent in special case
return super.getParent(object, configuration);
}
// Try to get the parent but do not return a parent which could be filtered away
Object sideValue = getBestSideValue(mergeViewerItem, configuration.getSide());
if (sideValue != null) {
Object parent = getUnfilteredParent(sideValue, configuration);
if (parent != null) {
return parent;
}
}
// fallback
return super.getParent(object, configuration);
}
/**
* Determines the parent of the given object but 'skips' parent elements which are filtered away.
*
* @param object
* the {@link Object} whose parent is to be determined.
* @param configuration
* the {@link IMergeViewerItemProviderConfiguration}.
* @return the unfiltered parent if one could be determined, {@code null} otherwise.
*/
protected Object getUnfilteredParent(Object object, IMergeViewerItemProviderConfiguration configuration) {
List<Object> pathToRoot = getPathToRoot(object, configuration);
Set<Object> alreadyLookedAt = new HashSet<Object>();
int currentIndex = pathToRoot.size() - 1;
while (true) {
Object nextObject = pathToRoot.get(currentIndex);
if (alreadyLookedAt.contains(nextObject)) {
// there is a containment circle
return null;
}
alreadyLookedAt.add(nextObject);
List<Object> childrenFromContentProvider = getChildrenFromContentProvider(nextObject,
configuration.getAdapterFactory());
childrenFromContentProvider.retainAll(pathToRoot);
if (childrenFromContentProvider.isEmpty()) {
// break in the chain
return null;
}
if (childrenFromContentProvider.get(0) == object) {
// found the parent that returns the given object
return nextObject;
}
currentIndex = pathToRoot.lastIndexOf(childrenFromContentProvider.get(0));
}
}
/**
* Determines all the parents of the given object up to the root.
*
* @param object
* the {@link Object} whose parents are to be determined.
* @param configuration
* the {@link IMergeViewerItemProviderConfiguration}
* @return A list starting from the given {@code object} and ending with the root element.
*/
private List<Object> getPathToRoot(Object object, IMergeViewerItemProviderConfiguration configuration) {
List<Object> path = new ArrayList<Object>();
Object currentObject = object;
while (currentObject != null) {
path.add(currentObject);
ITreeItemContentProvider treeItemContentProvider = (ITreeItemContentProvider)configuration
.getAdapterFactory().adapt(currentObject, ITreeItemContentProvider.class);
if (treeItemContentProvider == null) {
break;
}
currentObject = treeItemContentProvider.getParent(currentObject);
}
return path;
}
}