[457839] Adds model update strategy for opaque element body changes
Change-Id: I57be6a403660de8bc5f7f104cedcd5b93eb88206
Signed-off-by: Philip Langer <planger@eclipsesource.com>
diff --git a/plugins/org.eclipse.emf.compare.uml2.rcp.ui/src/org/eclipse/emf/compare/uml2/rcp/ui/internal/accessor/OpaqueElementBodyChangeUpdateStrategy.java b/plugins/org.eclipse.emf.compare.uml2.rcp.ui/src/org/eclipse/emf/compare/uml2/rcp/ui/internal/accessor/OpaqueElementBodyChangeUpdateStrategy.java
new file mode 100644
index 0000000..2c5cab2
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.rcp.ui/src/org/eclipse/emf/compare/uml2/rcp/ui/internal/accessor/OpaqueElementBodyChangeUpdateStrategy.java
@@ -0,0 +1,140 @@
+/*******************************************************************************
+ * Copyright (c) 2015 EclipseSource Muenchen GmbH and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Philip Langer - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.uml2.rcp.ui.internal.accessor;
+
+import java.util.List;
+
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.compare.Diff;
+import org.eclipse.emf.compare.rcp.ui.internal.contentmergeviewer.IModelUpdateStrategy;
+import org.eclipse.emf.compare.rcp.ui.internal.util.MergeViewerUtil;
+import org.eclipse.emf.compare.rcp.ui.mergeviewer.IMergeViewer.MergeViewerSide;
+import org.eclipse.emf.compare.uml2.internal.OpaqueElementBodyChange;
+import org.eclipse.emf.compare.uml2.internal.postprocessor.util.UMLCompareUtil;
+import org.eclipse.emf.compare.utils.IEqualityHelper;
+import org.eclipse.emf.ecore.EDataType;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.emf.edit.command.ChangeCommand;
+import org.eclipse.uml2.uml.UMLPackage;
+
+/**
+ * The model update strategy for {@link OpaqueElementBodyChange opaque element body changes}.
+ * <p>
+ * As this update strategy is intended to be used only by the EMFCompareTextMergeViewer (or subclasses) for
+ * changes of body values, this update strategy copes only with actual changes of body values where the
+ * EMFCompareTextMergeViewer is used (i.e., for changes, deletions, and additions; not for moves). In case of
+ * additions or deletions, only the side, in which the body is still present, is editable. The other side, on
+ * which the body is not present anymore or not yet, is not editable.
+ * </p>
+ *
+ * @author Philip Langer <planger@eclipsesource.com>
+ */
+public class OpaqueElementBodyChangeUpdateStrategy implements IModelUpdateStrategy {
+
+ /** The datatype of the body EAttribute of OpaqueAction (expression and behavior have the same). */
+ private static final EDataType BODY_ATTRIBUTE_TYPE = UMLPackage.eINSTANCE.getOpaqueAction_Body()
+ .getEAttributeType();
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see IModelUpdateStrategy#canUpdate(Diff, MergeViewerSide)
+ */
+ public boolean canUpdate(Diff diff, MergeViewerSide side) {
+ if (diff instanceof OpaqueElementBodyChange) {
+ final EObject targetObject = MergeViewerUtil.getEObject(diff.getMatch(), side);
+ final List<String> languages = UMLCompareUtil.getOpaqueElementLanguages(targetObject);
+ final List<String> bodies = UMLCompareUtil.getOpaqueElementBodies(targetObject);
+ final OpaqueElementBodyChange bodyChange = (OpaqueElementBodyChange)diff;
+ return languages.contains(bodyChange.getLanguage())
+ && languages.indexOf(bodyChange.getLanguage()) < bodies.size();
+ }
+ return false;
+ }
+
+ /**
+ * Returns the body value from the underlying model.
+ *
+ * @param bodyChange
+ * The change indicating the language at which the body value shall be obtained.
+ * @param side
+ * The side from which to obtain the value.
+ * @return The body value; if the body value does not exist, this method returns an empty string.
+ */
+ private String getOldBodyValue(OpaqueElementBodyChange bodyChange, MergeViewerSide side) {
+ final EObject targetObject = MergeViewerUtil.getEObject(bodyChange.getMatch(), side);
+ final int index = getIndexOfLanguage(bodyChange.getLanguage(), targetObject);
+ final List<String> bodies = UMLCompareUtil.getOpaqueElementBodies(targetObject);
+ if (index >= 0 && index < bodies.size()) {
+ return bodies.get(index);
+ } else {
+ return ""; //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Returns the index of the given {@code language} of the given {@code object}.
+ *
+ * @param language
+ * The language to get the index of.
+ * @param object
+ * The object to get all language values from.
+ * @return The index of {@code language}; -1 if {@code language} does not exist.
+ */
+ private int getIndexOfLanguage(String language, final EObject object) {
+ final List<String> languages = UMLCompareUtil.getOpaqueElementLanguages(object);
+ return languages.indexOf(language);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see IModelUpdateStrategy#getModelUpdateCommand(Diff, Object, MergeViewerSide)
+ */
+ public Command getModelUpdateCommand(final Diff diff, final Object newValue, final MergeViewerSide side) {
+ final EObject targetObject = MergeViewerUtil.getEObject(diff.getMatch(), side);
+ return new ChangeCommand(targetObject) {
+ @Override
+ public boolean canExecute() {
+ return canUpdate(diff, side) && needsUpdate(diff, newValue, side) && super.canExecute();
+ }
+
+ @Override
+ protected void doExecute() {
+ final List<String> bodies = UMLCompareUtil.getOpaqueElementBodies(targetObject);
+ final OpaqueElementBodyChange bodyChange = (OpaqueElementBodyChange)diff;
+ final int index = getIndexOfLanguage(bodyChange.getLanguage(), targetObject);
+ final String newStringValue = EcoreUtil.convertToString(BODY_ATTRIBUTE_TYPE, newValue);
+ bodies.set(index, newStringValue);
+ }
+ };
+ }
+
+ /**
+ * Specifies whether the value in the model needs to be updated with the given {@code newValue} on the
+ * given {@code side}.
+ *
+ * @param diff
+ * The diff acting as context of the potential model update.
+ * @param newValue
+ * The potentially changed new value to be checked against.
+ * @param side
+ * The side to check.
+ * @return <code>true</code> if an update is necessary, <code>false</code> otherwise.
+ */
+ private boolean needsUpdate(Diff diff, Object newValue, MergeViewerSide side) {
+ final OpaqueElementBodyChange bodyChange = (OpaqueElementBodyChange)diff;
+ final String oldValue = getOldBodyValue(bodyChange, side);
+ final IEqualityHelper equalityHelper = diff.getMatch().getComparison().getEqualityHelper();
+ return !equalityHelper.matchingAttributeValues(newValue, oldValue);
+ }
+}
diff --git a/plugins/org.eclipse.emf.compare.uml2.rcp.ui/src/org/eclipse/emf/compare/uml2/rcp/ui/internal/accessor/factory/OpaqueElementBodyChangeAccessorFactory.java b/plugins/org.eclipse.emf.compare.uml2.rcp.ui/src/org/eclipse/emf/compare/uml2/rcp/ui/internal/accessor/factory/OpaqueElementBodyChangeAccessorFactory.java
index 1f6ad69..0578b89 100644
--- a/plugins/org.eclipse.emf.compare.uml2.rcp.ui/src/org/eclipse/emf/compare/uml2/rcp/ui/internal/accessor/factory/OpaqueElementBodyChangeAccessorFactory.java
+++ b/plugins/org.eclipse.emf.compare.uml2.rcp.ui/src/org/eclipse/emf/compare/uml2/rcp/ui/internal/accessor/factory/OpaqueElementBodyChangeAccessorFactory.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2014 EclipseSource Muenchen GmbH and others.
+ * Copyright (c) 2014, 2015 EclipseSource Muenchen GmbH and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -13,10 +13,13 @@
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.compare.DifferenceKind;
import org.eclipse.emf.compare.rcp.ui.contentmergeviewer.accessor.legacy.ITypedElement;
+import org.eclipse.emf.compare.rcp.ui.internal.contentmergeviewer.IModelUpdateStrategy;
+import org.eclipse.emf.compare.rcp.ui.internal.contentmergeviewer.IModelUpdateStrategyProvider;
import org.eclipse.emf.compare.rcp.ui.internal.contentmergeviewer.accessor.factory.impl.AbstractAccessorFactory;
import org.eclipse.emf.compare.rcp.ui.mergeviewer.IMergeViewer.MergeViewerSide;
import org.eclipse.emf.compare.uml2.internal.OpaqueElementBodyChange;
import org.eclipse.emf.compare.uml2.rcp.ui.internal.accessor.OpaqueElementBodyChangeAccessor;
+import org.eclipse.emf.compare.uml2.rcp.ui.internal.accessor.OpaqueElementBodyChangeUpdateStrategy;
import org.eclipse.emf.compare.uml2.rcp.ui.internal.accessor.OpaqueElementBodyMoveAccessor;
/**
@@ -32,7 +35,7 @@
*
* @author Philip Langer <planger@eclipsesource.com>
*/
-public class OpaqueElementBodyChangeAccessorFactory extends AbstractAccessorFactory {
+public class OpaqueElementBodyChangeAccessorFactory extends AbstractAccessorFactory implements IModelUpdateStrategyProvider {
/**
* {@inheritDoc}
@@ -96,4 +99,13 @@
return new OpaqueElementBodyChangeAccessor(adapterFactory, bodyChange, side);
}
}
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see IModelUpdateStrategyProvider#getModelUpdateStrategy()
+ */
+ public IModelUpdateStrategy getModelUpdateStrategy() {
+ return new OpaqueElementBodyChangeUpdateStrategy();
+ }
}