[398361] Enhanced Model Merge UI

- Add new Ruler next to StructureMergeViewer
- When select diff in StructureMergeViewer, highlight required and
unmergeable diffs,
and create annotations in Ruler
- Add new merge and navigation actions in StructureMergeViewer toolbar.
- Delete old merge and navigation actions in ContentMergeViewer toolbar.

Bug: 398361
Change-Id: I3d43fe9c4938404361f835e93631ed744a2c4377

diff --git a/plugins/org.eclipse.emf.compare.diagram.ide.ui/src/org/eclipse/emf/compare/diagram/ide/ui/internal/contentmergeviewer/diagram/DiagramContentMergeViewer.java b/plugins/org.eclipse.emf.compare.diagram.ide.ui/src/org/eclipse/emf/compare/diagram/ide/ui/internal/contentmergeviewer/diagram/DiagramContentMergeViewer.java
index 90a8693..8b5f08d 100644
--- a/plugins/org.eclipse.emf.compare.diagram.ide.ui/src/org/eclipse/emf/compare/diagram/ide/ui/internal/contentmergeviewer/diagram/DiagramContentMergeViewer.java
+++ b/plugins/org.eclipse.emf.compare.diagram.ide.ui/src/org/eclipse/emf/compare/diagram/ide/ui/internal/contentmergeviewer/diagram/DiagramContentMergeViewer.java
@@ -27,7 +27,6 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.EventObject;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -1719,34 +1718,6 @@
 	/**
 	 * {@inheritDoc}
 	 * 
-	 * @see org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.EMFCompareContentMergeViewer#copyDiff(boolean)
-	 */
-	@Override
-	protected void copyDiff(boolean leftToRight) {
-		/*
-		 * FIXME change this! For the moment we always do a new setInput() on the content viewer whenever we
-		 * select a Diagram Difference. This is meant to change so that we use selection synchronization
-		 * instead. This code will break whenever we implement that change.
-		 */
-		if (fCurrentSelectedDiff != null) {
-			final Command command = getEditingDomain().createCopyCommand(
-					Collections.singletonList(fCurrentSelectedDiff), leftToRight,
-					EMFCompareRCPPlugin.getDefault().getMergerRegistry());
-			getEditingDomain().getCommandStack().execute(command);
-
-			if (leftToRight) {
-				setRightDirty(true);
-			} else {
-				setLeftDirty(true);
-			}
-			// refresh();
-		}
-
-	}
-
-	/**
-	 * {@inheritDoc}
-	 * 
 	 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#getContents(boolean)
 	 */
 	@Override
diff --git a/plugins/org.eclipse.emf.compare.edit/icons/full/ovr16/merged_left_ov.gif b/plugins/org.eclipse.emf.compare.edit/icons/full/ovr16/merged_left_ov.gif
new file mode 100644
index 0000000..117e63d
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.edit/icons/full/ovr16/merged_left_ov.gif
Binary files differ
diff --git a/plugins/org.eclipse.emf.compare.edit/icons/full/ovr16/merged_right_ov.gif b/plugins/org.eclipse.emf.compare.edit/icons/full/ovr16/merged_right_ov.gif
new file mode 100644
index 0000000..26ebe0f
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.edit/icons/full/ovr16/merged_right_ov.gif
Binary files differ
diff --git a/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/provider/spec/OverlayImageProvider.java b/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/provider/spec/OverlayImageProvider.java
index 3659329..a73652b 100644
--- a/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/provider/spec/OverlayImageProvider.java
+++ b/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/provider/spec/OverlayImageProvider.java
@@ -1,196 +1,217 @@
-/*******************************************************************************

- * Copyright (c) 2012 Obeo.

- * All rights reserved. This program and the accompanying materials

- * are made available under the terms of the Eclipse Public License v1.0

- * which accompanies this distribution, and is available at

- * http://www.eclipse.org/legal/epl-v10.html

- * 

- * Contributors:

- *     Obeo - initial API and implementation

- *******************************************************************************/

-package org.eclipse.emf.compare.provider.spec;

-

-import static com.google.common.collect.Lists.newArrayList;

-

-import java.util.Collection;

-import java.util.List;

-

-import org.eclipse.emf.common.util.ResourceLocator;

-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.edit.provider.ComposedImage;

-

-/**

- * @author <a href="mailto:mikael.barbero@obeo.fr">Mikael Barbero</a>

- */

-public class OverlayImageProvider {

-

-	private final ResourceLocator fResourceLocator;

-

-	/**

-	 * 

-	 */

-	public OverlayImageProvider(ResourceLocator resourceLocator) {

-		this.fResourceLocator = resourceLocator;

-	}

-

-	public Object getComposedImage(Diff diff, Object imageToCompose) {

-		String overlay = getImageOverlay(diff);

-		return getComposedImage(imageToCompose, overlay);

-	}

-

-	public Object getComposedImage(Match match, Object imageToCompose) {

-		String overlay = getImageOverlay(match);

-		return getComposedImage(imageToCompose, overlay);

-	}

-

-	private Object getComposedImage(Object imageToCompose, String overlay) {

-		Collection<Object> images = newArrayList();

-		images.add(imageToCompose);

-		if (overlay != null) {

-			Object image = fResourceLocator.getImage(overlay);

-			images.add(image);

-		}

-		return new ComposedImageExtension(images);

-	}

-

-	// Nothing here has to be externalized

-	@SuppressWarnings("nls")

-	private String getImageOverlay(Diff diff) {

-		final DifferenceSource source = diff.getSource();

-		final Match match = diff.getMatch();

-		final Conflict conflict = diff.getConflict();

-		final DifferenceKind diffKind = diff.getKind();

-		final Comparison comparison = match.getComparison();

-		String path = "full/ovr16/";

-

-		if (diff.getState() == DifferenceState.MERGED) {

-			path += "merged_ov";

-		} else if (diff.getState() == DifferenceState.DISCARDED) {

-			path += "removed_ov";

-		} else if (comparison.isThreeWay()) {

-			// "png" needs explicit declaration, "gif" does not

-			String extension = "";

-			if (conflict != null) {

-				extension = ".png";

-				if (conflict.getKind() == ConflictKind.PSEUDO) {

-					path += "p";

-				}

-				path += "conf";

-				if (source == DifferenceSource.RIGHT) {

-					path += "r_";

-				}

-			} else {

-				switch (source) {

-					case LEFT:

-						path += "r_out";

-						break;

-					case RIGHT:

-						path += "r_in";

-						break;

-					default:

-						// Cannot happen ... for now

-						break;

-				}

-			}

-

-			switch (diffKind) {

-				case ADD:

-					path += "add_ov";

-					break;

-				case DELETE:

-					path += "del_ov";

-					break;

-				case CHANGE:

-					// fallthrough

-				case MOVE:

-					path += "chg_ov";

-					break;

-				default:

-					// Cannot happen ... for now

-					break;

-			}

-			path += extension;

-		} else {

-			switch (diffKind) {

-				case ADD:

-					path += "add_ov";

-					break;

-				case DELETE:

-					path += "del_ov";

-					break;

-				case CHANGE:

-					// fallthrough

-				case MOVE:

-					path += "chg_ov";

-					break;

-				default:

-					break;

-			}

-		}

-		return path;

-	}

-

-	// Nothing here has to be externalized

-	@SuppressWarnings("nls")

-	private String getImageOverlay(Match match) {

-		return "full/ovr16/match_ov.png";

-	}

-

-	private final class ComposedImageExtension extends ComposedImage {

-

-		/**

-		 * 

-		 */

-		private static final int X_OFFSET = 10;

-

-		/**

-		 * @param images

-		 */

-		ComposedImageExtension(Collection<?> images) {

-			super(images);

-		}

-

-		/**

-		 * {@inheritDoc}

-		 * 

-		 * @see org.eclipse.emf.edit.provider.ComposedImage#getDrawPoints(org.eclipse.emf.edit.provider.ComposedImage.Size)

-		 */

-		@Override

-		public List<Point> getDrawPoints(Size size) {

-			List<ComposedImage.Point> result = super.getDrawPoints(size);

-			if (result.size() > 1) {

-				result.get(1).x = X_OFFSET;

-				result.get(1).y = 2;

-			}

-			return result;

-		}

-

-		/**

-		 * {@inheritDoc}

-		 * 

-		 * @see org.eclipse.emf.edit.provider.ComposedImage#getSize(java.util.Collection)

-		 */

-		@Override

-		public Size getSize(Collection<? extends Size> sizes) {

-			this.imageSizes = newArrayList(sizes);

-			List<Point> drawPoints = getDrawPoints(null);

-

-			Size result = new Size();

-			for (int i = 0; i < sizes.size(); i++) {

-				Size size = this.imageSizes.get(i);

-				Point point = drawPoints.get(i);

-

-				result.width = Math.max(result.width, size.width + Math.abs(point.x));

-				result.height = Math.max(result.height, size.height + Math.abs(point.y));

-			}

-			return result;

-		}

-	}

-}

+/*******************************************************************************
+ * Copyright (c) 2012 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.provider.spec;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.emf.common.notify.Adapter;
+import org.eclipse.emf.common.util.ResourceLocator;
+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.internal.merge.IDiffMergeData;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.emf.edit.provider.ComposedImage;
+
+/**
+ * @author <a href="mailto:mikael.barbero@obeo.fr">Mikael Barbero</a>
+ */
+public class OverlayImageProvider {
+
+	private final ResourceLocator fResourceLocator;
+
+	/**
+	 * 
+	 */
+	public OverlayImageProvider(ResourceLocator resourceLocator) {
+		this.fResourceLocator = resourceLocator;
+	}
+
+	public Object getComposedImage(Diff diff, Object imageToCompose) {
+		String overlay = getImageOverlay(diff);
+		return getComposedImage(imageToCompose, overlay);
+	}
+
+	public Object getComposedImage(Match match, Object imageToCompose) {
+		String overlay = getImageOverlay(match);
+		return getComposedImage(imageToCompose, overlay);
+	}
+
+	private Object getComposedImage(Object imageToCompose, String overlay) {
+		Collection<Object> images = newArrayList();
+		images.add(imageToCompose);
+		if (overlay != null) {
+			Object image = fResourceLocator.getImage(overlay);
+			images.add(image);
+		}
+		return new ComposedImageExtension(images);
+	}
+
+	// Nothing here has to be externalized
+	@SuppressWarnings("nls")
+	private String getImageOverlay(Diff diff) {
+		final DifferenceSource source = diff.getSource();
+		final Match match = diff.getMatch();
+		final Conflict conflict = diff.getConflict();
+		final DifferenceKind diffKind = diff.getKind();
+		final Comparison comparison = match.getComparison();
+		String path = "full/ovr16/";
+
+		if (diff.getState() == DifferenceState.MERGED) {
+			Adapter adapter = EcoreUtil.getExistingAdapter(diff, IDiffMergeData.class);
+			if (adapter != null) {
+				IDiffMergeData iMergeData = (IDiffMergeData)adapter;
+				if (iMergeData.isLeftEditable() && !iMergeData.isRightEditable()) {
+					if (iMergeData.hasBeenMergedToLeft()) {
+						path += "removed_ov";
+					} else {
+						path += "merged_ov";
+					}
+				} else if (iMergeData.isLeftEditable() && iMergeData.isRightEditable()) {
+					if (iMergeData.hasBeenMergedToLeft()) {
+						path += "merged_left_ov";
+					} else {
+						path += "merged_right_ov";
+					}
+				}
+			} else {
+				path += "merged_ov";
+			}
+		} else if (diff.getState() == DifferenceState.DISCARDED) {
+			path += "removed_ov";
+		} else if (comparison.isThreeWay()) {
+			// "png" needs explicit declaration, "gif" does not
+			String extension = "";
+			if (conflict != null) {
+				extension = ".png";
+				if (conflict.getKind() == ConflictKind.PSEUDO) {
+					path += "p";
+				}
+				path += "conf";
+				if (source == DifferenceSource.RIGHT) {
+					path += "r_";
+				}
+			} else {
+				switch (source) {
+					case LEFT:
+						path += "r_out";
+						break;
+					case RIGHT:
+						path += "r_in";
+						break;
+					default:
+						// Cannot happen ... for now
+						break;
+				}
+			}
+
+			switch (diffKind) {
+				case ADD:
+					path += "add_ov";
+					break;
+				case DELETE:
+					path += "del_ov";
+					break;
+				case CHANGE:
+					// fallthrough
+				case MOVE:
+					path += "chg_ov";
+					break;
+				default:
+					// Cannot happen ... for now
+					break;
+			}
+			path += extension;
+		} else {
+			switch (diffKind) {
+				case ADD:
+					path += "add_ov";
+					break;
+				case DELETE:
+					path += "del_ov";
+					break;
+				case CHANGE:
+					// fallthrough
+				case MOVE:
+					path += "chg_ov";
+					break;
+				default:
+					break;
+			}
+		}
+		return path;
+	}
+
+	// Nothing here has to be externalized
+	@SuppressWarnings("nls")
+	private String getImageOverlay(Match match) {
+		return "full/ovr16/match_ov.png";
+	}
+
+	private final class ComposedImageExtension extends ComposedImage {
+
+		/**
+		 * 
+		 */
+		private static final int X_OFFSET = 10;
+
+		/**
+		 * @param images
+		 */
+		ComposedImageExtension(Collection<?> images) {
+			super(images);
+		}
+
+		/**
+		 * {@inheritDoc}
+		 * 
+		 * @see org.eclipse.emf.edit.provider.ComposedImage#getDrawPoints(org.eclipse.emf.edit.provider.ComposedImage.Size)
+		 */
+		@Override
+		public List<Point> getDrawPoints(Size size) {
+			List<ComposedImage.Point> result = super.getDrawPoints(size);
+			if (result.size() > 1) {
+				result.get(1).x = X_OFFSET;
+				result.get(1).y = 2;
+			}
+			return result;
+		}
+
+		/**
+		 * {@inheritDoc}
+		 * 
+		 * @see org.eclipse.emf.edit.provider.ComposedImage#getSize(java.util.Collection)
+		 */
+		@Override
+		public Size getSize(Collection<? extends Size> sizes) {
+			this.imageSizes = newArrayList(sizes);
+			List<Point> drawPoints = getDrawPoints(null);
+
+			Size result = new Size();
+			for (int i = 0; i < sizes.size(); i++) {
+				Size size = this.imageSizes.get(i);
+				Point point = drawPoints.get(i);
+
+				result.width = Math.max(result.width, size.width + Math.abs(point.x));
+				result.height = Math.max(result.height, size.height + Math.abs(point.y));
+			}
+			return result;
+		}
+	}
+}
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/accept_all_changes.gif b/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/accept_all_changes.gif
new file mode 100644
index 0000000..8456759
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/accept_all_changes.gif
Binary files differ
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/accept_change.gif b/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/accept_change.gif
new file mode 100644
index 0000000..23c97f0
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/accept_change.gif
Binary files differ
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/left_to_right.gif b/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/left_to_right.gif
new file mode 100644
index 0000000..29189bb
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/left_to_right.gif
Binary files differ
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/merge_all_to_left.gif b/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/merge_all_to_left.gif
new file mode 100644
index 0000000..e029948
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/merge_all_to_left.gif
Binary files differ
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/merge_all_to_right.gif b/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/merge_all_to_right.gif
new file mode 100644
index 0000000..0659813
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/merge_all_to_right.gif
Binary files differ
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/merge_to_left.gif b/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/merge_to_left.gif
new file mode 100644
index 0000000..db2b1e3
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/merge_to_left.gif
Binary files differ
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/merge_to_right.gif b/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/merge_to_right.gif
new file mode 100644
index 0000000..9ebd50a
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/merge_to_right.gif
Binary files differ
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/next_diff.gif b/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/next_diff.gif
new file mode 100644
index 0000000..79cda13
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/next_diff.gif
Binary files differ
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/prev_diff.gif b/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/prev_diff.gif
new file mode 100644
index 0000000..d5a96ec
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/prev_diff.gif
Binary files differ
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/reject_all_changes.gif b/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/reject_all_changes.gif
new file mode 100644
index 0000000..a873b30
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/reject_all_changes.gif
Binary files differ
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/reject_change.gif b/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/reject_change.gif
new file mode 100644
index 0000000..1aca259
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/reject_change.gif
Binary files differ
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/right_to_left.gif b/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/right_to_left.gif
new file mode 100644
index 0000000..ce33df2
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/icons/full/toolb16/right_to_left.gif
Binary files differ
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/plugin.properties b/plugins/org.eclipse.emf.compare.ide.ui/plugin.properties
index c87ce89..a9c88e2 100644
--- a/plugins/org.eclipse.emf.compare.ide.ui/plugin.properties
+++ b/plugins/org.eclipse.emf.compare.ide.ui/plugin.properties
@@ -14,3 +14,45 @@
 save.model.label = Save Comparison Model
 save.model.tooltip = Save Comparison Model
 save.model.command.name = EMF Compare Save Comparison Model
+
+next.diff = Next Difference
+next.diff.tooltip = Next Difference
+next.diff.command.name = EMF Compare Next Difference
+
+previous.diff = Previous Difference
+previous.diff.tooltip = Previous Difference
+previous.diff.command.name = EMF Compare Previous Difference
+
+accept.change = Accept Change
+accept.change.tooltip = Accept Change
+accept.change.command.name = EMF Compare Accept Change
+
+accept.all.changes = Accept All Non-Conflicting Changes
+accept.all.changes.tooltip = Accept All Non-Conflicting Changes
+accept.all.changes.command.name = EMF Compare Accept All Non-Conflicting Changes
+
+reject.change = Reject Change
+reject.change.tooltip = Reject Change
+reject.change.command.name = EMF Compare Reject Change
+
+reject.all.changes = Reject All Non-Conflicting Changes
+reject.all.changes.tooltip = Reject All Non-Conflicting Changes
+reject.all.changes.command.name = EMF Compare Reject All Non-Conflicting Changes
+
+merged.to.left = Copy Current Change To Left
+merged.to.left.tooltip = Copy Current Change From Right To Left
+merged.to.left.command.name = EMF Compare Copy Current Change To Left
+
+merged.to.right = Copy Current Change To Right
+merged.to.right.tooltip = Copy Current Change From Left To Right
+merged.to.right.command.name = EMF Compare Copy Current Change To Right
+
+merged.all.to.left = Copy All Non-Conflicting Changes To Left
+merged.all.to.left.tooltip = Copy All Non-Conflicting Changes From Right To Left
+merged.all.to.left.command.name = EMF Compare Copy All Non-Conflicting Changes To Left
+
+merged.all.to.right = Copy All Non-Conflicting Changes To Right
+merged.all.to.right.tooltip = Copy All Non-Conflicting Changes From Left To Right
+merged.all.to.right.command.name = EMF Compare Copy All Non-Conflicting Changes To Right
+
+dropdown.tooltip = Select the way of merge
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/plugin.xml b/plugins/org.eclipse.emf.compare.ide.ui/plugin.xml
index ddc8431..124535c 100644
--- a/plugins/org.eclipse.emf.compare.ide.ui/plugin.xml
+++ b/plugins/org.eclipse.emf.compare.ide.ui/plugin.xml
@@ -106,13 +106,176 @@
             allPopups="false"
             locationURI="toolbar:org.eclipse.emf.compare.structuremergeviewer.toolbar">
          <command
+               commandId="org.eclipse.emf.compare.ide.ui.dropdown"
+               icon="icons/full/toolb16/left_to_right.gif"
+               id="org.eclipse.emf.compare.ide.ui.setdropdown"
+               style="pulldown"
+               tooltip="%dropdown.tooltip">
+         </command>
+         <command
+               commandId="org.eclipse.emf.compare.ide.ui.acceptChange"
+               icon="icons/full/toolb16/accept_change.gif"
+               label="%accept.change"
+               style="push"
+               tooltip="%accept.change.tooltip">
+            <visibleWhen
+                  checkEnabled="false">
+               <with
+                     variable="activeEditor">
+                  <test
+                        property="emfcompare.hasReadOnlySide">
+                  </test>
+               </with>
+            </visibleWhen>
+         </command>
+         <command
+               commandId="org.eclipse.emf.compare.ide.ui.acceptAllChanges"
+               icon="icons/full/toolb16/accept_all_changes.gif"
+               label="%accept.all.changes"
+               style="push"
+               tooltip="%accept.all.changes.tooltip">
+            <visibleWhen
+                  checkEnabled="true">
+            </visibleWhen>
+         </command>
+         <command
+               commandId="org.eclipse.emf.compare.ide.ui.mergedToRight"
+               icon="icons/full/toolb16/merge_to_right.gif"
+               label="%merged.to.right"
+               style="push"
+               tooltip="%merged.to.right.tooltip">
+            <visibleWhen
+                  checkEnabled="false">
+               <with
+                     variable="activeEditor">
+                  <test
+                        property="emfcompare.bothSidesWriteable">
+                  </test>
+               </with>
+            </visibleWhen>
+         </command>
+         <command
+               commandId="org.eclipse.emf.compare.ide.ui.mergedAllToRight"
+               icon="icons/full/toolb16/merge_all_to_right.gif"
+               label="%merged.all.to.right"
+               style="push"
+               tooltip="%merged.all.to.right.tooltip">
+            <visibleWhen
+                  checkEnabled="false">
+               <with
+                     variable="activeEditor">
+                  <test
+                        property="emfcompare.bothSidesWriteable">
+                  </test>
+               </with>
+            </visibleWhen>
+         </command>
+         <separator
+               name="org.eclipse.emf.compare.ide.ui.separatorLeftRight"
+               visible="true">
+         </separator>
+         <command
+               commandId="org.eclipse.emf.compare.ide.ui.rejectChange"
+               icon="icons/full/toolb16/reject_change.gif"
+               label="%reject.change"
+               style="push"
+               tooltip="%reject.change.tooltip">
+            <visibleWhen
+                  checkEnabled="false">
+               <with
+                     variable="activeEditor">
+                  <test
+                        property="emfcompare.hasReadOnlySide">
+                  </test>
+               </with>
+            </visibleWhen>
+         </command>
+         <command
+               commandId="org.eclipse.emf.compare.ide.ui.rejectAllChanges"
+               icon="icons/full/toolb16/reject_all_changes.gif"
+               label="%reject.all.changes"
+               style="push"
+               tooltip="%reject.all.changes.tooltip">
+            <visibleWhen
+                  checkEnabled="true">
+            </visibleWhen>
+         </command>
+         <command
+               commandId="org.eclipse.emf.compare.ide.ui.mergedToLeft"
+               icon="icons/full/toolb16/merge_to_left.gif"
+               label="%merged.to.left"
+               style="push"
+               tooltip="%merged.to.left.tooltip">
+            <visibleWhen
+                  checkEnabled="false">
+               <with
+                     variable="activeEditor">
+                  <test
+                        property="emfcompare.bothSidesWriteable">
+                  </test>
+               </with>
+            </visibleWhen>
+         </command>
+         <command
+               commandId="org.eclipse.emf.compare.ide.ui.mergedAllToLeft"
+               icon="icons/full/toolb16/merge_all_to_left.gif"
+               label="%merged.all.to.left"
+               style="push"
+               tooltip="%merged.all.to.left.tooltip">
+            <visibleWhen
+                  checkEnabled="false">
+               <with
+                     variable="activeEditor">
+                  <test
+                        property="emfcompare.bothSidesWriteable">
+                  </test>
+               </with>
+            </visibleWhen>
+         </command>
+         <separator
+               name="org.eclipse.emf.compare.ide.ui.separatorNextPrevDiff"
+               visible="true">
+         </separator>
+         <command
+               commandId="org.eclipse.emf.compare.ide.ui.nextDiff"
+               icon="icons/full/toolb16/next_diff.gif"
+               label="%next.diff"
+               style="push"
+               tooltip="%next.diff.tooltip">
+         </command>
+         <command
+               commandId="org.eclipse.emf.compare.ide.ui.previousDiff"
+               icon="icons/full/toolb16/prev_diff.gif"
+               label="%previous.diff"
+               style="push"
+               tooltip="%previous.diff.tooltip">
+         </command>
+         <separator
+               name="org.eclipse.emf.compare.ide.ui.separatorSave1"
+               visible="true">
+         </separator>
+         <command
                commandId="org.eclipse.emf.compare.ide.ui.saveComparisonModel"
                icon="icons/full/toolb16/saveas_edit.gif"
-               label="%save.model.name"
+               label="%save.model.label"
                style="push"
                tooltip="%save.model.tooltip">
          </command>
       </menuContribution>
+      <menuContribution
+            allPopups="false"
+            locationURI="menu:org.eclipse.emf.compare.ide.ui.setdropdown">
+         <command
+               commandId="org.eclipse.emf.compare.ide.ui.dropdown.ltr"
+               icon="icons/full/toolb16/left_to_right.gif"
+               style="push">
+         </command>
+         <command
+               commandId="org.eclipse.emf.compare.ide.ui.dropdown.rtl"
+               icon="icons/full/toolb16/right_to_left.gif"
+               style="push">
+         </command>
+      </menuContribution>
    </extension>
    <extension
          point="org.eclipse.ui.commands">
@@ -131,6 +294,58 @@
             name="Each Other">
       </command>
       <command
+            id="org.eclipse.emf.compare.ide.ui.dropdown"
+            name="org.eclipse.emf.compare.ide.ui.dropdown">
+      </command>
+      <command
+            id="org.eclipse.emf.compare.ide.ui.dropdown.ltr"
+            name="Left to Right">
+      </command>
+      <command
+            id="org.eclipse.emf.compare.ide.ui.dropdown.rtl"
+            name="Right to Left">
+      </command>
+      <command
+            id="org.eclipse.emf.compare.ide.ui.acceptChange"
+            name="%accept.change.command.name">
+      </command>
+      <command
+            id="org.eclipse.emf.compare.ide.ui.acceptAllChanges"
+            name="%accept.all.changes.command.name">
+      </command>
+      <command
+            id="org.eclipse.emf.compare.ide.ui.rejectChange"
+            name="%reject.change.command.name">
+      </command>
+      <command
+            id="org.eclipse.emf.compare.ide.ui.rejectAllChanges"
+            name="%reject.all.changes.command.name">
+      </command>
+      <command
+            id="org.eclipse.emf.compare.ide.ui.mergedToRight"
+            name="%merged.to.right.command.name">
+      </command>
+      <command
+            id="org.eclipse.emf.compare.ide.ui.mergedAllToRight"
+            name="%merged.all.to.right.command.name">
+      </command>
+      <command
+            id="org.eclipse.emf.compare.ide.ui.mergedToLeft"
+            name="%merged.to.left.command.name">
+      </command>
+      <command
+            id="org.eclipse.emf.compare.ide.ui.mergedAllToLeft"
+            name="%merged.all.to.left.command.name">
+      </command>
+      <command
+            id="org.eclipse.emf.compare.ide.ui.nextDiff"
+            name="%next.diff.command.name">
+      </command>
+      <command
+            id="org.eclipse.emf.compare.ide.ui.previousDiff"
+            name="%previous.diff.command.name">
+      </command>
+      <command
             id="org.eclipse.emf.compare.ide.ui.saveComparisonModel"
             name="%save.model.command.name">
       </command>
@@ -216,6 +431,161 @@
          </activeWhen>
       </handler>
       <handler
+            class="org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.AcceptChange"
+            commandId="org.eclipse.emf.compare.ide.ui.acceptChange">
+         <activeWhen>
+            <with
+                  variable="activeEditor">
+               <test
+                     property="emfcompare.hasReadOnlySide">
+               </test>
+            </with>
+         </activeWhen>
+         <enabledWhen>
+            <with
+                  variable="activeEditor">
+               <and>
+                  <test
+                        property="emfcompare.diffSelected">
+                  </test>
+                  <test
+                        property="emfcompare.leftToRightSide">
+                  </test>
+               </and>
+            </with>
+         </enabledWhen>
+      </handler>
+      <handler
+            class="org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.AcceptAllChanges"
+            commandId="org.eclipse.emf.compare.ide.ui.acceptAllChanges">
+         <enabledWhen>
+            <with
+                  variable="activeEditor">
+               <test
+                     property="emfcompare.hasReadOnlySide">
+               </test>
+            </with>
+         </enabledWhen>
+      </handler>
+      <handler
+            class="org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.RejectChange"
+            commandId="org.eclipse.emf.compare.ide.ui.rejectChange">
+         <activeWhen>
+            <with
+                  variable="activeEditor">
+               <test
+                     property="emfcompare.hasReadOnlySide">
+               </test>
+            </with>
+         </activeWhen>
+         <enabledWhen>
+            <with
+                  variable="activeEditor">
+               <and>
+                  <test
+                        property="emfcompare.diffSelected">
+                  </test>
+                  <test
+                        property="emfcompare.rightToLeftSide">
+                  </test>
+               </and>
+            </with>
+         </enabledWhen>
+      </handler>
+      <handler
+            class="org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.RejectAllChanges"
+            commandId="org.eclipse.emf.compare.ide.ui.rejectAllChanges">
+         <enabledWhen>
+            <with
+                  variable="activeEditor">
+               <test
+                     property="emfcompare.hasReadOnlySide">
+               </test>
+            </with>
+         </enabledWhen>
+      </handler>
+      <handler
+            class="org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.MergedToRight"
+            commandId="org.eclipse.emf.compare.ide.ui.mergedToRight">
+         <activeWhen>
+            <with
+                  variable="activeEditor">
+               <test
+                     property="emfcompare.bothSidesWriteable">
+               </test>
+            </with>
+         </activeWhen>
+         <enabledWhen>
+            <with
+                  variable="activeEditor">
+               <and>
+                  <test
+                        property="emfcompare.diffSelected">
+                  </test>
+                  <test
+                        property="emfcompare.leftToRightSide">
+                  </test>
+               </and>
+            </with>
+         </enabledWhen>
+      </handler>
+      <handler
+            class="org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.MergedAllToRight"
+            commandId="org.eclipse.emf.compare.ide.ui.mergedAllToRight">
+         <activeWhen>
+            <with
+                  variable="activeEditor">
+               <test
+                     property="emfcompare.bothSidesWriteable">
+               </test>
+            </with>
+         </activeWhen>
+      </handler>
+      <handler
+            class="org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.MergedToLeft"
+            commandId="org.eclipse.emf.compare.ide.ui.mergedToLeft">
+         <activeWhen>
+            <with
+                  variable="activeEditor">
+               <test
+                     property="emfcompare.bothSidesWriteable">
+               </test>
+            </with>
+         </activeWhen>
+         <enabledWhen>
+            <with
+                  variable="activeEditor">
+               <and>
+                  <test
+                        property="emfcompare.diffSelected">
+                  </test>
+                  <test
+                        property="emfcompare.rightToLeftSide">
+                  </test>
+               </and>
+            </with>
+         </enabledWhen>
+      </handler>
+      <handler
+            class="org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.MergedAllToLeft"
+            commandId="org.eclipse.emf.compare.ide.ui.mergedAllToLeft">
+         <activeWhen>
+            <with
+                  variable="activeEditor">
+               <test
+                     property="emfcompare.bothSidesWriteable">
+               </test>
+            </with></activeWhen>
+      </handler>
+      <handler
+            class="org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.SelectNextDiff"
+            commandId="org.eclipse.emf.compare.ide.ui.nextDiff">
+      </handler>
+      <handler
+            class="org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.SelectPreviousDiff"
+            commandId="org.eclipse.emf.compare.ide.ui.previousDiff">
+      </handler>
+      <handler
             class="org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.SaveComparisonModel"
             commandId="org.eclipse.emf.compare.ide.ui.saveComparisonModel">
          <enabledWhen>
@@ -228,6 +598,18 @@
          
          </enabledWhen>
       </handler>
+      <handler
+            class="org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.DropDownHandler"
+            commandId="org.eclipse.emf.compare.ide.ui.dropdown">
+      </handler>
+      <handler
+            class="org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.DropDownLeftToRight"
+            commandId="org.eclipse.emf.compare.ide.ui.dropdown.ltr">
+      </handler>
+      <handler
+            class="org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.DropDownRightToLeft"
+            commandId="org.eclipse.emf.compare.ide.ui.dropdown.rtl">
+      </handler>
    </extension>
    <extension
          id="org.eclipse.emf.compare.model.provider"
@@ -259,12 +641,47 @@
    <extension
          point="org.eclipse.core.expressions.propertyTesters">
       <propertyTester
-            class="org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.ModelSaveablePropertyTester"
+            class="org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.propertytester.ModelSaveablePropertyTester"
             id="org.eclipse.emf.compare.ide.ui.modelSaveable"
             namespace="emfcompare"
             properties="isSaveable"
             type="java.lang.Object">
       </propertyTester>
+      <propertyTester
+            class="org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.propertytester.AcceptRejectChangePropertyTester"
+            id="org.eclipse.emf.compare.ide.ui.hasReadOnlySide"
+            namespace="emfcompare"
+            properties="hasReadOnlySide"
+            type="java.lang.Object">
+      </propertyTester>
+      <propertyTester
+            class="org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.propertytester.MergedToPropertyTester"
+            id="org.eclipse.emf.compare.ide.ui.bothSidesWriteable"
+            namespace="emfcompare"
+            properties="bothSidesWriteable"
+            type="java.lang.Object">
+      </propertyTester>
+      <propertyTester
+            class="org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.propertytester.DiffSelectedPropertyTester"
+            id="org.eclipse.emf.compare.ide.ui.diffSelected"
+            namespace="emfcompare"
+            properties="diffSelected"
+            type="java.lang.Object">
+      </propertyTester>
+      <propertyTester
+            class="org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.propertytester.LeftToRightSidePropertyTester"
+            id="org.eclipse.emf.compare.ide.ui.leftToRightSide"
+            namespace="emfcompare"
+            properties="leftToRightSide"
+            type="java.lang.Object">
+      </propertyTester>
+      <propertyTester
+            class="org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.propertytester.RightToLeftSidePropertyTester"
+            id="org.eclipse.emf.compare.ide.ui.rightToLeftSide"
+            namespace="emfcompare"
+            properties="rightToLeftSide"
+            type="java.lang.Object">
+      </propertyTester>
    </extension>
    <extension
          point="org.eclipse.emf.compare.ide.ui.modelResolvers">
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/EMFCompareIDEUIPlugin.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/EMFCompareIDEUIPlugin.java
index 03c8098..c3df552 100644
--- a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/EMFCompareIDEUIPlugin.java
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/EMFCompareIDEUIPlugin.java
@@ -10,6 +10,10 @@
  *******************************************************************************/
 package org.eclipse.emf.compare.ide.ui.internal;
 
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
 import org.eclipse.core.runtime.IExtensionRegistry;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Platform;
@@ -18,6 +22,8 @@
 import org.eclipse.emf.compare.ide.ui.internal.logical.ModelResolverRegistryImpl;
 import org.eclipse.emf.compare.ide.ui.internal.logical.ModelResolverRegistryListener;
 import org.eclipse.emf.compare.rcp.extension.AbstractRegistryEventListener;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.Image;
 import org.eclipse.ui.plugin.AbstractUIPlugin;
 import org.osgi.framework.BundleContext;
 
@@ -42,6 +48,9 @@
 	/** Registry of model resolvers. */
 	private IModelResolverRegistry modelResolverRegistry;
 
+	/** keep track of resources that should be freed when exiting. */
+	private static Map<String, Image> resourcesMapper = new HashMap<String, Image>();
+
 	/** Default constructor. */
 	public EMFCompareIDEUIPlugin() {
 		// Empty constructor
@@ -90,6 +99,62 @@
 	}
 
 	/**
+	 * <p>
+	 * returns a plugin image. The returned image does not need to be explicitly disposed.
+	 * </p>
+	 * 
+	 * @param imagePath
+	 *            : plugin relative path to the image
+	 * @return Image : plugin hosted image
+	 */
+	public static Image getImage(String imagePath) {
+		Image image = resourcesMapper.get(imagePath);
+		if (image == null) {
+			ImageDescriptor imageDescriptor = imageDescriptorFromPlugin(PLUGIN_ID, imagePath);
+			image = imageDescriptor.createImage();
+			resourcesMapper.put(imagePath, image);
+		}
+		return image;
+	}
+
+	/**
+	 * <p>
+	 * returns a plugin image descriptor.
+	 * </p>
+	 * 
+	 * @param imagePath
+	 *            : plugin relative path to the image
+	 * @return ImageDescriptor : image descriptor.
+	 */
+	public static ImageDescriptor getImageDescriptor(String imagePath) {
+		return imageDescriptorFromPlugin(PLUGIN_ID, imagePath);
+	}
+
+	/**
+	 * Dispose image with the given id.
+	 * 
+	 * @param id
+	 *            : dispose system resources associated with the image with the given id.
+	 */
+	public static void disposeImage(String id) {
+		Image image = resourcesMapper.remove(id);
+		if (image != null) {
+			image.dispose();
+		}
+	}
+
+	/**
+	 * dispose system resources associated with cached images.
+	 */
+	public static void disposeCachedImages() {
+		Iterator<Image> iterator = resourcesMapper.values().iterator();
+		while (iterator.hasNext()) {
+			iterator.next().dispose();
+		}
+		resourcesMapper.clear();
+	}
+
+	/**
 	 * Returns the registry containing all known model resolvers.
 	 * 
 	 * @return The registry containing all known model resolvers.
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/actions/expand/ExpandAllModelAction.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/actions/expand/ExpandAllModelAction.java
index ea3ba98..a369418 100644
--- a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/actions/expand/ExpandAllModelAction.java
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/actions/expand/ExpandAllModelAction.java
@@ -37,5 +37,7 @@
 	@Override
 	public void run() {
 		treeViewer.expandToLevel(256);
+		// Workaround to force the redraw of the EMFCompareDiffTreeruler
+		treeViewer.setSelection(treeViewer.getSelection());
 	}
 }
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/contentmergeviewer/EMFCompareContentMergeViewer.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/contentmergeviewer/EMFCompareContentMergeViewer.java
index 28deda7..0ab4775 100644
--- a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/contentmergeviewer/EMFCompareContentMergeViewer.java
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/contentmergeviewer/EMFCompareContentMergeViewer.java
@@ -23,11 +23,8 @@
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.eclipse.compare.CompareConfiguration;
-import org.eclipse.compare.CompareNavigator;
-import org.eclipse.compare.ICompareNavigator;
 import org.eclipse.compare.contentmergeviewer.ContentMergeViewer;
 import org.eclipse.compare.internal.CompareHandlerService;
-import org.eclipse.compare.internal.Utilities;
 import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.emf.common.command.Command;
 import org.eclipse.emf.common.command.CommandStackListener;
@@ -51,8 +48,6 @@
 import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.filters.IDifferenceFilter;
 import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.filters.impl.CascadingDifferencesFilter;
 import org.eclipse.emf.compare.utils.EMFComparePredicates;
-import org.eclipse.jface.action.Action;
-import org.eclipse.jface.action.ActionContributionItem;
 import org.eclipse.jface.action.ToolBarManager;
 import org.eclipse.jface.util.IPropertyChangeListener;
 import org.eclipse.jface.util.PropertyChangeEvent;
@@ -91,10 +86,6 @@
 
 	private IMergeViewer fRight;
 
-	private ActionContributionItem fCopyDiffLeftToRightItem;
-
-	private ActionContributionItem fCopyDiffRightToLeftItem;
-
 	private final AtomicBoolean fSyncingSelections = new AtomicBoolean(false);
 
 	private EMFCompareColor fColors;
@@ -292,66 +283,6 @@
 					"toolbar:org.eclipse.emf.compare.contentmergeviewer.toolbar");
 		}
 
-		// Copy actions
-		CompareConfiguration cc = getCompareConfiguration();
-
-		if (cc.isRightEditable()) {
-			Action copyLeftToRight = new Action() {
-				@Override
-				public void run() {
-					copyDiff(true);
-					// Select next diff
-					navigate(true);
-				}
-			};
-			Utilities.initAction(copyLeftToRight, getResourceBundle(), "action.CopyDiffLeftToRight."); //$NON-NLS-1$
-			copyLeftToRight.setEnabled(false);
-			fCopyDiffLeftToRightItem = new ActionContributionItem(copyLeftToRight);
-			fCopyDiffLeftToRightItem.setVisible(true);
-			toolBarManager.appendToGroup("merge", fCopyDiffLeftToRightItem); //$NON-NLS-1$
-			getHandlerService().registerAction(copyLeftToRight, "org.eclipse.compare.copyLeftToRight"); //$NON-NLS-1$
-		}
-
-		if (cc.isLeftEditable()) {
-			Action copyRightToLeft = new Action() {
-				@Override
-				public void run() {
-					copyDiff(false);
-					// Select next diff
-					navigate(true);
-				}
-			};
-			Utilities.initAction(copyRightToLeft, getResourceBundle(), "action.CopyDiffRightToLeft."); //$NON-NLS-1$
-			copyRightToLeft.setEnabled(false);
-			fCopyDiffRightToLeftItem = new ActionContributionItem(copyRightToLeft);
-			fCopyDiffRightToLeftItem.setVisible(true);
-			toolBarManager.appendToGroup("merge", fCopyDiffRightToLeftItem); //$NON-NLS-1$
-			getHandlerService().registerAction(copyRightToLeft, "org.eclipse.compare.copyRightToLeft"); //$NON-NLS-1$
-		}
-
-		// Navigation
-		final Action nextDiff = new Action() {
-			@Override
-			public void run() {
-				navigate(true);
-			}
-		};
-		Utilities.initAction(nextDiff, getResourceBundle(), "action.NextDiff.");
-		ActionContributionItem contributionNextDiff = new ActionContributionItem(nextDiff);
-		contributionNextDiff.setVisible(true);
-		toolBarManager.appendToGroup("navigation", contributionNextDiff);
-
-		final Action previousDiff = new Action() {
-			@Override
-			public void run() {
-				navigate(false);
-			}
-		};
-		Utilities.initAction(previousDiff, getResourceBundle(), "action.PrevDiff.");
-		ActionContributionItem contributionPreviousDiff = new ActionContributionItem(previousDiff);
-		contributionPreviousDiff.setVisible(true);
-		toolBarManager.appendToGroup("navigation", contributionPreviousDiff);
-
 		undoAction = new UndoAction(getEditingDomain());
 		redoAction = new RedoAction(getEditingDomain());
 
@@ -416,29 +347,6 @@
 	}
 
 	/**
-	 * Called by the framework to navigate to the next (or previous) difference. This will open the content
-	 * viewer for the next (or previous) diff displayed in the structure viewer.
-	 * 
-	 * @param next
-	 *            <code>true</code> if we are to open the next structure viewer's diff, <code>false</code> if
-	 *            we should go to the previous instead.
-	 */
-	protected void navigate(boolean next) {
-		final Control control = getControl();
-		if (control != null && !control.isDisposed()) {
-			final ICompareNavigator navigator = getCompareConfiguration().getContainer().getNavigator();
-			if (navigator instanceof CompareNavigator && ((CompareNavigator)navigator).hasChange(next)) {
-				navigator.selectChange(next);
-			}
-		}
-	}
-
-	/**
-	 * 
-	 */
-	protected abstract void copyDiff(boolean leftToRight);
-
-	/**
 	 * {@inheritDoc}
 	 * 
 	 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#handleResizeAncestor(int, int, int, int)
@@ -568,36 +476,6 @@
 	}
 
 	/**
-	 * {@inheritDoc}
-	 * 
-	 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#updateToolItems()
-	 */
-	@Override
-	protected void updateToolItems() {
-		super.updateToolItems();
-
-		manageCopyActionsActivation();
-	}
-
-	protected void manageCopyActionsActivation() {
-		Diff diff = getDiffFrom(getRightMergeViewer());
-		if (diff == null) {
-			diff = getDiffFrom(getLeftMergeViewer());
-		}
-		boolean enableCopy = false;
-		if (diff != null) {
-			enableCopy = diff.getState() == DifferenceState.UNRESOLVED;
-		}
-
-		if (fCopyDiffLeftToRightItem != null) {
-			fCopyDiffLeftToRightItem.getAction().setEnabled(enableCopy);
-		}
-		if (fCopyDiffRightToLeftItem != null) {
-			fCopyDiffRightToLeftItem.getAction().setEnabled(enableCopy);
-		}
-	}
-
-	/**
 	 * Checks the element selected in the given viewer in order to determine whether it can be adapted into a
 	 * Diff.
 	 * 
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/contentmergeviewer/table/TableContentMergeViewer.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/contentmergeviewer/table/TableContentMergeViewer.java
index 68a7c51..45ef92e 100644
--- a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/contentmergeviewer/table/TableContentMergeViewer.java
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/contentmergeviewer/table/TableContentMergeViewer.java
@@ -10,14 +10,9 @@
  *******************************************************************************/
 package org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.table;
 
-import static com.google.common.collect.Iterables.addAll;
-
-import java.util.ArrayList;
-import java.util.List;
 import java.util.ResourceBundle;
 
 import org.eclipse.compare.CompareConfiguration;
-import org.eclipse.emf.common.command.Command;
 import org.eclipse.emf.compare.Diff;
 import org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.EMFCompareContentMergeViewer;
 import org.eclipse.emf.compare.internal.utils.ComparisonUtil;
@@ -35,9 +30,7 @@
 import org.eclipse.emf.edit.provider.resource.ResourceItemProviderAdapterFactory;
 import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
 import org.eclipse.jface.viewers.ArrayContentProvider;
-import org.eclipse.jface.viewers.ISelection;
 import org.eclipse.jface.viewers.ISelectionChangedListener;
-import org.eclipse.jface.viewers.IStructuredSelection;
 import org.eclipse.jface.viewers.SelectionChangedEvent;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.DisposeEvent;
@@ -109,40 +102,6 @@
 	/**
 	 * {@inheritDoc}
 	 * 
-	 * @see org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.EMFCompareContentMergeViewer#copyDiff(boolean)
-	 */
-	@Override
-	protected void copyDiff(boolean leftToRight) {
-		final Diff diffToCopy = getDiffToCopy(getRightMergeViewer());
-		if (diffToCopy != null) {
-			List<Diff> diffsToCopy = new ArrayList<Diff>();
-			diffsToCopy.add(diffToCopy);
-			if (isSubDiffFilterActive()) {
-				addAll(diffsToCopy, ComparisonUtil.getSubDiffs(leftToRight).apply(diffToCopy));
-			}
-			Command copyCommand = getEditingDomain().createCopyCommand(diffsToCopy, leftToRight,
-					EMFCompareRCPPlugin.getDefault().getMergerRegistry());
-
-			getEditingDomain().getCommandStack().execute(copyCommand);
-			refresh();
-		}
-	}
-
-	private Diff getDiffToCopy(AbstractMergeViewer abstractMergeViewer) {
-		Diff diffToCopy = null;
-		ISelection selection = abstractMergeViewer.getSelection();
-		if (selection instanceof IStructuredSelection && !selection.isEmpty()) {
-			Object firstElement = ((IStructuredSelection)selection).getFirstElement();
-			if (firstElement instanceof IMergeViewerItem) {
-				diffToCopy = ((IMergeViewerItem)firstElement).getDiff();
-			}
-		}
-		return diffToCopy;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 * 
 	 * @see org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.EMFCompareContentMergeViewer#getLeftMergeViewer()
 	 */
 	@Override
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 d3f6cd7..db0483d 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
@@ -11,20 +11,17 @@
 package org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.tree;
 
 import static com.google.common.base.Predicates.equalTo;
-import static com.google.common.collect.Iterables.addAll;
 import static com.google.common.collect.Iterables.filter;
 import static com.google.common.collect.Lists.newArrayList;
 
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 
-import java.util.ArrayList;
 import java.util.List;
 import java.util.ResourceBundle;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.eclipse.compare.CompareConfiguration;
-import org.eclipse.emf.common.command.Command;
 import org.eclipse.emf.compare.Diff;
 import org.eclipse.emf.compare.DifferenceKind;
 import org.eclipse.emf.compare.Match;
@@ -50,9 +47,7 @@
 import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
 import org.eclipse.jface.viewers.IContentProvider;
 import org.eclipse.jface.viewers.ILabelProvider;
-import org.eclipse.jface.viewers.ISelection;
 import org.eclipse.jface.viewers.ISelectionChangedListener;
-import org.eclipse.jface.viewers.IStructuredSelection;
 import org.eclipse.jface.viewers.SelectionChangedEvent;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.DisposeEvent;
@@ -167,45 +162,6 @@
 	/**
 	 * {@inheritDoc}
 	 * 
-	 * @see org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.EMFCompareContentMergeViewer#copyDiff(boolean)
-	 */
-	@Override
-	protected void copyDiff(boolean leftToRight) {
-		final Diff diffToCopy;
-		if (leftToRight) {
-			diffToCopy = getDiffToCopy(getLeftMergeViewer());
-		} else {
-			diffToCopy = getDiffToCopy(getRightMergeViewer());
-		}
-		if (diffToCopy != null) {
-			List<Diff> diffsToCopy = new ArrayList<Diff>();
-			diffsToCopy.add(diffToCopy);
-			if (isSubDiffFilterActive()) {
-				addAll(diffsToCopy, ComparisonUtil.getSubDiffs(leftToRight).apply(diffToCopy));
-			}
-			Command copyCommand = getEditingDomain().createCopyCommand(diffsToCopy, leftToRight,
-					EMFCompareRCPPlugin.getDefault().getMergerRegistry());
-
-			getEditingDomain().getCommandStack().execute(copyCommand);
-			refresh();
-		}
-	}
-
-	private Diff getDiffToCopy(AbstractMergeViewer abstractMergeViewer) {
-		Diff diffToCopy = null;
-		ISelection selection = abstractMergeViewer.getSelection();
-		if (selection instanceof IStructuredSelection && !selection.isEmpty()) {
-			Object firstElement = ((IStructuredSelection)selection).getFirstElement();
-			if (firstElement instanceof IMergeViewerItem) {
-				diffToCopy = ((IMergeViewerItem)firstElement).getDiff();
-			}
-		}
-		return diffToCopy;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 * 
 	 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#getContents(boolean)
 	 */
 	@Override
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/AbstractViewerWrapper.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/AbstractViewerWrapper.java
new file mode 100644
index 0000000..41b62f0
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/AbstractViewerWrapper.java
@@ -0,0 +1,369 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer;
+
+import java.util.List;
+
+import org.eclipse.compare.CompareConfiguration;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.IContentProvider;
+import org.eclipse.jface.viewers.IOpenListener;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredViewer;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Widget;
+
+/**
+ * A control that wrapped a StructuredViewer and another control.
+ * 
+ * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
+ */
+public abstract class AbstractViewerWrapper extends StructuredViewer {
+
+	/** The StructuredViewer associated with this wrapper. */
+	private StructuredViewer fViewer;
+
+	/** A composite control that will contains all sub-control of this wrapper. */
+	private final Control fControl;
+
+	/** The selection changed listener. */
+	private ISelectionChangedListener fWrappedViewerListener;
+
+	/** The compare configuration object. */
+	private final CompareConfiguration fConfiguration;
+
+	/**
+	 * Constructor.
+	 * 
+	 * @param parent
+	 *            the SWT parent control under which to create the viewer's SWT control.
+	 * @param config
+	 *            a compare configuration the newly created viewer might want to use.
+	 */
+	public AbstractViewerWrapper(Composite parent, CompareConfiguration config) {
+		fConfiguration = config;
+		fControl = createControl(parent, config);
+		hookControl(fControl);
+		fWrappedViewerListener = new ISelectionChangedListener() {
+			public void selectionChanged(SelectionChangedEvent event) {
+				fireSelectionChanged(new SelectionChangedEvent(AbstractViewerWrapper.this, event
+						.getSelection()));
+			}
+		};
+		fViewer.addSelectionChangedListener(fWrappedViewerListener);
+
+		setLabelProvider(fViewer.getLabelProvider());
+		setContentProvider(fViewer.getContentProvider());
+	}
+
+	/**
+	 * Should call {@link #setViewer(org.eclipse.jface.viewers.Viewer)}.
+	 * 
+	 * @param parent
+	 *            the SWT control under which to create the viewer.
+	 * @param config
+	 *            the compare configuration object.
+	 * @return a composite control that will contains all sub-control of this wrapper.
+	 */
+	protected abstract Control createControl(Composite parent, CompareConfiguration config);
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.jface.viewers.StructuredViewer#addOpenListener(IOpenListener)
+	 */
+	@Override
+	public void addOpenListener(IOpenListener listener) {
+		fViewer.addOpenListener(listener);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.jface.viewers.StructuredViewer#removeOpenListener(IOpenListener)
+	 */
+	@Override
+	public void removeOpenListener(IOpenListener listener) {
+		fViewer.removeOpenListener(listener);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.jface.viewers.StructuredViewer#update(Object, String[])
+	 */
+	@Override
+	public void update(Object element, String[] properties) {
+		fViewer.update(element, properties);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.jface.viewers.Viewer#getControl()
+	 */
+	@Override
+	public Control getControl() {
+		return fControl;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.jface.viewers.ContentViewer#getInput()
+	 */
+	@Override
+	public Object getInput() {
+		return super.getInput();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.jface.viewers.StructuredViewer#getSelection()
+	 */
+	@Override
+	public ISelection getSelection() {
+		return fViewer.getSelection();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.jface.viewers.StructuredViewer#refresh()
+	 */
+	@Override
+	public void refresh() {
+		fViewer.refresh();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.jface.viewers.StructuredViewer#refresh(boolean)
+	 */
+	@Override
+	public void refresh(boolean updateLabels) {
+		fViewer.refresh(updateLabels);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.jface.viewers.StructuredViewer#setSelection(ISelection, boolean)
+	 */
+	@Override
+	public void setSelection(ISelection selection, boolean reveal) {
+		fViewer.setSelection(selection, reveal);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.jface.viewers.StructuredViewer#reveal(Object)
+	 */
+	@Override
+	public void reveal(Object element) {
+		fViewer.reveal(element);
+
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.jface.viewers.ContentViewer#getContentProvider()
+	 */
+	@Override
+	public IContentProvider getContentProvider() {
+		return super.getContentProvider();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.jface.viewers.ContentViewer#setContentProvider(IContentProvider)
+	 */
+	@Override
+	public void setContentProvider(IContentProvider provider) {
+		super.setContentProvider(provider);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.jface.viewers.ContentViewer#getLabelProvider()
+	 */
+	@Override
+	public IBaseLabelProvider getLabelProvider() {
+		return super.getLabelProvider();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.jface.viewers.ContentViewer#setLabelProvider(IBaseLabelProvider)
+	 */
+	@Override
+	public void setLabelProvider(IBaseLabelProvider labelProvider) {
+		super.setLabelProvider(labelProvider);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.jface.viewers.StructuredViewer#doFindInputItem(Object)
+	 */
+	@Override
+	protected Widget doFindInputItem(Object element) {
+		/*
+		 * Nothing to do here. The method doFindInputItem(Object element) is only called by
+		 * StructuredViewer#update(Object element, String[] properties), which is override in this class.
+		 */
+		return null;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.jface.viewers.StructuredViewer#doFindItem(Object)
+	 */
+	@Override
+	protected Widget doFindItem(Object element) {
+		/*
+		 * Nothing to do here. The method doFindItem(Object element) is only called by
+		 * StructuredViewer#update(Object element, String[] properties), which is override in this class.
+		 */
+		return null;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.jface.viewers.StructuredViewer#doUpdateItem(Widget, Object, boolean)
+	 */
+	@Override
+	protected void doUpdateItem(Widget item, Object element, boolean fullMap) {
+		/*
+		 * Nothing to do here. The method doUpdateItem(Widget item, Object element, boolean fullMap) is only
+		 * called by StructuredViewer#update(Object element, String[] properties), which is override in this
+		 * class.
+		 */
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.jface.viewers.StructuredViewer#getSelectionFromWidget()
+	 */
+	@Override
+	protected List getSelectionFromWidget() {
+		/*
+		 * Nothing to do here. The method getSelectionFromWidget() is only called by
+		 * StructuredViewer#getSelection(), which is override in this class.
+		 */
+		return null;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.jface.viewers.StructuredViewer#internalRefresh(Object)
+	 */
+	@Override
+	protected void internalRefresh(Object element) {
+		/*
+		 * Nothing to do here. The method internalRefresh(Object element) is only called by
+		 * StructuredViewer#internalRefresh(Object element, boolean updateLabels), which is override in
+		 * AbstractTreeViewer.
+		 */
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.jface.viewers.StructuredViewer#setSelectionToWidget(List, boolean)
+	 */
+	@Override
+	protected void setSelectionToWidget(List l, boolean reveal) {
+		/*
+		 * Nothing to do here. The method setSelectionToWidget(List l, boolean reveal) is only called by
+		 * StructuredViewer#setSelectionToWidget(ISelection selection, boolean reveal), which is override in
+		 * AbstractTreeViewer.
+		 */
+	}
+
+	/**
+	 * Adds event listener hooks to the given control.
+	 * <p>
+	 * All subclasses must call this method when their control is first established.
+	 * </p>
+	 * <p>
+	 * The <code>ContentViewer</code> implementation of this method hooks dispose events for the given
+	 * control. Subclasses may override if they need to add other control hooks; however,
+	 * <code>super.hookControl</code> must be invoked.
+	 * </p>
+	 * 
+	 * @param control
+	 *            the control
+	 */
+	@Override
+	protected void hookControl(Control control) {
+		control.addDisposeListener(new DisposeListener() {
+			public void widgetDisposed(DisposeEvent event) {
+				handleDispose(event);
+			}
+		});
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.jface.viewers.StructuredViewer#handleDispose(DisposeEvent)
+	 */
+	@Override
+	protected void handleDispose(DisposeEvent event) {
+		fViewer.removeSelectionChangedListener(fWrappedViewerListener);
+	}
+
+	/**
+	 * Returns the {@link StructuredViewer} associated with this wrapper.
+	 * 
+	 * @return a StructuredViewer.
+	 */
+	protected StructuredViewer getViewer() {
+		return fViewer;
+	}
+
+	/**
+	 * Set the {@link StructuredViewer} of this wrapper.
+	 * 
+	 * @param fViewer
+	 *            a StructuredViewer.
+	 */
+	protected void setViewer(StructuredViewer viewer) {
+		fViewer = viewer;
+	}
+
+	/**
+	 * Get the compare configuration object.
+	 * 
+	 * @return the compare configuration object.
+	 */
+	public CompareConfiguration getCompareConfiguration() {
+		return fConfiguration;
+	}
+
+}
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/EMFCompareDiffTreeRuler.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/EMFCompareDiffTreeRuler.java
new file mode 100644
index 0000000..7cefbdb
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/EMFCompareDiffTreeRuler.java
@@ -0,0 +1,631 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Sets;
+
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.compare.CompareConfiguration;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.emf.common.notify.Adapter;
+import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.emf.compare.Diff;
+import org.eclipse.emf.compare.internal.utils.DiffUtil;
+import org.eclipse.emf.compare.rcp.ui.internal.EMFCompareConstants;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.filters.IDifferenceFilter;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TreePath;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.MouseMoveListener;
+import org.eclipse.swt.events.MouseTrackListener;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Cursor;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.ScrollBar;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+
+/**
+ * A specific canvas that must be presented next to a TreeViewer. It shows consequences of a Diff (required
+ * and unmergeable differences), as in the TreeViewer, but in a compact format (small colored rectangles) and
+ * with links to respectives Treeitems.
+ * 
+ * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
+ */
+public class EMFCompareDiffTreeRuler extends Canvas {
+
+	/** The vertical offset for an annotation. */
+	private static final int Y_OFFSET = 6;
+
+	/** The height of an annotation. */
+	private static final int ANNOTATION_HEIGHT = 5;
+
+	/** The TreeViewer associated with this Treeruler. */
+	private final TreeViewer fTreeViewer;
+
+	/** The color a required diff. */
+	private final Color requiredDiffFillColor;
+
+	/** The color of an unmergeable diff. **/
+	private final Color unmergeableDiffFillColor;
+
+	/** The border color a required diff. */
+	private final Color requiredDiffBorderColor;
+
+	/** The border color an unmergeable diff. */
+	private final Color unmergeableDiffBorderColor;
+
+	/** The width of this tree ruler. */
+	private final int fWidth;
+
+	/** The list of required Diff that need to be shown in the TreeRuler. */
+	private Set<Diff> requires;
+
+	/** The list of unmergeables Diff that need to be shown in the TreeRuler. */
+	private Set<Diff> unmergeables;
+
+	/** A map that links a diff with tree items. */
+	private Multimap<Diff, TreeItem> diffItems;
+
+	/** A map that links a rectangle with a tree item. */
+	private Map<Rectangle, TreeItem> annotationsData;
+
+	/** The paint listener. */
+	private PaintListener paintListener;
+
+	/** The mouse click listener. */
+	private MouseListener mouseClickListener;
+
+	/** The mouse move listener. */
+	private MouseMoveListener mouseMoveListener;
+
+	/** The mouse track listener. */
+	private MouseTrackListener mouseTrackListener;
+
+	/** The last cursor used. */
+	private Cursor lastCursor;
+
+	/** The configuration for this control. */
+	private CompareConfiguration fConfiguration;
+
+	/** The selected diff in the Treeviewer associated with this Treeruler. */
+	private Diff selectedDiff;
+
+	/**
+	 * Constructor.
+	 * 
+	 * @param parent
+	 *            the control's parent.
+	 * @param style
+	 *            the style of the control to construct.
+	 * @param width
+	 *            the control's width.
+	 * @param treeViewer
+	 *            the TreeViewer associated with this control.
+	 * @param config
+	 *            the configuration for this control.
+	 */
+	EMFCompareDiffTreeRuler(Composite parent, int style, int width, TreeViewer treeViewer,
+			CompareConfiguration config) {
+		super(parent, style);
+		fWidth = width;
+		fTreeViewer = treeViewer;
+		fConfiguration = config;
+
+		requiredDiffFillColor = JFaceResources.getColorRegistry().get(
+				EMFCompareDiffTreeViewer.REQUIRED_DIFF_COLOR);
+		requiredDiffBorderColor = JFaceResources.getColorRegistry().get(
+				EMFCompareDiffTreeViewer.REQUIRED_DIFF_BORDER_COLOR);
+		unmergeableDiffFillColor = JFaceResources.getColorRegistry().get(
+				EMFCompareDiffTreeViewer.UNMERGEABLE_DIFF_COLOR);
+		unmergeableDiffBorderColor = JFaceResources.getColorRegistry().get(
+				EMFCompareDiffTreeViewer.UNMERGEABLE_DIFF_BORDER_COLOR);
+
+		requires = Sets.newHashSet();
+		unmergeables = Sets.newHashSet();
+		diffItems = HashMultimap.create();
+		annotationsData = Maps.newHashMap();
+
+		paintListener = new PaintListener() {
+			public void paintControl(PaintEvent e) {
+				handlePaintEvent(e);
+			}
+		};
+		addPaintListener(paintListener);
+
+		mouseClickListener = new MouseListener() {
+
+			public void mouseUp(MouseEvent e) {
+				handleMouseClickEvent(e);
+			}
+
+			public void mouseDown(MouseEvent e) {
+				// Do nothing.
+			}
+
+			public void mouseDoubleClick(MouseEvent e) {
+				// Do nothing.
+			}
+		};
+		addMouseListener(mouseClickListener);
+
+		mouseMoveListener = new MouseMoveListener() {
+
+			public void mouseMove(MouseEvent e) {
+				handleMouveMoveEvent(e);
+			}
+		};
+		addMouseMoveListener(mouseMoveListener);
+
+		mouseTrackListener = new MouseTrackListener() {
+
+			public void mouseHover(MouseEvent e) {
+				handleMouseHoverEvent(e);
+			}
+
+			public void mouseExit(MouseEvent e) {
+				// Do nothing.
+			}
+
+			public void mouseEnter(MouseEvent e) {
+				// Do nothing.
+			}
+		};
+		addMouseTrackListener(mouseTrackListener);
+	}
+
+	/**
+	 * Compute consequences (required and unmergeable differences) when selection changed occurs.
+	 * 
+	 * @param event
+	 *            the SelectionChangedEvent event.
+	 */
+	public void selectionChanged(SelectionChangedEvent event) {
+		clearAllData();
+		ISelection selection = event.getSelection();
+		if (selection instanceof IStructuredSelection) {
+			Object element = ((IStructuredSelection)selection).getFirstElement();
+			if (element instanceof Adapter) {
+				Object target = ((Adapter)element).getTarget();
+				if (target instanceof Diff) {
+					selectedDiff = (Diff)target;
+					computeConsequences();
+				}
+			}
+		}
+	}
+
+	/**
+	 * Compute consequences (required and unmergeable differences).
+	 */
+	public void computeConsequences() {
+		clearAllData();
+		if (selectedDiff != null) {
+			Boolean leftToRight = (Boolean)fConfiguration.getProperty(EMFCompareConstants.MERGE_WAY);
+			boolean ltr = false;
+			if (leftToRight == null || leftToRight.booleanValue()) {
+				ltr = true;
+			}
+			boolean leftEditable = fConfiguration.isLeftEditable();
+			boolean rightEditable = fConfiguration.isRightEditable();
+			boolean bothSidesEditable = leftEditable && rightEditable;
+			if ((ltr && (leftEditable || bothSidesEditable)) || (!ltr && (rightEditable && !leftEditable))) {
+				requires = DiffUtil.getRequires(selectedDiff, true, selectedDiff.getSource());
+				unmergeables = DiffUtil.getUnmergeables(selectedDiff, true);
+			} else {
+				requires = DiffUtil.getRequires(selectedDiff, false, selectedDiff.getSource());
+				unmergeables = DiffUtil.getUnmergeables(selectedDiff, false);
+			}
+			associateTreeItems(Lists.newLinkedList(Iterables.concat(requires, unmergeables)));
+		}
+	}
+
+	/**
+	 * Maps tree items with the given list of diffs.
+	 * 
+	 * @param diffs
+	 *            the given list of diffs.
+	 */
+	private void associateTreeItems(List<Diff> diffs) {
+		Tree tree = fTreeViewer.getTree();
+		for (TreeItem item : tree.getItems()) {
+			associateTreeItem(item, diffs);
+		}
+	}
+
+	/**
+	 * Maps, if necessary, the given tree item and all his children with the given list of diffs.
+	 * 
+	 * @param item
+	 *            the given tree item.
+	 * @param diffs
+	 *            the given list of diffs.
+	 */
+	private void associateTreeItem(TreeItem item, List<Diff> diffs) {
+		Object data = item.getData();
+		if (data instanceof Adapter) {
+			Notifier target = ((Adapter)data).getTarget();
+			if (diffs.contains(target)) {
+				diffItems.put((Diff)target, item);
+			}
+		}
+		for (TreeItem child : item.getItems()) {
+			associateTreeItem(child, diffs);
+		}
+	}
+
+	/**
+	 * Clear all data.
+	 */
+	private void clearAllData() {
+		requires.clear();
+		unmergeables.clear();
+		diffItems.clear();
+		annotationsData.clear();
+	}
+
+	/**
+	 * Handles the dispose event on this control.
+	 */
+	public void handleDispose() {
+		removeMouseTrackListener(mouseTrackListener);
+		removeMouseMoveListener(mouseMoveListener);
+		removeMouseListener(mouseClickListener);
+		removePaintListener(paintListener);
+	}
+
+	/**
+	 * Handles the paint event.
+	 * 
+	 * @param e
+	 *            the paint event.
+	 */
+	private void handlePaintEvent(PaintEvent e) {
+		annotationsData.clear();
+		Collection<IDifferenceFilter> filters = (Collection<IDifferenceFilter>)fConfiguration
+				.getProperty(EMFCompareConstants.SELECTED_FILTERS);
+		Collection<? extends Diff> filteredRequires = filteredDiffs(requires, filters);
+		Collection<? extends Diff> filteredUnmergeables = filteredDiffs(unmergeables, filters);
+		for (Diff diff : filteredRequires) {
+			for (TreeItem item : diffItems.get(diff)) {
+				createAnnotation(e, diff, item, requiredDiffFillColor, requiredDiffBorderColor);
+			}
+		}
+		for (Diff diff : filteredUnmergeables) {
+			for (TreeItem item : diffItems.get(diff)) {
+				createAnnotation(e, diff, item, unmergeableDiffFillColor, unmergeableDiffBorderColor);
+			}
+		}
+	}
+
+	/**
+	 * Handles the mouse click event.
+	 * 
+	 * @param e
+	 *            the mouse click event.
+	 */
+	private void handleMouseClickEvent(MouseEvent e) {
+		for (Rectangle rect : annotationsData.keySet()) {
+			if (e.y >= rect.y && e.y <= rect.y + ANNOTATION_HEIGHT) {
+				TreeItem item = annotationsData.get(rect);
+				TreePath treePath = getTreePathFromItem(item);
+				fTreeViewer.expandToLevel(treePath, 0);
+				fTreeViewer.reveal(treePath);
+				if (isVerticalScrollBarEnabled()) {
+					TreeItem previousItem = getPreviousItem(item, 2);
+					fTreeViewer.getTree().setTopItem(previousItem);
+				}
+				redraw();
+				return;
+			}
+		}
+	}
+
+	/**
+	 * Handles the mouse move event.
+	 * 
+	 * @param e
+	 *            the mouse move event.
+	 */
+	private void handleMouveMoveEvent(MouseEvent e) {
+		Cursor cursor = null;
+		for (Rectangle rect : annotationsData.keySet()) {
+			if (e.y >= rect.y && e.y <= rect.y + ANNOTATION_HEIGHT) {
+				cursor = e.display.getSystemCursor(SWT.CURSOR_HAND);
+				break;
+			}
+		}
+		if (cursor != lastCursor) {
+			setCursor(cursor);
+			lastCursor = cursor;
+		}
+	}
+
+	/**
+	 * Handles the mouse hover event.
+	 * 
+	 * @param e
+	 *            the mouve hover event.
+	 */
+	private void handleMouseHoverEvent(MouseEvent e) {
+		String overview = ""; //$NON-NLS-1$
+		for (Rectangle rect : annotationsData.keySet()) {
+			if (e.y >= rect.y && e.y <= rect.y + ANNOTATION_HEIGHT) {
+				TreeItem item = annotationsData.get(rect);
+				overview = item.getText();
+				break;
+			}
+		}
+		setToolTipText(overview);
+	}
+
+	/**
+	 * Create an annotation in the tree ruler.
+	 * 
+	 * @param e
+	 *            the PaintEvent.
+	 * @param diff
+	 *            the Diff for which we want to create the annotation.
+	 * @param treeItem
+	 *            the tree item associated with the diff.
+	 * @param fill
+	 *            the annotation's fill color.
+	 * @param border
+	 *            the annotation's border color.
+	 */
+	private void createAnnotation(PaintEvent e, Diff diff, TreeItem treeItem, Color fill, Color border) {
+		TreeItem item = getDeepestVisibleTreeItem(treeItem, treeItem);
+		if (item != null) {
+			int y = item.getBounds().y;
+			int yRuler = getSize().y;
+			if (isVerticalScrollBarEnabled()) {
+				int yMin = Math.abs(item.getParent().getItems()[0].getBounds().y);
+				int yMax = getLastVisibleItem().getBounds().y;
+				int realYMax = yMax + yMin;
+				y = (y + yMin) * yRuler / realYMax;
+				if (y + Y_OFFSET + ANNOTATION_HEIGHT > yRuler) {
+					y = yRuler - Y_OFFSET - ANNOTATION_HEIGHT;
+				}
+			}
+			Rectangle rect = drawAnnotation(e.gc, 2, y + Y_OFFSET, fWidth - 5, ANNOTATION_HEIGHT, fill,
+					border);
+			annotationsData.put(rect, treeItem);
+		}
+	}
+
+	/**
+	 * Returns the full tree path of the given tree item.
+	 * 
+	 * @param item
+	 *            the given tree item.
+	 * @return the full tree path of the given tree item.
+	 */
+	private TreePath getTreePathFromItem(TreeItem item) {
+		LinkedList<Object> segments = Lists.newLinkedList();
+		TreeItem parent = item;
+		while (parent != null) {
+			Object segment = parent.getData();
+			Assert.isNotNull(segment);
+			segments.addFirst(segment);
+			parent = parent.getParentItem();
+		}
+		return new TreePath(segments.toArray());
+	}
+
+	/**
+	 * Checks if the vertical scroll bar of the tree viewer associated with this tree ruler is activated and
+	 * enabled.
+	 * 
+	 * @return true if the vertical scroll bar is activated and enabled, false otherwise.
+	 */
+	private boolean isVerticalScrollBarEnabled() {
+		ScrollBar verticalBar = fTreeViewer.getTree().getVerticalBar();
+		if (verticalBar != null) {
+			return verticalBar.isVisible() && verticalBar.isEnabled();
+		}
+		return false;
+	}
+
+	/**
+	 * Draw an annotation (a Rectangle) on this tree ruler.
+	 * 
+	 * @param gc
+	 *            the swt GC.
+	 * @param x
+	 *            the x coordinate of the origin of the annotation.
+	 * @param y
+	 *            the y coordinate of the origin of the annotation.
+	 * @param w
+	 *            the width of the annotation.
+	 * @param h
+	 *            the height of the annotation.
+	 * @param fill
+	 *            the annotation's fill color.
+	 * @param border
+	 *            the annotation's border color.
+	 * @return the annotation (a Rectangle).
+	 */
+	private Rectangle drawAnnotation(GC gc, int x, int y, int w, int h, Color fill, Color border) {
+		Rectangle rect = new Rectangle(x, y, w, h);
+		gc.setBackground(fill);
+		gc.fillRectangle(rect);
+
+		gc.setForeground(border);
+		gc.drawRectangle(x, y, w, h);
+		return rect;
+	}
+
+	/**
+	 * Returns, for the given tree item, the deepest visible {@link TreeItem} in the Treeviewer associated
+	 * with this TreeRuler.
+	 * 
+	 * @param currentItem
+	 *            the given tree item.
+	 * @param deepestVisibleItem
+	 *            the deepest visible tree item (a parent or the item itself) of the given item.
+	 * @return the deepest visible tree item (a parent or the item itself).
+	 */
+	private TreeItem getDeepestVisibleTreeItem(final TreeItem currentItem, final TreeItem deepestVisibleItem) {
+		TreeItem item = null;
+		TreeItem parent = currentItem.getParentItem();
+		if (parent == null) {
+			item = deepestVisibleItem;
+		} else if (parent.getExpanded()) {
+			item = getDeepestVisibleTreeItem(parent, deepestVisibleItem);
+		} else {
+			item = getDeepestVisibleTreeItem(parent, parent);
+		}
+		return item;
+	}
+
+	/**
+	 * Get the previous item of the given {@link TreeItem}.
+	 * 
+	 * @param treeItem
+	 *            the given {@link TreeItem}.
+	 * @param index
+	 *            the index of the previous item.
+	 * @return the previous item of the given {@link TreeItem}.
+	 */
+	private TreeItem getPreviousItem(TreeItem treeItem, int index) {
+		TreeItem previousItem = treeItem;
+		if (index > 0) {
+			TreeItem parentItem = treeItem.getParentItem();
+			if (parentItem != null) {
+				int treeItemIndex = 0;
+				for (TreeItem siblingItem : parentItem.getItems()) {
+					if (siblingItem.equals(treeItem)) {
+						break;
+					}
+					treeItemIndex++;
+				}
+				if (treeItemIndex == 0) {
+					previousItem = getPreviousItem(parentItem, index - 1);
+				} else if (treeItemIndex == 1) {
+					TreeItem firstChild = parentItem.getItem(0);
+					previousItem = getLastVisibleItem(firstChild);
+					previousItem = getPreviousItem(previousItem, index - 1);
+				} else {
+					previousItem = getPreviousItem(getLastVisibleItem(parentItem.getItem(treeItemIndex - 1)),
+							index - 1);
+				}
+			} else {
+				// It is a root item. May be there are some previous root items.
+				Tree tree = treeItem.getParent();
+				int treeItemIndex = 0;
+				for (TreeItem siblingItem : tree.getItems()) {
+					if (siblingItem.equals(treeItem)) {
+						break;
+					}
+					treeItemIndex++;
+				}
+				if (treeItemIndex == 0) {
+					previousItem = treeItem;
+				} else if (treeItemIndex == 1) {
+					TreeItem firstRoot = tree.getItem(0);
+					if (firstRoot.getExpanded()) {
+						previousItem = getLastVisibleItem(firstRoot);
+					} else {
+						previousItem = firstRoot;
+					}
+					previousItem = getPreviousItem(previousItem, index - 1);
+				} else {
+					previousItem = tree.getItem(treeItemIndex - index);
+				}
+			}
+		}
+		return previousItem;
+	}
+
+	/**
+	 * Returns the last visible {@link TreeItem} in the Treeviewer associated with this TreeRuler.
+	 * 
+	 * @return the last visible TreeItem in the Treeviewer associated with this TreeRuler.
+	 */
+	private TreeItem getLastVisibleItem() {
+		int rootChildren = fTreeViewer.getTree().getItemCount();
+		return getLastVisibleItem(fTreeViewer.getTree().getItem(rootChildren - 1));
+	}
+
+	/**
+	 * Returns the last visible child of the given {@link TreeItem} in the Treeviewer associated with this
+	 * TreeRuler.
+	 * 
+	 * @param item
+	 *            teh given TreeItem.
+	 * @return the last visible child of the given TreeItem in the Treeviewer associated with this TreeRuler.
+	 */
+	private TreeItem getLastVisibleItem(TreeItem item) {
+		TreeItem lastVisibleItem = null;
+		int directChildren = item.getItemCount();
+		if (directChildren == 0) {
+			lastVisibleItem = item;
+		} else {
+			TreeItem lastDirectChildren = item.getItem(directChildren - 1);
+			if (lastDirectChildren.getData() == null) {
+				lastVisibleItem = item;
+			} else if (lastDirectChildren.getExpanded()) {
+				lastVisibleItem = getLastVisibleItem(lastDirectChildren);
+			} else {
+				lastVisibleItem = lastDirectChildren;
+			}
+		}
+		return lastVisibleItem;
+	}
+
+	/**
+	 * From a list of {@link Diff}s, returns the diffs which are not filtered by a filter of the given list of
+	 * {@link IDifferenceFilter}.
+	 * 
+	 * @param unfilteredDiffs
+	 *            the given list of unfiltered diffs.
+	 * @param filters
+	 *            the given list of IDifferenceFilter.
+	 * @return A filtered list of diffs.
+	 */
+	protected Collection<? extends Diff> filteredDiffs(Collection<? extends Diff> unfilteredDiffs,
+			Collection<IDifferenceFilter> filters) {
+		if (filters != null) {
+			List<Diff> filteredDiffs = Lists.newArrayList(unfilteredDiffs);
+			for (IDifferenceFilter filter : filters) {
+				for (Diff unfilteredDiff : unfilteredDiffs) {
+					if (filter.getPredicateWhenSelected().apply(unfilteredDiff)) {
+						filteredDiffs.remove(unfilteredDiff);
+					}
+				}
+			}
+			return filteredDiffs;
+		}
+		return unfilteredDiffs;
+
+	}
+}
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/EMFCompareDiffTreeViewer.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/EMFCompareDiffTreeViewer.java
new file mode 100644
index 0000000..d517160
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/EMFCompareDiffTreeViewer.java
@@ -0,0 +1,641 @@
+/*******************************************************************************
+ * Copyright (c) 2012, 2013 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer;
+
+import com.google.common.eventbus.EventBus;
+import com.google.common.eventbus.Subscribe;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.compare.CompareConfiguration;
+import org.eclipse.compare.CompareViewerPane;
+import org.eclipse.compare.CompareViewerSwitchingPane;
+import org.eclipse.compare.structuremergeviewer.DiffTreeViewer;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.emf.common.notify.Adapter;
+import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.emf.compare.Conflict;
+import org.eclipse.emf.compare.Diff;
+import org.eclipse.emf.compare.DifferenceSource;
+import org.eclipse.emf.compare.ide.ui.internal.EMFCompareIDEUIPlugin;
+import org.eclipse.emf.compare.ide.ui.internal.actions.collapse.CollapseAllModelAction;
+import org.eclipse.emf.compare.ide.ui.internal.actions.expand.ExpandAllModelAction;
+import org.eclipse.emf.compare.internal.utils.DiffUtil;
+import org.eclipse.emf.compare.rcp.ui.internal.EMFCompareConstants;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.actions.FilterActionMenu;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.actions.GroupActionMenu;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.filters.IDifferenceFilter;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.filters.IDifferenceFilterSelectionChangeEvent;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.filters.StructureMergeViewerFilter;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.IDifferenceGroupProvider;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.StructureMergeViewerGrouper;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.impl.DefaultGroupProvider;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.action.ToolBarManager;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider;
+import org.eclipse.jface.viewers.IElementComparer;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.swt.widgets.Widget;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.actions.CommandAction;
+import org.eclipse.ui.menus.IMenuService;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.eclipse.ui.services.IServiceLocator;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Version;
+
+/**
+ * @author <a href="mailto:mikael.barbero@obeo.fr">Mikael Barbero</a>
+ */
+public class EMFCompareDiffTreeViewer extends DiffTreeViewer {
+
+	public static final String REQUIRED_DIFF_COLOR = "RequiredDiffColor"; //$NON-NLS-1$
+
+	public static final String REQUIRED_DIFF_BORDER_COLOR = "RequiredDiffBorderColor"; //$NON-NLS-1$
+
+	public static final String UNMERGEABLE_DIFF_COLOR = "UnmergeableDiffColor"; //$NON-NLS-1$
+
+	public static final String UNMERGEABLE_DIFF_BORDER_COLOR = "UnmergeableDiffBorderColor"; //$NON-NLS-1$
+
+	private final Color requiredDiffColor;
+
+	private final Color unmergeableDiffColor;
+
+	private final ISelectionChangedListener fSelectionChangedListener;
+
+	private final CompareViewerSwitchingPane fParent;
+
+	private ToolBarManager toolbarManager;
+
+	private Object fRoot;
+
+	/**
+	 * The difference filter that will be applied to the structure viewer. Note that this will be initialized
+	 * from {@link #createToolItems(ToolBarManager)} since that method is called from the super-constructor
+	 * and we cannot init ourselves beforehand.
+	 */
+	private StructureMergeViewerFilter structureMergeViewerFilter;
+
+	/**
+	 * This will be used by our adapter factory in order to group together the differences located under the
+	 * Comparison. Note that this will be initialized from {@link #createToolItems(ToolBarManager)} since that
+	 * method is called from the super-constructor and we cannot init ourselves beforehand.
+	 */
+	private StructureMergeViewerGrouper structureMergeViewerGrouper;
+
+	private MenuManager groupsMenuManager;
+
+	private MenuManager filtersMenuManager;
+
+	private GroupActionMenu groupActionMenu;
+
+	private DefaultGroupProvider defaultGroupProvider;
+
+	private FilterActionMenu filterActionMenu;
+
+	private EventBus eventBus;
+
+	private Listener fEraseItemListener;
+
+	/**
+	 * @param parent
+	 * @param adapterFactory
+	 * @param configuration
+	 */
+	public EMFCompareDiffTreeViewer(Composite parent, AdapterFactory adapterFactory,
+			CompareConfiguration configuration) {
+		super(parent, configuration);
+
+		ToolBarManager tbm = CompareViewerPane.getToolBarManager(parent.getParent());
+		if (tbm != null) {
+			tbm.removeAll();
+
+			tbm.add(new Separator("merge")); //$NON-NLS-1$
+			tbm.add(new Separator("modes")); //$NON-NLS-1$
+			tbm.add(new Separator("navigation")); //$NON-NLS-1$
+
+			createToolItems(tbm);
+			// updateActions();
+
+			tbm.update(true);
+		}
+
+		setLabelProvider(new DelegatingStyledCellLabelProvider(
+				new EMFCompareStructureMergeViewerLabelProvider(adapterFactory, this)));
+		setContentProvider(new EMFCompareStructureMergeViewerContentProvider(adapterFactory,
+				getStructureMergeViewerGrouper(), getStructureMergeViewerFilter(), configuration));
+
+		if (parent instanceof CompareViewerSwitchingPane) {
+			fParent = (CompareViewerSwitchingPane)parent;
+		} else {
+			fParent = null;
+		}
+
+		fSelectionChangedListener = new ISelectionChangedListener() {
+			public void selectionChanged(SelectionChangedEvent event) {
+				getControl().redraw();
+				getCompareConfiguration()
+						.setProperty(EMFCompareConstants.SMV_SELECTION, event.getSelection());
+				if (toolbarManager != null) {
+					for (IContributionItem item : toolbarManager.getItems()) {
+						item.update();
+					}
+				}
+			}
+		};
+		addSelectionChangedListener(fSelectionChangedListener);
+
+		fEraseItemListener = new Listener() {
+			public void handleEvent(Event event) {
+				EMFCompareDiffTreeViewer.this.handleEraseItemEvent(event);
+			}
+		};
+		getControl().addListener(SWT.EraseItem, fEraseItemListener);
+
+		// Wrap the defined comparer in our own.
+		setComparer(new DiffNodeComparer(super.getComparer()));
+
+		if (eventBus == null) {
+			eventBus = new EventBus();
+			eventBus.register(this);
+		}
+
+		JFaceResources.getColorRegistry().put(REQUIRED_DIFF_COLOR, new RGB(215, 255, 200));
+		JFaceResources.getColorRegistry().put(REQUIRED_DIFF_BORDER_COLOR, new RGB(195, 235, 180));
+		JFaceResources.getColorRegistry().put(UNMERGEABLE_DIFF_COLOR, new RGB(255, 205, 180));
+		JFaceResources.getColorRegistry().put(UNMERGEABLE_DIFF_BORDER_COLOR, new RGB(235, 185, 160));
+
+		requiredDiffColor = JFaceResources.getColorRegistry().get(REQUIRED_DIFF_COLOR);
+		unmergeableDiffColor = JFaceResources.getColorRegistry().get(UNMERGEABLE_DIFF_COLOR);
+
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.jface.viewers.StructuredViewer#getComparator()
+	 */
+	@Override
+	public ViewerComparator getComparator() {
+		return null;
+	}
+
+	@SuppressWarnings("unchecked")
+	@Subscribe
+	public void recordFilterSelectionChange(IDifferenceFilterSelectionChangeEvent event) {
+		final Object property = getCompareConfiguration().getProperty(EMFCompareConstants.SELECTED_FILTERS);
+		final Collection<IDifferenceFilter> selectedFilters;
+		if (property == null) {
+			selectedFilters = new HashSet<IDifferenceFilter>();
+		} else {
+			selectedFilters = new HashSet<IDifferenceFilter>((Collection<IDifferenceFilter>)property);
+		}
+		switch (event.getAction()) {
+			case ACTIVATE:
+				selectedFilters.add(event.getFilter());
+				break;
+			case DEACTIVATE:
+				selectedFilters.remove(event.getFilter());
+				break;
+			default:
+				throw new IllegalStateException();
+		}
+		getCompareConfiguration().setProperty(EMFCompareConstants.SELECTED_FILTERS, selectedFilters);
+	}
+
+	@Subscribe
+	public void recordGroupProviderSelectionChange(IDifferenceGroupProvider differenceGroupProvider) {
+		getCompareConfiguration().setProperty(EMFCompareConstants.SELECTED_GROUP, differenceGroupProvider);
+	}
+
+	public void configurationPropertyChanged() {
+		getControl().redraw();
+		if (toolbarManager != null) {
+			for (IContributionItem item : toolbarManager.getItems()) {
+				item.update();
+			}
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.jface.viewers.StructuredViewer#getRoot()
+	 */
+	@Override
+	public Object getRoot() {
+		return fRoot;
+	}
+
+	public void setRoot(Object root) {
+		fRoot = root;
+	}
+
+	public void createChildrenSilently(Object o) {
+		if (o instanceof Tree) {
+			createChildren((Widget)o);
+			for (TreeItem item : ((Tree)o).getItems()) {
+				createChildrenSilently(item);
+			}
+		} else if (o instanceof TreeItem) {
+			createChildren((Widget)o);
+			for (TreeItem item : ((TreeItem)o).getItems()) {
+				createChildrenSilently(item);
+			}
+		}
+	}
+
+	@Override
+	public void initialSelection() {
+		super.initialSelection();
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * @see org.eclipse.jface.viewers.AbstractTreeViewer#isExpandable(java.lang.Object)
+	 */
+	@Override
+	public boolean isExpandable(Object parent) {
+		if (hasFilters()) {
+			// workaround for 65762
+			return hasFilteredChildren(parent);
+		}
+		return super.isExpandable(parent);
+	}
+
+	/**
+	 * Public method to test if a element has any children that passed the filters
+	 * 
+	 * @param parent
+	 *            the element to test
+	 * @return return <code>true</code> if the element has at least a child that passed the filters
+	 */
+	public final boolean hasFilteredChildren(Object parent) {
+		Object[] rawChildren = getRawChildren(parent);
+		return containsNonFiltered(rawChildren, parent);
+	}
+
+	private boolean containsNonFiltered(Object[] elements, Object parent) {
+		if (elements.length == 0) {
+			return false;
+		}
+		if (!hasFilters()) {
+			return true;
+		}
+		ViewerFilter[] filters = getFilters();
+		for (int i = 0; i < elements.length; i++) {
+			Object object = elements[i];
+			if (!isFiltered(object, parent, filters)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * All element filter tests must go through this method. Can be overridden by subclasses.
+	 * 
+	 * @param object
+	 *            the object to filter
+	 * @param parent
+	 *            the parent
+	 * @param filters
+	 *            the filters to apply
+	 * @return true if the element is filtered
+	 */
+	protected boolean isFiltered(Object object, Object parent, ViewerFilter[] filters) {
+		for (int i = 0; i < filters.length; i++) {
+			ViewerFilter filter = filters[i];
+			if (!filter.select(this, parent, object)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	public void refreshAfterDiff(String message, Object root) {
+		if (getControl().isDisposed()) {
+			return;
+		}
+
+		if (fParent != null) {
+			fParent.setTitleArgument(message);
+		}
+
+		refresh(root);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.jface.viewers.StructuredViewer#setComparer(org.eclipse.jface.viewers.IElementComparer)
+	 */
+	@Override
+	public void setComparer(IElementComparer comparer) {
+		// Wrap this new comparer in our own
+		super.setComparer(new DiffNodeComparer(comparer));
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.compare.structuremergeviewer.DiffTreeViewer#createToolItems(org.eclipse.jface.action.ToolBarManager)
+	 */
+	@Override
+	protected void createToolItems(ToolBarManager toolbarManager) {
+
+		this.toolbarManager = toolbarManager;
+
+		super.createToolItems(toolbarManager);
+
+		// Add extension point contributions to the structure merge viewer toolbar
+		IServiceLocator workbench = PlatformUI.getWorkbench();
+		IMenuService menuService = (IMenuService)workbench.getService(IMenuService.class);
+		if (menuService != null) {
+			menuService.populateContributionManager(toolbarManager,
+					"toolbar:org.eclipse.emf.compare.structuremergeviewer.toolbar");
+		}
+
+		Bundle uiWorkbenchBundle = Platform.getBundle("org.eclipse.ui.workbench"); //$NON-NLS-1$
+		Version junoStart = Version.parseVersion("3.103"); //$NON-NLS-1$
+
+		// XXX MBA change to 3.105 once bug #366528 is fixed
+		Version keplerStart = Version.parseVersion("3.105"); //$NON-NLS-1$
+
+		if (uiWorkbenchBundle != null && uiWorkbenchBundle.getVersion().compareTo(junoStart) >= 0
+				&& uiWorkbenchBundle.getVersion().compareTo(keplerStart) < 0) {
+			IAction action = new CommandAction(PlatformUI.getWorkbench(),
+					"org.eclipse.emf.compare.ide.ui.saveComparisonModel"); //$NON-NLS-1$
+			action.setToolTipText("Save Comparison model"); //$NON-NLS-1$
+			action.setImageDescriptor(AbstractUIPlugin.imageDescriptorFromPlugin(
+					EMFCompareIDEUIPlugin.PLUGIN_ID, "icons/full/toolb16/saveas_edit.gif")); //$NON-NLS-1$
+			toolbarManager.add(action);
+		}
+
+		groupActionMenu = new GroupActionMenu(getStructureMergeViewerGrouper(), getGroupsMenuManager(),
+				getDefaultGroupProvider());
+		filterActionMenu = new FilterActionMenu(getStructureMergeViewerFilter(), getFiltersMenuManager());
+
+		toolbarManager.add(new Separator());
+		toolbarManager.add(new ExpandAllModelAction(this));
+		toolbarManager.add(new CollapseAllModelAction(this));
+		toolbarManager.add(new Separator());
+		toolbarManager.add(groupActionMenu);
+		toolbarManager.add(filterActionMenu);
+	}
+
+	/**
+	 * Returns the viewer filter that is to be applied on the structure viewer.
+	 * <p>
+	 * Note that this will be called from {@link #createToolItems(ToolBarManager)}, which is called from the
+	 * super-constructor, when we have had no time to initialize the {@link #structureMergeViewerFilter}
+	 * field.
+	 * </p>
+	 * 
+	 * @return The difference filter that is to be applied on the structure viewer.
+	 */
+	protected StructureMergeViewerFilter getStructureMergeViewerFilter() {
+		if (structureMergeViewerFilter == null) {
+			if (eventBus == null) {
+				eventBus = new EventBus();
+				eventBus.register(this);
+			}
+			structureMergeViewerFilter = new StructureMergeViewerFilter(eventBus);
+			structureMergeViewerFilter.install(this);
+		}
+		return structureMergeViewerFilter;
+	}
+
+	/**
+	 * Returns the viewer grouper that is to be applied on the structure viewer.
+	 * <p>
+	 * Note that this will be called from {@link #createToolItems(ToolBarManager)}, which is called from the
+	 * super-constructor, when we have had no time to initialize the {@link #structureMergeViewerGrouper}
+	 * field.
+	 * </p>
+	 * 
+	 * @return The viewer grouper grouper that is to be applied on the structure viewer.
+	 */
+	protected StructureMergeViewerGrouper getStructureMergeViewerGrouper() {
+		if (structureMergeViewerGrouper == null) {
+			if (eventBus == null) {
+				eventBus = new EventBus();
+				eventBus.register(this);
+			}
+			structureMergeViewerGrouper = new StructureMergeViewerGrouper(eventBus);
+			structureMergeViewerGrouper.install(this);
+		}
+		return structureMergeViewerGrouper;
+	}
+
+	/**
+	 * Returns the menu manager that is to be applied to groups on the structure viewer.
+	 * 
+	 * @return The menu manager that is to be applied to groups on the structure viewer.
+	 */
+	public MenuManager getGroupsMenuManager() {
+		if (groupsMenuManager == null) {
+			groupsMenuManager = new MenuManager();
+		}
+		return groupsMenuManager;
+	}
+
+	/**
+	 * @return the groupActionMenu
+	 */
+	public GroupActionMenu getGroupActionMenu() {
+		return groupActionMenu;
+	}
+
+	/**
+	 * @param groupActionMenu
+	 *            the groupActionMenu to set
+	 */
+	public void setGroupActionMenu(GroupActionMenu groupActionMenu) {
+		this.groupActionMenu = groupActionMenu;
+	}
+
+	/**
+	 * Returns the menu manager that is to be applied to filters on the structure viewer.
+	 * 
+	 * @return The menu manager that is to be applied to filters on the structure viewer.
+	 */
+	public MenuManager getFiltersMenuManager() {
+		if (filtersMenuManager == null) {
+			filtersMenuManager = new MenuManager();
+		}
+		return filtersMenuManager;
+	}
+
+	/**
+	 * @return the filterActionMenu
+	 */
+	public FilterActionMenu getFilterActionMenu() {
+		return filterActionMenu;
+	}
+
+	/**
+	 * @param filterActionMenu
+	 *            the filterActionMenu to set
+	 */
+	public void setFilterActionMenu(FilterActionMenu filterActionMenu) {
+		this.filterActionMenu = filterActionMenu;
+	}
+
+	/**
+	 * Returns the default group provider that is to be applied on the structure viewer.
+	 * 
+	 * @return The default group provider that is to be applied on the structure viewer.
+	 */
+	public DefaultGroupProvider getDefaultGroupProvider() {
+		if (defaultGroupProvider == null) {
+			defaultGroupProvider = new DefaultGroupProvider();
+		}
+		return defaultGroupProvider;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.compare.structuremergeviewer.DiffTreeViewer#handleDispose(org.eclipse.swt.events.DisposeEvent)
+	 */
+	@Override
+	protected void handleDispose(DisposeEvent event) {
+		getControl().removeListener(SWT.EraseItem, fEraseItemListener);
+		removeSelectionChangedListener(fSelectionChangedListener);
+		super.handleDispose(event);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.jface.viewers.AbstractTreeViewer#getSortedChildren(java.lang.Object)
+	 */
+	@Override
+	protected Object[] getSortedChildren(Object parentElementOrTreePath) {
+		Object[] result = super.getSortedChildren(parentElementOrTreePath);
+		if (parentElementOrTreePath instanceof Adapter
+				&& ((Adapter)parentElementOrTreePath).getTarget() instanceof Conflict) {
+
+			Collections.sort(Arrays.asList(result), new Comparator<Object>() {
+				public int compare(Object o1, Object o2) {
+					return getValue(o1) - getValue(o2);
+				}
+
+				public int getValue(Object o) {
+					int value = 0;
+					if (o instanceof Adapter && ((Adapter)o).getTarget() instanceof Diff) {
+						if (((Diff)((Adapter)o).getTarget()).getSource() == DifferenceSource.LEFT) {
+							value = 1;
+						} else {
+							value = 2;
+						}
+					}
+					return value;
+				}
+			});
+
+		}
+		return result;
+	}
+
+	/**
+	 * Handle the erase item event. When select a difference in the structure merge viewer, highlight required
+	 * differences with a specific color, and highlight unmergeable differences with another color.
+	 * 
+	 * @param event
+	 *            the erase item event.
+	 */
+	protected void handleEraseItemEvent(Event event) {
+		ISelection selection = getSelection();
+		Object firstElement = ((IStructuredSelection)selection).getFirstElement();
+		if (firstElement instanceof Adapter) {
+			Notifier target = ((Adapter)firstElement).getTarget();
+			if (target instanceof Diff) {
+				TreeItem item = (TreeItem)event.item;
+				Object dataTreeItem = item.getData();
+				if (dataTreeItem instanceof Adapter) {
+					final Set<Diff> unmergeables;
+					final Set<Diff> requires;
+					Boolean leftToRight = (Boolean)getCompareConfiguration().getProperty(
+							EMFCompareConstants.MERGE_WAY);
+					boolean ltr = false;
+					if (leftToRight == null || leftToRight.booleanValue()) {
+						ltr = true;
+					}
+					boolean leftEditable = getCompareConfiguration().isLeftEditable();
+					boolean rightEditable = getCompareConfiguration().isRightEditable();
+					boolean bothSidesEditable = leftEditable && rightEditable;
+					Diff diff = (Diff)target;
+					if ((ltr && (leftEditable || bothSidesEditable))
+							|| (!ltr && (rightEditable && !leftEditable))) {
+						requires = DiffUtil.getRequires(diff, true, diff.getSource());
+						unmergeables = DiffUtil.getUnmergeables(diff, true);
+					} else {
+						requires = DiffUtil.getRequires(diff, false, diff.getSource());
+						unmergeables = DiffUtil.getUnmergeables(diff, false);
+					}
+					final GC g = event.gc;
+					if (requires.contains(((Adapter)dataTreeItem).getTarget())) {
+						paintItemBackground(g, item, requiredDiffColor);
+					} else if (unmergeables.contains(((Adapter)dataTreeItem).getTarget())) {
+						paintItemBackground(g, item, unmergeableDiffColor);
+					}
+				}
+			}
+		}
+	}
+
+	/**
+	 * Paint the background of the given item with the given color.
+	 * 
+	 * @param g
+	 *            the GC associated to the item.
+	 * @param item
+	 *            the given item.
+	 * @param color
+	 *            the given color.
+	 */
+	private void paintItemBackground(GC g, TreeItem item, Color color) {
+		Rectangle itemBounds = item.getBounds();
+		Tree tree = item.getParent();
+		Rectangle areaBounds = tree.getClientArea();
+		g.setClipping(areaBounds.x, itemBounds.y, areaBounds.width, itemBounds.height);
+		g.setBackground(color);
+		g.fillRectangle(areaBounds.x, itemBounds.y, areaBounds.width, itemBounds.height);
+	}
+}
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/EMFCompareStructureMergeViewer.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/EMFCompareStructureMergeViewer.java
index 4895d49..a9968c4 100644
--- a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/EMFCompareStructureMergeViewer.java
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/EMFCompareStructureMergeViewer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2012, 2013 Obeo.
+ * Copyright (c) 2013 Obeo.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -12,31 +12,23 @@
 
 import static com.google.common.collect.Iterables.getFirst;
 
-import com.google.common.eventbus.EventBus;
-import com.google.common.eventbus.Subscribe;
-
 import java.lang.reflect.Field;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
-import java.util.Arrays;
 import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
 import java.util.EventObject;
-import java.util.HashSet;
 import java.util.Iterator;
 
 import org.eclipse.compare.CompareConfiguration;
-import org.eclipse.compare.CompareViewerSwitchingPane;
+import org.eclipse.compare.INavigatable;
 import org.eclipse.compare.ITypedElement;
-import org.eclipse.compare.structuremergeviewer.DiffTreeViewer;
+import org.eclipse.compare.internal.CompareHandlerService;
 import org.eclipse.compare.structuremergeviewer.ICompareInput;
 import org.eclipse.compare.structuremergeviewer.ICompareInputChangeListener;
 import org.eclipse.core.resources.IStorage;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.NullProgressMonitor;
-import org.eclipse.core.runtime.Platform;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.core.runtime.SubMonitor;
 import org.eclipse.core.runtime.jobs.Job;
@@ -46,17 +38,14 @@
 import org.eclipse.emf.common.notify.Adapter;
 import org.eclipse.emf.common.util.BasicMonitor;
 import org.eclipse.emf.compare.Comparison;
-import org.eclipse.emf.compare.Conflict;
-import org.eclipse.emf.compare.Diff;
-import org.eclipse.emf.compare.DifferenceSource;
 import org.eclipse.emf.compare.EMFCompare;
 import org.eclipse.emf.compare.Match;
 import org.eclipse.emf.compare.command.ICompareCopyCommand;
 import org.eclipse.emf.compare.domain.ICompareEditingDomain;
 import org.eclipse.emf.compare.domain.impl.EMFCompareEditingDomain;
 import org.eclipse.emf.compare.ide.ui.internal.EMFCompareIDEUIPlugin;
-import org.eclipse.emf.compare.ide.ui.internal.actions.collapse.CollapseAllModelAction;
-import org.eclipse.emf.compare.ide.ui.internal.actions.expand.ExpandAllModelAction;
+import org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.util.RedoAction;
+import org.eclipse.emf.compare.ide.ui.internal.contentmergeviewer.util.UndoAction;
 import org.eclipse.emf.compare.ide.ui.internal.editor.ComparisonScopeInput;
 import org.eclipse.emf.compare.ide.ui.internal.logical.ComparisonScopeBuilder;
 import org.eclipse.emf.compare.ide.ui.internal.logical.IdenticalResourceMinimizer;
@@ -69,14 +58,6 @@
 import org.eclipse.emf.compare.ide.ui.logical.IStorageProviderAccessor;
 import org.eclipse.emf.compare.rcp.EMFCompareRCPPlugin;
 import org.eclipse.emf.compare.rcp.ui.internal.EMFCompareConstants;
-import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.actions.FilterActionMenu;
-import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.actions.GroupActionMenu;
-import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.filters.IDifferenceFilter;
-import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.filters.IDifferenceFilterSelectionChangeEvent;
-import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.filters.StructureMergeViewerFilter;
-import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.IDifferenceGroupProvider;
-import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.StructureMergeViewerGrouper;
-import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.impl.DefaultGroupProvider;
 import org.eclipse.emf.compare.scope.IComparisonScope;
 import org.eclipse.emf.ecore.EObject;
 import org.eclipse.emf.ecore.resource.Resource;
@@ -84,70 +65,56 @@
 import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
 import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory;
 import org.eclipse.emf.edit.provider.resource.ResourceItemProviderAdapterFactory;
-import org.eclipse.jface.action.IAction;
-import org.eclipse.jface.action.MenuManager;
-import org.eclipse.jface.action.Separator;
-import org.eclipse.jface.action.ToolBarManager;
-import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider;
-import org.eclipse.jface.viewers.IElementComparer;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.viewers.ITreeViewerListener;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
 import org.eclipse.jface.viewers.StructuredSelection;
-import org.eclipse.jface.viewers.ViewerComparator;
-import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.jface.viewers.TreeExpansionEvent;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
 import org.eclipse.swt.widgets.TreeItem;
 import org.eclipse.team.core.subscribers.Subscriber;
 import org.eclipse.team.core.subscribers.SubscriberMergeContext;
 import org.eclipse.team.internal.ui.mapping.ModelCompareEditorInput;
 import org.eclipse.team.ui.synchronize.ISynchronizeParticipant;
 import org.eclipse.team.ui.synchronize.ModelSynchronizeParticipant;
-import org.eclipse.ui.PlatformUI;
-import org.eclipse.ui.internal.actions.CommandAction;
-import org.eclipse.ui.menus.IMenuService;
-import org.eclipse.ui.plugin.AbstractUIPlugin;
-import org.eclipse.ui.services.IServiceLocator;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.Version;
+import org.eclipse.ui.actions.ActionFactory;
 
 /**
- * @author <a href="mailto:mikael.barbero@obeo.fr">Mikael Barbero</a>
+ * Implementation of {@link AbstractViewerWrapper}.
+ * 
+ * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
  */
-public class EMFCompareStructureMergeViewer extends DiffTreeViewer implements CommandStackListener {
+public class EMFCompareStructureMergeViewer extends AbstractViewerWrapper implements CommandStackListener {
 
-	private final ICompareInputChangeListener fCompareInputChangeListener;
+	private static final int TREE_RULER_WIDTH = 17;
 
-	private final ComposedAdapterFactory fAdapterFactory;
+	private ComposedAdapterFactory fAdapterFactory;
 
-	private final CompareViewerSwitchingPane fParent;
+	/** The tree ruler associated with this viewer. */
+	private EMFCompareDiffTreeRuler treeRuler;
 
-	private Object fRoot;
+	private ICompareInputChangeListener fCompareInputChangeListener;
 
-	/**
-	 * The difference filter that will be applied to the structure viewer. Note that this will be initialized
-	 * from {@link #createToolItems(ToolBarManager)} since that method is called from the super-constructor
-	 * and we cannot init ourselves beforehand.
-	 */
-	private StructureMergeViewerFilter structureMergeViewerFilter;
+	/** The expand/collapse item listener. */
+	private ITreeViewerListener fWrappedTreeListener;
 
-	/**
-	 * This will be used by our adapter factory in order to group together the differences located under the
-	 * Comparison. Note that this will be initialized from {@link #createToolItems(ToolBarManager)} since that
-	 * method is called from the super-constructor and we cannot init ourselves beforehand.
-	 */
-	private StructureMergeViewerGrouper structureMergeViewerGrouper;
+	/** The compare configuration property change listener. */
+	private IPropertyChangeListener fCompareConfigurationPropertyChangeListener;
 
-	private MenuManager groupsMenuManager;
+	/** The tree viewer. */
+	private EMFCompareDiffTreeViewer diffTreeViewer;
 
-	private MenuManager filtersMenuManager;
+	private UndoAction undoAction;
 
-	private GroupActionMenu groupActionMenu;
+	private RedoAction redoAction;
 
-	private DefaultGroupProvider defaultGroupProvider;
-
-	private FilterActionMenu filterActionMenu;
-
-	private EventBus eventBus;
+	private CompareHandlerService fHandlerService;
 
 	/**
 	 * When comparing EObjects from a resource, the resource involved doesn't need to be unload by EMF
@@ -156,11 +123,27 @@
 	private boolean resourcesShouldBeUnload;
 
 	/**
+	 * Constructor.
+	 * 
 	 * @param parent
-	 * @param configuration
+	 *            the SWT parent control under which to create the viewer's SWT control.
+	 * @param config
+	 *            a compare configuration the newly created viewer might want to use.
 	 */
-	public EMFCompareStructureMergeViewer(Composite parent, CompareConfiguration configuration) {
-		super(parent, configuration);
+	public EMFCompareStructureMergeViewer(Composite parent, CompareConfiguration config) {
+		super(parent, config);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see 
+	 *      org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.ViewerWrapper.createControl(Composite,
+	 *      CompareConfiguration)
+	 */
+	@Override
+	protected Control createControl(Composite parent, CompareConfiguration config) {
+		Composite control = new Composite(parent, SWT.NONE);
 
 		fAdapterFactory = new ComposedAdapterFactory(EMFCompareRCPPlugin.getDefault()
 				.getAdapterFactoryRegistry());
@@ -168,16 +151,25 @@
 		fAdapterFactory.addAdapterFactory(new ReflectiveItemProviderAdapterFactory());
 		fAdapterFactory.addAdapterFactory(new ResourceItemProviderAdapterFactory());
 
-		setLabelProvider(new DelegatingStyledCellLabelProvider(
-				new EMFCompareStructureMergeViewerLabelProvider(fAdapterFactory, this)));
-		setContentProvider(new EMFCompareStructureMergeViewerContentProvider(fAdapterFactory,
-				getStructureMergeViewerGrouper(), getStructureMergeViewerFilter(), configuration));
-
-		if (parent instanceof CompareViewerSwitchingPane) {
-			fParent = (CompareViewerSwitchingPane)parent;
-		} else {
-			fParent = null;
-		}
+		GridLayout layout = new GridLayout(2, false);
+		layout.marginWidth = 0;
+		layout.marginHeight = 0;
+		layout.horizontalSpacing = 0;
+		layout.verticalSpacing = 0;
+		GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
+		control.setLayout(layout);
+		control.setLayoutData(data);
+		diffTreeViewer = new EMFCompareDiffTreeViewer(control, fAdapterFactory, config);
+		setViewer(diffTreeViewer);
+		control.setData(INavigatable.NAVIGATOR_PROPERTY, diffTreeViewer.getControl().getData(
+				INavigatable.NAVIGATOR_PROPERTY));
+		diffTreeViewer.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+		GridData layoutData = new GridData(SWT.FILL, SWT.FILL, false, true);
+		layoutData.widthHint = TREE_RULER_WIDTH;
+		layoutData.minimumWidth = TREE_RULER_WIDTH;
+		treeRuler = new EMFCompareDiffTreeRuler(control, SWT.NONE, layoutData.widthHint, diffTreeViewer,
+				config);
+		treeRuler.setLayoutData(layoutData);
 
 		fCompareInputChangeListener = new ICompareInputChangeListener() {
 			public void compareInputChanged(ICompareInput input) {
@@ -185,54 +177,155 @@
 			}
 		};
 
-		// Wrap the defined comparer in our own.
-		setComparer(new DiffNodeComparer(super.getComparer()));
+		fWrappedTreeListener = new ITreeViewerListener() {
 
-		if (eventBus == null) {
-			eventBus = new EventBus();
-			eventBus.register(this);
-		}
+			public void treeExpanded(TreeExpansionEvent event) {
+				treeRuler.redraw();
+			}
 
-		inputChangedTask.setPriority(Job.LONG);
+			public void treeCollapsed(TreeExpansionEvent event) {
+				treeRuler.redraw();
+			}
+		};
+		diffTreeViewer.addTreeListener(fWrappedTreeListener);
+
+		fCompareConfigurationPropertyChangeListener = new IPropertyChangeListener() {
+			public void propertyChange(PropertyChangeEvent event) {
+				if (EMFCompareConstants.MERGE_WAY.equals(event.getProperty()) && event.getNewValue() != null) {
+					diffTreeViewer.configurationPropertyChanged();
+					treeRuler.computeConsequences();
+					treeRuler.redraw();
+				} else if (EMFCompareConstants.SELECTED_FILTERS.equals(event.getProperty())
+						&& event.getNewValue() != null) {
+					diffTreeViewer.createChildrenSilently(diffTreeViewer.getTree());
+					treeRuler.computeConsequences();
+					treeRuler.redraw();
+				} else if (EMFCompareConstants.SELECTED_GROUP.equals(event.getProperty())
+						&& event.getNewValue() != null) {
+					diffTreeViewer.createChildrenSilently(diffTreeViewer.getTree());
+					treeRuler.computeConsequences();
+					treeRuler.redraw();
+				}
+			}
+		};
+		getCompareConfiguration().addPropertyChangeListener(fCompareConfigurationPropertyChangeListener);
+
+		fHandlerService = CompareHandlerService.createFor(getCompareConfiguration().getContainer(),
+				diffTreeViewer.getControl().getShell());
+
+		// inputChangedTask.setPriority(Job.LONG);
+
+		return control;
 	}
 
 	/**
 	 * {@inheritDoc}
 	 * 
-	 * @see org.eclipse.jface.viewers.StructuredViewer#getComparator()
+	 * @see org.eclipse.jface.viewers.Viewer#fireSelectionChanged(SelectionChangedEvent)
 	 */
 	@Override
-	public ViewerComparator getComparator() {
-		return null;
+	protected void fireSelectionChanged(SelectionChangedEvent event) {
+		super.fireSelectionChanged(event);
+		treeRuler.selectionChanged(event);
+		treeRuler.redraw();
 	}
 
-	@SuppressWarnings("unchecked")
-	@Subscribe
-	public void recordFilterSelectionChange(IDifferenceFilterSelectionChangeEvent event) {
-		final Object property = getCompareConfiguration().getProperty(EMFCompareConstants.SELECTED_FILTERS);
-		final Collection<IDifferenceFilter> selectedFilters;
-		if (property == null) {
-			selectedFilters = new HashSet<IDifferenceFilter>();
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.jface.viewers.Viewer#inputChanged(Object, Object)
+	 */
+	@Override
+	protected void inputChanged(Object input, Object oldInput) {
+		if (oldInput instanceof ICompareInput) {
+			ICompareInput old = (ICompareInput)oldInput;
+			old.removeCompareInputChangeListener(fCompareInputChangeListener);
+		}
+		if (input instanceof ICompareInput) {
+			ICompareInput ci = (ICompareInput)input;
+			ci.addCompareInputChangeListener(fCompareInputChangeListener);
+
+			// Hack to display a message in the tree viewer while the differences are being computed.
+			TreeItem item = new TreeItem(diffTreeViewer.getTree(), SWT.NONE);
+			item.setText("Computing model differences...");
+
+			compareInputChanged(ci);
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.AbstractViewerWrapper#handleDispose(DisposeEvent)
+	 */
+	@Override
+	protected void handleDispose(DisposeEvent event) {
+		if (fHandlerService != null) {
+			fHandlerService.dispose();
+		}
+		getCompareConfiguration().removePropertyChangeListener(fCompareConfigurationPropertyChangeListener);
+		diffTreeViewer.removeTreeListener(fWrappedTreeListener);
+		Object input = getInput();
+		if (input instanceof ICompareInput) {
+			ICompareInput ci = (ICompareInput)input;
+			ci.removeCompareInputChangeListener(fCompareInputChangeListener);
+		}
+		compareInputChanged((ICompareInput)null);
+		treeRuler.handleDispose();
+		fAdapterFactory.dispose();
+		super.handleDispose(event);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.emf.common.command.CommandStackListener#commandStackChanged(java.util.EventObject)
+	 */
+	public void commandStackChanged(EventObject event) {
+		if (undoAction != null) {
+			undoAction.update();
+		}
+		if (redoAction != null) {
+			redoAction.update();
+		}
+
+		Command mostRecentCommand = ((CommandStack)event.getSource()).getMostRecentCommand();
+		if (mostRecentCommand instanceof ICompareCopyCommand) {
+			Collection<?> affectedObjects = mostRecentCommand.getAffectedObjects();
+
+			SWTUtil.safeAsyncExec(new Runnable() {
+				public void run() {
+					refresh(true);
+					diffTreeViewer.createChildrenSilently(diffTreeViewer.getTree());
+					treeRuler.computeConsequences();
+					treeRuler.redraw();
+				}
+			});
+			if (!affectedObjects.isEmpty()) {
+				// MUST NOT call a setSelection with a list, o.e.compare does not handle it (cf
+				// org.eclipse.compare.CompareEditorInput#getElement(ISelection))
+				final Object adaptedAffectedObject = fAdapterFactory.adapt(getFirst(affectedObjects, null),
+						ICompareInput.class);
+				SWTUtil.safeAsyncExec(new Runnable() {
+					public void run() {
+						setSelectionToWidget(new StructuredSelection(adaptedAffectedObject), true);
+					}
+				});
+			}
 		} else {
-			selectedFilters = new HashSet<IDifferenceFilter>((Collection<IDifferenceFilter>)property);
+			// FIXME, should recompute the difference, something happened outside of this compare editor
 		}
-		switch (event.getAction()) {
-			case ACTIVATE:
-				selectedFilters.add(event.getFilter());
-				break;
-			case DEACTIVATE:
-				selectedFilters.remove(event.getFilter());
-				break;
-			default:
-				throw new IllegalStateException();
-		}
-		getCompareConfiguration().setProperty(EMFCompareConstants.SELECTED_FILTERS, selectedFilters);
+
 	}
 
-	@Subscribe
-	public void recordGroupProviderSelectionChange(IDifferenceGroupProvider differenceGroupProvider) {
-		getCompareConfiguration().setProperty(EMFCompareConstants.SELECTED_GROUP, differenceGroupProvider);
-	}
+	private Job inputChangedTask = new Job("Compute Model Differences") {
+		@Override
+		public IStatus run(IProgressMonitor monitor) {
+			SubMonitor subMonitor = SubMonitor.convert(monitor, "Computing Model Differences", 100);
+			compareInputChanged((ICompareInput)getInput(), subMonitor.newChild(100));
+			return Status.OK_STATUS;
+		}
+	};
 
 	/**
 	 * Triggered by fCompareInputChangeListener and {@link #inputChanged(Object, Object)}.
@@ -250,24 +343,199 @@
 		}
 	}
 
-	/**
-	 * {@inheritDoc}
-	 * 
-	 * @see org.eclipse.jface.viewers.StructuredViewer#getRoot()
-	 */
-	@Override
-	protected Object getRoot() {
-		return fRoot;
+	void compareInputChanged(ComparisonNode input, IProgressMonitor monitor) {
+		ICompareEditingDomain editingDomain = (ICompareEditingDomain)getCompareConfiguration().getProperty(
+				EMFCompareConstants.EDITING_DOMAIN);
+		editingDomain.getCommandStack().addCommandStackListener(this);
+
+		compareInputChanged(null, input.getTarget());
 	}
 
-	private Job inputChangedTask = new Job("Compute Model Differences") {
-		@Override
-		public IStatus run(IProgressMonitor monitor) {
-			SubMonitor subMonitor = SubMonitor.convert(monitor, "Computing Model Differences", 100);
-			compareInputChanged((ICompareInput)getInput(), subMonitor.newChild(100));
-			return Status.OK_STATUS;
+	void compareInputChanged(ComparisonScopeInput input, IProgressMonitor monitor) {
+		ICompareEditingDomain editingDomain = (ICompareEditingDomain)getCompareConfiguration().getProperty(
+				EMFCompareConstants.EDITING_DOMAIN);
+		editingDomain.getCommandStack().addCommandStackListener(this);
+
+		EMFCompare comparator = (EMFCompare)getCompareConfiguration().getProperty(
+				EMFCompareConstants.COMPARATOR);
+
+		IComparisonScope comparisonScope = input.getComparisonScope();
+		Comparison comparison = comparator.compare(comparisonScope, BasicMonitor.toMonitor(monitor));
+		compareInputChanged(input.getComparisonScope(), comparison);
+	}
+
+	void compareInputChanged(final IComparisonScope scope, final Comparison comparison) {
+		if (!getControl().isDisposed()) { // guard against disposal
+			diffTreeViewer.setRoot(fAdapterFactory.adapt(comparison, ICompareInput.class));
+			getCompareConfiguration().setProperty(EMFCompareConstants.COMPARE_RESULT, comparison);
+
+			String message = null;
+			if (comparison.getDifferences().isEmpty()) {
+				message = "No Differences";
+			}
+
+			final String theMessage = message;
+			SWTUtil.safeAsyncExec(new Runnable() {
+				public void run() {
+					if (diffTreeViewer.getGroupActionMenu() != null) {
+						diffTreeViewer.getGroupActionMenu().createActions(scope, comparison);
+					}
+					if (diffTreeViewer.getFilterActionMenu() != null) {
+						diffTreeViewer.getFilterActionMenu().createActions(scope, comparison);
+					}
+					diffTreeViewer.refreshAfterDiff(theMessage, diffTreeViewer.getRoot());
+					// Mandatory for the EMFCompareDiffTreeRuler, all TreeItems must have been created
+					diffTreeViewer.createChildrenSilently(diffTreeViewer.getTree());
+					diffTreeViewer.initialSelection();
+				}
+			});
+
+			ICompareEditingDomain editingDomain = (ICompareEditingDomain)getCompareConfiguration()
+					.getProperty(EMFCompareConstants.EDITING_DOMAIN);
+
+			undoAction = new UndoAction(editingDomain);
+			redoAction = new RedoAction(editingDomain);
+
+			fHandlerService.setGlobalActionHandler(ActionFactory.UNDO.getId(), undoAction);
+			fHandlerService.setGlobalActionHandler(ActionFactory.REDO.getId(), redoAction);
 		}
-	};
+	}
+
+	void compareInputChanged(ICompareInput input, IProgressMonitor monitor) {
+		if (input != null) {
+			if (input instanceof ComparisonNode) {
+				resourcesShouldBeUnload = false;
+				compareInputChanged((ComparisonNode)input, monitor);
+			} else if (input instanceof ComparisonScopeInput) {
+				resourcesShouldBeUnload = false;
+				compareInputChanged((ComparisonScopeInput)input, monitor);
+			} else {
+				resourcesShouldBeUnload = true;
+				SubMonitor subMonitor = SubMonitor.convert(monitor, 100);
+
+				final ITypedElement left = input.getLeft();
+				final ITypedElement right = input.getRight();
+				final ITypedElement origin = input.getAncestor();
+
+				final IComparisonScope scope = buildComparisonScope(left, right, origin, subMonitor
+						.newChild(85));
+				final Comparison compareResult = EMFCompare
+						.builder()
+						.setMatchEngineFactoryRegistry(
+								EMFCompareRCPPlugin.getDefault().getMatchEngineFactoryRegistry())
+						.setPostProcessorRegistry(EMFCompareRCPPlugin.getDefault().getPostProcessorRegistry())
+						.build().compare(scope, BasicMonitor.toMonitor(subMonitor.newChild(15)));
+
+				final ResourceSet leftResourceSet = (ResourceSet)scope.getLeft();
+				final ResourceSet rightResourceSet = (ResourceSet)scope.getRight();
+				final ResourceSet originResourceSet = (ResourceSet)scope.getOrigin();
+
+				if (getCompareConfiguration() != null) {
+					ICompareEditingDomain editingDomain = (ICompareEditingDomain)getCompareConfiguration()
+							.getProperty(EMFCompareConstants.EDITING_DOMAIN);
+					if (editingDomain != null) {
+						editingDomain.getCommandStack().removeCommandStackListener(this);
+						editingDomain.dispose();
+					}
+
+					editingDomain = EMFCompareEditingDomain.create(leftResourceSet, rightResourceSet,
+							originResourceSet);
+					editingDomain.getCommandStack().addCommandStackListener(this);
+					getCompareConfiguration().setProperty(EMFCompareConstants.EDITING_DOMAIN, editingDomain);
+				}
+
+				compareInputChanged(scope, compareResult);
+			}
+		} else {
+			ResourceSet leftResourceSet = null;
+			ResourceSet rightResourceSet = null;
+			ResourceSet originResourceSet = null;
+
+			if (diffTreeViewer.getRoot() != null) {
+				Comparison comparison = (Comparison)((Adapter)diffTreeViewer.getRoot()).getTarget();
+				Iterator<Match> matchIt = comparison.getMatches().iterator();
+				if (comparison.isThreeWay()) {
+					while (matchIt.hasNext()
+							&& (leftResourceSet == null || rightResourceSet == null || originResourceSet == null)) {
+						Match match = matchIt.next();
+						if (leftResourceSet == null) {
+							leftResourceSet = getResourceSet(match.getLeft());
+						}
+						if (rightResourceSet == null) {
+							rightResourceSet = getResourceSet(match.getRight());
+						}
+						if (originResourceSet == null) {
+							originResourceSet = getResourceSet(match.getOrigin());
+						}
+					}
+				} else {
+					while (matchIt.hasNext() && (leftResourceSet == null || rightResourceSet == null)) {
+						Match match = matchIt.next();
+						if (leftResourceSet == null) {
+							leftResourceSet = getResourceSet(match.getLeft());
+						}
+						if (rightResourceSet == null) {
+							rightResourceSet = getResourceSet(match.getRight());
+						}
+					}
+				}
+			}
+
+			ICompareEditingDomain editingDomain = (ICompareEditingDomain)getCompareConfiguration()
+					.getProperty(EMFCompareConstants.EDITING_DOMAIN);
+			if (editingDomain != null) {
+				editingDomain.getCommandStack().removeCommandStackListener(this);
+				getCompareConfiguration().setProperty(EMFCompareConstants.EDITING_DOMAIN, null);
+				editingDomain.dispose();
+				editingDomain = null;
+			}
+
+			if (resourcesShouldBeUnload) {
+				unload(leftResourceSet);
+				unload(rightResourceSet);
+				unload(originResourceSet);
+			}
+
+			if (getCompareConfiguration() != null) {
+				getCompareConfiguration().setProperty(EMFCompareConstants.COMPARE_RESULT, null);
+				getCompareConfiguration().setProperty(EMFCompareConstants.SELECTED_FILTERS, null);
+				getCompareConfiguration().setProperty(EMFCompareConstants.SELECTED_GROUP, null);
+				getCompareConfiguration().setProperty(EMFCompareConstants.MERGE_WAY, null);
+				getCompareConfiguration().setProperty(EMFCompareConstants.SMV_SELECTION, null);
+			}
+			diffTreeViewer.setRoot(null);
+		}
+	}
+
+	/**
+	 * Constructs the comparison scope corresponding to the given typed elements.
+	 * 
+	 * @param left
+	 *            Left of the compared elements.
+	 * @param right
+	 *            Right of the compared elements.
+	 * @param origin
+	 *            Common ancestor of the <code>left</code> and <code>right</code> compared elements.
+	 * @param monitor
+	 *            Monitor to report progress on.
+	 * @return The created comparison scope.
+	 */
+	private IComparisonScope buildComparisonScope(ITypedElement left, ITypedElement right,
+			ITypedElement origin, IProgressMonitor monitor) {
+		IStorageProviderAccessor storageAccessor = null;
+		if (getSubscriber() != null) {
+			storageAccessor = new SubscriberStorageAccessor(getSubscriber());
+		}
+		IStorage leftStorage = PlatformElementUtil.findFile(left);
+		if (leftStorage == null) {
+			leftStorage = StreamAccessorStorage.fromTypedElement(left);
+		}
+		IModelResolver resolver = EMFCompareIDEUIPlugin.getDefault().getModelResolverRegistry()
+				.getBestResolverFor(leftStorage);
+		final ComparisonScopeBuilder scopeBuilder = new ComparisonScopeBuilder(resolver,
+				new IdenticalResourceMinimizer(), storageAccessor);
+		return scopeBuilder.build(left, right, origin, monitor);
+	}
 
 	/**
 	 * Team left us with absolutely no way to determine whether our supplied input is the result of a
@@ -319,162 +587,6 @@
 		return null;
 	}
 
-	void compareInputChanged(ICompareInput input, IProgressMonitor monitor) {
-		if (input != null) {
-			if (input instanceof ComparisonNode) {
-				resourcesShouldBeUnload = false;
-				compareInputChanged((ComparisonNode)input, monitor);
-			} else if (input instanceof ComparisonScopeInput) {
-				resourcesShouldBeUnload = false;
-				compareInputChanged((ComparisonScopeInput)input, monitor);
-			} else {
-				resourcesShouldBeUnload = true;
-				SubMonitor subMonitor = SubMonitor.convert(monitor, 100);
-
-				final ITypedElement left = input.getLeft();
-				final ITypedElement right = input.getRight();
-				final ITypedElement origin = input.getAncestor();
-
-				final IComparisonScope scope = buildComparisonScope(left, right, origin, subMonitor
-						.newChild(85));
-
-				final Comparison compareResult = EMFCompare
-						.builder()
-						.setMatchEngineFactoryRegistry(
-								EMFCompareRCPPlugin.getDefault().getMatchEngineFactoryRegistry())
-						.setPostProcessorRegistry(EMFCompareRCPPlugin.getDefault().getPostProcessorRegistry())
-						.build().compare(scope, BasicMonitor.toMonitor(subMonitor.newChild(15)));
-
-				final ResourceSet leftResourceSet = (ResourceSet)scope.getLeft();
-				final ResourceSet rightResourceSet = (ResourceSet)scope.getRight();
-				final ResourceSet originResourceSet = (ResourceSet)scope.getOrigin();
-
-				if (getCompareConfiguration() != null) {
-					ICompareEditingDomain editingDomain = (ICompareEditingDomain)getCompareConfiguration()
-							.getProperty(EMFCompareConstants.EDITING_DOMAIN);
-					if (editingDomain != null) {
-						editingDomain.getCommandStack().removeCommandStackListener(this);
-						editingDomain.dispose();
-					}
-
-					editingDomain = EMFCompareEditingDomain.create(leftResourceSet, rightResourceSet,
-							originResourceSet);
-					editingDomain.getCommandStack().addCommandStackListener(this);
-					getCompareConfiguration().setProperty(EMFCompareConstants.EDITING_DOMAIN, editingDomain);
-				}
-
-				compareInputChanged(scope, compareResult);
-			}
-		} else {
-			ResourceSet leftResourceSet = null;
-			ResourceSet rightResourceSet = null;
-			ResourceSet originResourceSet = null;
-
-			if (fRoot != null) {
-				Comparison comparison = (Comparison)((Adapter)fRoot).getTarget();
-				Iterator<Match> matchIt = comparison.getMatches().iterator();
-				if (comparison.isThreeWay()) {
-					while (matchIt.hasNext()
-							&& (leftResourceSet == null || rightResourceSet == null || originResourceSet == null)) {
-						Match match = matchIt.next();
-						if (leftResourceSet == null) {
-							leftResourceSet = getResourceSet(match.getLeft());
-						}
-						if (rightResourceSet == null) {
-							rightResourceSet = getResourceSet(match.getRight());
-						}
-						if (originResourceSet == null) {
-							originResourceSet = getResourceSet(match.getOrigin());
-						}
-					}
-				} else {
-					while (matchIt.hasNext() && (leftResourceSet == null || rightResourceSet == null)) {
-						Match match = matchIt.next();
-						if (leftResourceSet == null) {
-							leftResourceSet = getResourceSet(match.getLeft());
-						}
-						if (rightResourceSet == null) {
-							rightResourceSet = getResourceSet(match.getRight());
-						}
-					}
-				}
-			}
-
-			ICompareEditingDomain editingDomain = (ICompareEditingDomain)getCompareConfiguration()
-					.getProperty(EMFCompareConstants.EDITING_DOMAIN);
-			if (editingDomain != null) {
-				editingDomain.getCommandStack().removeCommandStackListener(this);
-				getCompareConfiguration().setProperty(EMFCompareConstants.EDITING_DOMAIN, null);
-				editingDomain.dispose();
-				editingDomain = null;
-			}
-
-			if (resourcesShouldBeUnload) {
-				unload(leftResourceSet);
-				unload(rightResourceSet);
-				unload(originResourceSet);
-			}
-
-			if (getCompareConfiguration() != null) {
-				getCompareConfiguration().setProperty(EMFCompareConstants.COMPARE_RESULT, null);
-				getCompareConfiguration().setProperty(EMFCompareConstants.SELECTED_FILTERS, null);
-				getCompareConfiguration().setProperty(EMFCompareConstants.SELECTED_GROUP, null);
-			}
-			fRoot = null;
-		}
-	}
-
-	/**
-	 * Constructs the comparison scope corresponding to the given typed elements.
-	 * 
-	 * @param left
-	 *            Left of the compared elements.
-	 * @param right
-	 *            Right of the compared elements.
-	 * @param origin
-	 *            Common ancestor of the <code>left</code> and <code>right</code> compared elements.
-	 * @param monitor
-	 *            Monitor to report progress on.
-	 * @return The created comparison scope.
-	 */
-	private IComparisonScope buildComparisonScope(ITypedElement left, ITypedElement right,
-			ITypedElement origin, IProgressMonitor monitor) {
-		IStorageProviderAccessor storageAccessor = null;
-		if (getSubscriber() != null) {
-			storageAccessor = new SubscriberStorageAccessor(getSubscriber());
-		}
-		IStorage leftStorage = PlatformElementUtil.findFile(left);
-		if (leftStorage == null) {
-			leftStorage = StreamAccessorStorage.fromTypedElement(left);
-		}
-		IModelResolver resolver = EMFCompareIDEUIPlugin.getDefault().getModelResolverRegistry()
-				.getBestResolverFor(leftStorage);
-		final ComparisonScopeBuilder scopeBuilder = new ComparisonScopeBuilder(resolver,
-				new IdenticalResourceMinimizer(), storageAccessor);
-		return scopeBuilder.build(left, right, origin, monitor);
-	}
-
-	void compareInputChanged(ComparisonNode input, IProgressMonitor monitor) {
-		ICompareEditingDomain editingDomain = (ICompareEditingDomain)getCompareConfiguration().getProperty(
-				EMFCompareConstants.EDITING_DOMAIN);
-		editingDomain.getCommandStack().addCommandStackListener(this);
-
-		compareInputChanged(null, input.getTarget());
-	}
-
-	void compareInputChanged(ComparisonScopeInput input, IProgressMonitor monitor) {
-		ICompareEditingDomain editingDomain = (ICompareEditingDomain)getCompareConfiguration().getProperty(
-				EMFCompareConstants.EDITING_DOMAIN);
-		editingDomain.getCommandStack().addCommandStackListener(this);
-
-		EMFCompare comparator = (EMFCompare)getCompareConfiguration().getProperty(
-				EMFCompareConstants.COMPARATOR);
-
-		IComparisonScope comparisonScope = input.getComparisonScope();
-		Comparison comparison = comparator.compare(comparisonScope, BasicMonitor.toMonitor(monitor));
-		compareInputChanged(input.getComparisonScope(), comparison);
-	}
-
 	private static void unload(ResourceSet resourceSet) {
 		if (resourceSet != null) {
 			for (Resource resource : resourceSet.getResources()) {
@@ -493,344 +605,4 @@
 		}
 		return null;
 	}
-
-	void compareInputChanged(final IComparisonScope scope, final Comparison comparison) {
-		if (!getControl().isDisposed()) { // guard against disposal
-			fRoot = fAdapterFactory.adapt(comparison, ICompareInput.class);
-			getCompareConfiguration().setProperty(EMFCompareConstants.COMPARE_RESULT, comparison);
-
-			String message = null;
-			if (comparison.getDifferences().isEmpty()) {
-				message = "No Differences";
-			}
-
-			final String theMessage = message;
-			SWTUtil.safeAsyncExec(new Runnable() {
-				public void run() {
-					groupActionMenu.createActions(scope, comparison);
-					filterActionMenu.createActions(scope, comparison);
-					refreshAfterDiff(theMessage, fRoot);
-					initialSelection();
-				}
-			});
-		}
-	}
-
-	/*
-	 * (non-Javadoc)
-	 * @see org.eclipse.jface.viewers.AbstractTreeViewer#isExpandable(java.lang.Object)
-	 */
-	@Override
-	public boolean isExpandable(Object parent) {
-		if (hasFilters()) {
-			// workaround for 65762
-			return hasFilteredChildren(parent);
-		}
-		return super.isExpandable(parent);
-	}
-
-	/**
-	 * Public method to test if a element has any children that passed the filters
-	 * 
-	 * @param parent
-	 *            the element to test
-	 * @return return <code>true</code> if the element has at least a child that passed the filters
-	 */
-	public final boolean hasFilteredChildren(Object parent) {
-		Object[] rawChildren = getRawChildren(parent);
-		return containsNonFiltered(rawChildren, parent);
-	}
-
-	private boolean containsNonFiltered(Object[] elements, Object parent) {
-		if (elements.length == 0) {
-			return false;
-		}
-		if (!hasFilters()) {
-			return true;
-		}
-		ViewerFilter[] filters = getFilters();
-		for (int i = 0; i < elements.length; i++) {
-			Object object = elements[i];
-			if (!isFiltered(object, parent, filters)) {
-				return true;
-			}
-		}
-		return false;
-	}
-
-	/**
-	 * All element filter tests must go through this method. Can be overridden by subclasses.
-	 * 
-	 * @param object
-	 *            the object to filter
-	 * @param parent
-	 *            the parent
-	 * @param filters
-	 *            the filters to apply
-	 * @return true if the element is filtered
-	 */
-	protected boolean isFiltered(Object object, Object parent, ViewerFilter[] filters) {
-		for (int i = 0; i < filters.length; i++) {
-			ViewerFilter filter = filters[i];
-			if (!filter.select(this, parent, object)) {
-				return true;
-			}
-		}
-		return false;
-	}
-
-	private void refreshAfterDiff(String message, Object root) {
-		if (getControl().isDisposed()) {
-			return;
-		}
-
-		if (fParent != null) {
-			fParent.setTitleArgument(message);
-		}
-
-		refresh(root);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 * 
-	 * @see org.eclipse.jface.viewers.StructuredViewer#setComparer(org.eclipse.jface.viewers.IElementComparer)
-	 */
-	@Override
-	public void setComparer(IElementComparer comparer) {
-		// Wrap this new comparer in our own
-		super.setComparer(new DiffNodeComparer(comparer));
-	}
-
-	/**
-	 * {@inheritDoc}
-	 * 
-	 * @see org.eclipse.compare.structuremergeviewer.DiffTreeViewer#createToolItems(org.eclipse.jface.action.ToolBarManager)
-	 */
-	@Override
-	protected void createToolItems(ToolBarManager toolbarManager) {
-		super.createToolItems(toolbarManager);
-
-		// Add extension point contributions to the structure merge viewer toolbar
-		IServiceLocator workbench = PlatformUI.getWorkbench();
-		IMenuService menuService = (IMenuService)workbench.getService(IMenuService.class);
-		if (menuService != null) {
-			menuService.populateContributionManager(toolbarManager,
-					"toolbar:org.eclipse.emf.compare.structuremergeviewer.toolbar"); //$NON-NLS-1$
-		}
-
-		Bundle uiWorkbenchBundle = Platform.getBundle("org.eclipse.ui.workbench"); //$NON-NLS-1$
-		Version junoStart = Version.parseVersion("3.103"); //$NON-NLS-1$
-
-		// XXX MBA change to 3.105 once bug #366528 is fixed
-		Version keplerStart = Version.parseVersion("3.105"); //$NON-NLS-1$
-
-		if (uiWorkbenchBundle != null && uiWorkbenchBundle.getVersion().compareTo(junoStart) >= 0
-				&& uiWorkbenchBundle.getVersion().compareTo(keplerStart) < 0) {
-			IAction action = new CommandAction(PlatformUI.getWorkbench(),
-					"org.eclipse.emf.compare.ide.ui.saveComparisonModel"); //$NON-NLS-1$
-			action.setToolTipText("Save Comparison model");
-			action.setImageDescriptor(AbstractUIPlugin.imageDescriptorFromPlugin(
-					EMFCompareIDEUIPlugin.PLUGIN_ID, "icons/full/toolb16/saveas_edit.gif")); //$NON-NLS-1$
-			toolbarManager.add(action);
-		}
-
-		groupActionMenu = new GroupActionMenu(getStructureMergeViewerGrouper(), getGroupsMenuManager(),
-				getDefaultGroupProvider());
-		filterActionMenu = new FilterActionMenu(getStructureMergeViewerFilter(), getFiltersMenuManager());
-
-		toolbarManager.add(new Separator());
-		toolbarManager.add(new ExpandAllModelAction(this));
-		toolbarManager.add(new CollapseAllModelAction(this));
-		toolbarManager.add(new Separator());
-		toolbarManager.add(groupActionMenu);
-		toolbarManager.add(filterActionMenu);
-
-	}
-
-	/**
-	 * Returns the viewer filter that is to be applied on the structure viewer.
-	 * <p>
-	 * Note that this will be called from {@link #createToolItems(ToolBarManager)}, which is called from the
-	 * super-constructor, when we have had no time to initialize the {@link #structureMergeViewerFilter}
-	 * field.
-	 * </p>
-	 * 
-	 * @return The difference filter that is to be applied on the structure viewer.
-	 */
-	protected StructureMergeViewerFilter getStructureMergeViewerFilter() {
-		if (structureMergeViewerFilter == null) {
-			if (eventBus == null) {
-				eventBus = new EventBus();
-				eventBus.register(this);
-			}
-			structureMergeViewerFilter = new StructureMergeViewerFilter(eventBus);
-			structureMergeViewerFilter.install(this);
-		}
-		return structureMergeViewerFilter;
-	}
-
-	/**
-	 * Returns the viewer grouper that is to be applied on the structure viewer.
-	 * <p>
-	 * Note that this will be called from {@link #createToolItems(ToolBarManager)}, which is called from the
-	 * super-constructor, when we have had no time to initialize the {@link #structureMergeViewerGrouper}
-	 * field.
-	 * </p>
-	 * 
-	 * @return The viewer grouper grouper that is to be applied on the structure viewer.
-	 */
-	protected StructureMergeViewerGrouper getStructureMergeViewerGrouper() {
-		if (structureMergeViewerGrouper == null) {
-			if (eventBus == null) {
-				eventBus = new EventBus();
-				eventBus.register(this);
-			}
-			structureMergeViewerGrouper = new StructureMergeViewerGrouper(eventBus);
-			structureMergeViewerGrouper.install(this);
-		}
-		return structureMergeViewerGrouper;
-	}
-
-	/**
-	 * Returns the menu manager that is to be applied to groups on the structure viewer.
-	 * 
-	 * @return The menu manager that is to be applied to groups on the structure viewer.
-	 */
-	public MenuManager getGroupsMenuManager() {
-		if (groupsMenuManager == null) {
-			groupsMenuManager = new MenuManager();
-		}
-		return groupsMenuManager;
-	}
-
-	/**
-	 * Returns the menu manager that is to be applied to filters on the structure viewer.
-	 * 
-	 * @return The menu manager that is to be applied to filters on the structure viewer.
-	 */
-	public MenuManager getFiltersMenuManager() {
-		if (filtersMenuManager == null) {
-			filtersMenuManager = new MenuManager();
-		}
-		return filtersMenuManager;
-	}
-
-	/**
-	 * Returns the default group provider that is to be applied on the structure viewer.
-	 * 
-	 * @return The default group provider that is to be applied on the structure viewer.
-	 */
-	public DefaultGroupProvider getDefaultGroupProvider() {
-		if (defaultGroupProvider == null) {
-			defaultGroupProvider = new DefaultGroupProvider();
-		}
-		return defaultGroupProvider;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 * 
-	 * @see org.eclipse.compare.structuremergeviewer.DiffTreeViewer#inputChanged(java.lang.Object,
-	 *      java.lang.Object)
-	 */
-	@Override
-	protected void inputChanged(Object input, Object oldInput) {
-		if (oldInput instanceof ICompareInput) {
-			ICompareInput old = (ICompareInput)oldInput;
-			old.removeCompareInputChangeListener(fCompareInputChangeListener);
-		}
-		if (input instanceof ICompareInput) {
-			ICompareInput ci = (ICompareInput)input;
-			ci.addCompareInputChangeListener(fCompareInputChangeListener);
-
-			// Hack to display a message in the tree viewer while the differences are being computed.
-			TreeItem item = new TreeItem(getTree(), SWT.NONE);
-			item.setText("Computing model differences...");
-
-			compareInputChanged(ci);
-		}
-	}
-
-	/**
-	 * {@inheritDoc}
-	 * 
-	 * @see org.eclipse.compare.structuremergeviewer.DiffTreeViewer#handleDispose(org.eclipse.swt.events.DisposeEvent)
-	 */
-	@Override
-	protected void handleDispose(DisposeEvent event) {
-		Object input = getInput();
-		if (input instanceof ICompareInput) {
-			ICompareInput ci = (ICompareInput)input;
-			ci.removeCompareInputChangeListener(fCompareInputChangeListener);
-		}
-		compareInputChanged((ICompareInput)null);
-		fAdapterFactory.dispose();
-
-		super.handleDispose(event);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 * 
-	 * @see org.eclipse.emf.common.command.CommandStackListener#commandStackChanged(java.util.EventObject)
-	 */
-	public void commandStackChanged(EventObject event) {
-		Command mostRecentCommand = ((CommandStack)event.getSource()).getMostRecentCommand();
-		if (mostRecentCommand instanceof ICompareCopyCommand) {
-			Collection<?> affectedObjects = mostRecentCommand.getAffectedObjects();
-
-			SWTUtil.safeAsyncExec(new Runnable() {
-				public void run() {
-					refresh(true);
-				}
-			});
-			if (!affectedObjects.isEmpty()) {
-				// MUST NOT call a setSelection with a list, o.e.compare does not handle it (cf
-				// org.eclipse.compare.CompareEditorInput#getElement(ISelection))
-				final Object adaptedAffectedObject = fAdapterFactory.adapt(getFirst(affectedObjects, null),
-						ICompareInput.class);
-				SWTUtil.safeAsyncExec(new Runnable() {
-					public void run() {
-						setSelectionToWidget(new StructuredSelection(adaptedAffectedObject), true);
-					}
-				});
-			}
-		} else {
-			// FIXME, should recompute the difference, something happened outside of this compare editor
-		}
-	}
-
-	/**
-	 * {@inheritDoc}
-	 * 
-	 * @see org.eclipse.jface.viewers.AbstractTreeViewer#getSortedChildren(java.lang.Object)
-	 */
-	@Override
-	protected Object[] getSortedChildren(Object parentElementOrTreePath) {
-		Object[] result = super.getSortedChildren(parentElementOrTreePath);
-		if (parentElementOrTreePath instanceof Adapter
-				&& ((Adapter)parentElementOrTreePath).getTarget() instanceof Conflict) {
-
-			Collections.sort(Arrays.asList(result), new Comparator<Object>() {
-				public int compare(Object o1, Object o2) {
-					return getValue(o1) - getValue(o2);
-				}
-
-				public int getValue(Object o) {
-					int value = 0;
-					if (o instanceof Adapter && ((Adapter)o).getTarget() instanceof Diff) {
-						if (((Diff)((Adapter)o).getTarget()).getSource() == DifferenceSource.LEFT) {
-							value = 1;
-						} else {
-							value = 2;
-						}
-					}
-					return value;
-				}
-			});
-
-		}
-		return result;
-	}
 }
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/EMFCompareStructureMergeViewerContentProvider.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/EMFCompareStructureMergeViewerContentProvider.java
index 492208b..901488d 100644
--- a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/EMFCompareStructureMergeViewerContentProvider.java
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/EMFCompareStructureMergeViewerContentProvider.java
@@ -23,6 +23,8 @@
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 
+import java.util.Collection;
+import java.util.LinkedHashSet;
 import java.util.List;
 
 import org.eclipse.compare.CompareConfiguration;
@@ -97,8 +99,19 @@
 		if (element instanceof Adapter) {
 			ret = getAdapterFactory().adapt(super.getParent(((Adapter)element).getTarget()),
 					ICompareInput.class);
+			if (ret instanceof ComparisonNode) {
+				Comparison root = ((ComparisonNode)ret).getTarget();
+				final Iterable<? extends IDifferenceGroup> groups = fViewerGrouper.getGroups(root);
+				Collection<IDifferenceGroup> parentGroups = new LinkedHashSet<IDifferenceGroup>();
+				for (IDifferenceGroup iDifferenceGroup : groups) {
+					parentGroups.add(iDifferenceGroup);
+				}
+				if (!parentGroups.isEmpty()) {
+					ret = parentGroups;
+				}
+			}
 		} else if (element instanceof IDifferenceGroup) {
-			ret = ((IDifferenceGroup)element).getComparison();
+			ret = getAdapterFactory().adapt(((IDifferenceGroup)element).getComparison(), ICompareInput.class);
 		} else {
 			ret = null;
 		}
@@ -298,7 +311,7 @@
 	 *            the given differences.
 	 * @return true if the object should be contained in the given differences, false otherwise.
 	 */
-	private boolean isPartOfGroup(Object object, final Iterable<? extends Diff> differences) {
+	public static boolean isPartOfGroup(Object object, final Iterable<? extends Diff> differences) {
 		final Predicate<? super EObject> isPartOfTree = new Predicate<EObject>() {
 			public boolean apply(EObject input) {
 				return Iterables.contains(differences, input);
@@ -380,7 +393,7 @@
 		 * 
 		 * @return the wrapped AbstractEDiffNode.
 		 */
-		private AbstractEDiffNode delegate() {
+		public AbstractEDiffNode delegate() {
 			return fDelegate;
 		}
 
@@ -510,5 +523,15 @@
 		public boolean isAdapterForType(Object type) {
 			return delegate().isAdapterForType(type);
 		}
+
+		@Override
+		public boolean equals(Object obj) {
+			return delegate().equals(obj);
+		}
+
+		@Override
+		public int hashCode() {
+			return delegate().hashCode();
+		}
 	}
 }
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/EMFCompareStructureMergeViewerCreator.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/EMFCompareStructureMergeViewerCreator.java
index b9b13a0..9c8b99d 100644
--- a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/EMFCompareStructureMergeViewerCreator.java
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/EMFCompareStructureMergeViewerCreator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2012 Obeo.
+ * Copyright (c) 2012, 2013 Obeo.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/AbstractAcceptRejectAllChanges.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/AbstractAcceptRejectAllChanges.java
new file mode 100644
index 0000000..6ad6ac9
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/AbstractAcceptRejectAllChanges.java
@@ -0,0 +1,252 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler;
+
+import static com.google.common.collect.Iterables.filter;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
+import java.util.List;
+
+import org.eclipse.compare.CompareConfiguration;
+import org.eclipse.compare.CompareEditorInput;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.common.command.CompoundCommand;
+import org.eclipse.emf.compare.Comparison;
+import org.eclipse.emf.compare.Diff;
+import org.eclipse.emf.compare.DifferenceSource;
+import org.eclipse.emf.compare.DifferenceState;
+import org.eclipse.emf.compare.command.ICompareCopyCommand;
+import org.eclipse.emf.compare.domain.ICompareEditingDomain;
+import org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.util.EMFCompareUIHandlerUtil;
+import org.eclipse.emf.compare.rcp.EMFCompareRCPPlugin;
+import org.eclipse.emf.compare.rcp.ui.internal.EMFCompareConstants;
+import org.eclipse.emf.compare.utils.EMFComparePredicates;
+import org.eclipse.emf.ecore.change.util.ChangeRecorder;
+import org.eclipse.emf.edit.command.ChangeCommand;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * Abstract handler that manages the accept all and reject all actions (when one side of a diff is not
+ * editable).
+ * 
+ * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
+ */
+public abstract class AbstractAcceptRejectAllChanges extends AbstractHandler {
+
+	/** The compare configuration object used to get the compare model. */
+	protected CompareConfiguration configuration;
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.core.commands.IHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		Object editorInput = HandlerUtil.getVariable(event, ISources.ACTIVE_EDITOR_INPUT_NAME);
+		if (editorInput instanceof CompareEditorInput) {
+			configuration = ((CompareEditorInput)editorInput).getCompareConfiguration();
+			boolean rightEditableOnly = !configuration.isLeftEditable() && configuration.isRightEditable();
+			boolean leftEditableOnly = configuration.isLeftEditable() && !configuration.isRightEditable();
+			if (leftEditableOnly) {
+				manageChanges(false);
+			} else if (rightEditableOnly) {
+				manageChanges(true);
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Check if the way of merge of the given diff correspond to a copy or a simple change state (unresolved
+	 * to merged).
+	 * 
+	 * @param diff
+	 *            the given diff.
+	 * @param leftToRight
+	 *            the way of merge.
+	 * @return true if the way of merge of the given diff correspond to a copy, false if it corresponds to a
+	 *         simple change state.
+	 */
+	protected abstract boolean isCopyDiffCase(Diff diff, boolean leftToRight);
+
+	/**
+	 * Manage changes (copy or change state) for all non-conflicting diffs.
+	 * 
+	 * @param leftToRight
+	 *            the way of merge.
+	 */
+	private void manageChanges(final boolean leftToRight) {
+		final List<Diff> differences;
+		Comparison comparison = (Comparison)configuration.getProperty(EMFCompareConstants.COMPARE_RESULT);
+		if (comparison.isThreeWay()) {
+			differences = ImmutableList.copyOf(filter(comparison.getDifferences(), new Predicate<Diff>() {
+				public boolean apply(Diff diff) {
+					final boolean unresolved = diff.getState() == DifferenceState.UNRESOLVED;
+					final boolean nonConflictual = diff.getConflict() == null;
+					final boolean fromLeftToRight = leftToRight && diff.getSource() == DifferenceSource.LEFT;
+					final boolean fromRightToLeft = !leftToRight
+							&& diff.getSource() == DifferenceSource.RIGHT;
+					return unresolved && nonConflictual && (fromLeftToRight || fromRightToLeft);
+				}
+			}));
+		} else {
+			differences = ImmutableList.copyOf(filter(comparison.getDifferences(), EMFComparePredicates
+					.hasState(DifferenceState.UNRESOLVED)));
+		}
+
+		if (differences.size() > 0) {
+
+			ICompareEditingDomain editingDomain = (ICompareEditingDomain)configuration
+					.getProperty(EMFCompareConstants.EDITING_DOMAIN);
+
+			AcceptRejectAllChangesCompoundCommand compoundCommand = new AcceptRejectAllChangesCompoundCommand(
+					leftToRight);
+
+			for (Diff diff : differences) {
+				if (DifferenceState.UNRESOLVED == diff.getState()) {
+					if (isCopyDiffCase(diff, leftToRight)) {
+						EMFCompareUIHandlerUtil.setMergeDataForDiff(diff, leftToRight, configuration
+								.isLeftEditable(), configuration.isRightEditable());
+						compoundCommand.append(editingDomain.createCopyCommand(Lists.newArrayList(diff),
+								leftToRight, EMFCompareRCPPlugin.getDefault().getMergerRegistry()));
+					} else {
+						compoundCommand.append(createChangeStateFromUnresolvedToMergedCommand(diff,
+								!leftToRight));
+					}
+				}
+			}
+
+			editingDomain.getCommandStack().execute(compoundCommand);
+		}
+	}
+
+	/**
+	 * Execute a command that change the state of the given diff from {@link DifferenceState#UNRESOLVED} to
+	 * {@link DifferenceState#MERGED}.
+	 * 
+	 * @param diffToChangeState
+	 *            the given diff.
+	 * @param leftToRight
+	 *            the way of merge.
+	 * @return A command that change the state of the given diff from {@link DifferenceState#UNRESOLVED} to
+	 *         {@link DifferenceState#MERGED}.
+	 */
+	protected Command createChangeStateFromUnresolvedToMergedCommand(Diff diffToChangeState,
+			boolean leftToRight) {
+		if (diffToChangeState != null) {
+			ICompareEditingDomain compareEditingDomain = (ICompareEditingDomain)configuration
+					.getProperty(EMFCompareConstants.EDITING_DOMAIN);
+			Command changeStateCommand = new AcceptRejectAllChangesCommand(compareEditingDomain
+					.getChangeRecorder(), diffToChangeState, leftToRight, configuration);
+			return changeStateCommand;
+		}
+		return null;
+	}
+
+	/**
+	 * A specific {@link ChangeCommand} that change the state of the given diff from
+	 * {@link DifferenceState#UNRESOLVED} to {@link DifferenceState#MERGED}.
+	 * 
+	 * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
+	 */
+	private static class AcceptRejectAllChangesCommand extends ChangeCommand implements ICompareCopyCommand {
+
+		/** The difference concerned by the command. */
+		private Diff difference;
+
+		/** The way of merge. */
+		private boolean leftToRight;
+
+		/** The compare configuration object. */
+		private CompareConfiguration configuration;
+
+		/**
+		 * Constructor.
+		 * 
+		 * @param changeRecorder
+		 *            the change recorder used by the command.
+		 * @param difference
+		 *            the difference concerned by the command.
+		 * @param leftToRight
+		 *            the way of merge.
+		 * @param configuration
+		 *            the compare configuration object.
+		 */
+		public AcceptRejectAllChangesCommand(ChangeRecorder changeRecorder, Diff difference,
+				boolean leftToRight, CompareConfiguration configuration) {
+			super(changeRecorder, difference);
+			this.difference = difference;
+			this.leftToRight = leftToRight;
+			this.configuration = configuration;
+		}
+
+		/**
+		 * {@inheritDoc}
+		 * 
+		 * @see org.eclipse.emf.edit.command.ChangeCommand#doExecute()
+		 */
+		@Override
+		public void doExecute() {
+			EMFCompareUIHandlerUtil.setMergeDataForDiff(difference, leftToRight, configuration
+					.isLeftEditable(), configuration.isRightEditable());
+			difference.setState(DifferenceState.MERGED);
+
+		}
+
+		/**
+		 * Returns true if the command will be applied from left to right side, false otherwise.
+		 * 
+		 * @return true if the command will be applied from left to right side, false otherwise.
+		 */
+		public boolean isLeftToRight() {
+			return leftToRight;
+		}
+
+	}
+
+	/**
+	 * A specific {@link CompoundCommand} that implements {@link ICompareCopyCommand}.
+	 * 
+	 * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
+	 */
+	private static class AcceptRejectAllChangesCompoundCommand extends CompoundCommand implements ICompareCopyCommand {
+
+		/** The way of merge. */
+		private boolean leftToRight;
+
+		/**
+		 * Constructor.
+		 * 
+		 * @param leftToRight
+		 *            the way of merge.
+		 */
+		public AcceptRejectAllChangesCompoundCommand(boolean leftToRight) {
+			this.leftToRight = leftToRight;
+		}
+
+		/**
+		 * Returns true if the command will be applied from left to right side, false otherwise.
+		 * 
+		 * @return true if the command will be applied from left to right side, false otherwise.
+		 */
+		public boolean isLeftToRight() {
+			return leftToRight;
+		}
+
+	}
+}
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/AbstractAcceptRejectChange.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/AbstractAcceptRejectChange.java
new file mode 100644
index 0000000..317da68
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/AbstractAcceptRejectChange.java
@@ -0,0 +1,181 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler;
+
+import com.google.common.collect.ImmutableSet;
+
+import org.eclipse.compare.CompareConfiguration;
+import org.eclipse.compare.CompareEditorInput;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.common.notify.Adapter;
+import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.emf.compare.Diff;
+import org.eclipse.emf.compare.DifferenceState;
+import org.eclipse.emf.compare.command.ICompareCopyCommand;
+import org.eclipse.emf.compare.domain.ICompareEditingDomain;
+import org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.util.EMFCompareUIHandlerUtil;
+import org.eclipse.emf.compare.internal.utils.DiffUtil;
+import org.eclipse.emf.compare.rcp.ui.internal.EMFCompareConstants;
+import org.eclipse.emf.ecore.change.util.ChangeRecorder;
+import org.eclipse.emf.edit.command.ChangeCommand;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * Abstract handler that manages the accept and reject actions (when one side of a diff is not editable).
+ * 
+ * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
+ */
+public abstract class AbstractAcceptRejectChange extends AbstractHandler {
+
+	/** The compare configuration object used to get the compare model. */
+	private CompareConfiguration configuration;
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.core.commands.IHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		Object editorInput = HandlerUtil.getVariable(event, ISources.ACTIVE_EDITOR_INPUT_NAME);
+		if (editorInput instanceof CompareEditorInput) {
+			configuration = ((CompareEditorInput)editorInput).getCompareConfiguration();
+			Object diffNode = ((CompareEditorInput)editorInput).getSelectedEdition();
+			if (diffNode instanceof Adapter) {
+				Notifier diff = ((Adapter)diffNode).getTarget();
+				if (diff instanceof Diff) {
+					boolean rightEditableOnly = !configuration.isLeftEditable()
+							&& configuration.isRightEditable();
+					boolean leftEditableOnly = configuration.isLeftEditable()
+							&& !configuration.isRightEditable();
+					if (leftEditableOnly) {
+						if (isCopyDiffCase((Diff)diff, false)) {
+							EMFCompareUIHandlerUtil.copyDiff((Diff)diff, false, configuration);
+						} else {
+							changeStateFromUnresolvedToMerged((Diff)diff, true);
+						}
+					} else if (rightEditableOnly) {
+						if (isCopyDiffCase((Diff)diff, true)) {
+							EMFCompareUIHandlerUtil.copyDiff((Diff)diff, true, configuration);
+						} else {
+							changeStateFromUnresolvedToMerged((Diff)diff, false);
+						}
+					}
+					// Select next diff
+					EMFCompareUIHandlerUtil.navigate(true, configuration);
+				}
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Check if the way of merge of the given diff correspond to a copy or a simple change state (unresolved
+	 * to merged).
+	 * 
+	 * @param diff
+	 *            the given diff.
+	 * @param leftToRight
+	 *            the way of merge.
+	 * @return true if the way of merge of the given diff correspond to a copy, false if it corresponds to a
+	 *         simple change state.
+	 */
+	protected abstract boolean isCopyDiffCase(Diff diff, boolean leftToRight);
+
+	/**
+	 * Execute a command that change the state of the given diff from {@link DifferenceState#UNRESOLVED} to
+	 * {@link DifferenceState#MERGED}.
+	 * 
+	 * @param diffToChangeState
+	 *            the given diff.
+	 * @param leftToRight
+	 *            the way of merge.
+	 */
+	private void changeStateFromUnresolvedToMerged(Diff diffToChangeState, boolean leftToRight) {
+		if (diffToChangeState != null) {
+			ICompareEditingDomain compareEditingDomain = (ICompareEditingDomain)configuration
+					.getProperty(EMFCompareConstants.EDITING_DOMAIN);
+			Command changeStateCommand = new AcceptRejectChangeCommand(compareEditingDomain
+					.getChangeRecorder(), diffToChangeState, leftToRight, configuration);
+			compareEditingDomain.getCommandStack().execute(changeStateCommand);
+		}
+	}
+
+	/**
+	 * A specific {@link ChangeCommand} that change the state of the given diff and all its required diffs
+	 * from {@link DifferenceState#UNRESOLVED} to {@link DifferenceState#MERGED}.
+	 * 
+	 * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
+	 */
+	private static class AcceptRejectChangeCommand extends ChangeCommand implements ICompareCopyCommand {
+
+		/** The difference concerned by the command. */
+		private Diff difference;
+
+		/** The way of merge. */
+		private boolean leftToRight;
+
+		/** The compare configuration object. */
+		private CompareConfiguration configuration;
+
+		/**
+		 * Constructor.
+		 * 
+		 * @param changeRecorder
+		 *            the change recorder used by the command.
+		 * @param difference
+		 *            the difference concerned by the command.
+		 * @param leftToRight
+		 *            the way of merge.
+		 * @param configuration
+		 *            the compare configuration object.
+		 */
+		public AcceptRejectChangeCommand(ChangeRecorder changeRecorder, Diff difference, boolean leftToRight,
+				CompareConfiguration configuration) {
+			super(changeRecorder, ImmutableSet.<Notifier> builder().add(difference).addAll(
+					DiffUtil.getRequires(difference, leftToRight, difference.getSource())).build());
+			this.difference = difference;
+			this.leftToRight = leftToRight;
+			this.configuration = configuration;
+		}
+
+		/**
+		 * {@inheritDoc}
+		 * 
+		 * @see org.eclipse.emf.edit.command.ChangeCommand#doExecute()
+		 */
+		@Override
+		public void doExecute() {
+			for (Diff require : DiffUtil.getRequires(difference, leftToRight, difference.getSource())) {
+				EMFCompareUIHandlerUtil.setMergeDataForDiff(require, leftToRight, configuration
+						.isLeftEditable(), configuration.isRightEditable());
+				require.setState(DifferenceState.MERGED);
+			}
+			EMFCompareUIHandlerUtil.setMergeDataForDiff(difference, leftToRight, configuration
+					.isLeftEditable(), configuration.isRightEditable());
+			difference.setState(DifferenceState.MERGED);
+
+		}
+
+		/**
+		 * Returns true if the command will be applied from left to right side, false otherwise.
+		 * 
+		 * @return true if the command will be applied from left to right side, false otherwise.
+		 */
+		public boolean isLeftToRight() {
+			return leftToRight;
+		}
+	}
+
+}
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/AbstractMergedAllTo.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/AbstractMergedAllTo.java
new file mode 100644
index 0000000..0cc2812
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/AbstractMergedAllTo.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler;
+
+import org.eclipse.compare.CompareConfiguration;
+import org.eclipse.compare.CompareEditorInput;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * Abstract Handler that manages a merge of a all non-conflicting difference in case of both sides of the
+ * comparison are editable.
+ * 
+ * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
+ * @since 3.0
+ */
+public abstract class AbstractMergedAllTo extends AbstractHandler {
+
+	/** The compare configuration object used to get the compare model. */
+	private CompareConfiguration configuration;
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.core.commands.IHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		Object editorInput = HandlerUtil.getVariable(event, ISources.ACTIVE_EDITOR_INPUT_NAME);
+		if (editorInput instanceof CompareEditorInput) {
+			setConfiguration(((CompareEditorInput)editorInput).getCompareConfiguration());
+			copyAllDiffs();
+		}
+		return null;
+	}
+
+	/**
+	 * Copy all non-conflicting differences.
+	 */
+	protected abstract void copyAllDiffs();
+
+	/**
+	 * Get the compare configuration object.
+	 * 
+	 * @return the configuration
+	 */
+	public CompareConfiguration getConfiguration() {
+		return configuration;
+	}
+
+	/**
+	 * Set the compare configuration object.
+	 * 
+	 * @param configuration
+	 *            the configuration to set
+	 */
+	public void setConfiguration(CompareConfiguration configuration) {
+		this.configuration = configuration;
+	}
+}
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/AbstractMergedTo.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/AbstractMergedTo.java
new file mode 100644
index 0000000..ddb0173
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/AbstractMergedTo.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler;
+
+import org.eclipse.compare.CompareConfiguration;
+import org.eclipse.compare.CompareEditorInput;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.emf.common.notify.Adapter;
+import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.emf.compare.Diff;
+import org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.util.EMFCompareUIHandlerUtil;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * Abstract Handler that manages a merge of a difference in case of both sides of the comparison are editable.
+ * 
+ * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
+ * @since 3.0
+ */
+public abstract class AbstractMergedTo extends AbstractHandler {
+
+	/** The compare configuration object used to get the compare model. */
+	private CompareConfiguration configuration;
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.core.commands.IHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		Object editorInput = HandlerUtil.getVariable(event, ISources.ACTIVE_EDITOR_INPUT_NAME);
+		if (editorInput instanceof CompareEditorInput) {
+			setConfiguration(((CompareEditorInput)editorInput).getCompareConfiguration());
+			Object diffNode = ((CompareEditorInput)editorInput).getSelectedEdition();
+			if (diffNode instanceof Adapter) {
+				Notifier diff = ((Adapter)diffNode).getTarget();
+				if (diff instanceof Diff) {
+					copyDiff((Diff)diff);
+					// Select next diff
+					EMFCompareUIHandlerUtil.navigate(true, configuration);
+				}
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Copy the diff.
+	 * 
+	 * @param diff
+	 *            the given diff.
+	 */
+	protected abstract void copyDiff(Diff diff);
+
+	/**
+	 * Get the compare configuration object.
+	 * 
+	 * @return the configuration
+	 */
+	public CompareConfiguration getConfiguration() {
+		return configuration;
+	}
+
+	/**
+	 * Set the compare configuration object.
+	 * 
+	 * @param configuration
+	 *            the configuration to set
+	 */
+	public void setConfiguration(CompareConfiguration configuration) {
+		this.configuration = configuration;
+	}
+}
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/AcceptAllChanges.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/AcceptAllChanges.java
new file mode 100644
index 0000000..2929d57
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/AcceptAllChanges.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler;
+
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.fromSide;
+
+import org.eclipse.emf.compare.Diff;
+import org.eclipse.emf.compare.DifferenceSource;
+
+/**
+ * Handler that manages a merge of all non-conflicting differences in case of one side of the comparison is
+ * not editable.
+ * 
+ * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
+ * @since 3.0
+ */
+public class AcceptAllChanges extends AbstractAcceptRejectAllChanges {
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.handler.AbstractAcceptRejectAllChanges#isCopyDiffCase(org.eclipse.emf.compare.Diff,
+	 *      boolean)
+	 */
+	@Override
+	protected boolean isCopyDiffCase(Diff diff, boolean leftToRight) {
+		if (leftToRight) {
+			return fromSide(DifferenceSource.LEFT).apply(diff);
+		} else {
+			return fromSide(DifferenceSource.RIGHT).apply(diff);
+		}
+	}
+
+}
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/AcceptChange.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/AcceptChange.java
new file mode 100644
index 0000000..8996720
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/AcceptChange.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler;
+
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.fromSide;
+
+import org.eclipse.emf.compare.Diff;
+import org.eclipse.emf.compare.DifferenceSource;
+
+/**
+ * Handler that manages a merge of a difference in case of one side of the comparison is not editable.
+ * 
+ * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
+ * @since 3.0
+ */
+public class AcceptChange extends AbstractAcceptRejectChange {
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.handler.AbstractAcceptRejectChange#isCopyDiffCase(org.eclipse.emf.compare.Diff,
+	 *      boolean)
+	 */
+	@Override
+	protected boolean isCopyDiffCase(Diff diff, boolean leftToRight) {
+		if (leftToRight) {
+			return fromSide(DifferenceSource.LEFT).apply(diff);
+		} else {
+			return fromSide(DifferenceSource.RIGHT).apply(diff);
+		}
+	}
+
+}
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/DropDownHandler.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/DropDownHandler.java
new file mode 100644
index 0000000..3d94941
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/DropDownHandler.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 2012, 2013 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler;
+
+import java.util.Map;
+
+import org.eclipse.compare.CompareConfiguration;
+import org.eclipse.compare.CompareEditorInput;
+import org.eclipse.compare.internal.CompareEditor;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.emf.compare.ide.ui.internal.EMFCompareIDEUIPlugin;
+import org.eclipse.emf.compare.rcp.ui.internal.EMFCompareConstants;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.ToolItem;
+import org.eclipse.swt.widgets.Widget;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.commands.IElementUpdater;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.ui.menus.UIElement;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+/**
+ * Handler that manages the click on the dropdown menu of the toolbar of the structure merge viewer.
+ * 
+ * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
+ */
+public class DropDownHandler extends AbstractHandler implements IElementUpdater {
+
+	/** The compare configuration object. */
+	private CompareConfiguration configuration;
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.core.commands.IHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+
+		Object editorInput = HandlerUtil.getVariable(event, ISources.ACTIVE_EDITOR_INPUT_NAME);
+		if (editorInput instanceof CompareEditorInput) {
+			Object trigger = event.getTrigger();
+			if (trigger instanceof Event) {
+				Event eventWidget = (Event)event.getTrigger();
+				Widget widget = eventWidget.widget;
+				if (widget instanceof ToolItem) {
+					ToolItem toolItem = (ToolItem)widget;
+					configuration = ((CompareEditorInput)editorInput).getCompareConfiguration();
+					Boolean mergeWay = (Boolean)configuration.getProperty(EMFCompareConstants.MERGE_WAY);
+					if (mergeWay == null || mergeWay.booleanValue()) {
+						configuration.setProperty(EMFCompareConstants.MERGE_WAY, new Boolean(false));
+						toolItem.setImage(EMFCompareIDEUIPlugin
+								.getImage("icons/full/toolb16/right_to_left.gif")); //$NON-NLS-1$
+					} else {
+						configuration.setProperty(EMFCompareConstants.MERGE_WAY, new Boolean(true));
+						toolItem.setImage(EMFCompareIDEUIPlugin
+								.getImage("icons/full/toolb16/left_to_right.gif")); //$NON-NLS-1$
+					}
+				}
+			}
+		}
+
+		return null;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.ui.commands.IElementUpdater#updateElement(UIElement, Map)
+	 */
+	public void updateElement(UIElement element, Map parameters) {
+		if (configuration == null) {
+			Object value = parameters.get("org.eclipse.ui.IWorkbenchWindow"); //$NON-NLS-1$
+			if (value instanceof IWorkbenchWindow) {
+				IWorkbenchPage pa = ((IWorkbenchWindow)value).getActivePage();
+				IEditorPart editor = pa.getActiveEditor();
+				if (editor instanceof CompareEditor) {
+					IEditorInput editorInput = editor.getEditorInput();
+					if (editorInput instanceof CompareEditorInput) {
+						configuration = ((CompareEditorInput)editorInput).getCompareConfiguration();
+					}
+				}
+			}
+		}
+		if (configuration != null) {
+			Boolean mergeWay = (Boolean)configuration.getProperty(EMFCompareConstants.MERGE_WAY);
+			if (mergeWay == null || mergeWay.booleanValue()) {
+				element.setIcon(AbstractUIPlugin.imageDescriptorFromPlugin(EMFCompareIDEUIPlugin.PLUGIN_ID,
+						"icons/full/toolb16/left_to_right.gif")); //$NON-NLS-1$
+			} else {
+				element.setIcon(AbstractUIPlugin.imageDescriptorFromPlugin(EMFCompareIDEUIPlugin.PLUGIN_ID,
+						"icons/full/toolb16/right_to_left.gif")); //$NON-NLS-1$
+			}
+		}
+	}
+}
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/DropDownLeftToRight.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/DropDownLeftToRight.java
new file mode 100644
index 0000000..beeca1c
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/DropDownLeftToRight.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2012, 2013 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler;
+
+import org.eclipse.compare.CompareConfiguration;
+import org.eclipse.compare.CompareEditorInput;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.emf.compare.rcp.ui.internal.EMFCompareConstants;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * Handler that manages the click on the menu item left to right in the dropdown menu of the toolbar of the
+ * structure merge viewer.
+ * 
+ * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
+ */
+public class DropDownLeftToRight extends AbstractHandler {
+
+	/** The compare configuration object. */
+	private CompareConfiguration configuration;
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.core.commands.IHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		Object editorInput = HandlerUtil.getVariable(event, ISources.ACTIVE_EDITOR_INPUT_NAME);
+		if (editorInput instanceof CompareEditorInput) {
+			configuration = ((CompareEditorInput)editorInput).getCompareConfiguration();
+			configuration.setProperty(EMFCompareConstants.MERGE_WAY, new Boolean(true));
+		}
+
+		ICommandService commandService = (ICommandService)PlatformUI.getWorkbench().getService(
+				ICommandService.class);
+		commandService.refreshElements("org.eclipse.emf.compare.ide.ui.dropdown", null); //$NON-NLS-1$
+
+		return null;
+	}
+}
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/DropDownRightToLeft.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/DropDownRightToLeft.java
new file mode 100644
index 0000000..3daff91
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/DropDownRightToLeft.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2012, 2013 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler;
+
+import org.eclipse.compare.CompareConfiguration;
+import org.eclipse.compare.CompareEditorInput;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.emf.compare.rcp.ui.internal.EMFCompareConstants;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * Handler that manages the click on the menu item right to left in the dropdown menu of the toolbar of the
+ * structure merge viewer.
+ * 
+ * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
+ */
+public class DropDownRightToLeft extends AbstractHandler {
+
+	/** The compare configuration object. */
+	private CompareConfiguration configuration;
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.core.commands.IHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		Object editorInput = HandlerUtil.getVariable(event, ISources.ACTIVE_EDITOR_INPUT_NAME);
+		if (editorInput instanceof CompareEditorInput) {
+			configuration = ((CompareEditorInput)editorInput).getCompareConfiguration();
+			configuration.setProperty(EMFCompareConstants.MERGE_WAY, new Boolean(false));
+		}
+		ICommandService commandService = (ICommandService)PlatformUI.getWorkbench().getService(
+				ICommandService.class);
+		commandService.refreshElements("org.eclipse.emf.compare.ide.ui.dropdown", null); //$NON-NLS-1$
+		return null;
+	}
+}
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/MergedAllToLeft.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/MergedAllToLeft.java
new file mode 100644
index 0000000..543f4c9
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/MergedAllToLeft.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler;
+
+import org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.util.EMFCompareUIHandlerUtil;
+
+/**
+ * Handler that manages a merge from left to right of all non-conflicting differences in case of both sides of
+ * the comparison are editable.
+ * 
+ * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
+ * @since 3.0
+ */
+public class MergedAllToLeft extends AbstractMergedAllTo {
+
+	@Override
+	protected void copyAllDiffs() {
+		EMFCompareUIHandlerUtil.copyAllDiffs(false, getConfiguration());
+	}
+}
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/MergedAllToRight.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/MergedAllToRight.java
new file mode 100644
index 0000000..eab8d32
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/MergedAllToRight.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler;
+
+import org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.util.EMFCompareUIHandlerUtil;
+
+/**
+ * Handler that manages a merge from left to right of all non-conflicting differences in case of both sides of
+ * the comparison are editable.
+ * 
+ * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
+ * @since 3.0
+ */
+public class MergedAllToRight extends AbstractMergedAllTo {
+
+	@Override
+	protected void copyAllDiffs() {
+		EMFCompareUIHandlerUtil.copyAllDiffs(true, getConfiguration());
+	}
+}
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/MergedToLeft.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/MergedToLeft.java
new file mode 100644
index 0000000..dde61ec
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/MergedToLeft.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler;
+
+import org.eclipse.emf.compare.Diff;
+import org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.util.EMFCompareUIHandlerUtil;
+
+/**
+ * Handler that manages a merge from right to left of a difference in case of both sides of the comparison are
+ * editable.
+ * 
+ * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
+ * @since 3.0
+ */
+public class MergedToLeft extends AbstractMergedTo {
+
+	@Override
+	protected void copyDiff(Diff diff) {
+		EMFCompareUIHandlerUtil.copyDiff(diff, false, getConfiguration());
+	}
+}
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/MergedToRight.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/MergedToRight.java
new file mode 100644
index 0000000..5e754f3
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/MergedToRight.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler;
+
+import org.eclipse.emf.compare.Diff;
+import org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.util.EMFCompareUIHandlerUtil;
+
+/**
+ * Handler that manages a merge from left to right of a difference in case of both sides of the comparison are
+ * editable.
+ * 
+ * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
+ * @since 3.0
+ */
+public class MergedToRight extends AbstractMergedTo {
+
+	@Override
+	protected void copyDiff(Diff diff) {
+		EMFCompareUIHandlerUtil.copyDiff(diff, true, getConfiguration());
+	}
+
+}
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/RejectAllChanges.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/RejectAllChanges.java
new file mode 100644
index 0000000..1e9cd62
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/RejectAllChanges.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler;
+
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.fromSide;
+
+import org.eclipse.emf.compare.Diff;
+import org.eclipse.emf.compare.DifferenceSource;
+
+/**
+ * Handler that manages a merge of all non-conflicting differences in case of one side of the comparison is
+ * not editable.
+ * 
+ * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
+ * @since 3.0
+ */
+public class RejectAllChanges extends AbstractAcceptRejectAllChanges {
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.handler.AbstractAcceptRejectAllChanges#isCopyDiffCase(org.eclipse.emf.compare.Diff,
+	 *      boolean)
+	 */
+	@Override
+	protected boolean isCopyDiffCase(Diff diff, boolean leftToRight) {
+		if (leftToRight) {
+			return fromSide(DifferenceSource.RIGHT).apply(diff);
+		} else {
+			return fromSide(DifferenceSource.LEFT).apply(diff);
+		}
+	}
+
+}
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/RejectChange.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/RejectChange.java
new file mode 100644
index 0000000..996a129
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/RejectChange.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler;
+
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.fromSide;
+
+import org.eclipse.emf.compare.Diff;
+import org.eclipse.emf.compare.DifferenceSource;
+
+/**
+ * Handler that manages a reject of a difference in case of one side of the comparison is not editable.
+ * 
+ * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
+ * @since 3.0
+ */
+public class RejectChange extends AbstractAcceptRejectChange {
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.handler.AbstractAcceptRejectChange#isCopyDiffCase(org.eclipse.emf.compare.Diff,
+	 *      boolean)
+	 */
+	@Override
+	protected boolean isCopyDiffCase(Diff diff, boolean leftToRight) {
+		if (leftToRight) {
+			return fromSide(DifferenceSource.RIGHT).apply(diff);
+		} else {
+			return fromSide(DifferenceSource.LEFT).apply(diff);
+		}
+	}
+
+}
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/SelectNextDiff.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/SelectNextDiff.java
new file mode 100644
index 0000000..e2e6bb1
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/SelectNextDiff.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler;
+
+import org.eclipse.compare.CompareConfiguration;
+import org.eclipse.compare.CompareEditorInput;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.util.EMFCompareUIHandlerUtil;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * Handler that manages the select next diff button.
+ * 
+ * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
+ */
+public class SelectNextDiff extends AbstractHandler {
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.core.commands.IHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		Object editorInput = HandlerUtil.getVariable(event, ISources.ACTIVE_EDITOR_INPUT_NAME);
+		if (editorInput instanceof CompareEditorInput) {
+			CompareConfiguration configuration = ((CompareEditorInput)editorInput).getCompareConfiguration();
+			// Select next diff
+			EMFCompareUIHandlerUtil.navigate(true, configuration);
+		}
+		return null;
+	}
+
+}
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/SelectPreviousDiff.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/SelectPreviousDiff.java
new file mode 100644
index 0000000..5ecd4e1
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/SelectPreviousDiff.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler;
+
+import org.eclipse.compare.CompareConfiguration;
+import org.eclipse.compare.CompareEditorInput;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.util.EMFCompareUIHandlerUtil;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * Handler that manages the select previous diff button.
+ * 
+ * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
+ */
+public class SelectPreviousDiff extends AbstractHandler {
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.core.commands.IHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+	 */
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		Object editorInput = HandlerUtil.getVariable(event, ISources.ACTIVE_EDITOR_INPUT_NAME);
+		if (editorInput instanceof CompareEditorInput) {
+			CompareConfiguration configuration = ((CompareEditorInput)editorInput).getCompareConfiguration();
+			// Select next diff
+			EMFCompareUIHandlerUtil.navigate(false, configuration);
+		}
+		return null;
+	}
+
+}
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/ModelSaveablePropertyTester.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/propertytester/AcceptRejectChangePropertyTester.java
similarity index 73%
copy from plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/ModelSaveablePropertyTester.java
copy to plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/propertytester/AcceptRejectChangePropertyTester.java
index 3b409db..a79978c 100644
--- a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/ModelSaveablePropertyTester.java
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/propertytester/AcceptRejectChangePropertyTester.java
@@ -8,7 +8,7 @@
  * Contributors:
  *     Obeo - initial API and implementation
  *******************************************************************************/
-package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler;
+package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.propertytester;
 
 import org.eclipse.compare.CompareConfiguration;
 import org.eclipse.compare.CompareEditorInput;
@@ -17,13 +17,14 @@
 import org.eclipse.ui.IEditorPart;
 
 /**
- * A property tester linked with {@link SaveComparisonModel}. It tests the editable property of both model
- * sides.
+ * A property tester linked with
+ * {@link org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.handler.AbstractMergedTo}. It returns
+ * true when only one model side is editable.
  * 
  * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
  * @since 3.0
  */
-public class ModelSaveablePropertyTester extends PropertyTester {
+public class AcceptRejectChangePropertyTester extends PropertyTester {
 
 	/**
 	 * {@inheritDoc}
@@ -36,14 +37,14 @@
 			IEditorInput i = ((IEditorPart)receiver).getEditorInput();
 			if (i instanceof CompareEditorInput) {
 				CompareConfiguration configuration = ((CompareEditorInput)i).getCompareConfiguration();
-				if (!configuration.isLeftEditable() || !configuration.isRightEditable()) {
-					return false;
-				} else if (((CompareEditorInput)i).isDirty()) {
-					return false;
+				if (configuration.isLeftEditable() && !configuration.isRightEditable()) {
+					return true;
+				} else if (!configuration.isLeftEditable() && configuration.isRightEditable()) {
+					return true;
 				}
 			}
 		}
-		return true;
+		return false;
 	}
 
 }
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/ModelSaveablePropertyTester.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/propertytester/DiffSelectedPropertyTester.java
similarity index 61%
copy from plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/ModelSaveablePropertyTester.java
copy to plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/propertytester/DiffSelectedPropertyTester.java
index 3b409db..ebad5be 100644
--- a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/ModelSaveablePropertyTester.java
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/propertytester/DiffSelectedPropertyTester.java
@@ -8,22 +8,27 @@
  * Contributors:
  *     Obeo - initial API and implementation
  *******************************************************************************/
-package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler;
+package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.propertytester;
 
 import org.eclipse.compare.CompareConfiguration;
 import org.eclipse.compare.CompareEditorInput;
 import org.eclipse.core.expressions.PropertyTester;
+import org.eclipse.emf.common.notify.Adapter;
+import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.emf.compare.Diff;
+import org.eclipse.emf.compare.rcp.ui.internal.EMFCompareConstants;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
 import org.eclipse.ui.IEditorInput;
 import org.eclipse.ui.IEditorPart;
 
 /**
- * A property tester linked with {@link SaveComparisonModel}. It tests the editable property of both model
- * sides.
+ * A property tester that checks if a diff is selected in the compare editor.
  * 
  * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
  * @since 3.0
  */
-public class ModelSaveablePropertyTester extends PropertyTester {
+public class DiffSelectedPropertyTester extends PropertyTester {
 
 	/**
 	 * {@inheritDoc}
@@ -36,14 +41,20 @@
 			IEditorInput i = ((IEditorPart)receiver).getEditorInput();
 			if (i instanceof CompareEditorInput) {
 				CompareConfiguration configuration = ((CompareEditorInput)i).getCompareConfiguration();
-				if (!configuration.isLeftEditable() || !configuration.isRightEditable()) {
-					return false;
-				} else if (((CompareEditorInput)i).isDirty()) {
-					return false;
+				ISelection selection = (ISelection)configuration
+						.getProperty(EMFCompareConstants.SMV_SELECTION);
+				if (selection instanceof IStructuredSelection) {
+					Object element = ((IStructuredSelection)selection).getFirstElement();
+					if (element instanceof Adapter) {
+						Notifier diffNode = ((Adapter)element).getTarget();
+						if (diffNode instanceof Diff) {
+							return true;
+						}
+					}
 				}
 			}
 		}
-		return true;
+		return false;
 	}
 
 }
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/ModelSaveablePropertyTester.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/propertytester/LeftToRightSidePropertyTester.java
similarity index 77%
copy from plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/ModelSaveablePropertyTester.java
copy to plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/propertytester/LeftToRightSidePropertyTester.java
index 3b409db..7808605 100644
--- a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/ModelSaveablePropertyTester.java
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/propertytester/LeftToRightSidePropertyTester.java
@@ -8,22 +8,22 @@
  * Contributors:
  *     Obeo - initial API and implementation
  *******************************************************************************/
-package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler;
+package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.propertytester;
 
 import org.eclipse.compare.CompareConfiguration;
 import org.eclipse.compare.CompareEditorInput;
 import org.eclipse.core.expressions.PropertyTester;
+import org.eclipse.emf.compare.rcp.ui.internal.EMFCompareConstants;
 import org.eclipse.ui.IEditorInput;
 import org.eclipse.ui.IEditorPart;
 
 /**
- * A property tester linked with {@link SaveComparisonModel}. It tests the editable property of both model
- * sides.
+ * A property tester that check the way of merge.
  * 
  * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
  * @since 3.0
  */
-public class ModelSaveablePropertyTester extends PropertyTester {
+public class LeftToRightSidePropertyTester extends PropertyTester {
 
 	/**
 	 * {@inheritDoc}
@@ -36,14 +36,13 @@
 			IEditorInput i = ((IEditorPart)receiver).getEditorInput();
 			if (i instanceof CompareEditorInput) {
 				CompareConfiguration configuration = ((CompareEditorInput)i).getCompareConfiguration();
-				if (!configuration.isLeftEditable() || !configuration.isRightEditable()) {
-					return false;
-				} else if (((CompareEditorInput)i).isDirty()) {
-					return false;
+				Boolean leftToRight = (Boolean)configuration.getProperty(EMFCompareConstants.MERGE_WAY);
+				if (leftToRight == null || leftToRight.booleanValue()) {
+					return true;
 				}
 			}
 		}
-		return true;
+		return false;
 	}
 
 }
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/ModelSaveablePropertyTester.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/propertytester/MergedToPropertyTester.java
similarity index 78%
copy from plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/ModelSaveablePropertyTester.java
copy to plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/propertytester/MergedToPropertyTester.java
index 3b409db..75447c3 100644
--- a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/ModelSaveablePropertyTester.java
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/propertytester/MergedToPropertyTester.java
@@ -8,7 +8,7 @@
  * Contributors:
  *     Obeo - initial API and implementation
  *******************************************************************************/
-package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler;
+package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.propertytester;
 
 import org.eclipse.compare.CompareConfiguration;
 import org.eclipse.compare.CompareEditorInput;
@@ -17,13 +17,14 @@
 import org.eclipse.ui.IEditorPart;
 
 /**
- * A property tester linked with {@link SaveComparisonModel}. It tests the editable property of both model
- * sides.
+ * A property tester linked with
+ * {@link org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.handler.AbstractMergedTo}. It returns
+ * true when both model sides are editable.
  * 
  * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
  * @since 3.0
  */
-public class ModelSaveablePropertyTester extends PropertyTester {
+public class MergedToPropertyTester extends PropertyTester {
 
 	/**
 	 * {@inheritDoc}
@@ -36,14 +37,12 @@
 			IEditorInput i = ((IEditorPart)receiver).getEditorInput();
 			if (i instanceof CompareEditorInput) {
 				CompareConfiguration configuration = ((CompareEditorInput)i).getCompareConfiguration();
-				if (!configuration.isLeftEditable() || !configuration.isRightEditable()) {
-					return false;
-				} else if (((CompareEditorInput)i).isDirty()) {
-					return false;
+				if (configuration.isLeftEditable() && configuration.isRightEditable()) {
+					return true;
 				}
 			}
 		}
-		return true;
+		return false;
 	}
 
 }
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/ModelSaveablePropertyTester.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/propertytester/ModelSaveablePropertyTester.java
similarity index 88%
rename from plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/ModelSaveablePropertyTester.java
rename to plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/propertytester/ModelSaveablePropertyTester.java
index 3b409db..ea6890f 100644
--- a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/ModelSaveablePropertyTester.java
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/propertytester/ModelSaveablePropertyTester.java
@@ -8,7 +8,7 @@
  * Contributors:
  *     Obeo - initial API and implementation
  *******************************************************************************/
-package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler;
+package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.propertytester;
 
 import org.eclipse.compare.CompareConfiguration;
 import org.eclipse.compare.CompareEditorInput;
@@ -17,8 +17,9 @@
 import org.eclipse.ui.IEditorPart;
 
 /**
- * A property tester linked with {@link SaveComparisonModel}. It tests the editable property of both model
- * sides.
+ * A property tester linked with
+ * {@link org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.SaveComparisonModel}. It tests
+ * the editable property of both model sides.
  * 
  * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
  * @since 3.0
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/ModelSaveablePropertyTester.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/propertytester/RightToLeftSidePropertyTester.java
similarity index 77%
copy from plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/ModelSaveablePropertyTester.java
copy to plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/propertytester/RightToLeftSidePropertyTester.java
index 3b409db..92310ab 100644
--- a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/ModelSaveablePropertyTester.java
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/propertytester/RightToLeftSidePropertyTester.java
@@ -8,22 +8,22 @@
  * Contributors:
  *     Obeo - initial API and implementation
  *******************************************************************************/
-package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler;
+package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.propertytester;
 
 import org.eclipse.compare.CompareConfiguration;
 import org.eclipse.compare.CompareEditorInput;
 import org.eclipse.core.expressions.PropertyTester;
+import org.eclipse.emf.compare.rcp.ui.internal.EMFCompareConstants;
 import org.eclipse.ui.IEditorInput;
 import org.eclipse.ui.IEditorPart;
 
 /**
- * A property tester linked with {@link SaveComparisonModel}. It tests the editable property of both model
- * sides.
+ * A property tester that check the way of merge.
  * 
  * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
  * @since 3.0
  */
-public class ModelSaveablePropertyTester extends PropertyTester {
+public class RightToLeftSidePropertyTester extends PropertyTester {
 
 	/**
 	 * {@inheritDoc}
@@ -36,14 +36,13 @@
 			IEditorInput i = ((IEditorPart)receiver).getEditorInput();
 			if (i instanceof CompareEditorInput) {
 				CompareConfiguration configuration = ((CompareEditorInput)i).getCompareConfiguration();
-				if (!configuration.isLeftEditable() || !configuration.isRightEditable()) {
-					return false;
-				} else if (((CompareEditorInput)i).isDirty()) {
-					return false;
+				Boolean leftToRight = (Boolean)configuration.getProperty(EMFCompareConstants.MERGE_WAY);
+				if (leftToRight != null && !leftToRight.booleanValue()) {
+					return true;
 				}
 			}
 		}
-		return true;
+		return false;
 	}
 
 }
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/util/EMFCompareUIHandlerUtil.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/util/EMFCompareUIHandlerUtil.java
new file mode 100644
index 0000000..59e1b6b
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/handler/util/EMFCompareUIHandlerUtil.java
@@ -0,0 +1,194 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.handler.util;
+
+import static com.google.common.collect.Iterables.addAll;
+import static com.google.common.collect.Iterables.filter;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.compare.CompareConfiguration;
+import org.eclipse.compare.CompareNavigator;
+import org.eclipse.compare.ICompareNavigator;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.common.notify.Adapter;
+import org.eclipse.emf.compare.Comparison;
+import org.eclipse.emf.compare.Diff;
+import org.eclipse.emf.compare.DifferenceSource;
+import org.eclipse.emf.compare.DifferenceState;
+import org.eclipse.emf.compare.domain.ICompareEditingDomain;
+import org.eclipse.emf.compare.internal.merge.DiffMergeDataAdapter;
+import org.eclipse.emf.compare.internal.merge.IDiffMergeData;
+import org.eclipse.emf.compare.internal.utils.DiffUtil;
+import org.eclipse.emf.compare.rcp.EMFCompareRCPPlugin;
+import org.eclipse.emf.compare.rcp.ui.internal.EMFCompareConstants;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.filters.IDifferenceFilter;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.filters.impl.CascadingDifferencesFilter;
+import org.eclipse.emf.compare.utils.EMFComparePredicates;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+
+/**
+ * Util class that provides utilities methods for RCP UI handlers.
+ * 
+ * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
+ * @since 3.0
+ */
+public final class EMFCompareUIHandlerUtil {
+
+	/**
+	 * Utility classes don't need a default constructor.
+	 */
+	private EMFCompareUIHandlerUtil() {
+		// Hides default constructor.
+	}
+
+	/**
+	 * Checks the state of the cascading differences filter.
+	 * 
+	 * @param configuration
+	 *            the compare configuration object.
+	 * @return true, if the cascading differences filter is active, false otherwise.
+	 */
+	public static boolean isCascadingDifferencesFilterActive(CompareConfiguration configuration) {
+		Object property = configuration.getProperty(EMFCompareConstants.SELECTED_FILTERS);
+		final Collection<IDifferenceFilter> selectedFilters;
+		if (property != null) {
+			selectedFilters = (Collection<IDifferenceFilter>)property;
+			for (IDifferenceFilter iDifferenceFilter : selectedFilters) {
+				if (iDifferenceFilter instanceof CascadingDifferencesFilter) {
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Copy the given diff.
+	 * 
+	 * @param diffToCopy
+	 *            the given diff to copy.
+	 * @param leftToRight
+	 *            the way of merge.
+	 * @param configuration
+	 *            the compare configuration object.
+	 */
+	public static void copyDiff(Diff diffToCopy, boolean leftToRight, CompareConfiguration configuration) {
+		if (diffToCopy != null) {
+			List<Diff> diffsToCopy = new ArrayList<Diff>();
+			diffsToCopy.add(diffToCopy);
+			for (Diff require : DiffUtil.getRequires(diffToCopy, leftToRight, diffToCopy.getSource())) {
+				EMFCompareUIHandlerUtil.setMergeDataForDiff(require, leftToRight, configuration
+						.isLeftEditable(), configuration.isRightEditable());
+			}
+			if (EMFCompareUIHandlerUtil.isCascadingDifferencesFilterActive(configuration)) {
+				addAll(diffsToCopy, org.eclipse.emf.compare.utils.DiffUtil.getSubDiffs(leftToRight).apply(
+						diffToCopy));
+			}
+			for (Diff diff : diffsToCopy) {
+				EMFCompareUIHandlerUtil.setMergeDataForDiff(diff, leftToRight,
+						configuration.isLeftEditable(), configuration.isRightEditable());
+			}
+			ICompareEditingDomain editingDomain = (ICompareEditingDomain)configuration
+					.getProperty(EMFCompareConstants.EDITING_DOMAIN);
+			Command copyCommand = editingDomain.createCopyCommand(diffsToCopy, leftToRight,
+					EMFCompareRCPPlugin.getDefault().getMergerRegistry());
+			editingDomain.getCommandStack().execute(copyCommand);
+		}
+	}
+
+	/**
+	 * Copy all non-conflicting changes.
+	 * 
+	 * @param leftToRight
+	 *            the way of merge.
+	 * @param configuration
+	 *            the compare configuration object.
+	 */
+	public static void copyAllDiffs(final boolean leftToRight, CompareConfiguration configuration) {
+		final List<Diff> differences;
+		Comparison comparison = (Comparison)configuration.getProperty(EMFCompareConstants.COMPARE_RESULT);
+		if (comparison.isThreeWay()) {
+			differences = ImmutableList.copyOf(filter(comparison.getDifferences(), new Predicate<Diff>() {
+				public boolean apply(Diff diff) {
+					final boolean unresolved = diff.getState() == DifferenceState.UNRESOLVED;
+					final boolean nonConflictual = diff.getConflict() == null;
+					final boolean fromLeftToRight = leftToRight && diff.getSource() == DifferenceSource.LEFT;
+					final boolean fromRightToLeft = !leftToRight
+							&& diff.getSource() == DifferenceSource.RIGHT;
+					return unresolved && nonConflictual && (fromLeftToRight || fromRightToLeft);
+				}
+			}));
+		} else {
+			differences = ImmutableList.copyOf(filter(comparison.getDifferences(), EMFComparePredicates
+					.hasState(DifferenceState.UNRESOLVED)));
+		}
+
+		if (differences.size() > 0) {
+			for (Diff diff : differences) {
+				EMFCompareUIHandlerUtil.setMergeDataForDiff(diff, leftToRight,
+						configuration.isLeftEditable(), configuration.isRightEditable());
+			}
+			ICompareEditingDomain editingDomain = (ICompareEditingDomain)configuration
+					.getProperty(EMFCompareConstants.EDITING_DOMAIN);
+			final Command copyCommand = editingDomain.createCopyCommand(differences, leftToRight,
+					EMFCompareRCPPlugin.getDefault().getMergerRegistry());
+
+			editingDomain.getCommandStack().execute(copyCommand);
+		}
+	}
+
+	/**
+	 * Called by the framework to navigate to the next (or previous) difference. This will open the content
+	 * viewer for the next (or previous) diff displayed in the structure viewer.
+	 * 
+	 * @param next
+	 *            <code>true</code> if we are to open the next structure viewer's diff, <code>false</code> if
+	 *            we should go to the previous instead.
+	 * @param configuration
+	 *            the compare configuration object.
+	 */
+	public static void navigate(boolean next, CompareConfiguration configuration) {
+		final ICompareNavigator navigator = configuration.getContainer().getNavigator();
+		if (navigator instanceof CompareNavigator && ((CompareNavigator)navigator).hasChange(next)) {
+			navigator.selectChange(next);
+		}
+	}
+
+	/**
+	 * Set the merge way for the given diff. After a merge, it allows to know the way of the merge.
+	 * 
+	 * @param diff
+	 *            the given diff.
+	 * @param leftToRight
+	 *            the way of the merge.
+	 * @param leftEditable
+	 *            the left side of the difference is editable.
+	 * @param rightEditable
+	 *            the right side of the difference is editable.
+	 */
+	public static void setMergeDataForDiff(Diff diff, boolean leftToRight, boolean leftEditable,
+			boolean rightEditable) {
+		Adapter adapter = EcoreUtil.getExistingAdapter(diff, IDiffMergeData.class);
+		if (adapter != null) {
+			((IDiffMergeData)adapter).setMergedTo(leftToRight);
+			((IDiffMergeData)adapter).setLeftEditable(leftEditable);
+			((IDiffMergeData)adapter).setRightEditable(rightEditable);
+		} else {
+			diff.eAdapters().add(new DiffMergeDataAdapter(leftToRight, leftEditable, rightEditable));
+		}
+	}
+}
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/EMFCompareConstants.java b/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/EMFCompareConstants.java
index aa7c8f9..4d1b073 100644
--- a/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/EMFCompareConstants.java
+++ b/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/EMFCompareConstants.java
@@ -43,6 +43,10 @@
 
 	public static final String SELECTED_GROUP = EMFCompareRCPUIPlugin.PLUGIN_ID + ".SELECTED_GROUP"; //$NON-NLS-1$
 
+	public static final String SMV_SELECTION = EMFCompareRCPUIPlugin.PLUGIN_ID + ".SMV_SELECTION"; //$NON-NLS-1$
+
+	public static final String MERGE_WAY = EMFCompareRCPUIPlugin.PLUGIN_ID + ".MERGE_WAY"; //$NON-NLS-1$
+
 	// ITypedElement#getType()
 
 	public static final String NODE_TYPE__EMF_RESOURCESET = "NODE_TYPE__EMF_RESOURCESET"; //$NON-NLS-1$
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/groups/StructureMergeViewerGrouper.java b/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/groups/StructureMergeViewerGrouper.java
index e2ed6a9..29970df 100644
--- a/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/groups/StructureMergeViewerGrouper.java
+++ b/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/groups/StructureMergeViewerGrouper.java
@@ -91,8 +91,8 @@
 		if (this.provider != provider) {
 			this.provider = provider;
 			filteredGroups = null;
-			eventBus.post(provider);
 			refreshViewers();
+			eventBus.post(provider);
 		}
 	}
 
diff --git a/plugins/org.eclipse.emf.compare/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.compare/META-INF/MANIFEST.MF
index 6f1c8b2..10caf73 100644
--- a/plugins/org.eclipse.emf.compare/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.emf.compare/META-INF/MANIFEST.MF
@@ -13,6 +13,7 @@
  org.eclipse.emf.compare.equi,
  org.eclipse.emf.compare.impl,
  org.eclipse.emf.compare.internal;x-friends:="org.eclipse.emf.compare.logical,org.eclipse.emf.compare.ide",
+ org.eclipse.emf.compare.internal.merge;x-friends:="org.eclipse.emf.compare.rcp.ui,org.eclipse.emf.compare.edit,org.eclipse.emf.compare.ide.ui",
  org.eclipse.emf.compare.internal.postprocessor.factories;x-internal:=true,
  org.eclipse.emf.compare.internal.spec;x-friends:="org.eclipse.emf.compare.tests",
  org.eclipse.emf.compare.internal.utils;
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/merge/DiffMergeDataAdapter.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/merge/DiffMergeDataAdapter.java
new file mode 100644
index 0000000..513e76b
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/merge/DiffMergeDataAdapter.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.internal.merge;
+
+import org.eclipse.emf.common.notify.impl.AdapterImpl;
+
+/**
+ * Adapter that help to know the way of merge and the editable sides of a difference.
+ * 
+ * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
+ * @since 3.0
+ */
+public class DiffMergeDataAdapter extends AdapterImpl implements IDiffMergeData {
+
+	/** The merge way. */
+	boolean leftToRight;
+
+	/** Left side is editable. */
+	boolean leftEditable;
+
+	/** Right side is editable. */
+	boolean rightEditable;
+
+	/**
+	 * Constructor.
+	 * 
+	 * @param leftToRight
+	 *            The merge way.
+	 * @param leftEditable
+	 *            Left side editable.
+	 * @param rightEditable
+	 *            Right side editable.
+	 */
+	public DiffMergeDataAdapter(boolean leftToRight, boolean leftEditable, boolean rightEditable) {
+		this.leftToRight = leftToRight;
+		this.leftEditable = leftEditable;
+		this.rightEditable = rightEditable;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.emf.compare.internal.merge.IDiffMergeData#hasBeenMergedToLeft()
+	 */
+	public boolean hasBeenMergedToLeft() {
+		return !leftToRight;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.emf.compare.internal.merge.IDiffMergeData#hasBeenMergedToRight()
+	 */
+	public boolean hasBeenMergedToRight() {
+		return leftToRight;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.emf.compare.internal.merge.IDiffMergeData#setMergedTo(boolean)
+	 */
+	public void setMergedTo(boolean lToR) {
+		this.leftToRight = lToR;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.emf.compare.internal.merge.IDiffMergeData#isLeftEditable()
+	 */
+	public boolean isLeftEditable() {
+		return leftEditable;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.emf.compare.internal.merge.IDiffMergeData#isRightEditable()
+	 */
+	public boolean isRightEditable() {
+		return rightEditable;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.emf.compare.internal.merge.IDiffMergeData#setLeftEditable(boolean)
+	 */
+	public void setLeftEditable(boolean leftEditable) {
+		this.leftEditable = leftEditable;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.emf.compare.internal.merge.IDiffMergeData#setRightEditable(boolean)
+	 */
+	public void setRightEditable(boolean rightEditable) {
+		this.rightEditable = rightEditable;
+	}
+
+	@Override
+	public boolean isAdapterForType(Object type) {
+		return type == IDiffMergeData.class;
+	}
+
+}
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/merge/IDiffMergeData.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/merge/IDiffMergeData.java
new file mode 100644
index 0000000..7531b54
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/merge/IDiffMergeData.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.internal.merge;
+
+/**
+ * Interface implemented by {@link org.eclipse.emf.compare.internal.merge.DiffMergeDataAdapter}. It helps to
+ * know the way of merge and the editable sides of a difference.
+ * 
+ * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
+ */
+public interface IDiffMergeData {
+
+	/**
+	 * Check if the difference has been merged from right to left.
+	 * 
+	 * @return true if the difference has been merged from right to left, false otherwise.
+	 */
+	boolean hasBeenMergedToLeft();
+
+	/**
+	 * Check if the difference has been merged from left to right.
+	 * 
+	 * @return true if the difference has been merged from left to right, false otherwise.
+	 */
+	boolean hasBeenMergedToRight();
+
+	/**
+	 * Set the way of merge.
+	 * 
+	 * @param leftToRight
+	 *            true if the difference has been merge from left to right, false otehrwise.
+	 */
+	void setMergedTo(boolean leftToRight);
+
+	/**
+	 * Check if the left side of the difference is editable.
+	 * 
+	 * @return true if the left side of the difference is editable, false otherwise.
+	 */
+	boolean isLeftEditable();
+
+	/**
+	 * Check if the right side of the difference is editable.
+	 * 
+	 * @return true if the right side of the difference is editable, false otherwise.
+	 */
+	boolean isRightEditable();
+
+	/**
+	 * Set that the left side of the difference is editable or not.
+	 * 
+	 * @param leftEditable
+	 *            true if the left side of the difference is editable, false otherwise.
+	 */
+	void setLeftEditable(boolean leftEditable);
+
+	/**
+	 * Set that the right side of the difference is editable or not.
+	 * 
+	 * @param rightEditable
+	 *            true if the right side of the difference is editable, false otherwise.
+	 */
+	void setRightEditable(boolean rightEditable);
+
+}
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/utils/DiffUtil.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/utils/DiffUtil.java
index dfa567f..8dedf68 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/utils/DiffUtil.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/utils/DiffUtil.java
@@ -10,6 +10,11 @@
  *******************************************************************************/
 package org.eclipse.emf.compare.internal.utils;
 
+import static com.google.common.base.Predicates.and;
+import static com.google.common.base.Predicates.or;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.fromSide;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.ofKind;
+
 import com.google.common.base.Predicate;
 import com.google.common.collect.HashMultiset;
 import com.google.common.collect.ImmutableList;
@@ -27,6 +32,8 @@
 
 import org.eclipse.emf.compare.AttributeChange;
 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;
@@ -866,6 +873,127 @@
 	}
 
 	/**
+	 * Get the list of all required differences for merge of the given difference (required, required of
+	 * required...).
+	 * 
+	 * @param diff
+	 *            the given difference.
+	 * @param leftToRight
+	 *            the way of merge.
+	 * @param originalDiffSource
+	 *            the source of the given diff.
+	 * @return the list of all required differences.
+	 * @since 3.0
+	 */
+	public static Set<Diff> getRequires(Diff diff, boolean leftToRight, DifferenceSource originalDiffSource) {
+		return getRequires(diff, diff, leftToRight, originalDiffSource, Sets.newHashSet());
+	}
+
+	/**
+	 * Get the list of all required differences for merge of the given original difference (required, required
+	 * of required...).
+	 * 
+	 * @param currentDiff
+	 *            the current difference being processed.
+	 * @param originalDiff
+	 *            the original given difference.
+	 * @param leftToRight
+	 *            the way of merge.
+	 * @param originalDiffSource
+	 *            the source of the given diff.
+	 * @param processedDiffs
+	 *            the list of already processed diffs.
+	 * @return the list of all required differences.
+	 * @since 3.0
+	 */
+	private static Set<Diff> getRequires(Diff currentDiff, Diff originalDiff, boolean leftToRight,
+			DifferenceSource originalDiffSource, Set<Object> processedDiffs) {
+		Set<Diff> requires = Sets.newHashSet();
+		final List<Diff> diffRequires;
+		if (leftToRight) {
+			if (DifferenceSource.LEFT == originalDiffSource) {
+				diffRequires = currentDiff.getRequires();
+			} else if (DifferenceSource.RIGHT == originalDiffSource) {
+				diffRequires = currentDiff.getRequiredBy();
+			} else {
+				diffRequires = Collections.emptyList();
+			}
+		} else {
+			if (DifferenceSource.RIGHT == originalDiffSource) {
+				diffRequires = currentDiff.getRequires();
+			} else if (DifferenceSource.LEFT == originalDiffSource) {
+				diffRequires = currentDiff.getRequiredBy();
+			} else {
+				diffRequires = Collections.emptyList();
+			}
+		}
+		diffRequires.addAll(currentDiff.getRefinedBy());
+		for (Diff require : diffRequires) {
+			if (!originalDiff.equals(require) && !processedDiffs.contains(require)) {
+				processedDiffs.add(require);
+				requires.add(require);
+				requires.addAll(getRequires(require, originalDiff, leftToRight, originalDiffSource,
+						processedDiffs));
+			}
+		}
+		return requires;
+	}
+
+	/**
+	 * Get the list of unmergeable differences after the merge of the given difference.
+	 * 
+	 * @param diff
+	 *            the given difference.
+	 * @param leftToRight
+	 *            the way of merge.
+	 * @return the list of unmergeable differences.
+	 * @since 3.0
+	 */
+	public static Set<Diff> getUnmergeables(Diff diff, boolean leftToRight) {
+		Set<Diff> unmergeables = Sets.newHashSet();
+		Conflict conflict = diff.getConflict();
+		if (conflict != null && conflict.getKind() == ConflictKind.REAL) {
+			for (Diff diffConflict : conflict.getDifferences()) {
+				if (leftToRight
+						&& and(fromSide(DifferenceSource.LEFT),
+								or(ofKind(DifferenceKind.ADD), ofKind(DifferenceKind.CHANGE))).apply(diff)) {
+					if (and(fromSide(DifferenceSource.RIGHT),
+							or(ofKind(DifferenceKind.DELETE), ofKind(DifferenceKind.CHANGE))).apply(
+							diffConflict)) {
+						unmergeables.add(diffConflict);
+					}
+				} else if (leftToRight
+						&& and(fromSide(DifferenceSource.LEFT),
+								or(ofKind(DifferenceKind.DELETE), ofKind(DifferenceKind.CHANGE))).apply(diff)) {
+					if (and(fromSide(DifferenceSource.RIGHT),
+							or(ofKind(DifferenceKind.ADD), ofKind(DifferenceKind.CHANGE)))
+							.apply(diffConflict)) {
+						unmergeables.add(diffConflict);
+					}
+				} else if (!leftToRight
+						&& and(fromSide(DifferenceSource.RIGHT),
+								or(ofKind(DifferenceKind.DELETE), ofKind(DifferenceKind.CHANGE))).apply(diff)) {
+					if (and(fromSide(DifferenceSource.LEFT),
+							or(ofKind(DifferenceKind.ADD), ofKind(DifferenceKind.CHANGE)))
+							.apply(diffConflict)) {
+						unmergeables.add(diffConflict);
+					}
+				} else if (!leftToRight
+						&& and(fromSide(DifferenceSource.RIGHT),
+								or(ofKind(DifferenceKind.ADD), ofKind(DifferenceKind.CHANGE))).apply(diff)) {
+					if (and(fromSide(DifferenceSource.LEFT),
+							or(ofKind(DifferenceKind.DELETE), ofKind(DifferenceKind.CHANGE))).apply(
+							diffConflict)) {
+						unmergeables.add(diffConflict);
+					}
+				}
+
+			}
+		}
+		return unmergeables;
+	}
+
+	/**
 	 * Retrieves the "source" list of the given {@code diff}. This will be different according to the kind of
 	 * change and the direction of the merging.
 	 * 
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/merge/AbstractMerger.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/merge/AbstractMerger.java
index 8d85231..93460f7 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/merge/AbstractMerger.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/merge/AbstractMerger.java
@@ -1,190 +1,190 @@
-/*******************************************************************************

- * Copyright (c) 2012, 2013 Obeo.

- * All rights reserved. This program and the accompanying materials

- * are made available under the terms of the Eclipse Public License v1.0

- * which accompanies this distribution, and is available at

- * http://www.eclipse.org/legal/epl-v10.html

- * 

- * Contributors:

- *     Obeo - initial API and implementation

- *******************************************************************************/

-package org.eclipse.emf.compare.merge;

-

-import java.util.List;

-

-import org.eclipse.emf.common.util.Monitor;

-import org.eclipse.emf.compare.Diff;

-import org.eclipse.emf.compare.utils.EMFCompareCopier;

-import org.eclipse.emf.ecore.EObject;

-import org.eclipse.emf.ecore.util.EcoreUtil;

-import org.eclipse.emf.ecore.util.InternalEList;

-

-/**

- * Abstract implementation of an {@link IMerger}. This can be used as a base implementation to avoid

- * re-implementing the whole contract.

- * 

- * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>

- * @since 3.0

- */

-public abstract class AbstractMerger implements IMerger {

-	/** Ranking of this merger. */

-	private int ranking;

-

-	/** Registry from which this merger has been created.. */

-	private Registry registry;

-

-	/**

-	 * {@inheritDoc}

-	 * 

-	 * @see org.eclipse.emf.compare.merge.IMerger#getRanking()

-	 */

-	public int getRanking() {

-		return ranking;

-	}

-

-	/**

-	 * {@inheritDoc}

-	 * 

-	 * @see org.eclipse.emf.compare.merge.IMerger#setRanking(int)

-	 */

-	public void setRanking(int r) {

-		ranking = r;

-	}

-

-	/**

-	 * {@inheritDoc}

-	 * 

-	 * @see org.eclipse.emf.compare.merge.IMerger#getRegistry()

-	 */

-	public Registry getRegistry() {

-		return registry;

-	}

-

-	/**

-	 * {@inheritDoc}

-	 * 

-	 * @see org.eclipse.emf.compare.merge.IMerger#setRegistry(org.eclipse.emf.compare.merge.IMerger.Registry)

-	 */

-	public void setRegistry(Registry registry) {

-		if (this.registry != null && registry != null) {

-			throw new IllegalStateException("The registry has to be set only once."); //$NON-NLS-1$

-		}

-		this.registry = registry;

-	}

-

-	/**

-	 * This will merge all {@link Diff#getRequiredBy() differences that require} {@code diff} in the given

-	 * direction.

-	 * 

-	 * @param diff

-	 *            We need to merge all differences that require this one (see {@link Diff#getRequiredBy()}.

-	 * @param rightToLeft

-	 *            If {@code true}, {@link #copyRightToLeft(Diff, Monitor) apply} all differences that require

-	 *            {@code diff}. Otherwise, {@link #copyLeftToRight(Diff, Monitor) revert} them.

-	 * @param monitor

-	 *            The monitor we should use to report progress.

-	 */

-	protected void mergeRequiredBy(Diff diff, boolean rightToLeft, Monitor monitor) {

-		// TODO log back to the user what we will merge along?

-		for (Diff dependency : diff.getRequiredBy()) {

-			// TODO: what to do when state = Discarded but is required?

-			mergeDiff(dependency, rightToLeft, monitor);

-		}

-	}

-

-	/**

-	 * This will merge all {@link Diff#getRequires() differences required by} {@code diff} in the given

-	 * direction.

-	 * 

-	 * @param diff

-	 *            The difference which requirements we need to merge.

-	 * @param rightToLeft

-	 *            If {@code true}, {@link #copyRightToLeft(Diff, Monitor) apply} all required differences.

-	 *            Otherwise, {@link #copyLeftToRight(Diff, Monitor) revert} them.

-	 * @param monitor

-	 *            The monitor we should use to report progress.

-	 */

-	protected void mergeRequires(Diff diff, boolean rightToLeft, Monitor monitor) {

-		// TODO log back to the user what we will merge along?

-		for (Diff dependency : diff.getRequires()) {

-			// TODO: what to do when state = Discarded but is required?

-			mergeDiff(dependency, rightToLeft, monitor);

-		}

-	}

-

-	/**

-	 * This can be used by mergers to merge another (required, equivalent...) difference using the right

-	 * merger for that diff.

-	 * 

-	 * @param diff

-	 *            The diff we need to merge.

-	 * @param rightToLeft

-	 *            Direction of that merge.

-	 * @param monitor

-	 *            The monitor we should use to report progress.

-	 */

-	protected void mergeDiff(Diff diff, boolean rightToLeft, Monitor monitor) {

-		if (rightToLeft) {

-			final IMerger delegate = getRegistry().getHighestRankingMerger(diff);

-			delegate.copyRightToLeft(diff, monitor);

-		} else {

-			final IMerger delegate = getRegistry().getHighestRankingMerger(diff);

-			delegate.copyLeftToRight(diff, monitor);

-		}

-	}

-

-	/**

-	 * This will create a copy of the given EObject that can be used as the target of an addition (or the

-	 * reverting of a deletion).

-	 * <p>

-	 * The target will be self-contained and will have no reference towards any other EObject set (neither

-	 * containment nor "classic" references). All of its attributes' values will match the given

-	 * {@code referenceObject}'s.

-	 * </p>

-	 * 

-	 * @param referenceObject

-	 *            The EObject for which we'll create a copy.

-	 * @return A self-contained copy of {@code referenceObject}.

-	 * @see EMFCompareCopier#copy(EObject)

-	 */

-	protected EObject createCopy(EObject referenceObject) {

-		/*

-		 * We can't simply use EcoreUtil.copy. References will have their own diffs and will thus be merged

-		 * later on.

-		 */

-		final EcoreUtil.Copier copier = new EMFCompareCopier();

-		return copier.copy(referenceObject);

-	}

-

-	/**

-	 * Adds the given {@code value} into the given {@code list} at the given {@code index}. An {@code index}

-	 * under than zero or above the list's size will mean that the value should be appended at the end of the

-	 * list.

-	 * 

-	 * @param list

-	 *            The list into which {@code value} should be added.

-	 * @param value

-	 *            The value we need to add to {@code list}.

-	 * @param <E>

-	 *            Type of objects contained in the list.

-	 * @param insertionIndex

-	 *            The index at which {@code value} should be inserted into {@code list}. {@code -1} if it

-	 *            should be appended at the end of the list.

-	 */

-	@SuppressWarnings("unchecked")

-	protected <E> void addAt(List<E> list, E value, int insertionIndex) {

-		if (list instanceof InternalEList<?>) {

-			if (insertionIndex < 0 || insertionIndex > list.size()) {

-				((InternalEList<Object>)list).addUnique(value);

-			} else {

-				((InternalEList<Object>)list).addUnique(insertionIndex, value);

-			}

-		} else {

-			if (insertionIndex < 0 || insertionIndex > list.size()) {

-				list.add(value);

-			} else {

-				list.add(insertionIndex, value);

-			}

-		}

-	}

-}

+/*******************************************************************************
+ * Copyright (c) 2012, 2013 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.merge;
+
+import java.util.List;
+
+import org.eclipse.emf.common.util.Monitor;
+import org.eclipse.emf.compare.Diff;
+import org.eclipse.emf.compare.utils.EMFCompareCopier;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.emf.ecore.util.InternalEList;
+
+/**
+ * Abstract implementation of an {@link IMerger}. This can be used as a base implementation to avoid
+ * re-implementing the whole contract.
+ * 
+ * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
+ * @since 3.0
+ */
+public abstract class AbstractMerger implements IMerger {
+	/** Ranking of this merger. */
+	private int ranking;
+
+	/** Registry from which this merger has been created.. */
+	private Registry registry;
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.emf.compare.merge.IMerger#getRanking()
+	 */
+	public int getRanking() {
+		return ranking;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.emf.compare.merge.IMerger#setRanking(int)
+	 */
+	public void setRanking(int r) {
+		ranking = r;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.emf.compare.merge.IMerger#getRegistry()
+	 */
+	public Registry getRegistry() {
+		return registry;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.emf.compare.merge.IMerger#setRegistry(org.eclipse.emf.compare.merge.IMerger.Registry)
+	 */
+	public void setRegistry(Registry registry) {
+		if (this.registry != null && registry != null) {
+			throw new IllegalStateException("The registry has to be set only once."); //$NON-NLS-1$
+		}
+		this.registry = registry;
+	}
+
+	/**
+	 * This will merge all {@link Diff#getRequiredBy() differences that require} {@code diff} in the given
+	 * direction.
+	 * 
+	 * @param diff
+	 *            We need to merge all differences that require this one (see {@link Diff#getRequiredBy()}.
+	 * @param rightToLeft
+	 *            If {@code true}, {@link #copyRightToLeft(Diff, Monitor) apply} all differences that require
+	 *            {@code diff}. Otherwise, {@link #copyLeftToRight(Diff, Monitor) revert} them.
+	 * @param monitor
+	 *            The monitor we should use to report progress.
+	 */
+	protected void mergeRequiredBy(Diff diff, boolean rightToLeft, Monitor monitor) {
+		// TODO log back to the user what we will merge along?
+		for (Diff dependency : diff.getRequiredBy()) {
+			// TODO: what to do when state = Discarded but is required?
+			mergeDiff(dependency, rightToLeft, monitor);
+		}
+	}
+
+	/**
+	 * This will merge all {@link Diff#getRequires() differences required by} {@code diff} in the given
+	 * direction.
+	 * 
+	 * @param diff
+	 *            The difference which requirements we need to merge.
+	 * @param rightToLeft
+	 *            If {@code true}, {@link #copyRightToLeft(Diff, Monitor) apply} all required differences.
+	 *            Otherwise, {@link #copyLeftToRight(Diff, Monitor) revert} them.
+	 * @param monitor
+	 *            The monitor we should use to report progress.
+	 */
+	protected void mergeRequires(Diff diff, boolean rightToLeft, Monitor monitor) {
+		// TODO log back to the user what we will merge along?
+		for (Diff dependency : diff.getRequires()) {
+			// TODO: what to do when state = Discarded but is required?
+			mergeDiff(dependency, rightToLeft, monitor);
+		}
+	}
+
+	/**
+	 * This can be used by mergers to merge another (required, equivalent...) difference using the right
+	 * merger for that diff.
+	 * 
+	 * @param diff
+	 *            The diff we need to merge.
+	 * @param rightToLeft
+	 *            Direction of that merge.
+	 * @param monitor
+	 *            The monitor we should use to report progress.
+	 */
+	protected void mergeDiff(Diff diff, boolean rightToLeft, Monitor monitor) {
+		if (rightToLeft) {
+			final IMerger delegate = getRegistry().getHighestRankingMerger(diff);
+			delegate.copyRightToLeft(diff, monitor);
+		} else {
+			final IMerger delegate = getRegistry().getHighestRankingMerger(diff);
+			delegate.copyLeftToRight(diff, monitor);
+		}
+	}
+
+	/**
+	 * This will create a copy of the given EObject that can be used as the target of an addition (or the
+	 * reverting of a deletion).
+	 * <p>
+	 * The target will be self-contained and will have no reference towards any other EObject set (neither
+	 * containment nor "classic" references). All of its attributes' values will match the given
+	 * {@code referenceObject}'s.
+	 * </p>
+	 * 
+	 * @param referenceObject
+	 *            The EObject for which we'll create a copy.
+	 * @return A self-contained copy of {@code referenceObject}.
+	 * @see EMFCompareCopier#copy(EObject)
+	 */
+	protected EObject createCopy(EObject referenceObject) {
+		/*
+		 * We can't simply use EcoreUtil.copy. References will have their own diffs and will thus be merged
+		 * later on.
+		 */
+		final EcoreUtil.Copier copier = new EMFCompareCopier();
+		return copier.copy(referenceObject);
+	}
+
+	/**
+	 * Adds the given {@code value} into the given {@code list} at the given {@code index}. An {@code index}
+	 * under than zero or above the list's size will mean that the value should be appended at the end of the
+	 * list.
+	 * 
+	 * @param list
+	 *            The list into which {@code value} should be added.
+	 * @param value
+	 *            The value we need to add to {@code list}.
+	 * @param <E>
+	 *            Type of objects contained in the list.
+	 * @param insertionIndex
+	 *            The index at which {@code value} should be inserted into {@code list}. {@code -1} if it
+	 *            should be appended at the end of the list.
+	 */
+	@SuppressWarnings("unchecked")
+	protected <E> void addAt(List<E> list, E value, int insertionIndex) {
+		if (list instanceof InternalEList<?>) {
+			if (insertionIndex < 0 || insertionIndex > list.size()) {
+				((InternalEList<Object>)list).addUnique(value);
+			} else {
+				((InternalEList<Object>)list).addUnique(insertionIndex, value);
+			}
+		} else {
+			if (insertionIndex < 0 || insertionIndex > list.size()) {
+				list.add(value);
+			} else {
+				list.add(insertionIndex, value);
+			}
+		}
+	}
+}
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/merge/ReferenceChangeMerger.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/merge/ReferenceChangeMerger.java
index f77eef0..ce9d162 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/merge/ReferenceChangeMerger.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/merge/ReferenceChangeMerger.java
@@ -1,753 +1,753 @@
-/*******************************************************************************

- * Copyright (c) 2012, 2013 Obeo.

- * All rights reserved. This program and the accompanying materials

- * are made available under the terms of the Eclipse Public License v1.0

- * which accompanies this distribution, and is available at

- * http://www.eclipse.org/legal/epl-v10.html

- * 

- * Contributors:

- *     Obeo - initial API and implementation

- *******************************************************************************/

-package org.eclipse.emf.compare.merge;

-

-import static org.eclipse.emf.compare.utils.ReferenceUtil.safeEIsSet;

-

-import com.google.common.base.Predicates;

-import com.google.common.collect.Iterables;

-

-import java.util.Iterator;

-import java.util.List;

-

-import org.eclipse.emf.common.util.EList;

-import org.eclipse.emf.common.util.Monitor;

-import org.eclipse.emf.compare.Comparison;

-import org.eclipse.emf.compare.Diff;

-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.internal.utils.DiffUtil;

-import org.eclipse.emf.compare.utils.IEqualityHelper;

-import org.eclipse.emf.ecore.EObject;

-import org.eclipse.emf.ecore.EReference;

-import org.eclipse.emf.ecore.resource.Resource;

-import org.eclipse.emf.ecore.util.EcoreUtil;

-import org.eclipse.emf.ecore.xmi.XMIResource;

-

-/**

- * This specific implementation of {@link AbstractMerger} will be used to merge reference changes.

- * 

- * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>

- */

-public class ReferenceChangeMerger extends AbstractMerger {

-	/**

-	 * {@inheritDoc}

-	 * 

-	 * @see org.eclipse.emf.compare.merge.IMerger#isMergerFor(org.eclipse.emf.compare.Diff)

-	 */

-	public boolean isMergerFor(Diff target) {

-		return target instanceof ReferenceChange;

-	}

-

-	/**

-	 * {@inheritDoc}

-	 * 

-	 * @see org.eclipse.emf.compare.merge.IMerger#copyLeftToRight(org.eclipse.emf.compare.Diff,

-	 *      org.eclipse.emf.common.util.Monitor)

-	 */

-	public void copyLeftToRight(Diff target, Monitor monitor) {

-		// Don't merge an already merged (or discarded) diff

-		if (target.getState() != DifferenceState.UNRESOLVED) {

-			return;

-		}

-		final ReferenceChange diff = (ReferenceChange)target;

-

-		// Change the diff's state before we actually merge it : this allows us to avoid requirement cycles.

-		diff.setState(DifferenceState.MERGED);

-

-		if (diff.getSource() == DifferenceSource.LEFT) {

-			// merge all "requires" diffs

-			mergeRequires(diff, false, monitor);

-			handleImplies(diff, false, monitor);

-		} else {

-			// merge all "required by" diffs

-			mergeRequiredBy(diff, false, monitor);

-			handleImpliedBy(diff, false, monitor);

-		}

-

-		boolean hasToBeMerged = true;

-		if (diff.getEquivalence() != null) {

-			hasToBeMerged = handleEquivalences(diff, false, monitor);

-		}

-

-		if (hasToBeMerged) {

-			if (diff.getSource() == DifferenceSource.LEFT) {

-				accept(diff, false);

-			} else {

-				reject(diff, false);

-			}

-		}

-	}

-

-	/**

-	 * {@inheritDoc}

-	 * 

-	 * @see org.eclipse.emf.compare.merge.IMerger#copyRightToLeft(org.eclipse.emf.compare.Diff,

-	 *      org.eclipse.emf.common.util.Monitor)

-	 */

-	public void copyRightToLeft(Diff target, Monitor monitor) {

-		// Don't merge an already merged (or discarded) diff

-		if (target.getState() != DifferenceState.UNRESOLVED) {

-			return;

-		}

-		final ReferenceChange diff = (ReferenceChange)target;

-

-		// Change the diff's state before we actually merge it : this allows us to avoid requirement cycles.

-		diff.setState(DifferenceState.MERGED);

-

-		if (diff.getSource() == DifferenceSource.LEFT) {

-			// merge all "required by" diffs

-			mergeRequiredBy(diff, true, monitor);

-			handleImpliedBy(diff, true, monitor);

-		} else {

-			// merge all "requires" diffs

-			mergeRequires(diff, true, monitor);

-			handleImplies(diff, true, monitor);

-		}

-

-		boolean hasToBeMerged = true;

-		if (diff.getEquivalence() != null) {

-			hasToBeMerged = handleEquivalences(diff, true, monitor);

-		}

-

-		if (hasToBeMerged) {

-			if (diff.getSource() == DifferenceSource.LEFT) {

-				reject(diff, true);

-			} else {

-				accept(diff, true);

-			}

-		}

-	}

-

-	/**

-	 * Merge the given difference rejecting it.

-	 * 

-	 * @param diff

-	 *            The difference to merge.

-	 * @param rightToLeft

-	 *            The direction of the merge.

-	 */

-	private void reject(final ReferenceChange diff, boolean rightToLeft) {

-		DifferenceSource source = diff.getSource();

-		switch (diff.getKind()) {

-			case ADD:

-				// We have a ADD on left, thus nothing in right. We need to revert the addition

-				removeFromTarget(diff, rightToLeft);

-				break;

-			case DELETE:

-				// DELETE in the left, thus an element in right. We need to re-create that element

-				addInTarget(diff, rightToLeft);

-				break;

-			case MOVE:

-				moveElement(diff, rightToLeft);

-				break;

-			case CHANGE:

-				EObject container = null;

-				if (source == DifferenceSource.LEFT) {

-					container = diff.getMatch().getLeft();

-

-				} else {

-					container = diff.getMatch().getRight();

-				}

-				// Is it an unset?

-				if (container != null) {

-					final EObject leftValue = (EObject)container.eGet(diff.getReference(), false);

-					if (leftValue == null) {

-						// Value has been unset in the right, and we are merging towards right.

-						// We need to re-add this element

-						addInTarget(diff, rightToLeft);

-					} else {

-						// We'll actually need to "reset" this reference to its original value

-						resetInTarget(diff, rightToLeft);

-					}

-				} else {

-					// we have no left, and the source is on the left. Can only be an unset

-					addInTarget(diff, rightToLeft);

-				}

-				break;

-			default:

-				break;

-		}

-	}

-

-	/**

-	 * Merge the given difference accepting it.

-	 * 

-	 * @param diff

-	 *            The difference to merge.

-	 * @param rightToLeft

-	 *            The direction of the merge.

-	 */

-	private void accept(final ReferenceChange diff, boolean rightToLeft) {

-		DifferenceSource source = diff.getSource();

-		switch (diff.getKind()) {

-			case ADD:

-				// Create the same element in right

-				addInTarget(diff, rightToLeft);

-				break;

-			case DELETE:

-				// Delete that same element from right

-				removeFromTarget(diff, rightToLeft);

-				break;

-			case MOVE:

-				moveElement(diff, rightToLeft);

-				break;

-			case CHANGE:

-				EObject container = null;

-				if (source == DifferenceSource.LEFT) {

-					container = diff.getMatch().getLeft();

-				} else {

-					container = diff.getMatch().getRight();

-				}

-				// Is it an unset?

-				if (container != null) {

-					final EObject leftValue = (EObject)container.eGet(diff.getReference(), false);

-					if (leftValue == null) {

-						removeFromTarget(diff, rightToLeft);

-					} else {

-						addInTarget(diff, rightToLeft);

-					}

-				} else {

-					// we have no left, and the source is on the left. Can only be an unset

-					removeFromTarget(diff, rightToLeft);

-				}

-				break;

-			default:

-				break;

-		}

-	}

-

-	/**

-	 * Mark as MERGED all the implied differences recursively from the given one.

-	 * 

-	 * @param diff

-	 *            The difference from which the implications have to be marked.

-	 * @param rightToLeft

-	 *            The direction of the merge.

-	 * @param monitor

-	 *            Monitor.

-	 */

-	private void handleImplies(Diff diff, boolean rightToLeft, Monitor monitor) {

-		for (Diff implied : diff.getImplies()) {

-			implied.setState(DifferenceState.MERGED);

-			handleImplies(implied, rightToLeft, monitor);

-		}

-	}

-

-	/**

-	 * Mark as MERGED all the implying differences recursively from the given one.

-	 * 

-	 * @param diff

-	 *            The difference from which the implications have to be marked.

-	 * @param rightToLeft

-	 *            The direction of the merge.

-	 * @param monitor

-	 *            Monitor.

-	 */

-	private void handleImpliedBy(Diff diff, boolean rightToLeft, Monitor monitor) {

-		for (Diff impliedBy : diff.getImpliedBy()) {

-			impliedBy.setState(DifferenceState.MERGED);

-			handleImpliedBy(impliedBy, rightToLeft, monitor);

-		}

-	}

-

-	/**

-	 * This will be called when trying to copy a "MOVE" diff.

-	 * 

-	 * @param diff

-	 *            The diff we are currently merging.

-	 * @param rightToLeft

-	 *            Whether we should move the value in the left or right side.

-	 */

-	protected void moveElement(ReferenceChange diff, boolean rightToLeft) {

-		final Comparison comparison = diff.getMatch().getComparison();

-		final Match valueMatch = comparison.getMatch(diff.getValue());

-		final EReference reference = diff.getReference();

-

-		final EObject expectedContainer;

-		if (reference.isContainment()) {

-			/*

-			 * We cannot "trust" the holding match (getMatch) in this case. However, "valueMatch" cannot be

-			 * null : we cannot have detected a move if the moved element is not matched on both sides. Use

-			 * that information to retrieve the proper "target" container.

-			 */

-			final Match targetContainerMatch;

-			// If it exists, use the source side's container as reference

-			if (rightToLeft && valueMatch.getRight() != null) {

-				targetContainerMatch = comparison.getMatch(valueMatch.getRight().eContainer());

-			} else if (!rightToLeft && valueMatch.getLeft() != null) {

-				targetContainerMatch = comparison.getMatch(valueMatch.getLeft().eContainer());

-			} else {

-				// Otherwise, the value we're moving on one side has been removed from its source side.

-				targetContainerMatch = comparison.getMatch(valueMatch.getOrigin().eContainer());

-			}

-			if (rightToLeft) {

-				expectedContainer = targetContainerMatch.getLeft();

-			} else {

-				expectedContainer = targetContainerMatch.getRight();

-			}

-		} else if (rightToLeft) {

-			expectedContainer = diff.getMatch().getLeft();

-		} else {

-			expectedContainer = diff.getMatch().getRight();

-		}

-		if (expectedContainer == null) {

-			// FIXME throw exception? log? re-try to merge our requirements?

-			// one of the "required" diffs should have created our container.

-			return;

-		}

-

-		final EObject expectedValue;

-		if (valueMatch == null) {

-			// The value being moved is out of the scope

-			/*

-			 * Note : there should not be a way to end up with a "move" for an out of scope value : a move can

-			 * only be detected if the object is matched on both sides, otherwise all we can see is "add" and

-			 * "delete"... Is this "fallback" code even reachable? If so, how?

-			 */

-			// We need to look it up

-			if (reference.isMany()) {

-				@SuppressWarnings("unchecked")

-				final List<EObject> targetList = (List<EObject>)expectedContainer.eGet(reference);

-				expectedValue = findMatchIn(comparison, targetList, diff.getValue());

-			} else {

-				expectedValue = (EObject)expectedContainer.eGet(reference);

-			}

-		} else {

-			if (rightToLeft) {

-				expectedValue = valueMatch.getLeft();

-			} else {

-				expectedValue = valueMatch.getRight();

-			}

-		}

-		// We now know the target container, target reference and target value.

-		doMove(diff, comparison, expectedContainer, expectedValue, rightToLeft);

-	}

-

-	/**

-	 * This will do the actual work of moving the element into its reference. All sanity checks were made in

-	 * {@link #moveElement(boolean)} and no more verification will be made here.

-	 * 

-	 * @param diff

-	 *            The diff we are currently merging.

-	 * @param comparison

-	 *            Comparison holding this Diff.

-	 * @param expectedContainer

-	 *            The container in which we are reorganizing a reference.

-	 * @param expectedValue

-	 *            The value that is to be moved within its reference.

-	 * @param rightToLeft

-	 *            Whether we should move the value in the left or right side.

-	 */

-	@SuppressWarnings("unchecked")

-	protected void doMove(ReferenceChange diff, Comparison comparison, EObject expectedContainer,

-			EObject expectedValue, boolean rightToLeft) {

-		final EReference reference = diff.getReference();

-		if (reference.isMany()) {

-			// Element to move cannot be part of the LCS... or there would not be a MOVE diff

-			int insertionIndex = findInsertionIndex(comparison, diff, rightToLeft);

-

-			/*

-			 * However, it could still have been located "before" its new index, in which case we need to take

-			 * it into account.

-			 */

-			final List<EObject> targetList = (List<EObject>)expectedContainer.eGet(reference);

-			final int currentIndex = targetList.indexOf(expectedValue);

-			if (insertionIndex > currentIndex && currentIndex >= 0) {

-				insertionIndex--;

-			}

-

-			if (currentIndex == -1) {

-				// happens for container changes for example.

-				if (!reference.isContainment()) {

-					targetList.remove(expectedValue);

-				}

-				if (insertionIndex < 0 && insertionIndex > targetList.size()) {

-					targetList.add(expectedValue);

-				} else {

-					targetList.add(insertionIndex, expectedValue);

-				}

-			} else if (targetList instanceof EList<?>) {

-				if (insertionIndex < 0 && insertionIndex > targetList.size()) {

-					((EList<EObject>)targetList).move(targetList.size() - 1, expectedValue);

-				} else {

-					((EList<EObject>)targetList).move(insertionIndex, expectedValue);

-				}

-			} else {

-				targetList.remove(expectedValue);

-				if (insertionIndex < 0 && insertionIndex > targetList.size()) {

-					targetList.add(expectedValue);

-				} else {

-					targetList.add(insertionIndex, expectedValue);

-				}

-			}

-		} else {

-			expectedContainer.eSet(reference, expectedValue);

-		}

-	}

-

-	/**

-	 * This will be called when we need to create an element in the target side.

-	 * <p>

-	 * All necessary sanity checks have been made to ensure that the current operation is one that should

-	 * create an object in its side or add an objet to a reference. In other words, either :

-	 * <ul>

-	 * <li>We are copying from right to left and

-	 * <ul>

-	 * <li>we are copying an addition to the right side (we need to create the same object in the left), or</li>

-	 * <li>we are copying a deletion from the left side (we need to revert the deletion).</li>

-	 * </ul>

-	 * </li>

-	 * <li>We are copying from left to right and

-	 * <ul>

-	 * <li>we are copying a deletion from the right side (we need to revert the deletion), or</li>

-	 * <li>we are copying an addition to the left side (we need to create the same object in the right).</li>

-	 * </ul>

-	 * </li>

-	 * </ul>

-	 * </p>

-	 * 

-	 * @param diff

-	 *            The diff we are currently merging.

-	 * @param rightToLeft

-	 *            Tells us whether we are to add an object on the left or right side.

-	 */

-	@SuppressWarnings("unchecked")

-	protected void addInTarget(ReferenceChange diff, boolean rightToLeft) {

-		final Match match = diff.getMatch();

-		final EObject expectedContainer;

-		if (rightToLeft) {

-			expectedContainer = match.getLeft();

-		} else {

-			expectedContainer = match.getRight();

-		}

-

-		if (expectedContainer == null) {

-			// FIXME throw exception? log? re-try to merge our requirements?

-			// one of the "required" diffs should have created our container.

-			return;

-		}

-

-		final Comparison comparison = match.getComparison();

-		final EReference reference = diff.getReference();

-		final EObject expectedValue;

-		final Match valueMatch = comparison.getMatch(diff.getValue());

-		if (valueMatch == null) {

-			// This is an out of scope value.

-			if (diff.getValue().eIsProxy()) {

-				// Copy the proxy

-				expectedValue = EcoreUtil.copy(diff.getValue());

-			} else {

-				// Use the same value.

-				expectedValue = diff.getValue();

-			}

-		} else if (rightToLeft) {

-			if (reference.isContainment()) {

-				expectedValue = createCopy(diff.getValue());

-				valueMatch.setLeft(expectedValue);

-			} else {

-				expectedValue = valueMatch.getLeft();

-			}

-		} else {

-			if (reference.isContainment()) {

-				expectedValue = createCopy(diff.getValue());

-				valueMatch.setRight(expectedValue);

-			} else {

-				expectedValue = valueMatch.getRight();

-			}

-		}

-

-		// We have the container, reference and value. We need to know the insertion index.

-		if (reference.isMany()) {

-			final int insertionIndex = findInsertionIndex(comparison, diff, rightToLeft);

-

-			final List<EObject> targetList = (List<EObject>)expectedContainer.eGet(reference);

-			addAt(targetList, expectedValue, insertionIndex);

-		} else {

-			expectedContainer.eSet(reference, expectedValue);

-		}

-

-		if (reference.isContainment()) {

-			// Copy XMI ID when applicable.

-			final Resource initialResource = diff.getValue().eResource();

-			final Resource targetResource = expectedValue.eResource();

-			if (initialResource instanceof XMIResource && targetResource instanceof XMIResource) {

-				((XMIResource)targetResource).setID(expectedValue, ((XMIResource)initialResource).getID(diff

-						.getValue()));

-			}

-		}

-	}

-

-	/**

-	 * This will be called when we need to remove an element from the target side.

-	 * <p>

-	 * All necessary sanity checks have been made to ensure that the current operation is one that should

-	 * delete an object. In other words, we are :

-	 * <ul>

-	 * <li>Copying from right to left and either

-	 * <ul>

-	 * <li>we are copying a deletion from the right side (we need to remove the same object in the left) or,</li>

-	 * <li>we are copying an addition to the left side (we need to revert the addition).</li>

-	 * </ul>

-	 * </li>

-	 * <li>Copying from left to right and either

-	 * <ul>

-	 * <li>we are copying an addition to the right side (we need to revert the addition), or.</li>

-	 * <li>we are copying a deletion from the left side (we need to remove the same object in the right).</li>

-	 * </ul>

-	 * </li>

-	 * </ul>

-	 * </p>

-	 * 

-	 * @param diff

-	 *            The diff we are currently merging.

-	 * @param rightToLeft

-	 *            Tells us whether we are to add an object on the left or right side.

-	 */

-	@SuppressWarnings("unchecked")

-	protected void removeFromTarget(ReferenceChange diff, boolean rightToLeft) {

-		final Match match = diff.getMatch();

-		final EReference reference = diff.getReference();

-		final EObject currentContainer;

-		if (rightToLeft) {

-			currentContainer = match.getLeft();

-		} else {

-			currentContainer = match.getRight();

-		}

-		final Comparison comparison = match.getComparison();

-		final Match valueMatch = comparison.getMatch(diff.getValue());

-

-		if (currentContainer == null) {

-			// FIXME throw exception? log? re-try to merge our requirements?

-			// one of the "required" diffs should have created our container.

-			return;

-		}

-

-		final EObject expectedValue;

-		if (valueMatch == null) {

-			// value is out of the scope... we need to look it up

-			if (reference.isMany()) {

-				final List<EObject> targetList = (List<EObject>)currentContainer.eGet(reference);

-				expectedValue = findMatchIn(comparison, targetList, diff.getValue());

-			} else {

-				// the value will not be needed anyway

-				expectedValue = null;

-			}

-		} else if (rightToLeft) {

-			expectedValue = valueMatch.getLeft();

-		} else {

-			expectedValue = valueMatch.getRight();

-		}

-

-		// We have the container, reference and value to remove. Expected value can be null when the

-		// deletion was made on both side (i.e. a pseudo delete)

-		if (reference.isContainment() && expectedValue != null) {

-			EcoreUtil.remove(expectedValue);

-			if (rightToLeft && valueMatch != null) {

-				valueMatch.setLeft(null);

-			} else if (valueMatch != null) {

-				valueMatch.setRight(null);

-			}

-			// TODO remove dangling? remove empty Match?

-		} else if (reference.isMany()) {

-			/*

-			 * TODO if the same value appears twice, should we try and find the one that has actually been

-			 * deleted? Can it happen? For now, remove the first occurence we find.

-			 */

-			final List<EObject> targetList = (List<EObject>)currentContainer.eGet(reference);

-			targetList.remove(expectedValue);

-		} else {

-			currentContainer.eUnset(reference);

-		}

-	}

-

-	/**

-	 * This will be called by the merge operations in order to reset a reference to its original value, be

-	 * that the left or right side.

-	 * <p>

-	 * Should never be called on multi-valued references.

-	 * </p>

-	 * 

-	 * @param diff

-	 *            The diff we are currently merging.

-	 * @param rightToLeft

-	 *            Tells us the direction of this merge operation.

-	 */

-	protected void resetInTarget(ReferenceChange diff, boolean rightToLeft) {

-		final Match match = diff.getMatch();

-		final EReference reference = diff.getReference();

-		final EObject targetContainer;

-		if (rightToLeft) {

-			targetContainer = match.getLeft();

-		} else {

-			targetContainer = match.getRight();

-		}

-

-		final EObject originContainer;

-		if (match.getComparison().isThreeWay()) {

-			originContainer = match.getOrigin();

-		} else if (rightToLeft) {

-			originContainer = match.getRight();

-		} else {

-			originContainer = match.getLeft();

-		}

-

-		if (originContainer == null || !safeEIsSet(targetContainer, reference)

-				|| !safeEIsSet(originContainer, reference)) {

-			targetContainer.eUnset(reference);

-		} else {

-			final EObject originalValue = (EObject)originContainer.eGet(reference);

-			final Match valueMatch = match.getComparison().getMatch(originalValue);

-			final EObject expectedValue;

-			if (valueMatch == null) {

-				// Value is out of the scope, use it as-is

-				expectedValue = originalValue;

-			} else if (rightToLeft) {

-				expectedValue = valueMatch.getLeft();

-			} else {

-				expectedValue = valueMatch.getRight();

-			}

-			targetContainer.eSet(reference, expectedValue);

-		}

-	}

-

-	/**

-	 * Handles the equivalences of this difference.

-	 * <p>

-	 * Note that in certain cases, we'll merge our opposite instead of merging this diff. Specifically, we'll

-	 * do that for one-to-many eOpposites : we'll merge the 'many' side instead of the 'unique' one. This

-	 * allows us not to worry about the order of the references on that 'many' side.

-	 * </p>

-	 * <p>

-	 * This is called before the merge of <code>this</code>. In short, if this returns <code>false</code>, we

-	 * won't carry on merging <code>this</code> after returning.

-	 * </p>

-	 * 

-	 * @param diff

-	 *            The diff we are currently merging.

-	 * @param rightToLeft

-	 *            Direction of the merge.

-	 * @param monitor

-	 *            The monitor to use in order to report progress information.

-	 * @return <code>true</code> if the current difference should still be merged after handling its

-	 *         equivalences, <code>false</code> if it should be considered "already merged".

-	 */

-	protected boolean handleEquivalences(ReferenceChange diff, boolean rightToLeft, Monitor monitor) {

-		final EReference reference = diff.getReference();

-		boolean continueMerge = true;

-		for (Diff equivalent : diff.getEquivalence().getDifferences()) {

-			// For 1..*, merge diff on many-valued to preserve ordering

-			if (equivalent instanceof ReferenceChange

-					&& reference.getEOpposite() == ((ReferenceChange)equivalent).getReference()

-					&& equivalent.getState() == DifferenceState.UNRESOLVED) {

-				// This equivalence is on our eOpposite. Should we merge it instead of 'this'?

-				final boolean mergeEquivalence = !reference.isMany()

-						&& ((ReferenceChange)equivalent).getReference().isMany();

-				if (mergeEquivalence) {

-					mergeDiff(equivalent, rightToLeft, monitor);

-					continueMerge = false;

-				}

-			}

-

-			/*

-			 * If one of the equivalent differences is implied or implying (depending on the merge direction)

-			 * a merged diff, then we have a dependency loop : the "current" difference has already been

-			 * merged because of this implication. This will allow us to break out of that loop.

-			 */

-			if (rightToLeft) {

-				if (diff.getSource() == DifferenceSource.LEFT) {

-					continueMerge = continueMerge

-							&& !containsAny(diff.getRequiredBy(), equivalent.getImplies());

-				} else {

-					continueMerge = continueMerge

-							&& !containsAny(diff.getRequires(), equivalent.getImpliedBy());

-				}

-			} else {

-				if (diff.getSource() == DifferenceSource.LEFT) {

-					continueMerge = continueMerge

-							&& !containsAny(diff.getRequires(), equivalent.getImpliedBy());

-				} else {

-					continueMerge = continueMerge

-							&& !containsAny(diff.getRequiredBy(), equivalent.getImplies());

-				}

-			}

-

-			equivalent.setState(DifferenceState.MERGED);

-		}

-		return continueMerge;

-	}

-

-	/**

-	 * Utility method to check that the first sequence contains one of the elements of the second sequence at

-	 * least.

-	 * 

-	 * @param sequence1

-	 *            The first sequence.

-	 * @param sequence2

-	 *            The second sequence.

-	 * @return True if the given first sequence contains one of the elements of the second sequence at least.

-	 *         false otherwise.

-	 */

-	private boolean containsAny(List<? extends EObject> sequence1, List<? extends EObject> sequence2) {

-		return Iterables.any(sequence2, Predicates.in(sequence1));

-	}

-

-	/**

-	 * Seeks a match of the given {@code element} in the given list, using the equality helper to find it.

-	 * This is only used when moving or deleting proxies for now.

-	 * 

-	 * @param comparison

-	 *            The comparison which Diff we are currently merging.

-	 * @param list

-	 *            The list from which we seek a value.

-	 * @param element

-	 *            The value for which we need a match in {@code list}.

-	 * @return The match of {@code element} in {@code list}, {@code null} if none.

-	 */

-	protected EObject findMatchIn(Comparison comparison, List<EObject> list, EObject element) {

-		final IEqualityHelper helper = comparison.getEqualityHelper();

-		final Iterator<EObject> it = list.iterator();

-		while (it.hasNext()) {

-			final EObject next = it.next();

-			if (helper.matchingValues(next, element)) {

-				return next;

-			}

-		}

-		return null;

-	}

-

-	/**

-	 * This will be used by the distinct merge actions in order to find the index at which a value should be

-	 * inserted in its target list. See {@link DiffUtil#findInsertionIndex(Comparison, Diff, boolean)} for

-	 * more on this.

-	 * <p>

-	 * Sub-classes can override this if the insertion order is irrelevant. A return value of {@code -1} will

-	 * be considered as "no index" and the value will be inserted at the end of its target list.

-	 * </p>

-	 * 

-	 * @param comparison

-	 *            This will be used in order to retrieve the Match for EObjects when comparing them.

-	 * @param diff

-	 *            The diff which merging will trigger the need for an insertion index in its target list.

-	 * @param rightToLeft

-	 *            {@code true} if the merging will be done into the left list, so that we should consider the

-	 *            right model as the source and the left as the target.

-	 * @return The index at which this {@code diff}'s value should be inserted into the 'target' list, as

-	 *         inferred from {@code rightToLeft}. {@code -1} if the value should be inserted at the end of its

-	 *         target list.

-	 * @see DiffUtil#findInsertionIndex(Comparison, Diff, boolean)

-	 */

-	protected int findInsertionIndex(Comparison comparison, Diff diff, boolean rightToLeft) {

-		return DiffUtil.findInsertionIndex(comparison, diff, rightToLeft);

-	}

-}

+/*******************************************************************************
+ * Copyright (c) 2012, 2013 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.merge;
+
+import static org.eclipse.emf.compare.utils.ReferenceUtil.safeEIsSet;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.common.util.Monitor;
+import org.eclipse.emf.compare.Comparison;
+import org.eclipse.emf.compare.Diff;
+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.internal.utils.DiffUtil;
+import org.eclipse.emf.compare.utils.IEqualityHelper;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.emf.ecore.xmi.XMIResource;
+
+/**
+ * This specific implementation of {@link AbstractMerger} will be used to merge reference changes.
+ * 
+ * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
+ */
+public class ReferenceChangeMerger extends AbstractMerger {
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.emf.compare.merge.IMerger#isMergerFor(org.eclipse.emf.compare.Diff)
+	 */
+	public boolean isMergerFor(Diff target) {
+		return target instanceof ReferenceChange;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.emf.compare.merge.IMerger#copyLeftToRight(org.eclipse.emf.compare.Diff,
+	 *      org.eclipse.emf.common.util.Monitor)
+	 */
+	public void copyLeftToRight(Diff target, Monitor monitor) {
+		// Don't merge an already merged (or discarded) diff
+		if (target.getState() != DifferenceState.UNRESOLVED) {
+			return;
+		}
+		final ReferenceChange diff = (ReferenceChange)target;
+
+		// Change the diff's state before we actually merge it : this allows us to avoid requirement cycles.
+		diff.setState(DifferenceState.MERGED);
+
+		if (diff.getSource() == DifferenceSource.LEFT) {
+			// merge all "requires" diffs
+			mergeRequires(diff, false, monitor);
+			handleImplies(diff, false, monitor);
+		} else {
+			// merge all "required by" diffs
+			mergeRequiredBy(diff, false, monitor);
+			handleImpliedBy(diff, false, monitor);
+		}
+
+		boolean hasToBeMerged = true;
+		if (diff.getEquivalence() != null) {
+			hasToBeMerged = handleEquivalences(diff, false, monitor);
+		}
+
+		if (hasToBeMerged) {
+			if (diff.getSource() == DifferenceSource.LEFT) {
+				accept(diff, false);
+			} else {
+				reject(diff, false);
+			}
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.emf.compare.merge.IMerger#copyRightToLeft(org.eclipse.emf.compare.Diff,
+	 *      org.eclipse.emf.common.util.Monitor)
+	 */
+	public void copyRightToLeft(Diff target, Monitor monitor) {
+		// Don't merge an already merged (or discarded) diff
+		if (target.getState() != DifferenceState.UNRESOLVED) {
+			return;
+		}
+		final ReferenceChange diff = (ReferenceChange)target;
+
+		// Change the diff's state before we actually merge it : this allows us to avoid requirement cycles.
+		diff.setState(DifferenceState.MERGED);
+
+		if (diff.getSource() == DifferenceSource.LEFT) {
+			// merge all "required by" diffs
+			mergeRequiredBy(diff, true, monitor);
+			handleImpliedBy(diff, true, monitor);
+		} else {
+			// merge all "requires" diffs
+			mergeRequires(diff, true, monitor);
+			handleImplies(diff, true, monitor);
+		}
+
+		boolean hasToBeMerged = true;
+		if (diff.getEquivalence() != null) {
+			hasToBeMerged = handleEquivalences(diff, true, monitor);
+		}
+
+		if (hasToBeMerged) {
+			if (diff.getSource() == DifferenceSource.LEFT) {
+				reject(diff, true);
+			} else {
+				accept(diff, true);
+			}
+		}
+	}
+
+	/**
+	 * Merge the given difference rejecting it.
+	 * 
+	 * @param diff
+	 *            The difference to merge.
+	 * @param rightToLeft
+	 *            The direction of the merge.
+	 */
+	private void reject(final ReferenceChange diff, boolean rightToLeft) {
+		DifferenceSource source = diff.getSource();
+		switch (diff.getKind()) {
+			case ADD:
+				// We have a ADD on left, thus nothing in right. We need to revert the addition
+				removeFromTarget(diff, rightToLeft);
+				break;
+			case DELETE:
+				// DELETE in the left, thus an element in right. We need to re-create that element
+				addInTarget(diff, rightToLeft);
+				break;
+			case MOVE:
+				moveElement(diff, rightToLeft);
+				break;
+			case CHANGE:
+				EObject container = null;
+				if (source == DifferenceSource.LEFT) {
+					container = diff.getMatch().getLeft();
+
+				} else {
+					container = diff.getMatch().getRight();
+				}
+				// Is it an unset?
+				if (container != null) {
+					final EObject leftValue = (EObject)container.eGet(diff.getReference(), false);
+					if (leftValue == null) {
+						// Value has been unset in the right, and we are merging towards right.
+						// We need to re-add this element
+						addInTarget(diff, rightToLeft);
+					} else {
+						// We'll actually need to "reset" this reference to its original value
+						resetInTarget(diff, rightToLeft);
+					}
+				} else {
+					// we have no left, and the source is on the left. Can only be an unset
+					addInTarget(diff, rightToLeft);
+				}
+				break;
+			default:
+				break;
+		}
+	}
+
+	/**
+	 * Merge the given difference accepting it.
+	 * 
+	 * @param diff
+	 *            The difference to merge.
+	 * @param rightToLeft
+	 *            The direction of the merge.
+	 */
+	private void accept(final ReferenceChange diff, boolean rightToLeft) {
+		DifferenceSource source = diff.getSource();
+		switch (diff.getKind()) {
+			case ADD:
+				// Create the same element in right
+				addInTarget(diff, rightToLeft);
+				break;
+			case DELETE:
+				// Delete that same element from right
+				removeFromTarget(diff, rightToLeft);
+				break;
+			case MOVE:
+				moveElement(diff, rightToLeft);
+				break;
+			case CHANGE:
+				EObject container = null;
+				if (source == DifferenceSource.LEFT) {
+					container = diff.getMatch().getLeft();
+				} else {
+					container = diff.getMatch().getRight();
+				}
+				// Is it an unset?
+				if (container != null) {
+					final EObject leftValue = (EObject)container.eGet(diff.getReference(), false);
+					if (leftValue == null) {
+						removeFromTarget(diff, rightToLeft);
+					} else {
+						addInTarget(diff, rightToLeft);
+					}
+				} else {
+					// we have no left, and the source is on the left. Can only be an unset
+					removeFromTarget(diff, rightToLeft);
+				}
+				break;
+			default:
+				break;
+		}
+	}
+
+	/**
+	 * Mark as MERGED all the implied differences recursively from the given one.
+	 * 
+	 * @param diff
+	 *            The difference from which the implications have to be marked.
+	 * @param rightToLeft
+	 *            The direction of the merge.
+	 * @param monitor
+	 *            Monitor.
+	 */
+	private void handleImplies(Diff diff, boolean rightToLeft, Monitor monitor) {
+		for (Diff implied : diff.getImplies()) {
+			implied.setState(DifferenceState.MERGED);
+			handleImplies(implied, rightToLeft, monitor);
+		}
+	}
+
+	/**
+	 * Mark as MERGED all the implying differences recursively from the given one.
+	 * 
+	 * @param diff
+	 *            The difference from which the implications have to be marked.
+	 * @param rightToLeft
+	 *            The direction of the merge.
+	 * @param monitor
+	 *            Monitor.
+	 */
+	private void handleImpliedBy(Diff diff, boolean rightToLeft, Monitor monitor) {
+		for (Diff impliedBy : diff.getImpliedBy()) {
+			impliedBy.setState(DifferenceState.MERGED);
+			handleImpliedBy(impliedBy, rightToLeft, monitor);
+		}
+	}
+
+	/**
+	 * This will be called when trying to copy a "MOVE" diff.
+	 * 
+	 * @param diff
+	 *            The diff we are currently merging.
+	 * @param rightToLeft
+	 *            Whether we should move the value in the left or right side.
+	 */
+	protected void moveElement(ReferenceChange diff, boolean rightToLeft) {
+		final Comparison comparison = diff.getMatch().getComparison();
+		final Match valueMatch = comparison.getMatch(diff.getValue());
+		final EReference reference = diff.getReference();
+
+		final EObject expectedContainer;
+		if (reference.isContainment()) {
+			/*
+			 * We cannot "trust" the holding match (getMatch) in this case. However, "valueMatch" cannot be
+			 * null : we cannot have detected a move if the moved element is not matched on both sides. Use
+			 * that information to retrieve the proper "target" container.
+			 */
+			final Match targetContainerMatch;
+			// If it exists, use the source side's container as reference
+			if (rightToLeft && valueMatch.getRight() != null) {
+				targetContainerMatch = comparison.getMatch(valueMatch.getRight().eContainer());
+			} else if (!rightToLeft && valueMatch.getLeft() != null) {
+				targetContainerMatch = comparison.getMatch(valueMatch.getLeft().eContainer());
+			} else {
+				// Otherwise, the value we're moving on one side has been removed from its source side.
+				targetContainerMatch = comparison.getMatch(valueMatch.getOrigin().eContainer());
+			}
+			if (rightToLeft) {
+				expectedContainer = targetContainerMatch.getLeft();
+			} else {
+				expectedContainer = targetContainerMatch.getRight();
+			}
+		} else if (rightToLeft) {
+			expectedContainer = diff.getMatch().getLeft();
+		} else {
+			expectedContainer = diff.getMatch().getRight();
+		}
+		if (expectedContainer == null) {
+			// FIXME throw exception? log? re-try to merge our requirements?
+			// one of the "required" diffs should have created our container.
+			return;
+		}
+
+		final EObject expectedValue;
+		if (valueMatch == null) {
+			// The value being moved is out of the scope
+			/*
+			 * Note : there should not be a way to end up with a "move" for an out of scope value : a move can
+			 * only be detected if the object is matched on both sides, otherwise all we can see is "add" and
+			 * "delete"... Is this "fallback" code even reachable? If so, how?
+			 */
+			// We need to look it up
+			if (reference.isMany()) {
+				@SuppressWarnings("unchecked")
+				final List<EObject> targetList = (List<EObject>)expectedContainer.eGet(reference);
+				expectedValue = findMatchIn(comparison, targetList, diff.getValue());
+			} else {
+				expectedValue = (EObject)expectedContainer.eGet(reference);
+			}
+		} else {
+			if (rightToLeft) {
+				expectedValue = valueMatch.getLeft();
+			} else {
+				expectedValue = valueMatch.getRight();
+			}
+		}
+		// We now know the target container, target reference and target value.
+		doMove(diff, comparison, expectedContainer, expectedValue, rightToLeft);
+	}
+
+	/**
+	 * This will do the actual work of moving the element into its reference. All sanity checks were made in
+	 * {@link #moveElement(boolean)} and no more verification will be made here.
+	 * 
+	 * @param diff
+	 *            The diff we are currently merging.
+	 * @param comparison
+	 *            Comparison holding this Diff.
+	 * @param expectedContainer
+	 *            The container in which we are reorganizing a reference.
+	 * @param expectedValue
+	 *            The value that is to be moved within its reference.
+	 * @param rightToLeft
+	 *            Whether we should move the value in the left or right side.
+	 */
+	@SuppressWarnings("unchecked")
+	protected void doMove(ReferenceChange diff, Comparison comparison, EObject expectedContainer,
+			EObject expectedValue, boolean rightToLeft) {
+		final EReference reference = diff.getReference();
+		if (reference.isMany()) {
+			// Element to move cannot be part of the LCS... or there would not be a MOVE diff
+			int insertionIndex = findInsertionIndex(comparison, diff, rightToLeft);
+
+			/*
+			 * However, it could still have been located "before" its new index, in which case we need to take
+			 * it into account.
+			 */
+			final List<EObject> targetList = (List<EObject>)expectedContainer.eGet(reference);
+			final int currentIndex = targetList.indexOf(expectedValue);
+			if (insertionIndex > currentIndex && currentIndex >= 0) {
+				insertionIndex--;
+			}
+
+			if (currentIndex == -1) {
+				// happens for container changes for example.
+				if (!reference.isContainment()) {
+					targetList.remove(expectedValue);
+				}
+				if (insertionIndex < 0 && insertionIndex > targetList.size()) {
+					targetList.add(expectedValue);
+				} else {
+					targetList.add(insertionIndex, expectedValue);
+				}
+			} else if (targetList instanceof EList<?>) {
+				if (insertionIndex < 0 && insertionIndex > targetList.size()) {
+					((EList<EObject>)targetList).move(targetList.size() - 1, expectedValue);
+				} else {
+					((EList<EObject>)targetList).move(insertionIndex, expectedValue);
+				}
+			} else {
+				targetList.remove(expectedValue);
+				if (insertionIndex < 0 && insertionIndex > targetList.size()) {
+					targetList.add(expectedValue);
+				} else {
+					targetList.add(insertionIndex, expectedValue);
+				}
+			}
+		} else {
+			expectedContainer.eSet(reference, expectedValue);
+		}
+	}
+
+	/**
+	 * This will be called when we need to create an element in the target side.
+	 * <p>
+	 * All necessary sanity checks have been made to ensure that the current operation is one that should
+	 * create an object in its side or add an objet to a reference. In other words, either :
+	 * <ul>
+	 * <li>We are copying from right to left and
+	 * <ul>
+	 * <li>we are copying an addition to the right side (we need to create the same object in the left), or</li>
+	 * <li>we are copying a deletion from the left side (we need to revert the deletion).</li>
+	 * </ul>
+	 * </li>
+	 * <li>We are copying from left to right and
+	 * <ul>
+	 * <li>we are copying a deletion from the right side (we need to revert the deletion), or</li>
+	 * <li>we are copying an addition to the left side (we need to create the same object in the right).</li>
+	 * </ul>
+	 * </li>
+	 * </ul>
+	 * </p>
+	 * 
+	 * @param diff
+	 *            The diff we are currently merging.
+	 * @param rightToLeft
+	 *            Tells us whether we are to add an object on the left or right side.
+	 */
+	@SuppressWarnings("unchecked")
+	protected void addInTarget(ReferenceChange diff, boolean rightToLeft) {
+		final Match match = diff.getMatch();
+		final EObject expectedContainer;
+		if (rightToLeft) {
+			expectedContainer = match.getLeft();
+		} else {
+			expectedContainer = match.getRight();
+		}
+
+		if (expectedContainer == null) {
+			// FIXME throw exception? log? re-try to merge our requirements?
+			// one of the "required" diffs should have created our container.
+			return;
+		}
+
+		final Comparison comparison = match.getComparison();
+		final EReference reference = diff.getReference();
+		final EObject expectedValue;
+		final Match valueMatch = comparison.getMatch(diff.getValue());
+		if (valueMatch == null) {
+			// This is an out of scope value.
+			if (diff.getValue().eIsProxy()) {
+				// Copy the proxy
+				expectedValue = EcoreUtil.copy(diff.getValue());
+			} else {
+				// Use the same value.
+				expectedValue = diff.getValue();
+			}
+		} else if (rightToLeft) {
+			if (reference.isContainment()) {
+				expectedValue = createCopy(diff.getValue());
+				valueMatch.setLeft(expectedValue);
+			} else {
+				expectedValue = valueMatch.getLeft();
+			}
+		} else {
+			if (reference.isContainment()) {
+				expectedValue = createCopy(diff.getValue());
+				valueMatch.setRight(expectedValue);
+			} else {
+				expectedValue = valueMatch.getRight();
+			}
+		}
+
+		// We have the container, reference and value. We need to know the insertion index.
+		if (reference.isMany()) {
+			final int insertionIndex = findInsertionIndex(comparison, diff, rightToLeft);
+
+			final List<EObject> targetList = (List<EObject>)expectedContainer.eGet(reference);
+			addAt(targetList, expectedValue, insertionIndex);
+		} else {
+			expectedContainer.eSet(reference, expectedValue);
+		}
+
+		if (reference.isContainment()) {
+			// Copy XMI ID when applicable.
+			final Resource initialResource = diff.getValue().eResource();
+			final Resource targetResource = expectedValue.eResource();
+			if (initialResource instanceof XMIResource && targetResource instanceof XMIResource) {
+				((XMIResource)targetResource).setID(expectedValue, ((XMIResource)initialResource).getID(diff
+						.getValue()));
+			}
+		}
+	}
+
+	/**
+	 * This will be called when we need to remove an element from the target side.
+	 * <p>
+	 * All necessary sanity checks have been made to ensure that the current operation is one that should
+	 * delete an object. In other words, we are :
+	 * <ul>
+	 * <li>Copying from right to left and either
+	 * <ul>
+	 * <li>we are copying a deletion from the right side (we need to remove the same object in the left) or,</li>
+	 * <li>we are copying an addition to the left side (we need to revert the addition).</li>
+	 * </ul>
+	 * </li>
+	 * <li>Copying from left to right and either
+	 * <ul>
+	 * <li>we are copying an addition to the right side (we need to revert the addition), or.</li>
+	 * <li>we are copying a deletion from the left side (we need to remove the same object in the right).</li>
+	 * </ul>
+	 * </li>
+	 * </ul>
+	 * </p>
+	 * 
+	 * @param diff
+	 *            The diff we are currently merging.
+	 * @param rightToLeft
+	 *            Tells us whether we are to add an object on the left or right side.
+	 */
+	@SuppressWarnings("unchecked")
+	protected void removeFromTarget(ReferenceChange diff, boolean rightToLeft) {
+		final Match match = diff.getMatch();
+		final EReference reference = diff.getReference();
+		final EObject currentContainer;
+		if (rightToLeft) {
+			currentContainer = match.getLeft();
+		} else {
+			currentContainer = match.getRight();
+		}
+		final Comparison comparison = match.getComparison();
+		final Match valueMatch = comparison.getMatch(diff.getValue());
+
+		if (currentContainer == null) {
+			// FIXME throw exception? log? re-try to merge our requirements?
+			// one of the "required" diffs should have created our container.
+			return;
+		}
+
+		final EObject expectedValue;
+		if (valueMatch == null) {
+			// value is out of the scope... we need to look it up
+			if (reference.isMany()) {
+				final List<EObject> targetList = (List<EObject>)currentContainer.eGet(reference);
+				expectedValue = findMatchIn(comparison, targetList, diff.getValue());
+			} else {
+				// the value will not be needed anyway
+				expectedValue = null;
+			}
+		} else if (rightToLeft) {
+			expectedValue = valueMatch.getLeft();
+		} else {
+			expectedValue = valueMatch.getRight();
+		}
+
+		// We have the container, reference and value to remove. Expected value can be null when the
+		// deletion was made on both side (i.e. a pseudo delete)
+		if (reference.isContainment() && expectedValue != null) {
+			EcoreUtil.remove(expectedValue);
+			if (rightToLeft && valueMatch != null) {
+				valueMatch.setLeft(null);
+			} else if (valueMatch != null) {
+				valueMatch.setRight(null);
+			}
+			// TODO remove dangling? remove empty Match?
+		} else if (reference.isMany()) {
+			/*
+			 * TODO if the same value appears twice, should we try and find the one that has actually been
+			 * deleted? Can it happen? For now, remove the first occurence we find.
+			 */
+			final List<EObject> targetList = (List<EObject>)currentContainer.eGet(reference);
+			targetList.remove(expectedValue);
+		} else {
+			currentContainer.eUnset(reference);
+		}
+	}
+
+	/**
+	 * This will be called by the merge operations in order to reset a reference to its original value, be
+	 * that the left or right side.
+	 * <p>
+	 * Should never be called on multi-valued references.
+	 * </p>
+	 * 
+	 * @param diff
+	 *            The diff we are currently merging.
+	 * @param rightToLeft
+	 *            Tells us the direction of this merge operation.
+	 */
+	protected void resetInTarget(ReferenceChange diff, boolean rightToLeft) {
+		final Match match = diff.getMatch();
+		final EReference reference = diff.getReference();
+		final EObject targetContainer;
+		if (rightToLeft) {
+			targetContainer = match.getLeft();
+		} else {
+			targetContainer = match.getRight();
+		}
+
+		final EObject originContainer;
+		if (match.getComparison().isThreeWay()) {
+			originContainer = match.getOrigin();
+		} else if (rightToLeft) {
+			originContainer = match.getRight();
+		} else {
+			originContainer = match.getLeft();
+		}
+
+		if (originContainer == null || !safeEIsSet(targetContainer, reference)
+				|| !safeEIsSet(originContainer, reference)) {
+			targetContainer.eUnset(reference);
+		} else {
+			final EObject originalValue = (EObject)originContainer.eGet(reference);
+			final Match valueMatch = match.getComparison().getMatch(originalValue);
+			final EObject expectedValue;
+			if (valueMatch == null) {
+				// Value is out of the scope, use it as-is
+				expectedValue = originalValue;
+			} else if (rightToLeft) {
+				expectedValue = valueMatch.getLeft();
+			} else {
+				expectedValue = valueMatch.getRight();
+			}
+			targetContainer.eSet(reference, expectedValue);
+		}
+	}
+
+	/**
+	 * Handles the equivalences of this difference.
+	 * <p>
+	 * Note that in certain cases, we'll merge our opposite instead of merging this diff. Specifically, we'll
+	 * do that for one-to-many eOpposites : we'll merge the 'many' side instead of the 'unique' one. This
+	 * allows us not to worry about the order of the references on that 'many' side.
+	 * </p>
+	 * <p>
+	 * This is called before the merge of <code>this</code>. In short, if this returns <code>false</code>, we
+	 * won't carry on merging <code>this</code> after returning.
+	 * </p>
+	 * 
+	 * @param diff
+	 *            The diff we are currently merging.
+	 * @param rightToLeft
+	 *            Direction of the merge.
+	 * @param monitor
+	 *            The monitor to use in order to report progress information.
+	 * @return <code>true</code> if the current difference should still be merged after handling its
+	 *         equivalences, <code>false</code> if it should be considered "already merged".
+	 */
+	protected boolean handleEquivalences(ReferenceChange diff, boolean rightToLeft, Monitor monitor) {
+		final EReference reference = diff.getReference();
+		boolean continueMerge = true;
+		for (Diff equivalent : diff.getEquivalence().getDifferences()) {
+			// For 1..*, merge diff on many-valued to preserve ordering
+			if (equivalent instanceof ReferenceChange
+					&& reference.getEOpposite() == ((ReferenceChange)equivalent).getReference()
+					&& equivalent.getState() == DifferenceState.UNRESOLVED) {
+				// This equivalence is on our eOpposite. Should we merge it instead of 'this'?
+				final boolean mergeEquivalence = !reference.isMany()
+						&& ((ReferenceChange)equivalent).getReference().isMany();
+				if (mergeEquivalence) {
+					mergeDiff(equivalent, rightToLeft, monitor);
+					continueMerge = false;
+				}
+			}
+
+			/*
+			 * If one of the equivalent differences is implied or implying (depending on the merge direction)
+			 * a merged diff, then we have a dependency loop : the "current" difference has already been
+			 * merged because of this implication. This will allow us to break out of that loop.
+			 */
+			if (rightToLeft) {
+				if (diff.getSource() == DifferenceSource.LEFT) {
+					continueMerge = continueMerge
+							&& !containsAny(diff.getRequiredBy(), equivalent.getImplies());
+				} else {
+					continueMerge = continueMerge
+							&& !containsAny(diff.getRequires(), equivalent.getImpliedBy());
+				}
+			} else {
+				if (diff.getSource() == DifferenceSource.LEFT) {
+					continueMerge = continueMerge
+							&& !containsAny(diff.getRequires(), equivalent.getImpliedBy());
+				} else {
+					continueMerge = continueMerge
+							&& !containsAny(diff.getRequiredBy(), equivalent.getImplies());
+				}
+			}
+
+			equivalent.setState(DifferenceState.MERGED);
+		}
+		return continueMerge;
+	}
+
+	/**
+	 * Utility method to check that the first sequence contains one of the elements of the second sequence at
+	 * least.
+	 * 
+	 * @param sequence1
+	 *            The first sequence.
+	 * @param sequence2
+	 *            The second sequence.
+	 * @return True if the given first sequence contains one of the elements of the second sequence at least.
+	 *         false otherwise.
+	 */
+	private boolean containsAny(List<? extends EObject> sequence1, List<? extends EObject> sequence2) {
+		return Iterables.any(sequence2, Predicates.in(sequence1));
+	}
+
+	/**
+	 * Seeks a match of the given {@code element} in the given list, using the equality helper to find it.
+	 * This is only used when moving or deleting proxies for now.
+	 * 
+	 * @param comparison
+	 *            The comparison which Diff we are currently merging.
+	 * @param list
+	 *            The list from which we seek a value.
+	 * @param element
+	 *            The value for which we need a match in {@code list}.
+	 * @return The match of {@code element} in {@code list}, {@code null} if none.
+	 */
+	protected EObject findMatchIn(Comparison comparison, List<EObject> list, EObject element) {
+		final IEqualityHelper helper = comparison.getEqualityHelper();
+		final Iterator<EObject> it = list.iterator();
+		while (it.hasNext()) {
+			final EObject next = it.next();
+			if (helper.matchingValues(next, element)) {
+				return next;
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * This will be used by the distinct merge actions in order to find the index at which a value should be
+	 * inserted in its target list. See {@link DiffUtil#findInsertionIndex(Comparison, Diff, boolean)} for
+	 * more on this.
+	 * <p>
+	 * Sub-classes can override this if the insertion order is irrelevant. A return value of {@code -1} will
+	 * be considered as "no index" and the value will be inserted at the end of its target list.
+	 * </p>
+	 * 
+	 * @param comparison
+	 *            This will be used in order to retrieve the Match for EObjects when comparing them.
+	 * @param diff
+	 *            The diff which merging will trigger the need for an insertion index in its target list.
+	 * @param rightToLeft
+	 *            {@code true} if the merging will be done into the left list, so that we should consider the
+	 *            right model as the source and the left as the target.
+	 * @return The index at which this {@code diff}'s value should be inserted into the 'target' list, as
+	 *         inferred from {@code rightToLeft}. {@code -1} if the value should be inserted at the end of its
+	 *         target list.
+	 * @see DiffUtil#findInsertionIndex(Comparison, Diff, boolean)
+	 */
+	protected int findInsertionIndex(Comparison comparison, Diff diff, boolean rightToLeft) {
+		return DiffUtil.findInsertionIndex(comparison, diff, rightToLeft);
+	}
+}