Author: Grid.Qian
Date: 2009-12-08 02:33:02 -0500 (Tue, 08 Dec 2009)
New Revision: 19096
Added:
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/.classpath
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/.project
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/.settings/
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/.settings/org.eclipse.jdt.core.prefs
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/META-INF/
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/META-INF/MANIFEST.MF
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/build.properties
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/icons/
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/icons/full/
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/icons/full/obj16/
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/icons/full/obj16/MatchModel.gif
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/plugin.properties
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/plugin.xml
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/Activator.java
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/annotation/
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/annotation/Annotation.java
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/annotation/AnnotationSwitch.java
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/annotation/AnnotationsStore.java
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/annotation/model2diffresult.zip
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/bpel/
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/bpel/BPELCompareEditPartFactory.java
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/bpel/BPELCompareEditPolicy.java
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/bpel/BPELContentMergeViewer.java
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/bpel/BPELContentMergeViewerCreator.java
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/bpel/BPELMatchEngine.java
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/mergeviewer/
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/mergeviewer/GEFContentMergeViewer.java
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/mergeviewer/GEFContentMergeViewerResources.properties
Log:
JBIDE-5349: sync the bpel codes from eclipse bpel codes base
Added: trunk/bpel/plugins/org.eclipse.bpel.compare.ui/.classpath
===================================================================
--- trunk/bpel/plugins/org.eclipse.bpel.compare.ui/.classpath (rev
0)
+++ trunk/bpel/plugins/org.eclipse.bpel.compare.ui/.classpath 2009-12-08 07:33:02 UTC (rev
19096)
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con"
path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con"
path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
Property changes on: trunk/bpel/plugins/org.eclipse.bpel.compare.ui/.classpath
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: trunk/bpel/plugins/org.eclipse.bpel.compare.ui/.project
===================================================================
--- trunk/bpel/plugins/org.eclipse.bpel.compare.ui/.project (rev
0)
+++ trunk/bpel/plugins/org.eclipse.bpel.compare.ui/.project 2009-12-08 07:33:02 UTC (rev
19096)
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.bpel.compare.ui</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
Property changes on: trunk/bpel/plugins/org.eclipse.bpel.compare.ui/.project
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added:
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/.settings/org.eclipse.jdt.core.prefs
===================================================================
--- trunk/bpel/plugins/org.eclipse.bpel.compare.ui/.settings/org.eclipse.jdt.core.prefs
(rev 0)
+++
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/.settings/org.eclipse.jdt.core.prefs 2009-12-08
07:33:02 UTC (rev 19096)
@@ -0,0 +1,7 @@
+#Fri Apr 17 20:00:18 MSD 2009
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
Property changes on:
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/.settings/org.eclipse.jdt.core.prefs
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: trunk/bpel/plugins/org.eclipse.bpel.compare.ui/META-INF/MANIFEST.MF
===================================================================
--- trunk/bpel/plugins/org.eclipse.bpel.compare.ui/META-INF/MANIFEST.MF
(rev 0)
+++ trunk/bpel/plugins/org.eclipse.bpel.compare.ui/META-INF/MANIFEST.MF 2009-12-08
07:33:02 UTC (rev 19096)
@@ -0,0 +1,33 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-SymbolicName: org.eclipse.bpel.compare.ui;singleton:=true
+Bundle-Version: 0.5.0.qualifier
+Bundle-Activator: org.eclipse.bpel.compare.ui.Activator
+Require-Bundle: org.eclipse.ui;bundle-version="[3.5.0,4.0.0)",
+ org.eclipse.core.runtime;bundle-version="[3.5.0,4.0.0)",
+ org.eclipse.compare;bundle-version="[3.5.0,4.0.0)",
+ org.eclipse.emf.common;bundle-version="[2.5.0,3.0.0)",
+ org.eclipse.core.resources;bundle-version="[3.5.0,4.0.0)",
+ org.eclipse.emf.ecore;bundle-version="[2.5.0,3.0.0)",
+ org.eclipse.emf.compare;bundle-version="[1.0.0,2.0.0)",
+ org.eclipse.bpel.ui;bundle-version="0.5.0",
+ org.eclipse.bpel.common.ui;bundle-version="0.4.0",
+ org.eclipse.gef;bundle-version="[3.5.0,4.0.0)",
+ org.eclipse.ui.ide;bundle-version="[3.5.0,4.0.0)",
+ org.eclipse.bpel.model;bundle-version="0.5.0",
+ org.eclipse.wst.wsdl;bundle-version="[1.1.200,2.0.0)",
+ javax.wsdl;bundle-version="[1.5.0,1.6.0)",
+ org.eclipse.gmf.runtime.diagram.ui;bundle-version="1.1.3",
+ org.eclipse.emf.compare.match;bundle-version="[1.0.0,2.0.0)",
+ org.eclipse.emf.compare.diff;bundle-version="[1.0.0,2.0.0)",
+ org.eclipse.bpel.common.model;bundle-version="0.5.0",
+ org.eclipse.emf.compare.ui;bundle-version="[1.0.0,2.0.0)"
+Bundle-ActivationPolicy: lazy
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Export-Package: org.eclipse.bpel.compare.ui,
+ org.eclipse.bpel.compare.ui.annotation,
+ org.eclipse.bpel.compare.ui.gef.bpel,
+ org.eclipse.bpel.compare.ui.gef.mergeviewer
+Bundle-Vendor: %providerName
+Bundle-Localization: plugin
Property changes on: trunk/bpel/plugins/org.eclipse.bpel.compare.ui/META-INF/MANIFEST.MF
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: trunk/bpel/plugins/org.eclipse.bpel.compare.ui/build.properties
===================================================================
--- trunk/bpel/plugins/org.eclipse.bpel.compare.ui/build.properties
(rev 0)
+++ trunk/bpel/plugins/org.eclipse.bpel.compare.ui/build.properties 2009-12-08 07:33:02
UTC (rev 19096)
@@ -0,0 +1,7 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ icons/,\
+ plugin.properties,\
+ plugin.xml
\ No newline at end of file
Property changes on: trunk/bpel/plugins/org.eclipse.bpel.compare.ui/build.properties
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: trunk/bpel/plugins/org.eclipse.bpel.compare.ui/icons/full/obj16/MatchModel.gif
===================================================================
(Binary files differ)
Property changes on:
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/icons/full/obj16/MatchModel.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/bpel/plugins/org.eclipse.bpel.compare.ui/plugin.properties
===================================================================
--- trunk/bpel/plugins/org.eclipse.bpel.compare.ui/plugin.properties
(rev 0)
+++ trunk/bpel/plugins/org.eclipse.bpel.compare.ui/plugin.properties 2009-12-08 07:33:02
UTC (rev 19096)
@@ -0,0 +1,3 @@
+pluginName = BPEL Compare Plug-in
+providerName = JBoss by Red Hat
+BPEL_MATCHING_ENGINE=BPEL Matching Engine
\ No newline at end of file
Property changes on: trunk/bpel/plugins/org.eclipse.bpel.compare.ui/plugin.properties
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: trunk/bpel/plugins/org.eclipse.bpel.compare.ui/plugin.xml
===================================================================
--- trunk/bpel/plugins/org.eclipse.bpel.compare.ui/plugin.xml (rev
0)
+++ trunk/bpel/plugins/org.eclipse.bpel.compare.ui/plugin.xml 2009-12-08 07:33:02 UTC (rev
19096)
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.2"?>
+<plugin>
+
+ <extension
+ point="org.eclipse.compare.contentMergeViewers">
+ <viewer
+
class="org.eclipse.bpel.compare.ui.gef.bpel.BPELContentMergeViewerCreator"
+ id="org.eclipse.emf.compare.ui.gef.mergeviewer.content">
+ </viewer>
+ <contentTypeBinding
+
contentMergeViewerId="org.eclipse.emf.compare.ui.gef.mergeviewer.content"
+ contentTypeId="org.eclipse.bpel.common.ui.bpel.content-type">
+ </contentTypeBinding>
+ </extension>
+
+ <extension
+ point="org.eclipse.emf.compare.match.engine">
+ <matchengine
+ engineClass="org.eclipse.bpel.compare.ui.gef.bpel.BPELMatchEngine"
+ fileExtension="bpel"
+ icon="icons/full/obj16/MatchModel.gif"
+ label="%BPEL_MATCHING_ENGINE"/>
+ </extension>
+
+ <!--extension
+ point="org.eclipse.compare.structureMergeViewers">
+ <contentTypeBinding
+
structureMergeViewerId="org.eclipse.emf.compare.ui.structuremergeviewer.ModelStructureMergeViewer"
+ contentTypeId="org.eclipse.bpel.common.ui.bpel.content-type"/>
+ </extension-->
+
+</plugin>
Property changes on: trunk/bpel/plugins/org.eclipse.bpel.compare.ui/plugin.xml
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added:
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/Activator.java
===================================================================
---
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/Activator.java
(rev 0)
+++
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/Activator.java 2009-12-08
07:33:02 UTC (rev 19096)
@@ -0,0 +1,50 @@
+package org.eclipse.bpel.compare.ui;
+
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class Activator extends AbstractUIPlugin {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "org.eclipse.bpel.compare.ui";
+
+ // The shared instance
+ private static Activator plugin;
+
+ /**
+ * The constructor
+ */
+ public Activator() {
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
+ */
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ plugin = this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
+ */
+ public void stop(BundleContext context) throws Exception {
+ plugin = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static Activator getDefault() {
+ return plugin;
+ }
+
+}
Property changes on:
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/Activator.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added:
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/annotation/Annotation.java
===================================================================
---
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/annotation/Annotation.java
(rev 0)
+++
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/annotation/Annotation.java 2009-12-08
07:33:02 UTC (rev 19096)
@@ -0,0 +1,5 @@
+package org.eclipse.bpel.compare.ui.annotation;
+
+public enum Annotation {
+ Added, Deleted, Modified, Moved;
+}
Property changes on:
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/annotation/Annotation.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added:
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/annotation/AnnotationSwitch.java
===================================================================
---
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/annotation/AnnotationSwitch.java
(rev 0)
+++
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/annotation/AnnotationSwitch.java 2009-12-08
07:33:02 UTC (rev 19096)
@@ -0,0 +1,91 @@
+package org.eclipse.bpel.compare.ui.annotation;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.emf.compare.diff.metamodel.DiffElement;
+import org.eclipse.emf.compare.diff.metamodel.DiffModel;
+import org.eclipse.emf.compare.diff.metamodel.ModelElementChangeLeftTarget;
+import org.eclipse.emf.compare.diff.metamodel.ModelElementChangeRightTarget;
+import org.eclipse.emf.compare.diff.metamodel.MoveModelElement;
+import org.eclipse.emf.compare.diff.metamodel.ReferenceChangeRightTarget;
+import org.eclipse.emf.compare.diff.metamodel.UpdateAttribute;
+import org.eclipse.emf.compare.diff.metamodel.util.DiffSwitch;
+import org.eclipse.emf.compare.match.metamodel.MatchModel;
+import org.eclipse.emf.ecore.EObject;
+
+class AnnotationSwitch extends DiffSwitch<Object> {
+
+ private HashMap<EObject, DiffElement> model2annotation =
+ new HashMap<EObject, DiffElement>();
+ public List<DiffElement> annotations = new ArrayList<DiffElement>();
+
+ public HashMap<EObject, DiffElement> getAnnotations(DiffModel diff, MatchModel
match) {
+
+ for (Iterator<EObject> iter = diff.eAllContents(); iter.hasNext();) {
+ EObject eObject = iter.next();
+ doSwitch(eObject);
+ }
+
+ return model2annotation;
+ }
+
+ @Override
+ public Object caseUpdateAttribute(UpdateAttribute object) {
+ annotate(object.getLeftElement(), object);
+ annotate(object.getRightElement(), object);
+ annotations.add(object);
+ return object;
+ }
+
+ @Override
+ public Object caseModelElementChangeLeftTarget(ModelElementChangeLeftTarget object) {
+ annotate(object.getLeftElement(), object);
+ annotations.add(object);
+ return object;
+ }
+
+ @Override
+ public Object caseModelElementChangeRightTarget(ModelElementChangeRightTarget object) {
+ annotate(object.getRightElement(), object);
+ annotations.add(object);
+ return object;
+ }
+
+// @Override
+// public Object caseRemoveModelElement(RemoveModelElement object) {
+// annotate(object.getLeftElement(), object);
+// annotations.add(object);
+// return object;
+// }
+
+ @Override
+ public Object caseReferenceChangeRightTarget(
+ ReferenceChangeRightTarget object) {
+ annotate(object.getRightElement(), object);
+ annotations.add(object);
+ return object;
+ }
+
+// @Override
+// public Object caseAddModelElement(AddModelElement object) {
+// annotate(object.getRightElement(), object);
+// annotations.add(object);
+// return object;
+// }
+
+ @Override
+ public Object caseMoveModelElement(MoveModelElement object) {
+ annotate(object.getLeftElement(), object);
+ annotate(object.getRightElement(), object);
+ annotations.add(object);
+ return object;
+ }
+
+ private void annotate(EObject model, DiffElement annotation) {
+ model2annotation.put(model, annotation);
+ }
+
+}
Property changes on:
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/annotation/AnnotationSwitch.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added:
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/annotation/AnnotationsStore.java
===================================================================
---
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/annotation/AnnotationsStore.java
(rev 0)
+++
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/annotation/AnnotationsStore.java 2009-12-08
07:33:02 UTC (rev 19096)
@@ -0,0 +1,65 @@
+package org.eclipse.bpel.compare.ui.annotation;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.WeakHashMap;
+
+import org.eclipse.emf.compare.diff.metamodel.DiffElement;
+import org.eclipse.emf.compare.diff.metamodel.DiffModel;
+import org.eclipse.emf.compare.diff.service.DiffService;
+import org.eclipse.emf.compare.match.metamodel.MatchModel;
+import org.eclipse.emf.compare.match.service.MatchService;
+import org.eclipse.emf.ecore.EObject;
+
+import org.eclipse.compare.CompareConfiguration;
+
+public class AnnotationsStore {
+
+ private static AnnotationsStore instance;
+ private WeakHashMap<EObject, DiffElement> model2annotation =
+ new WeakHashMap<EObject, DiffElement>();
+ public HashMap<CompareConfiguration, List<DiffElement>> annotations = new
HashMap<CompareConfiguration, List<DiffElement>>();
+
+ public static synchronized AnnotationsStore getInstance() {
+ if (instance == null) {
+ instance = new AnnotationsStore();
+ }
+ return instance;
+ }
+
+ /**
+ * Compares two models and stores all the changes.
+ * To get the change for certain element use {@link #getAnnotation(EObject)}
+ *
+ * This function should be used once for given <code>left</code>
+ * and <code>right</code> objects. Next call will override the result of
+ * the previous call.
+ *
+ * I.e. this function should not be used like that:
+ * annotate(left, right);
+ * annotate(left, right1);
+ *
+ * @param left
+ * @param right
+ */
+ public void annotate(CompareConfiguration cc, EObject left, EObject right) {
+ try {
+ MatchModel match = MatchService.doMatch(left, right,
+ Collections.<String, Object> emptyMap());
+ DiffModel diff = DiffService.doDiff(match, false);
+ AnnotationSwitch as = new AnnotationSwitch();
+ model2annotation.putAll(as.getAnnotations(diff, match));
+ annotations.put(cc, as.annotations);
+
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ public DiffElement getAnnotation(EObject model) {
+ return model2annotation.get(model);
+ }
+
+}
Property changes on:
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/annotation/AnnotationsStore.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added:
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/annotation/model2diffresult.zip
===================================================================
(Binary files differ)
Property changes on:
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/annotation/model2diffresult.zip
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added:
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/bpel/BPELCompareEditPartFactory.java
===================================================================
---
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/bpel/BPELCompareEditPartFactory.java
(rev 0)
+++
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/bpel/BPELCompareEditPartFactory.java 2009-12-08
07:33:02 UTC (rev 19096)
@@ -0,0 +1,61 @@
+package org.eclipse.bpel.compare.ui.gef.bpel;
+
+import java.util.WeakHashMap;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.EditPartFactory;
+import org.eclipse.gef.EditPartListener;
+import org.eclipse.gef.EditPartViewer;
+
+public class BPELCompareEditPartFactory extends
+ org.eclipse.bpel.ui.editparts.util.BPELEditPartFactory {
+
+ String GRAPHICAL_ROLE = "GraphicalEditPolicy";
+
+ private static WeakHashMap<EObject, EditPart> model2editPart =
+ new WeakHashMap<EObject, EditPart>();
+
+ public static EditPart getEditPart(EObject model) {
+ return model2editPart.get(model);
+ }
+
+ @Override
+ public EditPart createEditPart(EditPart context, Object model) {
+ EditPart editPart = super.createEditPart(context, model);
+ model2editPart.put((EObject) editPart.getModel(), editPart);
+ updateEditPolicy(editPart);
+ return editPart;
+ }
+
+ private void updateEditPolicy(EditPart editPart) {
+ if (editPart == null) {
+ return;
+ }
+ editPart.installEditPolicy(GRAPHICAL_ROLE, new BPELCompareEditPolicy());
+ editPart.addEditPartListener(new EditPartListener.Stub() {
+ @Override
+ public void selectedStateChanged(EditPart editpart) {
+ if (editpart.getSelected() != EditPart.SELECTED_NONE) {
+ EditPartViewer viewer = editpart.getViewer();
+ EditPartFactory uiFactory = viewer.getEditPartFactory();
+ if (uiFactory instanceof BPELCompareEditPartFactory) {
+ BPELContentMergeViewer mergeViewer =
+ BPELContentMergeViewer.getBPELContentMergeViewer(
+ (BPELCompareEditPartFactory) uiFactory);
+ mergeViewer.selectionChanged(viewer);
+ }
+ }
+ EObject model = (EObject) editpart.getModel();
+ }
+
+ });
+
+ for (Object child : editPart.getChildren()) {
+ if (child instanceof EditPart) {
+ updateEditPolicy((EditPart) child);
+ }
+ }
+ }
+
+}
Property changes on:
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/bpel/BPELCompareEditPartFactory.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added:
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/bpel/BPELCompareEditPolicy.java
===================================================================
---
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/bpel/BPELCompareEditPolicy.java
(rev 0)
+++
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/bpel/BPELCompareEditPolicy.java 2009-12-08
07:33:02 UTC (rev 19096)
@@ -0,0 +1,104 @@
+package org.eclipse.bpel.compare.ui.gef.bpel;
+
+import java.util.List;
+
+import org.eclipse.bpel.compare.ui.annotation.AnnotationsStore;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.emf.compare.diff.metamodel.DiffElement;
+import org.eclipse.emf.compare.diff.metamodel.ModelElementChangeLeftTarget;
+import org.eclipse.emf.compare.diff.metamodel.ModelElementChangeRightTarget;
+import org.eclipse.emf.compare.diff.metamodel.MoveModelElement;
+import org.eclipse.emf.compare.diff.metamodel.UpdateAttribute;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gef.editpolicies.GraphicalEditPolicy;
+import org.eclipse.swt.graphics.Color;
+
+public class BPELCompareEditPolicy extends GraphicalEditPolicy {
+
+ private static Color COLOR_GREEN = new Color(null, 160, 255, 160);
+ private static Color COLOR_YELLOW = new Color(null, 255, 255, 160);
+ private static Color COLOR_NONE = new Color(null, 255, 255, 255);
+ private static Color COLOR_BLUE = new Color(null, 175, 238, 238);
+
+ @Override
+ public void activate() {
+ super.activate();
+ EObject model = (EObject) getHost().getModel();
+ if (getHost().getParent().getModel() == model) {
+ return;
+ }
+ DiffElement annotation = AnnotationsStore.getInstance()
+ .getAnnotation(model);
+ if (annotation == null) {
+ getHostFigure().setBackgroundColor(COLOR_NONE);
+ return;
+ }
+
+ //if (annotation instanceof AddModelElement) {
+ if (annotation instanceof ModelElementChangeLeftTarget) {
+ getHostFigure().setBackgroundColor(COLOR_GREEN);
+ //} else if (annotation instanceof RemoveModelElement) {
+ } else if (annotation instanceof ModelElementChangeRightTarget) {
+ getHostFigure().setBackgroundColor(COLOR_GREEN);
+ } else if (annotation instanceof MoveModelElement) {
+ getHostFigure().setBackgroundColor(COLOR_BLUE);
+ } else if (annotation instanceof UpdateAttribute) {
+ List children = getHostFigure().getChildren();
+ int num = 0;
+ if (children.size() > num) {
+ IFigure child = (IFigure) children.get(num);
+ child.setBackgroundColor(COLOR_YELLOW);
+ }
+ }
+
+// if (++index == 2) {
+// switch (annotation) {
+// case Added:
+// getHostFigure().setBackgroundColor(COLOR_GREEN);
+// break;
+// case Modified:
+// List children = getHostFigure().getChildren();
+// int num = 0;
+// if (children.size() > num) {
+// IFigure child = (IFigure) children.get(num);
+// child.setBackgroundColor(COLOR_YELLOW);
+// }
+//// getHostFigure().setBackgroundColor(COLOR_YELLOW);
+// break;
+// case Moved:
+// getHostFigure().setBackgroundColor(COLOR_BLUE);
+// break;
+// }
+// getHostFigure().setForegroundColor();
+// getHostFigure().setBackgroundColor(new Color(null, 160, 255, 160));
+// figure = parent;
+// List children = parent.getChildren();
+// for (Object child : children) {
+// if (child instanceof IFigure) {
+// updateAllChildren((IFigure) child);
+// }
+// }
+// }
+// if (hostFigure instanceof LayeredPane) {
+// LayeredPane lp = (LayeredPane) hostFigure;
+// int i = 0;
+// Layer layer = lp.getLayer(i++);
+// while (layer != null) {
+// layer.setForegroundColor(new Color(null, 160, 255, 160));
+// layer = lp.getLayer(i++);
+// }
+// }
+ }
+
+ private void updateAllChildren(IFigure parent) {
+// parent.setForegroundColor(new Color(null, 160, 255, 160));
+// parent.setBackgroundColor(new Color(null, 160, 255, 160));
+ List children = parent.getChildren();
+ for (Object child : children) {
+ if (child instanceof IFigure) {
+ updateAllChildren((IFigure) child);
+ }
+ }
+ }
+
+}
Property changes on:
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/bpel/BPELCompareEditPolicy.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added:
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/bpel/BPELContentMergeViewer.java
===================================================================
---
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/bpel/BPELContentMergeViewer.java
(rev 0)
+++
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/bpel/BPELContentMergeViewer.java 2009-12-08
07:33:02 UTC (rev 19096)
@@ -0,0 +1,77 @@
+package org.eclipse.bpel.compare.ui.gef.bpel;
+
+import java.util.HashMap;
+import java.util.Iterator;
+
+import org.eclipse.bpel.compare.ui.gef.mergeviewer.GEFContentMergeViewer;
+import org.eclipse.bpel.model.Process;
+import org.eclipse.bpel.ui.BPELEditDomain;
+import org.eclipse.bpel.ui.ScrollingBPELGraphicalViewer;
+import org.eclipse.bpel.ui.editparts.FlowEditPart;
+import org.eclipse.compare.CompareConfiguration;
+import org.eclipse.compare.CompareUI;
+import org.eclipse.draw2d.ColorConstants;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.swt.widgets.Composite;
+
+public class BPELContentMergeViewer extends GEFContentMergeViewer {
+
+ private static HashMap<BPELCompareEditPartFactory, BPELContentMergeViewer>
+ uiFactory2mergeViewer =
+ new HashMap<BPELCompareEditPartFactory, BPELContentMergeViewer>();
+
+ public static BPELContentMergeViewer getBPELContentMergeViewer(
+ BPELCompareEditPartFactory uiFactory) {
+ return uiFactory2mergeViewer.get(uiFactory);
+ }
+
+ protected BPELContentMergeViewer(Composite parent, CompareConfiguration cc) {
+ super(parent, cc);
+ getControl().setData(CompareUI.COMPARE_VIEWER_TITLE,
+ "BPEL Processes Compare");
+ }
+
+ @Override
+ public void updateContent(EObject modelAncestor, EObject modelLeft,
+ EObject modelRight) {
+ BPELEditDomain bpelEditDomain = new BPELEditDomain(null);
+ bpelEditDomain.setProcess((Process)modelLeft);
+ viewerLeft.setEditDomain(bpelEditDomain);
+ BPELCompareEditPartFactory uiFactory = new BPELCompareEditPartFactory();
+ viewerLeft.setEditPartFactory(uiFactory);
+ uiFactory2mergeViewer.put(uiFactory, this);
+// viewer_left.setRootEditPart(new
DiagramRootEditPart(diag_left.getMeasurementUnit()));
+ viewerLeft.setContents(modelLeft);
+
+ bpelEditDomain = new BPELEditDomain(null);
+ bpelEditDomain.setProcess((Process) modelRight);
+ viewerRight.setEditDomain(bpelEditDomain);
+ viewerRight.setEditPartFactory(uiFactory);
+ viewerRight.setContents(modelRight);
+
+ if (modelAncestor != null) {
+ bpelEditDomain = new BPELEditDomain(null);
+ bpelEditDomain.setProcess((Process) modelAncestor);
+ viewerAncestor.setEditDomain(bpelEditDomain);
+ viewerAncestor.setEditPartFactory(uiFactory);
+ viewerAncestor.setContents(modelAncestor);
+ }
+
+ }
+
+ @Override
+ public void initializeViewers(Composite composite) {
+ viewerLeft = new ScrollingBPELGraphicalViewer();
+ viewerLeft.createControl(composite);
+ viewerLeft.getControl().setBackground(ColorConstants.listBackground);
+
+ viewerRight = new ScrollingBPELGraphicalViewer();
+ viewerRight.createControl(composite);
+ viewerRight.getControl().setBackground(ColorConstants.listBackground);
+
+ viewerAncestor = new ScrollingBPELGraphicalViewer();
+ viewerAncestor.createControl(composite);
+ viewerAncestor.getControl().setBackground(ColorConstants.listBackground);
+ }
+
+}
Property changes on:
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/bpel/BPELContentMergeViewer.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added:
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/bpel/BPELContentMergeViewerCreator.java
===================================================================
---
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/bpel/BPELContentMergeViewerCreator.java
(rev 0)
+++
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/bpel/BPELContentMergeViewerCreator.java 2009-12-08
07:33:02 UTC (rev 19096)
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Tobias Jaehnel.
+ * 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:
+ * Tobias Jaehnel - Bug#241385
+ *******************************************************************************/
+
+package org.eclipse.bpel.compare.ui.gef.bpel;
+
+import org.eclipse.compare.CompareConfiguration;
+import org.eclipse.compare.IViewerCreator;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.widgets.Composite;
+
+public class BPELContentMergeViewerCreator implements IViewerCreator {
+
+ public BPELContentMergeViewerCreator() {
+ // TODO Auto-generated constructor stub
+ }
+
+ public Viewer createViewer(Composite parent, CompareConfiguration config) {
+ return new BPELContentMergeViewer(parent, config);
+ }
+
+}
Property changes on:
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/bpel/BPELContentMergeViewerCreator.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added:
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/bpel/BPELMatchEngine.java
===================================================================
---
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/bpel/BPELMatchEngine.java
(rev 0)
+++
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/bpel/BPELMatchEngine.java 2009-12-08
07:33:02 UTC (rev 19096)
@@ -0,0 +1,1940 @@
+package org.eclipse.bpel.compare.ui.gef.bpel;
+/*******************************************************************************
+ * Copyright (c) 2006, 2007, 2008 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
+ *******************************************************************************/
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.emf.common.EMFPlugin;
+import org.eclipse.emf.common.util.BasicMonitor;
+import org.eclipse.emf.common.util.Monitor;
+import org.eclipse.emf.common.util.TreeIterator;
+import org.eclipse.emf.compare.EMFComparePlugin;
+import org.eclipse.emf.compare.FactoryException;
+import org.eclipse.emf.compare.match.MatchOptions;
+import org.eclipse.emf.compare.match.engine.IMatchEngine;
+import org.eclipse.emf.compare.match.internal.statistic.NameSimilarity;
+import org.eclipse.emf.compare.match.internal.statistic.StructureSimilarity;
+import org.eclipse.emf.compare.match.metamodel.Match2Elements;
+import org.eclipse.emf.compare.match.metamodel.Match3Elements;
+import org.eclipse.emf.compare.match.metamodel.MatchElement;
+import org.eclipse.emf.compare.match.metamodel.MatchFactory;
+import org.eclipse.emf.compare.match.metamodel.MatchModel;
+import org.eclipse.emf.compare.match.metamodel.Side;
+import org.eclipse.emf.compare.match.metamodel.UnmatchElement;
+import org.eclipse.emf.compare.match.statistic.MetamodelFilter;
+import org.eclipse.emf.compare.util.EFactory;
+import org.eclipse.emf.compare.util.EMFCompareMap;
+import org.eclipse.emf.compare.util.EMFComparePreferenceConstants;
+import org.eclipse.emf.compare.util.EclipseModelUtils;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.emf.ecore.xmi.XMIResource;
+
+/**
+ * These services are useful when one wants to compare models more precisely using the
method modelDiff.
+ *
+ * @author <a href="mailto:cedric.brun@obeo.fr">Cedric Brun</a>
+ */
+public class BPELMatchEngine implements IMatchEngine {
+//public class BPELMatchEngine extends GenericMatchEngine {
+
+ /** Used while computing similarity, this defines the general threshold. */
+ private static final double GENERAL_THRESHOLD = 0.96d;
+
+ /** Containmnent reference for the matched elements root. */
+ private static final String MATCH_ELEMENT_NAME = "matchedElements";
//$NON-NLS-1$
+
+ /**
+ * Minimal number of attributes an element must have for content comparison.
+ */
+ private static final int MIN_ATTRIBUTES_COUNT = 5;
+
+ /** This constant is used as key for the buffering of name similarity. */
+ private static final char NAME_SIMILARITY = 'n';
+
+ /** This constant is used as key for the buffering of relations similarity. */
+ private static final char RELATION_SIMILARITY = 'r';
+
+ /** Containmnent reference for {@link MatchElement}s' submatches. */
+ private static final String SUBMATCH_ELEMENT_NAME = "subMatchElements";
//$NON-NLS-1$
+
+ /** This constant is used as key for the buffering of type similarity. */
+ private static final char TYPE_SIMILARITY = 't';
+
+ /** Containmnent reference for the {@link MatchModel}'s unmatched elements. */
+ private static final String UNMATCH_ELEMENT_NAME = "unmatchedElements";
//$NON-NLS-1$
+
+ /** This constant is used as key for the buffering of value similarity. */
+ private static final char VALUE_SIMILARITY = 'v';
+
+ /**
+ * {@link MetamodelFilter} used for filtering unused features of the objects we're
computing the
+ * similarity for.
+ */
+ protected final MetamodelFilter filter = new MetamodelFilter();
+
+ /** Contains the options given to the match procedure. */
+ protected final Map<String, Object> options = new EMFCompareMap<String,
Object>();
+
+ /**
+ * This map allows us memorize the {@link EObject} we've been able to match thanks
to their functional ID.
+ */
+ private final Map<String, EObject> matchedByID = new EMFCompareMap<String,
EObject>();
+
+ /**
+ * This map allows us memorize the {@link EObject} we've been able to match thanks
to their XMI ID.
+ */
+ private final Map<String, EObject> matchedByXMIID = new EMFCompareMap<String,
EObject>();
+
+ /**
+ * This map is used to cache the comparison results Pair(Element1, Element2) =>
[nameSimilarity,
+ * valueSimilarity, relationSimilarity, TypeSimilarity].
+ */
+ private final Map<String, Double> metricsCache = new EMFCompareMap<String,
Double>();
+
+ /**
+ * This list allows us to memorize the unMatched elements for a three-way
comparison.<br/>
+ * <p>
+ * More specifically, we will populate this list with the {@link UnmatchElement}s
created by the
+ * comparison between the left and the ancestor model, followed by the {@link
UnmatchElement} created by
+ * the comparison between the right and the ancestor model.<br/> Those {@link
UnmatchElement} will then
+ * be filtered to retain only those that actually cannot be matched.
+ * </p>
+ */
+ private final Set<EObject> remainingUnMatchedElements = new
HashSet<EObject>();
+
+ /**
+ * This list will be intensively used while matching elements to keep track of the
unmatched ones from the
+ * left model.
+ */
+ private final List<EObject> stillToFindFromModel1 = new
ArrayList<EObject>();
+
+ /**
+ * This list will be intensively used while matching elements to keep track of the
unmatched ones from the
+ * right model.
+ */
+ private final List<EObject> stillToFindFromModel2 = new
ArrayList<EObject>();
+
+ /**
+ * The options map must be initialized to avoid potential NPEs. This initializer will
take care of this
+ * issue.
+ */
+ {
+ options.putAll(loadPreferenceOptionMap());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.eclipse.emf.compare.match.api.IMatchEngine#contentMatch(org.eclipse.emf.ecore.EObject,
+ * org.eclipse.emf.ecore.EObject, org.eclipse.emf.ecore.EObject, java.util.Map)
+ */
+ public MatchModel contentMatch(EObject leftObject, EObject rightObject, EObject
ancestor,
+ Map<String, Object> optionMap) {
+ final MatchModel root = MatchFactory.eINSTANCE.createMatchModel();
+ setModelRoots(root, leftObject.eResource(), rightObject.eResource(),
ancestor.eResource());
+ final Monitor monitor = createProgressMonitor();
+ final MatchModel leftObjectAncestorMatch = contentMatch(leftObject, ancestor,
optionMap);
+ final MatchModel rightObjectAncestorMatch = contentMatch(rightObject, ancestor,
optionMap);
+
+ final List<MatchElement> leftObjectMatchedElements = new
ArrayList<MatchElement>(
+ leftObjectAncestorMatch.getMatchedElements());
+ final List<MatchElement> rightObjectMatchedElements = new
ArrayList<MatchElement>(
+ rightObjectAncestorMatch.getMatchedElements());
+
+ // populates the unmatched elements list for later use
+ for (Object unMatch : leftObjectAncestorMatch.getUnmatchedElements())
+ remainingUnMatchedElements.add(((UnmatchElement)unMatch).getElement());
+ for (Object unMatch : rightObjectAncestorMatch.getUnmatchedElements())
+ remainingUnMatchedElements.add(((UnmatchElement)unMatch).getElement());
+
+ try {
+ Match3Elements subMatchRoot = null;
+ if (leftObjectMatchedElements.size() > 0 &&
rightObjectMatchedElements.size() > 0) {
+ final Match2Elements leftObjectMatchRoot =
(Match2Elements)leftObjectMatchedElements.get(0);
+ final Match2Elements rightObjectMatchRoot =
(Match2Elements)rightObjectMatchedElements.get(0);
+ subMatchRoot = MatchFactory.eINSTANCE.createMatch3Elements();
+
+ subMatchRoot.setSimilarity(absoluteMetric(leftObjectMatchRoot.getLeftElement(),
+ rightObjectMatchRoot.getLeftElement(), rightObjectMatchRoot.getRightElement()));
+ subMatchRoot.setLeftElement(leftObjectMatchRoot.getLeftElement());
+ subMatchRoot.setRightElement(rightObjectMatchRoot.getLeftElement());
+ subMatchRoot.setOriginElement(rightObjectMatchRoot.getRightElement());
+ redirectedAdd(root, MATCH_ELEMENT_NAME, subMatchRoot);
+ createSub3Match(root, subMatchRoot, leftObjectMatchRoot, rightObjectMatchRoot);
+ } else {
+ for (EObject left : leftObjectMatchedElements)
+ stillToFindFromModel1.add(left);
+ for (EObject right : rightObjectMatchedElements)
+ stillToFindFromModel2.add(right);
+ }
+
+ // We will now check through the unmatched object for matches.
+ processUnmatchedElements(root, subMatchRoot);
+
+ // #createSub3Match(MatchModel, Match3Element, Match2Elements,
+ // Match2Elements) will have updated "remainingUnMatchedElements"
+ final Set<EObject> remainingLeft = new HashSet<EObject>();
+ final Set<EObject> remainingRight = new HashSet<EObject>();
+ for (EObject unMatched : remainingUnMatchedElements) {
+ if (unMatched.eResource() == leftObject.eResource()) {
+ remainingLeft.add(unMatched);
+ final TreeIterator<EObject> iterator = unMatched.eAllContents();
+ while (iterator.hasNext())
+ remainingLeft.add(iterator.next());
+ } else if (unMatched.eResource() == rightObject.eResource()) {
+ remainingRight.add(unMatched);
+ final TreeIterator<EObject> iterator = unMatched.eAllContents();
+ while (iterator.hasNext())
+ remainingRight.add(iterator.next());
+ }
+ }
+ stillToFindFromModel1.clear();
+ stillToFindFromModel2.clear();
+ final List<Match2Elements> mappings = mapLists(new
ArrayList<EObject>(remainingLeft),
+ new ArrayList<EObject>(remainingRight), this
+ .<Integer> getOption(MatchOptions.OPTION_SEARCH_WINDOW), monitor);
+ for (Match2Elements map : mappings) {
+ final Match3Elements subMatch = MatchFactory.eINSTANCE.createMatch3Elements();
+ subMatch.setLeftElement(map.getLeftElement());
+ subMatch.setRightElement(map.getRightElement());
+ if (subMatchRoot == null)
+ redirectedAdd(root, MATCH_ELEMENT_NAME, subMatch);
+ else
+ redirectedAdd(subMatchRoot, SUBMATCH_ELEMENT_NAME, subMatch);
+ }
+ final Map<EObject, Boolean> unMatchedElements = new EMFCompareMap<EObject,
Boolean>();
+ for (EObject remoteUnMatch : stillToFindFromModel1) {
+ unMatchedElements.put(remoteUnMatch, true);
+ }
+ for (EObject unMatch : stillToFindFromModel2) {
+ unMatchedElements.put(unMatch, false);
+ }
+ createThreeWayUnmatchElements(root, unMatchedElements);
+ } catch (FactoryException e) {
+ EMFComparePlugin.log(e, false);
+ } catch (InterruptedException e) {
+ // Cannot be thrown since we have no monitor
+ }
+
+ return root;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.eclipse.emf.compare.match.api.IMatchEngine#contentMatch(org.eclipse.emf.ecore.EObject,
+ * org.eclipse.emf.ecore.EObject, java.util.Map)
+ */
+ public MatchModel contentMatch(EObject leftObject, EObject rightObject, Map<String,
Object> optionMap) {
+ if (optionMap != null && optionMap.size() > 0)
+ loadOptionMap(optionMap);
+
+ final Monitor monitor = createProgressMonitor();
+
+ final MatchModel root = MatchFactory.eINSTANCE.createMatchModel();
+ setModelRoots(root, leftObject.eResource(), rightObject.eResource());
+
+ /*
+ * As we could very well be passed two EClasses (as opposed to modelMatch which
compares all roots of
+ * a resource), we cannot filter the model.
+ */
+
+ final Set<EObject> still1 = new HashSet<EObject>();
+ final Set<EObject> still2 = new HashSet<EObject>();
+
+ // navigate through both objects at the same time and realize mappings..
+ try {
+ if (!this.<Boolean> getOption(MatchOptions.OPTION_IGNORE_XMI_ID))
+ matchByXMIID(leftObject, rightObject);
+ if (!this.<Boolean> getOption(MatchOptions.OPTION_IGNORE_ID))
+ matchByID(leftObject, rightObject);
+ if (isSimilar(leftObject, rightObject)) {
+ stillToFindFromModel1.clear();
+ stillToFindFromModel2.clear();
+ final Match2Elements matchModelRoot = recursiveMappings(leftObject, rightObject,
monitor);
+ redirectedAdd(root, MATCH_ELEMENT_NAME, matchModelRoot);
+ createSubMatchElements(matchModelRoot, new
ArrayList<EObject>(stillToFindFromModel1),
+ new ArrayList<EObject>(stillToFindFromModel2), monitor);
+ still1.addAll(stillToFindFromModel1);
+ still2.addAll(stillToFindFromModel2);
+ createUnmatchElements(root, still1, Side.LEFT);
+ createUnmatchElements(root, still2, Side.RIGHT);
+ } else {
+ // The two objects passed as this method's parameters are not
+ // similar. Creates unmatch root.
+ still1.add(leftObject);
+ still1.add(rightObject);
+ createUnmatchElements(root, still1, null);
+ }
+ } catch (FactoryException e) {
+ EMFComparePlugin.log(e, false);
+ } catch (InterruptedException e) {
+ // Cannot be thrown since we have no monitor
+ }
+ return root;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.eclipse.emf.compare.match.api.IMatchEngine#modelMatch(org.eclipse.emf.ecore.EObject,
+ * org.eclipse.emf.ecore.EObject, org.eclipse.emf.ecore.EObject, java.util.Map)
+ */
+ public MatchModel modelMatch(EObject leftRoot, EObject rightRoot, EObject ancestor,
+ Map<String, Object> optionMap) throws InterruptedException {
+ if (optionMap != null && optionMap.size() > 0)
+ loadOptionMap(optionMap);
+
+ MatchModel result = null;
+ // Creates and sizes progress monitor
+ final Monitor monitor = createProgressMonitor();
+ int size = 1;
+ for (EObject root : leftRoot.eResource().getContents()) {
+ final Iterator<EObject> rootContent = root.eAllContents();
+ while (rootContent.hasNext()) {
+ rootContent.next();
+ size++;
+ }
+ }
+ startMonitor(monitor, size * 2);
+
+ result = doMatch(leftRoot.eResource(), rightRoot.eResource(), ancestor.eResource(),
monitor);
+
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.eclipse.emf.compare.match.api.IMatchEngine#modelMatch(org.eclipse.emf.ecore.EObject,
+ * org.eclipse.emf.ecore.EObject, java.util.Map)
+ */
+ public MatchModel modelMatch(EObject leftRoot, EObject rightRoot, Map<String,
Object> optionMap)
+ throws InterruptedException {
+ if (optionMap != null && optionMap.size() > 0)
+ loadOptionMap(optionMap);
+
+ MatchModel result = null;
+ // Creates and sizes progress monitor
+ final Monitor monitor = createProgressMonitor();
+ int size = 1;
+ for (EObject root : leftRoot.eResource().getContents()) {
+ final Iterator<EObject> rootContent = root.eAllContents();
+ while (rootContent.hasNext()) {
+ rootContent.next();
+ size++;
+ }
+ }
+ startMonitor(monitor, size);
+
+ result = doMatch(leftRoot.eResource(), rightRoot.eResource(), monitor);
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.emf.compare.match.api.IMatchEngine#reset()
+ */
+ public void reset() {
+ filter.clear();
+ options.clear();
+ matchedByID.clear();
+ matchedByXMIID.clear();
+ metricsCache.clear();
+ remainingUnMatchedElements.clear();
+ stillToFindFromModel1.clear();
+ stillToFindFromModel2.clear();
+ options.putAll(loadPreferenceOptionMap());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.eclipse.emf.compare.match.api.IMatchEngine#resourceMatch(org.eclipse.emf.ecore.resource.Resource,
+ * org.eclipse.emf.ecore.resource.Resource, java.util.Map)
+ */
+ public MatchModel resourceMatch(Resource leftResource, Resource rightResource,
+ Map<String, Object> optionMap) throws InterruptedException {
+ if (optionMap != null && optionMap.size() > 0)
+ loadOptionMap(optionMap);
+
+ MatchModel result = null;
+ // Creates and sizes progress monitor
+ final Monitor monitor = createProgressMonitor();
+ int size = 1;
+ for (EObject root : leftResource.getContents()) {
+ final Iterator<EObject> rootContent = root.eAllContents();
+ while (rootContent.hasNext()) {
+ rootContent.next();
+ size++;
+ }
+ }
+ startMonitor(monitor, size);
+
+ result = doMatch(leftResource, rightResource, monitor);
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.eclipse.emf.compare.match.api.IMatchEngine#resourceMatch(org.eclipse.emf.ecore.resource.Resource,
+ * org.eclipse.emf.ecore.resource.Resource,
org.eclipse.emf.ecore.resource.Resource, java.util.Map)
+ */
+ public MatchModel resourceMatch(Resource leftResource, Resource rightResource, Resource
ancestorResource,
+ Map<String, Object> optionMap) throws InterruptedException {
+ if (optionMap != null && optionMap.size() > 0)
+ loadOptionMap(optionMap);
+
+ MatchModel result = null;
+ // Creates and sizes progress monitor
+ final Monitor monitor = createProgressMonitor();
+ int size = 1;
+ for (EObject root : leftResource.getContents()) {
+ final Iterator<EObject> rootContent = root.eAllContents();
+ while (rootContent.hasNext()) {
+ rootContent.next();
+ size++;
+ }
+ }
+ startMonitor(monitor, size * 2);
+
+ result = doMatch(leftResource, rightResource, ancestorResource, monitor);
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.eclipse.emf.compare.match.api.IMatchEngine#resourceSetMatch(org.eclipse.emf.ecore.resource.ResourceSet,
+ * org.eclipse.emf.ecore.resource.ResourceSet, java.util.Map)
+ */
+ public MatchModel resourceSetMatch(ResourceSet leftResourceSet, ResourceSet
rightResourceSet,
+ Map<String, Object> optionMap) {
+ // TODO this should be implemented. It will break both match and diff
+ // MMs so wait till 0.9/1.0.
+ throw new UnsupportedOperationException("Not implemented yet.");
//$NON-NLS-1$
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.eclipse.emf.compare.match.api.IMatchEngine#resourceSetMatch(org.eclipse.emf.ecore.resource.ResourceSet,
+ * org.eclipse.emf.ecore.resource.ResourceSet,
org.eclipse.emf.ecore.resource.ResourceSet,
+ * java.util.Map)
+ */
+ public MatchModel resourceSetMatch(ResourceSet leftResourceSet, ResourceSet
rightResourceSet,
+ ResourceSet ancestorResourceSet, Map<String, Object> optionMap) {
+ // TODO this should be implemented. It will break both match and diff
+ // MMs so wait till 0.9/1.0.
+ throw new UnsupportedOperationException("Not implemented yet.");
//$NON-NLS-1$
+ }
+
+ /**
+ * This will compute the similarity between two {@link EObject}s' contents.
+ *
+ * @param obj1
+ * First of the two {@link EObject}s.
+ * @param obj2
+ * Second of the two {@link EObject}s.
+ * @return <code>double</code> representing the similarity between the two
{@link EObject}s' contents.
+ * 0 < value < 1.
+ * @throws FactoryException
+ * Thrown if we cannot compute the {@link EObject}s' contents similarity
metrics.
+ * @see NameSimilarity#contentValue(EObject, MetamodelFilter)
+ */
+ protected double contentSimilarity(EObject obj1, EObject obj2) throws FactoryException
{
+ double similarity = 0d;
+ final Double value = getSimilarityFromCache(obj1, obj2, VALUE_SIMILARITY);
+ if (value != null) {
+ similarity = value;
+ } else {
+ similarity = NameSimilarity.nameSimilarityMetric(NameSimilarity.contentValue(obj1,
filter),
+ NameSimilarity.contentValue(obj2, filter));
+ setSimilarityInCache(obj1, obj2, VALUE_SIMILARITY, similarity);
+ }
+ return similarity;
+ }
+
+ /**
+ * This will iterate through the given {@link List} and return its element which is most
similar (as given
+ * by {@link #absoluteMetric(EObject, EObject)}) to the given {@link EObject}.
+ *
+ * @param eObj
+ * {@link EObject} we're searching a similar item for in the list.
+ * @param list
+ * {@link List} in which we are to find an object similar to
<code>eObj</code>.
+ * @return The element from <code>list</code> which is the most similar to
<code>eObj</code>.
+ * @throws FactoryException
+ * Thrown if we cannot compute the {@link #absoluteMetric(EObject, EObject)
absolute metric}
+ * between <code>eObj</code> and one of the list's objects.
+ */
+ protected EObject findMostSimilar(EObject eObj, List<EObject> list) throws
FactoryException {
+ double max = 0d;
+ EObject resultObject = null;
+ final Iterator<EObject> it = list.iterator();
+ while (it.hasNext() && max != 1.0d) {
+ final EObject next = it.next();
+ if (this.<Boolean> getOption(MatchOptions.OPTION_DISTINCT_METAMODELS)
+ || eObj.eClass() == next.eClass()) {
+ final double similarity = absoluteMetric(eObj, next);
+ if (similarity > max) {
+ max = similarity;
+ resultObject = next;
+ }
+ }
+ }
+ return resultObject;
+ }
+
+ /**
+ * This will return the value associated to the given key in the options map.
+ * <p>
+ * NOTE : Misuses of this method will easily throw {@link ClassCastException}s.
+ * </p>
+ *
+ * @param <T>
+ * Expected type of the value associated to <code>key</code>.
+ * @param key
+ * Key of the value to retrieve.
+ * @return Value associated to the given key in the options map.
+ * @throws ClassCastException
+ * If the value isn't assignment compatible with the expected type.
+ */
+ @SuppressWarnings("unchecked")
+ protected <T> T getOption(String key) throws ClassCastException {
+ return (T)options.get(key);
+ }
+
+ /**
+ * This will lookup in the {@link #matchedByID} map and check if the two given objects
have indeed been
+ * matched by their ID.
+ *
+ * @param left
+ * Left of the two objects to check.
+ * @param right
+ * right of the two objects to check.
+ * @return <code>True</code> these objects haven't been matched by their
ID, <code>False</code>
+ * otherwise.
+ * @throws FactoryException
+ * Thrown if we cannot compute the key for the object to match.
+ */
+ protected boolean haveDistinctID(EObject left, EObject right) throws FactoryException {
+ boolean result = false;
+ final StringBuilder leftKey = new StringBuilder();
+ leftKey.append(NameSimilarity.findName(left));
+ leftKey.append(left.hashCode());
+ final EObject matched = matchedByID.get(leftKey.toString());
+ // must be the same instance
+ if (matched != null)
+ result = matched != right;
+ else
+ // we didn't match a single element with this ID.
+ // This could be because no IDs are defined.
+ result = EcoreUtil.getID(left) != null;
+ return result;
+ }
+
+ /**
+ * This will lookup in the {@link #matchedByXMIID} map and check if the two given
objects have indeed been
+ * matched by their XMI ID.
+ *
+ * @param left
+ * Left of the two objects to check.
+ * @param right
+ * right of the two objects to check.
+ * @return <code>True</code> these objects haven't been matched by their
XMI ID, <code>False</code>
+ * otherwise.
+ * @throws FactoryException
+ * Thrown if we cannot compute the key for the object to match.
+ */
+ protected boolean haveDistinctXMIID(EObject left, EObject right) throws FactoryException
{
+ boolean result = false;
+ final StringBuilder leftKey = new StringBuilder();
+ leftKey.append(NameSimilarity.findName(left));
+ leftKey.append(left.hashCode());
+ final EObject matched = matchedByXMIID.get(leftKey.toString());
+ // must be the same instance
+ if (matched != null)
+ result = matched != right;
+ else
+ // we didn't match a single element with this ID.
+ // This could be because no IDs are defined.
+ result = left.eResource() instanceof XMIResource
+ && ((XMIResource)left.eResource()).getID(left) != null;
+ return result;
+ }
+
+ /**
+ * Returns <code>True</code> if the 2 given {@link EObject}s are considered
similar.
+ *
+ * @param obj1
+ * The first {@link EObject} to compare.
+ * @param obj2
+ * Second of the {@link EObject}s to compare.
+ * @return <code>True</code> if both elements have the same serialization
ID, <code>False</code>
+ * otherwise.
+ * @throws FactoryException
+ * Thrown if we cannot compute one of the needed similarity.
+ */
+ protected boolean isSimilar(EObject obj1, EObject obj2) throws FactoryException {
+ boolean similar = false;
+
+ // Defines threshold constants to assume objects' similarity
+ final double nameOnlyMetricThreshold = 0.7d;
+ final double fewerAttributesNameThreshold = 0.8d;
+ final double relationsThreshold = 0.3d;
+ final double nameThreshold = 0.2d;
+ final double contentThreshold = 0.9d;
+ final double triWayThreshold = 0.9d;
+ final double generalThreshold = GENERAL_THRESHOLD;
+
+ // Computes some of the required metrics
+ final double nameSimilarity = nameSimilarity(obj1, obj2);
+ final boolean hasSameUri = hasSameUri(obj1, obj2);
+ final int obj1NonNullFeatures = nonNullFeaturesCount(obj1);
+ final int obj2NonNullFeatures = nonNullFeaturesCount(obj2);
+
+ if (!this.<Boolean> getOption(MatchOptions.OPTION_DISTINCT_METAMODELS)
+ && obj1.eClass() != obj2.eClass()) {
+ similar = false;
+ } else if (!this.<Boolean> getOption(MatchOptions.OPTION_IGNORE_ID) &&
haveDistinctID(obj1, obj2)) {
+ similar = false;
+ } else if (!this.<Boolean> getOption(MatchOptions.OPTION_IGNORE_XMI_ID)
+ && haveDistinctXMIID(obj1, obj2)) {
+ similar = false;
+ } else if (nameSimilarity == 1) {
+ similar = true;
+ // softer tests if we don't have enough attributes to compare the
+ // objects
+ } else if (obj1NonNullFeatures == 1 && obj2NonNullFeatures == 1) {
+ similar = nameSimilarity > nameOnlyMetricThreshold;
+ } else if (nameSimilarity > fewerAttributesNameThreshold
+ && obj1NonNullFeatures <= MIN_ATTRIBUTES_COUNT &&
obj2NonNullFeatures <= MIN_ATTRIBUTES_COUNT
+ && typeSimilarity(obj1, obj2) > generalThreshold) {
+ similar = true;
+ } else {
+ final double contentSimilarity = contentSimilarity(obj1, obj2);
+ final double relationsSimilarity = relationsSimilarity(obj1, obj2);
+
+ if (relationsSimilarity == 1 && hasSameUri && nameSimilarity >
nameThreshold) {
+ similar = true;
+ } else if (contentSimilarity == 1 && relationsSimilarity == 1) {
+ similar = true;
+ } else if (contentSimilarity > generalThreshold && relationsSimilarity >
relationsThreshold
+ && nameSimilarity > nameThreshold) {
+ similar = true;
+ } else if (relationsSimilarity > generalThreshold && contentSimilarity >
contentThreshold) {
+ similar = true;
+ } else if (contentSimilarity > triWayThreshold && nameSimilarity >
triWayThreshold
+ && relationsSimilarity > triWayThreshold) {
+ similar = true;
+ } else if (contentSimilarity > generalThreshold && nameSimilarity >
generalThreshold
+ && typeSimilarity(obj1, obj2) > generalThreshold) {
+ similar = true;
+ }
+ }
+ return similar;
+ }
+
+ /**
+ * This will compute the similarity between two {@link EObject}s' names.
+ *
+ * @param obj1
+ * First of the two {@link EObject}s.
+ * @param obj2
+ * Second of the two {@link EObject}s.
+ * @return <code>double</code> representing the similarity between the two
{@link EObject}s' names. 0
+ * < value < 1.
+ * @see NameSimilarity#nameSimilarityMetric(String, String)
+ */
+ protected double nameSimilarity(EObject obj1, EObject obj2) {
+ double similarity = 0d;
+ try {
+ final Double value = getSimilarityFromCache(obj1, obj2, NAME_SIMILARITY);
+ if (value != null) {
+ similarity = value;
+ } else {
+ similarity = NameSimilarity.nameSimilarityMetric(NameSimilarity.findName(obj1),
+ NameSimilarity.findName(obj2));
+ setSimilarityInCache(obj1, obj2, NAME_SIMILARITY, similarity);
+ }
+ } catch (FactoryException e) {
+ // fails silently, will return a similarity of 0d
+ }
+ return similarity;
+ }
+
+ /*
+ * created as package visibility method to allow access from initializer's listener.
Shouldn't be further
+ * opened.
+ */
+ /**
+ * This will load all the needed options with their default values.
+ *
+ * @return Map containing all the needed options with their default values.
+ */
+ /* package */Map<String, Object> loadPreferenceOptionMap() {
+ final Map<String, Object> optionMap = new EMFCompareMap<String,
Object>(17);
+ optionMap.put(MatchOptions.OPTION_SEARCH_WINDOW, getPreferenceSearchWindow());
+ optionMap.put(MatchOptions.OPTION_IGNORE_ID, getPreferenceIgnoreID());
+ optionMap.put(MatchOptions.OPTION_IGNORE_XMI_ID, getPreferenceIgnoreXMIID());
+ optionMap.put(MatchOptions.OPTION_DISTINCT_METAMODELS,
getPreferenceDistinctMetaModel());
+ optionMap.put(MatchOptions.OPTION_PROGRESS_MONITOR, null);
+ return optionMap;
+ }
+
+ /**
+ * Returns an absolute comparison metric between the two given {@link EObject}s.
+ *
+ * @param obj1
+ * The first {@link EObject} to compare.
+ * @param obj2
+ * Second of the {@link EObject}s to compare.
+ * @return An absolute comparison metric. 0 < value < 1.
+ * @throws FactoryException
+ * Thrown if we cannot compute the content similarity.
+ */
+ private double absoluteMetric(EObject obj1, EObject obj2) throws FactoryException {
+ final double nameSimilarity = nameSimilarity(obj1, obj2);
+ if (nameSimilarity == 1.0d) {
+ return 1.0;
+ }
+ final double relationsSimilarity = relationsSimilarity(obj1, obj2);
+ double sameUri = 0d;
+ if (hasSameUri(obj1, obj2))
+ sameUri = 1;
+ final double positionSimilarity = relationsSimilarity / 2d + sameUri / 2d;
+
+ final double contentWeight = 0.5d;
+
+ if (nonNullFeaturesCount(obj1) > MIN_ATTRIBUTES_COUNT
+ && nonNullFeaturesCount(obj2) > MIN_ATTRIBUTES_COUNT) {
+ final double nameWeight = 0.8d;
+ final double positionWeight = 0.4d;
+ final double contentSimilarity = contentSimilarity(obj1, obj2);
+ // Computing type similarity really is time expensive
+ // double typeSimilarity = typeSimilarity(obj1, obj2);
+ return (contentSimilarity * contentWeight + nameSimilarity * nameWeight +
positionSimilarity
+ * positionWeight)
+ / (contentWeight + nameWeight + positionWeight);
+ }
+ // we didn't have enough features to compute an accurate metric
+ final double nameWeight = 0.4d;
+ final double positionWeight = 0.2d;
+ return (nameSimilarity * nameWeight + positionSimilarity * positionWeight)
+ / (nameWeight + positionWeight);
+ }
+
+ /**
+ * Returns an absolute comparison metric between the three given {@link EObject}s.
+ *
+ * @param obj1
+ * The first {@link EObject} to compare.
+ * @param obj2
+ * Second of the {@link EObject}s to compare.
+ * @param obj3
+ * Second of the {@link EObject}s to compare.
+ * @return An absolute comparison metric
+ * @throws FactoryException
+ * Thrown if we cannot compute the content similarity.
+ */
+ private double absoluteMetric(EObject obj1, EObject obj2, EObject obj3) throws
FactoryException {
+ final double metric1 = absoluteMetric(obj1, obj2);
+ final double metric2 = absoluteMetric(obj1, obj3);
+ final double metric3 = absoluteMetric(obj2, obj3);
+
+ return (metric1 + metric2 + metric3) / 3;
+ }
+
+ /**
+ * This will recursively create three-way submatches and add them under the given {@link
MatchModel}. The
+ * two {@link Match2Elements} we consider as parameters are the result of the two-way
comparisons between :
+ * <ul>
+ * <li>The left and origin model.</li>
+ * <li>The right and origin model.</li>
+ * </ul>
+ * <br/><br/>We can then consider that a {@link Match3Element} would be :
+ *
+ * <pre>
+ * match.leftElement = left.getLeftElement();
+ * match.originElement = left.getRightElement() = right.getRightElement();
+ * match.rightElement = right.getLeftElement();
+ * </pre>
+ *
+ * @param root
+ * {@link MatchModel} under which to add our {@link Match3Element}s.
+ * @param matchElementRoot
+ * Root of the {@link Match3Element}s' hierarchy for the current element
to be created.
+ * @param left
+ * Left {@link Match2Elements} to consider.
+ * @param right
+ * Right {@link Match2Elements} to consider.
+ * @throws FactoryException
+ * Thrown if we cannot compute the {@link #absoluteMetric(EObject, EObject,
EObject) absolute
+ * metric} between the three elements or if we cannot add a {@link
Match3Element} under the
+ * given <code>matchElementRoot</code>.
+ */
+ private void createSub3Match(MatchModel root, Match3Elements matchElementRoot,
Match2Elements left,
+ Match2Elements right) throws FactoryException {
+ final List<MatchElement> leftSubMatches = left.getSubMatchElements();
+ final List<MatchElement> rightSubMatches = right.getSubMatchElements();
+ final List<MatchElement> leftNotFound = new
ArrayList<MatchElement>(leftSubMatches);
+ final List<MatchElement> rightNotFound = new
ArrayList<MatchElement>(rightSubMatches);
+
+ for (MatchElement nextLeft : leftSubMatches) {
+ final Match2Elements nextLeftMatch = (Match2Elements)nextLeft;
+ Match2Elements correspondingMatch = null;
+
+ for (MatchElement nextRight : rightNotFound) {
+ final Match2Elements nextRightMatch = (Match2Elements)nextRight;
+ if (nextRightMatch.getRightElement().equals(nextLeftMatch.getRightElement())) {
+ correspondingMatch = nextRightMatch;
+ break;
+ }
+ }
+
+ if (correspondingMatch != null) {
+ final Match3Elements match = MatchFactory.eINSTANCE.createMatch3Elements();
+ match.setSimilarity(absoluteMetric(nextLeftMatch.getLeftElement(),
correspondingMatch
+ .getLeftElement(), correspondingMatch.getRightElement()));
+ match.setLeftElement(nextLeftMatch.getLeftElement());
+ match.setRightElement(correspondingMatch.getLeftElement());
+ match.setOriginElement(correspondingMatch.getRightElement());
+ redirectedAdd(matchElementRoot, SUBMATCH_ELEMENT_NAME, match);
+ createSub3Match(root, matchElementRoot, nextLeftMatch, correspondingMatch);
+ leftNotFound.remove(nextLeftMatch);
+ rightNotFound.remove(correspondingMatch);
+ }
+ }
+
+ for (MatchElement nextLeftNotFound : leftNotFound) {
+ stillToFindFromModel1.add(nextLeftNotFound);
+ }
+ for (MatchElement nextRightNotFound : rightNotFound) {
+ stillToFindFromModel2.add(nextRightNotFound);
+ }
+ }
+
+ /**
+ * Creates the {@link Match2Elements submatch elements} corresponding to the mapping of
objects from the
+ * two given {@link List}s.
+ *
+ * @param root
+ * Root of the {@link MatchModel} where to insert all these mappings.
+ * @param list1
+ * First of the lists used to compute mapping.
+ * @param list2
+ * Second of the lists used to compute mapping.
+ * @param monitor
+ * {@link CompareProgressMonitor progress monitor} to display while the
comparison lasts. Might
+ * be <code>null</code>, in which case we won't monitor
progress.
+ * @throws FactoryException
+ * Thrown if we cannot match the elements of the two lists or add submatch
elements to
+ * <code>root</code>.
+ * @throws InterruptedException
+ * Thrown if the operation is cancelled or fails somehow.
+ */
+ private void createSubMatchElements(EObject root, List<EObject> list1,
List<EObject> list2,
+ Monitor monitor) throws FactoryException, InterruptedException {
+ stillToFindFromModel1.clear();
+ stillToFindFromModel2.clear();
+ final List<Match2Elements> mappings = mapLists(list1, list2, this
+ .<Integer> getOption(MatchOptions.OPTION_SEARCH_WINDOW), monitor);
+
+ final Iterator<Match2Elements> it = mappings.iterator();
+ while (it.hasNext()) {
+ final Match2Elements map = it.next();
+ final Match2Elements match = recursiveMappings(map.getLeftElement(),
map.getRightElement(),
+ monitor);
+ redirectedAdd(root, SUBMATCH_ELEMENT_NAME, match);
+ }
+ }
+
+ /**
+ * Creates {@link UnmatchElement}s and {@link RemoteUnmatchElement}s wrapped around all
the elements of
+ * the given {@link List}.
+ *
+ * @param root
+ * Root of the {@link MatchModel} under which to insert all these elements.
+ * @param unMatchedElements
+ * {@link List} containing all the elements we haven't been able to
match.
+ * @throws FactoryException
+ * Thrown if we cannot add elements under the given {@link MatchModel
root}.
+ */
+ private void createThreeWayUnmatchElements(MatchModel root, Map<EObject, Boolean>
unMatchedElements)
+ throws FactoryException {
+ for (EObject element : unMatchedElements.keySet()) {
+ // We will only consider the highest level of an unmatched element
+ // hierarchy
+ if (!unMatchedElements.containsKey(element.eContainer())) {
+ final UnmatchElement unMap;
+ if (unMatchedElements.get(element)) {
+ unMap = MatchFactory.eINSTANCE.createUnmatchElement();
+ unMap.setRemote(true);
+ }
+ else
+ unMap = MatchFactory.eINSTANCE.createUnmatchElement();
+ unMap.setElement(element);
+ redirectedAdd(root, UNMATCH_ELEMENT_NAME, unMap);
+ }
+ }
+ unMatchedElements.clear();
+ }
+
+ /**
+ * Creates {@link UnmatchElement}s wrapped around all the elements of the given {@link
List}.
+ *
+ * @param root
+ * Root of the {@link MatchModel} under which to insert all these {@link
UnmatchElement}s.
+ * @param unMatchedElements
+ * {@link Set} containing all the elements we haven't been able to
match.
+ * @throws FactoryException
+ * Thrown if we cannot add elements under the given {@link MatchModel
root}.
+ */
+ private void createUnmatchElements(MatchModel root, Set<EObject>
unMatchedElements, Side side)
+ throws FactoryException {
+ for (EObject element : unMatchedElements) {
+ final UnmatchElement unMap = MatchFactory.eINSTANCE.createUnmatchElement();
+ unMap.setElement(element);
+ if (side != null)
+ unMap.setSide(side);
+ redirectedAdd(root, UNMATCH_ELEMENT_NAME, unMap);
+ }
+ unMatchedElements.clear();
+ }
+
+ /**
+ * This method handles the creation and returning of a two way model match.
+ *
+ * @param leftResource
+ * Left model for the comparison.
+ * @param rightResource
+ * Right model for the comparison.
+ * @param monitor
+ * Progress monitor to display while the comparison lasts.
+ * @return The corresponding {@link MatchModel}.
+ * @throws InterruptedException
+ * Thrown if the comparison is interrupted somehow.
+ */
+ private MatchModel doMatch(Resource leftResource, Resource rightResource, Monitor
monitor)
+ throws InterruptedException {
+ final MatchModel root = MatchFactory.eINSTANCE.createMatchModel();
+ setModelRoots(root, leftResource, rightResource);
+
+ // filters unused features
+ filterUnused(leftResource);
+ filterUnused(rightResource);
+
+ // navigate through both models at the same time and realize mappings..
+ try {
+ if (!this.<Boolean> getOption(MatchOptions.OPTION_IGNORE_XMI_ID))
+ if (leftResource instanceof XMIResource && rightResource instanceof
XMIResource)
+ matchByXMIID((XMIResource)leftResource, (XMIResource)rightResource);
+ if (!this.<Boolean> getOption(MatchOptions.OPTION_IGNORE_ID))
+ matchByID(leftResource, rightResource);
+
+ monitor.subTask("Matching roots"); //$NON-NLS-1$
+ final List<Match2Elements> matchedRoots = mapLists(leftResource.getContents(),
rightResource
+ .getContents(), this.<Integer> getOption(MatchOptions.OPTION_SEARCH_WINDOW),
monitor);
+ stillToFindFromModel1.clear();
+ stillToFindFromModel2.clear();
+ final List<EObject> unMatchedLeftRoots = new
ArrayList<EObject>(leftResource.getContents());
+ final List<EObject> unMatchedRightRoots = new
ArrayList<EObject>(rightResource.getContents());
+ // These sets will help us in keeping track of the yet to be found
+ // elements
+ final Set<EObject> still1 = new HashSet<EObject>();
+ final Set<EObject> still2 = new HashSet<EObject>();
+
+ // If one of the resources has no roots, considers it as deleted
+ if (leftResource.getContents().size() > 0 &&
rightResource.getContents().size() > 0) {
+ Match2Elements matchModelRoot = MatchFactory.eINSTANCE.createMatch2Elements();
+ // We haven't found any similar roots, we then consider the
+ // firsts to be similar.
+ if (matchedRoots.size() == 0) {
+ final Match2Elements rootMapping = MatchFactory.eINSTANCE.createMatch2Elements();
+ rootMapping.setLeftElement(leftResource.getContents().get(0));
+ EObject rightElement = findMostSimilar(leftResource.getContents().get(0),
+ unMatchedRightRoots);
+ if (rightElement == null)
+ rightElement = unMatchedRightRoots.get(0);
+ rootMapping.setRightElement(rightElement);
+ matchedRoots.add(rootMapping);
+ }
+ monitor.subTask("Processing matched roots' contents"); //$NON-NLS-1$
+ for (Match2Elements matchedRoot : matchedRoots) {
+
+ List<EObject> rightContentsWithChildren =
getContentsWithChildren(matchedRoot.getRightElement());
+ final Match2Elements rootMapping =
myRecursiveMappings(matchedRoot.getLeftElement(),
+ matchedRoot.getRightElement(), rightContentsWithChildren, monitor);
+ stillToFindFromModel2.addAll(rightContentsWithChildren);
+// final Match2Elements rootMapping =
recursiveMappings(matchedRoot.getLeftElement(),
+// matchedRoot.getRightElement(), monitor);
+ // this is the first passage
+ if (matchModelRoot.getLeftElement() == null) {
+ matchModelRoot = rootMapping;
+ redirectedAdd(root, MATCH_ELEMENT_NAME, matchModelRoot);
+ } else {
+ redirectedAdd(matchModelRoot, SUBMATCH_ELEMENT_NAME, rootMapping);
+ }
+
+ // Synchronizes the two lists to avoid multiple elements
+ still1.removeAll(stillToFindFromModel1);
+ still2.removeAll(stillToFindFromModel2);
+ // checks for matches within the yet to found elements lists
+ createSubMatchElements(rootMapping, new
ArrayList<EObject>(stillToFindFromModel1),
+ new ArrayList<EObject>(stillToFindFromModel2), monitor);
+ // Adds all unfound elements to the sets
+ still1.addAll(stillToFindFromModel1);
+ still2.addAll(stillToFindFromModel2);
+
+ unMatchedLeftRoots.remove(matchedRoot.getLeftElement());
+ unMatchedRightRoots.remove(matchedRoot.getRightElement());
+ }
+ // We'll iterate through the unMatchedRoots all contents
+ monitor.subTask("Processing unmatched roots"); //$NON-NLS-1$
+ createSubMatchElements(matchModelRoot, unMatchedLeftRoots, unMatchedRightRoots,
monitor);
+ } else {
+ // Roots are unmatched, this is either a file addition or
+ // deletion
+ still1.addAll(unMatchedLeftRoots);
+ still2.addAll(unMatchedRightRoots);
+ }
+
+ // Now takes care of remaining unfound elements
+ still1.addAll(stillToFindFromModel1);
+ still2.addAll(stillToFindFromModel2);
+ createUnmatchElements(root, still1, Side.LEFT);
+ createUnmatchElements(root, still2, Side.RIGHT);
+ } catch (FactoryException e) {
+ EMFComparePlugin.log(e, false);
+ }
+ return root;
+ }
+
+ /**
+ * This method handles the creation and returning of a three way model match.
+ *
+ * @param leftResource
+ * Left model for the comparison.
+ * @param rightResource
+ * Right model for the comparison.
+ * @param ancestorResource
+ * Common ancestor of the right and left models.
+ * @param monitor
+ * Progress monitor to display while the comparison lasts.
+ * @return The corresponding {@link MatchModel}.
+ * @throws InterruptedException
+ * Thrown if the comparison is interrupted somehow.
+ */
+ private MatchModel doMatch(Resource leftResource, Resource rightResource, Resource
ancestorResource,
+ Monitor monitor) throws InterruptedException {
+ final MatchModel root = MatchFactory.eINSTANCE.createMatchModel();
+ setModelRoots(root, leftResource, rightResource, ancestorResource);
+ final MatchModel root1AncestorMatch = doMatch(leftResource, ancestorResource,
monitor);
+ final MatchModel root2AncestorMatch = doMatch(rightResource, ancestorResource,
monitor);
+
+ final List<MatchElement> root1MatchedElements = new
ArrayList<MatchElement>(root1AncestorMatch
+ .getMatchedElements());
+ final List<MatchElement> root2MatchedElements = new
ArrayList<MatchElement>(root2AncestorMatch
+ .getMatchedElements());
+
+ // populates the unmatched elements list for later use
+ for (Object unMatch : root1AncestorMatch.getUnmatchedElements())
+ remainingUnMatchedElements.add(((UnmatchElement)unMatch).getElement());
+ for (Object unMatch : root2AncestorMatch.getUnmatchedElements())
+ remainingUnMatchedElements.add(((UnmatchElement)unMatch).getElement());
+
+ try {
+ final Match3Elements subMatchRoot = MatchFactory.eINSTANCE.createMatch3Elements();
+ if (root2MatchedElements.size() > 0) {
+ final Match2Elements root1Match = (Match2Elements)root1MatchedElements.get(0);
+ final Match2Elements root2Match = (Match2Elements)root2MatchedElements.get(0);
+
+ subMatchRoot.setSimilarity(absoluteMetric(root1Match.getLeftElement(), root2Match
+ .getLeftElement(), root2Match.getRightElement()));
+ subMatchRoot.setLeftElement(root1Match.getLeftElement());
+ subMatchRoot.setRightElement(root2Match.getLeftElement());
+ subMatchRoot.setOriginElement(root2Match.getRightElement());
+ redirectedAdd(root, MATCH_ELEMENT_NAME, subMatchRoot);
+ createSub3Match(root, subMatchRoot, root1Match, root2Match);
+ } else if (root1MatchedElements.size() > 0) {
+ stillToFindFromModel1.add(root1MatchedElements.get(0));
+ }
+
+ // We will now check through the unmatched object for matches. This
+ // will allow for a more accurate detection
+ // for models with multiple roots.
+ processUnmatchedElements(root, subMatchRoot);
+
+ // #processUnmatchedElements(MatchModel, Match3Element)
+ // will have updated "remainingUnMatchedElements"
+ final Set<EObject> remainingLeft = new HashSet<EObject>();
+ final Set<EObject> remainingRight = new HashSet<EObject>();
+ for (EObject unMatched : remainingUnMatchedElements) {
+ if (unMatched.eResource() == leftResource) {
+ remainingLeft.add(unMatched);
+ final TreeIterator<EObject> iterator = unMatched.eAllContents();
+ while (iterator.hasNext())
+ remainingLeft.add(iterator.next());
+ } else if (unMatched.eResource() == rightResource) {
+ remainingRight.add(unMatched);
+ final TreeIterator<EObject> iterator = unMatched.eAllContents();
+ while (iterator.hasNext())
+ remainingRight.add(iterator.next());
+ }
+ }
+ stillToFindFromModel1.clear();
+ stillToFindFromModel2.clear();
+ final List<Match2Elements> mappings = mapLists(new
ArrayList<EObject>(remainingLeft),
+ new ArrayList<EObject>(remainingRight), this
+ .<Integer> getOption(MatchOptions.OPTION_SEARCH_WINDOW), monitor);
+ for (Match2Elements map : mappings) {
+ final Match3Elements subMatch = MatchFactory.eINSTANCE.createMatch3Elements();
+ subMatch.setLeftElement(map.getLeftElement());
+ subMatch.setRightElement(map.getRightElement());
+ redirectedAdd(subMatchRoot, SUBMATCH_ELEMENT_NAME, subMatch);
+ }
+ final Map<EObject, Boolean> unMatchedElements = new EMFCompareMap<EObject,
Boolean>();
+ for (EObject remoteUnMatch : stillToFindFromModel1) {
+ unMatchedElements.put(remoteUnMatch, true);
+ }
+ for (EObject unMatch : stillToFindFromModel2) {
+ unMatchedElements.put(unMatch, false);
+ }
+ createThreeWayUnmatchElements(root, unMatchedElements);
+ } catch (FactoryException e) {
+ EMFComparePlugin.log(e, false);
+ }
+
+ return root;
+ }
+
+ /**
+ * Filters unused features of the resource.
+ *
+ * @param resource
+ * Resource to be apply filter on.
+ */
+ private void filterUnused(Resource resource) {
+ for (EObject root : resource.getContents())
+ filter.analyseModel(root);
+ }
+
+ /**
+ * Workaround for bug #235606 : elements held by a reference with containment=true and
derived=true are
+ * not matched since not returned by {@link EObject#eContents()}. This allows us to
return the list of all
+ * contents from an EObject <u>including</u> those references.
+ *
+ * @param eObject
+ * The EObject we seek the content of.
+ * @return The list of all the content of a given EObject, derived containmnent
references included.
+ */
+ @SuppressWarnings("unchecked")
+ private List<EObject> getContents(EObject eObject) {
+ // TODO can this be cached (Map<EClass, List<EReference>>)?
+ final List<EObject> result = new ArrayList(eObject.eContents());
+ for (EReference reference : eObject.eClass().getEAllReferences()) {
+ if (reference.isContainment() && reference.isDerived()) {
+ final Object value = eObject.eGet(reference);
+ if (value instanceof Collection)
+ result.addAll((Collection)value);
+ else if (value instanceof EObject)
+ result.add((EObject)value);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns whether we should assume the metamodels of the compared models are distinct.
+ *
+ * @return <code>true</code> if the metamodels are to be assumed distinct,
<code>false</code>
+ * otherwise.
+ */
+ private boolean getPreferenceDistinctMetaModel() {
+ if (EMFPlugin.IS_ECLIPSE_RUNNING && EMFComparePlugin.getDefault() != null)
+ return EMFComparePlugin.getDefault().getBoolean(
+ EMFComparePreferenceConstants.PREFERENCES_KEY_DISTINCT_METAMODEL);
+ return MatchOptions.DEFAULT_DISTINCT_METAMODEL;
+ }
+
+ /**
+ * Returns whether we should ignore the IDs or compare using them.
+ *
+ * @return <code>True</code> if we should ignore ID,
<code>False</code> otherwise.
+ */
+ private boolean getPreferenceIgnoreID() {
+ if (EMFPlugin.IS_ECLIPSE_RUNNING && EMFComparePlugin.getDefault() != null)
+ return EMFComparePlugin.getDefault().getBoolean(
+ EMFComparePreferenceConstants.PREFERENCES_KEY_IGNORE_ID);
+ return MatchOptions.DEFAULT_IGNORE_ID;
+ }
+
+ /**
+ * Returns whether we should ignore the XMI IDs or compare with them.
+ *
+ * @return <code>True</code> if we should ignore XMI ID,
<code>False</code> otherwise.
+ */
+ private boolean getPreferenceIgnoreXMIID() {
+ if (EMFPlugin.IS_ECLIPSE_RUNNING && EMFComparePlugin.getDefault() != null)
+ return EMFComparePlugin.getDefault().getBoolean(
+ EMFComparePreferenceConstants.PREFERENCES_KEY_IGNORE_XMIID);
+ return MatchOptions.DEFAULT_IGNORE_XMI_ID;
+ }
+
+ /**
+ * Returns the search window corresponding to the number of siblings to consider while
matching. Reducing
+ * this number (on the preferences page) considerably improve performances while
reducing precision.
+ *
+ * @return An <code>int</code> representing the number of siblings to
consider for matching.
+ */
+ private int getPreferenceSearchWindow() {
+ int searchWindow = MatchOptions.DEFAULT_SEARCH_WINDOW;
+ if (EMFPlugin.IS_ECLIPSE_RUNNING
+ && EMFComparePlugin.getDefault() != null
+ && EMFComparePlugin.getDefault().getInt(
+ EMFComparePreferenceConstants.PREFERENCES_KEY_SEARCH_WINDOW) > 0)
+ searchWindow = EMFComparePlugin.getDefault().getInt(
+ EMFComparePreferenceConstants.PREFERENCES_KEY_SEARCH_WINDOW);
+ if (searchWindow < 0)
+ searchWindow = 0;
+ return searchWindow;
+ }
+
+ /**
+ * Returns the given similarity between the two given {@link EObject}s as it is stored
in cache.<br/>
+ * <p>
+ * <code>similarityKind</code> must be one of
+ * <ul>
+ * <li>{@link #NAME_SIMILARITY}</li>
+ * <li>{@link #TYPE_SIMILARITY}</li>
+ * <li>{@link #VALUE_SIMILARITY}</li>
+ * <li>{@link #RELATION_SIMILARITY}</li>
+ * </ul>
+ * </p>
+ *
+ * @param obj1
+ * First of the two {@link EObject}s we seek the similarity for.
+ * @param obj2
+ * Second of the two {@link EObject}s we seek the similarity for.
+ * @param similarityKind
+ * Kind of similarity to get.
+ * @return The similarity as described by <code>similarityKind</code> as it
is stored in cache for the
+ * two given {@link EObject}s.
+ */
+ private Double getSimilarityFromCache(EObject obj1, EObject obj2, char similarityKind)
{
+ return metricsCache.get(pairHashCode(obj1, obj2, similarityKind));
+ }
+
+ /**
+ * Checks wether the two given {@link EObject} have the same URI.
+ *
+ * @param obj1
+ * First of the two {@link EObject} we're comparing.
+ * @param obj2
+ * Second {@link EObject} we're comparing.
+ * @return <code>True</code> if the {@link EObject}s have the same URI,
<code>False</code> otherwise.
+ */
+ private boolean hasSameUri(EObject obj1, EObject obj2) {
+ if (obj1.eResource() != null && obj2.eResource() != null)
+ return
obj1.eResource().getURIFragment(obj1).equals(obj2.eResource().getURIFragment(obj2));
+ return false;
+ }
+
+ /**
+ * This replaces the contents of the defaults options map with the options overridden by
the given map.
+ *
+ * @param map
+ * Map containing the option given to the match procedure. cannot be
<code>null</code>.
+ */
+ private void loadOptionMap(Map<String, Object> map) {
+ options.putAll(map);
+ if (this.<Integer> getOption(MatchOptions.OPTION_SEARCH_WINDOW) < 0)
+ options.put(MatchOptions.OPTION_SEARCH_WINDOW, getPreferenceSearchWindow());
+ }
+
+ /**
+ * Returns a list containing mappings of the nodes of both given {@link List}s.
+ *
+ * @param list1
+ * First of the lists from which we need to map the elements
+ * @param list2
+ * Second list to map the elements from.
+ * @param window
+ * Number of siblings to consider for the matching.
+ * @param monitor
+ * {@link CompareProgressMonitor Progress monitor} to display while the
comparison lasts. Might
+ * be <code>null</code>, in which case we won't monitor
progress.
+ * @return A {@link List} containing mappings of the nodes of both given {@link List}s.
+ * @throws FactoryException
+ * Thrown if the metrics cannot be computed.
+ * @throws InterruptedException
+ * Thrown if the matching process is interrupted somehow.
+ */
+ private List<Match2Elements> mapLists(List<EObject> list1,
List<EObject> list2, int window,
+ Monitor monitor) throws FactoryException, InterruptedException {
+ final List<Match2Elements> result = new ArrayList<Match2Elements>();
+ int curIndex = 0 - window / 2;
+ final List<EObject> notFoundList1 = new ArrayList<EObject>(list1);
+ final List<EObject> notFoundList2 = new ArrayList<EObject>(list2);
+
+ final Iterator<EObject> it1 = list1.iterator();
+ // then iterate over the 2 lists and compare the elements
+ while (it1.hasNext() && notFoundList2.size() > 0) {
+ final EObject obj1 = it1.next();
+
+ final StringBuilder obj1Key = new StringBuilder();
+ obj1Key.append(NameSimilarity.findName(obj1));
+ obj1Key.append(obj1.hashCode());
+ EObject obj2 = matchedByID.get(obj1Key.toString());
+
+ if (obj2 == null) {
+ // subtracts the difference between the notfound and the
+ // original list to avoid ArrayOutOfBounds
+ final int end = Math.min(curIndex + window - (list2.size() - notFoundList2.size()),
+ notFoundList2.size());
+ final int index = Math
+ .min(Math.max(curIndex - (list2.size() - notFoundList2.size()), 0), end);
+
+ obj2 = findMostSimilar(obj1, notFoundList2.subList(index, end));
+ if (obj2 != null) {
+ // checks if the most similar to obj2 is obj1
+ final EObject obj1Check = findMostSimilar(obj2, notFoundList1);
+ if (obj1Check != obj1 && obj1Check != null && isSimilar(obj1Check,
obj2)) {
+ continue;
+ }
+ }
+ }
+
+ if (notFoundList1.contains(obj1) && notFoundList2.contains(obj2) &&
isSimilar(obj1, obj2)) {
+ final Match2Elements mapping = MatchFactory.eINSTANCE.createMatch2Elements();
+ final double metric = absoluteMetric(obj1, obj2);
+
+ mapping.setLeftElement(obj1);
+ mapping.setRightElement(obj2);
+ mapping.setSimilarity(metric);
+ result.add(mapping);
+ notFoundList2.remove(obj2);
+ notFoundList1.remove(obj1);
+ }
+ curIndex += 1;
+ monitor.worked(1);
+ if (monitor.isCanceled())
+ throw new InterruptedException();
+ }
+
+ // now putting the not found elements aside for later
+ stillToFindFromModel2.addAll(notFoundList2);
+ stillToFindFromModel1.addAll(notFoundList1);
+ return result;
+ }
+
+ /**
+ * Returns a list containing mappings of the nodes of both given {@link List}s.
+ *
+ * @param list1
+ * First of the lists from which we need to map the elements
+ * @param list2
+ * Second list to map the elements from.
+ * @param window
+ * Number of siblings to consider for the matching.
+ * @param monitor
+ * {@link CompareProgressMonitor Progress monitor} to display while the
comparison lasts. Might
+ * be <code>null</code>, in which case we won't monitor
progress.
+ * @return A {@link List} containing mappings of the nodes of both given {@link List}s.
+ * @throws FactoryException
+ * Thrown if the metrics cannot be computed.
+ * @throws InterruptedException
+ * Thrown if the matching process is interrupted somehow.
+ */
+ private List<Match2Elements> myMapLists(List<EObject> list1,
List<EObject> list2, int window,
+ Monitor monitor) throws FactoryException, InterruptedException {
+ final List<Match2Elements> result = new ArrayList<Match2Elements>();
+ int curIndex = 0 - window / 2;
+ final List<EObject> notFoundList1 = new ArrayList<EObject>(list1);
+ final List<EObject> notFoundList2 = new ArrayList<EObject>(list2);
+
+ final Iterator<EObject> it1 = list1.iterator();
+ // then iterate over the 2 lists and compare the elements
+ while (it1.hasNext() && notFoundList2.size() > 0) {
+ final EObject obj1 = it1.next();
+
+ final StringBuilder obj1Key = new StringBuilder();
+ obj1Key.append(NameSimilarity.findName(obj1));
+ obj1Key.append(obj1.hashCode());
+ EObject obj2 = matchedByID.get(obj1Key.toString());
+
+ if (obj2 == null) {
+ // subtracts the difference between the notfound and the
+ // original list to avoid ArrayOutOfBounds
+ final int end = Math.min(curIndex + window - (list2.size() - notFoundList2.size()),
+ notFoundList2.size());
+ final int index = Math
+ .min(Math.max(curIndex - (list2.size() - notFoundList2.size()), 0), end);
+
+ obj2 = findMostSimilar(obj1, notFoundList2.subList(index, end));
+ if (obj2 != null) {
+ // checks if the most similar to obj2 is obj1
+ final EObject obj1Check = findMostSimilar(obj2, notFoundList1);
+ if (obj1Check != obj1 && obj1Check != null && isSimilar(obj1Check,
obj2)) {
+ continue;
+ }
+ }
+ }
+
+ if (notFoundList1.contains(obj1) && notFoundList2.contains(obj2) &&
isSimilar(obj1, obj2)) {
+ final Match2Elements mapping = MatchFactory.eINSTANCE.createMatch2Elements();
+ final double metric = absoluteMetric(obj1, obj2);
+
+ mapping.setLeftElement(obj1);
+ mapping.setRightElement(obj2);
+ mapping.setSimilarity(metric);
+ result.add(mapping);
+ notFoundList2.remove(obj2);
+ notFoundList1.remove(obj1);
+ list2.remove(obj2);
+ }
+ curIndex += 1;
+ monitor.worked(1);
+ if (monitor.isCanceled())
+ throw new InterruptedException();
+ }
+
+ // now putting the not found elements aside for later
+// stillToFindFromModel2.addAll(notFoundList2);
+ stillToFindFromModel1.addAll(notFoundList1);
+ return result;
+ }
+
+
+ /**
+ * Iterates through both of the given EObjects to find all of their children that can be
matched by their
+ * functional ID, then populates {@link #matchedByID} with those mappings.
+ * <p>
+ * Note that this method will perform a check to ensure the two objects' resources
are indeed
+ * XMIResources.
+ * </p>
+ *
+ * @param obj1
+ * First of the two EObjects to visit.
+ * @param obj2
+ * Second of the EObjects to visit.
+ * @throws FactoryException
+ * Thrown if we couldn't compute a key to store the items in cache.
+ */
+ private void matchByID(EObject obj1, EObject obj2) throws FactoryException {
+ matchedByID.clear();
+ final Iterator<EObject> iterator1 = obj1.eAllContents();
+ while (iterator1.hasNext()) {
+ final EObject item1 = iterator1.next();
+ final String item1ID = EcoreUtil.getID(item1);
+ if (item1ID != null) {
+ final Iterator<EObject> iterator2 = obj2.eAllContents();
+ while (iterator2.hasNext()) {
+ final EObject item2 = iterator2.next();
+ final String item2ID = EcoreUtil.getID(item2);
+ if (item2 != null && item1ID.equals(item2ID)) {
+ final StringBuilder item1Key = new StringBuilder();
+ item1Key.append(NameSimilarity.findName(item1));
+ item1Key.append(item1.hashCode());
+ matchedByID.put(item1Key.toString(), item2);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Iterates through both of the given {@link XMIResource resources} to find all the
elements that can be
+ * matched by their XMI ID, then populates {@link #matchedByID} with those mappings.
+ *
+ * @param left
+ * First of the two {@link XMIResource resources} to visit.
+ * @param right
+ * Second of the {@link XMIResource resources} to visit.
+ * @throws FactoryException
+ * Thrown if we couldn't compute a key to store the items in cache.
+ */
+ private void matchByID(Resource left, Resource right) throws FactoryException {
+ matchedByID.clear();
+ final Iterator<EObject> leftIterator = left.getAllContents();
+ while (leftIterator.hasNext()) {
+ final EObject item1 = leftIterator.next();
+ final String item1ID = EcoreUtil.getID(item1);
+ if (item1ID != null) {
+ final Iterator<EObject> rightIterator = right.getAllContents();
+ while (rightIterator.hasNext()) {
+ final EObject item2 = rightIterator.next();
+ final String item2ID = EcoreUtil.getID(item2);
+ if (item2 != null && item1ID.equals(item2ID)) {
+ final StringBuilder item1Key = new StringBuilder();
+ item1Key.append(NameSimilarity.findName(item1));
+ item1Key.append(item1.hashCode());
+ matchedByID.put(item1Key.toString(), item2);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Iterates through both of the given EObjects to find all of their children that can be
matched by their
+ * XMI ID, then populates {@link #matchedByXMIID} with those mappings.
+ * <p>
+ * Note that this method will perform a check to ensure the two objects' resources
are indeed
+ * XMIResources.
+ * </p>
+ *
+ * @param obj1
+ * First of the two EObjects to visit.
+ * @param obj2
+ * Second of the EObjects to visit.
+ * @throws FactoryException
+ * Thrown if we couldn't compute a key to store the items in cache.
+ */
+ private void matchByXMIID(EObject obj1, EObject obj2) throws FactoryException {
+ matchedByXMIID.clear();
+ if (obj1 != null && obj2 != null && obj1.eResource() instanceof
XMIResource
+ && obj2.eResource() instanceof XMIResource) {
+ final XMIResource left = (XMIResource)obj1.eResource();
+ final XMIResource right = (XMIResource)obj2.eResource();
+ final Iterator<EObject> iterator = obj1.eAllContents();
+ while (iterator.hasNext()) {
+ final EObject item1 = iterator.next();
+ final String item1ID = left.getID(item1);
+ if (item1ID != null) {
+ final EObject item2 = right.getEObject(item1ID);
+ if (item2 != null) {
+ final StringBuilder item1Key = new StringBuilder();
+ item1Key.append(NameSimilarity.findName(item1));
+ item1Key.append(item1.hashCode());
+ matchedByXMIID.put(item1Key.toString(), item2);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Iterates through both of the given {@link XMIResource resources} to find all the
elements that can be
+ * matched by their XMI ID, then populates {@link #matchedByXMIID} with those mappings.
+ *
+ * @param left
+ * First of the two {@link XMIResource resources} to visit.
+ * @param right
+ * Second of the {@link XMIResource resources} to visit.
+ * @throws FactoryException
+ * Thrown if we couldn't compute a key to store the items in cache.
+ */
+ private void matchByXMIID(XMIResource left, XMIResource right) throws FactoryException
{
+ matchedByXMIID.clear();
+ final Iterator<EObject> leftIterator = left.getAllContents();
+
+ while (leftIterator.hasNext()) {
+ final EObject item1 = leftIterator.next();
+ final String item1ID = left.getID(item1);
+ if (item1ID != null) {
+ final EObject item2 = right.getEObject(item1ID);
+ if (item2 != null) {
+ final StringBuilder item1Key = new StringBuilder();
+ item1Key.append(NameSimilarity.findName(item1));
+ item1Key.append(item1.hashCode());
+ matchedByXMIID.put(item1Key.toString(), item2);
+ }
+ }
+ }
+ }
+
+ /**
+ * Counts all the {@link EStructuralFeature features} of the given {@link EObject} that
are
+ * <code>null</code> or initialized to the empty {@link String}
"".
+ *
+ * @param eobj
+ * {@link EObject} we need to count the empty features of.
+ * @return The number of features initialized to <code>null</code> or the
empty String.
+ */
+ private int nonNullFeaturesCount(EObject eobj) {
+ // TODO should probably cache result here
+ int nonNullFeatures = 0;
+ final Iterator<EStructuralFeature> features =
eobj.eClass().getEAllStructuralFeatures().iterator();
+ while (features.hasNext()) {
+ final EStructuralFeature feature = features.next();
+ if (eobj.eGet(feature) != null &&
!"".equals(eobj.eGet(feature).toString())) //$NON-NLS-1$
+ nonNullFeatures++;
+ }
+ return nonNullFeatures;
+ }
+
+ /**
+ * Computes an unique key between to {@link EObject}s to store their similarity in
cache.
+ * <p>
+ * <code>similarityKind</code> must be one of
+ * <ul>
+ * <li>{@link #NAME_SIMILARITY}</li>
+ * <li>{@link #TYPE_SIMILARITY}</li>
+ * <li>{@link #VALUE_SIMILARITY}</li>
+ * <li>{@link #RELATION_SIMILARITY}</li>
+ * </ul>
+ * </p>
+ *
+ * @param obj1
+ * First of the two {@link EObject}s.
+ * @param obj2
+ * Second of the two {@link EObject}s.
+ * @param similarityKind
+ * Kind of similarity this key will represent in cache.
+ * @return Unique key for the similarity cache.
+ */
+ private String pairHashCode(EObject obj1, EObject obj2, char similarityKind) {
+ if (similarityKind == NAME_SIMILARITY || similarityKind == TYPE_SIMILARITY
+ || similarityKind == VALUE_SIMILARITY || similarityKind == RELATION_SIMILARITY) {
+ final StringBuilder hash = new StringBuilder();
+ hash.append(similarityKind).append(obj1.hashCode()).append(obj2.hashCode());
+ return hash.toString();
+ }
+ throw new
IllegalArgumentException("DifferencesServices.illegalSimilarityKind");
//$NON-NLS-1$
+ }
+
+ /**
+ * Allows for a more accurate modifications detection for three way comparison with
multiple roots models.
+ *
+ * @param root
+ * Root of the {@link MatchModel}.
+ * @param subMatchRoot
+ * Root of the {@link Match3Element}s' hierarchy for the current element
to be created.
+ * @throws FactoryException
+ * Thrown if we cannot compute {@link EObject}s similarity or if adding
elements to either
+ * <code>root</code> or <code>subMatchRoot</code>
fails somehow.
+ */
+ private void processUnmatchedElements(MatchModel root, Match3Elements subMatchRoot)
+ throws FactoryException {
+ for (EObject obj1 : new ArrayList<EObject>(stillToFindFromModel1)) {
+ boolean matchFound = false;
+ if (obj1 instanceof Match2Elements) {
+ final Match2Elements match1 = (Match2Elements)obj1;
+ for (EObject obj2 : new ArrayList<EObject>(stillToFindFromModel2)) {
+ if (obj2 instanceof Match2Elements) {
+ final Match2Elements match2 = (Match2Elements)obj2;
+
+ if (match1.getRightElement() == match2.getRightElement()) {
+ matchFound = true;
+ final Match3Elements match = MatchFactory.eINSTANCE.createMatch3Elements();
+ match.setSimilarity(absoluteMetric(match1.getLeftElement(), match2
+ .getLeftElement(), match2.getRightElement()));
+ match.setLeftElement(match1.getLeftElement());
+ match.setRightElement(match2.getLeftElement());
+ match.setOriginElement(match2.getRightElement());
+ // This will happen if we couldn't match previously
+ if (subMatchRoot == null) {
+ redirectedAdd(root, MATCH_ELEMENT_NAME, match);
+ createSub3Match(root, match, match1, match2);
+ } else {
+ redirectedAdd(subMatchRoot, SUBMATCH_ELEMENT_NAME, match);
+ createSub3Match(root, subMatchRoot, match1, match2);
+ }
+ stillToFindFromModel1.remove(match1);
+ stillToFindFromModel2.remove(match2);
+ }
+ }
+ }
+ if (!matchFound) {
+ remainingUnMatchedElements.add(match1.getLeftElement());
+ }
+ }
+ }
+
+ for (EObject eObj : new ArrayList<EObject>(stillToFindFromModel1)) {
+ if (eObj instanceof Match2Elements) {
+ final Match2Elements nextLeftNotFound = (Match2Elements)eObj;
+ final UnmatchElement unMatch = MatchFactory.eINSTANCE.createUnmatchElement();
+ unMatch.setElement(nextLeftNotFound.getLeftElement());
+ remainingUnMatchedElements.remove(nextLeftNotFound.getLeftElement());
+ remainingUnMatchedElements.remove(nextLeftNotFound.getRightElement());
+ redirectedAdd(root, UNMATCH_ELEMENT_NAME, unMatch);
+ }
+ }
+ for (EObject eObj : new ArrayList<EObject>(stillToFindFromModel2)) {
+ if (eObj instanceof Match2Elements) {
+ final Match2Elements nextRightNotFound = (Match2Elements)eObj;
+ final UnmatchElement unMatch = MatchFactory.eINSTANCE.createUnmatchElement();
+ unMatch.setRemote(true);
+ unMatch.setElement(nextRightNotFound.getLeftElement());
+ remainingUnMatchedElements.remove(nextRightNotFound.getLeftElement());
+ remainingUnMatchedElements.remove(nextRightNotFound.getRightElement());
+ redirectedAdd(root, UNMATCH_ELEMENT_NAME, unMatch);
+ }
+ }
+ }
+
+
+ /**
+ * We consider here <code>current1</code> and
<code>current2</code> are similar. This method creates
+ * the mapping for the objects <code>current1</code> and
<code>current2</code>, Then submappings for
+ * these two elements' contents.
+ *
+ * @param current1
+ * First element of the two elements mapping.
+ * @param current2
+ * Second of the two elements mapping.
+ * @param monitor
+ * {@link CompareProgressMonitor Progress monitor} to display while the
comparison lasts. Might
+ * be <code>null</code>, in which case we won't monitor
progress.
+ * @return The mapping for <code>current1</code> and
<code>current2</code> and their content.
+ * @throws FactoryException
+ * Thrown when the metrics cannot be computed for
<code>current1</code> and
+ * <code>current2</code>.
+ * @throws InterruptedException
+ * Thrown if the matching process is interrupted somehow.
+ */
+ private Match2Elements recursiveMappings(EObject current1, EObject current2,
+ Monitor monitor) throws FactoryException, InterruptedException {
+ Match2Elements mapping = null;
+ mapping = MatchFactory.eINSTANCE.createMatch2Elements();
+ mapping.setLeftElement(current1);
+ mapping.setRightElement(current2);
+ mapping.setSimilarity(absoluteMetric(current1, current2));
+ final List<Match2Elements> mapList = mapLists(getContents(current1),
getContents(current2), this
+ .<Integer> getOption(MatchOptions.OPTION_SEARCH_WINDOW), monitor);
+ // We can map other elements with mapLists; we iterate through them.
+ final Iterator<Match2Elements> it = mapList.iterator();
+ while (it.hasNext()) {
+ final Match2Elements subMapping = it.next();
+ // As we know source and target are similars, we call recursive
+ // mappings onto these objects
+ EFactory.eAdd(mapping, SUBMATCH_ELEMENT_NAME,
recursiveMappings(subMapping.getLeftElement(),
+ subMapping.getRightElement(), monitor));
+ }
+ return mapping;
+ }
+
+
+ /**
+ * We consider here <code>current1</code> and
<code>current2</code> are similar. This method creates
+ * the mapping for the objects <code>current1</code> and
<code>current2</code>, Then submappings for
+ * these two elements' contents.
+ *
+ * @param current1
+ * First element of the two elements mapping.
+ * @param current2
+ * Second of the two elements mapping.
+ * @param monitor
+ * {@link CompareProgressMonitor Progress monitor} to display while the
comparison lasts. Might
+ * be <code>null</code>, in which case we won't monitor
progress.
+ * @return The mapping for <code>current1</code> and
<code>current2</code> and their content.
+ * @throws FactoryException
+ * Thrown when the metrics cannot be computed for
<code>current1</code> and
+ * <code>current2</code>.
+ * @throws InterruptedException
+ * Thrown if the matching process is interrupted somehow.
+ */
+ private Match2Elements myRecursiveMappings(EObject current1, EObject current2,
List<EObject> rightChildren,
+ Monitor monitor) throws FactoryException, InterruptedException {
+ Match2Elements mapping = null;
+ mapping = MatchFactory.eINSTANCE.createMatch2Elements();
+ mapping.setLeftElement(current1);
+ mapping.setRightElement(current2);
+ mapping.setSimilarity(absoluteMetric(current1, current2));
+ final List<Match2Elements> mapList = myMapLists(getContents(current1),
rightChildren, this
+ .<Integer> getOption(MatchOptions.OPTION_SEARCH_WINDOW), monitor);
+ // We can map other elements with mapLists; we iterate through them.
+ final Iterator<Match2Elements> it = mapList.iterator();
+ while (it.hasNext()) {
+ final Match2Elements subMapping = it.next();
+ // As we know source and target are similars, we call recursive
+ // mappings onto these objects
+ EFactory.eAdd(mapping, SUBMATCH_ELEMENT_NAME,
myRecursiveMappings(subMapping.getLeftElement(),
+ subMapping.getRightElement(), rightChildren, monitor));
+ }
+ return mapping;
+ }
+
+ private List<EObject> getContentsWithChildren(EObject eObject) {
+ List<EObject> result = new ArrayList<EObject>();
+ List<EObject> children = getContents(eObject);
+ result.addAll(children);
+ for (EObject child : children) {
+ result.addAll(getContentsWithChildren(child));
+ }
+ return result;
+ }
+
+ /**
+ * This method is an indirection for adding Mappings in the current MappingGroup.
+ *
+ * @param object
+ * {@link EObject} to add a feature value to.
+ * @param name
+ * Name of the feature to consider.
+ * @param value
+ * Value to add to the feature <code>name</code> of
<code>object</code>.
+ * @throws FactoryException
+ * Thrown if the value's affectation fails.
+ */
+ private void redirectedAdd(EObject object, String name, Object value) throws
FactoryException {
+ EFactory.eAdd(object, name, value);
+ }
+
+ /**
+ * This will compute the similarity between two {@link EObject}s' relations.
+ *
+ * @param obj1
+ * First of the two {@link EObject}s.
+ * @param obj2
+ * Second of the two {@link EObject}s.
+ * @return <code>double</code> representing the similarity between the two
{@link EObject}s' relations.
+ * 0 < value < 1.
+ * @throws FactoryException
+ * Thrown if we cannot compute the relations' similarity metrics.
+ * @see StructureSimilarity#relationsSimilarityMetric(EObject, EObject,
MetamodelFilter)
+ */
+ private double relationsSimilarity(EObject obj1, EObject obj2) throws FactoryException
{
+ double similarity = 0d;
+ final Double value = getSimilarityFromCache(obj1, obj2, RELATION_SIMILARITY);
+ if (value != null) {
+ similarity = value;
+ } else {
+ similarity = StructureSimilarity.relationsSimilarityMetric(obj1, obj2, filter);
+ setSimilarityInCache(obj1, obj2, RELATION_SIMILARITY, similarity);
+ }
+ return similarity;
+ }
+
+ /**
+ * Sets the values of the {@link MatchModel}'s left and right models.
+ *
+ * @param modelRoot
+ * Root of the {@link MatchModel}.
+ * @param left
+ * Element from which to resolve the left model URI.
+ * @param right
+ * Element from which to resolve the right model URI.
+ */
+ private void setModelRoots(MatchModel modelRoot, Resource left, Resource right) {
+ setModelRoots(modelRoot, left, right, null);
+ }
+
+ /**
+ * Sets the values of the {@link MatchModel}'s left, right and ancestor models.
+ *
+ * @param modelRoot
+ * Root of the {@link MatchModel}.
+ * @param left
+ * Element from which to resolve the left model URI.
+ * @param right
+ * Element from which to resolve the right model URI.
+ * @param ancestor
+ * Element from which to resolve the ancestor model URI. Can be
<code>null</code>.
+ */
+ private void setModelRoots(MatchModel modelRoot, Resource left, Resource right, Resource
ancestor) {
+ // Sets values of left, right and ancestor model URIs
+ if (left != null) {
+ modelRoot.getLeftRoots().addAll(left.getContents());
+ }
+ if (right != null) {
+ modelRoot.getRightRoots().addAll(right.getContents());
+ }
+ if (ancestor != null) {
+ modelRoot.getAncestorRoots().addAll(ancestor.getContents());
+ }
+ }
+
+ /**
+ * Stores in cache the given similarity between the two given {@link
EObject}s.<br/>
+ * <p>
+ * <code>similarityKind</code> must be one of
+ * <ul>
+ * <li>{@link #NAME_SIMILARITY}</li>
+ * <li>{@link #TYPE_SIMILARITY}</li>
+ * <li>{@link #VALUE_SIMILARITY}</li>
+ * <li>{@link #RELATION_SIMILARITY}</li>
+ * </ul>
+ * </p>
+ *
+ * @param obj1
+ * First of the two {@link EObject}s we're setting the similarity for.
+ * @param obj2
+ * Second of the two {@link EObject}s we're setting the similarity for.
+ * @param similarityKind
+ * Kind of similarity to set.
+ * @param similarity
+ * Value of the similarity between the two {@link EObject}s.
+ */
+ private void setSimilarityInCache(EObject obj1, EObject obj2, char similarityKind,
double similarity) {
+ metricsCache.put(pairHashCode(obj1, obj2, similarityKind), new Double(similarity));
+ }
+
+ /**
+ * Starts the monitor for comparison progress. Externalized here to avoid multiple usage
of the Strings.
+ *
+ * @param monitor
+ * The monitor that need be started
+ * @param size
+ * Size of the monitor
+ */
+ private void startMonitor(Monitor monitor, int size) {
+ monitor.beginTask("Comparing model", size); //$NON-NLS-1$
+ monitor.subTask("Browsing model"); //$NON-NLS-1$
+ }
+
+ /**
+ * This will compute the similarity between two {@link EObject}s' types.
+ *
+ * @param obj1
+ * First of the two {@link EObject}s.
+ * @param obj2
+ * Second of the two {@link EObject}s.
+ * @return <code>double</code> representing the similarity between the two
{@link EObject}s' types. 0
+ * < value < 1.
+ * @throws FactoryException
+ * Thrown if we cannot compute the type similarity metrics.
+ * @see StructureSimilarity#typeSimilarityMetric(EObject, EObject)
+ */
+ private double typeSimilarity(EObject obj1, EObject obj2) throws FactoryException {
+ double similarity = 0d;
+ final Double value = getSimilarityFromCache(obj1, obj2, TYPE_SIMILARITY);
+ if (value != null) {
+ similarity = value;
+ } else {
+ similarity = StructureSimilarity.typeSimilarityMetric(obj1, obj2);
+ setSimilarityInCache(obj1, obj2, TYPE_SIMILARITY, similarity);
+ }
+ return similarity;
+ }
+
+ /**
+ * Creates the progress monitor that will be displayed to the user while the comparison
lasts.
+ *
+ * @return The progress monitor that will be displayed to the user while the comparison
lasts.
+ */
+ private Monitor createProgressMonitor() {
+ Monitor monitor = new BasicMonitor();
+ final Object delegateMonitor = getOption(MatchOptions.OPTION_PROGRESS_MONITOR);
+ if (delegateMonitor != null && EMFPlugin.IS_ECLIPSE_RUNNING) {
+ monitor = EclipseModelUtils.createProgressMonitor(delegateMonitor);
+ }
+ return monitor;
+ }
+}
Property changes on:
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/bpel/BPELMatchEngine.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added:
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/mergeviewer/GEFContentMergeViewer.java
===================================================================
---
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/mergeviewer/GEFContentMergeViewer.java
(rev 0)
+++
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/mergeviewer/GEFContentMergeViewer.java 2009-12-08
07:33:02 UTC (rev 19096)
@@ -0,0 +1,441 @@
+package org.eclipse.bpel.compare.ui.gef.mergeviewer;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.ResourceBundle;
+
+import org.eclipse.bpel.common.extension.model.ExtensionMap;
+import org.eclipse.bpel.common.extension.model.ExtensionmodelFactory;
+import org.eclipse.bpel.compare.ui.annotation.AnnotationsStore;
+import org.eclipse.bpel.compare.ui.gef.bpel.BPELCompareEditPartFactory;
+import org.eclipse.bpel.model.Activity;
+import org.eclipse.bpel.model.BPELFactory;
+import org.eclipse.bpel.ui.BPELUIPlugin;
+import org.eclipse.bpel.ui.IBPELUIConstants;
+import org.eclipse.compare.CompareConfiguration;
+import org.eclipse.compare.IStreamContentAccessor;
+import org.eclipse.compare.ITypedElement;
+import org.eclipse.compare.ResourceNode;
+import org.eclipse.compare.contentmergeviewer.ContentMergeViewer;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.compare.diff.metamodel.DiffElement;
+import org.eclipse.emf.compare.diff.metamodel.ModelElementChangeLeftTarget;
+import org.eclipse.emf.compare.diff.metamodel.ModelElementChangeRightTarget;
+import org.eclipse.emf.compare.diff.metamodel.MoveModelElement;
+import org.eclipse.emf.compare.diff.metamodel.UpdateAttribute;
+import org.eclipse.emf.compare.ui.AbstractCompareAction;
+import org.eclipse.emf.compare.util.ModelUtils;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.EditPartViewer;
+import org.eclipse.gef.editparts.ScalableFreeformRootEditPart;
+import org.eclipse.gef.editparts.ZoomManager;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.ToolBarManager;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * ContentMergeViewer to merge EMF models using GEF panes.
+ *
+ */
+public abstract class GEFContentMergeViewer extends ContentMergeViewer {
+
+ /** Name of the bundle resources property file. */
+ public static final String BUNDLE_NAME =
"org.eclipse.bpel.compare.ui.gef.mergeviewer.GEFContentMergeViewerResources";
//$NON-NLS-1$
+
+ /**
+ * these viewers should be initialized by subclass in {@link #createControls(Composite)
+ */
+ protected EditPartViewer viewerLeft;
+ protected EditPartViewer viewerRight;
+ protected EditPartViewer viewerAncestor;
+ protected Text txtMessage;
+ private final CompareConfiguration configuration;
+
+ private AbstractCompareAction copyDiffLeftToRight;
+
+ private AbstractCompareAction copyDiffRightToLeft;
+
+ /** Indicates that this is a three-way comparison. */
+ private boolean isThreeWay;
+
+ protected GEFContentMergeViewer(Composite parent, CompareConfiguration cc) {
+ super(SWT.NONE, null, cc);
+ configuration = cc;
+ buildControl(parent);
+ }
+
+
+ @Override
+ protected void copy(boolean leftToRight) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ protected byte[] getContents(boolean left) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ protected void handleResizeAncestor(int x, int y, int width, int height) {
+ if (viewerAncestor != null) {
+ if (width > 0) {
+ viewerAncestor.getControl().setVisible(true);
+ viewerAncestor.getControl().setBounds(x, y, width, height);
+ } else {
+ viewerAncestor.getControl().setVisible(false);
+ }
+ }
+ }
+
+ @Override
+ protected void handleResizeLeftRight(int x, int y, int leftWidth,
+ int centerWidth, int rightWidth, int height) {
+ final int txtMessegeHeight = 100;
+ viewerLeft.getControl().setBounds(x, y, leftWidth, height-txtMessegeHeight);
+ viewerRight.getControl().setBounds(x + leftWidth + centerWidth, y, rightWidth,
height-txtMessegeHeight);
+ if (viewerLeft.getRootEditPart() instanceof ScalableFreeformRootEditPart) {
+ ScalableFreeformRootEditPart rootEditPart = (ScalableFreeformRootEditPart)viewerLeft
+ .getRootEditPart();
+ rootEditPart.getZoomManager().setZoomAnimationStyle(ZoomManager.ANIMATE_NEVER);
+ rootEditPart.getZoomManager().setZoom(0.7);
+ }
+ if (viewerRight.getRootEditPart() instanceof ScalableFreeformRootEditPart) {
+ ScalableFreeformRootEditPart rootEditPart = (ScalableFreeformRootEditPart)viewerRight
+ .getRootEditPart();
+ rootEditPart.getZoomManager().setZoomAnimationStyle(ZoomManager.ANIMATE_NEVER);
+ rootEditPart.getZoomManager().setZoom(0.7);
+ }
+ txtMessage.setBounds(x, y + height - txtMessegeHeight + centerWidth,
+ leftWidth + centerWidth + rightWidth, txtMessegeHeight - centerWidth);
+ }
+
+ @SuppressWarnings("restriction")
+ @Override
+ protected void updateContent(Object ancestor, Object left, Object right) {
+ Resource resourceLeft = null;
+ Resource resourceRight = null;
+ Resource resourceAnc = null;
+ ResourceSetImpl resourceSet = new ResourceSetImpl();
+
+ String nameRight;
+ String nameLeft;
+ String nameAncestor;
+
+ if(left instanceof ResourceNode) {
+ nameLeft = URI.createPlatformResourceURI(
+ ((ResourceNode)left).getResource().getFullPath().toString(),
+ true).toString();
+ } else {
+ nameLeft = ((ITypedElement)left).getName();
+ }
+ if(right instanceof ResourceNode) {
+ nameRight = URI.createPlatformResourceURI(
+ ((ResourceNode)right).getResource().getFullPath().toString(),
+ true).toString();
+ } else {
+ nameRight = ((ITypedElement)right).getName();
+ }
+ if(ancestor instanceof ResourceNode) {
+ nameAncestor = URI.createPlatformResourceURI(
+ ((ResourceNode)right).getResource().getFullPath().toString(),
+ true).toString();
+ } else {
+ nameAncestor = ((ITypedElement)right).getName();
+ }
+
+ try {
+ resourceLeft = ModelUtils.load(((IStreamContentAccessor)left)
+ .getContents(), nameLeft, resourceSet).eResource();
+ loadAssociatedBPELEX(resourceSet, nameLeft);
+
+
+ resourceRight = ModelUtils.load(((IStreamContentAccessor)right)
+ .getContents(), nameRight, resourceSet).eResource();
+ loadAssociatedBPELEX(resourceSet, nameRight);
+
+ if (ancestor != null) {
+ resourceAnc = ModelUtils.load(((IStreamContentAccessor)ancestor)
+ .getContents(), nameAncestor, resourceSet).eResource();
+ }
+ } catch (IOException e1) {
+ // TODO Auto-generated catch block
+ e1.printStackTrace();
+ } catch (CoreException e1) {
+ // TODO Auto-generated catch block
+ e1.printStackTrace();
+ }
+
+ EObject modelLeft = (EObject) resourceLeft.getContents().get(0);
+ EObject modelRight = (EObject) resourceRight.getContents().get(0);
+ EObject modelAncestor = null;
+ if (resourceAnc != null) {
+ modelAncestor = (EObject) resourceAnc.getContents().get(0);
+ }
+
+ AnnotationsStore.getInstance().annotate(getCompareConfiguration(), modelLeft,
modelRight);
+ updateContent(modelAncestor, modelLeft, modelRight);
+ // TODO: attach listeners
+
+ }
+
+
+ private void loadAssociatedBPELEX(ResourceSetImpl resourceSet,
+ String bpelexName) throws IOException {
+ ExtensionMap extensionMap = null;
+ Resource extensionsResource = null;
+ org.eclipse.core.runtime.IPath extensionsPath = (new
org.eclipse.core.runtime.Path(bpelexName)).removeFileExtension().addFileExtension(IBPELUIConstants.EXTENSION_MODEL_EXTENSIONS);
+ URI extensionsUri = URI.createURI(extensionsPath.toString());
+ ModelUtils.load(extensionsUri, resourceSet);
+ //IFile extensionsFile =
ResourcesPlugin.getWorkspace().getRoot().getFile(extensionsPath);
+ try {
+ //extensionsResource = resourceSet.getResource(extensionsUri,
extensionsFile.exists());
+ extensionsResource = ModelUtils.load(extensionsUri, resourceSet).eResource();
+ if (extensionsResource != null) {
+ extensionMap = ExtensionmodelFactory.eINSTANCE.findExtensionMap(
+ IBPELUIConstants.MODEL_EXTENSIONS_NAMESPACE, extensionsResource.getContents());
+ }
+ } catch (Exception e) {
+ BPELUIPlugin.log(e);
+ }
+ if (extensionMap != null) extensionMap.initializeAdapter();
+
+
+ if (extensionMap == null) {
+ extensionMap =
ExtensionmodelFactory.eINSTANCE.createExtensionMap(IBPELUIConstants.MODEL_EXTENSIONS_NAMESPACE);
+ if (extensionsResource == null) {
+ extensionsResource = resourceSet.createResource(extensionsUri);
+ }
+ extensionsResource.getContents().clear();
+ extensionsResource.getContents().add(extensionMap);
+ }
+ }
+
+ @Override
+ protected void createControls(Composite composite) {
+ initializeViewers(composite);
+ txtMessage = new Text(composite, SWT.MULTI | SWT.READ_ONLY);
+ }
+
+
+ public void selectionChanged(EditPartViewer viewer) {
+ if (viewer.equals(viewerLeft)) {
+ selectPairEditPart(true);
+ } else if (viewer.equals(viewerRight)) {
+ selectPairEditPart(false);
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ @Override
+ protected void createToolItems(ToolBarManager tbm) {
+ /*// COPY DIFF LEFT TO RIGHT
+ if (getCompareConfiguration().isRightEditable()) {
+ copyDiffLeftToRight = new
AbstractCompareAction(ResourceBundle.getBundle(BUNDLE_NAME),
+ "action.CopyDiffLeftToRight.") { //$NON-NLS-1$
+ @Override
+ public void run() {
+// copyDiffLeftToRight();
+ }
+ };
+ final ActionContributionItem copyLeftToRightContribution = new
ActionContributionItem(
+ copyDiffLeftToRight);
+ copyLeftToRightContribution.setVisible(true);
+ tbm.appendToGroup("merge", copyLeftToRightContribution); //$NON-NLS-1$
+ }
+ // COPY DIFF RIGHT TO LEFT
+ if (getCompareConfiguration().isLeftEditable()) {
+ copyDiffRightToLeft = new
AbstractCompareAction(ResourceBundle.getBundle(BUNDLE_NAME),
+ "action.CopyDiffRightToLeft.") { //$NON-NLS-1$
+ @Override
+ public void run() {
+// copyDiffRightToLeft();
+ }
+ };
+ final ActionContributionItem copyRightToLeftContribution = new
ActionContributionItem(
+ copyDiffRightToLeft);
+ copyRightToLeftContribution.setVisible(true);
+ tbm.appendToGroup("merge", copyRightToLeftContribution); //$NON-NLS-1$
+ }*/
+ // NEXT DIFF
+ final Action nextDiff = new
AbstractCompareAction(ResourceBundle.getBundle(BUNDLE_NAME),
+ "action.NextDiff.") { //$NON-NLS-1$
+ @Override
+ public void run() {
+ navigate(true);
+ }
+ };
+ final ActionContributionItem nextDiffContribution = new
ActionContributionItem(nextDiff);
+ nextDiffContribution.setVisible(true);
+ tbm.appendToGroup("navigation", nextDiffContribution); //$NON-NLS-1$
+ // PREVIOUS DIFF
+ final Action previousDiff = new
AbstractCompareAction(ResourceBundle.getBundle(BUNDLE_NAME),
+ "action.PrevDiff.") { //$NON-NLS-1$
+ @Override
+ public void run() {
+ navigate(false);
+ }
+ };
+ final ActionContributionItem previousDiffContribution = new
ActionContributionItem(previousDiff);
+ previousDiffContribution.setVisible(true);
+ tbm.appendToGroup("navigation", previousDiffContribution); //$NON-NLS-1$
+ }
+
+ private void navigate(boolean next) {
+ EObject selectedModel = getSelectedModel(true);
+ DiffElement selectedAnnotation =
AnnotationsStore.getInstance().getAnnotation(selectedModel);
+ List<DiffElement> annotations =
AnnotationsStore.getInstance().annotations.get(getCompareConfiguration());
+ int curIndex = annotations.indexOf(selectedAnnotation);
+ if (next) {
+ // go to next
+ if (annotations.size() > curIndex + 1) {
+ DiffElement annotation = annotations.get(curIndex + 1);
+ navigateToDiff(annotation);
+ }
+ } else {
+ // go to previous
+ int prevIndex = curIndex - 1;
+ if (prevIndex >= 0 && prevIndex < annotations.size()) {
+ DiffElement annotation = annotations.get(prevIndex);
+ navigateToDiff(annotation);
+ }
+ }
+
+ }
+
+ private void navigateToDiff(DiffElement annotation) {
+ if (annotation != null) {
+ if (annotation instanceof ModelElementChangeRightTarget) {
+ EObject leftObject = ((ModelElementChangeRightTarget) annotation).getLeftParent();
+ while (!(leftObject instanceof Activity)) {
+ leftObject = leftObject.eContainer();
+ }
+ Activity leftParent = (Activity) leftObject;
+// viewerLeft.select(BPELCompareEditPartFactory.getEditPart(leftParent));
+ EObject rightObject = ((ModelElementChangeRightTarget)
annotation).getRightElement();
+ while (!(rightObject instanceof Activity)) {
+ rightObject = rightObject.eContainer();
+ }
+ Activity rightElement = (Activity) rightObject;
+ viewerRight.select(BPELCompareEditPartFactory.getEditPart(rightElement));
+ String leftParentName = leftParent.getName() != null ?
+ leftParent.getName() : leftParent.toString();
+ txtMessage.setText(rightElement.getName() + " has been added into " +
+ leftParentName);
+ } else if (annotation instanceof ModelElementChangeLeftTarget) {
+ EObject leftObject = ((ModelElementChangeLeftTarget) annotation).getLeftElement();
+ while (!(leftObject instanceof Activity)) {
+ leftObject = leftObject.eContainer();
+ }
+ Activity leftElement = (Activity) leftObject;
+ viewerLeft.select(BPELCompareEditPartFactory.getEditPart(leftElement));
+ EObject rightObject = ((ModelElementChangeLeftTarget) annotation).getRightParent();
+ while (!(rightObject instanceof Activity)) {
+ rightObject = rightObject.eContainer();
+ }
+ Activity rightParent = (Activity) rightObject;
+// viewerRight.select(BPELCompareEditPartFactory.getEditPart(rightParent));
+ String rightParentName = rightParent.getName() != null ?
+ rightParent.getName() : rightParent.toString();
+ txtMessage.setText(leftElement.getName() + " has been removed from " +
+ rightParentName);
+ }
+// EObject leftObject = ((RemoveModelElement) annotation).getLeftElement();
+// while (!(leftObject instanceof Activity)) {
+// leftObject = leftObject.eContainer();
+// }
+// Activity leftElement = (Activity) leftObject;
+// viewerLeft.select(BPELCompareEditPartFactory.getEditPart(leftElement));
+// EObject rightObject = ((RemoveModelElement) annotation).getRightParent();
+// while (!(rightObject instanceof Activity)) {
+// rightObject = rightObject.eContainer();
+// }
+// Activity rightParent = (Activity) rightObject;
+// viewerRight.select(BPELCompareEditPartFactory.getEditPart(rightParent));
+// String rightParentName = rightParent.getName() != null ?
+// rightParent.getName() : rightParent.toString();
+// txtMessage.setText(leftElement.getName() + " has been removed from " +
+// rightParentName);
+ else if (annotation instanceof MoveModelElement) {
+ EObject leftObject = ((MoveModelElement) annotation).getLeftElement();
+ while (!(leftObject instanceof Activity)) {
+ leftObject = leftObject.eContainer();
+ }
+ Activity leftElement = (Activity) leftObject;
+
+ EObject rightObject = ((MoveModelElement) annotation).getRightElement();
+ while (!(rightObject instanceof Activity)) {
+ rightObject = rightObject.eContainer();
+ }
+ Activity rightElement = (Activity) leftObject;
+
+// if (left) {
+ viewerRight.select(BPELCompareEditPartFactory.getEditPart(
+ rightElement));
+// } else {
+ viewerLeft.select(BPELCompareEditPartFactory.getEditPart(
+ leftElement));
+// }
+ Activity leftTarget = (Activity) leftElement.eContainer();
+ Activity rightTarget = (Activity) rightElement.eContainer();
+ String leftTargetName = leftTarget.getName() == null ?
+ leftTarget.toString() : leftTarget.getName();
+ String rightTargetName = rightTarget.getName() != null ?
+ rightTarget.getName() : rightTarget.toString();
+ txtMessage.setText(rightElement.getName() + " has been moved from " +
+ leftTargetName + " to " + rightTargetName);
+ } else if (annotation instanceof UpdateAttribute) {
+// if (left) {
+ viewerRight.select(BPELCompareEditPartFactory.getEditPart(
+ ((UpdateAttribute) annotation).getRightElement()));
+// } else {
+ viewerLeft.select(BPELCompareEditPartFactory.getEditPart(
+ ((UpdateAttribute) annotation).getLeftElement()));
+// }
+ txtMessage.setText(annotation.toString());
+ }
+ } else {
+ txtMessage.setText("");
+// if (left) {
+ viewerRight.deselectAll();
+// } else {
+ viewerLeft.deselectAll();
+// }
+ }
+ }
+
+ private EObject getSelectedModel(boolean left) {
+ List editParts;
+ if (left) {
+ editParts = viewerLeft.getSelectedEditParts();
+ } else {
+ editParts = viewerRight.getSelectedEditParts();
+ }
+ if (editParts.size() == 0) {
+ return null;
+ }
+ EditPart editPart = (EditPart) editParts.get(0);
+ return (EObject) editPart.getModel();
+ }
+
+ private void selectPairEditPart(boolean left) {
+ DiffElement annotation = AnnotationsStore.getInstance()
+ .getAnnotation(getSelectedModel(left));
+ navigateToDiff(annotation);
+ }
+
+ protected abstract void initializeViewers(Composite composite);
+
+ protected abstract void updateContent(EObject modelAncestor, EObject modelleft, EObject
right);
+
+}
Property changes on:
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/mergeviewer/GEFContentMergeViewer.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added:
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/mergeviewer/GEFContentMergeViewerResources.properties
===================================================================
---
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/mergeviewer/GEFContentMergeViewerResources.properties
(rev 0)
+++
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/mergeviewer/GEFContentMergeViewerResources.properties 2009-12-08
07:33:02 UTC (rev 19096)
@@ -0,0 +1,101 @@
+################################################################################
+# Copyright (c) 2006, 2009 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
+################################################################################
+# Resource strings for ModelContentMergeViewer.java
+title = Visualization of Structural Differences
+
+saveDialog.title = Save Resource
+saveDialog.message = Resource has been modified. Save changes?
+
+compareProgressTask.title = Computing Differences...
+
+tooComplexError.title = Error
+tooComplexError.format = Too many differences. Turn on the ''Ignore White
Space'' option or do a structure compare first.
+
+UI_SaveDeltaWizard_FileExtension = emfdiff
+
+#####################################################
+# Toolbar actions
+#####################################################
+
+action.CopyLeftToRight.label = Copy Left to Right
+action.CopyLeftToRight.tooltip = Copy All from Left to Right
+action.CopyLeftToRight.image = copy_r_co.gif
+
+action.CopyRightToLeft.label = Copy Right to Left
+action.CopyRightToLeft.tooltip = Copy All Non-Conflicting Changes from Right to Left
+action.CopyRightToLeft.image = copy_l_co.gif
+
+action.CopyDiffLeftToRight.label = Copy Current Change to Right
+action.CopyDiffLeftToRight.tooltip = Copy Current Change from Left to Right
+action.CopyDiffLeftToRight.image = copycont_r_co.gif
+
+action.CopyDiffRightToLeft.label = Copy Current Change to Left
+action.CopyDiffRightToLeft.tooltip = Copy Current Change from Right to Left
+action.CopyDiffRightToLeft.image = copycont_l_co.gif
+
+action.NextDiff.label = Next
+action.NextDiff.tooltip = Select Next Change
+action.NextDiff.image = next_nav.gif
+
+action.PrevDiff.label = Previous
+action.PrevDiff.tooltip = Select Previous Change
+action.PrevDiff.image = prev_nav.gif
+
+action.EnableAncestor.label = Enable Ancestor Pane
+action.EnableAncestor.tooltip.unchecked = Show Ancestor Pane
+action.EnableAncestor.tooltip.checked = Hide Ancestor Pane
+action.EnableAncestor.description.unchecked = Show Ancestor Pane
+action.EnableAncestor.description.checked = Hide Ancestor Pane
+action.EnableAncestor.image = ancestorpane_co.gif
+
+action.IgnoreAncestor.label = Ignore Ancestor
+action.IgnoreAncestor.tooltip.unchecked = Two-Way Compare (Ignore Ancestor)
+action.IgnoreAncestor.tooltip.checked = Three-Way Compare
+action.IgnoreAncestor.description.unchecked = Two-Way Compare (Ignore Ancestor)
+action.IgnoreAncestor.description.checked = Three-Way Compare
+action.IgnoreAncestor.image = twowaycompare_co.gif
+
+
+#####################################################
+# Context menu actions
+#####################################################
+
+action.undo.label = Undo@Ctrl+Z
+action.undo.tooltip = Undo Last Operation
+
+action.redo.label = Redo@Ctrl+Y
+action.redo.tooltip = Redo Last Operation
+
+action.cut.label = Cut@Ctrl+X
+action.cut.tooltip = Cut Text Selection to Clipboard
+
+action.copy.label = Copy@Ctrl+C
+action.copy.tooltip = Copy Text Selection to Clipboard
+
+action.paste.label = Paste@Ctrl+V
+action.paste.tooltip = Replace Text Selection with Clipboard Contents
+
+action.delete.label = Delete
+action.delete.tooltip = Delete Current Text Selection
+
+action.find.label = Find...@Ctrl+F
+action.find.tooltip = Find Occurrence
+
+action.selectAll.label = Select All@Ctrl+A
+action.selectAll.tooltip = Select All Changes
+
+action.export.menu.label = Export diff as...@Ctrl+E
+action.export.menu.tooltip = export DiffModel
+action.export.menu.image = save.gif
+
+action.export.emfdiff.label = As emfdiff@Ctrl+S
+action.export.emfdiff.tooltip = export as emfdiff
+action.export.emfdiff.image = save.gif
\ No newline at end of file
Property changes on:
trunk/bpel/plugins/org.eclipse.bpel.compare.ui/src/org/eclipse/bpel/compare/ui/gef/mergeviewer/GEFContentMergeViewerResources.properties
___________________________________________________________________
Name: svn:mime-type
+ text/plain