Skip to content

Commit

Permalink
#2675 Fix undo of pasted element
Browse files Browse the repository at this point in the history
The fix consists in using a Recording command instead of AddCommand or SetCommand in the PasteCommand. Indeed, it will properly recreate the cut element using the default undo method based on ChangeDescription(which AddCommand and SetCommand does not do)

Bug: #2675
Signed-off-by: Laurent Fasani <laurent.fasani@obeo.fr>
  • Loading branch information
lfasani authored and pdulth committed Jul 18, 2023
1 parent ab45446 commit 3f925b2
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 20 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2006, 2020 THALES GLOBAL SERVICES.
* Copyright (c) 2006, 2023 THALES GLOBAL SERVICES.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
Expand All @@ -16,19 +16,20 @@
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.command.CompoundCommand;
import org.eclipse.emf.common.command.UnexecutableCommand;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.edit.command.AddCommand;
import org.eclipse.emf.edit.command.SetCommand;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.transaction.RecordingCommand;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.sirius.business.api.session.Session;
import org.eclipse.sirius.business.api.session.SessionManager;
import org.polarsys.capella.common.model.copypaste.SharedCopyPasteElements;
Expand All @@ -37,8 +38,6 @@
import org.polarsys.capella.core.data.cs.ComponentPkg;
import org.polarsys.capella.core.data.cs.CsPackage;
import org.polarsys.capella.core.data.cs.Part;
import org.polarsys.capella.core.model.handler.helpers.CapellaProjectHelper;
import org.polarsys.capella.core.model.handler.helpers.CapellaProjectHelper.TriStateBoolean;
import org.polarsys.capella.core.model.handler.helpers.CrossReferencerHelper;
import org.polarsys.capella.core.ui.toolkit.Activator;

Expand All @@ -52,9 +51,9 @@ public class PasteCommandHelper {
private PasteCommandHelper() {
// Avoid to instantiate.
}
public static IStatus createPasteCommands(Collection<?> pasteElements, CompoundCommand commands, EObject owner, EStructuralFeature feature,
EditingDomain domain, int index, boolean useIndex) {

public static IStatus createPasteCommands(Collection<?> pasteElements, CompoundCommand commands, EObject owner,
EStructuralFeature feature, EditingDomain domain, int index, boolean useIndex) {
IStatus status = Status.OK_STATUS;
EStructuralFeature feat = feature;
SharedCopyPasteElements instance = SharedCopyPasteElements.getInstance();
Expand All @@ -76,7 +75,7 @@ public static IStatus createPasteCommands(Collection<?> pasteElements, CompoundC
} else {
feat = getNewTargetContainingFeature((EObject) originalObject, owner, containingFeature);
}

boolean append = true;
// Check original object and the new owner are in the same session.
Session session = SessionManager.INSTANCE.getSession(owner);
Expand All @@ -93,18 +92,27 @@ public static IStatus createPasteCommands(Collection<?> pasteElements, CompoundC
if (null != feat) {
// Is a many feature ?
if (feat.isMany()) {
// Use AddCommand.
command =
(useIndex) ? AddCommand.create(domain, owner, feat, Collections.singletonList(pasteElement), index) : AddCommand.create(domain,
owner, feat, Collections.singletonList(pasteElement));
// Use are RecordingCommand instead of AddCommand to be sure undo is properly done(in case of cut).
var featureCommand = feat;
command = new RecordingCommand((TransactionalEditingDomain) domain) {
@Override
protected void doExecute() {
((EList) owner.eGet(featureCommand)).addAll(Collections.singletonList(pasteElement));
}
};
} else {
// Not many : use a SetCommand.
command =
(useIndex) ? SetCommand.create(domain, owner, feat, pasteElement, index) : SetCommand.create(domain, owner, feat,
pasteElement);
// Use are RecordingCommand instead of SetCommand to be sure undo is properly done(in case of cut).
var featureCommand = feat;
command = new RecordingCommand((TransactionalEditingDomain) domain) {
@Override
protected void doExecute() {
owner.eSet(featureCommand, Collections.singletonList(pasteElement));
}
};
}
} else {
// Unknown feature : EMF will computes automatically the appropriate feature; it seems to handle correctly all type of feature : many or not.
// Unknown feature : EMF will computes automatically the appropriate feature; it seems to handle correctly all
// type of feature : many or not.
command = AddCommand.create(domain, owner, null, pasteElement);
}
if (null != command) {
Expand Down Expand Up @@ -137,7 +145,8 @@ protected static EStructuralFeature getNewTargetContainingFeature(EObject origin
if (newOwner instanceof ComponentPkg
&& originalContainingFeature == CapellacorePackage.Literals.CLASSIFIER__OWNED_FEATURES) {
return CsPackage.Literals.COMPONENT_PKG__OWNED_PARTS;
} else if (newOwner instanceof Component && originalContainingFeature == CsPackage.Literals.COMPONENT_PKG__OWNED_PARTS) {
} else if (newOwner instanceof Component
&& originalContainingFeature == CsPackage.Literals.COMPONENT_PKG__OWNED_PARTS) {
return CapellacorePackage.Literals.CLASSIFIER__OWNED_FEATURES;
}
} // If I move a Component or a ComponentPkg ...
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2019, 2020 THALES GLOBAL SERVICES.
* Copyright (c) 2019, 2023 THALES GLOBAL SERVICES.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
Expand Down Expand Up @@ -39,6 +39,7 @@ protected List<BasicTestArtefact> getTests() {
tests.add(new CopyPasteModelWithFunctionalAllocation());
tests.add(new CopyPasteModelElementReferencingLibrary());
tests.add(new CopyPasteComponent());
tests.add(new CutPasteUndoModelElement());
return tests;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*******************************************************************************
* Copyright (c) 2023 THALES GLOBAL SERVICES.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Thales - initial API and implementation
*******************************************************************************/
package org.polarsys.capella.test.model.ju.testcase.copyPasteModel;

import java.util.Collections;

import org.eclipse.emf.edit.command.CommandParameter;
import org.eclipse.emf.edit.ui.EMFEditUIPlugin;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.sirius.business.api.session.Session;
import org.eclipse.ui.PlatformUI;
import org.polarsys.capella.core.data.oa.OperationalActivity;
import org.polarsys.capella.core.platform.sirius.ui.commands.CapellaCutCommand;
import org.polarsys.capella.core.platform.sirius.ui.commands.CapellaPasteCommand;
import org.polarsys.capella.core.platform.sirius.ui.navigator.view.CapellaCommonNavigator;
import org.polarsys.capella.test.framework.context.SessionContext;
import org.polarsys.capella.test.model.ju.model.MiscModel;

/**
* Test undo after cut and paste on capella model.
*
* @author lfasani
*/
public class CutPasteUndoModelElement extends MiscModel {

@Override
public void test() throws Exception {
//
// Test data creation.
//
Session session = getSessionForTestModel(getRequiredTestModels().get(0));
SessionContext context = new SessionContext(session);
OperationalActivity rootOA = context.getSemanticElement(OA__OPERATIONAL_ACTIVITIES__ROOT_OA);
OperationalActivity operationalActivity1 = rootOA.getChildrenOperationalActivities().get(0);
OperationalActivity operationalActivity2 = rootOA.getChildrenOperationalActivities().get(1);

TransactionalEditingDomain ted = session.getTransactionalEditingDomain();

assertEquals("bad number of expected elements in root OperationalActivity", 3,
rootOA.getChildrenOperationalActivities().size());

// ------------------
// Cut paste and undo

// Cut
CapellaCommonNavigator capellaProjectView = (CapellaCommonNavigator) PlatformUI.getWorkbench()
.getActiveWorkbenchWindow().getActivePage().showView(CapellaCommonNavigator.ID);
CapellaCutCommand capellaCutCommand = new CapellaCutCommand(
EMFEditUIPlugin.INSTANCE.getString("_UI_Cut_menu_item"),
Collections.singleton(operationalActivity1), capellaProjectView.getCommonViewer());
ted.getCommandStack().execute(capellaCutCommand);
// Paste
CapellaPasteCommand capellaPasteCommand = new CapellaPasteCommand(ted, operationalActivity2, null,
CommandParameter.NO_INDEX);
ted.getCommandStack().execute(capellaPasteCommand);
// Checks
assertTrue("operationalActivity1 is expected to in operationalActivity2",
operationalActivity1.eContainer().equals(operationalActivity2));
assertEquals("bad number of expected elements in operationalActivity2", 1,
operationalActivity2.getChildrenOperationalActivities().size());
assertEquals("bad number of expected elements in root OperationalActivity", 2,
rootOA.getChildrenOperationalActivities().size());

// ----------------
// Undo and check
ted.getCommandStack().undo();
assertTrue("operationalActivity1 is expected to in rootOA",
operationalActivity1.eContainer().equals(rootOA));
assertEquals("bad number of expected elements in operationalActivity2", 0,
operationalActivity2.getChildrenOperationalActivities().size());
assertEquals("bad number of expected elements in root OperationalActivity", 3,
rootOA.getChildrenOperationalActivities().size());
}
}

0 comments on commit 3f925b2

Please sign in to comment.