Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEdgar Mueller2016-06-01 14:58:30 +0000
committerPhilip Langer2016-07-01 15:46:35 +0000
commit49971d97e08242a395eea3ecb317136785efbc7f (patch)
treed9e04c678043772beff93022a73a6dfa63b296a6
parent889b193baf3276837ca1865930ad28586f3ffa96 (diff)
downloadorg.eclipse.emf.compare-49971d97e08242a395eea3ecb317136785efbc7f.tar.gz
org.eclipse.emf.compare-49971d97e08242a395eea3ecb317136785efbc7f.tar.xz
org.eclipse.emf.compare-49971d97e08242a395eea3ecb317136785efbc7f.zip
[487595] Add specialized PapyrusTreeContentMergeViewer
If we are in the context of a Papyrus comparison, we are now using a dedicated tree content merge viewer instead of the default one. This dedicated content merge viewer shows the model tree according to how it looks like in the model explorer of Papyrus. Therefore, it * filters all unrelated root elements * filters Diagram elements * uses Papyrus Content and Label Provider to display elements * registered for Papyrus types * uses a CompareAccessorFactory-Wrapper to "generate" the Papyrus types * as the content provider does not support directly revealing elements, we cache the model tree and therefore have to traverse it once Bug: 487595 Signed-off-by: Stefan Dirix <sdirix@eclipsesource.com> Signed-off-by: Philip Langer <planger@eclipsesource.com> Signed-off-by: Edgar Mueller <emueller@eclipsesource.com> Also-by: Philip Langer <planger@eclipsesource.com> Change-Id: Ibf27a6ac338f556e190891f572375f59eae94f2d
-rw-r--r--plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/META-INF/MANIFEST.MF11
-rw-r--r--plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/plugin.xml23
-rw-r--r--plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/pom.xml14
-rw-r--r--plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/PapyrusTreeContentMergeViewer.java356
-rw-r--r--plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/PapyrusTreeContentMergeViewer.properties111
-rw-r--r--plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/PapyrusTreeContentMergeViewerCreator.java43
-rw-r--r--plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/facet/PapyrusFacetContentProviderWrapper.java68
-rw-r--r--plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/facet/PapyrusFacetContentProviderWrapperAdapterFactory.java92
-rw-r--r--plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/item/ContentProviderMergeViewerItem.java1053
-rw-r--r--plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/item/ContentProviderMergeViewerItemFactory.java73
-rw-r--r--plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/item/MergeViewerItemConverter.java120
-rw-r--r--plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/item/PapyrusContentProviderMergeViewerItem.java193
-rw-r--r--plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/provider/PapyrusTreeContentMergeViewerItemContentProvider.java252
-rw-r--r--plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/provider/PapyrusTreeContentMergeViewerItemLabelProvider.java152
-rw-r--r--plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/internal/CompareDiagramIDEUIPapyrusPlugin.java40
-rw-r--r--plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/internal/accessorfactory/PapyrusAccessorFactoryWrapper.java146
-rw-r--r--plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/internal/accessorfactory/PapyrusAccessorWrapper.java91
-rw-r--r--plugins/org.eclipse.emf.compare.diagram.papyrus.tests/META-INF/MANIFEST.MF2
-rw-r--r--plugins/org.eclipse.emf.compare.ide.ui/META-INF/MANIFEST.MF1
-rw-r--r--plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/contentmergeviewer/tree/TreeContentMergeViewer.java187
-rw-r--r--plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/contentmergeviewer/tree/provider/TreeContentMergeViewerItemContentProvider.java85
-rw-r--r--plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/contentmergeviewer/tree/provider/TreeContentMergeViewerItemLabelProvider.java97
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.edit/src/org/eclipse/emf/compare/uml2/internal/provider/decorator/UMLCompareItemProviderDecoratorAdapterFactory.java8
23 files changed, 3085 insertions, 133 deletions
diff --git a/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/META-INF/MANIFEST.MF
index fb581a381..11e5e46fb 100644
--- a/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/META-INF/MANIFEST.MF
@@ -13,6 +13,7 @@ Require-Bundle: org.eclipse.ui.ide;bundle-version="3.5.0",
org.eclipse.emf.compare.ide;bundle-version="3.1.0",
org.eclipse.emf.compare.ide.ui;bundle-version="4.1.0",
org.eclipse.emf.compare.diagram.ide.ui;bundle-version="3.0.0",
+ org.eclipse.emf.compare.rcp.ui;bundle-version="4.2.0",
org.eclipse.gmf.runtime.diagram.ui;bundle-version="0.9.1",
org.eclipse.papyrus.uml.diagram.common;bundle-version="0.9.1",
org.eclipse.papyrus.infra.gmfdiag.common;bundle-version="0.9.1",
@@ -20,7 +21,15 @@ Require-Bundle: org.eclipse.ui.ide;bundle-version="3.5.0",
org.eclipse.papyrus.infra.onefile;bundle-version="0.9.1",
org.eclipse.papyrus.infra.gmfdiag.css;bundle-version="1.0.0",
org.eclipse.papyrus.uml.tools;bundle-version="1.0.0",
- org.eclipse.papyrus.infra.emf;bundle-version="1.0.0"
+ org.eclipse.papyrus.infra.emf,
+ org.eclipse.compare,
+ org.eclipse.emf.compare.rcp.ui,
+ org.eclipse.emf.edit.ui,
+ org.eclipse.papyrus.emf.facet.custom.metamodel,
+ org.eclipse.papyrus.emf.facet.custom.ui,
+ org.eclipse.uml2.uml.edit,
+ org.eclipse.papyrus.infra.services.labelprovider,
+ org.eclipse.ui.navigator
Bundle-RequiredExecutionEnvironment: J2SE-1.5
Import-Package: com.google.common.base;version="[11.0.0,16.0.0)",
com.google.common.collect;version="[11.0.0,16.0.0)",
diff --git a/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/plugin.xml b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/plugin.xml
index e57d27f08..d85f9234f 100644
--- a/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/plugin.xml
+++ b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/plugin.xml
@@ -62,4 +62,27 @@
</adapter>
</factory>
</extension>
+ <extension
+ point="org.eclipse.compare.contentMergeViewers">
+ <viewer
+ class="org.eclipse.emf.compare.diagram.ide.ui.papyrus.contentmergeviewer.PapyrusTreeContentMergeViewerCreator"
+ id="org.eclipse.emf.compare.ide.ui.papyrus.PapyrusTreeContentMergeViewer"
+ label="Model Compare (Papyrus)"
+ extensions=
+ "papyrus-org.eclipse.emf.compare.rcp.ui.eTreeDiff,
+ papyrus-org.eclipse.emf.compare.rcp.ui.eMatch,
+ papyrus-org.eclipse.emf.compare.rcp.ui.eResourceDiff,
+ papyrus-NODE_TYPE__EMF_EOBJECT,
+ papyrus-NODE_TYPE__EMF_RESOURCE,
+ papyrus-NODE_TYPE__EMF_RESOURCESET,
+ papyrus-NODE_TYPE__EMF_COMPARISON">
+ </viewer>
+ </extension>
+ <extension
+ point="org.eclipse.emf.compare.rcp.ui.accessorFactory">
+ <factory
+ class="org.eclipse.emf.compare.diagram.ide.ui.papyrus.internal.accessorfactory.PapyrusAccessorFactoryWrapper"
+ ranking="1000">
+ </factory>
+ </extension>
</plugin>
diff --git a/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/pom.xml b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/pom.xml
index dfb71c51a..aeca7f38d 100644
--- a/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/pom.xml
+++ b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/pom.xml
@@ -12,4 +12,18 @@
<artifactId>org.eclipse.emf.compare.diagram.ide.ui.papyrus</artifactId>
<version>2.5.0-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.eclipse.tycho</groupId>
+ <artifactId>target-platform-configuration</artifactId>
+ <version>${tycho-version}</version>
+ <configuration>
+ <dependency-resolution>
+ <optionalDependencies>ignore</optionalDependencies>
+ </dependency-resolution>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
</project>
diff --git a/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/PapyrusTreeContentMergeViewer.java b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/PapyrusTreeContentMergeViewer.java
new file mode 100644
index 000000000..9a430922f
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/PapyrusTreeContentMergeViewer.java
@@ -0,0 +1,356 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EclipseSource Muenchen GmbH 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:
+ * Stefan Dirix - initial API and implementation
+ * Philip Langer - introduce caching
+ *******************************************************************************/
+package org.eclipse.emf.compare.diagram.ide.ui.papyrus.contentmergeviewer;
+
+import static com.google.common.base.Predicates.instanceOf;
+import static com.google.common.base.Predicates.not;
+import static com.google.common.collect.Iterables.any;
+import static java.util.Arrays.asList;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.ResourceBundle;
+
+import org.eclipse.emf.compare.diagram.ide.ui.papyrus.contentmergeviewer.item.PapyrusContentProviderMergeViewerItem;
+import org.eclipse.emf.compare.diagram.ide.ui.papyrus.contentmergeviewer.provider.PapyrusTreeContentMergeViewerItemContentProvider;
+import org.eclipse.emf.compare.diagram.ide.ui.papyrus.contentmergeviewer.provider.PapyrusTreeContentMergeViewerItemLabelProvider;
+import org.eclipse.emf.compare.ide.ui.internal.configuration.EMFCompareConfiguration;
+import org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.tree.TreeContentMergeViewer;
+import org.eclipse.emf.compare.rcp.ui.contentmergeviewer.accessor.ICompareAccessor;
+import org.eclipse.emf.compare.rcp.ui.internal.mergeviewer.impl.AbstractMergeViewer;
+import org.eclipse.emf.compare.rcp.ui.internal.mergeviewer.impl.AbstractTableOrTreeMergeViewer.ElementComparer;
+import org.eclipse.emf.compare.rcp.ui.internal.mergeviewer.impl.TreeMergeViewer;
+import org.eclipse.emf.compare.rcp.ui.mergeviewer.IMergeViewer.MergeViewerSide;
+import org.eclipse.emf.compare.rcp.ui.mergeviewer.item.IMergeViewerItem;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.IContentProvider;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * Specialized Tree Content Merge Viewer for Papyrus.
+ *
+ * @author Stefan Dirix
+ */
+@SuppressWarnings("restriction")
+public class PapyrusTreeContentMergeViewer extends TreeContentMergeViewer {
+
+ /**
+ * Since Papyrus trees could in theory be infinite, we need a maximum search level.
+ */
+ private static final int MAX_SEARCH_LEVEL = 20;
+
+ /**
+ * Map of objects to {@link PapyrusContentProviderMergeViewerItem Papyrus merge viewer items } used when
+ * changing the selection in order to find the merge viewer item to be selected when a specific object
+ * (model element or diff) is to be revealed.
+ */
+ private Map<Object, IMergeViewerItem> cachedMapForSelection;
+
+ /**
+ * Constructor.
+ *
+ * @param style
+ * the style parameter
+ * @param bundle
+ * the {@link ResourceBundle}
+ * @param parent
+ * the {@link Composite} parent
+ * @param config
+ * the {@link EMFCompareConfiguration}
+ */
+ public PapyrusTreeContentMergeViewer(int style, ResourceBundle bundle, Composite parent,
+ EMFCompareConfiguration config) {
+ super(style, bundle, parent, config);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.EMFCompareContentMergeViewer#createMergeViewer(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ protected AbstractMergeViewer createMergeViewer(final Composite parent, final MergeViewerSide side) {
+ final TreeMergeViewer mergeTreeViewer = new TreeMergeViewer(parent, side, this,
+ getCompareConfiguration());
+ final IContentProvider contentProvider = new PapyrusTreeContentMergeViewerItemContentProvider(
+ getAdapterFactory(), getCompareConfiguration(), getDifferenceGroupProvider(),
+ getDifferenceFilterPredicate());
+ mergeTreeViewer.setContentProvider(contentProvider);
+
+ final IBaseLabelProvider labelProvider = new PapyrusTreeContentMergeViewerItemLabelProvider(
+ getResourceBundle(), getAdapterFactory(), side);
+ mergeTreeViewer.setLabelProvider(labelProvider);
+
+ hookListeners(mergeTreeViewer);
+
+ return mergeTreeViewer;
+ }
+
+ /**
+ * Check whether the given input is an instance of {@link ICompareAccessor}.
+ *
+ * @param input
+ * the given input to check
+ * @return {@code true}, if the input is an instance of {@link ICompareAccessor}, {@code false} otherwise
+ */
+ private static boolean isCompareAccessor(Object input) {
+ return input instanceof ICompareAccessor;
+ }
+
+ /**
+ * Check whether the current input of the given side differs from the given one.
+ *
+ * @param side
+ * the side to be checked, either {@link MergeViewerSide#LEFT} or {@link MergeViewerSide#RIGHT}
+ * @param input
+ * the input to check against
+ * @return {@code true}, if the input is different, {@code false} otherwise
+ */
+ private boolean isDifferentInput(MergeViewerSide side, Object input) {
+ TreeMergeViewer viewer = getMergeViewer(side);
+ if (!isCompareAccessor(input) || !isCompareAccessor(viewer.getInput())) {
+ return true;
+ }
+ ImmutableList<? extends IMergeViewerItem> inputItems = ICompareAccessor.class.cast(input).getItems();
+ ImmutableList<? extends IMergeViewerItem> vieweritems = ICompareAccessor.class.cast(viewer.getInput())
+ .getItems();
+ if (inputItems.size() != vieweritems.size()) {
+ return true;
+ }
+ ElementComparer comparer = new ElementComparer();
+ for (int i = 0; i < vieweritems.size(); i++) {
+ if (!comparer.equals(inputItems.get(i), vieweritems.get(i))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns the {@link TreeMergeViewer} of the given side.
+ *
+ * @param side
+ * the side for which to return the {@link TreeMergeViewer}
+ * @return the {@link TreeMergeViewer} of the respective side
+ */
+ public TreeMergeViewer getMergeViewer(MergeViewerSide side) {
+ if (side == MergeViewerSide.LEFT) {
+ return getLeftMergeViewer();
+ } else if (side == MergeViewerSide.RIGHT) {
+ return getRightMergeViewer();
+ }
+ return getAncestorMergeViewer();
+ }
+
+ @Override
+ protected void updateContent(Object ancestor, Object left, Object right) {
+ // Modify selection so it works with the Papyrus Merge Viewer Items
+
+ // first check whether the input on any side has changed
+ if (isDifferentInput(MergeViewerSide.LEFT, left) || isDifferentInput(MergeViewerSide.RIGHT, right)) {
+ getAncestorMergeViewer().setInput(ancestor);
+ getLeftMergeViewer().setInput(left);
+ getRightMergeViewer().setInput(right);
+ }
+
+ IMergeViewerItem leftInitialItem = null;
+ if (left instanceof ICompareAccessor) {
+ leftInitialItem = ((ICompareAccessor)left).getInitialItem();
+ }
+
+ // Bug 458818: In some cases, the left initial item is null because
+ // the item that should be selected has been deleted on the right
+ // and this delete is part of a conflict
+ if (leftInitialItem == null || leftInitialItem.getLeft() == null) {
+ if (right instanceof ICompareAccessor) {
+ IMergeViewerItem rightInitialItem = ((ICompareAccessor)right).getInitialItem();
+ if (rightInitialItem == null) {
+ getLeftMergeViewer().setSelection(StructuredSelection.EMPTY, true);
+ } else {
+ setSelection((ICompareAccessor)right, getRightMergeViewer());
+ }
+ } else {
+ // Strange case: left is an ICompareAccessor but right is not?
+ getLeftMergeViewer().setSelection(StructuredSelection.EMPTY, true);
+ }
+ } else {
+ // others will synchronize on this one :)
+ setSelection((ICompareAccessor)left, getLeftMergeViewer());
+ }
+ redrawCenterControl();
+ }
+
+ /**
+ * Caches the tree viewer content given by the objects <code>left</code> and <code>right</code>, if we
+ * haven't built a cache yet.
+ * <p>
+ * The caching builds a {@link #cachedMapForSelection map} of objects to be objects of the tree and their
+ * {@link IMergeViewerItem} that represent those objects.
+ * </p>
+ *
+ * @param left
+ * the left object, which must be a {@link ICompareAccessor}.
+ * @param right
+ * the right object, which must be a {@link ICompareAccessor}.
+ */
+ private void cacheTreeViewerContentIfNecessary(Object left, Object right) {
+ if (cachedMapForSelection != null || notICompareAccessor(left, right)) {
+ // we already have a cache or can't build one anyway
+ return;
+ }
+
+ cachedMapForSelection = new HashMap<Object, IMergeViewerItem>();
+
+ cacheTreeViewerContent((ICompareAccessor)left, getLeftMergeViewer(), MergeViewerSide.LEFT);
+ cacheTreeViewerContent((ICompareAccessor)right, getRightMergeViewer(), MergeViewerSide.RIGHT);
+ }
+
+ /**
+ * Specifies whether the given <code>objects</code> are all instances of {@link ICompareAccessor}.
+ *
+ * @param objects
+ * The objects to check.
+ * @return <code>true</code> if they all are instances of {@link ICompareAccessor}, <code>false</code>
+ * otherwise.
+ */
+ private boolean notICompareAccessor(Object... objects) {
+ return any(asList(objects), not(instanceOf(ICompareAccessor.class)));
+ }
+
+ /**
+ * Traverses all {@link ITreeContentProvider#getElements(Object) elements} of the given
+ * <code>accessor</code> and caches its content for the given <code>side</code>.
+ * <p>
+ * Note that this may be an expensive method, if the model is very large.
+ * </p>
+ *
+ * @param accessor
+ * The accessor representing the content to be cached.
+ * @param viewer
+ * The viewer for obtaining the content provider from.
+ * @param side
+ * The side of the viewer.
+ */
+ private void cacheTreeViewerContent(ICompareAccessor accessor, TreeMergeViewer viewer,
+ MergeViewerSide side) {
+ final ITreeContentProvider provider = ITreeContentProvider.class.cast(viewer.getContentProvider());
+ for (Object element : provider.getElements(accessor)) {
+ if (element instanceof IMergeViewerItem) {
+ final IMergeViewerItem item = IMergeViewerItem.class.cast(element);
+ cacheTreeViewerContent(item, provider, side, MAX_SEARCH_LEVEL);
+ }
+ }
+ }
+
+ /**
+ * Caches the given <code>item</code> and its children determined by the given <code>provider</code>.
+ *
+ * @param item
+ * The item to be cached.
+ * @param provider
+ * The content provider for determining the children of <code>item</code>.
+ * @param side
+ * The merge viewer side.
+ * @param maxSearchLevel
+ * The maximum search level.
+ */
+ private void cacheTreeViewerContent(IMergeViewerItem item, ITreeContentProvider provider,
+ MergeViewerSide side, int maxSearchLevel) {
+ if (maxSearchLevel == 0) {
+ return;
+ }
+
+ cacheItem(item, side);
+
+ for (Object child : provider.getChildren(item)) {
+ if (child instanceof IMergeViewerItem) {
+ final IMergeViewerItem childItem = (IMergeViewerItem)child;
+ cacheTreeViewerContent(childItem, provider, side, maxSearchLevel - 1);
+ }
+ }
+ }
+
+ /**
+ * Caches the given <code>item</code> for the given side.
+ *
+ * @param item
+ * The item to cache.
+ * @param side
+ * The side.
+ */
+ private void cacheItem(IMergeViewerItem item, MergeViewerSide side) {
+ if (MergeViewerSide.LEFT.equals(side) && item.getLeft() != null) {
+ cachedMapForSelection.put(item.getLeft(), item);
+ } else if (MergeViewerSide.RIGHT.equals(side) && item.getRight() != null) {
+ cachedMapForSelection.put(item.getRight(), item);
+ }
+ }
+
+ /**
+ * Sets the selection according to the accessor.
+ *
+ * @param accessor
+ * The {@link ICompareAccessor} which contains the root tree elements and the initial
+ * selection.
+ * @param viewer
+ * The {@ink TreeMergeViewer} for which the selection is to be set.
+ */
+ private void setSelection(ICompareAccessor accessor, TreeMergeViewer viewer) {
+ // First try to set the initial item directly
+ final IMergeViewerItem initialItem = accessor.getInitialItem();
+ viewer.setSelection(new StructuredSelection(initialItem), true);
+
+ // if that didn't work (empty selection), use cache to find correct merge viewer item
+ if (viewer.getSelection().isEmpty()) {
+ // init cache, if necessary
+ cacheTreeViewerContentIfNecessary(getLeftMergeViewer().getInput(),
+ getRightMergeViewer().getInput());
+ final IMergeViewerItem itemToBeSelected = getItemToBeSelectedFromCache(initialItem);
+ if (itemToBeSelected != null) {
+ viewer.setSelection(new StructuredSelection(itemToBeSelected), true);
+ } else {
+ viewer.setSelection(new StructuredSelection(), true);
+ }
+ }
+ }
+
+ /**
+ * Obtains the item for the selection in the tree viewers for the given <code>item</code>.
+ *
+ * @param item
+ * The item to be selected.
+ * @return The item that can be used for selection in the merge viewer trees.
+ */
+ private IMergeViewerItem getItemToBeSelectedFromCache(IMergeViewerItem item) {
+ IMergeViewerItem itemToBeSelected = null;
+ if (MergeViewerSide.LEFT.equals(item.getSide()) && item.getLeft() != null) {
+ itemToBeSelected = cachedMapForSelection.get(item.getLeft());
+ } else if (MergeViewerSide.RIGHT.equals(item.getSide()) && item.getRight() != null) {
+ itemToBeSelected = cachedMapForSelection.get(item.getRight());
+ }
+ return itemToBeSelected;
+ }
+
+ @Override
+ protected void handleDispose(DisposeEvent event) {
+ if (cachedMapForSelection != null) {
+ this.cachedMapForSelection.clear();
+ this.cachedMapForSelection = null;
+ }
+ super.handleDispose(event);
+ }
+}
diff --git a/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/PapyrusTreeContentMergeViewer.properties b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/PapyrusTreeContentMergeViewer.properties
new file mode 100644
index 000000000..4bacade97
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/PapyrusTreeContentMergeViewer.properties
@@ -0,0 +1,111 @@
+###############################################################################
+# Copyright (c) 2012, 2016 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
+# Stefan Dirix - adjustments for Papyrus
+###############################################################################
+
+title= Model Compare (Papyrus)
+
+saveDialog.title= Save Resource
+saveDialog.message= Resource has been modified. Save changes?
+
+compareProgressTask.title= Computing Differences...
+
+tooComplexError.title= Error
+tooComplexError.message= Too many differences. Turn on the 'Ignore White Space' option or do a structure compare first.
+
+UnkownResource = Unknown Resource
+
+#####################################################
+# Toolbar actions
+#####################################################
+
+action.CopyLeftToRight.label=Copy Left to Right
+action.CopyLeftToRight.tooltip=Copy All from Left to Right
+action.CopyLeftToRight.image=copy_r_co.gif
+
+action.CopyRightToLeft.label=Copy Right to Left
+action.CopyRightToLeft.tooltip=Copy All Non-Conflicting Changes from Right to Left
+action.CopyRightToLeft.image=copy_l_co.gif
+
+action.CopyDiffLeftToRight.label=Copy Current Change to Right
+action.CopyDiffLeToRight.tooltip=Copy Current Change from Left to Right
+action.CopyDiffLeftToRight.image=copycont_r_co.gif
+
+action.CopyDiffRightToLeft.label=Copy Current Change to Left
+action.CopyDiffRightToLeft.tooltip=Copy Current Change from Right to Left
+action.CopyDiffRightToLeft.image=copycont_l_co.gif
+
+action.NextDiff.label=Next Difference
+action.NextDiff.tooltip=Next Difference
+action.NextDiff.image=next_diff_nav.gif
+
+action.PrevDiff.label=Previous Difference
+action.PrevDiff.tooltip=Previous Difference
+action.PrevDiff.image=prev_diff_nav.gif
+
+action.NextChange.label=Next Change
+action.NextChange.tooltip=Next Change
+action.NextChange.image=next_change_nav.gif
+
+action.PrevChange.label=Previous Change
+action.PrevChange.tooltip=Previous Change
+action.PrevChange.image=prev_change_nav.gif
+
+action.EnableAncestor.label=Enable Ancestor Pane
+action.EnableAncestor.tooltip.unchecked=Show Ancestor Pane
+action.EnableAncestor.tooltip.checked=Hide Ancestor Pane
+action.EnableAncestor.description.unchecked=Show Ancestor Pane
+action.EnableAncestor.description.checked=Hide Ancestor Pane
+action.EnableAncestor.image=ancestorpane_co.gif
+
+action.IgnoreAncestor.label=Ignore Ancestor
+action.IgnoreAncestor.tooltip.unchecked=Two-Way Compare (Ignore Ancestor)
+action.IgnoreAncestor.tooltip.checked=Three-Way Compare
+action.IgnoreAncestor.description.unchecked=Two-Way Compare (Ignore Ancestor)
+action.IgnoreAncestor.description.checked=Three-Way Compare
+action.IgnoreAncestor.image=twowaycompare_co.gif
+
+
+#####################################################
+# Context menu actions
+#####################################################
+
+action.undo.label=&Undo
+action.undo.tooltip=Undo Last Operation
+
+action.redo.label=&Redo
+action.redo.tooltip=Redo Last Operation
+
+action.cut.label=Cu&t
+action.cut.tooltip=Cut Text Selection to Clipboard
+
+action.copy.label=&Copy
+action.copy.tooltip=Copy Text Selection to Clipboard
+
+action.paste.label=&Paste
+action.paste.tooltip=Replace Text Selection with Clipboard Contents
+
+action.delete.label=&Delete
+action.delete.tooltip=Delete Current Text Selection
+
+action.find.label=&Find...
+action.find.tooltip=Find Occurrence
+
+action.selectAll.label=Select &All
+action.selectAll.tooltip=Select All Changes
+
+Editor.FindReplace.label=&Find/Replace...
+Editor.FindReplace.tooltip=Find/Replace
+Editor.FindReplace.image=
+Editor.FindReplace.description=Find/Replace
+
+action.IgnoreWhiteSpace.label=&Ignore White Space
+action.IgnoreWhiteSpace.tooltip=Ignore White Space Where Applicable
+
diff --git a/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/PapyrusTreeContentMergeViewerCreator.java b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/PapyrusTreeContentMergeViewerCreator.java
new file mode 100644
index 000000000..5f306ce8a
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/PapyrusTreeContentMergeViewerCreator.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EclipseSource Muenchen GmbH 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:
+ * Stefan Dirix - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.diagram.ide.ui.papyrus.contentmergeviewer;
+
+import java.util.ResourceBundle;
+
+import org.eclipse.compare.CompareConfiguration;
+import org.eclipse.compare.IViewerCreator;
+import org.eclipse.emf.compare.ide.ui.internal.configuration.EMFCompareConfiguration;
+import org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.provider.TreeNodeCompareInput;
+import org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.provider.TreeNodeCompareInputLabelProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * Creator for {@link PapyrusTreeContentMergeViewer}.
+ *
+ * @author Stefan Dirix
+ */
+@SuppressWarnings("restriction")
+public class PapyrusTreeContentMergeViewerCreator implements IViewerCreator {
+
+ /**
+ * {@inheritDoc}
+ */
+ public Viewer createViewer(Composite parent, CompareConfiguration config) {
+ final EMFCompareConfiguration emfConfig = new EMFCompareConfiguration(config);
+ emfConfig.setLabelProvider(TreeNodeCompareInput.class, new TreeNodeCompareInputLabelProvider());
+ final Viewer viewer = new PapyrusTreeContentMergeViewer(SWT.NONE,
+ ResourceBundle.getBundle(PapyrusTreeContentMergeViewer.class.getName()), parent, emfConfig);
+ return viewer;
+ }
+
+}
diff --git a/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/facet/PapyrusFacetContentProviderWrapper.java b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/facet/PapyrusFacetContentProviderWrapper.java
new file mode 100644
index 000000000..3992e4fd3
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/facet/PapyrusFacetContentProviderWrapper.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EclipseSource Muenchen GmbH 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:
+ * Stefan Dirix - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.diagram.ide.ui.papyrus.contentmergeviewer.facet;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.edit.provider.ITreeItemContentProvider;
+import org.eclipse.emf.edit.provider.ItemProviderAdapter;
+import org.eclipse.papyrus.uml.tools.providers.SemanticUMLContentProvider;
+
+/**
+ * Wraps the Papyrus Facet content provider in an EMF {@link ItemProviderAdapter}.
+ *
+ * @author Stefan Dirix
+ */
+public class PapyrusFacetContentProviderWrapper extends ItemProviderAdapter implements ITreeItemContentProvider {
+
+ /**
+ * The Papyrus Facet Content Provider.
+ */
+ private SemanticUMLContentProvider facetContentProvider;
+
+ /**
+ * Constructor.
+ *
+ * @param adapterFactory
+ * the {@link AdapterFactory}.
+ * @param resourceSet
+ * the {@ResourceSet} for Papyrus Facet.
+ */
+ public PapyrusFacetContentProviderWrapper(AdapterFactory adapterFactory, ResourceSet resourceSet) {
+ super(adapterFactory);
+ facetContentProvider = new SemanticUMLContentProvider(resourceSet);
+
+ }
+
+ @Override
+ public Collection<?> getElements(Object object) {
+ return Arrays.asList(facetContentProvider.getElements(object));
+ }
+
+ @Override
+ public Collection<?> getChildren(Object object) {
+ return Arrays.asList(facetContentProvider.getChildren(object));
+ }
+
+ @Override
+ public boolean hasChildren(Object object) {
+ return facetContentProvider.hasChildren(object);
+ }
+
+ @Override
+ public Object getParent(Object object) {
+ return facetContentProvider.getParent(object);
+ }
+
+}
diff --git a/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/facet/PapyrusFacetContentProviderWrapperAdapterFactory.java b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/facet/PapyrusFacetContentProviderWrapperAdapterFactory.java
new file mode 100644
index 000000000..9c0c3e856
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/facet/PapyrusFacetContentProviderWrapperAdapterFactory.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EclipseSource Muenchen GmbH 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:
+ * Stefan Dirix - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.diagram.ide.ui.papyrus.contentmergeviewer.facet;
+
+import org.eclipse.emf.common.notify.Adapter;
+import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.edit.provider.Disposable;
+import org.eclipse.emf.edit.provider.IStructuredItemContentProvider;
+import org.eclipse.emf.edit.provider.ITreeItemContentProvider;
+import org.eclipse.uml2.uml.edit.providers.UMLItemProviderAdapterFactory;
+
+/**
+ * Couples the Papyrus Facet mechanism with the AdapterFactory approach of EMFCompare.
+ *
+ * @author Stefan Dirix <sdirix@eclipsesource.com>
+ */
+public class PapyrusFacetContentProviderWrapperAdapterFactory extends UMLItemProviderAdapterFactory {
+
+ /**
+ * Collects and disposes associated adapters.
+ */
+ private Disposable disposable = new Disposable();
+
+ /**
+ * Constructor.
+ */
+ public PapyrusFacetContentProviderWrapperAdapterFactory() {
+ super();
+ // Only support content types
+ supportedTypes.clear();
+ supportedTypes.add(ITreeItemContentProvider.class);
+ supportedTypes.add(IStructuredItemContentProvider.class);
+ }
+
+ @Override
+ public Adapter createAdapter(Notifier target) {
+ ResourceSet resourceSet = getResourceSet(target);
+ if (resourceSet != null) {
+ return new PapyrusFacetContentProviderWrapper(this, resourceSet);
+ }
+ return super.createAdapter(target);
+ }
+
+ /**
+ * Determines the {@link ResourceSet} of the given {@code target}.
+ *
+ * @param target
+ * The {@Notifier} for which a {@link ResourceSet} is to be determined.
+ * @return The {@link ResourceSet} for the given {@code target} if there is one, {@code null} otherwise.
+ */
+ private ResourceSet getResourceSet(Notifier target) {
+ if (EObject.class.isInstance(target)) {
+ EObject object = EObject.class.cast(target);
+ return object.eResource().getResourceSet();
+ }
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see NotationItemProviderAdapterFactory#dispose()
+ */
+ @Override
+ public void dispose() {
+ disposable.dispose();
+ super.dispose();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see NotationItemProviderAdapterFactory#associate(Adapter adapter, Notifier target)
+ */
+ @Override
+ protected void associate(Adapter adapter, Notifier target) {
+ super.associate(adapter, target);
+ if (adapter != null) {
+ disposable.add(adapter);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/item/ContentProviderMergeViewerItem.java b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/item/ContentProviderMergeViewerItem.java
new file mode 100644
index 000000000..2809655db
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/item/ContentProviderMergeViewerItem.java
@@ -0,0 +1,1053 @@
+/*******************************************************************************
+ * Copyright (c) 2012, 2016 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
+ * Stefan Dirix - Use ItemProvider instead of Reflection
+ *******************************************************************************/
+// CHECKSTYLE:OFF copied and (slightly) modified version of the MergeViewerItem
+package org.eclipse.emf.compare.diagram.ide.ui.papyrus.contentmergeviewer.item;
+
+import static com.google.common.base.Predicates.instanceOf;
+import static com.google.common.collect.Iterables.filter;
+import static com.google.common.collect.Iterables.getFirst;
+import static com.google.common.collect.Iterables.isEmpty;
+import static com.google.common.collect.Iterables.size;
+import static com.google.common.collect.Lists.newArrayList;
+import static com.google.common.collect.Lists.newArrayListWithCapacity;
+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.Objects;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.common.notify.impl.AdapterImpl;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.compare.Comparison;
+import org.eclipse.emf.compare.Conflict;
+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.ReferenceChange;
+import org.eclipse.emf.compare.ResourceAttachmentChange;
+import org.eclipse.emf.compare.graph.IGraphView;
+import org.eclipse.emf.compare.internal.spec.EObjectUtil;
+import org.eclipse.emf.compare.internal.utils.DiffUtil;
+import org.eclipse.emf.compare.match.impl.NotLoadedFragmentMatch;
+import org.eclipse.emf.compare.rcp.ui.internal.mergeviewer.item.impl.ResourceAttachmentChangeMergeViewerItem;
+import org.eclipse.emf.compare.rcp.ui.internal.util.MergeViewerUtil;
+import org.eclipse.emf.compare.rcp.ui.internal.util.ResourceUIUtil;
+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;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.util.FeatureMap;
+import org.eclipse.emf.edit.provider.FeatureMapEntryWrapperItemProvider;
+import org.eclipse.emf.edit.provider.ITreeItemContentProvider;
+
+/**
+ * @author <a href="mailto:mikael.barbero@obeo.fr">Mikael Barbero</a>
+ */
+@SuppressWarnings("restriction")
+public class ContentProviderMergeViewerItem extends AdapterImpl implements IMergeViewerItem {
+
+ private final Object fLeft;
+
+ private final Object fRight;
+
+ private final Object fAncestor;
+
+ private final Diff fDiff;
+
+ private final Comparison fComparison;
+
+ private final MergeViewerSide fSide;
+
+ private final AdapterFactory fAdapterFactory;
+
+ private ContentProviderMergeViewerItemFactory mergeViewerItemFactory;
+
+ public ContentProviderMergeViewerItem(Comparison comparison, Diff diff, Object left, Object right,
+ Object ancestor, MergeViewerSide side, AdapterFactory adapterFactory) {
+ fLeft = left;
+ fRight = right;
+ fAncestor = ancestor;
+ fDiff = diff;
+ fSide = side;
+ fAdapterFactory = adapterFactory;
+ fComparison = comparison;
+ mergeViewerItemFactory = new ContentProviderMergeViewerItemFactory();
+ }
+
+ /**
+ * @param comparison
+ * @param diff
+ * @param match
+ * @param side
+ * @param adapterFactory
+ */
+ public ContentProviderMergeViewerItem(Comparison comparison, Diff diff, Match match, MergeViewerSide side,
+ AdapterFactory adapterFactory) {
+ this(comparison, diff, match.getLeft(), match.getRight(), match.getOrigin(), side, adapterFactory);
+ }
+
+ /**
+ * Returns the factory to create new {@link ContentProviderMergeViewerItem.Container}.
+ */
+ protected ContentProviderMergeViewerItemFactory getMergeViewerItemFactory() {
+ return mergeViewerItemFactory;
+ }
+
+ /**
+ * Adapts to {@link ITreeItemMergeViewerContentProvider} or {@link ITreeItemContentProvider} and calls
+ * getChildren. Also unwraps {@link FeatureMap.Entry}.
+ *
+ * @param object
+ * The object for which the children are to be determined.
+ * @return A list of all children of the given {@code object}.
+ */
+ protected List<Object> getChildrenFromContentProvider(Object object) {
+ if (object == null) {
+ return Collections.emptyList();
+ }
+ // Check if a specialized content provider is active
+ ITreeItemContentProvider treeItemContentProvider = (ITreeItemContentProvider)getAdapterFactory()
+ .adapt(object, ITreeItemContentProvider.class);
+ if (treeItemContentProvider == null) {
+ // Fallback to a general content provider
+ treeItemContentProvider = (ITreeItemContentProvider)getAdapterFactory().adapt(object,
+ ITreeItemContentProvider.class);
+ }
+ if (treeItemContentProvider != null) {
+ final List<Object> children = new ArrayList<Object>(treeItemContentProvider.getChildren(object));
+ return unwrapFeatureMapEntryProviders(children);
+ }
+ return Collections.emptyList();
+ }
+
+ /**
+ * Returns the children of the given {@link MergeViewerSide}.
+ *
+ * @see #getChildrenFromContentProvider(Object)
+ * @param side
+ * The side for which the children are to be determined.
+ * @return A list of all children of the given {@code side}.
+ */
+ protected List<Object> getChildrenFromContentProvider(MergeViewerSide side) {
+ return getChildrenFromContentProvider(getSideValue(side));
+ }
+
+ private List<Object> unwrapFeatureMapEntryProviders(List<Object> values) {
+ final List<Object> result = new ArrayList<Object>(values.size());
+ for (Object value : values) {
+ if (FeatureMapEntryWrapperItemProvider.class.isInstance(value)) {
+ final FeatureMapEntryWrapperItemProvider featureMapEntryProvider = FeatureMapEntryWrapperItemProvider.class
+ .cast(value);
+ final Object featureMapEntry = featureMapEntryProvider.getValue();
+ if (FeatureMap.Entry.class.isInstance(featureMapEntry)) {
+ final Object featureMapValue = FeatureMap.Entry.class.cast(featureMapEntry).getValue();
+ result.add(featureMapValue);
+ }
+ } else {
+ result.add(value);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @return
+ */
+ public final Diff getDiff() {
+ return fDiff;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.emf.compare.rcp.ui.mergeviewer.item.ide.ui.internal.contentmergeviewer.IMergeViewerItem#getAncestor()
+ */
+ public final Object getAncestor() {
+ return fAncestor;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.emf.compare.rcp.ui.mergeviewer.item.ide.ui.internal.contentmergeviewer.IMergeViewerItem#getLeft()
+ */
+ public final Object getLeft() {
+ return fLeft;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.emf.compare.rcp.ui.mergeviewer.item.ide.ui.internal.contentmergeviewer.IMergeViewerItem#getRight()
+ */
+ public final Object getRight() {
+ return fRight;
+ }
+
+ /**
+ * @return the fSide
+ */
+ public final MergeViewerSide getSide() {
+ return fSide;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.emf.compare.rcp.ui.mergeviewer.item.ide.ui.internal.contentmergeviewer.IMergeViewerItem#getSideValue(org.eclipse.emf.compare.rcp.ui.mergeviewer.ide.ui.internal.contentmergeviewer.IMergeViewer.MergeViewerSide)
+ */
+ public final Object getSideValue(MergeViewerSide side) {
+ switch (side) {
+ case LEFT:
+ return fLeft;
+ case RIGHT:
+ return fRight;
+ case ANCESTOR:
+ return fAncestor;
+ default:
+ throw new IllegalStateException(); // happy compiler :)
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.emf.compare.rcp.ui.mergeviewer.item.IMergeViewerItem#getParent()
+ */
+ public IMergeViewerItem.Container getParent() {
+ IMergeViewerItem.Container ret = null;
+
+ if (getDiff() instanceof ResourceAttachmentChange) {
+ ret = createBasicContainer((ResourceAttachmentChange)getDiff());
+ } else {
+ Object sideValue = getBestSideValue();
+ ITreeItemContentProvider treeItemContentProvider = (ITreeItemContentProvider)fAdapterFactory
+ .adapt(sideValue, ITreeItemContentProvider.class);
+
+ Object parent = treeItemContentProvider != null ? treeItemContentProvider.getParent(sideValue)
+ : null;
+ if (parent instanceof EObject) {
+ ret = createBasicContainer((EObject)parent);
+ }
+ }
+
+ return ret;
+ }
+
+ public IMergeViewerItem cloneAsOpposite() {
+ return getMergeViewerItemFactory().createContentProviderMergeViewerItem(getComparison(), getDiff(),
+ getLeft(), getRight(), getAncestor(), getSide(), getAdapterFactory());
+ }
+
+ protected final Object getBestSideValue() {
+ Object sideValue;
+ if (fSide != MergeViewerSide.ANCESTOR) {
+ sideValue = getSideValue(fSide);
+ if (sideValue == null) {
+ sideValue = getSideValue(fSide.opposite());
+ if (sideValue == null) {
+ sideValue = getSideValue(MergeViewerSide.ANCESTOR);
+ }
+ }
+ } else {
+ sideValue = getSideValue(MergeViewerSide.ANCESTOR);
+ if (sideValue == null) {
+ sideValue = getSideValue(MergeViewerSide.LEFT);
+ if (sideValue == null) {
+ sideValue = getSideValue(MergeViewerSide.RIGHT);
+ }
+ }
+ }
+ return sideValue;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.emf.compare.rcp.ui.mergeviewer.item.IMergeViewerItem#isInsertionPoint()
+ */
+ public boolean isInsertionPoint() {
+ return getSideValue(getSide()) == null && getDiff() != null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ String className = this.getClass().getName();
+ int start = className.lastIndexOf('.');
+ // @formatter:off
+ return Objects.toStringHelper(className.substring(start + 1))
+ .add("ancestor", EObjectUtil.getLabel((EObject)getAncestor())) //$NON-NLS-1$
+ .add("left", EObjectUtil.getLabel((EObject)getLeft())) //$NON-NLS-1$
+ .add("right", EObjectUtil.getLabel((EObject)getRight())) //$NON-NLS-1$
+ .add("side", getSide()) //$NON-NLS-1$
+ .add("diff", getDiff()).toString(); //$NON-NLS-1$
+ // @formatter:on
+ }
+
+ /**
+ * @return the fComparison
+ */
+ protected final Comparison getComparison() {
+ return fComparison;
+ }
+
+ /**
+ * @return the fAdapterFactory
+ */
+ protected final AdapterFactory getAdapterFactory() {
+ return fAdapterFactory;
+ }
+
+ protected final IMergeViewerItem.Container createBasicContainer(EObject eObject) {
+ IMergeViewerItem.Container ret = null;
+ Match parentMatch = fComparison.getMatch(eObject);
+ if (parentMatch == null) {
+ return null;
+ }
+ EObject expectedValue = MergeViewerUtil.getEObject(parentMatch, fSide);
+ if (expectedValue != null) {
+ Iterable<? extends Diff> diffs = getDiffsWithValue(expectedValue, parentMatch);
+ Diff diff = getFirst(diffs, null);
+ ret = getMergeViewerItemFactory().createContentProviderMergeViewerItem(fComparison, diff,
+ parentMatch, fSide, fAdapterFactory);
+
+ } else {
+ expectedValue = MergeViewerUtil.getEObject(parentMatch, fSide.opposite());
+ Iterable<? extends Diff> diffs = Lists.newArrayList();
+ if (expectedValue != null) {
+ diffs = getDiffsWithValue(expectedValue, parentMatch);
+ }
+ if (isEmpty(diffs)) {
+ expectedValue = MergeViewerUtil.getEObject(parentMatch, MergeViewerSide.ANCESTOR);
+ if (expectedValue != null) {
+ diffs = getDiffsWithValue(expectedValue, parentMatch);
+ }
+ }
+
+ if (!isEmpty(diffs)) {
+ Diff diff = diffs.iterator().next();
+ if (diff instanceof ResourceAttachmentChange) {
+ ret = getMergeViewerItemFactory().createContentProviderMergeViewerItem(fComparison, diff,
+ parentMatch, fSide, fAdapterFactory);
+ } else {
+ ret = createInsertionPoint(diff, fSide, fAdapterFactory);
+ }
+ }
+ }
+ return ret;
+ }
+
+ /**
+ * Return an Iterable of {@link Diff} which are linked to the given expectedValue. Try to get containment
+ * reference changes first, then if empty, try to get resource attachment changes.
+ *
+ * @param expectedValue
+ * @return
+ */
+ private Iterable<? extends Diff> getDiffsWithValue(EObject expectedValue, Match parentMatch) {
+ Iterable<? extends Diff> diffs = filter(fComparison.getDifferences(expectedValue),
+ CONTAINMENT_REFERENCE_CHANGE);
+ if (size(diffs) > 1 && fSide != MergeViewerSide.ANCESTOR) {
+ diffs = filter(diffs, fromSide(fSide.convertToDifferenceSource()));
+ if (size(diffs) > 1) {
+ throw new IllegalStateException(
+ "Should not have more than one ReferenceChange on each Match for a side"); //$NON-NLS-1$
+ }
+ }
+
+ Diff referenceChange = getFirst(diffs, null);
+ if (referenceChange == null) {
+ diffs = filter(parentMatch.getDifferences(), instanceOf(ResourceAttachmentChange.class));
+ }
+
+ return diffs;
+ }
+
+ /**
+ * Create an IMergeViewerItem for the parent of the given {@link ResourceAttachmentChange}.
+ *
+ * @param diff
+ * the given {@link ResourceAttachmentChange}.
+ * @return an IMergeViewerItem.
+ */
+ protected final IMergeViewerItem.Container createBasicContainer(ResourceAttachmentChange diff) {
+ final Comparison comparison = getComparison();
+ Resource left = MergeViewerUtil.getResource(comparison, MergeViewerSide.LEFT, diff);
+ Resource right = MergeViewerUtil.getResource(comparison, MergeViewerSide.RIGHT, diff);
+ Resource ancestor = MergeViewerUtil.getResource(comparison, MergeViewerSide.ANCESTOR, diff);
+ IMergeViewerItem.Container ret = new ResourceAttachmentChangeMergeViewerItem(comparison, null, left,
+ right, ancestor, getSide(), getAdapterFactory());
+ return ret;
+ }
+
+ protected final List<IMergeViewerItem> createInsertionPoints(Comparison comparison,
+ final List<Object> sideContent, final List<Object> oppositeContent,
+ final List<Object> ancestorContent, final List<? extends IMergeViewerItem> values,
+ List<? extends Diff> differences) {
+ final List<IMergeViewerItem> ret = newArrayList(values);
+ if (differences.isEmpty()) {
+ return ret;
+ }
+
+ if (sideContent.isEmpty() && oppositeContent.isEmpty()) {
+ return ret;
+ }
+
+ for (Diff diff : Lists.reverse(differences)) {
+ EObject value = (EObject)MergeViewerUtil.getDiffValue(diff);
+ Match match = getComparison().getMatch(value);
+ if (!isPseudoAddConflict(diff) && (isAddOnOppositeSide(diff) || isDeleteOnSameSide(diff)
+ || isInsertOnBothSides(diff, match))) {
+ if (match == null && diff.getState() == DifferenceState.MERGED) {
+ EObject bestSideValue = (EObject)getBestSideValue();
+ match = getComparison().getMatch(bestSideValue);
+ match = getMatchWithNullValues(match);
+ }
+
+ if (match != null && !isRealAddConflict(diff, match)) {
+ IMergeViewerItem.Container insertionPoint = getMergeViewerItemFactory()
+ .createContentProviderMergeViewerItem(getComparison(), diff, match.getLeft(),
+ match.getRight(), match.getOrigin(), getSide(), getAdapterFactory());
+
+ final int insertionIndex;
+ if (match.getLeft() == null && match.getRight() == null && diff.getConflict() != null
+ && diff.getConflict().getKind() == ConflictKind.PSEUDO) {
+ // pseudo conflict delete...
+ insertionIndex = ancestorContent.indexOf(value);
+ } else {
+ insertionIndex = Math.min(
+ DiffUtil.findInsertionIndex(comparison, oppositeContent, sideContent, value),
+ ret.size());
+ }
+
+ // offset the insertion by the number of previous insertion points in the list
+ // Cannot be 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;
+ }
+
+ protected final List<IMergeViewerItem> createInsertionPoints(Comparison comparison,
+ final List<IMergeViewerItem> values, List<? extends Diff> differences) {
+ List<Object> sideContent = getChildrenFromContentProvider(getSide());
+ List<Object> oppositeContent = getChildrenFromContentProvider(getSide().opposite());
+ List<Object> ancestorContent = getChildrenFromContentProvider(MergeViewerSide.ANCESTOR);
+
+ return createInsertionPoints(comparison, sideContent, oppositeContent, ancestorContent, values,
+ differences);
+ }
+
+ private boolean isAddOnOppositeSide(Diff diff) {
+ if (diff.getState() != DifferenceState.MERGED && diff.getKind() == DifferenceKind.ADD) {
+ DifferenceSource source = diff.getSource();
+ MergeViewerSide side = getSide();
+ return (source == DifferenceSource.LEFT && side == MergeViewerSide.RIGHT)
+ || (source == DifferenceSource.RIGHT && side == MergeViewerSide.LEFT);
+ }
+
+ return false;
+ }
+
+ private boolean isDeleteOnSameSide(Diff diff) {
+ if (diff.getState() != DifferenceState.MERGED && diff.getKind() == DifferenceKind.DELETE) {
+ DifferenceSource source = diff.getSource();
+ MergeViewerSide side = getSide();
+ return (source == DifferenceSource.LEFT && side == MergeViewerSide.LEFT)
+ || (source == DifferenceSource.RIGHT && side == MergeViewerSide.RIGHT);
+ }
+
+ return false;
+ }
+
+ private boolean isInsertOnBothSides(Diff diff, Match match) {
+ return diff.getState() == DifferenceState.MERGED
+ && (match == null || (match.getLeft() == null && match.getRight() == null));
+ }
+
+ private boolean isPseudoAddConflict(Diff diff) {
+ Conflict conflict = diff.getConflict();
+ return conflict != null && conflict.getKind() == ConflictKind.PSEUDO
+ && diff.getKind() == DifferenceKind.ADD;
+ }
+
+ private boolean isRealAddConflict(Diff diff, Match match) {
+ // Real add conflict (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=442898)
+ return match.getRight() != null && match.getLeft() != null && isAddOnOppositeSide(diff);
+ }
+
+ /**
+ * After merging a diff which will lead to have an insertion point on both sides, the match associated
+ * with this diff will be unreacheable because its left and right sides will be null. This method will
+ * find this match.
+ *
+ * @param match
+ * the given match.
+ * @return the match associated with the given merged diff.
+ */
+ private Match getMatchWithNullValues(Match match) {
+ for (Match subMatch : match.getSubmatches()) {
+ if (subMatch.getLeft() == null && subMatch.getRight() == null) {
+ return subMatch;
+ }
+ }
+ return null;
+ }
+
+ private IMergeViewerItem.Container createInsertionPoint(Diff diff, MergeViewerSide side,
+ AdapterFactory adapterFactory) {
+ Object left = MergeViewerUtil.getValueFromDiff(diff, MergeViewerSide.LEFT);
+ Object right = MergeViewerUtil.getValueFromDiff(diff, MergeViewerSide.RIGHT);
+
+ IMergeViewerItem.Container insertionPoint = null;
+ if (left == null && right == null) {
+ // Do not display anything
+ } else {
+ final boolean leftEmptyBox = side == MergeViewerSide.LEFT
+ && (left == null || !MergeViewerUtil.getValues(diff, side).contains(left));
+ final boolean rightEmptyBox = side == MergeViewerSide.RIGHT
+ && (right == null || !MergeViewerUtil.getValues(diff, side).contains(right));
+ if (leftEmptyBox || rightEmptyBox) {
+ Object ancestor = MergeViewerUtil.getValueFromDiff(diff, MergeViewerSide.ANCESTOR);
+
+ insertionPoint = getMergeViewerItemFactory().createContentProviderMergeViewerItem(
+ getComparison(), diff, left, right, ancestor, side, adapterFactory);
+ }
+ }
+
+ return insertionPoint;
+ }
+
+ protected final List<IMergeViewerItem> createMergeViewerItemFrom(Collection<?> values) {
+ List<IMergeViewerItem> ret = newArrayListWithCapacity(values.size());
+ for (EObject value : filter(values, EObject.class)) {
+ Match match = getComparison().getMatch(value);
+ if (this.fDiff != null || (match != null && !isMatchWithAllProxyData(match))) {
+ IMergeViewerItem valueToAdd = createMergeViewerItemFrom(value);
+ if (valueToAdd != null) {
+ ret.add(valueToAdd);
+ }
+ }
+ }
+ return ret;
+ }
+
+ protected boolean yieldsMergeViewerItem(Collection<?> values) {
+ Iterable<EObject> elements = filter(values, EObject.class);
+ if (fDiff != null && !Iterables.isEmpty(elements)) {
+ return true;
+ }
+
+ for (EObject element : elements) {
+ Match match = getComparison().getMatch(element);
+ if (match != null && !isMatchWithAllProxyData(match)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ protected boolean yieldsInsertionPoint(Iterable<? extends Diff> diffs) {
+ List<Object> sideContent = getChildrenFromContentProvider(getSide());
+ List<Object> oppositeContent = getChildrenFromContentProvider(getSide().opposite());
+ if (sideContent.isEmpty() && oppositeContent.isEmpty()) {
+ return false;
+ }
+ return Iterables.any(diffs, new Predicate<Diff>() {
+ public boolean apply(Diff diff) {
+ if (isPseudoAddConflict(diff)) {
+ return false;
+ }
+
+ EObject value = (EObject)MergeViewerUtil.getDiffValue(diff);
+ Match match = getComparison().getMatch(value);
+ if (isAddOnOppositeSide(diff) || isDeleteOnSameSide(diff)
+ || isInsertOnBothSides(diff, match)) {
+ if (match == null && diff.getState() == DifferenceState.MERGED) {
+ EObject bestSideValue = (EObject)getBestSideValue();
+ match = getComparison().getMatch(bestSideValue);
+ match = getMatchWithNullValues(match);
+ }
+
+ return match != null && !isRealAddConflict(diff, match);
+ }
+
+ return false;
+ }
+ });
+ }
+
+ /**
+ * Check if the given match holds a proxy on each side.
+ *
+ * @param match
+ * the given match.
+ * @return true if the given match holds a proxy on each side, false otherwise.
+ */
+ private boolean isMatchWithAllProxyData(Match match) {
+ boolean proxy = false;
+ EObject left = match.getLeft();
+ EObject right = match.getRight();
+ EObject origin = match.getOrigin();
+ if (left != null && right != null) {
+ if (left.eIsProxy() && right.eIsProxy()) {
+ proxy = true;
+ }
+ }
+ if (proxy == true && fComparison.isThreeWay() && (origin == null || !origin.eIsProxy())) {
+ proxy = false;
+ }
+ return proxy;
+ }
+
+ /**
+ * Creates an IMergeViewerItem from an EObject.
+ *
+ * @param eObject
+ * the given eObject.
+ * @return an IMergeViewerItem.
+ */
+ protected IMergeViewerItem createMergeViewerItemFrom(EObject eObject) {
+
+ Match match = getComparison().getMatch(eObject);
+
+ ReferenceChange referenceChange = (ReferenceChange)getFirst(
+ filter(getComparison().getDifferences(eObject), CONTAINMENT_REFERENCE_CHANGE), null);
+ if (match != null) {
+ return getMergeViewerItemFactory().createContentProviderMergeViewerItem(getComparison(),
+ referenceChange, match, getSide(), getAdapterFactory());
+ } else {
+ switch (getSide()) {
+ case LEFT:
+ return getMergeViewerItemFactory().createContentProviderMergeViewerItem(getComparison(),
+ referenceChange, eObject, null, null, getSide(), getAdapterFactory());
+ case RIGHT:
+ return getMergeViewerItemFactory().createContentProviderMergeViewerItem(getComparison(),
+ referenceChange, null, eObject, null, getSide(), getAdapterFactory());
+ case ANCESTOR:
+ return getMergeViewerItemFactory().createContentProviderMergeViewerItem(getComparison(),
+ referenceChange, null, null, eObject, getSide(), getAdapterFactory());
+ default:
+ throw new IllegalStateException();
+ }
+ }
+ }
+
+ /**
+ * Returns a list of those of the given diffs that are displayed in a group as provided by the given group
+ * provider and satisfy the given predicate.
+ *
+ * @param unfilteredDiffs
+ * the unfiltered diffs
+ * @param predicate
+ * a filter predicate; a {@code null} predicate will be satisfied by any diff
+ * @param groupProvider
+ * the active group provider
+ * @return a list of the filtered diffs
+ */
+ protected List<? extends Diff> filteredDiffs(Iterable<? extends Diff> unfilteredDiffs,
+ Predicate<? super EObject> predicate, IDifferenceGroupProvider groupProvider) {
+ return Lists.newArrayList(filter(unfilteredDiffs, visibleInMergeViewer(predicate, groupProvider)));
+ }
+
+ protected Predicate<Diff> visibleInMergeViewer(final Predicate<? super EObject> predicate,
+ final IDifferenceGroupProvider groupProvider) {
+ if (predicate == null) {
+ return Predicates.alwaysTrue();
+ }
+
+ return new Predicate<Diff>() {
+ public boolean apply(Diff diff) {
+ return MergeViewerUtil.isVisibleInMergeViewer(diff, groupProvider, predicate);
+ }
+ };
+ }
+
+ public static class Container extends ContentProviderMergeViewerItem implements IMergeViewerItem.Container {
+
+ /**
+ *
+ */
+ private static final IMergeViewerItem[] NO_ITEMS_ARR = new IMergeViewerItem[0];
+
+ /**
+ * @param comparison
+ * @param diff
+ * @param left
+ * @param right
+ * @param ancestor
+ */
+ public Container(Comparison comparison, Diff diff, Object left, Object right, Object ancestor,
+ MergeViewerSide side, AdapterFactory adapterFactory) {
+ super(comparison, diff, left, right, ancestor, side, adapterFactory);
+ }
+
+ /**
+ * @param fComparison
+ * @param referenceChange
+ * @param parentMatch
+ * @param fSide
+ * @param fAdapterFactory
+ */
+ public Container(Comparison comparison, Diff diff, Match match, MergeViewerSide side,
+ AdapterFactory adapterFactory) {
+ super(comparison, diff, match, side, adapterFactory);
+ }
+
+ /**
+ * @return the noItemsArr
+ */
+ public static IMergeViewerItem[] getNoItemsArr() {
+ return NO_ITEMS_ARR;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.emf.compare.rcp.ui.MergeViewerItem.item.impl.AbstractMergeViewerItem#getParent()
+ */
+ @Override
+ public IMergeViewerItem.Container getParent() {
+ IMergeViewerItem.Container ret = null;
+
+ if (getDiff() instanceof ResourceAttachmentChange) {
+ ret = createBasicContainer((ResourceAttachmentChange)getDiff());
+ } else {
+ Object sideValue = getBestSideValue();
+ ITreeItemContentProvider treeItemContentProvider = (ITreeItemContentProvider)getAdapterFactory()
+ .adapt(sideValue, ITreeItemContentProvider.class);
+
+ Object parent = treeItemContentProvider != null ? treeItemContentProvider.getParent(sideValue)
+ : null;
+ if (parent instanceof EObject) {
+ ret = createBasicContainer((EObject)parent);
+ } else if (parent instanceof Resource) {
+ ret = getParent((Resource)parent);
+ } else if (sideValue instanceof NotLoadedFragmentMatch) {
+ ret = getParent((NotLoadedFragmentMatch)sideValue);
+ }
+ }
+ return ret;
+ }
+
+ /**
+ * Get the parent (as MergeViewerItem) of the MergeViewerItem in case the MergeViewerItem is a
+ * {@link org.eclipse.emf.ecore.resource.Resource}.
+ *
+ * @param resource
+ * the Resource for which we want the parent (as MergeViewerItem)
+ * @return the parent (a MergeViewerItem) of the given element.
+ */
+ private IMergeViewerItem.Container getParent(Resource resource) {
+ final IMergeViewerItem.Container parent;
+ URI uri = resource.getURI();
+ if (ResourceUIUtil.isFragment(uri)) {
+ final Object object = getBestSideValue();
+ final Match matchOfValue = getComparison().getMatch((EObject)object);
+ final NotLoadedFragmentMatch notLoadedFragmentMatch = new NotLoadedFragmentMatch(
+ matchOfValue);
+ parent = getMergeViewerItemFactory().createContentProviderMergeViewerItem(getComparison(),
+ getDiff(), notLoadedFragmentMatch, notLoadedFragmentMatch, notLoadedFragmentMatch,
+ getSide(), getAdapterFactory());
+ } else {
+ parent = null;
+ }
+ return parent;
+
+ }
+
+ /**
+ * Get the parent of the MergeViewerItem in case the MergeViewerItem is a
+ * {@link org.eclipse.emf.compare.match.impl.NotLoadedFragmentMatch}.
+ *
+ * @param nlfm
+ * the NotLoadedFragmentMatch for which we want the parent (as MergeViewerItem)
+ * @return the parent (a MergeViewerItem) of the given element.
+ */
+ private IMergeViewerItem.Container getParent(NotLoadedFragmentMatch nlfm) {
+ IMergeViewerItem.Container parent = null;
+ final Collection<? extends Match> children = nlfm.getChildren();
+ for (Match match : children) {
+ URI uri = ResourceUIUtil.getDataURI(match, getSide());
+ if (uri != null) {
+ IGraphView<URI> graph = ResourceUIUtil.getResourcesURIGraph();
+ URI parentData = graph.getParentData(uri);
+ ResourceSet rs = ResourceUIUtil.getDataResourceSet(match, getSide());
+ Resource resourceParent = ResourceUIUtil.getParent(rs, uri);
+ while (resourceParent == null && parentData != null) {
+ resourceParent = ResourceUIUtil.getParent(rs, parentData.trimFragment());
+ parentData = graph.getParentData(parentData.trimFragment());
+ }
+ if (resourceParent != null && parentData != null) {
+ EObject eObjectParent = resourceParent.getEObject(parentData.fragment());
+ if (eObjectParent != null) {
+ parent = createBasicContainer(eObjectParent);
+ break;
+ }
+ } else {
+ parent = createNotLoadedFragmentContainer(rs, uri);
+ if (parent != null) {
+ break;
+ }
+ }
+ }
+ }
+ return parent;
+ }
+
+ /**
+ * Create an IMergeViewerItem.Container that holds NotLoadedFragmentMatches.
+ *
+ * @param uri
+ * the URI of the Match element for which we want to create a container.
+ * @return an IMergeViewerItem.Container.
+ */
+ private IMergeViewerItem.Container createNotLoadedFragmentContainer(ResourceSet rs, URI uri) {
+ final IMergeViewerItem.Container parent;
+ URI parentURI = ResourceUIUtil.getParentResourceURI(rs, uri);
+ URI rootResourceURI = ResourceUIUtil.getRootResourceURI(uri);
+ if (parentURI == null) {
+ parentURI = rootResourceURI;
+ }
+ Collection<Match> notLoadedFragmentMatches = Lists.newArrayList();
+ Collection<Match> rootMatches = getComparison().getMatches();
+ Collection<URI> uris = ResourceUIUtil.getDataURIs(rootMatches, getSide());
+ for (Match rootMatch : rootMatches) {
+ URI rootMatchDataURI = ResourceUIUtil.getDataURI(rootMatch, getSide());
+ if (!rootResourceURI.equals(rootMatchDataURI) && !parentURI.equals(rootMatchDataURI)
+ && ResourceUIUtil.isChildOf(rootMatchDataURI, ImmutableSet.of(parentURI))
+ && !ResourceUIUtil.isChildOf(rootMatchDataURI, uris)) {
+ notLoadedFragmentMatches.add(new NotLoadedFragmentMatch(rootMatch));
+ }
+ }
+ if (notLoadedFragmentMatches.size() > 1) {
+ final NotLoadedFragmentMatch notLoadedFragmentMatch = new NotLoadedFragmentMatch(
+ notLoadedFragmentMatches);
+ parent = getMergeViewerItemFactory().createContentProviderMergeViewerItem(getComparison(),
+ getDiff(), notLoadedFragmentMatch, notLoadedFragmentMatch, notLoadedFragmentMatch,
+ getSide(), getAdapterFactory());
+ } else {
+ parent = null;
+ }
+ return parent;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.emf.compare.rcp.ui.mergeviewer.item.IMergeViewerItem.Container#hasChildren(IDifferenceGroupProvider,
+ * Predicate)
+ */
+ public boolean hasChildren(IDifferenceGroupProvider groupProvider,
+ Predicate<? super EObject> predicate) {
+ if (getLeft() instanceof NotLoadedFragmentMatch) {
+ final NotLoadedFragmentMatch notLoadedFragmentMatch = (NotLoadedFragmentMatch)getLeft();
+ return !notLoadedFragmentMatch.getChildren().isEmpty();
+ }
+
+ final Object sideValue = getSideValue(getSide());
+ final List<Object> children = getChildrenFromContentProvider(sideValue);
+ final List<Object> otherSideChildren = getChildrenFromContentProvider(getSide().opposite());
+
+ // collect and filter diffs
+ List<? extends Diff> differences = collectDifferences(otherSideChildren);
+ differences = Lists.newArrayList(filter(differences, CONTAINMENT_REFERENCE_CHANGE));
+ differences = filteredDiffs(differences, predicate, groupProvider);
+
+ if (hasChildren(differences, children)) {
+ return true;
+ }
+
+ final EObject bestSideValue = (EObject)getBestSideValue();
+ final Match match = getComparison().getMatch(bestSideValue);
+
+ return hasNotLoadedFragmentsItems(match);
+ }
+
+ private boolean hasChildren(Iterable<? extends Diff> differences, List<Object> children) {
+ if (yieldsMergeViewerItem(children)) {
+ return true;
+ }
+
+ if (getSide() != MergeViewerSide.ANCESTOR) {
+ return yieldsInsertionPoint(differences);
+ }
+
+ return true;
+ }
+
+ private boolean hasNotLoadedFragmentsItems(Match match) {
+ Collection<Match> childrenMatches = ResourceUIUtil
+ .getChildrenMatchWithNotLoadedParent(getComparison(), match, getSide());
+ return !childrenMatches.isEmpty();
+ }
+
+ @Override
+ public IMergeViewerItem.Container cloneAsOpposite() {
+ return getMergeViewerItemFactory().createContentProviderMergeViewerItem(getComparison(),
+ getDiff(), getLeft(), getRight(), getAncestor(), getSide(), getAdapterFactory());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.emf.compare.rcp.ui.mergeviewer.item.IMergeViewerItem.Container#getChildren(IDifferenceGroupProvider,
+ * Predicate)
+ */
+ public IMergeViewerItem[] getChildren(IDifferenceGroupProvider group,
+ Predicate<? super EObject> predicate) {
+
+ final List<IMergeViewerItem> ret = newArrayList();
+
+ if (this.getLeft() instanceof NotLoadedFragmentMatch) {
+ ret.addAll(getChildren((NotLoadedFragmentMatch)this.getLeft()));
+ } else {
+ final List<Object> children = getChildrenFromContentProvider(getSide());
+ final List<Object> otherSideChildren = getChildrenFromContentProvider(getSide().opposite());
+
+ // collect and filter diffs
+ List<? extends Diff> differences = collectDifferences(otherSideChildren);
+ differences = Lists.newArrayList(filter(differences, CONTAINMENT_REFERENCE_CHANGE));
+ differences = filteredDiffs(differences, predicate, group);
+
+ ret.addAll(getChildren(differences, children));
+
+ // Add not loaded fragment match if needed
+ final EObject bestSideValue = (EObject)getBestSideValue();
+ final Match match = getComparison().getMatch(bestSideValue);
+ ret.addAll(getNotLoadedFragmentsItems(match));
+ }
+ return ret.toArray(NO_ITEMS_ARR);
+ }
+
+ /**
+ * Collect the differences of the given objects.
+ *
+ * @param objects
+ * The objects whose differences will be returned
+ * @return An {@link Iterable} over all collected Differences.
+ */
+ private List<Diff> collectDifferences(Iterable<Object> objects) {
+ Iterable<Diff> differences = ImmutableList.of();
+ for (Object object : objects) {
+ if (EObject.class.isInstance(object)) {
+ EList<Diff> objectDifferences = getComparison()
+ .getDifferences(EObject.class.cast(object));
+ differences = Iterables.concat(differences, objectDifferences);
+ }
+ }
+ return Lists.newArrayList(differences);
+ }
+
+ /**
+ * Get the children of the MergeViewerItem in case the MergeViewerItem is a
+ * {@link org.eclipse.emf.compare.match.impl.NotLoadedFragmentMatch}.
+ *
+ * @param nlfm
+ * the NotLoadedFragmentMatch for which we want the children (as MergeViewerItems)
+ * @return the children (a list of MergeViewerItems) of the given element.
+ */
+ private List<IMergeViewerItem> getChildren(NotLoadedFragmentMatch nlfm) {
+ final List<IMergeViewerItem> ret = newArrayList();
+ final Collection<Match> matches = nlfm.getChildren();
+ for (Match match : matches) {
+ final IMergeViewerItem.Container container;
+ if (match instanceof NotLoadedFragmentMatch) {
+ container = getMergeViewerItemFactory().createContentProviderMergeViewerItem(
+ getComparison(), getDiff(), match, match, match, getSide(), getAdapterFactory());
+ } else {
+ container = getMergeViewerItemFactory().createContentProviderMergeViewerItem(
+ getComparison(), getDiff(), match.getLeft(), match.getRight(), match.getOrigin(),
+ getSide(), getAdapterFactory());
+ }
+ ret.add(container);
+ }
+ return ret;
+ }
+
+ /**
+ * Return potential NotLoadedFragment children items (as MergeViewerItem) of the MergeViewerItem in
+ * case the MergeViewerItem is a {@link org.eclipse.emf.compare.match.Match}.
+ *
+ * @param match
+ * the Match for which we want the potential NotLoadedFragment children items (as
+ * MergeViewerItems)
+ * @return the NotLoadedFragment children items (a list of MergeViewerItems) of the given element.
+ */
+ private List<IMergeViewerItem> getNotLoadedFragmentsItems(Match match) {
+ final List<IMergeViewerItem> ret = newArrayList();
+ final Collection<Match> childrenMatches = ResourceUIUtil
+ .getChildrenMatchWithNotLoadedParent(getComparison(), match, getSide());
+ if (childrenMatches.size() > 0) {
+ boolean setNames = childrenMatches.size() > 1;
+ for (Match child : childrenMatches) {
+ NotLoadedFragmentMatch notLoadedFragmentMatch = new NotLoadedFragmentMatch(child);
+ if (setNames) {
+ notLoadedFragmentMatch
+ .setName(ResourceUIUtil.getResourceName(notLoadedFragmentMatch));
+ }
+ IMergeViewerItem.Container notLoadedFragmentItem = getMergeViewerItemFactory()
+ .createContentProviderMergeViewerItem(getComparison(), null,
+ notLoadedFragmentMatch, notLoadedFragmentMatch, notLoadedFragmentMatch,
+ getSide(), getAdapterFactory());
+ ret.add(notLoadedFragmentItem);
+ }
+ }
+ return ret;
+ }
+
+ private List<IMergeViewerItem> getChildren(final List<? extends Diff> differences,
+ Collection<Object> children) {
+ final List<IMergeViewerItem> ret = Lists.newArrayList();
+
+ final List<IMergeViewerItem> mergeViewerItem = createMergeViewerItemFrom(children);
+ if (getSide() != MergeViewerSide.ANCESTOR) {
+ ret.addAll(createInsertionPoints(getComparison(), mergeViewerItem, differences));
+ } else {
+ ret.addAll(mergeViewerItem);
+ }
+ return ret;
+ }
+ }
+}
diff --git a/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/item/ContentProviderMergeViewerItemFactory.java b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/item/ContentProviderMergeViewerItemFactory.java
new file mode 100644
index 000000000..a819361e8
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/item/ContentProviderMergeViewerItemFactory.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EclipseSource Muenchen GmbH 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:
+ * Stefan Dirix - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.diagram.ide.ui.papyrus.contentmergeviewer.item;
+
+import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.compare.Comparison;
+import org.eclipse.emf.compare.Diff;
+import org.eclipse.emf.compare.Match;
+import org.eclipse.emf.compare.rcp.ui.mergeviewer.IMergeViewer.MergeViewerSide;
+import org.eclipse.emf.compare.rcp.ui.mergeviewer.item.IMergeViewerItem;
+
+/**
+ * Factory for {@link ContentProviderMergeViewerItem.Container}.
+ *
+ * @author Stefan Dirix
+ */
+public class ContentProviderMergeViewerItemFactory {
+
+ /**
+ * Creates and returns a new {@link ContentProviderMergeViewerItem.Container} instantiated with the given
+ * parameters.
+ *
+ * @param comparison
+ * the {@link Comparison}
+ * @param diff
+ * the {@link Diff}
+ * @param left
+ * the left object
+ * @param right
+ * the right object
+ * @param ancestor
+ * the ancestor object
+ * @param side
+ * the {@link MergeViewerSide}
+ * @param adapterFactory
+ * the {@link AdapterFactory}
+ * @return a new instance of {@link ContentProviderMergeViewerItem.Container}.
+ */
+ public IMergeViewerItem.Container createContentProviderMergeViewerItem(Comparison comparison, Diff diff,
+ Object left, Object right, Object ancestor, MergeViewerSide side, AdapterFactory adapterFactory) {
+ return new ContentProviderMergeViewerItem.Container(comparison, diff, left, right, ancestor, side,
+ adapterFactory);
+ }
+
+ /**
+ * Creates and returns a new {@link ContentProviderMergeViewerItem.Container} created with the given
+ * parameters.
+ *
+ * @param comparison
+ * the {@link Comparison}
+ * @param diff
+ * the {@link Diff}
+ * @param match
+ * the {@link Match}
+ * @param side
+ * the {@link MergeViewerSide}
+ * @param adapterFactory
+ * the {@link AdapterFactory}
+ * @return a new instance of {@link ContentProviderMergeViewerItem.Container}.
+ */
+ public IMergeViewerItem.Container createContentProviderMergeViewerItem(Comparison comparison, Diff diff,
+ Match match, MergeViewerSide side, AdapterFactory adapterFactory) {
+ return new ContentProviderMergeViewerItem.Container(comparison, diff, match, side, adapterFactory);
+ }
+}
diff --git a/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/item/MergeViewerItemConverter.java b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/item/MergeViewerItemConverter.java
new file mode 100644
index 000000000..8abc6e4b6
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/item/MergeViewerItemConverter.java
@@ -0,0 +1,120 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EclipseSource Muenchen GmbH 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:
+ * Stefan Dirix - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.diagram.ide.ui.papyrus.contentmergeviewer.item;
+
+import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.compare.Comparison;
+import org.eclipse.emf.compare.rcp.ui.mergeviewer.item.IMergeViewerItem;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.papyrus.emf.facet.custom.metamodel.v0_2_0.internal.treeproxy.EObjectTreeElement;
+import org.eclipse.papyrus.emf.facet.custom.metamodel.v0_2_0.internal.treeproxy.TreeproxyFactory;
+
+/**
+ * Converts MergeViewerItems to PapyrusMergeViewerItems.
+ *
+ * @author Stefan Dirix
+ */
+public class MergeViewerItemConverter {
+
+ /**
+ * The {@link AdapterFactory} which is used when creating new {@link IMergeViewerItem}s.
+ */
+ private AdapterFactory adapterFactory;
+
+ /**
+ * The {@link Comparison} which is used when creating new {@link IMergeViewerItem}s.
+ */
+ private Comparison comparison;
+
+ /**
+ * Constructor.
+ *
+ * @param factory
+ * the {@link AdapterFactory} which is used when creating new {@link IMergeViewerItem}s.
+ * @param comparison
+ * the {@link Comparison} which is used when creating new {@link IMergeViewerItem}s.
+ */
+ public MergeViewerItemConverter(AdapterFactory factory, Comparison comparison) {
+ this.adapterFactory = factory;
+ this.comparison = comparison;
+ }
+
+ /**
+ * Checks whether the given {@code item} needs conversion and executes the conversion if needed.
+ *
+ * @param item
+ * the {@link IMergeViewerItem} to convert.
+ * @return The converted {@link IMergeViewerItem} if the conversion was needed and allowed, the original
+ * {@link IMergeViewerItem} otherwise.
+ */
+ public IMergeViewerItem convert(IMergeViewerItem item) {
+ if (isConversionNeeded(item) && isConversionAllowed(item)) {
+ return doConvert(item);
+ }
+ return item;
+ }
+
+ /**
+ * Determines whether the conversion is allowed for this {@code item}.
+ *
+ * @param item
+ * the {@link IMergeViewerItem}.
+ * @return {@code true} if conversion is allowed, {@code false} otherwise.
+ */
+ protected boolean isConversionAllowed(IMergeViewerItem item) {
+ // Do not convert items regarding resources
+ return !isResourceItem(item);
+ }
+
+ /**
+ * Checks whether any side of the {@link IMergeViewerItem} is of kind '{@link Resource}'.
+ *
+ * @param item
+ * the {@link IMergeViewerItem} to check.
+ * @return {@code true} if any side is of kind '{@link Resource}', {@code false} otherwise.
+ */
+ private boolean isResourceItem(IMergeViewerItem item) {
+ return Resource.class.isInstance(item.getLeft()) || Resource.class.isInstance(item.getRight())
+ || Resource.class.isInstance(item.getAncestor());
+ }
+
+ /**
+ * Determines whether a conversion is needed for this {@code item}.
+ *
+ * @param item
+ * the {@link IMergeViewerItem}.
+ * @return {@code true} if a conversion is needed, {@code false} otherwise.
+ */
+ protected boolean isConversionNeeded(IMergeViewerItem item) {
+ return !ContentProviderMergeViewerItem.class.isInstance(item);
+ }
+
+ /**
+ * Converts the given {@code item}.
+ *
+ * @param item
+ * The {@link IMergeViewerItem}.
+ * @return The converted {@link IMergeViewerItem}.
+ */
+ protected IMergeViewerItem doConvert(IMergeViewerItem item) {
+ final Object value = item.getSideValue(item.getSide());
+ if (EObject.class.isInstance(value)) {
+ final EObjectTreeElement treeElement = TreeproxyFactory.eINSTANCE.createEObjectTreeElement();
+ treeElement.setEObject(EObject.class.cast(value));
+ return new PapyrusContentProviderMergeViewerItem(comparison, item.getDiff(), item.getLeft(),
+ item.getRight(), item.getAncestor(), item.getSide(), adapterFactory, treeElement, null);
+ }
+
+ return new ContentProviderMergeViewerItem.Container(comparison, item.getDiff(), item.getLeft(),
+ item.getRight(), item.getAncestor(), item.getSide(), adapterFactory);
+ }
+}
diff --git a/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/item/PapyrusContentProviderMergeViewerItem.java b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/item/PapyrusContentProviderMergeViewerItem.java
new file mode 100644
index 000000000..43f114046
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/item/PapyrusContentProviderMergeViewerItem.java
@@ -0,0 +1,193 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EclipseSource Muenchen GmbH 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:
+ * Stefan Dirix - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.diagram.ide.ui.papyrus.contentmergeviewer.item;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.compare.Comparison;
+import org.eclipse.emf.compare.Diff;
+import org.eclipse.emf.compare.Match;
+import org.eclipse.emf.compare.diagram.ide.ui.papyrus.contentmergeviewer.facet.PapyrusFacetContentProviderWrapper;
+import org.eclipse.emf.compare.rcp.ui.mergeviewer.IMergeViewer.MergeViewerSide;
+import org.eclipse.emf.compare.rcp.ui.mergeviewer.item.IMergeViewerItem;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.papyrus.emf.facet.custom.metamodel.v0_2_0.internal.treeproxy.EObjectTreeElement;
+import org.eclipse.papyrus.emf.facet.custom.metamodel.v0_2_0.internal.treeproxy.TreeElement;
+
+/**
+ * This class keeps track of the related {@link TreeElement}s and handles the raw ouput of the
+ * {@link PapyrusFacetContentProviderWrapper}.
+ *
+ * @author Stefan Dirix
+ */
+public class PapyrusContentProviderMergeViewerItem extends ContentProviderMergeViewerItem.Container {
+
+ /**
+ * The linked {@link TreeElement}.
+ */
+ protected EObjectTreeElement treeElement;
+
+ /**
+ * The parent of this item.
+ */
+ protected IMergeViewerItem.Container parent;
+
+ /**
+ * Mapping between EObjects and their {@link TreeElement}s.
+ */
+ private Map<EObject, EObjectTreeElement> childrenTreeElements;
+
+ /**
+ * Factory responsible for creating new {@link PapyrusContentProviderMergeViewerItem}s.
+ */
+ private ContentProviderMergeViewerItemFactory mergeViewerItemFactory;
+
+ /**
+ * Constructor.
+ *
+ * @param comparison
+ * the {@link Comparison}.
+ * @param diff
+ * the {@link Diff}.
+ * @param left
+ * the left object
+ * @param right
+ * the right object
+ * @param ancestor
+ * the ancestor object
+ * @param side
+ * the {@link MergeViewerSide}
+ * @param adapterFactory
+ * the {@link adapterFactory}
+ * @param treeElement
+ * the linked {@link EObjectTreeElement}.
+ */
+ // CHECKSTYLE:OFF Many parameters needed because of base class
+ public PapyrusContentProviderMergeViewerItem(Comparison comparison, Diff diff, Object left, Object right,
+ Object ancestor, MergeViewerSide side, AdapterFactory adapterFactory,
+ EObjectTreeElement treeElement, IMergeViewerItem.Container parent) {
+ // CHECKSTYLE:ON
+ super(comparison, diff, left, right, ancestor, side, adapterFactory);
+ this.treeElement = treeElement;
+ childrenTreeElements = new HashMap<EObject, EObjectTreeElement>();
+ mergeViewerItemFactory = new PapyrusContentProviderMergeViewerItemFactory(this);
+ this.parent = parent;
+ }
+
+ @Override
+ public ContentProviderMergeViewerItemFactory getMergeViewerItemFactory() {
+ return mergeViewerItemFactory;
+ }
+
+ @Override
+ protected List<Object> getChildrenFromContentProvider(Object object) {
+ final List<Object> children = super.getChildrenFromContentProvider(object);
+ final boolean thisSideChildren = treeElement != null && treeElement.getEObject() == object;
+ return unwrap(children, thisSideChildren);
+ }
+
+ @Override
+ public IMergeViewerItem.Container getParent() {
+ if (parent != null) {
+ return parent;
+ }
+ return super.getParent();
+ }
+
+ /**
+ * The Papyrus ModelExplorer tree consists of special Papyrus objects. To use them in EMFCompare they have
+ * to be unwrapped.
+ *
+ * @param children
+ * The children to unwrap
+ * @param thisSideChildren
+ * Indicates if these are children displayed as part of this side of the tree
+ * @return The collection of unwrapped objects.
+ */
+ private List<Object> unwrap(List<Object> children, boolean thisSideChildren) {
+ final List<Object> result = new ArrayList<Object>();
+ for (Object object : children) {
+ if (EObjectTreeElement.class.isInstance(object)) {
+ final EObjectTreeElement childTreeElement = EObjectTreeElement.class.cast(object);
+ result.add(childTreeElement.getEObject());
+ if (thisSideChildren) {
+ childTreeElement.setParent(treeElement);
+ }
+ childrenTreeElements.put(childTreeElement.getEObject(), childTreeElement);
+ } else {
+ result.add(object);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns the {@link TreeElement} for the value side.
+ *
+ * @return The {@link TreeElement} for the value side.
+ */
+ public TreeElement getTreeElement() {
+ return treeElement;
+ }
+
+ /**
+ * Factory for creating new {@link PapyrusContentProviderMergeViewerItem}s.
+ */
+ private class PapyrusContentProviderMergeViewerItemFactory extends ContentProviderMergeViewerItemFactory {
+
+ /**
+ * the parent.
+ */
+ private IMergeViewerItem.Container factoryParent;
+
+ /**
+ * Constructor.
+ *
+ * @param parent
+ * the parent.
+ */
+ PapyrusContentProviderMergeViewerItemFactory(IMergeViewerItem.Container parent) {
+ this.factoryParent = parent;
+ }
+
+ @Override
+ public IMergeViewerItem.Container createContentProviderMergeViewerItem(Comparison comparison,
+ Diff diff, Match match, MergeViewerSide side, AdapterFactory adapterFactory) {
+ return createContentProviderMergeViewerItem(comparison, diff, match.getLeft(), match.getRight(),
+ match.getOrigin(), side, adapterFactory);
+ }
+
+ @Override
+ public IMergeViewerItem.Container createContentProviderMergeViewerItem(Comparison comparison,
+ Diff diff, Object left, Object right, Object ancestor, MergeViewerSide side,
+ AdapterFactory adapterFactory) {
+ final EObjectTreeElement childTreeElement;
+ switch (side) {
+ case RIGHT:
+ childTreeElement = childrenTreeElements.get(right);
+ break;
+ case ANCESTOR:
+ childTreeElement = childrenTreeElements.get(ancestor);
+ break;
+ case LEFT:
+ default:
+ childTreeElement = childrenTreeElements.get(left);
+ }
+ return new PapyrusContentProviderMergeViewerItem(comparison, diff, left, right, ancestor, side,
+ adapterFactory, childTreeElement, factoryParent);
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/provider/PapyrusTreeContentMergeViewerItemContentProvider.java b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/provider/PapyrusTreeContentMergeViewerItemContentProvider.java
new file mode 100644
index 000000000..f52bfef22
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/provider/PapyrusTreeContentMergeViewerItemContentProvider.java
@@ -0,0 +1,252 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EclipseSource Muenchen GmbH 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:
+ * Stefan Dirix - initial API and implementation
+ * Philip Langer - filter diagrams and refactorings
+ *******************************************************************************/
+package org.eclipse.emf.compare.diagram.ide.ui.papyrus.contentmergeviewer.provider;
+
+import static com.google.common.base.Predicates.instanceOf;
+import static com.google.common.collect.Iterables.any;
+import static com.google.common.collect.Iterables.filter;
+import static com.google.common.collect.Iterables.toArray;
+import static com.google.common.collect.Iterables.transform;
+import static java.util.Arrays.asList;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSet.Builder;
+
+import java.util.Set;
+
+import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.compare.Diff;
+import org.eclipse.emf.compare.Match;
+import org.eclipse.emf.compare.diagram.ide.ui.papyrus.contentmergeviewer.facet.PapyrusFacetContentProviderWrapperAdapterFactory;
+import org.eclipse.emf.compare.diagram.ide.ui.papyrus.contentmergeviewer.item.MergeViewerItemConverter;
+import org.eclipse.emf.compare.ide.ui.internal.configuration.EMFCompareConfiguration;
+import org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.tree.provider.TreeContentMergeViewerItemContentProvider;
+import org.eclipse.emf.compare.rcp.ui.contentmergeviewer.accessor.ICompareAccessor;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.filters.StructureMergeViewerFilter;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.StructureMergeViewerGrouper;
+import org.eclipse.emf.compare.rcp.ui.internal.util.MergeViewerUtil;
+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.edit.provider.ComposedAdapterFactory;
+import org.eclipse.emf.edit.provider.IDisposable;
+import org.eclipse.gmf.runtime.notation.Diagram;
+
+/**
+ * The content provider for the {@link PyprusTreeContentMergeViewer}.
+ * <p>
+ * Note that this content provider filters {@link Diagram diagrams}, as they shouldn't show up in the content
+ * merge viewer after double-clicking a UML model element or a diff of a model element.
+ * </p>
+ *
+ * @author Stefan Dirix
+ */
+@SuppressWarnings("restriction")
+public class PapyrusTreeContentMergeViewerItemContentProvider extends TreeContentMergeViewerItemContentProvider {
+
+ /** Filters Diagram elements for inputs of type MergeViewerItem, Match, and Object. */
+ private static final Predicate<Object> DIAGRAM_FILTER = new Predicate<Object>() {
+ public boolean apply(Object input) {
+ if (input instanceof IMergeViewerItem) {
+ final IMergeViewerItem item = (IMergeViewerItem)input;
+ return containsNoDiagrams(asSet(item.getLeft(), item.getRight(), item.getAncestor()));
+ } else if (input instanceof Match) {
+ final Match match = (Match)input;
+ return containsNoDiagrams(asSet(match.getLeft(), match.getRight(), match.getOrigin()));
+ } else if (input instanceof Diagram) {
+ return true;
+ }
+ return false;
+ }
+ };
+
+ /**
+ * The Compare Configuration.
+ */
+ private EMFCompareConfiguration compareConfiguration;
+
+ /**
+ * The Converter to replace the 'standard' {@link IMergeViewerItem}s with the specialized ones of Papyrus.
+ */
+ private MergeViewerItemConverter converter;
+
+ /**
+ * The {@link AdapterFactory} for the {@link IMergeViewerItem}s.
+ */
+ private AdapterFactory itemAdapterFactory;
+
+ /**
+ * Constructor.
+ *
+ * @param adapterFactory
+ * the {@link AdapterFactory}.
+ * @param compareConfiguration
+ * the {@link EMFCompareConfiguration}.
+ * @param groupProvider
+ * the {@link IDifferenceGroupProvider}.
+ * @param predicate
+ * the {@link Predicate}.
+ */
+ public PapyrusTreeContentMergeViewerItemContentProvider(AdapterFactory adapterFactory,
+ EMFCompareConfiguration compareConfiguration, IDifferenceGroupProvider groupProvider,
+ Predicate<? super EObject> predicate) {
+ super(adapterFactory, groupProvider, predicate);
+ this.adapterFactory = adapterFactory;
+ this.compareConfiguration = compareConfiguration;
+ this.itemAdapterFactory = new PapyrusFacetContentProviderWrapperAdapterFactory();
+ this.converter = new MergeViewerItemConverter(
+ new ComposedAdapterFactory(new AdapterFactory[] {itemAdapterFactory, adapterFactory, }),
+ compareConfiguration.getComparison());
+ }
+
+ @Override
+ public Object[] getElements(Object object) {
+ if (object instanceof ICompareAccessor) {
+ final ICompareAccessor accessor = (ICompareAccessor)object;
+ return toArray(convert(filtered(accessor.getItems())), Object.class);
+ }
+ return super.getElements(object);
+ }
+
+ /**
+ * {@inheritDoc} Note that {@link Diagram diagrams} will be filtered.
+ */
+ @Override
+ public Object[] getChildren(Object object) {
+ return toArray(filter(asList(super.getChildren(object)), DIAGRAM_FILTER), Object.class);
+ }
+
+ /**
+ * Convert {@link IMergeViewerItem} s to the specialized ones of Papyrus.
+ *
+ * @param items
+ * The {@link IMergeViewerItem}s which shall be converted.
+ * @return An {@link Iterable} over the converted {@link IMergeViewerItem}s.
+ */
+ private Iterable<? extends IMergeViewerItem> convert(Iterable<? extends IMergeViewerItem> items) {
+ return transform(items, new Function<IMergeViewerItem, IMergeViewerItem>() {
+ public IMergeViewerItem apply(IMergeViewerItem input) {
+ return converter.convert(input);
+ }
+ });
+ }
+
+ /**
+ * Skips {@link IMergeViewerItem}s whose diffs shall not be displayed.
+ *
+ * @param items
+ * The {@link IMergeViewerItem}s to filter.
+ * @return An {@link Iterable} over the {@link IMergeViewerItem}s which shall be displayed.
+ */
+ private Iterable<? extends IMergeViewerItem> filtered(Iterable<? extends IMergeViewerItem> items) {
+ final StructureMergeViewerGrouper grouper = compareConfiguration.getStructureMergeViewerGrouper();
+ final StructureMergeViewerFilter filter = compareConfiguration.getStructureMergeViewerFilter();
+ final IDifferenceGroupProvider provider = grouper.getProvider();
+ final Predicate<? super EObject> aggregatedPredicate = filter.getAggregatedPredicate();
+ return filter(items, new Predicate<IMergeViewerItem>() {
+ public boolean apply(IMergeViewerItem item) {
+ final Match match = getMatch(item.getLeft(), item.getRight(), item.getAncestor());
+ if (match == null) {
+ // no match, but we can still show the element in the PCMV
+ return true;
+ }
+ if (!DIAGRAM_FILTER.apply(match)) {
+ return false;
+ }
+ return any(match.getAllDifferences(), new Predicate<Diff>() {
+ public boolean apply(Diff diff) {
+ return MergeViewerUtil.isVisibleInMergeViewer(diff, provider, aggregatedPredicate);
+ }
+ });
+ }
+ });
+ }
+
+ /**
+ * Determines the {@link Match} for the given object triple.
+ *
+ * @param left
+ * the left object.
+ * @param right
+ * the right object.
+ * @param origin
+ * the origin object.
+ * @return The determined {@link Match}, {@code null} otherwise.
+ */
+ private Match getMatch(Object left, Object right, Object origin) {
+ Match match = getMatch(left);
+ if (match != null) {
+ return match;
+ }
+ match = getMatch(right);
+ if (match != null) {
+ return match;
+ }
+ return getMatch(origin);
+ }
+
+ /**
+ * Determines the {@link Match} for the given object.
+ *
+ * @param object
+ * The object for which the match is to be determined.
+ * @return The determined {@link Match}, {@code null} otherwise.
+ */
+ private Match getMatch(Object object) {
+ if (object == null) {
+ return null;
+ }
+ for (Match match : compareConfiguration.getComparison().getMatches()) {
+ if (object == match.getLeft() || object == match.getRight() || object == match.getOrigin()) {
+ return match;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Creates a null-safe set of the specified objects.
+ *
+ * @param objects
+ * To create set of.
+ * @return The created set. Null values are ignored.
+ */
+ private static Set<Object> asSet(Object... objects) {
+ Builder<Object> builder = ImmutableSet.builder();
+ for (Object object : objects) {
+ if (object != null) {
+ builder.add(object);
+ }
+ }
+ return builder.build();
+ }
+
+ /**
+ * Specifies whether the given objects contain <em>no</em> instances of Diagrams.
+ *
+ * @param objects
+ * The objects to check.
+ * @return <code>true</code> if no diagram is contained, <code>false</code> otherwise.
+ */
+ private static boolean containsNoDiagrams(Set<Object> objects) {
+ return !any(objects, instanceOf(Diagram.class));
+ }
+
+ @Override
+ public void dispose() {
+ if (IDisposable.class.isInstance(itemAdapterFactory)) {
+ IDisposable.class.cast(itemAdapterFactory).dispose();
+ }
+ }
+}
diff --git a/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/provider/PapyrusTreeContentMergeViewerItemLabelProvider.java b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/provider/PapyrusTreeContentMergeViewerItemLabelProvider.java
new file mode 100644
index 000000000..f6d755c1f
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/contentmergeviewer/provider/PapyrusTreeContentMergeViewerItemLabelProvider.java
@@ -0,0 +1,152 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EclipseSource Muenchen GmbH 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:
+ * Stefan Dirix - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.diagram.ide.ui.papyrus.contentmergeviewer.provider;
+
+import java.util.ResourceBundle;
+
+import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.compare.diagram.ide.ui.papyrus.contentmergeviewer.item.ContentProviderMergeViewerItem;
+import org.eclipse.emf.compare.diagram.ide.ui.papyrus.contentmergeviewer.item.PapyrusContentProviderMergeViewerItem;
+import org.eclipse.emf.compare.diagram.ide.ui.papyrus.internal.CompareDiagramIDEUIPapyrusPlugin;
+import org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.tree.provider.TreeContentMergeViewerItemLabelProvider;
+import org.eclipse.emf.compare.rcp.ui.mergeviewer.IMergeViewer.MergeViewerSide;
+import org.eclipse.emf.compare.rcp.ui.mergeviewer.item.IMergeViewerItem;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.papyrus.emf.facet.custom.metamodel.v0_2_0.internal.treeproxy.TreeElement;
+import org.eclipse.papyrus.infra.gmfdiag.css.notation.CSSDiagram;
+import org.eclipse.papyrus.infra.services.labelprovider.service.LabelProviderService;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.uml2.uml.UMLPackage;
+
+/**
+ * The label provider for the {@link PyprusTreeContentMergeViewer}.
+ *
+ * @author Stefan Dirix
+ */
+@SuppressWarnings("restriction")
+public class PapyrusTreeContentMergeViewerItemLabelProvider extends TreeContentMergeViewerItemLabelProvider {
+ /**
+ * The {@link MergeViewerSide}.
+ */
+ private MergeViewerSide side;
+
+ /**
+ * Constructor.
+ *
+ * @param resourceBundle
+ * the {@link ResourceBundle}.
+ * @param adapterFactory
+ * the {@link AdapterFactory}.
+ * @param side
+ * the {@link MergeViewerSide}.
+ */
+ public PapyrusTreeContentMergeViewerItemLabelProvider(ResourceBundle resourceBundle,
+ AdapterFactory adapterFactory, MergeViewerSide side) {
+ super(resourceBundle, adapterFactory, side);
+ this.side = side;
+ }
+
+ @Override
+ public Image getImage(Object object) {
+ if (!ContentProviderMergeViewerItem.class.isInstance(object)) {
+ return super.getImage(object);
+ }
+
+ final Image image;
+ final IMergeViewerItem mergeViewerItem = IMergeViewerItem.class.cast(object);
+
+ // For all special cases fall back to parent to keep consistency
+ if (mergeViewerItem.isInsertionPoint()) {
+ image = super.getImage(object);
+ } else if (mergeViewerItem.getSideValue(side) == null
+ && mergeViewerItem.getSideValue(side.opposite()) instanceof Resource) {
+ image = super.getImage(mergeViewerItem.getSideValue(side.opposite()));
+ } else if (mergeViewerItem.getLeft() == null && mergeViewerItem.getRight() == null
+ && mergeViewerItem.getAncestor() instanceof Resource) {
+ image = super.getImage(mergeViewerItem.getAncestor());
+ } else {
+ final Object value = mergeViewerItem.getSideValue(side);
+ if (hasModelExplorerLabel(value)) {
+ final LabelProviderService labelProviderService = CompareDiagramIDEUIPapyrusPlugin
+ .getDefault().getLabelProviderService();
+ if (PapyrusContentProviderMergeViewerItem.class.isInstance(object)) {
+ final TreeElement treeElement = PapyrusContentProviderMergeViewerItem.class.cast(object)
+ .getTreeElement();
+ image = labelProviderService.getLabelProvider().getImage(treeElement);
+ } else {
+ image = labelProviderService.getLabelProvider().getImage(value);
+ }
+ } else {
+ image = super.getImage(object);
+ }
+ }
+ return image;
+ }
+
+ @Override
+ public String getText(Object object) {
+ if (!ContentProviderMergeViewerItem.class.isInstance(object)) {
+ return super.getText(object);
+ }
+
+ final String text;
+ final IMergeViewerItem mergeViewerItem = (IMergeViewerItem)object;
+ final Object value = mergeViewerItem.getSideValue(side);
+
+ // For all special cases fall back to parent to keep consistency
+ if (value instanceof EObject && ((EObject)value).eIsProxy()) {
+ text = super.getText(object);
+ } else if (mergeViewerItem.isInsertionPoint()) {
+ text = super.getText(object);
+ } else if (value == null && mergeViewerItem.getSideValue(side.opposite()) instanceof Resource) {
+ text = super.getText(object);
+ } else if (value == null && mergeViewerItem.getLeft() == null && mergeViewerItem.getRight() == null
+ && mergeViewerItem.getAncestor() instanceof Resource) {
+ text = super.getText(object);
+ } else {
+ if (hasModelExplorerLabel(value)) {
+ final LabelProviderService labelProviderService = CompareDiagramIDEUIPapyrusPlugin
+ .getDefault().getLabelProviderService();
+ if (PapyrusContentProviderMergeViewerItem.class.isInstance(object)) {
+ final TreeElement treeElement = PapyrusContentProviderMergeViewerItem.class.cast(object)
+ .getTreeElement();
+ text = labelProviderService.getLabelProvider().getText(treeElement);
+ } else {
+ text = labelProviderService.getLabelProvider().getText(value);
+ }
+ } else {
+ text = super.getText(object);
+ }
+ }
+ return text;
+ }
+
+ /**
+ * Determines if a given object has a label within the Papyrus ModelExplorer.
+ *
+ * @param object
+ * the object to check
+ * @return {@code true} if the {@code object} has a Papyrus ModelExplorer label, {@code false} otherwise.
+ */
+ protected boolean hasModelExplorerLabel(Object object) {
+ if (EObject.class.isInstance(object)) {
+ final EObject eObject = EObject.class.cast(object);
+ if (UMLPackage.class.isInstance(eObject.eClass().getEPackage())) {
+ return true;
+ }
+ if (CSSDiagram.class.isInstance(eObject)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/internal/CompareDiagramIDEUIPapyrusPlugin.java b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/internal/CompareDiagramIDEUIPapyrusPlugin.java
index aa0b7ae10..b986e8e0e 100644
--- a/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/internal/CompareDiagramIDEUIPapyrusPlugin.java
+++ b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/internal/CompareDiagramIDEUIPapyrusPlugin.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2015 Obeo.
+ * Copyright (c) 2015, 2016 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
@@ -7,9 +7,15 @@
*
* Contributors:
* Obeo - initial API and implementation
+ * Stefan Dirix - bug 487595
*******************************************************************************/
package org.eclipse.emf.compare.diagram.ide.ui.papyrus.internal;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.services.labelprovider.service.LabelProviderService;
+import org.eclipse.papyrus.infra.services.labelprovider.service.impl.LabelProviderServiceImpl;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
@@ -26,6 +32,9 @@ public class CompareDiagramIDEUIPapyrusPlugin extends AbstractUIPlugin {
/** The shared instance. */
private static CompareDiagramIDEUIPapyrusPlugin plugin;
+ /** The Papyrus Label Provder. */
+ private LabelProviderService labelProviderService;
+
/**
* The constructor.
*/
@@ -51,6 +60,14 @@ public class CompareDiagramIDEUIPapyrusPlugin extends AbstractUIPlugin {
*/
@Override
public void stop(BundleContext context) throws Exception {
+ if (labelProviderService != null) {
+ try {
+ labelProviderService.disposeService();
+ } catch (ServiceException ex) {
+ plugin.getLog().log(new Status(IStatus.WARNING, PLUGIN_ID,
+ "Unable to dispose Papyrus Label Provider Service", ex)); //$NON-NLS-1$
+ }
+ }
plugin = null;
super.stop(context);
}
@@ -64,4 +81,25 @@ public class CompareDiagramIDEUIPapyrusPlugin extends AbstractUIPlugin {
return plugin;
}
+ /**
+ * Returns the Papyrus Label Provider service. If the service does not exist yet it will be created.
+ *
+ * @return the Papyrus Label Provider service. Can be {@code null} if the service can not be started.
+ * @since 2.5
+ */
+ public LabelProviderService getLabelProviderService() {
+ if (labelProviderService == null) {
+ labelProviderService = new LabelProviderServiceImpl();
+ try {
+ labelProviderService.startService();
+ } catch (ServiceException ex) {
+ // prevent service from being used if it could not be started
+ labelProviderService = null;
+ getDefault().getLog().log(new Status(IStatus.WARNING, PLUGIN_ID,
+ "Unable to start Papyrus Label Provider Service", ex)); //$NON-NLS-1$
+ }
+ }
+ return labelProviderService;
+ }
+
}
diff --git a/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/internal/accessorfactory/PapyrusAccessorFactoryWrapper.java b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/internal/accessorfactory/PapyrusAccessorFactoryWrapper.java
new file mode 100644
index 000000000..3acdad920
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/internal/accessorfactory/PapyrusAccessorFactoryWrapper.java
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EclipseSource Muenchen GmbH 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:
+ * Stefan Dirix - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.diagram.ide.ui.papyrus.internal.accessorfactory;
+
+import com.google.common.collect.Sets;
+
+import java.util.Iterator;
+import java.util.Set;
+
+import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.compare.diagram.ide.ui.papyrus.internal.context.PapyrusContextUtil;
+import org.eclipse.emf.compare.rcp.ui.EMFCompareRCPUIPlugin;
+import org.eclipse.emf.compare.rcp.ui.contentmergeviewer.accessor.ICompareAccessor;
+import org.eclipse.emf.compare.rcp.ui.contentmergeviewer.accessor.factory.IAccessorFactory;
+import org.eclipse.emf.compare.rcp.ui.contentmergeviewer.accessor.legacy.ITypedElement;
+import org.eclipse.emf.compare.rcp.ui.internal.contentmergeviewer.accessor.factory.impl.AbstractAccessorFactory;
+
+/**
+ * Returns a special PapyrusAccessor when the comparison took place in a Papyrus context, otherwise the call
+ * is delegated to a the normal CompareAccessorFactories.
+ *
+ * @author Stefan Dirix <sdirix@eclipsesource.com>
+ */
+@SuppressWarnings("restriction")
+public class PapyrusAccessorFactoryWrapper extends AbstractAccessorFactory {
+
+ /**
+ * The types for which we return a special Papyrus CompareAccessor.
+ */
+ private static final Set<String> OVERRIDE_TYPES = Sets.newHashSet(
+ "org.eclipse.emf.compare.rcp.ui.eTreeDiff", "org.eclipse.emf.compare.rcp.ui.eMatch", //$NON-NLS-1$ //$NON-NLS-2$
+ "org.eclipse.emf.compare.rcp.ui.eResourceDiff", "NODE_TYPE__EMF_EOBJECT", //$NON-NLS-1$ //$NON-NLS-2$
+ "NODE_TYPE__EMF_RESOURCE", "NODE_TYPE__EMF_RESOURCESET", "NODE_TYPE__EMF_COMPARISON"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isFactoryFor(Object target) {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ITypedElement createLeft(AdapterFactory adapterFactory, Object target) {
+ final IAccessorFactory highestRankingFactory = getHighestRankingFactory(target);
+ if (highestRankingFactory != null) {
+ final ITypedElement left = highestRankingFactory.createLeft(adapterFactory, target);
+ return wrapIfNecessary(left);
+ }
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ITypedElement createRight(AdapterFactory adapterFactory, Object target) {
+ final IAccessorFactory highestRankingFactory = getHighestRankingFactory(target);
+ if (highestRankingFactory != null) {
+ final ITypedElement right = highestRankingFactory.createRight(adapterFactory, target);
+ return wrapIfNecessary(right);
+ }
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ITypedElement createAncestor(AdapterFactory adapterFactory, Object target) {
+ final IAccessorFactory highestRankingFactory = getHighestRankingFactory(target);
+ if (highestRankingFactory != null) {
+ final ITypedElement ancestor = highestRankingFactory.createAncestor(adapterFactory, target);
+ return wrapIfNecessary(ancestor);
+ }
+ return null;
+ }
+
+ /**
+ * Checks the given {@link ITypedElement} and wraps it in a PapyrusAccessor if needed.
+ *
+ * @param element
+ * the {@linked ITypedElement} to check.
+ * @return the wrapped {@code element} if a PapyrusAccessor is needed, the original {@code element}
+ * otherwise.
+ */
+ private ITypedElement wrapIfNecessary(ITypedElement element) {
+ if (element instanceof ICompareAccessor) {
+ final ICompareAccessor accessor = (ICompareAccessor)element;
+ if (PapyrusContextUtil.isPapyrusContext(accessor.getComparison())
+ && isOverrideType(element.getType())) {
+ return new PapyrusAccessorWrapper(accessor);
+ }
+ }
+ return element;
+ }
+
+ /**
+ * Determines whether the given type is one of the types we override in a Papyrus context.
+ *
+ * @param type
+ * the type to check.
+ * @return {@code true} if the type is one of the types we override, {@code false} otherwise.
+ */
+ private boolean isOverrideType(String type) {
+ return OVERRIDE_TYPES.contains(type);
+ }
+
+ /**
+ * Searches the highest ranking factory for the given target, disregarding {@code this} factory itself.
+ *
+ * @param target
+ * the target for which the highest ranking factory is to be determined.
+ * @return the highest ranking factory which is not this class itself, {@code null} if no other factory
+ * could be determined.
+ */
+ private IAccessorFactory getHighestRankingFactory(Object target) {
+ IAccessorFactory.Registry factoryRegistry = EMFCompareRCPUIPlugin.getDefault()
+ .getAccessorFactoryRegistry();
+
+ Iterator<IAccessorFactory> factories = factoryRegistry.getFactories(target).iterator();
+
+ IAccessorFactory ret = null;
+
+ while (factories.hasNext()) {
+ IAccessorFactory factory = factories.next();
+ // Do not use this or another higher ranking factory to avoid endless loops
+ if (factory.getRanking() >= this.getRanking()) {
+ continue;
+ }
+ if (ret == null || factory.getRanking() > ret.getRanking()) {
+ ret = factory;
+ }
+ }
+
+ return ret;
+ }
+
+}
diff --git a/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/internal/accessorfactory/PapyrusAccessorWrapper.java b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/internal/accessorfactory/PapyrusAccessorWrapper.java
new file mode 100644
index 000000000..dc107e892
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.diagram.ide.ui.papyrus/src/org/eclipse/emf/compare/diagram/ide/ui/papyrus/internal/accessorfactory/PapyrusAccessorWrapper.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EclipseSource Muenchen GmbH 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:
+ * Stefan Dirix - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.diagram.ide.ui.papyrus.internal.accessorfactory;
+
+import com.google.common.collect.ImmutableList;
+
+import org.eclipse.emf.compare.Comparison;
+import org.eclipse.emf.compare.rcp.ui.contentmergeviewer.accessor.ICompareAccessor;
+import org.eclipse.emf.compare.rcp.ui.mergeviewer.item.IMergeViewerItem;
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * A Papyrus Wrapper for an {@link ICompareAccessor}. All calls are delegated to the given ICompareAccesor,
+ * except the {@link #getType()} method which adds a {@link #PAPYRUS_TYPE} in front of the type to indicate
+ * the Papyrus context.
+ *
+ * @author Stefan Dirix <sdirix@eclipsesource.com>
+ */
+public class PapyrusAccessorWrapper implements ICompareAccessor {
+
+ /**
+ * The type-prefix which indicates the Papyrus context.
+ */
+ private static final String PAPYRUS_TYPE = "papyrus-"; //$NON-NLS-1$
+
+ /**
+ * The wrapped {@link ICompareAccessor}.
+ */
+ private ICompareAccessor delegate;
+
+ /**
+ * The Constructor.
+ *
+ * @param delegate
+ * The {@link ICompareAccessor} which is wrapped.
+ */
+ public PapyrusAccessorWrapper(ICompareAccessor delegate) {
+ this.delegate = delegate;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getName() {
+ return delegate.getName();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Image getImage() {
+ return delegate.getImage();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getType() {
+ return PAPYRUS_TYPE + delegate.getType();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Comparison getComparison() {
+ return delegate.getComparison();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public IMergeViewerItem getInitialItem() {
+ return delegate.getInitialItem();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ImmutableList<? extends IMergeViewerItem> getItems() {
+ return delegate.getItems();
+ }
+
+}
diff --git a/plugins/org.eclipse.emf.compare.diagram.papyrus.tests/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.compare.diagram.papyrus.tests/META-INF/MANIFEST.MF
index 226144562..af78c6818 100644
--- a/plugins/org.eclipse.emf.compare.diagram.papyrus.tests/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.emf.compare.diagram.papyrus.tests/META-INF/MANIFEST.MF
@@ -33,7 +33,7 @@ Require-Bundle: org.eclipse.core.runtime,
org.eclipse.emf.compare.diagram.edit;bundle-version="2.3.0",
org.eclipse.emf.compare.diagram.ide.ui;bundle-version="3.1.0",
org.eclipse.emf.compare.diagram.papyrus;bundle-version="1.0.0",
- org.eclipse.emf.compare.diagram.ide.ui.papyrus;bundle-version="2.4.0",
+ org.eclipse.emf.compare.diagram.ide.ui.papyrus;bundle-version="2.5.0",
org.eclipse.emf.compare.tests;bundle-version="2.0.0",
org.eclipse.emf.compare.rcp.ui.tests,
org.eclipse.emf.compare.ide.ui.tests;bundle-version="4.0.0",
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.compare.ide.ui/META-INF/MANIFEST.MF
index f0c65a3dc..241168c34 100644
--- a/plugins/org.eclipse.emf.compare.ide.ui/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.emf.compare.ide.ui/META-INF/MANIFEST.MF
@@ -33,6 +33,7 @@ Export-Package: org.eclipse.emf.compare.ide.ui.dependency;x-friends:="org.eclips
org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.table;x-internal:=true,
org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.text;x-internal:=true,
org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.tree;x-internal:=true,
+ org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.tree.provider;x-internal:=true,
org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.util;x-internal:=true,
org.eclipse.emf.compare.ide.ui.internal.editor;x-internal:=true,
org.eclipse.emf.compare.ide.ui.internal.handler;x-internal:=true,
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/contentmergeviewer/tree/TreeContentMergeViewer.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/contentmergeviewer/tree/TreeContentMergeViewer.java
index 4b7b35dd7..c95fcfe12 100644
--- a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/contentmergeviewer/tree/TreeContentMergeViewer.java
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/contentmergeviewer/tree/TreeContentMergeViewer.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2012, 2015 Obeo.
+ * Copyright (c) 2012, 2016 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
@@ -7,6 +7,7 @@
*
* Contributors:
* Obeo - initial API and implementation
+ * Stefan Dirix - bug 487595
*******************************************************************************/
package org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.tree;
@@ -32,9 +33,10 @@ import org.eclipse.emf.compare.Match;
import org.eclipse.emf.compare.ReferenceChange;
import org.eclipse.emf.compare.ide.ui.internal.configuration.EMFCompareConfiguration;
import org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.EMFCompareContentMergeViewer;
+import org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.tree.provider.TreeContentMergeViewerItemContentProvider;
+import org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.tree.provider.TreeContentMergeViewerItemLabelProvider;
import org.eclipse.emf.compare.match.impl.NotLoadedFragmentMatch;
import org.eclipse.emf.compare.rcp.EMFCompareRCPPlugin;
-import org.eclipse.emf.compare.rcp.ui.contentmergeviewer.accessor.ICompareAccessor;
import org.eclipse.emf.compare.rcp.ui.internal.mergeviewer.impl.AbstractMergeViewer;
import org.eclipse.emf.compare.rcp.ui.internal.mergeviewer.impl.TreeMergeViewer;
import org.eclipse.emf.compare.rcp.ui.internal.mergeviewer.item.impl.MergeViewerItem;
@@ -42,8 +44,6 @@ import org.eclipse.emf.compare.rcp.ui.internal.util.MergeViewerUtil;
import org.eclipse.emf.compare.rcp.ui.mergeviewer.IMergeViewer.MergeViewerSide;
import org.eclipse.emf.compare.rcp.ui.mergeviewer.item.IMergeViewerItem;
import org.eclipse.emf.ecore.EObject;
-import org.eclipse.emf.ecore.InternalEObject;
-import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory;
import org.eclipse.emf.edit.provider.resource.ResourceItemProviderAdapterFactory;
@@ -58,7 +58,6 @@ import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseWheelListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
-import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
@@ -102,13 +101,18 @@ public class TreeContentMergeViewer extends EMFCompareContentMergeViewer {
* {@link #setContentProvider(org.eclipse.jface.viewers.IContentProvider) content provider} to properly
* display ancestor, left and right parts.
*
+ * @param style
+ * the style indicator for the parent
+ * @param bundle
+ * the {@link ResourceBundle} for localization
* @param parent
* the parent composite to build the UI in
* @param config
* the {@link CompareConfiguration}
*/
- public TreeContentMergeViewer(Composite parent, EMFCompareConfiguration config) {
- super(SWT.NONE, ResourceBundle.getBundle(BUNDLE_NAME), config);
+ public TreeContentMergeViewer(int style, ResourceBundle bundle, Composite parent,
+ EMFCompareConfiguration config) {
+ super(style, bundle, config);
fAdapterFactory = new ComposedAdapterFactory(
EMFCompareRCPPlugin.getDefault().createFilteredAdapterFactoryRegistry());
@@ -120,6 +124,29 @@ public class TreeContentMergeViewer extends EMFCompareContentMergeViewer {
setContentProvider(new TreeContentMergeViewerContentProvider(config));
}
+ protected ComposedAdapterFactory getAdapterFactory() {
+ return fAdapterFactory;
+ }
+
+ /**
+ * Creates a new {@link TreeContentMergeViewer} by calling the super constructor with the given
+ * parameters.
+ * <p>
+ * It calls {@link #buildControl(Composite)} as stated in its javadoc.
+ * <p>
+ * It sets a {@link TreeContentMergeViewerContentProvider specific}
+ * {@link #setContentProvider(org.eclipse.jface.viewers.IContentProvider) content provider} to properly
+ * display ancestor, left and right parts.
+ *
+ * @param parent
+ * the parent composite to build the UI in
+ * @param config
+ * the {@link CompareConfiguration}
+ */
+ public TreeContentMergeViewer(Composite parent, EMFCompareConfiguration config) {
+ this(SWT.NONE, ResourceBundle.getBundle(BUNDLE_NAME), parent, config);
+ }
+
/**
* {@inheritDoc}
*
@@ -183,145 +210,47 @@ public class TreeContentMergeViewer extends EMFCompareContentMergeViewer {
protected AbstractMergeViewer createMergeViewer(final Composite parent, final MergeViewerSide side) {
final TreeMergeViewer mergeTreeViewer = new TreeMergeViewer(parent, side, this,
getCompareConfiguration());
- IContentProvider contentProvider = new AdapterFactoryContentProvider(fAdapterFactory) {
- /**
- * {@inheritDoc}
- *
- * @see org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider#getElements(java.lang.Object)
- */
- @Override
- public Object[] getElements(Object object) {
- if (object instanceof ICompareAccessor) {
- return ((ICompareAccessor)object).getItems().toArray();
- }
- return super.getElements(object);
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider#getChildren(java.lang.Object)
- */
- @Override
- public Object[] getChildren(Object object) {
- if (object instanceof IMergeViewerItem.Container) {
- IMergeViewerItem[] children = ((IMergeViewerItem.Container)object)
- .getChildren(getDifferenceGroupProvider(), getDifferenceFilterPredicate());
-
- return children;
- }
- return super.getChildren(object);
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider#hasChildren(java.lang.Object)
- */
- @Override
- public boolean hasChildren(Object object) {
- if (object instanceof IMergeViewerItem.Container) {
- return ((IMergeViewerItem.Container)object).hasChildren(getDifferenceGroupProvider(),
- getDifferenceFilterPredicate());
- }
- return super.hasChildren(object);
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider#getParent(java.lang.Object)
- */
- @Override
- public Object getParent(Object object) {
- if (object instanceof IMergeViewerItem.Container) {
- return ((IMergeViewerItem.Container)object).getParent();
- }
- return super.getParent(object);
- }
- };
+ IContentProvider contentProvider = new TreeContentMergeViewerItemContentProvider(fAdapterFactory,
+ getDifferenceGroupProvider(), getDifferenceFilterPredicate());
mergeTreeViewer.setContentProvider(contentProvider);
- AdapterFactoryLabelProvider labelProvider = new AdapterFactoryLabelProvider(fAdapterFactory) {
- /**
- * {@inheritDoc}
- *
- * @see org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider#getText(java.lang.Object)
- */
- @Override
- public String getText(Object object) {
- if (object instanceof IMergeViewerItem) {
- final String text;
- IMergeViewerItem mergeViewerItem = (IMergeViewerItem)object;
- final Object value = mergeViewerItem.getSideValue(side);
- if (value instanceof EObject && ((EObject)value).eIsProxy()) {
- text = "proxy : " + ((InternalEObject)value).eProxyURI().toString(); //$NON-NLS-1$
- } else if (mergeViewerItem.isInsertionPoint()) {
- // workaround for 406513: Windows specific issue. Only labels of (Tree/Table)Item are
- // selectable on Windows platform. The labels of placeholders in (Tree/Table)Viewer
- // are one whitespace. Placeholder are then selectable at the very left of itself.
- // Add a 42 whitespaces label to workaround.
- text = " "; //$NON-NLS-1$
- } else if (value == null
- && mergeViewerItem.getSideValue(side.opposite()) instanceof Resource) {
- text = getResourceBundle().getString("UnkownResource"); //$NON-NLS-1$
- } else if (value == null && mergeViewerItem.getLeft() == null
- && mergeViewerItem.getRight() == null
- && mergeViewerItem.getAncestor() instanceof Resource) {
- text = getResourceBundle().getString("UnkownResource"); //$NON-NLS-1$
- } else {
- text = super.getText(value);
- }
- return text;
- }
- return super.getText(object);
- }
+ AdapterFactoryLabelProvider labelProvider = new TreeContentMergeViewerItemLabelProvider(
+ getResourceBundle(), fAdapterFactory, side);
+ mergeTreeViewer.setLabelProvider(labelProvider);
- @Override
- public Image getImage(Object object) {
- if (object instanceof IMergeViewerItem) {
- IMergeViewerItem mergeViewerItem = (IMergeViewerItem)object;
- if (mergeViewerItem.isInsertionPoint()) {
- return null;
- } else if (mergeViewerItem.getSideValue(side) == null
- && mergeViewerItem.getSideValue(side.opposite()) instanceof Resource) {
- return super.getImage(mergeViewerItem.getSideValue(side.opposite()));
- } else if (mergeViewerItem.getLeft() == null && mergeViewerItem.getRight() == null
- && mergeViewerItem.getAncestor() instanceof Resource) {
- return super.getImage(mergeViewerItem.getAncestor());
- } else {
- return super.getImage(mergeViewerItem.getSideValue(side));
- }
- }
- return super.getImage(object);
- }
- };
+ hookListeners(mergeTreeViewer);
- mergeTreeViewer.setLabelProvider(labelProvider);
+ return mergeTreeViewer;
+ }
- mergeTreeViewer.getStructuredViewer().getTree().addListener(SWT.Collapse,
- new ExpandCollapseListener(mergeTreeViewer, false));
- mergeTreeViewer.getStructuredViewer().getTree().addListener(SWT.Expand,
- new ExpandCollapseListener(mergeTreeViewer, true));
+ /**
+ * Adds all required listeners to the given {@link TreeMergeViewer}.
+ *
+ * @param treeMergeViewer
+ * the {@link TreeMergeViewer}.
+ */
+ protected void hookListeners(TreeMergeViewer treeMergeViewer) {
+ treeMergeViewer.getStructuredViewer().getTree().addListener(SWT.Collapse,
+ new ExpandCollapseListener(treeMergeViewer, false));
+ treeMergeViewer.getStructuredViewer().getTree().addListener(SWT.Expand,
+ new ExpandCollapseListener(treeMergeViewer, true));
- mergeTreeViewer.getStructuredViewer().getTree().getVerticalBar().addListener(SWT.Selection,
+ treeMergeViewer.getStructuredViewer().getTree().getVerticalBar().addListener(SWT.Selection,
new Listener() {
public void handleEvent(Event event) {
redrawCenterControl();
}
});
- mergeTreeViewer.getStructuredViewer().getTree().addMouseWheelListener(new MouseWheelListener() {
+ treeMergeViewer.getStructuredViewer().getTree().addMouseWheelListener(new MouseWheelListener() {
public void mouseScrolled(MouseEvent e) {
redrawCenterControl();
}
});
- mergeTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+ treeMergeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
redrawCenterControl();
}
});
-
- return mergeTreeViewer;
}
/**
@@ -464,7 +393,7 @@ public class TreeContentMergeViewer extends EMFCompareContentMergeViewer {
/**
* @author <a href="mailto:mikael.barbero@obeo.fr">Mikael Barbero</a>
*/
- private final class ExpandCollapseListener implements Listener {
+ protected final class ExpandCollapseListener implements Listener {
/**
*
*/
@@ -475,7 +404,7 @@ public class TreeContentMergeViewer extends EMFCompareContentMergeViewer {
/**
* @param mergeTreeViewer
*/
- private ExpandCollapseListener(TreeMergeViewer mergeTreeViewer, boolean expanded) {
+ public ExpandCollapseListener(TreeMergeViewer mergeTreeViewer, boolean expanded) {
this.mergeTreeViewer = mergeTreeViewer;
this.expanded = expanded;
}
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/contentmergeviewer/tree/provider/TreeContentMergeViewerItemContentProvider.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/contentmergeviewer/tree/provider/TreeContentMergeViewerItemContentProvider.java
new file mode 100644
index 000000000..27323ad1e
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/contentmergeviewer/tree/provider/TreeContentMergeViewerItemContentProvider.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2012, 2016 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
+ * Stefan Dirix - extracted into own class
+ *******************************************************************************/
+package org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.tree.provider;
+
+import com.google.common.base.Predicate;
+
+import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.compare.rcp.ui.contentmergeviewer.accessor.ICompareAccessor;
+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.edit.ui.provider.AdapterFactoryContentProvider;
+
+/**
+ * The content provider for {@link IMergeViewerItem}s
+ */
+public class TreeContentMergeViewerItemContentProvider extends AdapterFactoryContentProvider {
+
+ private IDifferenceGroupProvider differenceGroupProvider;
+
+ private Predicate<? super EObject> differenceFilterPredicate;
+
+ /**
+ * Constructor.
+ *
+ * @param adapterFactory
+ * the {@link AdapterFactory}
+ * @param differenceGroupProvider
+ * the {@link IDifferenceGroupProvider}
+ * @param differenceFilterPredicate
+ * the {@link Predicate}
+ */
+ public TreeContentMergeViewerItemContentProvider(AdapterFactory adapterFactory,
+ IDifferenceGroupProvider differenceGroupProvider,
+ Predicate<? super EObject> differenceFilterPredicate) {
+ super(adapterFactory);
+ this.differenceGroupProvider = differenceGroupProvider;
+ this.differenceFilterPredicate = differenceFilterPredicate;
+ }
+
+ @Override
+ public Object[] getElements(Object object) {
+ if (object instanceof ICompareAccessor) {
+ return ((ICompareAccessor)object).getItems().toArray();
+ }
+ return super.getElements(object);
+ }
+
+ @Override
+ public Object[] getChildren(Object object) {
+ if (object instanceof IMergeViewerItem.Container) {
+ IMergeViewerItem[] children = ((IMergeViewerItem.Container)object)
+ .getChildren(differenceGroupProvider, differenceFilterPredicate);
+
+ return children;
+ }
+ return super.getChildren(object);
+ }
+
+ @Override
+ public boolean hasChildren(Object object) {
+ if (object instanceof IMergeViewerItem.Container) {
+ return ((IMergeViewerItem.Container)object).hasChildren(differenceGroupProvider,
+ differenceFilterPredicate);
+ }
+ return super.hasChildren(object);
+ }
+
+ @Override
+ public Object getParent(Object object) {
+ if (object instanceof IMergeViewerItem.Container) {
+ return ((IMergeViewerItem.Container)object).getParent();
+ }
+ return super.getParent(object);
+ }
+}
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/contentmergeviewer/tree/provider/TreeContentMergeViewerItemLabelProvider.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/contentmergeviewer/tree/provider/TreeContentMergeViewerItemLabelProvider.java
new file mode 100644
index 000000000..c0318d3d2
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/contentmergeviewer/tree/provider/TreeContentMergeViewerItemLabelProvider.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * Copyright (c) 2012, 2016 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
+ * Stefan Dirix - extracted into own class
+ *******************************************************************************/
+package org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.tree.provider;
+
+import java.util.ResourceBundle;
+
+import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.compare.rcp.ui.mergeviewer.IMergeViewer.MergeViewerSide;
+import org.eclipse.emf.compare.rcp.ui.mergeviewer.item.IMergeViewerItem;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.InternalEObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * Label Provider for {@link IMergeViewerItem}s.
+ */
+public class TreeContentMergeViewerItemLabelProvider extends AdapterFactoryLabelProvider {
+
+ private final MergeViewerSide side;
+
+ private ResourceBundle resourceBundle;
+
+ /**
+ * Constructor.
+ *
+ * @param resourceBundle
+ * the {@link ResourceBundle}. Used for error messages.
+ * @param adapterFactory
+ * the {@link AdapterFactory}.
+ * @param side
+ * the {@link MergeViewerSide}.
+ */
+ public TreeContentMergeViewerItemLabelProvider(ResourceBundle resourceBundle,
+ AdapterFactory adapterFactory, MergeViewerSide side) {
+ super(adapterFactory);
+ this.side = side;
+ this.resourceBundle = resourceBundle;
+ }
+
+ @Override
+ public String getText(Object object) {
+ if (object instanceof IMergeViewerItem) {
+ final String text;
+ IMergeViewerItem mergeViewerItem = (IMergeViewerItem)object;
+ final Object value = mergeViewerItem.getSideValue(side);
+ if (value instanceof EObject && ((EObject)value).eIsProxy()) {
+ text = "proxy : " + ((InternalEObject)value).eProxyURI().toString(); //$NON-NLS-1$
+ } else if (mergeViewerItem.isInsertionPoint()) {
+ // workaround for 406513: Windows specific issue. Only labels of (Tree/Table)Item are
+ // selectable on Windows platform. The labels of placeholders in (Tree/Table)Viewer
+ // are one whitespace. Placeholder are then selectable at the very left of itself.
+ // Add a 42 whitespaces label to workaround.
+ text = " "; //$NON-NLS-1$
+ } else if (value == null && mergeViewerItem.getSideValue(side.opposite()) instanceof Resource) {
+ text = resourceBundle.getString("UnkownResource"); //$NON-NLS-1$
+ } else if (value == null && mergeViewerItem.getLeft() == null
+ && mergeViewerItem.getRight() == null
+ && mergeViewerItem.getAncestor() instanceof Resource) {
+ text = resourceBundle.getString("UnkownResource"); //$NON-NLS-1$
+ } else {
+ text = super.getText(value);
+ }
+ return text;
+ }
+ return super.getText(object);
+ }
+
+ @Override
+ public Image getImage(Object object) {
+ if (object instanceof IMergeViewerItem) {
+ IMergeViewerItem mergeViewerItem = (IMergeViewerItem)object;
+ if (mergeViewerItem.isInsertionPoint()) {
+ return null;
+ } else if (mergeViewerItem.getSideValue(side) == null
+ && mergeViewerItem.getSideValue(side.opposite()) instanceof Resource) {
+ return super.getImage(mergeViewerItem.getSideValue(side.opposite()));
+ } else if (mergeViewerItem.getLeft() == null && mergeViewerItem.getRight() == null
+ && mergeViewerItem.getAncestor() instanceof Resource) {
+ return super.getImage(mergeViewerItem.getAncestor());
+ } else {
+ return super.getImage(mergeViewerItem.getSideValue(side));
+ }
+ }
+ return super.getImage(object);
+ }
+}
diff --git a/plugins/org.eclipse.emf.compare.uml2.edit/src/org/eclipse/emf/compare/uml2/internal/provider/decorator/UMLCompareItemProviderDecoratorAdapterFactory.java b/plugins/org.eclipse.emf.compare.uml2.edit/src/org/eclipse/emf/compare/uml2/internal/provider/decorator/UMLCompareItemProviderDecoratorAdapterFactory.java
index fe941edeb..b6bd65aa4 100644
--- a/plugins/org.eclipse.emf.compare.uml2.edit/src/org/eclipse/emf/compare/uml2/internal/provider/decorator/UMLCompareItemProviderDecoratorAdapterFactory.java
+++ b/plugins/org.eclipse.emf.compare.uml2.edit/src/org/eclipse/emf/compare/uml2/internal/provider/decorator/UMLCompareItemProviderDecoratorAdapterFactory.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2012, 2014 Obeo.
+ * Copyright (c) 2012, 2016 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
@@ -7,6 +7,7 @@
*
* Contributors:
* Obeo - initial API and implementation
+ * Stefan Dirix - bug 487595
*******************************************************************************/
package org.eclipse.emf.compare.uml2.internal.provider.decorator;
@@ -51,6 +52,11 @@ public class UMLCompareItemProviderDecoratorAdapterFactory extends DecoratorAdap
return createUMLDiffItemProviderDecorator();
}
+ @Override
+ public IItemProviderDecorator defaultCase(EObject object) {
+ return createUMLDiffItemProviderDecorator();
+ }
+
};
/**

Back to the top