Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • develop
  • master
  • 3.4.0
  • 3.4.1
  • 3.5.0
  • 3.5.1
  • 3.6.0
7 results

Target

Select target project
  • general/stups/camille
1 result
Select Git revision
  • develop
  • master
  • 3.4.0
  • 3.4.1
  • 3.5.0
  • 3.5.1
  • 3.6.0
7 results
Show changes
Commits on Source (7)
Showing
with 25 additions and 1501 deletions
/**
* Copyright (c) 2010
* University of Southampton and others.
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the Eclipse Public License v1.0 which accompanies this
* distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
*
*
* $Id$
*/
package org.eventb.texttools.diff;
import org.eclipse.emf.compare.diff.engine.check.AttributesCheck;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.ENamedElement;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil.CrossReferencer;
import org.eventb.emf.core.CorePackage;
public class EventBAttributesCheck extends AttributesCheck {
public EventBAttributesCheck(CrossReferencer referencer) {
super(referencer);
}
/**
* Determines if we should ignore an attribute for diff detection.
* <p>
* We do not ignore transient nor derived attributes by default because often these are the user visible/editable attribute. We ignore the reference attribute since name is the
* changeable part. We also ignore the attributes of Annotations and their maps
* </p>
*
* FIXME: Make this extensible via an extension point so that extenders can decide what should be ignored.
*
* @param attribute
* Attribute to determine whether it should be ignored.
* @return <code>True</code> if attribute has to be ignored, <code>False</code> otherwise.
*/
@Override
protected boolean shouldBeIgnored(EAttribute attribute) {
boolean ignore = false;
EObject container = attribute.eContainer();
// remove default ignore transient and derived since some of these are our user visible attributes
// ignore = ignore || attribute.isTransient();
// ignore = ignore || attribute.isDerived();
//ignore contents of string 2 string map entries (e.g. in RodinInternalDetails)
// FIXME: make this more specific to RodinInternalDetails
ignore = ignore || (container instanceof ENamedElement && "StringToStringMapEntry".equals(((ENamedElement) container).getName()));
//ignore contents of Annotations
// FIXME: make this more specific to RodinInternalDetails
ignore = ignore || container.equals(CorePackage.eINSTANCE.getAnnotation());
//ignore reference (instead, the derived attribute 'name' will be shown)
ignore = ignore || attribute.equals(CorePackage.eINSTANCE.getEventBElement_Reference());
//ignore attributes of Abstract Extension
ignore = ignore || container.equals(CorePackage.eINSTANCE.getAbstractExtension());
return ignore;
}
}
/**
* Copyright (c) 2010
* University of Southampton and others.
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the Eclipse Public License v1.0 which accompanies this
* distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
*
*
* $Id$
*/
package org.eventb.texttools.diff;
import java.util.List;
import org.eclipse.emf.compare.diff.engine.GenericDiffEngine;
import org.eclipse.emf.compare.diff.metamodel.DiffElement;
import org.eclipse.emf.compare.diff.metamodel.DiffGroup;
import org.eclipse.emf.compare.match.metamodel.UnmatchElement;
public class EventBDiffEngine extends GenericDiffEngine {
/**
* Returns the Event-B implementation of a
* {@link org.eclipse.emf.compare.diff.engine.check.AbstractCheck}
* responsible for the verification of updates on attribute values.
*
* @return The Event-B implementation of a
* {@link org.eclipse.emf.compare.diff.engine.check.AbstractCheck}
* responsible for the verification of updates on attribute values.
* @since 1.0
*/
@Override
protected EventBAttributesCheck getAttributesChecker() {
return new EventBAttributesCheck(matchCrossReferencer);
}
/**
* Returns the Event-B implementation of a
* {@link org.eclipse.emf.compare.diff.engine.check.AbstractCheck}
* responsible for the verification of updates on reference values.
*
* @return The Event-B implementation of a
* {@link org.eclipse.emf.compare.diff.engine.check.AbstractCheck}
* responsible for the verification of updates on reference values.
* @since 1.0
*/
@Override
protected EventBReferencesCheck getReferencesChecker() {
return new EventBReferencesCheck(matchCrossReferencer);
}
/**
* This will process the {@link #unmatchedElements unmatched elements} list
* and create the appropriate {@link DiffElement}s.
* <p>
* This is called for two-way comparison.
* </p>
* <p>
* Filters any unmatched elements according to the references checker. Rodin
* internal detail Annotation and then defers to the generic diff engine.
* </p>
* <p>
* FIXME: Make this extensible via an extension point so that extenders can
* decide what should be ignored.
* </p>
*
* @param diffRoot
* {@link DiffGroup} under which to create the
* {@link DiffElement}s.
* @param unmatched
* The MatchModel's {@link UnmatchElement}s.
*/
@Override
protected void processUnmatchedElements(DiffGroup diffRoot,
List<UnmatchElement> unmatched) {
super.processUnmatchedElements(diffRoot, getReferencesChecker()
.filterUnmatchedElements(unmatched));
}
}
/**
* Copyright (c) 2010
* University of Southampton and others.
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the Eclipse Public License v1.0 which accompanies this
* distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
*
*
* $Id$
*/
package org.eventb.texttools.diff;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.compare.FactoryException;
import org.eclipse.emf.compare.diff.engine.check.ReferencesCheck;
import org.eclipse.emf.compare.diff.metamodel.DiffGroup;
import org.eclipse.emf.compare.diff.metamodel.ReferenceChangeLeftTarget;
import org.eclipse.emf.compare.diff.metamodel.ReferenceChangeRightTarget;
import org.eclipse.emf.compare.match.metamodel.Match2Elements;
import org.eclipse.emf.compare.match.metamodel.UnmatchElement;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.util.EcoreUtil.CrossReferencer;
import org.eventb.emf.core.CorePackage;
public class EventBReferencesCheck extends ReferencesCheck {
public EventBReferencesCheck(CrossReferencer referencer) {
super(referencer);
}
/**
* Determines if we should ignore a reference for diff detection.
* This method is intended to be used to filter matched changes.
* Containments are dealt with as new element additions so these are ignored.
* Everything else is deferred to shouldBeIgnoredAllowContainments().
*
* @param reference
* Reference to determine whether it should be ignored.
* @return <code>True</code> if reference has to be ignored, <code>False</code> otherwise.
*/
@Override
protected boolean shouldBeIgnored(EReference reference) {
return reference.isContainment() ? true : shouldBeIgnoredAllowContainment(reference);
}
/**
* Determines if we should ignore a reference for diff detection.
* This method is intended to be used to filter matched or unmatched changes.
* (unmatched elements are additions to Containments)
* are dealt with as new element additions so these are ignored.
* Everything else is deferred to shouldBeIgnoredAllowContainments().
*
* <p>
* Apart from containment which is dealt with elsewhere, we copy the default which is to ignore references marked either
* <ul>
* <li>Container</li>
* <li>Transient</li>
* <li>Derived</li>
* </ul>
* </p>
* <p>
* We also ignore the references, refines, sees and extends because any differences will be shown in the derived attributes 'names' lists. We also ignore the containment,
* annotations, because it is only used to hold transient tool information. We also ignore anything contained by EcorePackage.eINSTANCE.getEGenericType() or
* CorePackage.eINSTANCE.getAnnotation()
*
* </p>
*
* FIXME: Make this extensible via an extension point so that extenders can decide what should be ignored.
*
* @param reference
* Reference to determine whether it should be ignored.
* @return <code>True</code> if reference has to be ignored, <code>False</code> otherwise.
*/
protected boolean shouldBeIgnoredAllowContainment(EReference reference) {
boolean ignore = false;
ignore = ignore || reference.isDerived();
ignore = ignore || reference.isTransient();
ignore = ignore || reference.isContainer();
ignore = ignore || reference.eContainer().equals(EcorePackage.eINSTANCE.getEGenericType());
String name = reference.getName();
ignore = ignore || "refines".equals(name);
ignore = ignore || "sees".equals(name);
ignore = ignore || "extends".equals(name);
ignore = ignore || "annotations".equals(name);
ignore = ignore || "extensions".equals(name);
// ignore = ignore || "attributes".equals(name); //Cannot ignore generic attributes since camille timestamp is an attribute
ignore = ignore || reference.eContainer().equals(CorePackage.eINSTANCE.getAnnotation());
return ignore;
}
@Override
protected void checkReferenceOrderChange(DiffGroup root, EReference reference, EObject leftElement, EObject rightElement,
List<ReferenceChangeLeftTarget> addedReferences, List<ReferenceChangeRightTarget> removedReferences) throws FactoryException {
if (shouldBeIgnored(reference)) {
return;
}
super.checkReferenceOrderChange(root, reference, leftElement, rightElement, addedReferences, removedReferences);
}
@Override
protected void checkContainmentReferenceOrderChange(DiffGroup root, Match2Elements mapping, EReference reference) throws FactoryException {
if (shouldBeIgnoredAllowContainment(reference)) {
return;
}
super.checkContainmentReferenceOrderChange(root, mapping, reference);
}
/**
* The standard difference checkers take no account of shouldBeIgnored references for unmatched elements.
* This additional method can be used to filter out new elements (that will have no match) from the differences.
* It returns a new list of UnmatchElement without any elements that are contained in a reference that should Be Ignored (i.e.
* for which shouldBeIgnored(containingFeature) returns true.
*
* @param unmatched
* : List<UnmatchElement>
* @return List<UnmatchElement>
*/
public List<UnmatchElement> filterUnmatchedElements(List<UnmatchElement> unmatched) {
final List<UnmatchElement> filteredUnmatched = new ArrayList<UnmatchElement>(unmatched.size());
for (UnmatchElement element : unmatched) {
if (element.getElement().eContainmentFeature() == null || !shouldBeIgnoredAllowContainment(element.getElement().eContainmentFeature())) {
filteredUnmatched.add(element);
}
}
return filteredUnmatched;
}
/**
* The standard difference checkers take no account of shouldBeIgnored references for unmatched elements.
* This additional method can be used to filter out new elements (that will have no match) from the differences.
* It returns a new list of UnmatchElement without any elements that are contained in a reference that should Be Ignored (i.e.
* for which shouldBeIgnored(containingFeature) returns true.
*
* @param unmatched
* : Map<UnmatchElement, Boolean>
* @return Map<UnmatchElement, Boolean>
*/
public Map<UnmatchElement, Boolean> filterUnmatchedElements(Map<UnmatchElement, Boolean> unmatched) {
final Map<UnmatchElement, Boolean> filteredUnmatched = new HashMap<UnmatchElement, Boolean>(unmatched.size());
for (final Map.Entry<UnmatchElement, Boolean> element : unmatched.entrySet()) {
if (!shouldBeIgnoredAllowContainment(element.getKey().getElement().eContainmentFeature())) {
filteredUnmatched.put(element.getKey(), element.getValue());
}
}
return filteredUnmatched;
}
}
/**
* (c) 2009 Lehrstuhl fuer Softwaretechnik und Programmiersprachen,
* Heinrich Heine Universitaet Duesseldorf
* This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html)
* */
package org.eventb.texttools.merge;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.emf.compare.FactoryException;
import org.eclipse.emf.compare.match.MatchOptions;
import org.eclipse.emf.compare.match.engine.GenericMatchEngine;
import org.eclipse.emf.compare.match.engine.IMatchEngine;
import org.eclipse.emf.compare.match.engine.MatchSettings;
import org.eclipse.emf.compare.match.internal.statistic.NameSimilarity;
import org.eclipse.emf.ecore.EObject;
import org.eventb.emf.core.EventBNamed;
import org.eventb.emf.core.EventBNamedCommentedComponentElement;
import org.eventb.emf.core.EventBPredicate;
import org.eventb.emf.core.machine.Event;
import org.eventb.emf.core.machine.Variant;
/**
* A {@link IMatchEngine} which matches EventB emf models. The special structure
* of those models is taken into consideration to produce more exact match
* models.
*/
public class EventBMatchEngine extends GenericMatchEngine {
public static final String OPTION_DONT_COMPARE_COMPONENTS = "eventb.dont.compare.components";
private static final Map<String, Object> defaultOptions = new HashMap<String, Object>();
static {
defaultOptions.put(OPTION_DONT_COMPARE_COMPONENTS, false);
}
public EventBMatchEngine() {
// needed for Extension Point
}
public EventBMatchEngine(final Map<String, Object> options) {
this.options.putAll(options);
}
@Override
public boolean isSimilar(final EObject obj1, final EObject obj2)
throws FactoryException {
/*
* Test if we consider components as match by default
*/
final Boolean dontCompareComponents = getOption(OPTION_DONT_COMPARE_COMPONENTS);
if (dontCompareComponents && areSameComponentType(obj1, obj2)) {
return true;
}
/*
* Only one variant may exist in a model, so two variants are a match
*/
if (areVariants(obj1, obj2)) {
return true;
}
/*
* Our models are typed strictly, that means: different type => no match
*/
if (!areSameType(obj1, obj2)) {
return false;
}
/*
* Improve matching for events with same name
*/
if (obj1 instanceof Event) {
final double similarity = nameSimilarity(obj1, obj2);
if (similarity == 1) {
return true;
}
}
// otherwise use default comparison of GenericMatchEngine
return super.isSimilar(obj1, obj2);
}
@Override
protected double nameSimilarity(final EObject obj1, final EObject obj2) {
if (!areSameType(obj1, obj2)) {
return 0d;
}
return NameSimilarity
.nameSimilarityMetric(getName(obj1), getName(obj2));
}
@Override
protected double contentSimilarity(final EObject obj1, final EObject obj2)
throws FactoryException {
if (!areSameType(obj1, obj2)) {
return 0d;
}
double result = super.contentSimilarity(obj1, obj2);
if (obj1 instanceof EventBPredicate) {
// give predicate equality extra weight
result = (result + 2 * contentSimilarity((EventBPredicate) obj1,
(EventBPredicate) obj2)) / 3;
}
return result;
}
private double contentSimilarity(final EventBPredicate pred1,
final EventBPredicate pred2) {
return NameSimilarity.nameSimilarityMetric(pred1.getPredicate(),
pred2.getPredicate());
}
/*
* Overridden to set custom matching options. (non-Javadoc)
*
* @see
* org.eclipse.emf.compare.match.engine.GenericMatchEngine#updateSettings
* (org.eclipse.emf.compare.match.engine.MatchSettings, java.util.Map)
*/
@Override
protected void updateSettings(MatchSettings settings,
Map<String, Object> optionMap) {
super.updateSettings(settings, optionMap);
Map<String, Object> ignoreOptions = new HashMap<String, Object>();
// don't compare by IDs as these can be not unique in current EMF of
// EventB
// FIXME: this can be removed if EMF is fixed to support unique IDs
ignoreOptions.put(MatchOptions.OPTION_IGNORE_XMI_ID, true);
ignoreOptions.put(MatchOptions.OPTION_IGNORE_ID, true);
super.updateSettings(settings, ignoreOptions);
}
@SuppressWarnings("unchecked")
@Override
protected <T> T getOption(final String key) throws ClassCastException {
if (options.containsKey(key)) {
return (T) options.get(key);
} else {
return (T) defaultOptions.get(key);
}
}
private String getName(final EObject object) {
/*
* Make sure correct names for EventBNamed elements are used.
*/
if (object instanceof EventBNamed) {
return ((EventBNamed) object).getName();
}
// fallback to default
try {
return NameSimilarity.findName(object);
} catch (final FactoryException e) {
return null;
}
}
private boolean areSameType(final EObject obj1, final EObject obj2) {
return obj1 != null && obj2 != null
&& obj1.eClass().equals(obj2.eClass());
}
/**
* Test if both given {@link EObject}s are {@link EventBComponent}s and of
* same type of component, includes <code>null</code> check.
*
* @param obj1
* @param obj2
* @return
*/
private boolean areSameComponentType(final EObject obj1, final EObject obj2) {
return areSameType(obj1, obj2)
&& obj1 instanceof EventBNamedCommentedComponentElement;
}
/**
* Test if both given {@link EObject}s are of type {@link Variant}, includes
* <code>null</code> check.
*
* @param obj1
* @param obj2
* @return
*/
private boolean areVariants(final EObject obj1, final EObject obj2) {
return areSameType(obj1, obj2) && obj2 instanceof Variant;
}
}
package org.eventb.texttools.merge;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eventb.emf.core.EventBElement;
import org.eventb.emf.core.context.Context;
import org.eventb.emf.core.machine.Event;
import org.eventb.emf.core.machine.Machine;
public class MergeUtil {
private MergeUtil() {
throw new InstantiationError(
"MergeUtil is not meant to be instantiated.");
}
static void copyMachineRef(final Machine leftParent,
final Machine leftTarget, final Machine rightTarget) {
if (leftTarget != null && leftTarget.eIsProxy()) {
// simply rename in proxy
leftTarget.setName(rightTarget.getName());
} else {
replaceInList(leftParent.getRefines(), leftTarget, rightTarget);
}
}
static void copyEventRef(final Event leftParent, final Event leftTarget,
final Event rightTarget) {
if (leftTarget != null && leftTarget.eIsProxy()) {
// simply rename in proxy
leftTarget.setName(rightTarget.getName());
} else {
replaceInList(leftParent.getRefines(), leftTarget, rightTarget);
}
}
static void copyContextRef(final EObject leftParent,
final Context leftTarget, final Context rightTarget) {
if (leftTarget != null && leftTarget.eIsProxy()) {
// simply rename proxy
leftTarget.setName(rightTarget.getName());
} else {
if (leftParent instanceof Machine) {
// references is a sees in a machine
replaceInList(((Machine) leftParent).getSees(), leftTarget,
rightTarget);
} else if (leftParent instanceof Context) {
// references is a extends in context
replaceInList(((Context) leftParent).getExtends(), leftTarget,
rightTarget);
}
}
}
static <T extends EventBElement> void replaceInList(
final EList<T> refinesList, final T leftTarget, final T rightTarget) {
EObject newTarget = EcoreUtil.copy(rightTarget);
if (leftTarget != null) {
// search old position and replace
for (int i = 0; i < refinesList.size(); i++) {
if (refinesList.get(i) == leftTarget) {
refinesList.set(i, (T) newTarget);
break;
}
}
} else {
// just add reference
// TODO Do we need to care about the position?
refinesList.add((T) newTarget);
}
}
/**
* Makes rightTarget a child of element, potentially displacing rightTarget.
*
* @return true if a copy was performed
*/
static boolean rodinCopy(EObject element, EObject leftTarget,
EObject rightTarget) {
if (leftTarget instanceof Machine || rightTarget instanceof Machine) {
// only case: refines attribute of a machine
copyMachineRef((Machine) element, (Machine) leftTarget,
(Machine) rightTarget);
return true;
} else if (leftTarget instanceof Context
|| rightTarget instanceof Context) {
copyContextRef(element, (Context) leftTarget, (Context) rightTarget);
return true;
} else if (leftTarget instanceof Event || rightTarget instanceof Event) {
copyEventRef((Event) element, (Event) leftTarget,
(Event) rightTarget);
return true;
}
return false;
}
}
/**
* (c) 2009 Lehrstuhl fuer Softwaretechnik und Programmiersprachen,
* Heinrich Heine Universitaet Duesseldorf
* This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html)
* */
package org.eventb.texttools.merge;
import java.util.Map;
import org.eclipse.emf.compare.diff.merge.IMerger;
import org.eclipse.emf.compare.diff.merge.IMergerProvider;
import org.eclipse.emf.compare.diff.metamodel.DiffElement;
import org.eclipse.emf.compare.diff.metamodel.ModelElementChangeRightTarget;
import org.eclipse.emf.compare.diff.metamodel.ReferenceChangeLeftTarget;
import org.eclipse.emf.compare.diff.metamodel.ReferenceChangeRightTarget;
import org.eclipse.emf.compare.diff.metamodel.ReferenceOrderChange;
import org.eclipse.emf.compare.util.EMFCompareMap;
public class MergerProvider implements IMergerProvider {
private Map<Class<? extends DiffElement>, Class<? extends IMerger>> mergerTypes;
public Map<Class<? extends DiffElement>, Class<? extends IMerger>> getMergers() {
if (mergerTypes == null) {
mergerTypes = new EMFCompareMap<Class<? extends DiffElement>, Class<? extends IMerger>>();
mergerTypes.put(ReferenceChangeRightTarget.class,
ReferenceChangeRightTargetMerger.class);
mergerTypes.put(ReferenceChangeLeftTarget.class,
ReferenceChangeLeftTargetMerger.class);
mergerTypes.put(ModelElementChangeRightTarget.class,
ModelElementChangeRightTargetMerger.class);
mergerTypes.put(ReferenceOrderChange.class,
ReferenceOrderChangeMerger.class);
}
return mergerTypes;
}
}
package org.eventb.texttools.merge;
import java.util.Iterator;
import java.util.List;
import org.eclipse.emf.compare.EMFComparePlugin;
import org.eclipse.emf.compare.FactoryException;
import org.eclipse.emf.compare.diff.merge.DefaultMerger;
import org.eclipse.emf.compare.diff.metamodel.DiffElement;
import org.eclipse.emf.compare.diff.metamodel.ModelElementChangeRightTarget;
import org.eclipse.emf.compare.diff.metamodel.ReferenceChangeRightTarget;
import org.eclipse.emf.compare.diff.metamodel.ReferenceOrderChange;
import org.eclipse.emf.compare.util.EFactory;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eventb.emf.core.context.Context;
import org.eventb.emf.core.machine.Event;
import org.eventb.emf.core.machine.Machine;
import org.eventb.texttools.PersistenceHelper;
public class ModelElementChangeRightTargetMerger extends DefaultMerger {
@Override
public void applyInOrigin() {
final ModelElementChangeRightTarget theDiff = (ModelElementChangeRightTarget) this.diff;
final EObject origin = theDiff.getLeftParent();
final EObject element = theDiff.getRightElement();
if (PersistenceHelper.DEBUG) {
System.out
.println("ModelElementChangeRightTargetMerger.applyInOrigin");
System.out.println(" element: " + element);
System.out.println(" origin: " + origin);
}
// Scenarios where we need to handle special:
// Machine sees Context
// Machine refines Machine
if (origin instanceof Machine && element instanceof Machine) {
MergeUtil.copyMachineRef((Machine) origin, null, (Machine) element);
// Context extends Context
} else if (origin instanceof Context && element instanceof Context) {
MergeUtil.copyContextRef((Context) origin, null, (Context) element);
// New Event added
} else if (origin instanceof Machine && element instanceof Event) {
Event newOne = (Event) EcoreUtil.copy(element);
final EReference ref = element.eContainmentFeature();
if (ref != null) {
try {
EFactory.eAdd(origin, ref.getName(), newOne);
setXMIID(newOne, getXMIID(element));
} catch (final FactoryException e) {
EMFComparePlugin.log(e, true);
}
} else {
origin.eResource().getContents().add(newOne);
}
} else {
originalApplyInOrigin();
}
}
private void originalApplyInOrigin() {
final ModelElementChangeRightTarget theDiff = (ModelElementChangeRightTarget) this.diff;
final EObject origin = theDiff.getLeftParent();
final EObject element = theDiff.getRightElement();
final EObject newOne = copy(element);
final EReference ref = element.eContainmentFeature();
if (ref != null) {
try {
int elementIndex = -1;
if (ref.isMany()) {
Object containmentRefVal = element.eContainer().eGet(ref);
if (containmentRefVal instanceof List) {
List listVal = (List) containmentRefVal;
elementIndex = listVal.indexOf(element);
}
}
EFactory.eAdd(origin, ref.getName(), newOne, elementIndex);
setXMIID(newOne, getXMIID(element));
} catch (final FactoryException e) {
EMFComparePlugin.log(e, true);
}
} else if (origin == null && getDiffModel().getLeftRoots().size() > 0) {
getDiffModel().getLeftRoots().get(0).eResource().getContents()
.add(newOne);
} else if (origin != null) {
origin.eResource().getContents().add(newOne);
} else {
// FIXME Throw exception : couldn't merge this
}
// we should now have a look for AddReferencesLinks needing this object
final Iterator<EObject> siblings = getDiffModel().eAllContents();
while (siblings.hasNext()) {
final DiffElement op = (DiffElement) siblings.next();
if (op instanceof ReferenceChangeRightTarget) {
final ReferenceChangeRightTarget link = (ReferenceChangeRightTarget) op;
// now if I'm in the target References I should put my copy in
// the origin
if (link.getLeftTarget() != null
&& link.getLeftTarget().equals(element)) {
link.setRightTarget(newOne);
}
} else if (op instanceof ReferenceOrderChange) {
final ReferenceOrderChange link = (ReferenceOrderChange) op;
if (link.getReference().equals(ref)) {
// FIXME respect ordering!
link.getLeftTarget().add(newOne);
}
}
}
super.applyInOrigin();
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.compare.diff.merge.api.AbstractMerger#undoInTarget()
*/
@Override
public void undoInTarget() {
throw new RuntimeException();
// final ModelElementChangeRightTarget theDiff =
// (ModelElementChangeRightTarget) this.diff;
// final EObject element = theDiff.getRightElement();
// final EObject parent = theDiff.getRightElement().eContainer();
// EcoreUtil.remove(element);
// // now removes all the dangling references
// removeDanglingReferences(parent);
// super.undoInTarget();
}
}
/**
* (c) 2009 Lehrstuhl fuer Softwaretechnik und Programmiersprachen,
* Heinrich Heine Universitaet Duesseldorf
* This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html)
* */
package org.eventb.texttools.merge;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.compare.diff.merge.service.MergeService;
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.service.DiffService;
import org.eclipse.emf.compare.match.MatchOptions;
import org.eclipse.emf.compare.match.engine.IMatchEngine;
import org.eclipse.emf.compare.match.metamodel.MatchModel;
import org.eclipse.emf.compare.match.service.MatchService;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.impl.ResourceImpl;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl;
import org.eventb.emf.core.Annotation;
import org.eventb.emf.core.EventBNamedCommentedComponentElement;
import org.eventb.emf.core.Extension;
import org.eventb.emf.formulas.BFormula;
import org.eventb.texttools.PersistenceHelper;
import org.eventb.texttools.TextPositionUtil;
/**
* <p>
* This class helps merging an core model instance which has been created by the
* parser back into the original model instance which was created from the
* RodinDB.
* </p>
* <p>
* It takes the original version (old version or left version) and a new version
* (right version) and merges the right into the left. This means it takes all
* changes from the right and applies them to the left. During this process it
* preserves those elements that are not part of the core model and have been
* added as {@link Extension}s or {@link Annotation}s or {@link EAnnotation}s.
* </p>
*/
public class ModelMerge {
private final EventBNamedCommentedComponentElement oldVersion;
private final EventBNamedCommentedComponentElement newVersion;
private final IResource resource;
private final Map<String, Object> matchOptions;
public ModelMerge(final EventBNamedCommentedComponentElement oldVersion,
final EventBNamedCommentedComponentElement newVersion) {
this.oldVersion = oldVersion;
this.newVersion = newVersion;
resource = PersistenceHelper.getIResource(oldVersion.eResource());
/*
* Configure the matching process: We want to match elements in the
* model by their similarity, so we ignore any IDs.
*/
matchOptions = new HashMap<String, Object>();
matchOptions.put(MatchOptions.OPTION_IGNORE_ID, true);
matchOptions.put(MatchOptions.OPTION_IGNORE_XMI_ID, true);
matchOptions
.put(EventBMatchEngine.OPTION_DONT_COMPARE_COMPONENTS, true);
}
/**
* Compares the two model versions that have been given to the constructor
* and merges all changes in the new version into the old version of the
* model. For this process certain changes are ignored:
* <ul>
* <li>RodinInternalAnnotations</li>
* <li>{@link Extension}s which are not {@link BFormula}s (they are changed
* by the text tools parser)</li>
* </ul>
*
* @throws InterruptedException
*/
public void applyChanges(final IProgressMonitor monitor)
throws InterruptedException {
final SubMonitor subMonitor = SubMonitor.convert(monitor,
"Analyzing model changes", 4);
// Fucking EMF and Eclipse reinventing the fucking wheel!!!
URI uri = URI.createURI(resource.getLocationURI().toString());
Resource resources = new ResourceImpl(uri);
final IMatchEngine matchEngine = MatchService
.getBestMatchEngine(resources);
// Workaround to make sure the models have an associated resource
// See setResourceFile() for Bug info
// First find the file extension
String path = oldVersion.getURI().path();
String extension = path.substring(path.lastIndexOf('.'));
File tmpFileNew = null;
if (newVersion.eResource() == null) {
tmpFileNew = setResourceFile(newVersion, extension);
// setRodinResource(newVersion, extension, projectName);
}
matchOptions.put(MatchOptions.OPTION_PROGRESS_MONITOR,
subMonitor.newChild(1));
long timeStart = System.currentTimeMillis();
final MatchModel matchModel = matchEngine.contentMatch(oldVersion,
newVersion, matchOptions);
long timeMatch = System.currentTimeMillis();
final DiffModel diff = getDiffModel(matchModel, subMonitor.newChild(2));
long timeDiff = System.currentTimeMillis();
final EList<DiffElement> ownedElements = diff.getOwnedElements();
if (ownedElements.size() > 0) {
// MergeService
// .merge(new ArrayList<DiffElement>(ownedElements), false);
MergeService.merge(ownedElements, false);
matchOptions.put(MatchOptions.OPTION_PROGRESS_MONITOR,
subMonitor.newChild(1));
subMonitor.worked(1);
}
long timeMerge = System.currentTimeMillis();
if (PersistenceHelper.DEBUG) {
System.out.println("*** applyChanges() ****");
System.out.println(" contentMatch: " + (timeMatch - timeStart));
System.out.println(" getDiffModel: " + (timeDiff - timeMatch));
System.out.println(" merge: " + (timeMerge - timeDiff));
System.out.println();
}
// cleanup tmp files
EcoreUtil.remove(newVersion);
if (tmpFileNew != null) {
tmpFileNew.delete();
}
}
/**
* This method exists to work around a bug in EMF Compare 1.0.1. The compare
* framework only works if a model has an associated resource. see
* https://bugs.eclipse.org/bugs/show_bug.cgi?id=258703
*/
private File setResourceFile(EventBNamedCommentedComponentElement element,
String extension) {
try {
File tmpFile = File.createTempFile("camille-", extension);
tmpFile.deleteOnExit();
URI uri = URI.createFileURI(tmpFile.getAbsolutePath());
Resource resource = new XMLResourceImpl(uri);
resource.getContents().add(element);
return tmpFile;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* Do the diff for the {@link MatchModel} and removed ignored elements
* afterwards.
*
* @param matchModel
* @param monitor
* @return
*/
private DiffModel getDiffModel(final MatchModel matchModel,
final IProgressMonitor monitor) {
final SubMonitor subMonitor = SubMonitor.convert(monitor, 2);
final DiffModel diff = DiffService.doDiff(matchModel);
subMonitor.worked(1);
final EList<DiffElement> ownedElements = diff.getOwnedElements();
final EList<DiffElement> cleanedDiffs = cleanDiffElements(ownedElements);
subMonitor.worked(1);
ownedElements.clear();
ownedElements.addAll(cleanedDiffs);
return diff;
}
/**
* Recursively remove all ignored diff elements.
*
* @see #isIgnoredDiff(DiffElement)
* @param elements
* @return
*/
private EList<DiffElement> cleanDiffElements(
final EList<DiffElement> elements) {
final EList<DiffElement> result = new BasicEList<DiffElement>();
if (elements != null) {
for (final DiffElement diffElement : elements) {
if (!isIgnoredDiff(diffElement)) {
// add this diff element to result
result.add(diffElement);
// continue clean recursively
final EList<DiffElement> subDiffElements = diffElement
.getSubDiffElements();
final EList<DiffElement> subResult = cleanDiffElements(subDiffElements);
subDiffElements.clear();
subDiffElements.addAll(subResult);
}
}
}
return result;
}
/**
* Returns whether the given {@link DiffElement} should be ignored when
* applying the diff.
*
* @param diffElement
* @return
*/
private boolean isIgnoredDiff(final DiffElement diffElement) {
if (diffElement instanceof ModelElementChangeLeftTarget) {
/*
* EMF elements of the original model (left) show up as
* RemoveModelElement diffs when they are missing in the new version
* (right). If we don't want to remove them for the merged version
* we just ignore the diff element.
*/
final ModelElementChangeLeftTarget removedDiff = (ModelElementChangeLeftTarget) diffElement;
final EObject leftElement = removedDiff.getLeftElement();
/*
* The original model may contain arbitrary annotations which we
* didn't create or handle. Ignore EAnnotations containing
* Textranges
*/
if (leftElement instanceof EAnnotation
&& !TextPositionUtil.ANNOTATION_TEXTRANGE
.equals(((EAnnotation) leftElement).getSource())) {
return true;
}
/*
* With eventb.emf v3.1.0 EAnnotations where replaced by
* Annotations. Ignore Annotations containing Textranges
*/
if (leftElement instanceof Annotation
&& !TextPositionUtil.ANNOTATION_TEXTRANGE
.equals(((Annotation) leftElement).getSource())) {
return true;
}
/*
* Ignore all Extensions but our own, i.e. BFormula
*/
if (leftElement instanceof Extension
&& !(leftElement instanceof BFormula)) {
return true;
}
}
return false;
}
}
package org.eventb.texttools.merge;
import java.util.Iterator;
import org.eclipse.emf.compare.EMFComparePlugin;
import org.eclipse.emf.compare.FactoryException;
import org.eclipse.emf.compare.diff.merge.DefaultMerger;
import org.eclipse.emf.compare.diff.metamodel.DiffElement;
import org.eclipse.emf.compare.diff.metamodel.ReferenceChangeLeftTarget;
import org.eclipse.emf.compare.diff.metamodel.ResourceDependencyChange;
import org.eclipse.emf.compare.util.EFactory;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eventb.texttools.PersistenceHelper;
/**
* Merger for an {@link ReferenceChangeLeftTarget} operation.<br/>
* <p>
* Are considered for this merger :
* <ul>
* <li>AddReferenceValue</li>
* <li>RemoteRemoveReferenceValue</li>
* </ul>
* </p>
*
* @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
*/
public class ReferenceChangeLeftTargetMerger extends DefaultMerger {
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.compare.diff.merge.DefaultMerger#applyInOrigin()
*/
@Override
public void applyInOrigin() {
final ReferenceChangeLeftTarget theDiff = (ReferenceChangeLeftTarget) this.diff;
final EObject element = theDiff.getLeftElement();
final EObject leftTarget = theDiff.getRightTarget();
if (PersistenceHelper.DEBUG) {
System.out.println("ReferenceChangeLeftTargetMerger.applyInOrigin");
System.out.println(" element: " + element);
System.out.println(" leftTarget: " + leftTarget);
}
try {
if (leftTarget != null) {
EFactory.eRemove(element, theDiff.getReference().getName(),
leftTarget);
} else {
// (mj) START
EFactory.eRemove(element, theDiff.getReference().getName(),
theDiff.getLeftTarget());
// (mj) END
}
} catch (final FactoryException e) {
EMFComparePlugin.log(e, true);
}
// we should now have a look for AddReferencesLinks needing this object
final Iterator<EObject> siblings = getDiffModel().eAllContents();
while (siblings.hasNext()) {
final DiffElement op = (DiffElement) siblings.next();
if (op instanceof ReferenceChangeLeftTarget) {
final ReferenceChangeLeftTarget link = (ReferenceChangeLeftTarget) op;
// now if I'm in the target References I should put my copy in
// the origin
if (link.getReference().equals(
theDiff.getReference().getEOpposite())
&& link.getRightTarget().equals(element)) {
removeFromContainer(link);
}
} else if (op instanceof ResourceDependencyChange) {
final ResourceDependencyChange link = (ResourceDependencyChange) op;
final Resource res = link.getRoots().get(0).eResource();
if (res == leftTarget.eResource()) {
EcoreUtil.remove(link);
res.unload();
}
}
}
super.applyInOrigin();
}
@Override
public void undoInTarget() {
throw new RuntimeException();
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.compare.diff.merge.DefaultMerger#undoInTarget()
*/
// @Override
// public void undoInTarget() {
// final ReferenceChangeLeftTarget theDiff = (ReferenceChangeLeftTarget)
// this.diff;
// final EObject element = theDiff.getRightElement();
// final EObject leftTarget = theDiff.getRightTarget();
// final EObject rightTarget = theDiff.getLeftTarget();
// // FIXME respect ordering!
// final EObject copiedValue = MergeService.getCopier(diff)
// .copyReferenceValue(theDiff.getReference(), element,
// leftTarget, rightTarget);
//
// // we should now have a look for AddReferencesLinks needing this object
// final Iterator<EObject> siblings = getDiffModel().eAllContents();
// while (siblings.hasNext()) {
// final DiffElement op = (DiffElement) siblings.next();
// if (op instanceof ReferenceChangeLeftTarget) {
// final ReferenceChangeLeftTarget link = (ReferenceChangeLeftTarget) op;
// // now if I'm in the target References I should put my copy in
// // the origin
// if (link.getReference().equals(
// theDiff.getReference().getEOpposite())
// && link.getLeftTarget().equals(element)) {
// removeFromContainer(link);
// }
// } else if (op instanceof ReferenceOrderChange) {
// final ReferenceOrderChange link = (ReferenceOrderChange) op;
// if (link.getReference().equals(theDiff.getReference())) {
// // FIXME respect ordering!
// link.getRightTarget().add(copiedValue);
// }
// }
// }
// super.undoInTarget();
// }
}
/**
* (c) 2009 Lehrstuhl fuer Softwaretechnik und Programmiersprachen,
* Heinrich Heine Universitaet Duesseldorf
* This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html)
* */
package org.eventb.texttools.merge;
import java.util.Iterator;
import java.util.List;
import org.eclipse.emf.compare.diff.merge.DefaultMerger;
import org.eclipse.emf.compare.diff.merge.service.MergeService;
import org.eclipse.emf.compare.diff.metamodel.DiffElement;
import org.eclipse.emf.compare.diff.metamodel.ReferenceChangeRightTarget;
import org.eclipse.emf.compare.diff.metamodel.ReferenceOrderChange;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eventb.texttools.PersistenceHelper;
public class ReferenceChangeRightTargetMerger extends DefaultMerger {
@Override
public void applyInOrigin() {
final ReferenceChangeRightTarget theDiff = (ReferenceChangeRightTarget) diff;
final EObject element = theDiff.getLeftElement();
final EObject leftTarget = theDiff.getLeftTarget();
final EObject rightTarget = theDiff.getRightTarget();
boolean applied = MergeUtil.rodinCopy(element, leftTarget, rightTarget);
if (PersistenceHelper.DEBUG) {
System.out.println("ReferenceChangeRightTargetMerger.applyInOrigin");
System.out.println(" element: " + element);
System.out.println(" leftTarget: " + leftTarget);
System.out.println(" rightTarget: " + rightTarget);
System.out.println(" Applied: " + applied);
}
if (!applied)
originalApplyInOrigin();
}
private void originalApplyInOrigin() {
final ReferenceChangeRightTarget theDiff = (ReferenceChangeRightTarget) this.diff;
final EObject element = theDiff.getLeftElement();
// (mj) In the past, we had right and left toggled.
final EObject rightTarget = theDiff.getRightTarget();
final EObject leftTarget = theDiff.getLeftTarget();
// FIXME respect ordering!
EReference reference = theDiff.getReference();
// ordering handling:
int index = -1;
if (reference.isMany()) {
EObject rightElement = theDiff.getRightElement();
Object fightRefValue = rightElement.eGet(reference);
if (fightRefValue instanceof List) {
List refRightValueList = (List) fightRefValue;
index = refRightValueList.indexOf(rightTarget);
}
}
final EObject copiedValue = MergeService.getCopier(diff)
.copyReferenceValue(reference, element, rightTarget,
leftTarget, index);
// We'll now look through this reference's eOpposite as they are already
// taken care of
final Iterator<EObject> related = getDiffModel().eAllContents();
while (related.hasNext()) {
final DiffElement op = (DiffElement) related.next();
if (op instanceof ReferenceChangeRightTarget) {
final ReferenceChangeRightTarget link = (ReferenceChangeRightTarget) op;
// If this is my eOpposite, delete it from the DiffModel (merged
// along with this one)
if (link.getReference().equals(
theDiff.getReference().getEOpposite())
&& link.getRightTarget().equals(element)) {
removeFromContainer(link);
}
} else if (op instanceof ReferenceOrderChange) {
final ReferenceOrderChange link = (ReferenceOrderChange) op;
if (link.getReference().equals(theDiff.getReference())) {
// FIXME respect ordering!
link.getLeftTarget().add(copiedValue);
}
}
}
super.applyInOrigin();
}
@Override
public void undoInTarget() {
throw new RuntimeException();
}
// /**
// * {@inheritDoc}
// *
// * @see
// org.eclipse.emf.compare.diff.merge.api.AbstractMerger#undoInTarget()
// */
// @Override
// public void undoInTarget() {
// final ReferenceChangeRightTarget theDiff = (ReferenceChangeRightTarget)
// this.diff;
// final EObject element = theDiff.getRightElement();
// final EObject rightTarget = theDiff.getLeftTarget();
// try {
// EFactory.eRemove(element, theDiff.getReference().getName(),
// rightTarget);
// } catch (final FactoryException e) {
// EMFComparePlugin.log(e, true);
// }
// // we should now have a look for AddReferencesLinks needing this object
// final Iterator<EObject> related = getDiffModel().eAllContents();
// while (related.hasNext()) {
// final DiffElement op = (DiffElement) related.next();
// if (op instanceof ReferenceChangeRightTarget) {
// final ReferenceChangeRightTarget link = (ReferenceChangeRightTarget) op;
// // now if I'm in the target References I should put my copy in
// // the origin
// if (link.getReference().equals(
// theDiff.getReference().getEOpposite())
// && link.getLeftTarget().equals(element)) {
// removeFromContainer(link);
// }
// } else if (op instanceof ResourceDependencyChange) {
// final ResourceDependencyChange link = (ResourceDependencyChange) op;
// final Resource res = link.getRoots().get(0).eResource();
// if (res == rightTarget.eResource()) {
// EcoreUtil.remove(link);
// res.unload();
// }
// }
// }
// super.undoInTarget();
// }
}
package org.eventb.texttools.merge;
import java.util.List;
import org.eclipse.emf.compare.EMFComparePlugin;
import org.eclipse.emf.compare.FactoryException;
import org.eclipse.emf.compare.diff.merge.DefaultMerger;
import org.eclipse.emf.compare.diff.metamodel.ReferenceOrderChange;
import org.eclipse.emf.compare.util.EFactory;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eventb.emf.core.context.Context;
import org.eventb.emf.core.machine.Event;
import org.eventb.emf.core.machine.Machine;
import org.eventb.texttools.Constants;
import org.eventb.texttools.PersistenceHelper;
public class ReferenceOrderChangeMerger extends DefaultMerger {
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.compare.diff.merge.DefaultMerger#applyInOrigin()
*/
@Override
public void applyInOrigin() {
final ReferenceOrderChange theDiff = (ReferenceOrderChange) this.diff;
final EObject element = theDiff.getLeftElement();
final List<EObject> leftTarget = theDiff.getLeftTarget();
if (PersistenceHelper.DEBUG) {
System.out.println("ReferenceOrderChangeMerger.applyInOrigin");
System.out.println(" element: " + element);
System.out.println(" leftTarget: " + leftTarget);
}
// (mj) START
if (leftTarget.size() == 0) {
// Handle Event Refinement changed
if (element instanceof Event
&& theDiff.getReference().getName()
.equals(Constants.REFINES)) {
Event leftEvent = (Event) element;
Event rightEvent = (Event) theDiff.getRightElement();
leftEvent.getRefines().clear();
leftEvent.getRefines().addAll(
EcoreUtil.copyAll(rightEvent.getRefines()));
} else if (element instanceof Machine) {
Machine leftMachine = (Machine) element;
Machine rightMachine = (Machine) theDiff.getRightElement();
if (theDiff.getReference().getName().equals(Constants.REFINES)) {
leftMachine.getRefines().clear();
leftMachine.getRefines().addAll(
EcoreUtil.copyAll(rightMachine.getRefines()));
} else if (theDiff.getReference().getName()
.equals(Constants.SEES)) {
leftMachine.getSees().clear();
leftMachine.getSees().addAll(
EcoreUtil.copyAll(rightMachine.getSees()));
}
} else if (element instanceof Context
&& theDiff.getReference().getName()
.equals(Constants.EXTENDS)) {
Context leftContext = (Context) element;
Context rightContext = (Context) theDiff.getRightElement();
leftContext.getExtends().clear();
leftContext.getExtends().addAll(
EcoreUtil.copyAll(rightContext.getExtends()));
}
super.applyInOrigin();
return;
}
// (mj) END
try {
if (theDiff.getReference().isMany()){
//leftTarget is a List!
EFactory.eSet(element, theDiff.getReference().getName(), leftTarget);
}
} catch (final FactoryException e) {
EMFComparePlugin.log(e, true);
}
super.applyInOrigin();
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.compare.diff.merge.DefaultMerger#undoInTarget()
*/
@Override
public void undoInTarget() {
throw new RuntimeException();
// final ReferenceOrderChange theDiff = (ReferenceOrderChange)
// this.diff;
// final EObject element = theDiff.getRightElement();
// final List<EObject> rightTarget = theDiff.getRightTarget();
// try {
// EFactory.eSet(element, theDiff.getReference().getName(),
// rightTarget);
// } catch (final FactoryException e) {
// EMFComparePlugin.log(e, true);
// }
// super.undoInTarget();
}
}
\ No newline at end of file
......@@ -46,28 +46,4 @@
</attributeType>
</relationship>
</extension>
<!-- <extension
point="org.eclipse.emf.compare.match.engine">
<matchengine
label="EventB Match Engine"
engineClass="org.eventb.texttools.merge.EventBMatchEngine"
fileExtension="bum,buc">
</matchengine>
</extension>
<extension
point="org.eclipse.emf.compare.diff.mergerprovider">
<mergerprovider
fileExtension="bum,buc"
mergerProviderClass="org.eventb.texttools.merge.MergerProvider"
priority="highest">
</mergerprovider>
</extension>
<extension
point="org.eclipse.emf.compare.diff.engine">
<diffengine
engineClass="org.eventb.texttools.diff.EventBDiffEngine"
label="Event-B Difference Engine"
priority="highest">
</diffengine>
</extension> -->
</plugin>
......@@ -167,8 +167,8 @@ public class PersistenceHelper {
try {
if (d.getState() != DifferenceState.MERGED)
evbMerger.copyRightToLeft(d,null);
} catch(Exception e) {
System.out.println("SKIPED:"+d);
} catch (RuntimeException e) {
TextToolsPlugin.getDefault().getLog().error("Failed to apply diff while saving edit", e);
}
}
......@@ -176,25 +176,13 @@ public class PersistenceHelper {
final EventBNamedCommentedComponentElement oldVersion,
final EventBNamedCommentedComponentElement newVersion,
final IProgressMonitor monitor) {
long time0 = System.currentTimeMillis();
long timeStart = System.currentTimeMillis();
IComparisonFactory comparisonFactory = new DefaultComparisonFactory(
new DefaultEqualityHelperFactory());
IEObjectMatcher matcher = new EventBEObjectMatcher();
// IMatchEngine matchEngine = new DefaultMatchEngine(matcher,
// comparisonFactory);
// final IMatchEngine eventBMatchEngine = new EventBMatchEngine(matcher,
// comparisonFactory);
// IMatchEngine.Factory matchEngineFactory = new
// MatchEngineFactoryImpl() {
// @Override
// public IMatchEngine getMatchEngine() {
// return eventBMatchEngine;
// }
// };
IMatchEngine.Factory matchEngineFactory = new MatchEngineFactoryImpl(
matcher, comparisonFactory);
matchEngineFactory.setRanking(20);
......@@ -211,11 +199,19 @@ public class PersistenceHelper {
IComparisonScope scope = new DefaultComparisonScope(oldVersion,
newVersion, null);
long timeSetup = System.currentTimeMillis();
if (DEBUG) {
System.out.println("Setting up comparator took " + (timeSetup - timeStart) + " ms");
}
Comparison comparison = comparator.compare(scope);
List<Diff> differences = comparison.getDifferences();
long time1 = System.currentTimeMillis();
long timeCompare = System.currentTimeMillis();
if (DEBUG) {
System.out.println("Comparing took " + (timeCompare - timeSetup) + " ms");
}
Registry registry = RegistryImpl.createStandaloneInstance();
IMerger evbMerger = new EventBMerger();
......@@ -228,11 +224,9 @@ public class PersistenceHelper {
for (Diff d: differences) applyDiff(oldVersion,evbMerger,d);
long time2 = System.currentTimeMillis();
long timeApply = System.currentTimeMillis();
if (DEBUG) {
System.out.println("new ModelMerge: " + (time1 - time0));
System.out.println("merge.applyChanges: " + (time2 - time1));
System.out.println("Merging changes took " + (timeApply - timeCompare) + " ms");
}
}
......
package org.eventb.texttools.diffmerge;
import org.eclipse.emf.compare.match.DefaultMatchEngine;
import org.eclipse.emf.compare.match.IComparisonFactory;
import org.eclipse.emf.compare.match.eobject.IEObjectMatcher;
public class EventBMatchEngine extends DefaultMatchEngine {
public EventBMatchEngine(IEObjectMatcher matcher,
IComparisonFactory comparisonFactory) {
super(matcher, comparisonFactory);
}
}
package org.eventb.texttools.diffmerge;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.compare.AttributeChange;
import org.eclipse.emf.compare.Diff;
import org.eclipse.emf.compare.ReferenceChange;
......@@ -8,7 +7,7 @@ import org.eclipse.emf.compare.merge.AbstractMerger;
import org.eclipse.emf.compare.merge.AttributeChangeMerger;
import org.eclipse.emf.compare.merge.ReferenceChangeMerger;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eventb.emf.core.EventBObject;
import org.eventb.texttools.TextPositionUtil;
......@@ -19,20 +18,18 @@ public class EventBMerger extends AbstractMerger {
@Override
public boolean isMergerFor(Diff target) {
String pack = "";
EStructuralFeature thing;
if (target instanceof ReferenceChange) {
ReferenceChange rc = (ReferenceChange) target;
pack = rc.getReference().getEContainingClass().getEPackage().getName();
//System.out.println("REF PACK:"+pack);
thing = rc.getReference();
} else if (target instanceof AttributeChange) {
AttributeChange ac = (AttributeChange) target;
pack = ac.getAttribute().getEContainingClass().getEPackage().getName();
//System.out.println("ATTR PACK:"+pack);
thing = ac.getAttribute();
} else {
System.out.println("TARGET:"+target);
return false;
}
return pack.equals("core") || pack.equals("machine") || pack.equals("context") || pack.equals("formulas");
String namespaceURI = thing.getEContainingClass().getEPackage().getNsURI();
return namespaceURI.startsWith("http://emf.eventb.org/models/core/");
}
......
......@@ -283,14 +283,14 @@ public class MyReferenceChangeMerger extends AbstractMerger {
targetList.add(insertionIndex, expectedValue);
}
} else if (targetList instanceof EList<?>) {
if (insertionIndex < 0 || insertionIndex > targetList.size()) {
if (insertionIndex < 0 || insertionIndex >= targetList.size()) {
((EList<EObject>)targetList).move(targetList.size() - 1, expectedValue);
} else {
((EList<EObject>)targetList).move(insertionIndex, expectedValue);
}
} else {
targetList.remove(expectedValue);
if (insertionIndex < 0 || insertionIndex > targetList.size()) {
if (insertionIndex < 0 || insertionIndex >= targetList.size()) {
targetList.add(expectedValue);
} else {
targetList.add(insertionIndex, expectedValue);
......@@ -410,7 +410,7 @@ public class MyReferenceChangeMerger extends AbstractMerger {
expectedValue = diff.getValue();
}
} else if (rightToLeft) {
if (reference.isContainment() || valueMatch.getLeft() == null) {
if (valueMatch.getLeft() == null) {
expectedValue = createCopy(diff.getValue());
valueMatch.setLeft(expectedValue);
needXmiId = true;
......@@ -418,7 +418,7 @@ public class MyReferenceChangeMerger extends AbstractMerger {
expectedValue = valueMatch.getLeft();
}
} else {
if (reference.isContainment() || valueMatch.getRight() == null) {
if (valueMatch.getRight() == null) {
expectedValue = createCopy(diff.getValue());
valueMatch.setRight(expectedValue);
needXmiId = true;
......@@ -440,7 +440,7 @@ public class MyReferenceChangeMerger extends AbstractMerger {
if (needXmiId) {
// Copy XMI ID when applicable.
final Resource initialResource = diff.getValue().eResource();
final Resource targetResource = expectedValue.eResource();
final Resource targetResource = expectedContainer.eResource();
if (initialResource instanceof XMIResource && targetResource instanceof XMIResource) {
((XMIResource)targetResource).setID(expectedValue,
((XMIResource)initialResource).getID(diff.getValue()));
......@@ -496,7 +496,6 @@ public class MyReferenceChangeMerger extends AbstractMerger {
}
final EObject expectedValue;
if (valueMatch == null) {
// value is out of the scope... we need to look it up
if (reference.isMany()) {
......