Added operation to delete trace links This patch adds an operation to delete trace links which can be undone and redone as necessary. Change-Id: Ie9a37b6c72e0c34cf0b4507342635c6503b58b25
diff --git a/bundles/org.eclipse.capra.ui/src/org/eclipse/capra/ui/operations/DeleteTraceOperation.java b/bundles/org.eclipse.capra.ui/src/org/eclipse/capra/ui/operations/DeleteTraceOperation.java new file mode 100644 index 0000000..a2bee3b --- /dev/null +++ b/bundles/org.eclipse.capra.ui/src/org/eclipse/capra/ui/operations/DeleteTraceOperation.java
@@ -0,0 +1,96 @@ +package org.eclipse.capra.ui.operations; + +import java.util.List; + +import org.eclipse.capra.core.adapters.Connection; +import org.eclipse.capra.core.adapters.TraceMetaModelAdapter; +import org.eclipse.capra.core.adapters.TracePersistenceAdapter; +import org.eclipse.capra.core.helpers.EditingDomainHelper; +import org.eclipse.capra.core.helpers.ExtensionPointHelper; +import org.eclipse.capra.core.helpers.TraceHelper; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.commands.operations.AbstractOperation; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.swt.widgets.Shell; + +/** + * Operation to delete trace links. Also allows to undo and redo the operation. + * + * @author Jan-Philipp Steghöfer + * + */ +public class DeleteTraceOperation extends AbstractOperation { + + private static final String ERROR_DIALOG_TITLE = "Error deleting trace link"; + private static final String EXCEPTION_MESSAGE_RUNTIME_EXCEPTION = "An exception occured during the deletion of the trace link."; + + private Connection connection; + + /** + * Creates a new operation to delete trace links. + * + * @param label the label used for the operation. Should never be + * <code>null</code>. + * @param connection the connection representing the trace link that should be + * deleted. + */ + public DeleteTraceOperation(String label, Connection connection) { + super(label); + this.connection = connection; + } + + @Override + public IStatus execute(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { + Shell shell = info.getAdapter(Shell.class); + IStatus executionStatus = null; + + try { + deleteTrace(); + executionStatus = Status.OK_STATUS; + } catch (IllegalStateException e) { + executionStatus = new Status(Status.ERROR, OperationsHelper.PLUGIN_ID, e.getMessage(), e); + OperationsHelper.createErrorMessage(shell, executionStatus, ERROR_DIALOG_TITLE, e.getMessage()); + } catch (RuntimeException e) { + executionStatus = new Status(Status.ERROR, OperationsHelper.PLUGIN_ID, e.getMessage(), e); + OperationsHelper.createErrorMessage(shell, executionStatus, ERROR_DIALOG_TITLE, + EXCEPTION_MESSAGE_RUNTIME_EXCEPTION); + } + return executionStatus; + + } + + @Override + public IStatus redo(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { + return execute(monitor, info); + } + + @Override + public IStatus undo(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { + TracePersistenceAdapter persistenceAdapter = ExtensionPointHelper.getTracePersistenceAdapter().orElseThrow(); + + ResourceSet resourceSet = EditingDomainHelper.getResourceSet(); + EObject traceModel = persistenceAdapter.getTraceModel(resourceSet); + TraceHelper traceHelper = new TraceHelper(traceModel); + traceHelper.createTrace(connection.getOrigins(), connection.getTargets(), connection.getTlink().eClass()); + return Status.OK_STATUS; + } + + /** + * Deletes the trace stored in the {@code connection} field. + */ + private void deleteTrace() { + TraceMetaModelAdapter traceAdapter = ExtensionPointHelper.getTraceMetamodelAdapter().get(); + TracePersistenceAdapter persistenceAdapter = ExtensionPointHelper.getTracePersistenceAdapter().get(); + ResourceSet resourceSet = EditingDomainHelper.getResourceSet(); + EObject traceModel = persistenceAdapter.getTraceModel(resourceSet); + EObject artifactModel = persistenceAdapter.getArtifactWrappers(resourceSet); + traceAdapter.deleteTrace(List.of(connection), traceModel); + persistenceAdapter.saveTracesAndArtifacts(traceModel, artifactModel); + } + +}
diff --git a/tests/org.eclipse.capra.testsuite/src/org/eclipse/capra/testsuite/TestDeleteTraceOperation.java b/tests/org.eclipse.capra.testsuite/src/org/eclipse/capra/testsuite/TestDeleteTraceOperation.java new file mode 100644 index 0000000..8b742af --- /dev/null +++ b/tests/org.eclipse.capra.testsuite/src/org/eclipse/capra/testsuite/TestDeleteTraceOperation.java
@@ -0,0 +1,161 @@ +package org.eclipse.capra.testsuite; + +import static org.eclipse.capra.testsupport.TestHelper.clearWorkspace; +import static org.eclipse.capra.testsupport.TestHelper.createEClassInEPackage; +import static org.eclipse.capra.testsupport.TestHelper.createEcoreModel; +import static org.eclipse.capra.testsupport.TestHelper.createSimpleProject; +import static org.eclipse.capra.testsupport.TestHelper.getProject; +import static org.eclipse.capra.testsupport.TestHelper.load; +import static org.eclipse.capra.testsupport.TestHelper.projectExists; +import static org.eclipse.capra.testsupport.TestHelper.purgeModels; +import static org.eclipse.capra.testsupport.TestHelper.resetSelectionView; +import static org.eclipse.capra.testsupport.TestHelper.save; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +import org.eclipse.capra.core.adapters.Connection; +import org.eclipse.capra.core.adapters.TracePersistenceAdapter; +import org.eclipse.capra.core.helpers.ArtifactHelper; +import org.eclipse.capra.core.helpers.EditingDomainHelper; +import org.eclipse.capra.core.helpers.ExtensionPointHelper; +import org.eclipse.capra.core.helpers.TraceHelper; +import org.eclipse.capra.generic.tracemodel.TracemodelPackage; +import org.eclipse.capra.testsupport.TestHelper; +import org.eclipse.capra.ui.operations.CreateTraceOperation; +import org.eclipse.capra.ui.operations.DeleteTraceOperation; +import org.eclipse.capra.ui.views.SelectionView; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.commands.operations.IOperationHistory; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.Status; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.PlatformUI; +import org.junit.Before; +import org.junit.Test; + +public class TestDeleteTraceOperation { + + private static final String TEST_NAME_UPDATED = "test-name-updated"; + private static final String CLASS_A_NAME = "A"; + private static final String CLASS_B_NAME = "B"; + private static final String CLASS_C_NAME = "C"; + + private static final String MODEL_A_FILENAME = "modelA.ecore"; + private static final String MODEL_B_FILENAME = "modelB.ecore"; + private static final String MODEL_A_NAME = "modelA"; + private static final String MODEL_B_NAME = "modelB"; + + private static final String TEST_PROJECT_NAME = "TestProject"; + + @Before + public void init() throws CoreException { + clearWorkspace(); + resetSelectionView(); + purgeModels(); + } + + /** + * Tests the creation of a trace link and its subsequent deletion using the + * operations defined in {@code org.eclipse.capra.ui.operations}. + * + * @throws CoreException + * @throws IOException + */ + @Test + public void testDeleteTrace() throws CoreException, IOException { + // Create a project + createSimpleProject(TEST_PROJECT_NAME); + assertTrue(projectExists(TEST_PROJECT_NAME)); + + // Create two models and persist them + IProject testProject = getProject(TEST_PROJECT_NAME); + EPackage a = TestHelper.createEcoreModel(MODEL_A_NAME); + createEClassInEPackage(a, CLASS_A_NAME); + save(testProject, a); + + EPackage b = createEcoreModel(MODEL_B_NAME); + createEClassInEPackage(b, CLASS_B_NAME); + createEClassInEPackage(b, CLASS_C_NAME); + save(testProject, b); + + // Load them, choose two elements + ResourceSet rs = new ResourceSetImpl(); + + EPackage _a = load(testProject, MODEL_A_FILENAME, rs); + assertEquals(_a.getName(), MODEL_A_NAME); + EClass _A = (EClass) _a.getEClassifier(CLASS_A_NAME); + + EPackage _b = load(testProject, MODEL_B_FILENAME, rs); + assertEquals(_b.getName(), MODEL_B_NAME); + EClass _B = (EClass) _b.getEClassifier(CLASS_B_NAME); + EClass _C = (EClass) _b.getEClassifier(CLASS_C_NAME); + + // Add them to the selection view + SelectionView.getOpenedView().dropToSelection(_A); + SelectionView.getOpenedView().dropToSelection(_B); + + EClass traceType = TracemodelPackage.eINSTANCE.getRelatedTo(); + + IAdaptable adapter = SelectionView.getOpenedView().getSite(); + + IWorkbench workbench = PlatformUI.getWorkbench(); + IOperationHistory operationHistory = workbench.getOperationSupport().getOperationHistory(); + + CreateTraceOperation createTraceOperation = TestHelper + .prepareCreateTraceOperationForCurrentSelectionOfType(traceType); + try { + assertEquals(operationHistory.execute(createTraceOperation, null, adapter), Status.OK_STATUS); + } catch (ExecutionException e) { + fail("Could not create trace: ExecutionException in operation"); + } + + TracePersistenceAdapter persistenceAdapter = ExtensionPointHelper.getTracePersistenceAdapter().get(); + TraceHelper traceHelper = new TraceHelper( + persistenceAdapter.getTraceModel(EditingDomainHelper.getResourceSet())); + EObject artifactModel = persistenceAdapter.getArtifactWrappers(_A.eResource().getResourceSet()); + ArtifactHelper artifactHelper = new ArtifactHelper(artifactModel); + List<EObject> selection = artifactHelper.createWrappers(SelectionView.getOpenedView().getSelection()); + + // Check that the trace between A and B exists + traceHelper = new TraceHelper(persistenceAdapter.getTraceModel(EditingDomainHelper.getResourceSet())); + selection = artifactHelper.createWrappers(SelectionView.getOpenedView().getSelection()); + assertTrue(traceHelper.traceExists(selection, traceType)); + + List<Connection> traces = traceHelper.getTraces(Arrays.asList(new EClass[] { _A, _B })); + assertFalse(traces.isEmpty()); + + DeleteTraceOperation deleteOp = new DeleteTraceOperation("Delete trace", traces.get(0)); + try { + assertEquals(operationHistory.execute(deleteOp, null, adapter), Status.OK_STATUS); + } catch (ExecutionException e) { + fail("Could not delete trace: ExecutionException in operation"); + } + + List<Connection> tracesAfterDelete = traceHelper.getTraces(Arrays.asList(new EClass[] { _A, _B })); + assertTrue(tracesAfterDelete.isEmpty()); + + try { + assertEquals(operationHistory.undoOperation(deleteOp, null, adapter), Status.OK_STATUS); + } catch (ExecutionException e) { + fail("Could not undo trace deletion: ExecutionException in operation"); + } + + List<Connection> tracesAfterUndo = traceHelper.getTraces(Arrays.asList(new EClass[] { _A, _B })); + assertFalse(tracesAfterUndo.isEmpty()); + + } + +}