| /***************************************************************************** |
| * Copyright (c) 2013, 2016 CEA LIST, Christian W. Damus, and others. |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation |
| * Christian W. Damus - bug 465656 |
| *****************************************************************************/ |
| import RSAToPapyrus; |
| |
| modeltype notation "strict" uses 'http://www.eclipse.org/gmf/runtime/1.0.2/notation'; |
| modeltype umlNotation "strict" uses 'http://www.eclipse.org/papyrus/umlnotation'; |
| modeltype uml "strict" uses 'http://www.eclipse.org/uml2/5.0.0/UML'; |
| modeltype ecore "strict" uses 'http://www.eclipse.org/emf/2002/Ecore'; |
| modeltype sash "strict" uses 'http://www.eclipse.org/papyrus/0.7.0/sashdi'; |
| modeltype config "strict" uses 'http:///RSAToPapyrusParameters.ecore'; |
| |
| transformation RSAStateMachineDiagram(inout semantics : uml, inout graphics : notation, out di : sash, in param : config); |
| |
| main() { |
| semantics.rootObjects()[uml::Element]->map toOwnedDiagrams(); |
| } |
| |
| query View::getDiagramType() : String{ |
| return 'PapyrusUMLStateMachineDiagram'; |
| } |
| |
| mapping notation::Diagram::generateDiagram() : notation::Diagram inherits Diagram::toPapyrusDiagram when { |
| self.type = 'Statechart' |
| }{ |
| end { |
| graphics.objectsOfType(DecorationNode)->select(type = 'Region_SubvertexCompartment').map addInRegion(); |
| graphics.objectsOfType(Shape)->select(type = 'StateMachine_Shape').map createIntermediateCompartment(); |
| graphics.objectsOfType(Shape)->select(type = 'State_Shape').map createStructureCompartment(); |
| graphics.objectsOfType(DecorationNode)->select(type = 'StateMachine_NameLabel').map addLayout(); |
| graphics.objectsOfType(DecorationNode)->select(type = 'State_NameLabel').map fixLayout(); |
| |
| graphics.objectsOfType(Shape)->select(type='Comment_Shape').map addCommentDecoration(); |
| graphics.objectsOfType(Shape)->select(type = 'Constraint_Shape').map addConstraintDecoration(); |
| } |
| } |
| |
| mapping inout Shape::createIntermediateCompartment() { |
| var compartment := object DecorationNode { |
| type := 'StateMachine_RegionCompartment'; |
| layoutConstraint := object Bounds{} |
| }; |
| |
| compartment.children := self.children->select(type = 'Region_Shape'); |
| |
| children := children->insertAt(2, compartment); /* Required for layout: the Structure Compartment of the Region must be in 2nd position */ |
| } |
| |
| mapping inout DecorationNode::addInRegion() { |
| var currentParent := self.oclAsType(EObject).eContainer(); |
| var currentBounds := self.layoutConstraint.oclAsType(Bounds); |
| |
| var region := object Shape { |
| type := 'Region_Shape'; |
| layoutConstraint := object Bounds{ |
| x := currentBounds.x; |
| y := currentBounds.y; |
| }; |
| element := self.element; |
| children := self; |
| eAnnotations := object EAnnotation { |
| source := "RegionAnnotationKey"; |
| details := object EStringToStringMapEntry{ |
| key := "RegionZoneKey"; |
| value := 'B'; |
| } |
| } |
| }; |
| |
| if self.layoutConstraint.oclIsUndefined() then self.layoutConstraint := object Bounds{} endif; |
| self.styles := self.styles->reject(oclIsTypeOf(TitleStyle)); |
| |
| currentParent.oclAsType(View).children += region; |
| } |
| |
| mapping inout Shape::createStructureCompartment() when { |
| not self.children->exists(type = 'State_RegionCompartment') |
| }{ |
| var compartment := object DecorationNode { |
| type := 'State_RegionCompartment'; |
| visible := self.children->exists(type='Region_Shape'); |
| layoutConstraint := object Bounds{}; |
| }; |
| |
| compartment.children += children->select(type = 'Region_Shape'); |
| children := children->insertAt(2, compartment); |
| } |
| |
| mapping inout DecorationNode::addLayout() { |
| if self.layoutConstraint.oclIsUndefined() then self.layoutConstraint := object Bounds{} endif; |
| } |
| |
| mapping inout DecorationNode::fixLayout(){ |
| var bounds := if self.layoutConstraint.oclIsUndefined() then object Bounds{} else self.layoutConstraint.oclAsType(Bounds) endif; |
| self.layoutConstraint := bounds; |
| |
| if bounds.height < 20 then bounds.height := 20 endif; |
| } |
| |
| mapping Node::toNode() : Node disjuncts |
| UMLShape::toPapyrusShape, |
| UMLShapeCompartment::toStructureCompartment, |
| BasicSemanticCompartment::toListCompartment, |
| BasicDecorationNode::toConnectorLabel, |
| BasicDecorationNode::toLabel |
| //TODO: Disjunct nodes mapping |
| ; |
| |
| mapping Edge::toEdge() : Edge disjuncts |
| UMLConnector::toCommentLink, |
| UMLConnector::toConstraintLink, |
| UMLConnector::toPapyrusConnector |
| //TODO: Disjunct edges mapping |
| ; |
| |
| mapping UMLShapeCompartment::toStructureCompartment() : DecorationNode inherits UMLShapeCompartment::toAbstractStructureCompartment when { |
| not self.getType().oclIsUndefined(); |
| }{ |
| |
| } |
| |
| mapping inout Shape::addCommentDecoration() when { |
| self.type = 'Comment_Shape' and self.diagram.type = self.getDiagramType() |
| } { |
| |
| self.children += object DecorationNode{ |
| type := 'Comment_BodyLabel'; |
| } |
| |
| } |
| |
| mapping inout Shape::addConstraintDecoration() when { |
| self.type = 'Constraint_Shape' and self.diagram.type = self.getDiagramType() |
| } { |
| |
| self.children += object DecorationNode{ |
| type := 'Constraint_BodyLabel'; //Constraint specification |
| } |
| |
| } |
| |
| /***** Nodes **********/ |
| |
| mapping UMLShape::toPapyrusShape() : Shape inherits Shape::toPapyrusShape when { |
| not self.getType().oclIsUndefined() |
| }{ |
| |
| } |
| |
| |
| /****** Connector Labels ******/ |
| |
| mapping BasicDecorationNode::toConnectorLabel() : DecorationNode inherits Node::toPapyrusConnectorLabel when { |
| not self.getType().oclIsUndefined() and ( |
| self.type = 'ToMultiplicityLabel' or |
| self.type = 'ToRoleLabel' or |
| self.type = 'FromMultiplicityLabel' or |
| self.type = 'FromRoleLabel' or |
| self.type = 'NameLabel' or |
| self.type = 'KindLabel' |
| ) |
| }{ |
| |
| } |
| |
| /****** Compartments *******/ |
| |
| mapping BasicDecorationNode::toLabel() : DecorationNode inherits Node::toPapyrusNode when { |
| not self.getType().oclIsUndefined() and |
| self.element.oclIsKindOf(uml::NamedElement) and |
| self.type = 'Name' |
| }{ |
| |
| } |
| |
| mapping BasicSemanticCompartment::toListCompartment() : BasicCompartment inherits Node::toPapyrusNode, DrawerStyle::toDrawerStyle when { |
| self.type.endsWith('Compartment') and not self.getType().oclIsUndefined() |
| }{ |
| |
| } |
| |
| |
| mapping uml::State::fillTransition(node : BasicSemanticCompartment) : Sequence(Node) when { |
| node.type=''; |
| }{ |
| init { |
| result := self.incoming->selectByKind(Transition).map toTransitionIn(node)->asSequence(); |
| } |
| } |
| |
| mapping uml::State::fillBehavior(node : BasicSemanticCompartment) : Sequence(Node) when { |
| node.type=''; |
| }{ |
| init { |
| result := self.entry->selectByKind(Behavior).map toBehaviorIn(node)->asSequence(); |
| } |
| } |
| |
| mapping Transition::toTransitionIn(node : Node) : Shape inherits Element::toCompartmentEntry { |
| result.type := 'Transition_InternalTransitionLabel'; |
| } |
| |
| mapping Behavior::toBehaviorIn(node : Node) : Shape inherits Element::toCompartmentEntry { |
| result.type := 'Behavior_EntryBehaviorLabel'; |
| } |
| |
| |
| |
| /******* Edges ********/ |
| |
| |
| mapping UMLConnector::toPapyrusConnector() : Connector inherits Connector::toPapyrusConnector when { |
| self.type = '' and |
| not self.getType().oclIsUndefined() and ( |
| self.element.oclIsTypeOf(Transition)or |
| self.element.oclIsTypeOf(Generalization) |
| ) |
| }{ |
| result.styles := self.map toFontStyle(); |
| } |
| |
| |
| mapping UMLConnector::toCommentLink() : Connector inherits Connector::toCommentLink when{ |
| self.type='Reference' |
| }{ |
| result.type :='Comment_AnnotatedElementEdge'; |
| result.bendpoints := self.bendpoints.map toBendpoint(self.diagram); |
| result.sourceAnchor := object IdentityAnchor{}; |
| } |
| |
| mapping UMLConnector::toConstraintLink() : Connector inherits Connector::toPapyrusConnector when{ |
| self.type='Reference' and ( |
| self.source.element.oclIsTypeOf(Constraint) or |
| self.target.element.oclIsKindOf(Constraint) |
| ) |
| }{ |
| result.type :='Constraint_ConstrainedElementEdge'; |
| result.bendpoints := self.bendpoints.map toBendpoint(self.diagram); |
| result.sourceAnchor := object IdentityAnchor{}; |
| } |
| |
| |
| /****** Element Type queries ******/ |
| |
| query View::getNodeType(element : Element) : String { |
| return |
| if element.oclIsTypeOf(Comment) then 'Comment_Shape' |
| elif element.oclIsTypeOf(FinalState) then 'FinalState_Shape' |
| elif element.oclIsTypeOf(Pseudostate) and element.oclAsType(Pseudostate).kind = PseudostateKind::join then 'Pseudostate_JoinShape' |
| elif element.oclIsTypeOf(State) then 'State_Shape' |
| elif element.oclIsTypeOf(Pseudostate) and element.oclAsType(Pseudostate).kind = PseudostateKind::shallowHistory then 'Pseudostate_ShallowHistoryShape' |
| elif element.oclIsTypeOf(Pseudostate) and element.oclAsType(Pseudostate).kind = PseudostateKind::terminate then 'Pseudostate_TerminateShape' |
| elif element.oclIsTypeOf(Pseudostate) and element.oclAsType(Pseudostate).kind = PseudostateKind::choice then 'Pseudostate_ChoiceShape' |
| elif element.oclIsTypeOf(Constraint) then 'Constraint_Shape' |
| elif element.oclIsTypeOf(StateMachine) then 'StateMachine_Shape' |
| elif element.oclIsTypeOf(Pseudostate) and element.oclAsType(Pseudostate).kind = PseudostateKind::fork then 'Pseudostate_ForkShape' |
| elif element.oclIsTypeOf(Region) then 'Region_Shape' |
| elif element.oclIsTypeOf(Pseudostate) and element.oclAsType(Pseudostate).kind = PseudostateKind::junction then 'Pseudostate_JunctionShape' |
| elif element.oclIsTypeOf(Pseudostate) and element.oclAsType(Pseudostate).kind = PseudostateKind::deepHistory then 'Pseudostate_DeepHistoryShape' |
| elif element.oclIsTypeOf(Pseudostate) and element.oclAsType(Pseudostate).kind = PseudostateKind::initial then 'Pseudostate_InitialShape' |
| elif element.oclIsTypeOf(Pseudostate) and element.oclAsType(Pseudostate).kind = PseudostateKind::entryPoint then 'Pseudostate_EntryPointShape' |
| elif element.oclIsTypeOf(Pseudostate) and element.oclAsType(Pseudostate).kind = PseudostateKind::exitPoint then 'Pseudostate_ExitPointShape' |
| elif element.oclIsTypeOf(ConnectionPointReference) then 'ConnectionPointReference_Shape' |
| else self.fail() |
| endif; |
| } |
| |
| |
| query View::getDecorationType(element : Element) : String{ |
| var res := self.doGetDecorationType(element); |
| |
| |
| /*log('Get papyrus ID for'+ self.element.eClass().name+', '+self.type); |
| |
| log(res); |
| |
| if self.container().oclIsKindOf(Node) then |
| log('IsNode') |
| else |
| log('IsEdge') |
| endif;*/ |
| |
| |
| return res; |
| } |
| |
| query View::doGetDecorationType(element : Element) : String{ |
| return if self.container().oclIsKindOf(Node) then { |
| return if element.oclIsTypeOf(Pseudostate) then |
| return switch { |
| case (self.type = 'Name') 'Pseudostate_ChoiceFloatingNameLabel'; |
| |
| } |
| elif element.oclIsTypeOf(Pseudostate) then |
| return switch { |
| case (self.type = 'Name') 'Pseudostate_ExitPointFloatingNameLabel'; |
| |
| } |
| elif element.oclIsTypeOf(Pseudostate) then |
| return switch { |
| case (self.type = 'Name') 'Pseudostate_ShallowHistoryFloatingNameLabel'; |
| |
| } |
| elif element.oclIsTypeOf(Pseudostate) then |
| return switch { |
| case (self.type = 'Name') 'Pseudostate_JoinFloatingNameLabel'; |
| |
| } |
| elif element.oclIsTypeOf(Pseudostate) then |
| return switch { |
| case (self.type = 'Name') 'Pseudostate_InitialFloatingNameLabel'; |
| |
| } |
| elif element.oclIsTypeOf(Region) then |
| return switch { |
| |
| case (self.type = 'Region' or self.type = '') 'Region_SubvertexCompartment'; |
| } |
| elif element.oclIsTypeOf(ConnectionPointReference) then |
| return switch { |
| case (self.type = 'Name') 'ConnectionPointReference_NameLabel'; |
| |
| } |
| elif element.oclIsTypeOf(State) then |
| return switch { |
| case (self.type = 'Name') 'State_NameLabel'; |
| } |
| elif element.oclIsTypeOf(FinalState) then |
| return switch { |
| case (self.type = 'Name') 'FinalState_FloatingNameLabel'; |
| |
| } |
| elif element.oclIsTypeOf(Pseudostate) then |
| return switch { |
| case (self.type = 'Name') 'Pseudostate_DeepHistoryFloatingNameLabel'; |
| |
| } |
| elif element.oclIsTypeOf(Pseudostate) then |
| return switch { |
| case (self.type = 'Name') 'Pseudostate_TerminateFloatingNameLabel'; |
| |
| } |
| elif element.oclIsTypeOf(Pseudostate) then |
| return switch { |
| case (self.type = 'Name') 'Pseudostate_ForkFloatingNameLabel'; |
| |
| } |
| elif element.oclIsTypeOf(Pseudostate) then |
| return switch { |
| case (self.type = 'Name') 'Pseudostate_EntryPointFloatingNameLabel'; |
| |
| } |
| elif element.oclIsTypeOf(StateMachine) then |
| return switch { |
| case (self.type = 'Name') 'StateMachine_NameLabel'; |
| case (self.type = 'StructureCompartment') 'StateMachine_RegionCompartment'; |
| } |
| elif element.oclIsTypeOf(Pseudostate) then |
| return switch { |
| case (self.type = 'Name') 'Pseudostate_JunctionFloatingNameLabel'; |
| |
| } |
| endif |
| } else { |
| return if element.oclIsTypeOf(Transition) then |
| return switch { |
| case (self.type='Name') 'Transition_NameLabel'; |
| case (self.type = 'NameLabel') 'Transition_NameLabel'; |
| |
| |
| } |
| endif |
| } endif; |
| } |
| |
| |
| query View::getEdgeType(element : Element) : String { |
| return |
| if self.type = 'Reference' then '' /* Constraint/Comment links handled separately */ |
| elif element.oclIsTypeOf(Transition) then 'Transition_Edge' |
| elif element.oclIsTypeOf(Generalization) then 'Generalization_Edge' |
| else self.fail() |
| endif; |
| } |
| |