diff --git a/features/org.eclipse.papyrus.uml.domain.services.feature/feature.xml b/features/org.eclipse.papyrus.uml.domain.services.feature/feature.xml index b10d316bc194b60c344f31f536b5a1b15c348a42..f63bfc1b3d6668e8988241565d21df21283438c9 100644 --- a/features/org.eclipse.papyrus.uml.domain.services.feature/feature.xml +++ b/features/org.eclipse.papyrus.uml.domain.services.feature/feature.xml @@ -2,7 +2,7 @@ <feature id="org.eclipse.papyrus.uml.domain.services.feature" label="%featureName" - version="0.23.0.qualifier" + version="0.24.0" provider-name="%providerName" license-feature="org.eclipse.license" license-feature-version="2.0.2"> diff --git a/features/org.eclipse.papyrus.uml.domain.services.feature/pom.xml b/features/org.eclipse.papyrus.uml.domain.services.feature/pom.xml index 97eddaaf1a9d4441e3123b05b2df9dfa63b84f45..50e9c71028fc8dbb0522ffd685f493684fd61841 100644 --- a/features/org.eclipse.papyrus.uml.domain.services.feature/pom.xml +++ b/features/org.eclipse.papyrus.uml.domain.services.feature/pom.xml @@ -6,7 +6,7 @@ <parent> <groupId>org.eclipse.papyrus.domainservices</groupId> <artifactId>parent</artifactId> - <version>0.23.0-SNAPSHOT</version> + <version>0.24.0</version> <relativePath>../../parent</relativePath> </parent> <artifactId>org.eclipse.papyrus.uml.domain.services.feature</artifactId> diff --git a/parent/pom.xml b/parent/pom.xml index ebc6a72339fbebb990779817a562af7a86d750dd..e17a6ae46159644c4984daa2efa09b8c8d8327ac 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -5,7 +5,7 @@ <modelVersion>4.0.0</modelVersion> <groupId>org.eclipse.papyrus.domainservices</groupId> <artifactId>parent</artifactId> - <version>0.23.0-SNAPSHOT</version> + <version>0.24.0</version> <packaging>pom</packaging> <name>Papyrus-UML-services</name> diff --git a/plugins/org.eclipse.papyrus.uml.domain.services.test/META-INF/MANIFEST.MF b/plugins/org.eclipse.papyrus.uml.domain.services.test/META-INF/MANIFEST.MF index 4948923abe77cc93af4545f36d62bb169cb44d36..96b4996d717854c50388cb7d6d27cdabce074991 100644 --- a/plugins/org.eclipse.papyrus.uml.domain.services.test/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.papyrus.uml.domain.services.test/META-INF/MANIFEST.MF @@ -2,10 +2,10 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: UML Domain service Tests Bundle-SymbolicName: org.eclipse.papyrus.uml.domain.services.test -Bundle-Version: 0.23.0.qualifier +Bundle-Version: 0.24.0 Fragment-Host: org.eclipse.papyrus.uml.domain.services;bundle-version="0.1.0" Automatic-Module-Name: org.eclipse.papyrus.uml.domain.services.test Bundle-RequiredExecutionEnvironment: JavaSE-17 Require-Bundle: org.eclipse.uml2.uml.resources;bundle-version="5.5.0", - org.junit.jupiter.api, - org.junit.jupiter.params + junit-jupiter-api, + junit-jupiter-params diff --git a/plugins/org.eclipse.papyrus.uml.domain.services.test/pom.xml b/plugins/org.eclipse.papyrus.uml.domain.services.test/pom.xml index 0b969848d52ce155163ef113ff7a3ead973731e7..e3aa0628227587220dd179306d57e4f65b93d923 100644 --- a/plugins/org.eclipse.papyrus.uml.domain.services.test/pom.xml +++ b/plugins/org.eclipse.papyrus.uml.domain.services.test/pom.xml @@ -7,7 +7,7 @@ <parent> <groupId>org.eclipse.papyrus.domainservices</groupId> <artifactId>parent</artifactId> - <version>0.23.0-SNAPSHOT</version> + <version>0.24.0</version> <relativePath>../../parent</relativePath> </parent> diff --git a/plugins/org.eclipse.papyrus.uml.domain.services.test/src/org/eclipse/papyrus/uml/domain/services/destroy/DiagramElementDeletorTest.java b/plugins/org.eclipse.papyrus.uml.domain.services.test/src/org/eclipse/papyrus/uml/domain/services/destroy/DiagramElementDeletorTest.java index da61be00f85a8229230bf19b894097d6c13e63a0..4aa5cc62c2544dcfb58a44c3a23a87ea266c968e 100644 --- a/plugins/org.eclipse.papyrus.uml.domain.services.test/src/org/eclipse/papyrus/uml/domain/services/destroy/DiagramElementDeletorTest.java +++ b/plugins/org.eclipse.papyrus.uml.domain.services.test/src/org/eclipse/papyrus/uml/domain/services/destroy/DiagramElementDeletorTest.java @@ -1,5 +1,5 @@ /***************************************************************************** - * Copyright (c) 2022, 2023 CEA LIST, Obeo. + * Copyright (c) 2022, 2024 CEA LIST, Obeo. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -489,41 +489,6 @@ public class DiagramElementDeletorTest extends AbstractUMLTest { assertTrue(interaction.getMessages().isEmpty()); } - @Test - public void deleteMessageWithSharedStartAndFinishEventsInInteraction() { - Interaction interaction = create(Interaction.class); - Message message = createIn(Message.class, interaction); - MessageOccurrenceSpecification sendEvent = createIn(MessageOccurrenceSpecification.class, interaction); - message.setSendEvent(sendEvent); - MessageOccurrenceSpecification receiveEvent = createIn(MessageOccurrenceSpecification.class, interaction); - message.setReceiveEvent(receiveEvent); - - Message message2 = createIn(Message.class, interaction); - message2.setSendEvent(sendEvent); - message2.setReceiveEvent(receiveEvent); - - assertFalse(interaction.getFragments().isEmpty()); - assertFalse(interaction.getMessages().isEmpty()); - DestroyerStatus messageDestroyStatus = ElementDestroyer.buildDefault(getCrossRef(), getEditableChecker()) - .destroy(message); - assertEquals(State.DONE, messageDestroyStatus.getState()); - assertTrue(interaction.getFragments().contains(sendEvent)); - assertTrue(interaction.getFragments().contains(receiveEvent)); - assertTrue(interaction.getMessages().contains(message2)); - // Only message is deleted because its send/receive events are shared with - // message 2. - assertFalse(interaction.getMessages().contains(message)); - - DestroyerStatus message2DestroyStatus = ElementDestroyer.buildDefault(getCrossRef(), getEditableChecker()) - .destroy(message2); - // Message 2 and its send/receive events are deleted since they aren't shared - // anymore. - assertEquals(State.DONE, message2DestroyStatus.getState()); - assertTrue(interaction.getFragments().isEmpty()); - assertTrue(interaction.getMessages().isEmpty()); - - } - @Test public void deleteMessageWithoutStartAndFinishEventsInInteraction() { Interaction interaction = create(Interaction.class); diff --git a/plugins/org.eclipse.papyrus.uml.domain.services.test/src/org/eclipse/papyrus/uml/domain/services/drop/SequenceInternalSourceToRepresentationDropBehaviorProviderTest.java b/plugins/org.eclipse.papyrus.uml.domain.services.test/src/org/eclipse/papyrus/uml/domain/services/drop/SequenceInternalSourceToRepresentationDropBehaviorProviderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..01589890beedcfdbeef1d17945204814a385dc0c --- /dev/null +++ b/plugins/org.eclipse.papyrus.uml.domain.services.test/src/org/eclipse/papyrus/uml/domain/services/drop/SequenceInternalSourceToRepresentationDropBehaviorProviderTest.java @@ -0,0 +1,107 @@ +/***************************************************************************** + * Copyright (c) 2024 CEA LIST. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Obeo - Initial API and implementation + *****************************************************************************/ +package org.eclipse.papyrus.uml.domain.services.drop; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.eclipse.papyrus.uml.domain.services.drop.diagrams.SequenceInternalSourceToRepresentationDropBehaviorProvider; +import org.eclipse.papyrus.uml.domain.services.status.State; +import org.eclipse.papyrus.uml.domain.services.status.Status; +import org.eclipse.papyrus.uml.domain.services.utils.AbstractUMLTest; +import org.eclipse.uml2.uml.Comment; +import org.eclipse.uml2.uml.Constraint; +import org.eclipse.uml2.uml.Interaction; +import org.eclipse.uml2.uml.InteractionOperand; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * Test class for + * {@link SequenceInternalSourceToRepresentationDropBehaviorProvider}. + * + * @author <a href="mailto:glenn.plouhinec@obeo.fr">Glenn Plouhinec</a> + */ +public class SequenceInternalSourceToRepresentationDropBehaviorProviderTest extends AbstractUMLTest { + + private SequenceInternalSourceToRepresentationDropBehaviorProvider sequenceInternalSourceToRepresentationDropBehaviorProvider; + + @BeforeEach + @Override + public void setUp() { + super.setUp(); + this.sequenceInternalSourceToRepresentationDropBehaviorProvider = new SequenceInternalSourceToRepresentationDropBehaviorProvider(); + } + + @Test + public void testCommentDropFromInteractionToInteractionOperand() { + Interaction interaction = this.create(Interaction.class); + Comment commentToDrop = this.create(Comment.class); + interaction.getOwnedComments().add(commentToDrop); + InteractionOperand interactionOperand = create(InteractionOperand.class); + + Status status = this.sequenceInternalSourceToRepresentationDropBehaviorProvider.drop(commentToDrop, interaction, + interactionOperand, this.getCrossRef(), this.getEditableChecker()); + + assertEquals(State.DONE, status.getState()); + assertTrue(interactionOperand.getOwnedComments().contains(commentToDrop)); + assertFalse(interaction.getOwnedComments().contains(commentToDrop)); + } + + @Test + public void testCommentDropFromInteractionOperandToInteraction() { + InteractionOperand interactionOperand = create(InteractionOperand.class); + Comment commentToDrop = this.create(Comment.class); + interactionOperand.getOwnedComments().add(commentToDrop); + Interaction interaction = this.create(Interaction.class); + + Status status = this.sequenceInternalSourceToRepresentationDropBehaviorProvider.drop(commentToDrop, + interactionOperand, interaction, this.getCrossRef(), this.getEditableChecker()); + + assertEquals(State.DONE, status.getState()); + assertTrue(interaction.getOwnedComments().contains(commentToDrop)); + assertFalse(interactionOperand.getOwnedComments().contains(commentToDrop)); + } + + @Test + public void testConstraintDropFromInteractionToInteractionOperand() { + Interaction interaction = this.create(Interaction.class); + Constraint constraintToDrop = this.create(Constraint.class); + interaction.getOwnedRules().add(constraintToDrop); + InteractionOperand interactionOperand = create(InteractionOperand.class); + + Status status = this.sequenceInternalSourceToRepresentationDropBehaviorProvider.drop(constraintToDrop, + interaction, interactionOperand, this.getCrossRef(), this.getEditableChecker()); + + assertEquals(State.DONE, status.getState()); + assertTrue(interactionOperand.getOwnedRules().contains(constraintToDrop)); + assertFalse(interaction.getOwnedRules().contains(constraintToDrop)); + } + + @Test + public void testConstraintDropFromInteractionOperandToInteraction() { + InteractionOperand interactionOperand = create(InteractionOperand.class); + Constraint constraintToDrop = this.create(Constraint.class); + interactionOperand.getOwnedRules().add(constraintToDrop); + Interaction interaction = this.create(Interaction.class); + + Status status = this.sequenceInternalSourceToRepresentationDropBehaviorProvider.drop(constraintToDrop, + interactionOperand, interaction, this.getCrossRef(), this.getEditableChecker()); + + assertEquals(State.DONE, status.getState()); + assertTrue(interaction.getOwnedRules().contains(constraintToDrop)); + assertFalse(interactionOperand.getOwnedRules().contains(constraintToDrop)); + } +} diff --git a/plugins/org.eclipse.papyrus.uml.domain.services.test/src/org/eclipse/papyrus/uml/domain/services/drop/SequenceInternalSourceToRepresentationDropCheckerTest.java b/plugins/org.eclipse.papyrus.uml.domain.services.test/src/org/eclipse/papyrus/uml/domain/services/drop/SequenceInternalSourceToRepresentationDropCheckerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..532b89aa8e0498523c3120a3c2c37268175ebc2b --- /dev/null +++ b/plugins/org.eclipse.papyrus.uml.domain.services.test/src/org/eclipse/papyrus/uml/domain/services/drop/SequenceInternalSourceToRepresentationDropCheckerTest.java @@ -0,0 +1,126 @@ +/***************************************************************************** + * Copyright (c) 2024 CEA LIST. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Obeo - Initial API and implementation + *****************************************************************************/ +package org.eclipse.papyrus.uml.domain.services.drop; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.eclipse.papyrus.uml.domain.services.drop.diagrams.SequenceInternalSourceToRepresentationDropChecker; +import org.eclipse.papyrus.uml.domain.services.status.CheckStatus; +import org.eclipse.papyrus.uml.domain.services.utils.AbstractUMLTest; +import org.eclipse.uml2.uml.CombinedFragment; +import org.eclipse.uml2.uml.Comment; +import org.eclipse.uml2.uml.Constraint; +import org.eclipse.uml2.uml.Interaction; +import org.eclipse.uml2.uml.InteractionOperand; +import org.eclipse.uml2.uml.InteractionUse; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * Test class for {@link SequenceInternalSourceToRepresentationDropChecker}. + * + * @author <a href="mailto:glenn.plouhinec@obeo.fr">Glenn Plouhinec</a> + */ +public class SequenceInternalSourceToRepresentationDropCheckerTest extends AbstractUMLTest { + + private SequenceInternalSourceToRepresentationDropChecker sequenceInternalSourceToRepresentationDropChecker; + + @Override + @BeforeEach + public void setUp() { + super.setUp(); + this.sequenceInternalSourceToRepresentationDropChecker = new SequenceInternalSourceToRepresentationDropChecker(); + } + + @Test + public void testCommentDropOnInteraction() { + Comment commentToDrop = this.create(Comment.class); + Interaction targetInteraction = this.create(Interaction.class); + + CheckStatus canDragAndDropStatus = this.sequenceInternalSourceToRepresentationDropChecker + .canDragAndDrop(commentToDrop, targetInteraction); + assertTrue(canDragAndDropStatus.isValid()); + } + + @Test + public void testCommentDropOnInteractionOperand() { + Comment commentToDrop = this.create(Comment.class); + InteractionOperand targetInteractionOperand = this.create(InteractionOperand.class); + + CheckStatus canDragAndDropStatus = this.sequenceInternalSourceToRepresentationDropChecker + .canDragAndDrop(commentToDrop, targetInteractionOperand); + assertTrue(canDragAndDropStatus.isValid()); + } + + @Test + public void testCommentDropOnCombinedFragment() { + Comment commentToDrop = this.create(Comment.class); + CombinedFragment targetCombinedFragment = this.create(CombinedFragment.class); + + CheckStatus canDragAndDropStatus = this.sequenceInternalSourceToRepresentationDropChecker + .canDragAndDrop(commentToDrop, targetCombinedFragment); + assertFalse(canDragAndDropStatus.isValid()); + } + + @Test + public void testCommentDropOnInteractionUse() { + Comment commentToDrop = this.create(Comment.class); + InteractionUse targetInteractionUse = this.create(InteractionUse.class); + + CheckStatus canDragAndDropStatus = this.sequenceInternalSourceToRepresentationDropChecker + .canDragAndDrop(commentToDrop, targetInteractionUse); + assertFalse(canDragAndDropStatus.isValid()); + } + + @Test + public void testConstraintDropOnInteraction() { + Constraint constraintToDrop = this.create(Constraint.class); + Interaction targetInteraction = this.create(Interaction.class); + + CheckStatus canDragAndDropStatus = this.sequenceInternalSourceToRepresentationDropChecker + .canDragAndDrop(constraintToDrop, targetInteraction); + assertTrue(canDragAndDropStatus.isValid()); + } + + @Test + public void testConstraintDropOnInteractionOperand() { + Constraint constraintToDrop = this.create(Constraint.class); + InteractionOperand targetInteractionOperand = this.create(InteractionOperand.class); + + CheckStatus canDragAndDropStatus = this.sequenceInternalSourceToRepresentationDropChecker + .canDragAndDrop(constraintToDrop, targetInteractionOperand); + assertTrue(canDragAndDropStatus.isValid()); + } + + @Test + public void testConstraintDropOnCombinedFragment() { + Constraint constraintToDrop = this.create(Constraint.class); + CombinedFragment targetCombinedFragment = this.create(CombinedFragment.class); + + CheckStatus canDragAndDropStatus = this.sequenceInternalSourceToRepresentationDropChecker + .canDragAndDrop(constraintToDrop, targetCombinedFragment); + assertFalse(canDragAndDropStatus.isValid()); + } + + @Test + public void testConstraintDropOnInteractionUse() { + Constraint constraintToDrop = this.create(Constraint.class); + InteractionUse targetInteractionUse = this.create(InteractionUse.class); + + CheckStatus canDragAndDropStatus = this.sequenceInternalSourceToRepresentationDropChecker + .canDragAndDrop(constraintToDrop, targetInteractionUse); + assertFalse(canDragAndDropStatus.isValid()); + } +} diff --git a/plugins/org.eclipse.papyrus.uml.domain.services.test/src/org/eclipse/papyrus/uml/domain/services/labels/ElementLabelProviderTest.java b/plugins/org.eclipse.papyrus.uml.domain.services.test/src/org/eclipse/papyrus/uml/domain/services/labels/ElementLabelProviderTest.java index 06beacf63081e7eb036a527351126b6e45571675..e968ca1cd6bd4bb6d48410a8233b00bcff2ddf69 100644 --- a/plugins/org.eclipse.papyrus.uml.domain.services.test/src/org/eclipse/papyrus/uml/domain/services/labels/ElementLabelProviderTest.java +++ b/plugins/org.eclipse.papyrus.uml.domain.services.test/src/org/eclipse/papyrus/uml/domain/services/labels/ElementLabelProviderTest.java @@ -1,5 +1,5 @@ /***************************************************************************** - * Copyright (c) 2022, 2023 CEA LIST, Obeo. + * Copyright (c) 2022, 2024 CEA LIST, Obeo. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -16,7 +16,6 @@ package org.eclipse.papyrus.uml.domain.services.labels; import static org.eclipse.papyrus.uml.domain.services.EMFUtils.allContainedObjectOfType; import static org.eclipse.papyrus.uml.domain.services.labels.UMLCharacters.CLOSE_ANGLE_BRACKET; import static org.eclipse.papyrus.uml.domain.services.labels.UMLCharacters.CLOSE_BRACKET; -import static org.eclipse.papyrus.uml.domain.services.labels.UMLCharacters.D_DOTS; import static org.eclipse.papyrus.uml.domain.services.labels.UMLCharacters.EMPTY; import static org.eclipse.papyrus.uml.domain.services.labels.UMLCharacters.EOL; import static org.eclipse.papyrus.uml.domain.services.labels.UMLCharacters.EQL; @@ -29,6 +28,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; +import java.text.MessageFormat; import java.util.List; import java.util.Map; import java.util.function.Function; @@ -56,6 +56,7 @@ import org.eclipse.uml2.uml.Constraint; import org.eclipse.uml2.uml.ControlFlow; import org.eclipse.uml2.uml.Dependency; import org.eclipse.uml2.uml.Duration; +import org.eclipse.uml2.uml.Element; import org.eclipse.uml2.uml.ExpansionKind; import org.eclipse.uml2.uml.ExpansionRegion; import org.eclipse.uml2.uml.Expression; @@ -148,6 +149,10 @@ public class ElementLabelProviderTest extends AbstractUMLTest { private static final String SINGLE_EXECUTION = "singleExecution"; private static final String A_PREFIX = "aPrefix"; + private static String guillemets(String value) { + return ST_LEFT + value + ST_RIGHT; + } + /** * Basic test case for {@link Usage} label. Prefix \u00ABuse\u00BB should * appear. @@ -157,9 +162,9 @@ public class ElementLabelProviderTest extends AbstractUMLTest { Usage usage = this.create(Usage.class); ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); - assertEquals(ST_LEFT + "use" + ST_RIGHT, elementLabelProvider.getLabel(usage)); + assertEquals(guillemets("use"), elementLabelProvider.getLabel(usage)); usage.setName("u1"); - assertEquals(ST_LEFT + "use" + ST_RIGHT + EOL + "u1", elementLabelProvider.getLabel(usage)); + assertEquals(guillemets("use") + EOL + "u1", elementLabelProvider.getLabel(usage)); } private ElementLabelProvider buildLabelProviderNoPrefix() { @@ -184,6 +189,41 @@ public class ElementLabelProviderTest extends AbstractUMLTest { .build(); } + private Lifeline createTypedLifeline() { + Lifeline result = this.create(Lifeline.class); + result.setName(LIFELINE); + Class clazz = this.create(Class.class); + clazz.setName(CLASS1); + Property property = this.create(Property.class); + property.setName(PROPERTY); + property.setType(clazz); + result.setRepresents(property); + return result; + } + + private Expression createExpression() { + Expression expression = this.create(Expression.class); + expression.setName(EXPRESSION); + LiteralString literalString = this.create(LiteralString.class); + literalString.setName(LITERAL_STRING); + literalString.setValue(LITERAL_STRING_VALUE); + expression.getOperands().add(literalString); + return expression; + } + + private void assertLifeline(String name, String selection, String type, Element lifeline) { + assertLabel(MessageFormat.format("{0}[{1}] : {2}", name, selection, type), lifeline); + } + + private void assertLifeline(String name, String type, Element lifeline) { + assertLabel(MessageFormat.format("{0} : {1}", name, type), lifeline); + } + + private void assertLabel(String label, Element element) { + ElementLabelProvider elementLabelProvider = buildLabelProviderNoPrefix(); + assertEquals(label, elementLabelProvider.getLabel(element)); + } + /** * Basic test case for {@link Abstraction} label. Prefix \u00ABabstraction\u00BB * should appear. @@ -193,9 +233,9 @@ public class ElementLabelProviderTest extends AbstractUMLTest { Abstraction abstraction = this.create(Abstraction.class); ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); - assertEquals(ST_LEFT + "abstraction" + ST_RIGHT, elementLabelProvider.getLabel(abstraction)); + assertEquals(guillemets("abstraction"), elementLabelProvider.getLabel(abstraction)); abstraction.setName("ab1"); - assertEquals(ST_LEFT + "abstraction" + ST_RIGHT + EOL + "ab1", elementLabelProvider.getLabel(abstraction)); + assertEquals(guillemets("abstraction") + EOL + "ab1", elementLabelProvider.getLabel(abstraction)); } @Test @@ -304,9 +344,9 @@ public class ElementLabelProviderTest extends AbstractUMLTest { Substitution substitution = this.create(Substitution.class); ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); - assertEquals(ST_LEFT + "substitute" + ST_RIGHT, elementLabelProvider.getLabel(substitution)); + assertEquals(guillemets("substitute"), elementLabelProvider.getLabel(substitution)); substitution.setName("s1"); - assertEquals(ST_LEFT + "substitute" + ST_RIGHT + EOL + "s1", elementLabelProvider.getLabel(substitution)); + assertEquals(guillemets("substitute") + EOL + "s1", elementLabelProvider.getLabel(substitution)); } /** @@ -318,9 +358,9 @@ public class ElementLabelProviderTest extends AbstractUMLTest { Manifestation manifestation = this.create(Manifestation.class); ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); - assertEquals(ST_LEFT + "manifest" + ST_RIGHT, elementLabelProvider.getLabel(manifestation)); + assertEquals(guillemets("manifest"), elementLabelProvider.getLabel(manifestation)); manifestation.setName("m1"); - assertEquals(ST_LEFT + "manifest" + ST_RIGHT + EOL + "m1", elementLabelProvider.getLabel(manifestation)); + assertEquals(guillemets("manifest") + EOL + "m1", elementLabelProvider.getLabel(manifestation)); } /** @@ -349,14 +389,14 @@ public class ElementLabelProviderTest extends AbstractUMLTest { ElementLabelProvider labelProvider = ElementLabelProvider.buildDefault(); String label0 = labelProvider.getLabel(classOneStereotype); - assertEquals(ST_LEFT + "Utility" + ST_RIGHT + EOL + classOneStereotypeName, label0); + assertEquals(guillemets("Utility") + EOL + classOneStereotypeName, label0); String classTwoStereotypeName = "ClassTwoStereotypes"; Class classTwoStereotype = allContainedObjectOfType(umlResource, Class.class) .filter(c -> classTwoStereotypeName.equals(c.getName())).findFirst().orElseThrow(); String label2 = labelProvider.getLabel(classTwoStereotype); - assertEquals(ST_LEFT + "Auxiliary, Focus" + ST_RIGHT + EOL + classTwoStereotypeName, label2); + assertEquals(guillemets("Auxiliary, Focus") + EOL + classTwoStereotypeName, label2); } /** @@ -367,19 +407,19 @@ public class ElementLabelProviderTest extends AbstractUMLTest { PackageImport element = this.create(PackageImport.class); ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); - assertEquals(ST_LEFT + "import" + ST_RIGHT, elementLabelProvider.getLabel(element)); + assertEquals(guillemets("import"), elementLabelProvider.getLabel(element)); // Label is not related to source or target. element.setImportedPackage(this.createNamedElement(Package.class, "Any")); - assertEquals(ST_LEFT + "import" + ST_RIGHT, elementLabelProvider.getLabel(element)); + assertEquals(guillemets("import"), elementLabelProvider.getLabel(element)); element.setVisibility(VisibilityKind.PRIVATE_LITERAL); String accessKeyword = "access"; - assertEquals(ST_LEFT + accessKeyword + ST_RIGHT, elementLabelProvider.getLabel(element)); + assertEquals(guillemets(accessKeyword), elementLabelProvider.getLabel(element)); element.setVisibility(VisibilityKind.PACKAGE_LITERAL); - assertEquals(ST_LEFT + accessKeyword + ST_RIGHT, elementLabelProvider.getLabel(element)); + assertEquals(guillemets(accessKeyword), elementLabelProvider.getLabel(element)); element.setVisibility(VisibilityKind.PROTECTED_LITERAL); - assertEquals(ST_LEFT + accessKeyword + ST_RIGHT, elementLabelProvider.getLabel(element)); + assertEquals(guillemets(accessKeyword), elementLabelProvider.getLabel(element)); } /** @@ -390,12 +430,12 @@ public class ElementLabelProviderTest extends AbstractUMLTest { PackageMerge element = this.create(PackageMerge.class); ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); - assertEquals(ST_LEFT + "merge" + ST_RIGHT, elementLabelProvider.getLabel(element)); + assertEquals(guillemets("merge"), elementLabelProvider.getLabel(element)); // Label is not related to source or target. element.setMergedPackage(this.createNamedElement(org.eclipse.uml2.uml.Package.class, "M1")); element.setReceivingPackage(this.createNamedElement(org.eclipse.uml2.uml.Package.class, "M2")); - assertEquals(ST_LEFT + "merge" + ST_RIGHT, elementLabelProvider.getLabel(element)); + assertEquals(guillemets("merge"), elementLabelProvider.getLabel(element)); } @Test @@ -456,9 +496,9 @@ public class ElementLabelProviderTest extends AbstractUMLTest { Collaboration collaboration = this.create(Collaboration.class); ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); - assertEquals(ST_LEFT + "collaboration" + ST_RIGHT, elementLabelProvider.getLabel(collaboration)); + assertEquals(guillemets("collaboration"), elementLabelProvider.getLabel(collaboration)); collaboration.setName(C1_NAME); - assertEquals(ST_LEFT + "collaboration" + ST_RIGHT + EOL + C1_NAME, + assertEquals(guillemets("collaboration") + EOL + C1_NAME, elementLabelProvider.getLabel(collaboration)); } @@ -471,9 +511,9 @@ public class ElementLabelProviderTest extends AbstractUMLTest { Activity activity = this.create(Activity.class); ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); - assertEquals(ST_LEFT + ACTIVITY + ST_RIGHT, elementLabelProvider.getLabel(activity)); + assertEquals(guillemets(ACTIVITY), elementLabelProvider.getLabel(activity)); activity.setName("a1"); - assertEquals(ST_LEFT + ACTIVITY + ST_RIGHT + EOL + "a1", elementLabelProvider.getLabel(activity)); + assertEquals(guillemets(ACTIVITY) + EOL + "a1", elementLabelProvider.getLabel(activity)); } /** @@ -503,9 +543,9 @@ public class ElementLabelProviderTest extends AbstractUMLTest { FunctionBehavior functionBehavior = this.create(FunctionBehavior.class); ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); - assertEquals(ST_LEFT + "functionBehavior" + ST_RIGHT, elementLabelProvider.getLabel(functionBehavior)); + assertEquals(guillemets("functionBehavior"), elementLabelProvider.getLabel(functionBehavior)); functionBehavior.setName("fb1"); - assertEquals(ST_LEFT + "functionBehavior" + ST_RIGHT + EOL + "fb1", + assertEquals(guillemets("functionBehavior") + EOL + "fb1", elementLabelProvider.getLabel(functionBehavior)); } @@ -514,9 +554,9 @@ public class ElementLabelProviderTest extends AbstractUMLTest { OpaqueBehavior opaqueBehavior = this.create(OpaqueBehavior.class); ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); - assertEquals(ST_LEFT + "opaqueBehavior" + ST_RIGHT, elementLabelProvider.getLabel(opaqueBehavior)); + assertEquals(guillemets("opaqueBehavior"), elementLabelProvider.getLabel(opaqueBehavior)); opaqueBehavior.setName("ob1"); - assertEquals(ST_LEFT + "opaqueBehavior" + ST_RIGHT + EOL + "ob1", + assertEquals(guillemets("opaqueBehavior") + EOL + "ob1", elementLabelProvider.getLabel(opaqueBehavior)); } @@ -525,9 +565,9 @@ public class ElementLabelProviderTest extends AbstractUMLTest { Interaction interaction = this.create(Interaction.class); ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); - assertEquals(ST_LEFT + "interaction" + ST_RIGHT, elementLabelProvider.getLabel(interaction)); + assertEquals(guillemets("interaction"), elementLabelProvider.getLabel(interaction)); interaction.setName("i1"); - assertEquals(ST_LEFT + "interaction" + ST_RIGHT + EOL + "i1", elementLabelProvider.getLabel(interaction)); + assertEquals(guillemets("interaction") + EOL + "i1", elementLabelProvider.getLabel(interaction)); } @Test @@ -535,9 +575,9 @@ public class ElementLabelProviderTest extends AbstractUMLTest { StateMachine stateMachine = this.create(StateMachine.class); ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); - assertEquals(ST_LEFT + "stateMachine" + ST_RIGHT, elementLabelProvider.getLabel(stateMachine)); + assertEquals(guillemets("stateMachine"), elementLabelProvider.getLabel(stateMachine)); stateMachine.setName("sm1"); - assertEquals(ST_LEFT + "stateMachine" + ST_RIGHT + EOL + "sm1", elementLabelProvider.getLabel(stateMachine)); + assertEquals(guillemets("stateMachine") + EOL + "sm1", elementLabelProvider.getLabel(stateMachine)); } @Test @@ -545,9 +585,9 @@ public class ElementLabelProviderTest extends AbstractUMLTest { ProtocolStateMachine protocolStateMachine = this.create(ProtocolStateMachine.class); ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); - assertEquals(ST_LEFT + "protocol" + ST_RIGHT, elementLabelProvider.getLabel(protocolStateMachine)); + assertEquals(guillemets("protocol"), elementLabelProvider.getLabel(protocolStateMachine)); protocolStateMachine.setName("psm1"); - assertEquals(ST_LEFT + "protocol" + ST_RIGHT + EOL + "psm1", + assertEquals(guillemets("protocol") + EOL + "psm1", elementLabelProvider.getLabel(protocolStateMachine)); } @@ -556,9 +596,9 @@ public class ElementLabelProviderTest extends AbstractUMLTest { InformationFlow informationFlow = this.create(InformationFlow.class); ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); - assertEquals(ST_LEFT + FLOW + ST_RIGHT, elementLabelProvider.getLabel(informationFlow)); + assertEquals(guillemets(FLOW), elementLabelProvider.getLabel(informationFlow)); informationFlow.setName(IF1); - assertEquals(ST_LEFT + FLOW + ST_RIGHT + EOL + IF1, elementLabelProvider.getLabel(informationFlow)); + assertEquals(guillemets(FLOW) + EOL + IF1, elementLabelProvider.getLabel(informationFlow)); // Test that conveyeds Elements name are displayed Class class1 = this.create(Class.class); @@ -566,7 +606,7 @@ public class ElementLabelProviderTest extends AbstractUMLTest { Class class2 = this.create(Class.class); class2.setName(CLASS2); informationFlow.getConveyeds().addAll(List.of(class1, class2)); - assertEquals(ST_LEFT + FLOW + ST_RIGHT + EOL + CLASS1 + ", " + CLASS2 + EOL + IF1, + assertEquals(guillemets(FLOW) + EOL + CLASS1 + ", " + CLASS2 + EOL + IF1, elementLabelProvider.getLabel(informationFlow)); // Test that conveyeds Elements name are displayed, even if the InformationFlow @@ -574,7 +614,7 @@ public class ElementLabelProviderTest extends AbstractUMLTest { InformationFlow informationFlow2 = this.create(InformationFlow.class); informationFlow2.getConveyeds().addAll(List.of(class1, class2)); - assertEquals(ST_LEFT + FLOW + ST_RIGHT + UMLCharacters.EOL + "Class1, Class2", + assertEquals(guillemets(FLOW) + UMLCharacters.EOL + "Class1, Class2", elementLabelProvider.getLabel(informationFlow2)); } @@ -583,9 +623,9 @@ public class ElementLabelProviderTest extends AbstractUMLTest { Component element = this.create(Component.class); ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); - assertEquals(ST_LEFT + "component" + ST_RIGHT, elementLabelProvider.getLabel(element)); + assertEquals(guillemets("component"), elementLabelProvider.getLabel(element)); element.setName("comp"); - assertEquals(ST_LEFT + "component" + ST_RIGHT + EOL + "comp", elementLabelProvider.getLabel(element)); + assertEquals(guillemets("component") + EOL + "comp", elementLabelProvider.getLabel(element)); } /** @@ -605,9 +645,9 @@ public class ElementLabelProviderTest extends AbstractUMLTest { Include element = this.create(Include.class); ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); - assertEquals(ST_LEFT + "include" + ST_RIGHT, elementLabelProvider.getLabel(element)); + assertEquals(guillemets("include"), elementLabelProvider.getLabel(element)); element.setName("incl"); - assertEquals(ST_LEFT + "include" + ST_RIGHT + EOL + "incl", elementLabelProvider.getLabel(element)); + assertEquals(guillemets("include") + EOL + "incl", elementLabelProvider.getLabel(element)); } @Test @@ -615,9 +655,9 @@ public class ElementLabelProviderTest extends AbstractUMLTest { Interface element = this.create(Interface.class); ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); - assertEquals(ST_LEFT + "interface" + ST_RIGHT, elementLabelProvider.getLabel(element)); + assertEquals(guillemets("interface"), elementLabelProvider.getLabel(element)); element.setName("inter"); - assertEquals(ST_LEFT + "interface" + ST_RIGHT + EOL + "inter", elementLabelProvider.getLabel(element)); + assertEquals(guillemets("interface") + EOL + "inter", elementLabelProvider.getLabel(element)); } @Test @@ -800,9 +840,9 @@ public class ElementLabelProviderTest extends AbstractUMLTest { ExpansionRegion expansionRegion = this.create(ExpansionRegion.class); ExpansionKind mode = expansionRegion.getMode(); ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); - assertEquals(ST_LEFT + mode.getName() + ST_RIGHT, elementLabelProvider.getLabel(expansionRegion)); + assertEquals(guillemets(mode.getName()), elementLabelProvider.getLabel(expansionRegion)); expansionRegion.setMode(ExpansionKind.PARALLEL_LITERAL); - assertEquals(ST_LEFT + ExpansionKind.PARALLEL_LITERAL.getName() + ST_RIGHT, + assertEquals(guillemets(ExpansionKind.PARALLEL_LITERAL.getName()), elementLabelProvider.getLabel(expansionRegion)); } @@ -832,189 +872,132 @@ public class ElementLabelProviderTest extends AbstractUMLTest { public void testStructuredActivityNodeLabel() { StructuredActivityNode structuredActivityNode = this.create(StructuredActivityNode.class); ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); - assertEquals(ST_LEFT + STRUCTURED + ST_RIGHT, elementLabelProvider.getLabel(structuredActivityNode)); + assertEquals(guillemets(STRUCTURED), elementLabelProvider.getLabel(structuredActivityNode)); } @Test public void testLoopNodeLabel() { LoopNode loopNode = this.create(LoopNode.class); ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); - assertEquals(ST_LEFT + LOOP_NODE + ST_RIGHT, elementLabelProvider.getLabel(loopNode)); + assertEquals(guillemets(LOOP_NODE), elementLabelProvider.getLabel(loopNode)); } @Test public void testSequenceNodeLabel() { SequenceNode sequenceNode = this.create(SequenceNode.class); ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); - assertEquals(ST_LEFT + SEQUENCE + ST_RIGHT, elementLabelProvider.getLabel(sequenceNode)); + assertEquals(guillemets(SEQUENCE), elementLabelProvider.getLabel(sequenceNode)); } @Test public void testConditionalNodeLabel() { ConditionalNode conditionalNode = this.create(ConditionalNode.class); ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); - assertEquals(ST_LEFT + CONDITIONAL + ST_RIGHT, elementLabelProvider.getLabel(conditionalNode)); + assertEquals(guillemets(CONDITIONAL), elementLabelProvider.getLabel(conditionalNode)); } @Test public void testLifelineWithNameNoRepresents() { Lifeline lifeline = this.create(Lifeline.class); lifeline.setName(LIFELINE); - ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); - assertEquals(LIFELINE, elementLabelProvider.getLabel(lifeline)); + assertLabel(LIFELINE, lifeline); } @Test public void testLifelineWithNoNameNoRepresents() { Lifeline lifeline = this.create(Lifeline.class); - ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); - assertEquals(EMPTY, elementLabelProvider.getLabel(lifeline)); + assertLabel(EMPTY, lifeline); } @Test public void testLifelineWithNameAndRepresentsNoSelector() { - Lifeline lifeline = this.create(Lifeline.class); - lifeline.setName(LIFELINE); - Class clazz = this.create(Class.class); - clazz.setName(CLASS1); - Property property = this.create(Property.class); - property.setName(PROPERTY); - property.setType(clazz); - lifeline.setRepresents(property); - ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); - assertEquals(PROPERTY + SPACE + D_DOTS + SPACE + CLASS1, elementLabelProvider.getLabel(lifeline)); + assertLifeline(PROPERTY, CLASS1, createTypedLifeline()); } @Test public void testLifelineWithNameAndRepresentsAndLiteralStringSelector() { - Lifeline lifeline = this.create(Lifeline.class); - lifeline.setName(LIFELINE); - Class clazz = this.create(Class.class); - clazz.setName(CLASS1); - Property property = this.create(Property.class); - property.setName(PROPERTY); - property.setType(clazz); - lifeline.setRepresents(property); + Lifeline lifeline = createTypedLifeline(); LiteralString literalString = this.create(LiteralString.class); literalString.setName(LITERAL_STRING); literalString.setValue(LITERAL_STRING_VALUE); lifeline.setSelector(literalString); - ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); - assertEquals(PROPERTY + OPEN_ANGLE_BRACKET + literalString.getValue() + CLOSE_ANGLE_BRACKET + SPACE + D_DOTS - + SPACE + CLASS1, elementLabelProvider.getLabel(lifeline)); + + assertLifeline(PROPERTY, LITERAL_STRING_VALUE, CLASS1, lifeline); } + @Test public void testLifelineWithNameAndRepresentsAndExpressionSelector() { - Lifeline lifeline = this.create(Lifeline.class); - lifeline.setName(LIFELINE); - Class clazz = this.create(Class.class); - clazz.setName(CLASS1); - Property property = this.create(Property.class); - property.setName(PROPERTY); - property.setType(clazz); - lifeline.setRepresents(property); - Expression expression = this.create(Expression.class); - expression.setName(EXPRESSION); - LiteralString literalString = this.create(LiteralString.class); - literalString.setName(LITERAL_STRING); - literalString.setValue(LITERAL_STRING_VALUE); - expression.getOperands().add(literalString); - lifeline.setSelector(expression); - ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); - assertEquals(PROPERTY + SPACE + D_DOTS + SPACE + CLASS1, elementLabelProvider.getLabel(lifeline)); + Lifeline lifeline = createTypedLifeline(); + lifeline.setSelector(createExpression()); + + assertLifeline(PROPERTY, "(" + LITERAL_STRING_VALUE + ")", CLASS1, lifeline); } @Test public void testLifelineWithNameNoRepresentsAndExpressionSelector() { Lifeline lifeline = this.create(Lifeline.class); lifeline.setName(LIFELINE); - Expression expression = this.create(Expression.class); - expression.setName(EXPRESSION); - LiteralString literalString = this.create(LiteralString.class); - literalString.setName(LITERAL_STRING); - literalString.setValue(LITERAL_STRING_VALUE); - expression.getOperands().add(literalString); - lifeline.setSelector(expression); - ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); - assertEquals("", elementLabelProvider.getLabel(lifeline)); + lifeline.setSelector(createExpression()); + + assertLabel(LIFELINE, lifeline); } @Test public void testLifelineWithNameAndRepresentsAndOpaqueExpressionSelector() { - Lifeline lifeline = this.create(Lifeline.class); - lifeline.setName(LIFELINE); - Class clazz = this.create(Class.class); - clazz.setName(CLASS1); - Property property = this.create(Property.class); - property.setName(PROPERTY); - property.setType(clazz); - lifeline.setRepresents(property); + Lifeline lifeline = createTypedLifeline(); + OpaqueExpression expression = this.create(OpaqueExpression.class); expression.setName(EXPRESSION); expression.getLanguages().add("JAVA"); expression.getBodies().add("1 + 1"); lifeline.setSelector(expression); - ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); - assertEquals(PROPERTY + SPACE + D_DOTS + SPACE + CLASS1, elementLabelProvider.getLabel(lifeline)); + + assertLifeline(PROPERTY, "1 + 1", CLASS1, lifeline); } @Test public void testLifelineWithNameAndRepresentsAndTimingExpression() { - Lifeline lifeline = this.create(Lifeline.class); - lifeline.setName(LIFELINE); - Class clazz = this.create(Class.class); - clazz.setName(CLASS1); - Property property = this.create(Property.class); - property.setName(PROPERTY); - property.setType(clazz); - lifeline.setRepresents(property); + Lifeline lifeline = createTypedLifeline(); + TimeExpression expression = this.create(TimeExpression.class); expression.setName(EXPRESSION); TimeObservation timeObservation = this.create(TimeObservation.class); timeObservation.setName("MyTimeObservation"); expression.getObservations().add(timeObservation); lifeline.setSelector(expression); - ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); - assertEquals(PROPERTY + SPACE + D_DOTS + SPACE + CLASS1, elementLabelProvider.getLabel(lifeline)); + + assertLifeline(PROPERTY, "MyTimeObservation", CLASS1, lifeline); } - @Test - public void testLifelineWithNameAndRepresentsAndInterval() { - Lifeline lifeline = this.create(Lifeline.class); - lifeline.setName(LIFELINE); - Class clazz = this.create(Class.class); - clazz.setName(CLASS1); - Property property = this.create(Property.class); - property.setName(PROPERTY); - property.setType(clazz); - lifeline.setRepresents(property); + private Interval createInterval() { Interval interval = this.create(Interval.class); interval.setName(EXPRESSION); LiteralInteger intervalMin = this.create(LiteralInteger.class); intervalMin.setValue(0); - interval.setMin(interval); + interval.setMin(intervalMin); LiteralInteger intervalMax = this.create(LiteralInteger.class); intervalMax.setValue(10); - lifeline.setSelector(interval); - ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); - assertEquals(PROPERTY + SPACE + D_DOTS + SPACE + CLASS1, elementLabelProvider.getLabel(lifeline)); + interval.setMax(intervalMax); + return interval; + } + + @Test + public void testLifelineWithNameAndRepresentsAndInterval() { + Lifeline lifeline = createTypedLifeline(); + lifeline.setSelector(createInterval()); + + assertLifeline(PROPERTY, "0..10", CLASS1, lifeline); } @Test public void testLifelineWithNameNoRepresentsAndInterval() { Lifeline lifeline = this.create(Lifeline.class); lifeline.setName(LIFELINE); - Interval interval = this.create(Interval.class); - interval.setName(EXPRESSION); - LiteralInteger intervalMin = this.create(LiteralInteger.class); - intervalMin.setValue(0); - interval.setMin(interval); - LiteralInteger intervalMax = this.create(LiteralInteger.class); - intervalMax.setValue(10); - lifeline.setSelector(interval); - ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); - assertEquals(LIFELINE, elementLabelProvider.getLabel(lifeline)); + lifeline.setSelector(createInterval()); + + // No property to select from + assertLabel(LIFELINE, lifeline); } @Test @@ -1024,6 +1007,7 @@ public class ElementLabelProviderTest extends AbstractUMLTest { Property property = this.create(Property.class); property.setName(PROPERTY); lifeline.setRepresents(property); + ElementLabelProvider elementLabelProvider = this.buildLabelProviderNoPrefix(); assertEquals(PROPERTY, elementLabelProvider.getLabel(lifeline)); } diff --git a/plugins/org.eclipse.papyrus.uml.domain.services/META-INF/MANIFEST.MF b/plugins/org.eclipse.papyrus.uml.domain.services/META-INF/MANIFEST.MF index 5a322a2b161de1e24130f5d266119bed127beb35..1e6b9400c5b8ee4b1d827d3a620399eb8cf7c7c4 100644 --- a/plugins/org.eclipse.papyrus.uml.domain.services/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.papyrus.uml.domain.services/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.papyrus.uml.domain.services -Bundle-Version: 0.23.0.qualifier +Bundle-Version: 0.24.0 Bundle-Localization: plugin Automatic-Module-Name: org.eclipse.papyrus.uml.domain.services Bundle-RequiredExecutionEnvironment: JavaSE-17 diff --git a/plugins/org.eclipse.papyrus.uml.domain.services/pom.xml b/plugins/org.eclipse.papyrus.uml.domain.services/pom.xml index 5aea327540693b55022a0253f66bde151c593f89..cb9f1dbb4179d0d6d0a39339ac23dddfdfca13fa 100644 --- a/plugins/org.eclipse.papyrus.uml.domain.services/pom.xml +++ b/plugins/org.eclipse.papyrus.uml.domain.services/pom.xml @@ -7,7 +7,7 @@ <parent> <groupId>org.eclipse.papyrus.domainservices</groupId> <artifactId>parent</artifactId> - <version>0.23.0-SNAPSHOT</version> + <version>0.24.0</version> <relativePath>../../parent</relativePath> </parent> diff --git a/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/UMLHelper.java b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/UMLHelper.java index 381aa66cb6c74f77cae15c53b6c60ea8ddec1ff6..1673305b6790fba74fd51ef32d7498285aaae068 100644 --- a/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/UMLHelper.java +++ b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/UMLHelper.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022, 2023 CEA, Obeo. + * Copyright (c) 2022, 2024 CEA List, Obeo. * This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at @@ -12,8 +12,16 @@ *******************************************************************************/ package org.eclipse.papyrus.uml.domain.services; +import java.util.function.BiFunction; + +import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.uml2.uml.Component; +import org.eclipse.uml2.uml.Element; +import org.eclipse.uml2.uml.Namespace; +import org.eclipse.uml2.uml.Package; +import org.eclipse.uml2.uml.PackageableElement; import org.eclipse.uml2.uml.UMLPackage; /** @@ -50,4 +58,65 @@ public final class UMLHelper { return eClass; } + /** + * Returns the closest container of {@link PackageableElement} in containment. + * <p> + * Result can be {@link Package} or {@link Component}. + * </p> + * + * @param element + * object to get container from + * @return {@link Package} or {@link Component} or null. + */ + public static Namespace getPackagedContainer(Element element) { + Namespace result = null; + if (element instanceof Package pkg) { + result = pkg; + } else if (element instanceof Component cmp) { + result = cmp; + } else if (element != null) { + result = getPackagedContainer(element.getOwner()); + } + return result; + } + + /** + * Returns the closest {@link PackageableElement} containment list. + * <p> + * Result can be 'packagedElement' of {@link Package} or {@link Component}. + * </p> + * + * @param element + * object to get container from + * @return containment list or null. + */ + public static EList<PackageableElement> getPackagedContainment(Element element) { + Namespace container = getPackagedContainer(element); + EList<PackageableElement> result = null; + if (container instanceof Package pkg) { + result = pkg.getPackagedElements(); + } else if (container instanceof Component cmp) { + result = cmp.getPackagedElements(); + } + return result; + } + + /** + * Returns a factory to create new {@link PackageableElement} in. + * + * @param element + * object to get container factory from + * @return factory of PackageableElement + */ + public static BiFunction<String, EClass, PackageableElement> getPackagedCreator(Element element) { + Namespace container = getPackagedContainer(element); + BiFunction<String, EClass, PackageableElement> result = null; + if (container instanceof Package pkg) { + result = (name, type) -> pkg.createPackagedElement(name, type); + } else if (container instanceof Component cmp) { + result = (name, type) -> cmp.createPackagedElement(name, type); + } + return result; + } + } diff --git a/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/create/ElementConfigurer.java b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/create/ElementConfigurer.java index 6c0f66d97a4986b55800bb1982c2c5fb8b7769a7..3b49cf2ee4ef1ad80e65178c2250ac390b14a0f0 100644 --- a/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/create/ElementConfigurer.java +++ b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/create/ElementConfigurer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022, 2023 CEA LIST, Obeo. + * Copyright (c) 2022, 2024 CEA LIST, Obeo. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -13,7 +13,14 @@ *******************************************************************************/ package org.eclipse.papyrus.uml.domain.services.create; +import java.util.List; +import java.util.function.BiFunction; +import java.util.function.Consumer; + +import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.papyrus.uml.domain.services.UMLHelper; import org.eclipse.papyrus.uml.domain.services.labels.ElementDefaultNameProvider; import org.eclipse.uml2.uml.AcceptCallAction; import org.eclipse.uml2.uml.Action; @@ -34,20 +41,20 @@ import org.eclipse.uml2.uml.DestroyLinkAction; import org.eclipse.uml2.uml.DestroyObjectAction; import org.eclipse.uml2.uml.Duration; import org.eclipse.uml2.uml.DurationConstraint; -import org.eclipse.uml2.uml.DurationInterval; import org.eclipse.uml2.uml.Element; import org.eclipse.uml2.uml.ExecutionOccurrenceSpecification; +import org.eclipse.uml2.uml.ExecutionSpecification; import org.eclipse.uml2.uml.ExtensionEnd; import org.eclipse.uml2.uml.InputPin; -import org.eclipse.uml2.uml.Interaction; +import org.eclipse.uml2.uml.InteractionFragment; import org.eclipse.uml2.uml.InteractionOperand; import org.eclipse.uml2.uml.Interval; import org.eclipse.uml2.uml.IntervalConstraint; -import org.eclipse.uml2.uml.LiteralInteger; -import org.eclipse.uml2.uml.Model; +import org.eclipse.uml2.uml.Lifeline; import org.eclipse.uml2.uml.NamedElement; import org.eclipse.uml2.uml.OpaqueExpression; import org.eclipse.uml2.uml.OutputPin; +import org.eclipse.uml2.uml.PackageableElement; import org.eclipse.uml2.uml.Pin; import org.eclipse.uml2.uml.Port; import org.eclipse.uml2.uml.Property; @@ -66,11 +73,11 @@ import org.eclipse.uml2.uml.StartObjectBehaviorAction; import org.eclipse.uml2.uml.TestIdentityAction; import org.eclipse.uml2.uml.TimeConstraint; import org.eclipse.uml2.uml.TimeExpression; -import org.eclipse.uml2.uml.TimeInterval; import org.eclipse.uml2.uml.UMLFactory; import org.eclipse.uml2.uml.UMLPackage; import org.eclipse.uml2.uml.UnmarshallAction; import org.eclipse.uml2.uml.UseCase; +import org.eclipse.uml2.uml.ValueSpecification; import org.eclipse.uml2.uml.ValueSpecificationAction; import org.eclipse.uml2.uml.util.UMLSwitch; @@ -248,26 +255,18 @@ public class ElementConfigurer implements IElementConfigurer { */ @Override public Void caseDurationConstraint(DurationConstraint durationConstraint) { + addParentToConstrained(durationConstraint); + fillInterval(durationConstraint, UMLPackage.eINSTANCE.getDurationInterval(), + UMLPackage.eINSTANCE.getDuration(), + terminal -> ((Duration) terminal).setExpr(UMLFactory.eINSTANCE.createLiteralInteger())); + return super.caseDurationConstraint(durationConstraint); + } + + private void addParentToConstrained(Constraint constraint) { if (this.parent instanceof Element) { - durationConstraint.getConstrainedElements().clear(); - durationConstraint.getConstrainedElements().add((Element) this.parent); + constraint.getConstrainedElements().clear(); + constraint.getConstrainedElements().add((Element) this.parent); } - DurationInterval durationInterval = UMLFactory.eINSTANCE.createDurationInterval(); - Model minMaxContainer = durationConstraint.getModel(); - if (minMaxContainer != null) { - Duration durationMin = (Duration) minMaxContainer.createPackagedElement("d1", - UMLPackage.eINSTANCE.getDuration()); - Duration durationMax = (Duration) minMaxContainer.createPackagedElement("d2", - UMLPackage.eINSTANCE.getDuration()); - LiteralInteger integerMin = UMLFactory.eINSTANCE.createLiteralInteger(); - LiteralInteger integerMax = UMLFactory.eINSTANCE.createLiteralInteger(); - durationMin.setExpr(integerMin); - durationMax.setExpr(integerMax); - durationInterval.setMin(durationMin); - durationInterval.setMax(durationMax); - } - durationConstraint.setSpecification(durationInterval); - return super.caseDurationConstraint(durationConstraint); } /** @@ -284,22 +283,33 @@ public class ElementConfigurer implements IElementConfigurer { */ @Override public Void caseIntervalConstraint(IntervalConstraint intervalConstraint) { - // Avoid overriding existing specification (specification is already set for - // TimeConstraint, DurationConstraint) - if (intervalConstraint.getSpecification() == null) { - Interval interval = UMLFactory.eINSTANCE.createInterval(); - Model minMaxContainer = intervalConstraint.getModel(); - if (minMaxContainer != null) { - LiteralInteger literalIntegerMin = (LiteralInteger) minMaxContainer.createPackagedElement("i1", - UMLPackage.eINSTANCE.getLiteralInteger()); - LiteralInteger literalIntegerMax = (LiteralInteger) minMaxContainer.createPackagedElement("i2", - UMLPackage.eINSTANCE.getLiteralInteger()); - interval.setMin(literalIntegerMin); - interval.setMax(literalIntegerMax); + fillInterval(intervalConstraint, UMLPackage.eINSTANCE.getInterval(), + UMLPackage.eINSTANCE.getLiteralInteger(), null); + return super.caseIntervalConstraint(intervalConstraint); + } + + private ValueSpecification fillInterval(IntervalConstraint container, EClass intervalType, + EClass terminalType, Consumer<ValueSpecification> terminalInit) { + caseNamedElement(container); + ValueSpecification existing = container.getSpecification(); + BiFunction<String, EClass, PackageableElement> creator = UMLHelper.getPackagedCreator(container); + if (existing != null) { // exists or impossible to create. + return existing; + } + + Interval result = (Interval) UMLFactory.eINSTANCE.create(intervalType); + container.setSpecification(result); // containment + + if (creator != null) { + result.setMin((ValueSpecification) creator.apply("Min" + container.getName(), terminalType)); + result.setMax((ValueSpecification) creator.apply("Max" + container.getName(), terminalType)); + if (terminalInit != null) { + terminalInit.accept(result.getMin()); + terminalInit.accept(result.getMax()); } - intervalConstraint.setSpecification(interval); } - return super.caseIntervalConstraint(intervalConstraint); + + return result; } @Override @@ -451,25 +461,10 @@ public class ElementConfigurer implements IElementConfigurer { */ @Override public Void caseTimeConstraint(TimeConstraint timeConstraint) { - if (this.parent instanceof Element) { - timeConstraint.getConstrainedElements().clear(); - timeConstraint.getConstrainedElements().add((Element) this.parent); - } - TimeInterval timeInterval = UMLFactory.eINSTANCE.createTimeInterval(); - Model minMaxContainer = timeConstraint.getModel(); - if (minMaxContainer != null) { - TimeExpression timeExpressionMin = (TimeExpression) minMaxContainer.createPackagedElement("t1", - UMLPackage.eINSTANCE.getTimeExpression()); - TimeExpression timeExpressionMax = (TimeExpression) minMaxContainer.createPackagedElement("t2", - UMLPackage.eINSTANCE.getTimeExpression()); - LiteralInteger literalIntegerMin = UMLFactory.eINSTANCE.createLiteralInteger(); - LiteralInteger literalIntegerMax = UMLFactory.eINSTANCE.createLiteralInteger(); - timeExpressionMin.setExpr(literalIntegerMin); - timeExpressionMax.setExpr(literalIntegerMax); - timeInterval.setMin(timeExpressionMin); - timeInterval.setMax(timeExpressionMax); - } - timeConstraint.setSpecification(timeInterval); + addParentToConstrained(timeConstraint); + fillInterval(timeConstraint, UMLPackage.eINSTANCE.getTimeInterval(), + UMLPackage.eINSTANCE.getTimeExpression(), + terminal -> ((TimeExpression) terminal).setExpr(UMLFactory.eINSTANCE.createLiteralInteger())); return super.caseTimeConstraint(timeConstraint); } @@ -497,28 +492,42 @@ public class ElementConfigurer implements IElementConfigurer { */ @Override public Void caseActionExecutionSpecification(ActionExecutionSpecification actionExecutionSpecification) { - if (actionExecutionSpecification.getOwner() instanceof Interaction) { - /* - * Need to get the name of the ExecutionSpecification first, otherwise we can't - * set the ExecutionOccurrenceSpecification names. - */ - String executionName = new ElementDefaultNameProvider().getDefaultName(actionExecutionSpecification, - this.parent); - Interaction interaction = (Interaction) actionExecutionSpecification.getOwner(); - ExecutionOccurrenceSpecification start = UMLFactory.eINSTANCE.createExecutionOccurrenceSpecification(); - interaction.getFragments().add(start); - start.setName(executionName + "Start"); - start.setExecution(actionExecutionSpecification); - actionExecutionSpecification.setStart(start); - ExecutionOccurrenceSpecification finish = UMLFactory.eINSTANCE.createExecutionOccurrenceSpecification(); - interaction.getFragments().add(finish); - finish.setName(executionName + "Finish"); - finish.setExecution(actionExecutionSpecification); - actionExecutionSpecification.setFinish(finish); - } + /* + * Need to get the name of the ExecutionSpecification first, otherwise we can't set the + * ExecutionOccurrenceSpecification names. + */ + caseNamedElement(actionExecutionSpecification); + addExecutionEvent(actionExecutionSpecification, UMLPackage.eINSTANCE.getExecutionSpecification_Start()); + addExecutionEvent(actionExecutionSpecification, UMLPackage.eINSTANCE.getExecutionSpecification_Finish()); + return super.caseExecutionSpecification(actionExecutionSpecification); } + private static void addExecutionEvent(ExecutionSpecification execution, EReference eventReference) { + List<InteractionFragment> containment; + if (execution.getEnclosingOperand() != null) { + containment = execution.getEnclosingOperand().getFragments(); + } else if (execution.getEnclosingInteraction() != null) { + containment = execution.getEnclosingInteraction().getFragments(); + } else { // no container + return; + } + ExecutionOccurrenceSpecification end = UMLFactory.eINSTANCE.createExecutionOccurrenceSpecification(); + containment.add(end); + String suffix = "Start"; + if (eventReference == UMLPackage.eINSTANCE.getExecutionSpecification_Finish()) { + suffix = "Finish"; + } + end.setName(execution.getName() + suffix); + end.setExecution(execution); + execution.eSet(eventReference, end); + + List<Lifeline> covereds = execution.getCovereds(); + if (!covereds.isEmpty()) { + end.getCovereds().add(covereds.get(0)); + } + } + /** * UML spec indicates that an ExtensionEnd should have its Aggregation set to * "Composite". diff --git a/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/destroy/ElementDependencyCollector.java b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/destroy/ElementDependencyCollector.java index 43d052bb28db922ed30976c2498c4217ecaaf0f7..f47eb1ff21bdee2249465c7bf3bc7286e581d5b2 100644 --- a/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/destroy/ElementDependencyCollector.java +++ b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/destroy/ElementDependencyCollector.java @@ -1,7 +1,7 @@ /***************************************************************************** - * Copyright (c) 2022, 2023 CEA LIST, Obeo. + * Copyright (c) 2022, 2024 CEA LIST. * - * All rights reserved. This program and the accompanying materials + * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ @@ -13,29 +13,22 @@ *****************************************************************************/ package org.eclipse.papyrus.uml.domain.services.destroy; -import static java.util.stream.Collectors.toList; - import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Optional; import java.util.Set; -import java.util.stream.Stream; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EReference; -import org.eclipse.emf.ecore.EStructuralFeature.Setting; import org.eclipse.emf.ecore.util.ECrossReferenceAdapter; import org.eclipse.papyrus.uml.domain.services.internal.helpers.CollaborationHelper; -import org.eclipse.papyrus.uml.domain.services.internal.helpers.DurationConstraintHelper; -import org.eclipse.papyrus.uml.domain.services.internal.helpers.DurationObservationHelper; import org.eclipse.papyrus.uml.domain.services.internal.helpers.OccurrenceSpecificationHelper; -import org.eclipse.papyrus.uml.domain.services.internal.helpers.TimeConstraintHelper; -import org.eclipse.papyrus.uml.domain.services.internal.helpers.TimeObservationHelper; import org.eclipse.papyrus.uml.domain.services.internal.helpers.UMLService; +import org.eclipse.papyrus.uml.domain.services.internal.helpers.UMLTemporalHelper; import org.eclipse.uml2.uml.ActivityNode; import org.eclipse.uml2.uml.Association; import org.eclipse.uml2.uml.Classifier; @@ -43,13 +36,13 @@ import org.eclipse.uml2.uml.Collaboration; import org.eclipse.uml2.uml.CombinedFragment; import org.eclipse.uml2.uml.Connector; import org.eclipse.uml2.uml.ConnectorEnd; -import org.eclipse.uml2.uml.DestructionOccurrenceSpecification; import org.eclipse.uml2.uml.DirectedRelationship; import org.eclipse.uml2.uml.Element; import org.eclipse.uml2.uml.ExecutionSpecification; -import org.eclipse.uml2.uml.Interaction; import org.eclipse.uml2.uml.InteractionFragment; import org.eclipse.uml2.uml.InteractionOperand; +import org.eclipse.uml2.uml.Interval; +import org.eclipse.uml2.uml.IntervalConstraint; import org.eclipse.uml2.uml.Lifeline; import org.eclipse.uml2.uml.Message; import org.eclipse.uml2.uml.MessageEnd; @@ -59,10 +52,9 @@ import org.eclipse.uml2.uml.OccurrenceSpecification; import org.eclipse.uml2.uml.Package; import org.eclipse.uml2.uml.PartDecomposition; import org.eclipse.uml2.uml.Property; -import org.eclipse.uml2.uml.TimeConstraint; -import org.eclipse.uml2.uml.TimeObservation; import org.eclipse.uml2.uml.UMLPackage; import org.eclipse.uml2.uml.UseCase; +import org.eclipse.uml2.uml.ValueSpecification; import org.eclipse.uml2.uml.Vertex; import org.eclipse.uml2.uml.util.UMLSwitch; @@ -81,7 +73,7 @@ public class ElementDependencyCollector implements IDestroyerDependencyCollector /** * Constructor. - * + * * @param theCrossReferenceAdapter * an adapter used to get inverse references */ @@ -99,34 +91,39 @@ public class ElementDependencyCollector implements IDestroyerDependencyCollector static class DestroyDependencyCollectorSwitch extends UMLSwitch<Void> { - /** - * Adapter used to get inverse references. - */ + /** Adapter used to get inverse references. */ private final ECrossReferenceAdapter crossReferenceAdapter; - /** - * Set of dependences to remove. - */ + + /** Set of dependences to remove. */ private final Set<EObject> dependentsToRemove = new HashSet<>(); /** + * Default constructor. + * * @param crossReferenceAdapter + * cross reference adapter */ DestroyDependencyCollectorSwitch(ECrossReferenceAdapter crossReferenceAdapter) { - super(); this.crossReferenceAdapter = crossReferenceAdapter; } + private void safeAdd(Element value) { + if (value != null) { + dependentsToRemove.add(value); + } + } + /** * Action to launch before deleting a {@link NamedElement}. Copy from * {@link org.eclipse.papyrus.uml.service.types.helper.advice.NamedElementHelperAdvice.getBeforeDestroyDependentsCommand(DestroyDependentsRequest)} - * + * * <pre> * This method deletes {@link DirectedRelationship} related to the named element (source or target). * </pre> - * + * * @param namedElementToDelete * the {@link NamedElement} to remove - * + * */ @Override public Void caseNamedElement(NamedElement namedElementToDelete) { @@ -172,11 +169,11 @@ public class ElementDependencyCollector implements IDestroyerDependencyCollector /** * Action to launch before deleting a {@link ConnectorEnd}. Copy from * {@link org.eclipse.papyrus.uml.service.types.helper.advice.ConnectorEndHelperAdvice.getBeforeDestroyDependentsCommand(DestroyDependentsRequest))} - * + * * <pre> * It deletes the related Connector in case this connector only has less than 2 ends left. * </pre> - * + * * @param connectorEndToDelete * the {@link NamedElement} to remove */ @@ -192,10 +189,10 @@ public class ElementDependencyCollector implements IDestroyerDependencyCollector /** * Action to launch before deleting a {@link Property}. Copy from * {@link org.eclipse.papyrus.uml.service.types.helper.advice.PropertyHelperAdvice.getBeforeDestroyDependentsCommand(DestroyDependentsRequest)} - * + * * @param propertyToDelete * the property to delete - * + * */ @Override public Void caseProperty(Property propertyToDelete) { @@ -227,28 +224,7 @@ public class ElementDependencyCollector implements IDestroyerDependencyCollector return super.caseProperty(propertyToDelete); } - /** - * Action to launch before deleting a {@link Message}. Copy from - * {@link org.eclipse.papyrus.uml.service.types.helper.advice.MessageHelperAdvice.getBeforeDestroyDependentsCommand(DestroyDependentsRequest))}. - * <p> - * Deletes the related {@link MessageEnd} when they are set and not shared with - * other elements. - * - * @param messageToDelete - * the {@link Message} to remove - */ - @Override - public Void caseMessage(Message messageToDelete) { - MessageEnd sendEvent = messageToDelete.getSendEvent(); - if (sendEvent != null && !(this.isSharedEvent(sendEvent, messageToDelete))) { - this.dependentsToRemove.add(sendEvent); - } - MessageEnd receiveEvent = messageToDelete.getReceiveEvent(); - if (receiveEvent != null && !(this.isSharedEvent(receiveEvent, messageToDelete))) { - this.dependentsToRemove.add(receiveEvent); - } - return super.caseMessage(messageToDelete); - } + @Override public Void caseElement(Element object) { @@ -260,62 +236,19 @@ public class ElementDependencyCollector implements IDestroyerDependencyCollector return super.caseElement(object); } - /** - * Tests if the {@code messageEnd} is referenced by other elements than the - * known referencer (except its container). - * <p> - * This method ignores references from other metamodels. It also ignores - * {@link Lifeline} referencers that reference the {@code messageEnd} via the - * {@link UMLPackage#getLifeline_CoveredBy()} reference. - * <p> - * This code is copied from - * {@link org.eclipse.papyrus.uml.service.types.helper.advice.MessageHelperAdvice.isSharedEvent(MessageEnd, - * EObject))}. - * - * @param messageEnd - * the message end to search the referencers from - * @param knownReferencer - * the known referencer to {@code messageEnd} - * @return {@code true} if the {@code messageEnd} is referenced by other - * elements than the known referencer, {@code false} otherwise. - */ - private boolean isSharedEvent(MessageEnd messageEnd, Message knownReferencer) { - EPackage mmPackage = messageEnd.eClass().getEPackage(); - - // Retrieve the list of elements referencing the messageEnd. - Set<EObject> crossReferences = new HashSet<EObject>(); - for (Setting setting : this.crossReferenceAdapter.getInverseReferences(messageEnd)) { - EObject eObject = setting.getEObject(); - if (!setting.getEStructuralFeature().equals(UMLPackage.eINSTANCE.getLifeline_CoveredBy())) { - if (eObject.eClass().getEPackage().equals(mmPackage)) { - crossReferences.add(eObject); - } - } - } - - // Remove the container of messageEnd. - crossReferences.remove(messageEnd.eContainer()); - // Remove the knownReferencer from the list of references. - crossReferences.remove(knownReferencer); - - // If no referencer remains in the list, the known element is the only usage and - // thus the messageEnd isn't shared. - return !(crossReferences.isEmpty()); - } - /** * Action to launch before deleting a {@link Classifier}. Copy from * {@link org.eclipse.papyrus.uml.service.types.helper.advice.ClassifierHelperAdvice.getBeforeDestroyDependentsCommand(DestroyDependentsRequest)} - * + * * <pre> * This method deletes : * - Generalization related to the Classifier (source or target). * - Association related to the Classifier (source or target type). * </pre> - * + * * @param classifierToDelete * the {@link Classifier} to remove - * + * */ @Override public Void caseClassifier(Classifier classifierToDelete) { @@ -349,10 +282,10 @@ public class ElementDependencyCollector implements IDestroyerDependencyCollector /** * Action to launch before deleting a {@link Collaboration}. Copy from * {@link org.eclipse.papyrus.uml.service.types.helper.advice.CollaborationHelperAdvice.getBeforeDestroyDependentsCommand(DestroyDependentsRequest)} - * + * * @param classifierToDelete * the {@link Collaboration} to remove - * + * */ @Override public Void caseCollaboration(Collaboration collaborationToDelete) { @@ -361,33 +294,22 @@ public class ElementDependencyCollector implements IDestroyerDependencyCollector return super.caseCollaboration(collaborationToDelete); } - /** - * Action to launch before deleting a - * {@link DestructionOccurrenceSpecification}. Copy from - * {@link org.eclipse.papyrus.uml.service.types.helper.advice.DestructionOccurrenceSpecificationEditHelperAdvice.getBeforeDestroyDependentsCommand(DestroyDependentsRequest)} - * - * @param destructionToDelete - * the {@link DestructionOccurrenceSpecification} to - * remove - */ @Override - public Void caseDestructionOccurrenceSpecification(DestructionOccurrenceSpecification destructionToDelete) { - Interaction interaction = OccurrenceSpecificationHelper.getInteraction(destructionToDelete); - - Stream<TimeConstraint> timeConstraints = OccurrenceSpecificationHelper.getTimeConstraints(interaction, - destructionToDelete); - Stream<TimeObservation> timeObservations = OccurrenceSpecificationHelper.getTimeObservations(interaction, - destructionToDelete); - - this.dependentsToRemove.addAll(Stream.concat(timeConstraints, timeObservations).collect(toList())); - return super.caseDestructionOccurrenceSpecification(destructionToDelete); - + public Void caseIntervalConstraint(IntervalConstraint interval) { + if (interval.getSpecification() instanceof Interval value) { // Only case allowed + for (ValueSpecification terminal : List.of(value.getMin(), value.getMax())) { + if (terminal != null && UMLService.isOnlyUsage(terminal, value, crossReferenceAdapter)) { + dependentsToRemove.add(terminal); + } + } + } + return super.caseIntervalConstraint(interval); } /** * Action to launch before deleting a {@link ExecutionSpecification}. Copy from * {@link org.eclipse.papyrus.uml.service.types.helper.advice.ExecutionSpecificationHelperAdvice.getBeforeDestroyDependentsCommand(DestroyDependentsRequest)} - * + * * @param esToDelete * the {@link ExecutionSpecification} to remove */ @@ -396,24 +318,47 @@ public class ElementDependencyCollector implements IDestroyerDependencyCollector // Check whether start - finish referenced OccurrenceSpecification should be // added to the dependents list OccurrenceSpecification osStart = esToDelete.getStart(); - if (OccurrenceSpecificationHelper.shouldDestroyOccurrenceSpecification(esToDelete, osStart, - this.crossReferenceAdapter) && (!(osStart instanceof MessageEnd))) { + if (OccurrenceSpecificationHelper.shouldDestroyWithExecution(esToDelete, osStart, + this.crossReferenceAdapter)) { this.dependentsToRemove.add(osStart); } OccurrenceSpecification osFinish = esToDelete.getFinish(); - if (OccurrenceSpecificationHelper.shouldDestroyOccurrenceSpecification(esToDelete, osFinish, - this.crossReferenceAdapter) && (!(osFinish instanceof MessageEnd))) { + if (OccurrenceSpecificationHelper.shouldDestroyWithExecution(esToDelete, osFinish, + this.crossReferenceAdapter)) { this.dependentsToRemove.add(osFinish); } + // add TimeElement and Duration + dependentsToRemove.addAll(UMLTemporalHelper.getTemporalElements(esToDelete, crossReferenceAdapter)); return super.caseExecutionSpecification(esToDelete); } + /** + * Action to launch before deleting a {@link Message}. Copy from + * {@link org.eclipse.papyrus.uml.service.types.helper.advice.MessageHelperAdvice.getBeforeDestroyDependentsCommand(DestroyDependentsRequest))}. + * <p> + * Deletes the related {@link MessageEnd} when they are set and not shared with other elements. + * + * @param messageToDelete + * the {@link Message} to remove + */ + @Override + public Void caseMessage(Message messageToDelete) { + safeAdd(messageToDelete.getReceiveEvent()); // Either MOS or Gate + safeAdd(messageToDelete.getSendEvent()); + + // add TimeElement and Duration + dependentsToRemove.addAll(UMLTemporalHelper.getTemporalElements(messageToDelete, crossReferenceAdapter)); + + return super.caseMessage(messageToDelete); + } + + /** * Action to launch before deleting a {@link Lifeline}. Copy from * {@link org.eclipse.papyrus.uml.service.types.helper.advice.LifelineHelperAdvice.getBeforeDestroyDependentsCommand(DestroyDependentsRequest)} - * + * * @param lifelineToDelete * the {@link Lifeline} to remove */ @@ -425,16 +370,17 @@ public class ElementDependencyCollector implements IDestroyerDependencyCollector this.dependentsToRemove.add(ift); } - // Destroy related Message - // Destroy related Message - if ((ift instanceof MessageOccurrenceSpecification) - && (((MessageOccurrenceSpecification) ift).getMessage() != null)) { - this.dependentsToRemove.add(((MessageOccurrenceSpecification) ift).getMessage()); - } - // Destroy covered OccurrenceSpecification if (ift instanceof OccurrenceSpecification) { this.dependentsToRemove.add(ift); + // Destroy related Message + if (ift instanceof MessageOccurrenceSpecification mos) { + this.dependentsToRemove.add(mos.getMessage()); + } + } + // Destroy all the interactionFragments that cover only the lifeline being deleted + if (ift.getCovereds().size() == 1) { + this.dependentsToRemove.add(ift); } } @@ -450,65 +396,28 @@ public class ElementDependencyCollector implements IDestroyerDependencyCollector /** * Action to launch before deleting a {@link OccurrenceSpecification}. Copy from * {@link org.eclipse.papyrus.uml.service.types.helper.advice.OccurrenceSpecificationHelperAdvice.getBeforeDestroyDependentsCommand(DestroyDependentsRequest)} - * + * * <pre> * Add dependents to destroy : * - related time elements * - linked general ordering * </pre> - * + * * @param osToDelete * the {@link OccurrenceSpecification} to remove */ @Override public Void caseOccurrenceSpecification(OccurrenceSpecification osToDelete) { - // look for all Execution that references this Occurrence specification - InteractionFragment containerPackage = (InteractionFragment) osToDelete.getOwner(); - if (containerPackage != null) { - Iterator<EObject> contentIterator = containerPackage.eAllContents(); - while (contentIterator.hasNext()) { - EObject currentEObject = contentIterator.next(); - if (currentEObject instanceof Message) { - Message m = (Message) currentEObject; - if (osToDelete.equals(m.getSendEvent())) { - this.dependentsToRemove.add(m); - if (m.getReceiveEvent() != null) { - this.dependentsToRemove.add(m.getReceiveEvent()); - } - } - if (osToDelete.equals(m.getReceiveEvent())) { - this.dependentsToRemove.add(m); - if (m.getSendEvent() != null) { - this.dependentsToRemove.add(m.getSendEvent()); - } - } - } - if (currentEObject instanceof ExecutionSpecification) { - ExecutionSpecification exec = (ExecutionSpecification) currentEObject; - if (osToDelete.equals(exec.getStart())) { - this.dependentsToRemove.add(exec); - if (exec.getFinish() != null && !(exec.getFinish() instanceof MessageEnd)) { - this.dependentsToRemove.add(exec.getFinish()); - } - } - if (osToDelete.equals(exec.getFinish())) { - this.dependentsToRemove.add(exec); - if (exec.getStart() != null && !(exec.getStart() instanceof MessageEnd)) { - this.dependentsToRemove.add(exec.getStart()); - } - } - } + for (Optional<ExecutionSpecification> execution : List.of( + OccurrenceSpecificationHelper.getExecutionFromStartOccurrence(osToDelete), + OccurrenceSpecificationHelper.getExecutionFromFinishOccurrence(osToDelete))) { + if (execution.isPresent()) { + dependentsToRemove.add(execution.get()); } } + // delete linked time elements - this.dependentsToRemove - .addAll(TimeObservationHelper.getTimeObservations(osToDelete, this.crossReferenceAdapter)); - this.dependentsToRemove - .addAll(TimeConstraintHelper.getTimeConstraintsOn(osToDelete, this.crossReferenceAdapter)); - this.dependentsToRemove.addAll( - DurationObservationHelper.getDurationObservationsOn(osToDelete, this.crossReferenceAdapter)); - this.dependentsToRemove - .addAll(DurationConstraintHelper.getDurationConstraintsOn(osToDelete, this.crossReferenceAdapter)); + dependentsToRemove.addAll(UMLTemporalHelper.getTemporalElements(osToDelete, crossReferenceAdapter)); // delete linked general ordering /** @@ -522,6 +431,13 @@ public class ElementDependencyCollector implements IDestroyerDependencyCollector return super.caseOccurrenceSpecification(osToDelete); } + @Override + public Void caseMessageOccurrenceSpecification(MessageOccurrenceSpecification osToDelete) { + safeAdd(osToDelete.getMessage()); + + return super.caseMessageOccurrenceSpecification(osToDelete); + } + /** * In the StateMachine, incoming and outgoing transitions are removed with the * Vertex (ex: State, PseudoState and InitialState) @@ -536,10 +452,10 @@ public class ElementDependencyCollector implements IDestroyerDependencyCollector /** * Action to launch before deleting a {@link Association}. Copy from * {@link org.eclipse.papyrus.uml.service.types.helper.advice.AssociationEditHelperAdvice.getBeforeDestroyDependentsCommand(DestroyDependentsRequest)} - * + * * @param association * the association to delete - * + * */ @Override public Void caseAssociation(Association association) { diff --git a/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/destroy/ElementDestroyer.java b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/destroy/ElementDestroyer.java index 3e6a6d44947f9680b1ad9438fae2ec034e5f525e..96327d7c9550b80d41dfb47870ac5cd15e1780a1 100644 --- a/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/destroy/ElementDestroyer.java +++ b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/destroy/ElementDestroyer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022 CEA, Obeo. + * Copyright (c) 2022, 2024 CEA List, Obeo. * This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at @@ -44,7 +44,7 @@ public class ElementDestroyer implements IDestroyer { /** * Constructor. - * + * * @param theCrossReferenceAdapter * an adapter used to get inverse references */ @@ -58,7 +58,7 @@ public class ElementDestroyer implements IDestroyer { /** * Default Constructor. - * + * * @param theCrossReferenceAdapter * an adapter used to get inverse references * @return default Constructor. @@ -80,7 +80,7 @@ public class ElementDestroyer implements IDestroyer { /** * Removes a semantic element value from its container. Inspired by - * + * * @see org.eclipse.gmf.runtime.emf.type.core.edithelper.AbstractEditHelper#getEditCommand(IEditCommandRequest, * IEditHelperAdvice[]) * @@ -122,30 +122,36 @@ public class ElementDestroyer implements IDestroyer { Set<EObject> notComputedDependencies = new LinkedHashSet<>(); notComputedDependencies.add(semanticElement); - while (!notComputedDependencies.isEmpty()) { + // Impossible to simply loop on 'notComputedDependencies' + // Collection is amended as element are analyzed. + // Remove First Iterator<EObject> iterator = notComputedDependencies.iterator(); EObject toAnalyse = iterator.next(); iterator.remove(); - EMFUtils.eAllContentStreamWithSelf(toAnalyse).filter(e -> !toDeletes.contains(e)).forEach(e -> { - Set<EObject> itemDependencies = dependencyCollector.collectDependencies(e); - for (EObject o : itemDependencies) { - if (!toDeletes.contains(o)) { - notComputedDependencies.add(o); - } - } - toDeletes.add(e); - }); + EMFUtils.eAllContentStreamWithSelf(toAnalyse) // with all sub-elements + .filter(e -> !toDeletes.contains(e)) // skip previous work + .forEach(e -> { + toDeletes.add(e); + Set<EObject> itemDependencies = dependencyCollector.collectDependencies(e); + // Amend Analysis + for (EObject o : itemDependencies) { + if (!toDeletes.contains(o)) { + notComputedDependencies.add(o); + } + } + }); } return toDeletes; } + /** * Tears down references to the object that we are destroying, from all other * objects in the resource set. - * + * * @param destructee * the object being destroyed */ @@ -174,7 +180,7 @@ public class ElementDestroyer implements IDestroyer { * Tears down outgoing unidirectional references from the object being destroyed * to all other elements in the resource set. This is required so that * reverse-reference queries will not find the destroyed object. - * + * * @param destructee * the object being destroyed */ diff --git a/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/drop/diagrams/SequenceExternalSourceToRepresentationDropBehaviorProvider.java b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/drop/diagrams/SequenceExternalSourceToRepresentationDropBehaviorProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..a3e43119546881c4af7211dff75d1cdfca0f7ca8 --- /dev/null +++ b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/drop/diagrams/SequenceExternalSourceToRepresentationDropBehaviorProvider.java @@ -0,0 +1,138 @@ +/***************************************************************************** + * Copyright (c) 2024 CEA LIST. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Obeo - Initial API and implementation + *****************************************************************************/ +package org.eclipse.papyrus.uml.domain.services.drop.diagrams; + +import java.util.Collections; +import java.util.Set; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.util.ECrossReferenceAdapter; +import org.eclipse.papyrus.uml.domain.services.EMFUtils; +import org.eclipse.papyrus.uml.domain.services.IEditableChecker; +import org.eclipse.papyrus.uml.domain.services.create.ElementConfigurer; +import org.eclipse.papyrus.uml.domain.services.create.ElementCreator; +import org.eclipse.papyrus.uml.domain.services.drop.DnDStatus; +import org.eclipse.papyrus.uml.domain.services.drop.IExternalSourceToRepresentationDropBehaviorProvider; +import org.eclipse.papyrus.uml.domain.services.modify.ElementFeatureModifier; +import org.eclipse.uml2.uml.Interaction; +import org.eclipse.uml2.uml.Lifeline; +import org.eclipse.uml2.uml.Property; +import org.eclipse.uml2.uml.Type; +import org.eclipse.uml2.uml.UMLPackage; +import org.eclipse.uml2.uml.util.UMLSwitch; + +/** + * Drop behavior provider of a semantic drop (from Model Explorer view) to a + * Sequence Diagram Element. + * + * @author <a href="mailto:glenn.plouhinec@obeo.fr">Glenn Plouhinec</a> + */ +public class SequenceExternalSourceToRepresentationDropBehaviorProvider + implements IExternalSourceToRepresentationDropBehaviorProvider { + + @Override + public DnDStatus drop(EObject droppedElement, EObject target, ECrossReferenceAdapter crossRef, + IEditableChecker editableChecker) { + return new SequenceDropInsideRepresentationBehaviorProviderSwitch(target, crossRef, editableChecker) + .doSwitch(droppedElement); + } + + static class SequenceDropInsideRepresentationBehaviorProviderSwitch extends UMLSwitch<DnDStatus> { + + private final EObject target; + + private final ECrossReferenceAdapter crossRef; + + private final IEditableChecker editableChecker; + + SequenceDropInsideRepresentationBehaviorProviderSwitch(EObject target, ECrossReferenceAdapter crossRef, + IEditableChecker editableChecker) { + super(); + this.target = target; + this.crossRef = crossRef; + this.editableChecker = editableChecker; + } + + @Override + public DnDStatus caseProperty(Property property) { + if (this.target instanceof Interaction || this.target instanceof Lifeline) { + Lifeline lifeline = null; + Set<EObject> resultStatusElements; + if (this.target instanceof Interaction interaction) { + // Drop a Property on an Interaction will create a Lifeline and type the Lifeline + lifeline = createLifeline(interaction); + resultStatusElements = Set.of(lifeline); + } else { + // Drop a Property on a Lifeline will type the Lifeline + lifeline = (Lifeline) this.target; + resultStatusElements = Collections.emptySet(); + } + lifeline.setRepresents(property); + + return DnDStatus.createOKStatus(resultStatusElements); + } + return super.caseProperty(property); + } + + @Override + public DnDStatus caseType(Type type) { + if (this.target instanceof Interaction || this.target instanceof Lifeline) { + Lifeline lifeline = null; + Property property = null; + Set<EObject> resultStatusElements; + if (this.target instanceof Interaction interaction) { + // Drop a Classifier on an Interaction : create a new lifeline, a new Property + // in the interaction typed by the dropped classifier and the new Lifeline will represent this property. + property = createProperty(interaction); + lifeline = createLifeline(interaction); + resultStatusElements = Set.of(lifeline); + } else { + // Drop a Classifier on a Lifeline : create a new Property in the interaction + // typed by the dropped classifier and the target Lifeline will represent this property. + property = createProperty(EMFUtils.getAncestor(Interaction.class, this.target)); + lifeline = (Lifeline) this.target; + resultStatusElements = Collections.emptySet(); + } + property.setType(type); + lifeline.setRepresents(property); + + return DnDStatus.createOKStatus(resultStatusElements); + } + return super.caseType(type); + } + + private ElementCreator initElementCreator() { + ElementFeatureModifier featureModifier = new ElementFeatureModifier(this.crossRef, this.editableChecker); + ElementCreator elementCreator = new ElementCreator(new ElementConfigurer(), featureModifier); + return elementCreator; + } + + private Lifeline createLifeline(Interaction interaction) { + ElementCreator elementCreator = initElementCreator(); + return (Lifeline) elementCreator.create(interaction, UMLPackage.eINSTANCE.getLifeline().getName(), + UMLPackage.eINSTANCE.getInteraction_Lifeline().getName()).getElement(); + } + + private Property createProperty(Interaction parentInteraction) { + ElementCreator elementCreator = initElementCreator(); + return (Property) elementCreator.create(parentInteraction, UMLPackage.eINSTANCE.getProperty().getName(), + UMLPackage.eINSTANCE.getStructuredClassifier_OwnedAttribute().getName()).getElement(); + } + + @Override + public DnDStatus defaultCase(EObject obj) { + return DnDStatus.createFailingStatus("DnD is forbidden.", Collections.emptySet()); + } + } +} diff --git a/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/drop/diagrams/SequenceExternalSourceToRepresentationDropChecker.java b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/drop/diagrams/SequenceExternalSourceToRepresentationDropChecker.java new file mode 100644 index 0000000000000000000000000000000000000000..5146686f4b1e4c2ae4930e8e8a3842358c900125 --- /dev/null +++ b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/drop/diagrams/SequenceExternalSourceToRepresentationDropChecker.java @@ -0,0 +1,74 @@ +/***************************************************************************** + * Copyright (c) 2024 CEA LIST. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Obeo - Initial API and implementation + *****************************************************************************/ +package org.eclipse.papyrus.uml.domain.services.drop.diagrams; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.papyrus.uml.domain.services.drop.IExternalSourceToRepresentationDropChecker; +import org.eclipse.papyrus.uml.domain.services.status.CheckStatus; +import org.eclipse.uml2.uml.Interaction; +import org.eclipse.uml2.uml.Lifeline; +import org.eclipse.uml2.uml.Property; +import org.eclipse.uml2.uml.Type; +import org.eclipse.uml2.uml.util.UMLSwitch; + +/** + * Check semantic drop (from Explorer view) to a Sequence Diagram Element. + * + * @author <a href="mailto:glenn.plouhinec@obeo.fr">Glenn Plouhinec</a> + */ +public class SequenceExternalSourceToRepresentationDropChecker implements IExternalSourceToRepresentationDropChecker { + + @Override + public CheckStatus canDragAndDrop(EObject elementToDrop, EObject newSemanticContainer) { + return new SequenceDropInsideRepresentationCheckerSwitch(newSemanticContainer).doSwitch(elementToDrop); + } + + static class SequenceDropInsideRepresentationCheckerSwitch extends UMLSwitch<CheckStatus> { + + private final EObject target; + + SequenceDropInsideRepresentationCheckerSwitch(EObject target) { + super(); + this.target = target; + } + + @Override + public CheckStatus caseProperty(Property property) { + final CheckStatus result; + if (this.target instanceof Lifeline || this.target instanceof Interaction) { + result = CheckStatus.YES; + } else { + result = CheckStatus.no("Property can only be drag and drop on an Interaction or a Lifeline."); + } + return result; + } + + @Override + public CheckStatus caseType(Type type) { + final CheckStatus result; + if (this.target instanceof Lifeline || this.target instanceof Interaction) { + result = CheckStatus.YES; + } else { + result = CheckStatus.no("Type can only be drag and drop on an Interaction or a Lifeline."); + } + return result; + } + + @Override + public CheckStatus defaultCase(EObject object) { + return CheckStatus.no("DnD is not authorized."); + } + } + +} diff --git a/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/drop/diagrams/SequenceInternalSourceToRepresentationDropBehaviorProvider.java b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/drop/diagrams/SequenceInternalSourceToRepresentationDropBehaviorProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..a2b33f537d046e3dad64a4c5ebbd39653158f03c --- /dev/null +++ b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/drop/diagrams/SequenceInternalSourceToRepresentationDropBehaviorProvider.java @@ -0,0 +1,101 @@ +/***************************************************************************** + * Copyright (c) 2024 CEA LIST. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Obeo - Initial API and implementation + *****************************************************************************/ +package org.eclipse.papyrus.uml.domain.services.drop.diagrams; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.util.ECrossReferenceAdapter; +import org.eclipse.papyrus.uml.domain.services.IEditableChecker; +import org.eclipse.papyrus.uml.domain.services.drop.IInternalSourceToRepresentationDropBehaviorProvider; +import org.eclipse.papyrus.uml.domain.services.modify.ElementFeatureModifier; +import org.eclipse.papyrus.uml.domain.services.modify.IFeatureModifier; +import org.eclipse.papyrus.uml.domain.services.status.State; +import org.eclipse.papyrus.uml.domain.services.status.Status; +import org.eclipse.uml2.uml.Element; +import org.eclipse.uml2.uml.util.UMLSwitch; + +/** + * Drop behavior provider of a diagram element to a Sequence Diagram Element. + * + * @author <a href="mailto:glenn.plouhinec@obeo.fr">Glenn Plouhinec</a> + */ +public class SequenceInternalSourceToRepresentationDropBehaviorProvider + implements IInternalSourceToRepresentationDropBehaviorProvider { + + @Override + public Status drop(EObject droppedElement, EObject oldContainer, EObject newContainer, + ECrossReferenceAdapter crossRef, IEditableChecker editableChecker) { + return new SequenceDropOutsideRepresentationBehaviorProviderSwitch(oldContainer, newContainer, crossRef, + editableChecker).doSwitch(droppedElement); + } + + static class SequenceDropOutsideRepresentationBehaviorProviderSwitch extends UMLSwitch<Status> { + + private final EObject oldContainer; + + private final EObject newContainer; + + private final ECrossReferenceAdapter crossRef; + + private final IEditableChecker editableChecker; + + /** + * Initializes the switch. + * + * @param oldContainer + * the old container of the element being dropped + * @param newContainer + * the new container of the element being dropped + * @param crossRef + * the cross referencer + * @param editableChecker + * the checker + */ + SequenceDropOutsideRepresentationBehaviorProviderSwitch(EObject oldContainer, EObject newContainer, + ECrossReferenceAdapter crossRef, IEditableChecker editableChecker) { + super(); + this.oldContainer = oldContainer; + this.newContainer = newContainer; + this.crossRef = crossRef; + this.editableChecker = editableChecker; + } + + /** + * Default Behavior : UML element can be D&D by using the same reference + * containment. + * + * @see org.eclipse.uml2.uml.util.UMLSwitch#caseElement(org.eclipse.uml2.uml.Element) + * + * @param droppedElement + * the element to drop + * @return OK or Failing status according to the complete D&D. + */ + @Override + public Status caseElement(Element droppedElement) { + Status dropStatus; + IFeatureModifier modifier = new ElementFeatureModifier(this.crossRef, this.editableChecker); + if (this.oldContainer != this.newContainer) { + String refName = droppedElement.eContainmentFeature().getName(); + if (this.oldContainer.eClass().getEStructuralFeature(refName) != null + && this.newContainer.eClass().getEStructuralFeature(refName) != null) { + dropStatus = modifier.removeValue(this.oldContainer, refName, droppedElement); + if (State.DONE == dropStatus.getState()) { + dropStatus = modifier.addValue(this.newContainer, refName, droppedElement); + } + return dropStatus; + } + } + return super.caseElement(droppedElement); + } + } +} diff --git a/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/drop/diagrams/SequenceInternalSourceToRepresentationDropChecker.java b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/drop/diagrams/SequenceInternalSourceToRepresentationDropChecker.java new file mode 100644 index 0000000000000000000000000000000000000000..5572a2eda33eba31d93976636290648a28286c46 --- /dev/null +++ b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/drop/diagrams/SequenceInternalSourceToRepresentationDropChecker.java @@ -0,0 +1,82 @@ +/***************************************************************************** + * Copyright (c) 2024 CEA LIST. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Obeo - Initial API and implementation + *****************************************************************************/ +package org.eclipse.papyrus.uml.domain.services.drop.diagrams; + +import java.text.MessageFormat; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.papyrus.uml.domain.services.drop.IInternalSourceToRepresentationDropChecker; +import org.eclipse.papyrus.uml.domain.services.status.CheckStatus; +import org.eclipse.uml2.uml.Comment; +import org.eclipse.uml2.uml.Constraint; +import org.eclipse.uml2.uml.Interaction; +import org.eclipse.uml2.uml.InteractionOperand; +import org.eclipse.uml2.uml.UMLPackage; +import org.eclipse.uml2.uml.util.UMLSwitch; + +/** + * SourceToRepresentationDropChecker for Sequence diagram. + * + * @author <a href="mailto:glenn.plouhinec@obeo.fr">Glenn Plouhinec</a> + */ +public class SequenceInternalSourceToRepresentationDropChecker implements IInternalSourceToRepresentationDropChecker { + + private static final String DROP_ERROR_MSG = "{0} can only be drag and drop on {1}."; + + private static final String COMA = ", "; + + @Override + public CheckStatus canDragAndDrop(EObject elementToDrop, EObject newSemanticContainer) { + return new SequenceDropOutsideRepresentationCheckerSwitch(newSemanticContainer).doSwitch(elementToDrop); + } + + static class SequenceDropOutsideRepresentationCheckerSwitch extends UMLSwitch<CheckStatus> { + + private EObject newSemanticContainer; + + SequenceDropOutsideRepresentationCheckerSwitch(EObject target) { + super(); + this.newSemanticContainer = target; + } + + @Override + public CheckStatus caseComment(Comment comment) { + final CheckStatus result; + if (this.newSemanticContainer instanceof Interaction + || this.newSemanticContainer instanceof InteractionOperand) { + result = CheckStatus.YES; + } else { + + result = CheckStatus.no(MessageFormat.format(DROP_ERROR_MSG, comment.eClass().getName(), + UMLPackage.eINSTANCE.getInteraction().getName() + COMA + + UMLPackage.eINSTANCE.getInteractionOperand().getName())); + } + return result; + } + + @Override + public CheckStatus caseConstraint(Constraint constraint) { + final CheckStatus result; + if (this.newSemanticContainer instanceof Interaction + || this.newSemanticContainer instanceof InteractionOperand) { + result = CheckStatus.YES; + } else { + result = CheckStatus.no(MessageFormat.format(DROP_ERROR_MSG, constraint.eClass().getName(), + UMLPackage.eINSTANCE.getInteraction().getName() + COMA + + UMLPackage.eINSTANCE.getInteractionOperand().getName())); + } + return result; + } + } +} diff --git a/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/internal/helpers/DurationConstraintHelper.java b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/internal/helpers/DurationConstraintHelper.java index 34560dcf5553e0200e28e473a1238dc57ca47584..dad1935f73c1787446a4874e6dd6605e507b43c1 100644 --- a/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/internal/helpers/DurationConstraintHelper.java +++ b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/internal/helpers/DurationConstraintHelper.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022 CEA, Obeo. + * Copyright (c) 2022, 2024 CEA List, Obeo. * This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at @@ -12,21 +12,17 @@ *******************************************************************************/ package org.eclipse.papyrus.uml.domain.services.internal.helpers; -import java.util.Collection; -import java.util.LinkedList; import java.util.List; -import org.eclipse.emf.ecore.EStructuralFeature.Setting; import org.eclipse.emf.ecore.util.ECrossReferenceAdapter; import org.eclipse.uml2.uml.DurationConstraint; import org.eclipse.uml2.uml.NamedElement; -import org.eclipse.uml2.uml.UMLPackage; /** * This helper provides interesting features for DurationConstraint objects. * Copy from * {@link org.eclipse.papyrus.uml.diagram.common.helper.DurationConstraintHelper} - * + * * @author <a href="mailto:jessy.mallet@obeo.fr">Jessy Mallet</a> */ public class DurationConstraintHelper { @@ -34,25 +30,18 @@ public class DurationConstraintHelper { /** * Get the list of all DurationConstraint constraining a given element. * + * @deprecated Use UMLTemporalHelper instead. * @param element * the constrained element * @param crossReferenceAdapter * an adapter used to get inverse references - * + * * @return list of DurationConstraint */ + @Deprecated public static List<DurationConstraint> getDurationConstraintsOn(NamedElement element, ECrossReferenceAdapter crossReferenceAdapter) { - Collection<Setting> inverseReferences = crossReferenceAdapter.getInverseReferences(element, false); - // DurationConstraint referencing element - List<DurationConstraint> referencing = new LinkedList<DurationConstraint>(); - for (Setting ref : inverseReferences) { - if (UMLPackage.eINSTANCE.getConstraint_ConstrainedElement().equals(ref.getEStructuralFeature()) - && ref.getEObject() instanceof DurationConstraint && ref.getEObject().eContainer() != null) { - referencing.add((DurationConstraint) ref.getEObject()); - } - } - return referencing; + return UMLTemporalHelper.getDurationConstraints(element, crossReferenceAdapter); } } diff --git a/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/internal/helpers/DurationObservationHelper.java b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/internal/helpers/DurationObservationHelper.java index c297480cbc8ebb726ae35428a3ddd3cd63685992..d7cabc9d490e09ceb8a8e828be91d6c56e558069 100644 --- a/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/internal/helpers/DurationObservationHelper.java +++ b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/internal/helpers/DurationObservationHelper.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022 CEA, Obeo. + * Copyright (c) 2022, 2024 CEA List, Obeo. * This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at @@ -12,21 +12,17 @@ *******************************************************************************/ package org.eclipse.papyrus.uml.domain.services.internal.helpers; -import java.util.Collection; -import java.util.LinkedList; import java.util.List; -import org.eclipse.emf.ecore.EStructuralFeature.Setting; import org.eclipse.emf.ecore.util.ECrossReferenceAdapter; import org.eclipse.uml2.uml.DurationObservation; import org.eclipse.uml2.uml.NamedElement; -import org.eclipse.uml2.uml.UMLPackage; /** * This helper provides interesting features for DurationObservation objects. * Copy from * {@link org.eclipse.papyrus.uml.diagram.common.helper.DurationObservationHelper} - * + * * @author <a href="mailto:jessy.mallet@obeo.fr">Jessy Mallet</a> */ public class DurationObservationHelper { @@ -35,24 +31,17 @@ public class DurationObservationHelper { * Get the list of all DurationObservation observing duration from or to an * element. * + * @deprecated Use UMLTemporalHelper instead. * @param element * the observed element * @param crossReferenceAdapter * an adapter used to get inverse references - * + * * @return list of DurationObservation */ + @Deprecated public static List<DurationObservation> getDurationObservationsOn(NamedElement element, ECrossReferenceAdapter crossReferenceAdapter) { - Collection<Setting> inverseReferences = crossReferenceAdapter.getInverseReferences(element, false); - // DurationObservation referencing element - List<DurationObservation> referencing1 = new LinkedList<DurationObservation>(); - for (Setting ref : inverseReferences) { - if (UMLPackage.eINSTANCE.getDurationObservation_Event().equals(ref.getEStructuralFeature()) - && ref.getEObject().eContainer() != null) { - referencing1.add((DurationObservation) ref.getEObject()); - } - } - return referencing1; + return UMLTemporalHelper.getDurationObservations(element, crossReferenceAdapter); } } diff --git a/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/internal/helpers/OccurrenceSpecificationHelper.java b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/internal/helpers/OccurrenceSpecificationHelper.java index f6e6b2adbf1f5989533e9da54c66a134d46b7d50..9f5edcc719cb3c13c2fda00f216a85255940934c 100644 --- a/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/internal/helpers/OccurrenceSpecificationHelper.java +++ b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/internal/helpers/OccurrenceSpecificationHelper.java @@ -1,7 +1,7 @@ /***************************************************************************** - * Copyright (c) 2022, 2023 CEA LIST, Obeo. + * Copyright (c) 2022, 2024 CEA LIST. * - * All rights reserved. This program and the accompanying materials + * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ @@ -13,10 +13,14 @@ *****************************************************************************/ package org.eclipse.papyrus.uml.domain.services.internal.helpers; +import java.util.Collection; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.stream.Stream; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature.Setting; import org.eclipse.emf.ecore.util.ECrossReferenceAdapter; import org.eclipse.uml2.common.util.CacheAdapter; import org.eclipse.uml2.uml.Constraint; @@ -26,6 +30,7 @@ import org.eclipse.uml2.uml.ExecutionSpecification; import org.eclipse.uml2.uml.Interaction; import org.eclipse.uml2.uml.InteractionFragment; import org.eclipse.uml2.uml.Lifeline; +import org.eclipse.uml2.uml.MessageOccurrenceSpecification; import org.eclipse.uml2.uml.NamedElement; import org.eclipse.uml2.uml.OccurrenceSpecification; import org.eclipse.uml2.uml.TimeConstraint; @@ -34,14 +39,14 @@ import org.eclipse.uml2.uml.UMLPackage; /** * This helper provides some utils method on {@link OccurrenceSpecification}. - * + * * @author <a href="mailto:jessy.mallet@obeo.fr">Jessy Mallet</a> */ public class OccurrenceSpecificationHelper { /** * Get interaction from a given {@link Element}. - * + * * @param element * the element attached to an interaction * @return its matching interaction. @@ -59,8 +64,8 @@ public class OccurrenceSpecificationHelper { } /** - * Get time constraints in the contextual {@code interaction} that constrain - * only the {@code constrained} element and no others. + * Get time constraints in the contextual {@code interaction} that constrain only the {@code constrained} element + * and no others. * * @param interaction * the contextual interaction @@ -74,16 +79,17 @@ public class OccurrenceSpecificationHelper { return Stream.empty(); } - return CacheAdapter.getInstance().getNonNavigableInverseReferences(constrained).stream().filter( - setting -> setting.getEStructuralFeature() == UMLPackage.Literals.CONSTRAINT__CONSTRAINED_ELEMENT) - .map(setting -> (Constraint) setting.getEObject()).filter(TimeConstraint.class::isInstance) - .filter(c -> c.getConstrainedElements().size() == 1).filter(c -> getInteraction(c) == interaction) + return CacheAdapter.getInstance().getNonNavigableInverseReferences(constrained).stream() + .filter(setting -> setting.getEStructuralFeature() == UMLPackage.Literals.CONSTRAINT__CONSTRAINED_ELEMENT) + .map(setting -> (Constraint) setting.getEObject()) + .filter(TimeConstraint.class::isInstance) + .filter(c -> c.getConstrainedElements().size() == 1) + .filter(c -> getInteraction(c) == interaction) .map(TimeConstraint.class::cast); } /** - * Get time observations in the contextual {@code interaction} that reference - * the given {@code observed} element. + * Get time observations in the contextual {@code interaction} that reference the given {@code observed} element. * * @param interaction * the contextual interaction @@ -116,18 +122,20 @@ public class OccurrenceSpecificationHelper { * </pre> * * @param es - * {@link ExecutionSpecification} which references - * {@link OccurrenceSpecification} (by means of #start/#finish - * references) + * {@link ExecutionSpecification} which references {@link OccurrenceSpecification} (by means of + * #start/#finish references) * @param os - * start or finish {@link OccurrenceSpecification} which defines the - * duration of {@link ExecutionSpecification} + * start or finish {@link OccurrenceSpecification} which defines the duration of + * {@link ExecutionSpecification} * @return true in case {@link OccurrenceSpecification} should be destroyed */ - public static boolean shouldDestroyOccurrenceSpecification(ExecutionSpecification es, OccurrenceSpecification os, + public static boolean shouldDestroyWithExecution(ExecutionSpecification es, OccurrenceSpecification os, ECrossReferenceAdapter crossReferenceAdapter) { - return os instanceof ExecutionOccurrenceSpecification - || (os != null && UMLService.isOnlyUsage(os, es, crossReferenceAdapter)); + return os != null // + && !(os instanceof MessageOccurrenceSpecification) + && (os instanceof ExecutionOccurrenceSpecification + // Strange case of unrelated event occurrence + || UMLService.isOnlyUsage(os, es, crossReferenceAdapter)); } /** @@ -135,21 +143,20 @@ public class OccurrenceSpecificationHelper { * <p> * This element can be: * <ul> - * <li>An {@link ExecutionSpecification} if the {@code occurrenceSpecification} - * is positioned between the {@link ExecutionSpecification#getStart()} and - * {@link ExecutionSpecification#getFinish()} occurrences in the enclosing - * {@link Interaction#getFragments()} - * <li>It's first covered {@link Lifeline} otherwise (see - * {@link OccurrenceSpecification#getCovereds()}) - * + * <li>An {@link ExecutionSpecification} if the {@code occurrenceSpecification} is positioned between the + * {@link ExecutionSpecification#getStart()} and {@link ExecutionSpecification#getFinish()} occurrences in the + * enclosing {@link Interaction#getFragments()}, or if {@code occurrenceSpecification} is the start or finish of the + * execution.</li> + * <li>It's first covered {@link Lifeline} otherwise (see {@link OccurrenceSpecification#getCovereds()})</li> + * </ul> + * </p> + * * @param occurrenceSpecification - * the {@link OccurrenceSpecification} to - * retrieve the enclosing element from + * the {@link OccurrenceSpecification} to retrieve the enclosing element from * @return the element enclosing the {@code occurrenceSpecification} - * + * * @throws NullPointerException - * if {@code occurrenceSpecification} is - * {@code null} + * if {@code occurrenceSpecification} is {@code null} */ public static NamedElement findEnclosingElement(OccurrenceSpecification occurrenceSpecification) { Objects.requireNonNull(occurrenceSpecification); @@ -176,20 +183,25 @@ public class OccurrenceSpecificationHelper { fragments = List.of(); } - ExecutionSpecification enclosingExecutionSpecification = null; - for (InteractionFragment fragment : fragments) { - if (fragment == occurrenceSpecification) { - break; - } else if (fragment instanceof ExecutionSpecification) { - enclosingExecutionSpecification = (ExecutionSpecification) fragment; - } else if (fragment instanceof OccurrenceSpecification) { - OccurrenceSpecification occurrenceSpecificationFragment = (OccurrenceSpecification) fragment; - if (enclosingExecutionSpecification != null && Objects - .equals(enclosingExecutionSpecification.getFinish(), occurrenceSpecificationFragment)) { - enclosingExecutionSpecification = null; + ExecutionSpecification enclosingExecutionSpecification = getStartingOrFinishingExecution( + occurrenceSpecification); + if (enclosingExecutionSpecification == null) { + // The occurrence isn't the start/finish of an execution, iterate the fragments + // to find the execution wrapping it. + for (InteractionFragment fragment : fragments) { + if (fragment == occurrenceSpecification) { + break; + } else if (fragment instanceof ExecutionSpecification) { + enclosingExecutionSpecification = (ExecutionSpecification) fragment; + } else if (fragment instanceof OccurrenceSpecification occurrenceSpecificationFragment) { + if (enclosingExecutionSpecification != null && Objects + .equals(enclosingExecutionSpecification.getFinish(), occurrenceSpecificationFragment)) { + enclosingExecutionSpecification = null; + } } } } + if (enclosingExecutionSpecification != null) { // Return the enclosing ExecutionSpecification if we found one, otherwise return // the enclosing Lifeline @@ -198,4 +210,87 @@ public class OccurrenceSpecificationHelper { } return enclosingElement; } + + /** + * Returns the {@link ExecutionSpecification} that has {@code occurrence} as its {@code start} or {@code finish}. + * + * @param occurrence + * the {@link OccurrenceSpecification} to get the execution from + * @return the {@link ExecutionSpecification} if it exists, {@code null} otherwise + */ + private static ExecutionSpecification getStartingOrFinishingExecution(OccurrenceSpecification occurrence) { + return getExecutionFromStartOccurrence(occurrence) + .orElseGet(() -> getExecutionFromFinishOccurrence(occurrence).orElse(null)); + } + + /** + * Returns {@code true} if {@code occurrence} is the start of an {@link ExecutionSpecification}. + * + * @param occurrence + * the {@link OccurrenceSpecification} to check + * @return {@code true} if {@code occurrence} is the start of an {@link ExecutionSpecification} + * @see #getExecutionFromStartOccurrence(OccurrenceSpecification) + */ + public static boolean isExecutionStartOccurrence(OccurrenceSpecification occurrence) { + return getExecutionFromStartOccurrence(occurrence).isPresent(); + } + + /** + * Returns {@code true} if {@code occurrence} is the finish of an {@link ExecutionSpecification}. + * + * @param occurrence + * the {@link OccurrenceSpecification} to check + * @return {@code true} if {@code occurrence} is the finish of an {@link ExecutionSpecification} + * @see #getExecutionFromFinishOccurrence(OccurrenceSpecification) + */ + public static boolean isExecutionFinishOccurrence(OccurrenceSpecification occurrence) { + return getExecutionFromFinishOccurrence(occurrence).isPresent(); + } + + /** + * Returns the {@link ExecutionSpecification} that contains {@code occurrence} as its start. + * + * @param occurrence + * the {@link OccurrenceSpecification} to check + * @return an {@link Optional} containing the {@link ExecutionSpecification}, or {@link Optional#empty()} + * @see #isExecutionStartOccurrence(OccurrenceSpecification) + */ + public static Optional<ExecutionSpecification> getExecutionFromStartOccurrence(OccurrenceSpecification occurrence) { + return getExecutionFromOccurrence(occurrence, UMLPackage.eINSTANCE.getExecutionSpecification_Start()); + } + + /** + * Returns the {@link ExecutionSpecification} that contains {@code occurrence} as its finish. + * + * @param occurrence + * the {@link OccurrenceSpecification} to check + * @return an {@link Optional} containing the {@link ExecutionSpecification}, or {@link Optional#empty()} + * @see #isExecutionFinishOccurrence(OccurrenceSpecification) + */ + public static Optional<ExecutionSpecification> getExecutionFromFinishOccurrence( + OccurrenceSpecification occurrence) { + return getExecutionFromOccurrence(occurrence, UMLPackage.eINSTANCE.getExecutionSpecification_Finish()); + } + + /** + * Returns the {@link ExecutionSpecification} that contains {@code occurrence} in its {@code executionReference}. + * + * @param occurrence + * the {@link OccurrenceSpecification} to check + * @param executionReference + * the {@link EReference} to check + * @return an {@link Optional} containing the {@link ExecutionSpecification}, or {@link Optional#empty()} + */ + private static Optional<ExecutionSpecification> getExecutionFromOccurrence(OccurrenceSpecification occurrence, + EReference executionReference) { + // Cross referencer is required for transformation: + // Element may not be in the same container. + ECrossReferenceAdapter crossReferenceAdapter = ECrossReferenceAdapter.getCrossReferenceAdapter(occurrence); + Collection<Setting> settings = crossReferenceAdapter.getInverseReferences(occurrence, executionReference, true); + return settings.stream() // Reference + .map(Setting::getEObject) // source + .filter(ExecutionSpecification.class::isInstance) // adapt + .map(ExecutionSpecification.class::cast) // collect + .findFirst(); + } } diff --git a/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/internal/helpers/TimeConstraintHelper.java b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/internal/helpers/TimeConstraintHelper.java index c2dc981b6354410c5f406b45325d2d49b4eff3be..a58df9be354a16e458284d3a7e6bbe304bc83e42 100644 --- a/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/internal/helpers/TimeConstraintHelper.java +++ b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/internal/helpers/TimeConstraintHelper.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022 CEA, Obeo. + * Copyright (c) 2022, 2024 CEA List, Obeo. * This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at @@ -12,21 +12,17 @@ *******************************************************************************/ package org.eclipse.papyrus.uml.domain.services.internal.helpers; -import java.util.Collection; -import java.util.LinkedList; import java.util.List; -import org.eclipse.emf.ecore.EStructuralFeature.Setting; import org.eclipse.emf.ecore.util.ECrossReferenceAdapter; import org.eclipse.uml2.uml.NamedElement; import org.eclipse.uml2.uml.TimeConstraint; -import org.eclipse.uml2.uml.UMLPackage; /** * This helper provides interesting features for TimeConstraint objects. Copy * from * {@link org.eclipse.papyrus.uml.diagram.common.helper.TimeConstraintHelper} - * + * * @author <a href="mailto:jessy.mallet@obeo.fr">Jessy Mallet</a> */ public class TimeConstraintHelper { @@ -34,24 +30,17 @@ public class TimeConstraintHelper { /** * Get the list of all TimeConstraint constraining a given element. * + * @deprecated Use UMLTemporalHelper instead. * @param element * the constrained element * @param crossReferenceAdapter * an adapter used to get inverse references - * + * * @return list of TimeConstraint */ + @Deprecated public static List<TimeConstraint> getTimeConstraintsOn(NamedElement element, ECrossReferenceAdapter crossReferenceAdapter) { - Collection<Setting> inverseReferences = crossReferenceAdapter.getInverseReferences(element, false); - // TimeConstraint referencing element - List<TimeConstraint> referencing = new LinkedList<>(); - for (Setting ref : inverseReferences) { - if (UMLPackage.eINSTANCE.getConstraint_ConstrainedElement().equals(ref.getEStructuralFeature()) - && ref.getEObject() instanceof TimeConstraint && ref.getEObject().eContainer() != null) { - referencing.add((TimeConstraint) ref.getEObject()); - } - } - return referencing; + return UMLTemporalHelper.getTimeConstraints(element, crossReferenceAdapter); } } diff --git a/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/internal/helpers/TimeObservationHelper.java b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/internal/helpers/TimeObservationHelper.java index 9bffbce5990d27f53e40fd5911410c08b00417a1..21aef28fe28aa0a0209f0a74f6bff4f0a28cb658 100644 --- a/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/internal/helpers/TimeObservationHelper.java +++ b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/internal/helpers/TimeObservationHelper.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022 CEA, Obeo. + * Copyright (c) 2022, 2024 CEA List, Obeo. * This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at @@ -12,21 +12,17 @@ *******************************************************************************/ package org.eclipse.papyrus.uml.domain.services.internal.helpers; -import java.util.Collection; -import java.util.LinkedList; import java.util.List; -import org.eclipse.emf.ecore.EStructuralFeature.Setting; import org.eclipse.emf.ecore.util.ECrossReferenceAdapter; import org.eclipse.uml2.uml.NamedElement; import org.eclipse.uml2.uml.TimeObservation; -import org.eclipse.uml2.uml.UMLPackage; /** * This helper provides interesting features for TimeObservation objects. Copy * from * {@link org.eclipse.papyrus.uml.diagram.common.helper.TimeObservationHelper} - * + * * @author <a href="mailto:jessy.mallet@obeo.fr">Jessy Mallet</a> */ public class TimeObservationHelper { @@ -34,24 +30,17 @@ public class TimeObservationHelper { /** * Get the list of all TimeObservation observing a given element. * + * @deprecated Use UMLTemporalHelper instead. * @param element * the observed element * @param crossReferenceAdapter * an adapter used to get inverse references - * + * * @return list of TimeObservation */ + @Deprecated public static List<TimeObservation> getTimeObservations(NamedElement element, ECrossReferenceAdapter crossReferenceAdapter) { - Collection<Setting> inverseReferences = crossReferenceAdapter.getInverseReferences(element, false); - // TimeConstraint referencing element - List<TimeObservation> referencing = new LinkedList<TimeObservation>(); - for (Setting ref : inverseReferences) { - if (UMLPackage.eINSTANCE.getTimeObservation_Event().equals(ref.getEStructuralFeature()) - && ref.getEObject().eContainer() != null) { - referencing.add((TimeObservation) ref.getEObject()); - } - } - return referencing; + return UMLTemporalHelper.getTimeObservations(element, crossReferenceAdapter); } } diff --git a/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/internal/helpers/UMLService.java b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/internal/helpers/UMLService.java index 335c2ced64303ced973f4a9788fa19b1b67db2d2..fdf0bac8f09b51b58cb2097228273e1d98f60841 100644 --- a/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/internal/helpers/UMLService.java +++ b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/internal/helpers/UMLService.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022, 2023 CEA, Obeo + * Copyright (c) 2022, 2024 CEA List, Obeo. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -18,10 +18,8 @@ import static java.util.stream.Collectors.toList; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.HashSet; import java.util.Iterator; import java.util.List; -import java.util.Set; import java.util.function.Predicate; import java.util.stream.Stream; @@ -29,7 +27,6 @@ import org.eclipse.emf.common.notify.Notifier; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.EStructuralFeature.Setting; @@ -42,6 +39,7 @@ import org.eclipse.uml2.uml.CombinedFragment; import org.eclipse.uml2.uml.Element; import org.eclipse.uml2.uml.Interaction; import org.eclipse.uml2.uml.InteractionOperand; +import org.eclipse.uml2.uml.UMLPackage; /** * Generic service for UML metamodel. @@ -100,14 +98,14 @@ public class UMLService { } } - + public static Stream<Resource> getUmlResources(EList<Resource> resources) { return resources.stream().filter(r -> !r.getContents().isEmpty() && r.getContents().get(0) instanceof Element); } /** * Check if a given {@link EObject} is an Interaction container. - * + * * @param object * the Object to check * @return <code>true</code> if the given {@link EObject} is an Interaction @@ -123,7 +121,7 @@ public class UMLService { * all referencers of a particular element. The search can be narrowed down by * passing the list of Reference features to match. <code>features</code> can be * null. - * + * * @param eObject * The referenced object. * @param features @@ -177,29 +175,19 @@ public class UMLService { */ public static boolean isOnlyUsage(EObject usedObject, EObject knownReferencer, ECrossReferenceAdapter crossReferenceAdapter) { - boolean isUsed = false; - EPackage mmPackage = usedObject.eClass().getEPackage(); + EObject container = usedObject.eContainer(); - // Retrieve the list of elements referencing the usedObject. - Set<EObject> crossReferences = new HashSet<>(); for (Setting setting : crossReferenceAdapter.getInverseReferences(usedObject, false)) { EObject eObj = setting.getEObject(); - if (eObj.eClass().getEPackage().equals(mmPackage)) { - crossReferences.add(eObj); + if (eObj.eClass().getEPackage() == UMLPackage.eINSTANCE + // ignore accessible through remote navigation + && !setting.getEStructuralFeature().isDerived() + // Ignore well known references + && eObj != knownReferencer && eObj != container) { + return false; } } - // Remove the container of used object. - crossReferences.remove(usedObject.eContainer()); - // Remove the knownReferencer from the list of references. - crossReferences.remove(knownReferencer); - - // If no referencer remains in the list, the known element is the only - // usage. - if (crossReferences.isEmpty()) { - isUsed = true; - } - - return isUsed; + return true; } } diff --git a/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/internal/helpers/UMLTemporalHelper.java b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/internal/helpers/UMLTemporalHelper.java new file mode 100644 index 0000000000000000000000000000000000000000..2f1d07189399aaf78370c05aef24bf8bf26ebd7f --- /dev/null +++ b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/internal/helpers/UMLTemporalHelper.java @@ -0,0 +1,224 @@ +/******************************************************************************* + * Copyright (c) 2024 CEA LIST. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Obeo - Initial API and implementation + *******************************************************************************/ +package org.eclipse.papyrus.uml.domain.services.internal.helpers; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature.Setting; +import org.eclipse.emf.ecore.util.ECrossReferenceAdapter; +import org.eclipse.uml2.uml.DurationConstraint; +import org.eclipse.uml2.uml.DurationObservation; +import org.eclipse.uml2.uml.NamedElement; +import org.eclipse.uml2.uml.PackageableElement; +import org.eclipse.uml2.uml.TimeConstraint; +import org.eclipse.uml2.uml.TimeObservation; +import org.eclipse.uml2.uml.UMLPackage; + +/** + * This helper provides interesting features for DurationConstraint objects. + * Copy from + * {@link org.eclipse.papyrus.uml.diagram.common.helper.DurationConstraintHelper} + * + * @author <a href="mailto:nicolas.peransin@obeo.fr">Nicolas Peransin</a> + */ +public class UMLTemporalHelper { + + private static final UMLPackage UML = UMLPackage.eINSTANCE; + + /** + * Descriptions of temporal relationship. + */ + private enum TemporalRelation { + + /** Reference of TimeObservation. */ + timeObservation(TimeObservation.class, UML.getTimeObservation_Event()), + /** Reference of DurationObservation. */ + durationObservation(DurationObservation.class, UML.getDurationObservation_Event()), + /** Reference of TimeConstraint. */ + timeConstraint(TimeConstraint.class, UML.getConstraint_ConstrainedElement()), + /** Reference of DurationConstraint. */ + durationConstraint(DurationConstraint.class, UML.getConstraint_ConstrainedElement()), + + /** Reference of TimeObservation and TimeConstraint. */ + timeElement(List.of(TimeConstraint.class, TimeObservation.class), UML.getConstraint_ConstrainedElement(), + UML.getTimeObservation_Event()), + /** Reference of DurationConstraint and DurationObservation. */ + durationElement(List.of(DurationConstraint.class, DurationObservation.class), + UML.getConstraint_ConstrainedElement(), UML.getTimeObservation_Event()), + + /** Reference of all temporal indications. */ + all(List.of(TimeConstraint.class, DurationConstraint.class, TimeObservation.class, DurationObservation.class), // PackageableElement + UML.getConstraint_ConstrainedElement(), UML.getDurationObservation_Event(), + UML.getTimeObservation_Event()); + + /** Filter based on type of referencing element. */ + private Predicate<EObject> typeFilter; + /** Filter based on reference of referencing element. */ + private final Predicate<Setting> referencefilter; + + /** + * Constructor with single type. + * + * @param type + * class of the relation + * @param reference + * EMF reference + */ + TemporalRelation(Class<? extends PackageableElement> type, EReference reference) { + this(Collections.singletonList(type), reference); + } + + /** + * Constructor for multiple type. + * + * @param subTypes + * classes of the relation + * @param reference + * EMF reference + */ + TemporalRelation(List<? extends Class<? extends PackageableElement>> subTypes, + EReference... references) { + + Collection<EReference> refs = Arrays.asList(references); + referencefilter = setting -> refs.contains(setting.getEStructuralFeature()); + typeFilter = value -> { + for (Class<?> subType : subTypes) { + if (subType.isInstance(value)) { + return true; + } + } + return false; + }; + } + + @SuppressWarnings("unchecked") // private call will ensure compatibility + private <R extends PackageableElement> List<R> getRelatedElements(NamedElement element, + ECrossReferenceAdapter crossRef) { + return (List<R>) crossRef.getInverseReferences(element, false) // references + .stream() // filtering + .filter(referencefilter) // right relation + .map(Setting::getEObject) // To target + .filter(typeFilter) // With expected type + .collect(Collectors.toList()); + } + } + + /** + * Returns all {@link DurationConstraint}s constraining a given element. + * + * @param element + * the constrained element + * @param crossRef + * an adapter used to get inverse references + * + * @return list of DurationConstraints + */ + public static List<DurationConstraint> getDurationConstraints(NamedElement element, + ECrossReferenceAdapter crossRef) { + return TemporalRelation.durationConstraint.getRelatedElements(element, crossRef); + } + + /** + * Returns all {@link TimeConstraint}s constraining a given element. + * + * @param element + * the constrained element + * @param crossRef + * an adapter used to get inverse references + * + * @return list of TimeConstraints + */ + public static List<TimeConstraint> getTimeConstraints(NamedElement element, ECrossReferenceAdapter crossRef) { + return TemporalRelation.timeConstraint.getRelatedElements(element, crossRef); + } + + /** + * Returns all {@link DurationObservation}s constraining a given element. + * + * @param element + * the constrained element + * @param crossRef + * an adapter used to get inverse references + * + * @return list of DurationObservations + */ + public static List<DurationObservation> getDurationObservations(NamedElement element, + ECrossReferenceAdapter crossRef) { + return TemporalRelation.durationObservation.getRelatedElements(element, crossRef); + } + + /** + * Returns all {@link TimeObservation}s constraining a given element. + * + * @param element + * the constrained element + * @param crossRef + * an adapter used to get inverse references + * + * @return list of TimeObservations + */ + public static List<TimeObservation> getTimeObservations(NamedElement element, ECrossReferenceAdapter crossRef) { + return TemporalRelation.timeObservation.getRelatedElements(element, crossRef); + } + + /** + * Returns all {@link TimeConstraint}s constraining a given element. + * + * @param element + * the constrained element + * @param crossRef + * an adapter used to get inverse references + * + * @return list of TimeConstraints + */ + public static List<PackageableElement> getTemporalElements(NamedElement element, ECrossReferenceAdapter crossRef) { + return TemporalRelation.all.getRelatedElements(element, crossRef); + } + + /** + * Returns all time {@link PackageableElement}s related to a given element. + * + * @param element + * the constrained element + * @param crossRef + * an adapter used to get inverse references + * + * @return list of PackageableElement + */ + public static List<PackageableElement> getTimeElements(NamedElement element, ECrossReferenceAdapter crossRef) { + return TemporalRelation.timeElement.getRelatedElements(element, crossRef); + } + + /** + * Returns all duration {@link PackageableElement}s related to a given element. + * + * @param element + * the constrained element + * @param crossRef + * an adapter used to get inverse references + * + * @return list of PackageableElement + */ + public static List<PackageableElement> getDurationElements(NamedElement element, ECrossReferenceAdapter crossRef) { + return TemporalRelation.durationElement.getRelatedElements(element, crossRef); + } + +} diff --git a/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/labels/ElementLabelProvider.java b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/labels/ElementLabelProvider.java index c0e24ab0daa29719f535e4263cb284a0964b012f..b2e8af66caf5680ea75dbf2bed9b28ecb7a15797 100644 --- a/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/labels/ElementLabelProvider.java +++ b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/labels/ElementLabelProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022, 2023, 2024 CEA LIST, Obeo, Artal Technologies. + * Copyright (c) 2022, 2024 CEA LIST, Obeo, Artal Technologies. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -17,7 +17,6 @@ package org.eclipse.papyrus.uml.domain.services.labels; import static org.eclipse.papyrus.uml.domain.services.labels.UMLCharacters.CLOSE_ANGLE_BRACKET; import static org.eclipse.papyrus.uml.domain.services.labels.UMLCharacters.CLOSE_BRACKET; import static org.eclipse.papyrus.uml.domain.services.labels.UMLCharacters.D_DOTS; -import static org.eclipse.papyrus.uml.domain.services.labels.UMLCharacters.EMPTY; import static org.eclipse.papyrus.uml.domain.services.labels.UMLCharacters.EOL; import static org.eclipse.papyrus.uml.domain.services.labels.UMLCharacters.EQL; import static org.eclipse.papyrus.uml.domain.services.labels.UMLCharacters.OPEN_ANGLE_BRACKET; @@ -26,6 +25,7 @@ import static org.eclipse.papyrus.uml.domain.services.labels.UMLCharacters.SPACE import static org.eclipse.papyrus.uml.domain.services.labels.UMLCharacters.ST_LEFT; import static org.eclipse.papyrus.uml.domain.services.labels.UMLCharacters.ST_RIGHT; +import java.util.Objects; import java.util.function.Function; import java.util.stream.Collectors; @@ -51,17 +51,17 @@ import org.eclipse.uml2.uml.ConditionalNode; import org.eclipse.uml2.uml.ConnectableElement; import org.eclipse.uml2.uml.Constraint; import org.eclipse.uml2.uml.Duration; +import org.eclipse.uml2.uml.DurationObservation; import org.eclipse.uml2.uml.Element; import org.eclipse.uml2.uml.ExpansionKind; import org.eclipse.uml2.uml.ExpansionRegion; -import org.eclipse.uml2.uml.Expression; import org.eclipse.uml2.uml.InformationFlow; import org.eclipse.uml2.uml.InteractionConstraint; import org.eclipse.uml2.uml.InteractionOperand; import org.eclipse.uml2.uml.InteractionUse; +import org.eclipse.uml2.uml.IntervalConstraint; import org.eclipse.uml2.uml.JoinNode; import org.eclipse.uml2.uml.Lifeline; -import org.eclipse.uml2.uml.LiteralSpecification; import org.eclipse.uml2.uml.LoopNode; import org.eclipse.uml2.uml.NamedElement; import org.eclipse.uml2.uml.OpaqueExpression; @@ -71,8 +71,10 @@ import org.eclipse.uml2.uml.Property; import org.eclipse.uml2.uml.Reception; import org.eclipse.uml2.uml.Region; import org.eclipse.uml2.uml.SequenceNode; +import org.eclipse.uml2.uml.StateInvariant; import org.eclipse.uml2.uml.StructuredActivityNode; import org.eclipse.uml2.uml.TimeExpression; +import org.eclipse.uml2.uml.TimeObservation; import org.eclipse.uml2.uml.Transition; import org.eclipse.uml2.uml.Type; import org.eclipse.uml2.uml.ValueSpecification; @@ -170,22 +172,32 @@ public final class ElementLabelProvider implements IViewLabelProvider { static final class ElementLabelProviderSwitch extends UMLSwitch<String> { - private static final String WEIGHT = "weight"; + private static final String REF = "ref"; - private static final String CONDITIONAL = "conditional"; + private static final String ASSIGNED = SPACE + EQL + SPACE; - private static final String SEQUENCE = "sequence"; + private static final String WEIGHT = "weight" + EQL; - private static final String LOOP_NODE = "loop node"; + private static final String CONDITIONAL = ST_LEFT + "conditional" + ST_RIGHT; - private static final String STRUCTURED = "structured"; + private static final String SEQUENCE = ST_LEFT + "sequence" + ST_RIGHT; - private static final String JOIN_SPEC = "joinSpec"; + private static final String LOOP_NODE = ST_LEFT + "loop node" + ST_RIGHT; + + private static final String STRUCTURED = ST_LEFT + "structured" + ST_RIGHT; + + private static final String JOIN_SPEC = "joinSpec" + ASSIGNED; private static final String NATURAL = "NATURAL"; private static final String NULL_CONSTRAINT = "<NULL Constraint>"; + private static final String TIME_OBSERVATION = ASSIGNED + "now"; + + private static final String DURATION_OBSERVATION = ASSIGNED + "duration"; + + private static final String TYPED = SPACE + D_DOTS + SPACE; + private CollaborationUseLabelHelper collaborationUseLabelHelper; private PropertyLabelHelper propertyLabelHelper; @@ -199,16 +211,12 @@ public final class ElementLabelProvider implements IViewLabelProvider { private ValueSpecificationLabelHelper valueSpecificationHelper; private final OperationLabelHelper operationLabelHelper; - + private final ReceptionLabelHelper receptionLabelHelper; - ElementLabelProviderSwitch() { - this(null); - } ElementLabelProviderSwitch(INamedElementNameProvider namedElementNameProvider) { - super(); - this.namedElementNameProvider = namedElementNameProvider; + this.namedElementNameProvider = Objects.requireNonNull(namedElementNameProvider); this.visibilityLabelHelper = new VisibilityLabelHelper(); this.collaborationUseLabelHelper = new CollaborationUseLabelHelper(namedElementNameProvider, this.visibilityLabelHelper); @@ -278,7 +286,7 @@ public final class ElementLabelProvider implements IViewLabelProvider { @Override public String caseInteractionUse(InteractionUse interactionUse) { - return "ref"; + return REF; } private String getConveyeds(EList<Classifier> conveyeds) { @@ -317,45 +325,65 @@ public final class ElementLabelProvider implements IViewLabelProvider { @Override public String caseConstraint(Constraint constraint) { StringBuilder constLabel = new StringBuilder(); - String body = EMPTY; - String lang = EMPTY; - ValueSpecification valueSpec = constraint.getSpecification(); constLabel.append(constraint.getName()); constLabel.append(EOL); - constLabel.append(OPEN_BRACKET); - if (valueSpec == null) { - constLabel.append(NULL_CONSTRAINT); - } else if (valueSpec instanceof OpaqueExpression) { - OpaqueExpression opaqueEsp = (OpaqueExpression) valueSpec; - if (!opaqueEsp.getBodies().isEmpty() && !opaqueEsp.getLanguages().isEmpty()) { - body = opaqueEsp.getBodies().get(0); - lang = opaqueEsp.getLanguages().get(0); - constLabel.append(OPEN_BRACKET); - constLabel.append(lang); - constLabel.append(CLOSE_BRACKET); - constLabel.append(SPACE); - constLabel.append(body); + + ValueSpecification value = constraint.getSpecification(); + String specLabel; + if (value == null) { + specLabel = NULL_CONSTRAINT; + } else if (value instanceof OpaqueExpression expression) { + if (!expression.getBodies().isEmpty()) { + String lang = expression.getLanguages().get(0); + specLabel = expression.getBodies().get(0); + if (!lang.isEmpty()) { // if language is available, prefix the label. + specLabel = encloseInBrackets(lang) + SPACE + specLabel; + } } else { - constLabel.append(OPEN_BRACKET); - constLabel.append(NATURAL); - constLabel.append(CLOSE_BRACKET); - constLabel.append(SPACE); + specLabel = encloseInBrackets(NATURAL) + SPACE; } + } else { + specLabel = valueSpecificationHelper.getSpecificationValue(value, false); } - constLabel.append(CLOSE_BRACKET); - return constLabel.toString(); + + return encloseInBrackets(specLabel, constLabel).toString(); } @Override public String caseOperation(Operation operation) { return this.operationLabelHelper.getLabel(operation); } - + @Override public String caseReception(Reception reception) { return this.receptionLabelHelper.getLabel(reception); } + @Override + public String caseStateInvariant(StateInvariant stateInvariant) { + ValueSpecification value = null; + if (stateInvariant.getInvariant() != null) { + value = stateInvariant.getInvariant().getSpecification(); + } + return getValueBasedLabel(stateInvariant, value); + } + + @Override + public String caseDurationObservation(DurationObservation object) { + return namedElementNameProvider.getName(object) + DURATION_OBSERVATION; + } + + @Override + public String caseTimeObservation(TimeObservation object) { + return namedElementNameProvider.getName(object) + TIME_OBSERVATION; + } + + @Override + public String caseIntervalConstraint(IntervalConstraint object) { + // Time and Duration constraint. + return getValueBasedLabel(object, object.getSpecification()); + } + @Override public String caseTimeExpression(TimeExpression timeExpression) { StringBuilder constLabel = new StringBuilder(); @@ -408,11 +436,8 @@ public final class ElementLabelProvider implements IViewLabelProvider { StringBuilder constLabel = new StringBuilder(); ValueSpecification joinSpec = joinNode.getJoinSpec(); if (joinSpec != null) { - constLabel.append(OPEN_BRACKET); - constLabel.append(JOIN_SPEC); - constLabel.append(SPACE + EQL + SPACE); - constLabel.append(this.valueSpecificationHelper.getSpecificationValue(joinSpec, true)); - constLabel.append(CLOSE_BRACKET); + encloseInBrackets(JOIN_SPEC + this.valueSpecificationHelper.getSpecificationValue(joinSpec, true), + constLabel); constLabel.append(EOL); } constLabel.append(this.namedElementNameProvider.getName(joinNode)); @@ -421,22 +446,22 @@ public final class ElementLabelProvider implements IViewLabelProvider { @Override public String caseStructuredActivityNode(StructuredActivityNode structuredActivityNode) { - return ST_LEFT + STRUCTURED + ST_RIGHT; + return STRUCTURED; } @Override public String caseLoopNode(LoopNode loopNode) { - return ST_LEFT + LOOP_NODE + ST_RIGHT; + return LOOP_NODE; } @Override public String caseSequenceNode(SequenceNode sequenceNode) { - return ST_LEFT + SEQUENCE + ST_RIGHT; + return SEQUENCE; } @Override public String caseConditionalNode(ConditionalNode conditionalNode) { - return ST_LEFT + CONDITIONAL + ST_RIGHT; + return CONDITIONAL; } @Override @@ -445,30 +470,25 @@ public final class ElementLabelProvider implements IViewLabelProvider { ConnectableElement connectableElement = lifeline.getRepresents(); ValueSpecification selector = lifeline.getSelector(); if (connectableElement == null) { - if (!(selector instanceof LiteralSpecification) && !(selector instanceof Expression) - && !(selector instanceof OpaqueExpression) && !(selector instanceof TimeExpression)) { - String lifelineName = this.namedElementNameProvider.getName(lifeline); - if (lifelineName != null) { - lifelineLabel.append(lifelineName); - } + + String lifelineName = this.namedElementNameProvider.getName(lifeline); + if (lifelineName != null) { + lifelineLabel.append(lifelineName); } + } else { String connectableElementName = this.namedElementNameProvider.getName(connectableElement); - if (connectableElement != null) { + if (connectableElementName != null) { lifelineLabel.append(connectableElementName); } if (selector != null) { - if (selector instanceof LiteralSpecification) { - lifelineLabel.append(OPEN_ANGLE_BRACKET); - lifelineLabel.append(this.valueSpecificationHelper.getSpecificationValue(selector, true)); - lifelineLabel.append(CLOSE_ANGLE_BRACKET); - } + lifelineLabel.append(OPEN_ANGLE_BRACKET); + lifelineLabel.append(this.valueSpecificationHelper.getSpecificationValue(selector, true)); + lifelineLabel.append(CLOSE_ANGLE_BRACKET); } Type type = connectableElement.getType(); - if (type != null && type.getName() != null && type.getName().length() > 0) { - lifelineLabel.append(SPACE); - lifelineLabel.append(D_DOTS); - lifelineLabel.append(SPACE); + if (type != null) { + lifelineLabel.append(TYPED); lifelineLabel.append(this.namedElementNameProvider.getName(type)); } } @@ -485,10 +505,8 @@ public final class ElementLabelProvider implements IViewLabelProvider { if (!objectFlowStringBuilder.isEmpty()) { objectFlowStringBuilder.append(EOL); } - objectFlowStringBuilder.append(OPEN_BRACKET); - objectFlowStringBuilder.append(WEIGHT + EQL); - objectFlowStringBuilder.append(this.valueSpecificationHelper.getSpecificationValue(weight, true)); - objectFlowStringBuilder.append(CLOSE_BRACKET); + encloseInBrackets(WEIGHT + valueSpecificationHelper.getSpecificationValue(weight, true), + objectFlowStringBuilder); } if (guard != null) { if (!objectFlowStringBuilder.isEmpty()) { @@ -500,6 +518,25 @@ public final class ElementLabelProvider implements IViewLabelProvider { } return objectFlowStringBuilder.toString(); } + + private String getValueBasedLabel(NamedElement element, ValueSpecification value) { + // Without content, show the name. + if (value == null) { + return namedElementNameProvider.getName(element); + } + return encloseInBrackets(valueSpecificationHelper.getSpecificationValue(value, false)); + } + } + + private static StringBuilder encloseInBrackets(String content, StringBuilder builder) { + builder.append(OPEN_BRACKET); + builder.append(content); + builder.append(CLOSE_BRACKET); + return builder; + } + + private static String encloseInBrackets(String content) { + return encloseInBrackets(content, new StringBuilder()).toString(); } public static Builder builder() { diff --git a/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/labels/UMLCharacters.java b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/labels/UMLCharacters.java index 1a8b5259e115fc9d2436412e48f9538e2295a344..88aee9b809fb657f290c610549dfb928826fb39a 100644 --- a/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/labels/UMLCharacters.java +++ b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/labels/UMLCharacters.java @@ -1,5 +1,5 @@ /***************************************************************************** - * Copyright (c) 2022, 2023 CEA LIST, Obeo. + * Copyright (c) 2022, 2024 CEA LIST, Obeo. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -43,7 +43,9 @@ public final class UMLCharacters { public static final String EQL = "="; //$NON-NLS-1$ - public static final String EOL = System.lineSeparator(); + // Do not use System line separator. + // Linux and Windows must edit model in the same way. + public static final String EOL = "\n"; //$NON-NLS-1$ public static final String TILDE = "\u007E"; //$NON-NLS-1$ @@ -51,16 +53,18 @@ public final class UMLCharacters { public static final String OPEN_BRACKET = "{"; //$NON-NLS-1$ - /** - * Open quote mark. - */ + /** Open guillemet quote mark. */ public static final String ST_LEFT = "\u00AB"; //$NON-NLS-1$ - /** - * Close quote mark. - */ + /** Close guillemet quote mark. */ public static final String ST_RIGHT = "\u00BB"; //$NON-NLS-1$ + /** Open quote mark. */ + public static final String Q_LEFT = "\u201C"; //$NON-NLS-1$ + + /** Close quote mark. */ + public static final String Q_RIGHT = "\u201D"; //$NON-NLS-1$ + /** The * KeyWord to represent an unlimited integer (infinite). */ public static final String UNLIMITED_KEYWORD = "*"; //$NON-NLS-1$ diff --git a/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/labels/domains/ValueSpecificationLabelHelper.java b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/labels/domains/ValueSpecificationLabelHelper.java index 65b4938999e09cbc97251c60fde01a7341e474f0..33f2cae62b7f174d017f36269575868c370fc5e7 100644 --- a/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/labels/domains/ValueSpecificationLabelHelper.java +++ b/plugins/org.eclipse.papyrus.uml.domain.services/src/org/eclipse/papyrus/uml/domain/services/labels/domains/ValueSpecificationLabelHelper.java @@ -1,5 +1,5 @@ /***************************************************************************** - * Copyright (c) 2008, 2023 CEA LIST. + * Copyright (c) 2008, 2024 CEA LIST. * * * All rights reserved. This program and the accompanying materials @@ -26,6 +26,7 @@ import static org.eclipse.papyrus.uml.domain.services.labels.UMLCharacters.TRUE; import java.util.Collection; import org.eclipse.papyrus.uml.domain.services.labels.INamedElementNameProvider; +import org.eclipse.papyrus.uml.domain.services.labels.UMLCharacters; import org.eclipse.uml2.uml.Constraint; import org.eclipse.uml2.uml.Duration; import org.eclipse.uml2.uml.Expression; @@ -34,7 +35,6 @@ import org.eclipse.uml2.uml.Interval; import org.eclipse.uml2.uml.LiteralBoolean; import org.eclipse.uml2.uml.LiteralInteger; import org.eclipse.uml2.uml.LiteralNull; -import org.eclipse.uml2.uml.LiteralReal; import org.eclipse.uml2.uml.LiteralString; import org.eclipse.uml2.uml.LiteralUnlimitedNatural; import org.eclipse.uml2.uml.OpaqueExpression; @@ -53,10 +53,8 @@ public class ValueSpecificationLabelHelper { private static final String ONE = "1"; //$NON-NLS-1$ - /** The * KeyWord to represent an unlimited integer (infinite) */ - private static final String UNLIMITED_KEYWORD = "*"; //$NON-NLS-1$ - - private static final String INTERVAL_FORMAT = "%1s..%2s"; //$NON-NLS-1$ + /** The '*' KeyWord to represent an unlimited integer (infinite) */ + private static final String UNLIMITED_KEYWORD = UMLCharacters.MANY; /** * Provider of element name. @@ -100,20 +98,11 @@ public class ValueSpecificationLabelHelper { if (specification != null && specification.eClass() != null) { switch (specification.eClass().getClassifierID()) { case UMLPackage.LITERAL_STRING: - value = ((LiteralString) specification).getValue(); - break; case UMLPackage.LITERAL_BOOLEAN: - value = Boolean.toString(((LiteralBoolean) specification).booleanValue()); - break; case UMLPackage.LITERAL_INTEGER: - value = Integer.toString(((LiteralInteger) specification).getValue()); - break; case UMLPackage.LITERAL_UNLIMITED_NATURAL: - value = Integer.toString(((LiteralUnlimitedNatural) specification).getValue()); - if ("-1".equals(value)) { //$NON-NLS-1$ - value = UNLIMITED_KEYWORD; - } - break; + case UMLPackage.LITERAL_REAL: + value = specification.stringValue(); case UMLPackage.LITERAL_NULL: break; case UMLPackage.OPAQUE_EXPRESSION: @@ -153,7 +142,7 @@ public class ValueSpecificationLabelHelper { case UMLPackage.DURATION: Duration durationExpr = (Duration) specification; if (durationExpr.getExpr() != null) { - value = this.getSpecificationValue(durationExpr.getExpr()); + value = safeReferenceValue(specification, durationExpr.getExpr()); } else if (durationExpr.getObservations().size() > 0) { if (useInternationalization) { value = this.namedElementNameProvider.getName(durationExpr.getObservations().get(0)); @@ -165,7 +154,7 @@ public class ValueSpecificationLabelHelper { case UMLPackage.TIME_EXPRESSION: TimeExpression timeExpr = (TimeExpression) specification; if (timeExpr.getExpr() != null) { - value = this.getSpecificationValue(timeExpr.getExpr()); + value = safeReferenceValue(specification, timeExpr.getExpr()); } else if (timeExpr.getObservations().size() > 0) { if (useInternationalization) { value = this.namedElementNameProvider.getName(timeExpr.getObservations().get(0)); @@ -177,18 +166,16 @@ public class ValueSpecificationLabelHelper { case UMLPackage.INTERVAL: case UMLPackage.TIME_INTERVAL: case UMLPackage.DURATION_INTERVAL: - if (!(specification instanceof Interval)) { // safety test for bug 430525, but should not be necessary - // to perform a test here... + if (!(specification instanceof Interval interval)) { + // safety test for bug 430525, but should not be necessary + // to perform a test here... break; } - Interval interval = (Interval) specification; - String min = this.getSpecificationValue(interval.getMin()); - String max = this.getSpecificationValue(interval.getMax()); - value = String.format(INTERVAL_FORMAT, min, max); + String min = safeReferenceValue(specification, interval.getMin()); + String max = safeReferenceValue(specification, interval.getMax()); + + value = min + UMLCharacters.CARD_SEP + max; break; - case UMLPackage.LITERAL_REAL: - LiteralReal real = (LiteralReal) specification; - return Double.toString(real.getValue()); // Precision? default: { break; } @@ -196,9 +183,19 @@ public class ValueSpecificationLabelHelper { } return value; } - // CHECKSTYLE:ON + + private String safeReferenceValue(ValueSpecification caller, ValueSpecification called) { + // UML can have reference in ValueSpecification without containment. + // This is a naive implementation (1-level) for basic mistake. + // A proper implementation would require an expensive call stack. + if (caller == called) { + return EMPTY; + } + return getSpecificationValue(called); + } + /** * Get a string representing a Constraint. * @@ -297,11 +294,7 @@ public class ValueSpecificationLabelHelper { * the new value */ public static void restoreLiteralBoolean(LiteralBoolean specification, String value) { - if (TRUE.equals(value) || ONE.equals(value)) { - specification.setValue(true); - } else { - specification.setValue(false); - } + specification.setValue(TRUE.equals(value) || ONE.equals(value)); } /** diff --git a/pom.xml b/pom.xml index dee199d2213f61c9f3c35236767337c7132d7e66..795c1a84fa99e9c83d05ffd08c2486f0ccca2d74 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ <modelVersion>4.0.0</modelVersion> <groupId>org.eclipse.papyrus.domainservices</groupId> <artifactId>container</artifactId> - <version>0.23.0-SNAPSHOT</version> + <version>0.24.0</version> <packaging>pom</packaging> <name>Papyrus-UML-services</name> diff --git a/releng/category/org.eclipse.papyrus.uml.domain.services.updatesite/pom.xml b/releng/category/org.eclipse.papyrus.uml.domain.services.updatesite/pom.xml index e4153157dafd7dc9b1f456cb0d50dac3cc8f574e..a71f6086403305224d94d23eafa980713a4d06a9 100644 --- a/releng/category/org.eclipse.papyrus.uml.domain.services.updatesite/pom.xml +++ b/releng/category/org.eclipse.papyrus.uml.domain.services.updatesite/pom.xml @@ -7,7 +7,7 @@ <parent> <groupId>org.eclipse.papyrus.domainservices</groupId> <artifactId>parent</artifactId> - <version>0.23.0-SNAPSHOT</version> + <version>0.24.0</version> <relativePath>../../../parent</relativePath> </parent> diff --git a/releng/targetplatform/org.eclipse.papyrus.uml.domain.services.releng.target/papyrusSiriusServices.target b/releng/targetplatform/org.eclipse.papyrus.uml.domain.services.releng.target/papyrusSiriusServices.target index 289124c15c9520956d6427b0d9d7f760160dccc3..2ad6b0bf2bc18014840fb57ad1fa058381e095f5 100644 --- a/releng/targetplatform/org.eclipse.papyrus.uml.domain.services.releng.target/papyrusSiriusServices.target +++ b/releng/targetplatform/org.eclipse.papyrus.uml.domain.services.releng.target/papyrusSiriusServices.target @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="Papyrus-Uml-Services - 2024-06" sequenceNumber="1718979530"> +<target name="Papyrus-Uml-Services - 2024-06" sequenceNumber="1734687882"> <locations> <location includeMode="planner" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="false" type="InstallableUnit"> <unit id="org.eclipse.uml2.sdk.feature.group" version="5.5.3.v20221116-1811"/> @@ -12,12 +12,12 @@ <repository id="Eclipse-Shared-License" location="https://download.eclipse.org/cbi/updates/license"/> </location> <location includeMode="planner" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="false" type="InstallableUnit"> - <unit id="org.slf4j.api" version="0.0.0"/> - <unit id="org.junit.jupiter.api" version="0.0.0"/> - <unit id="org.junit.jupiter.params" version="0.0.0"/> - <unit id="org.junit.platform.commons" version="0.0.0"/> - <unit id="org.junit.platform.engine" version="0.0.0"/> - <repository id="orbit" location="https://download.eclipse.org/tools/orbit/downloads/drops/S20230516204213/repository"/> + <unit id="slf4j.api" version="0.0.0"/> + <unit id="junit-jupiter-api" version="0.0.0"/> + <unit id="junit-jupiter-params" version="0.0.0"/> + <unit id="junit-platform-commons" version="0.0.0"/> + <unit id="junit-platform-engine" version="0.0.0"/> + <repository id="orbit" location="https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2024-06"/> </location> <location includeMode="planner" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="false" type="InstallableUnit"> <unit id="org.eclipse.sdk.feature.group" version="0.0.0"/> diff --git a/releng/targetplatform/org.eclipse.papyrus.uml.domain.services.releng.target/papyrusSiriusServices.tpd b/releng/targetplatform/org.eclipse.papyrus.uml.domain.services.releng.target/papyrusSiriusServices.tpd index e73a996bcf2117a454e2461b4fa1aedaeac3ac2c..b76bf80fefde767d9c4fcfdf87df5ae206bcb77d 100644 --- a/releng/targetplatform/org.eclipse.papyrus.uml.domain.services.releng.target/papyrusSiriusServices.tpd +++ b/releng/targetplatform/org.eclipse.papyrus.uml.domain.services.releng.target/papyrusSiriusServices.tpd @@ -11,13 +11,12 @@ location Eclipse-Shared-License "https://download.eclipse.org/cbi/updates/licens } // manual update -location orbit "https://download.eclipse.org/tools/orbit/downloads/drops/S20230516204213/repository" { - org.slf4j.api lazy - org.junit.jupiter.api lazy - org.junit.jupiter.params lazy - org.junit.platform.commons lazy - org.junit.platform.engine lazy - +location orbit "https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2024-06" { + slf4j.api lazy + junit-jupiter-api lazy + junit-jupiter-params lazy + junit-platform-commons lazy + junit-platform-engine lazy } // manual update diff --git a/releng/targetplatform/org.eclipse.papyrus.uml.domain.services.releng.target/pom.xml b/releng/targetplatform/org.eclipse.papyrus.uml.domain.services.releng.target/pom.xml index bf7b4a9d290e1997a4bcfaa31ff91d4a6ea898c5..14c22cf0c72a1f2ef581b4769a61f04d10c3e63a 100644 --- a/releng/targetplatform/org.eclipse.papyrus.uml.domain.services.releng.target/pom.xml +++ b/releng/targetplatform/org.eclipse.papyrus.uml.domain.services.releng.target/pom.xml @@ -7,7 +7,7 @@ <parent> <groupId>org.eclipse.papyrus.domainservices</groupId> <artifactId>parent</artifactId> - <version>0.23.0-SNAPSHOT</version> + <version>0.24.0</version> <relativePath>../../../parent</relativePath> </parent>