blob: c58fb8c4dbed35959de05c728f77da43dc6f98ff [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2017 THALES GLOBAL SERVICES.
* 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
*******************************************************************************/
package org.eclipse.sirius.tests.unit.diagram.synchronization;
import java.io.IOException;
import java.util.Collections;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.jobs.Job;
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.edit.provider.ComposedAdapterFactory;
import org.eclipse.emf.transaction.RecordingCommand;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.emf.transaction.impl.TransactionalEditingDomainImpl;
import org.eclipse.emf.transaction.util.TransactionUtil;
import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.sirius.business.api.preferences.SiriusPreferencesKeys;
import org.eclipse.sirius.common.tools.internal.resource.ResourceSyncClientNotifier;
import org.eclipse.sirius.diagram.DDiagram;
import org.eclipse.sirius.diagram.DDiagramElement;
import org.eclipse.sirius.diagram.DNodeContainer;
import org.eclipse.sirius.diagram.DSemanticDiagram;
import org.eclipse.sirius.diagram.description.tool.ContainerDropDescription;
import org.eclipse.sirius.diagram.ui.tools.internal.actions.delete.DeleteFromDiagramAction;
import org.eclipse.sirius.ecore.extender.tool.api.ModelUtils;
import org.eclipse.sirius.tests.SiriusTestsPlugin;
import org.eclipse.sirius.tests.support.api.EclipseTestsSupportHelper;
import org.eclipse.sirius.tests.support.api.SiriusDiagramTestCase;
import org.eclipse.sirius.tests.support.api.TestsUtil;
import org.eclipse.sirius.tests.support.api.matcher.DeletedDecoratorMatcher;
import org.eclipse.sirius.tools.api.command.DCommand;
import org.eclipse.sirius.ui.business.api.dialect.DialectEditor;
import org.eclipse.sirius.ui.business.api.dialect.DialectUIManager;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.PlatformUI;
/**
* Some tests about the unsyncrhonized mapping and semantic deletion made
* outside Sirius : See VP-2351.
*
* @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
*
*/
public class UnsynchronizedMappingAndDeleteFromOutsideEditorTests extends SiriusDiagramTestCase {
private static final String SEMANTIC_MODEL_PROJECT_RELATIVE_PATH = "data/unit/synchronization/unsynchronizedWithDeleteOuside.ecore";
private static final String MODELER_PROJECT_RELATIVE_PATH = "data/unit/synchronization/unsynchronizedWithDeleteOuside.odesign";
private static final String AIRD_PROJECT_RELATIVE_PATH = "data/unit/synchronization/unsynchronizedWithDeleteOuside.aird";
private static final String DIAGRAM_DESCRIPTION_NAME = "unsynchroWithDeleteOutsideDiag";
private DDiagram diagram;
private IEditorPart editor;
@Override
protected void setUp() throws Exception {
super.setUp();
// Copy the use case files in workspace
EclipseTestsSupportHelper.INSTANCE.copyFile(SiriusTestsPlugin.PLUGIN_ID, SEMANTIC_MODEL_PROJECT_RELATIVE_PATH, "/" + TEMPORARY_PROJECT_NAME + "/" + SEMANTIC_MODEL_PROJECT_RELATIVE_PATH);
EclipseTestsSupportHelper.INSTANCE.copyFile(SiriusTestsPlugin.PLUGIN_ID, MODELER_PROJECT_RELATIVE_PATH, "/" + TEMPORARY_PROJECT_NAME + "/" + MODELER_PROJECT_RELATIVE_PATH);
EclipseTestsSupportHelper.INSTANCE.copyFile(SiriusTestsPlugin.PLUGIN_ID, AIRD_PROJECT_RELATIVE_PATH, "/" + TEMPORARY_PROJECT_NAME + "/" + AIRD_PROJECT_RELATIVE_PATH);
// Init the use case
genericSetUp("/" + TEMPORARY_PROJECT_NAME + "/" + SEMANTIC_MODEL_PROJECT_RELATIVE_PATH, "/" + TEMPORARY_PROJECT_NAME + "/" + MODELER_PROJECT_RELATIVE_PATH, "/" + TEMPORARY_PROJECT_NAME + "/"
+ AIRD_PROJECT_RELATIVE_PATH);
TestsUtil.emptyEventsFromUIThread();
// Open the diagram
diagram = (DDiagram) getRepresentations(DIAGRAM_DESCRIPTION_NAME).toArray()[0];
editor = DialectUIManager.INSTANCE.openEditor(session, diagram, new NullProgressMonitor());
TestsUtil.synchronizationWithUIThread();
// Disable dialogs with an automatic reloading
disableUICallBackOnDialectEditor((DialectEditor) editor);
}
@Override
protected void tearDown() throws Exception {
// Close the editor and clean member variables
DialectUIManager.INSTANCE.closeEditor(editor, false);
diagram = null;
editor = null;
TestsUtil.synchronizationWithUIThread();
super.tearDown();
}
/**
* Checks that the behavior is OK in automatic refresh for DDiagramElement
* with mapping unsynchronized and whose target is a semantic that was
* deleted outside of the diagram.
*
* @throws Exception
* In case of problem during semantic modification outside the
* editor.
*/
public void testRefreshOfNotSynchroMapping_AutoRefresh() throws Exception {
changeSiriusPreference(SiriusPreferencesKeys.PREF_AUTO_REFRESH.name(), true);
assertEquals("The diagram does not contain the correct number of children.", 5, diagram.getOwnedDiagramElements().size());
modifySemanticModelOutsideDiagram();
// Check the number of diagram elements
assertEquals("The diagram should only contain elements that are not deleted.", 2, diagram.getOwnedDiagramElements().size());
// Check the number of edit parts
assertEquals("The diagram editPart should only contain elements that are not deleted.", 2, getEditPart(diagram).getChildren().size());
}
/**
* Checks that the behavior is OK in manual refresh for DDiagramElement with
* mapping unsynchronized and whose target is a semantic that was deleted
* outside of the diagram.
*
* @throws Exception
* In case of problem during semantic modification outside the
* editor.
*/
public void testRefreshOfNotSynchroMapping_ManualRefresh() throws Exception {
changeSiriusPreference(SiriusPreferencesKeys.PREF_AUTO_REFRESH.name(), false);
assertEquals("The diagram does not contain the correct number of children.", 5, diagram.getOwnedDiagramElements().size());
// Keep some semantic elements for future tests
EPackage ePackage = (EPackage) semanticModel;
EClass testedClass = (EClass) ePackage.getESubpackages().get(2).getEClassifier("C1InSubRoot");
EPackage testedPackage = ePackage.getESubpackages().get(2).getESubpackages().get(0);
assertFalse("At least one error occurs before the semantic modification.", doesAnErrorOccurs());
modifySemanticModelOutsideDiagram();
// Check there is no errorLog message during semantic modification and
// diagram refresh
assertFalse("At least one error occurs during the semantic modification (and so diagram refresh).", doesAnErrorOccurs());
// Check the number of diagram elements
assertEquals("The diagram should not be modify because we are in manual refresh mode.", 5, diagram.getOwnedDiagramElements().size());
// Check edit part for a DNode
IGraphicalEditPart testedClassEditPart = getEditPart(testedClass);
assertFalse("The editMode of editPart which target the class C1InSubRoot must be disabled.", testedClassEditPart.isEditModeEnabled());
// Check edit part for a DNode is decorated with a red cross
assertTrue("No deleted decorator found on editPart which target the class C1InSubRoot", new DeletedDecoratorMatcher().matches(testedClassEditPart));
IGraphicalEditPart testedPackageEditPart = getEditPart(testedPackage);
// Check edit part for a DContainer
assertFalse("The editMode of editPart which target the package p1InSubRoot must be disabled.", testedPackageEditPart.isEditModeEnabled());
// Check edit part for a DNode is decorated with a red cross
assertTrue("No deleted decorator found on editPart which target the package p1InSubRoot", new DeletedDecoratorMatcher().matches(testedPackageEditPart));
// Launch a manual refresh and check again the number of diagram
// elements
refresh(diagram);
assertFalse("At least one error occurs during the manual refresh.", doesAnErrorOccurs());
assertEquals("The diagram should only contain elements that are not deleted.", 2, diagram.getOwnedDiagramElements().size());
}
/**
* Checks that the "Delete from diagram" is not available for
* DDiagramElement that will be removed at the next manual refresh.
*
* @throws Exception
* In case of problem during semantic modification outside the
* editor.
*/
public void testDeleteFromDiagramNotActivatedForDisableEditPart() throws Exception {
changeSiriusPreference(SiriusPreferencesKeys.PREF_AUTO_REFRESH.name(), false);
assertEquals("The diagram does not contain the correct number of children.", 5, diagram.getOwnedDiagramElements().size());
// Keep some semantic elements for future tests
EPackage ePackage = (EPackage) semanticModel;
EClass testedClass = (EClass) ePackage.getESubpackages().get(2).getEClassifier("C1InSubRoot");
EPackage testedPackage = ePackage.getESubpackages().get(2).getESubpackages().get(0);
assertFalse("At least one error occurs before the semantic modification.", doesAnErrorOccurs());
modifySemanticModelOutsideDiagram();
// Check there is no errorLog message during semantic modification and
// diagram refresh
assertFalse("At least one error occurs during the semantic modification (and so diagram refresh).", doesAnErrorOccurs());
// Check the number of diagram elements
assertEquals("The diagram should not be modify because we are in manual refresh mode.", 5, diagram.getOwnedDiagramElements().size());
// Check the disablement of action DeleteFromDiagram for the DNode edit
// part
final StructuredSelection dNodeSelection = new StructuredSelection(getEditPart(testedClass));
final DeleteFromDiagramAction actionDelegate = new DeleteFromDiagramAction();
final Action mockAction = new Action() {};
actionDelegate.selectionChanged(mockAction, dNodeSelection);
assertFalse("As the node edit part has its target deleted then the delete from diagram should be disabled", mockAction.isEnabled());
// Check the disablement of action DeleteFromDiagram for the
// DNodeContainer edit part
final StructuredSelection dNodeContainerSelection = new StructuredSelection(getEditPart(testedPackage));
actionDelegate.selectionChanged(mockAction, dNodeContainerSelection);
assertFalse("As the nodeContainer edit part has its target deleted then the delete from diagram should be disabled", mockAction.isEnabled());
}
/**
* Check that a drag'n'drop is not available in DDiagramElement that will be
* removed at the next manual refresh.
*
* @throws Exception
* In case of problem during semantic modification outside the
* editor.
*/
public void testDragNDropForDisableEditPart() throws Exception {
changeSiriusPreference(SiriusPreferencesKeys.PREF_AUTO_REFRESH.name(), false);
assertEquals("The diagram does not contain the correct number of children.", 5, diagram.getOwnedDiagramElements().size());
// Keep some semantic elements for future tests
EPackage ePackage = (EPackage) semanticModel;
EPackage dropTargetPackage = ePackage.getESubpackages().get(2);
assertFalse("At least one error occurs before the semantic modification.", doesAnErrorOccurs());
modifySemanticModelOutsideDiagram();
// Check there is no errorLog message during semantic modification and
// diagram refresh
assertFalse("At least one error occurs during the semantic modification (and so diagram refresh).", doesAnErrorOccurs());
// Get some semantic elements for future tests
EPackage rootPackage = (EPackage) ((DSemanticDiagram) diagram).getTarget();
EPackage dragElementToContainer = rootPackage.getESubpackages().get(0);
EPackage dragElementToDiagram = rootPackage.getESubpackages().get(1);
// Try Drag'n'Drop in diagram (must be OK)
final ContainerDropDescription dragAndDropToolInDiagram = (ContainerDropDescription) getTool(diagram, "DndPackageInDiagram");
assertNotNull("Could not find the tool to drop a container in the diagram", dragAndDropToolInDiagram);
DCommand command = (DCommand) getCommandFactory().buildDropInContainerCommandFromTool(diagram, dragElementToDiagram, dragAndDropToolInDiagram);
int nbDiagElementsBeforeDnD = diagram.getOwnedDiagramElements().size();
session.getTransactionalEditingDomain().getCommandStack().execute(command);
// Check the number of diagram elements
assertEquals("This drag'n'drop is authorized, so it should be one diagram element more.", nbDiagElementsBeforeDnD + 1, diagram.getOwnedDiagramElements().size());
// Try Drag'n'Drop in a container with deleted target (must be KO)
final ContainerDropDescription dragAndDropToolInContainer = (ContainerDropDescription) getTool(diagram, "DndPackageInPackage");
assertNotNull("Could not find the tool to drop a container in the container", dragAndDropToolInContainer);
// When user try to drag'n'drop, the command is not build because the
// GraphicalEditPart.showTargetFeedback return before because the
// editMode of the edit part is disabled. But for this test we try to do
// the d'n'd.
command = (DCommand) getCommandFactory().buildDropInContainerCommandFromTool((DNodeContainer) getFirstDiagramElement(diagram, dropTargetPackage), dragElementToContainer,
dragAndDropToolInContainer);
nbDiagElementsBeforeDnD = diagram.getOwnedDiagramElements().size();
session.getTransactionalEditingDomain().getCommandStack().execute(command);
assertTrue("A message must be logged because during the build of the command the session of the deleted object can not be reached.", doesAnErrorOccurs());
clearErrors();
// Check the number of diagram elements
assertEquals("This drag'n'drop is not authorized, so the number of diagram element should be the same.", nbDiagElementsBeforeDnD, diagram.getOwnedDiagramElements().size());
}
/**
* Get the edit part which have this target.
*
* @return the corresponding edit part.
*/
private IGraphicalEditPart getEditPart(EObject target) {
DDiagramElement diagramElement = getFirstDiagramElement(diagram, target);
assertNotNull("The semantic element has no corresponding diagramElement", diagramElement);
IGraphicalEditPart editPart = getEditPart(diagramElement);
assertNotNull("The semantic element has no corresponding edit part.", editPart);
return editPart;
}
/**
* Delete the "subRoot" package. The modification is not made in the same
* resourceSet, as if this modification is made in another editor not in
* Sirius.
*/
private void modifySemanticModelOutsideDiagram() throws Exception {
EPackage ePackage = (EPackage) semanticModel;
// Load the semantic resource in another resource set, delete the
// elements and save the resource.
TransactionalEditingDomain domain = new TransactionalEditingDomainImpl(new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE));
ResourceSet set = domain.getResourceSet();
try {
final EPackage ePackageInAnotherResourceSet = (EPackage) ModelUtils.load(ePackage.eResource().getURI(), set);
assertFalse("The editing domain of each root semantic must be different.", domain.equals(TransactionUtil.getEditingDomain(ePackage)));
domain.getCommandStack().execute(new RecordingCommand(domain, "Delete semantic elements outside the diagram") {
@Override
protected void doExecute() {
// Remove the package subRoot
ePackageInAnotherResourceSet.getESubpackages().remove(2);
}
});
ePackageInAnotherResourceSet.eResource().save(Collections.EMPTY_MAP);
} catch (IOException e) {
fail("Pb when saving the resource in another resourceSet : " + e.getMessage());
}
// Wait job ResourceSyncClientNotifier to ensure the session has been
// reloaded.
if (Display.getCurrent() != null) {
PlatformUI.getWorkbench().getProgressService().busyCursorWhile(new IRunnableWithProgress() {
@Override
public void run(IProgressMonitor monitor) throws InterruptedException {
Job.getJobManager().join(ResourceSyncClientNotifier.FAMILY, monitor);
}
});
} else {
Job.getJobManager().join(ResourceSyncClientNotifier.FAMILY, new NullProgressMonitor());
}
}
}