Skip to content

Commit

Permalink
Preserving style when the type of a task or a gateway is changed
Browse files Browse the repository at this point in the history
Change-Id: I6f56fb425d916f80c60f4df74c2144233308b263
  • Loading branch information
Stephane Drapeau authored and Stephane Drapeau committed Mar 18, 2024
1 parent cab5889 commit 5c1d3de
Show file tree
Hide file tree
Showing 11 changed files with 844 additions and 474 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,39 +22,39 @@
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.sirius.diagram.AbstractDNode;
import org.eclipse.sirius.diagram.DDiagram;
import org.eclipse.sirius.diagram.DNode;
import org.eclipse.sirius.diagram.description.AbstractNodeMapping;
import org.eclipse.sirius.diagram.description.ContainerMapping;
import org.eclipse.sirius.diagram.description.Layer;
import org.eclipse.sirius.diagram.description.NodeMapping;
import org.obeonetwork.bpmn2.design.refactoring.SiriusElementRefactor;
import org.obeonetwork.bpmn2.design.ui.PopupChoiceSelector;
import org.obeonetwork.bpmn2.design.ui.UiConstants;
import org.obeonetwork.dsl.bpmn2.Bpmn2Package;
import org.obeonetwork.dsl.bpmn2.Gateway;


/**
* Conversion services to operate on FlowNode objects.
*
* @author nperansin
*
*/
public class FlowNodeService {

private static final Bpmn2Package PKG = Bpmn2Package.eINSTANCE;
private static final List<EClass> GATEWAY_CLASSES = Arrays.asList(
// Order is the same to Gateways Toolsection of VSM
PKG.getParallelGateway(), PKG.getExclusiveGateway(),
PKG.getInclusiveGateway(), PKG.getComplexGateway(),
PKG.getEventBasedGateway()
);
PKG.getParallelGateway(), PKG.getExclusiveGateway(), PKG.getInclusiveGateway(), PKG.getComplexGateway(),
PKG.getEventBasedGateway());

/**
* Converts a Gateway into another kind.
* <p>
* Most of related data are restored.
* </p>
*
* @param view of Gateway
* @param view of Gateway
* @param eClass class to convert in
* @return created Gateway
*/
Expand All @@ -63,46 +63,57 @@ public static Gateway convertToSpecificGateway(AbstractDNode view, EClass eClass
if (eClass.equals(previous.eClass())) {
return previous;
}

return (Gateway) new SiriusElementRefactor(view) {
@Override
protected boolean isTransferable(EStructuralFeature feature, EClass targetType) {
return Bpmn2Package.eINSTANCE.getBaseElement_Id() != feature;
}

@Override
protected AbstractNodeMapping getApplicableNodeMapping(AbstractNodeMapping previous, EObject current) {
// Gateways have several mappings. (For no good reason: only image)
return current instanceof Gateway
? getGatewayMapping(previous.eContainer(), current)
: previous;
// Gateways have several mappings.
return current instanceof Gateway ? getGatewayMapping(previous, current) : previous;
}

@Override
protected void postCreateNewNode(AbstractDNode newDNode, boolean isExternalLabel) {
if (newDNode instanceof DNode && isExternalLabel) {
ServiceHelper.setExternalLabel((DNode) newDNode);
}
}
}.transformInto(eClass);
}

private static AbstractNodeMapping getGatewayMapping(EObject mappingOwner, EObject target) {

private static AbstractNodeMapping getGatewayMapping(AbstractNodeMapping previous, EObject target) {
if (previous.getName().endsWith("Gateway")) {
String classname = "bpmn2." + target.eClass().getName(); // Notation used in ODesign
return getMapping(previous.eContainer(), classname);
} else {
String classname = "bpmn2.BaseElement"; // Notation used in ODesign
return getMapping(previous.eContainer(), classname);
}
}

private static AbstractNodeMapping getMapping(EObject mappingOwner, String className) {
List<NodeMapping> siblingMappings = Collections.emptyList();
if (mappingOwner instanceof ContainerMapping) {
siblingMappings = ((ContainerMapping) mappingOwner).getSubNodeMappings();
} else if (mappingOwner instanceof Layer) {
siblingMappings = ((Layer) mappingOwner).getNodeMappings();
}
String classname = "bpmn2." + target.eClass().getName(); // Notation used in ODesign
for (NodeMapping mapping : siblingMappings) {
if (Objects.equals(mapping.getDomainClass(), classname)) {
if (Objects.equals(mapping.getDomainClass(), className)) {
return mapping;
}
}
return null;
}



/**
* Applies a function with a type choosen by user.
*
* @param it context
* @param types to choose from
* @param it context
* @param types to choose from
* @param transform to apply
*/
public static <T> T applyToChoosableClass(EObject it, List<EClass> types, Function<EClass, T> transform) {
Expand All @@ -118,20 +129,19 @@ public static <T> T applyToChoosableClass(EObject it, List<EClass> types, Functi
}
return transform.apply(target.get());
}

/**
* Converts a gateway in a new type.
* <p>
* If no gateway is selected, whole operation is aborted.
* </p>
*
* @param it gateway to convert
* @param it gateway to convert
* @param view on which the task is triggered
* @return new gateway
*/
public static Gateway convertToChoosableGateway(Gateway it, AbstractDNode view) {
return FlowNodeService.applyToChoosableClass(it, GATEWAY_CLASSES,
type -> convertToSpecificGateway(view, type));
return FlowNodeService.applyToChoosableClass(it, GATEWAY_CLASSES, type -> convertToSpecificGateway(view, type));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@
import org.obeonetwork.dsl.bpmn2.SubProcess;
import org.obeonetwork.dsl.bpmn2.Task;


/**
* Services for BPMN Viewpoints.
*
Expand Down Expand Up @@ -82,7 +81,8 @@ public static ECrossReferenceAdapter getCrossReferenceAdapter(EObject eo) {
/**
* Logs a message with called message.
* <p>
* This method should only be used will editing VSM. It must be used any released version.
* This method should only be used will editing VSM. It must be used any
* released version.
* </p>
*
* @param eObject
Expand Down Expand Up @@ -113,12 +113,10 @@ public static Definitions getDefinitionsObject(EObject it) {
public static Process getProcess(EObject it) {
return getAncestor(Process.class, it);
}

@SuppressWarnings("unchecked")
private static <T extends EObject> T getAncestor(Class<T> type, EObject it) {
return it == null || type.isInstance(it)
? (T) it
: getAncestor(type, it.eContainer());
return it == null || type.isInstance(it) ? (T) it : getAncestor(type, it.eContainer());
}

public static List<BaseElement> getElementsWithExternalLabel(DNodeContainer dNodeContainer) {
Expand All @@ -128,14 +126,12 @@ public static List<BaseElement> getElementsWithExternalLabel(DNodeContainer dNod
while (it.hasNext()) {
DDiagramElement dde = it.next();
Object bpmnElement = dde.getTarget();
if ((bpmnElement instanceof Event)
|| (bpmnElement instanceof Gateway)
if ((bpmnElement instanceof Event) || (bpmnElement instanceof Gateway)
|| (bpmnElement instanceof ItemAwareElement)) {
if (!(bpmnElement instanceof BoundaryEvent) && isExternalLabel((DNode) dde)) {
result.add((BaseElement) bpmnElement);
}
} else if ((bpmnElement instanceof Task)
|| (bpmnElement instanceof SubProcess)
} else if ((bpmnElement instanceof Task) || (bpmnElement instanceof SubProcess)
|| (bpmnElement instanceof CallActivity)) {
DNodeContainer dNodeTask = (DNodeContainer) dde;
for (DDiagramElement subDDE : dNodeTask.getElements()) {
Expand All @@ -152,18 +148,35 @@ public static List<BaseElement> getElementsWithExternalLabel(DNodeContainer dNod
}

public static boolean isExternalLabel(DNode dNode) {
if (dNode != null && ServiceHelper.IS_EXTERNAL_LABEL.equals(dNode.getTooltipText())) {
//Crapy code used when the type of a Task or a Gateway is changed.
if (dNode.getStyle() != null || dNode.getOwnedStyle().getCustomFeatures() != null) {
setExternalLabel(dNode);
} else {
return true;
}
}
if (dNode == null || dNode.getOwnedStyle() == null || dNode.getOwnedStyle().getCustomFeatures() == null) {
return false;
}
return dNode.getOwnedStyle().getCustomFeatures().contains(ServiceHelper.IS_EXTERNAL_LABEL);
}

public static void setExternalLabelInTooltip(DNode dNode) {
//Crapy code used when the type of a Task or a Gateway is changed.
dNode.setTooltipText(IS_EXTERNAL_LABEL);
}

public static void setExternalLabel(DNode dNode) {
dNode.getStyle().getCustomFeatures().add(IS_EXTERNAL_LABEL);
//Crapy code used when the type of a Task or a Gateway is changed.
setExternalLabelInTooltip(dNode);
}

public static void setInternalLabel(DNode dNode) {
dNode.getStyle().getCustomFeatures().remove(IS_EXTERNAL_LABEL);
//Crapy code used when the type of a Task or a Gateway is changed.
dNode.setTooltipText("");
}

public static boolean isDefaultPath(DEdge dEdge) {
Expand All @@ -176,7 +189,7 @@ public static boolean isDefaultPath(DEdge dEdge) {
}
return result;
}

private static SequenceFlow getGatewayDefault(Gateway it) {
SequenceFlow result = null;
if (it instanceof InclusiveGateway) {
Expand All @@ -192,7 +205,7 @@ private static SequenceFlow getGatewayDefault(Gateway it) {
/**
* Moves a flow node from a container to another container.
*
* @param element to mode
* @param element to mode
* @param oldSemanticContainer old container
* @param newSemanticContainer new container
*/
Expand All @@ -214,7 +227,7 @@ private List<? super FlowNode> getFlowNodeContainment(EObject container) {
// no empty list to indicate containment is not possible
return null;
}

public List<FlowNode> getFlowNodeElements(EObject container, String className) {
Class<?> clazz = null;
try {
Expand All @@ -223,30 +236,22 @@ public List<FlowNode> getFlowNodeElements(EObject container, String className) {
Activator.log(IStatus.ERROR, e.getMessage(), e);
return Collections.emptyList();
}

List<?> elements = getFlowNodeContainment(container);
return elements == null
? Collections.emptyList()
: elements.stream()
.filter(clazz::isInstance)
.map(FlowNode.class::cast)
.collect(Collectors.toList());
return elements == null ? Collections.emptyList()
: elements.stream().filter(clazz::isInstance).map(FlowNode.class::cast).collect(Collectors.toList());
}

public List<DataInput> getDataInputs(EObject container) {
InputOutputSpecification ioSpec = getIoSpecification(container);
return ioSpec != null
? ioSpec.getDataInputs()
: Collections.emptyList();
return ioSpec != null ? ioSpec.getDataInputs() : Collections.emptyList();
}

public List<DataOutput> getDataOutputs(EObject container) {
InputOutputSpecification ioSpec = getIoSpecification(container);
return ioSpec != null
? ioSpec.getDataOutputs()
: Collections.emptyList();
return ioSpec != null ? ioSpec.getDataOutputs() : Collections.emptyList();
}

private InputOutputSpecification getIoSpecification(EObject container) {
if (container instanceof Lane && ((Lane) container).getPartitionElement() instanceof InputOutputSpecification) {
return (InputOutputSpecification) ((Lane) container).getPartitionElement();
Expand All @@ -255,7 +260,7 @@ private InputOutputSpecification getIoSpecification(EObject container) {
}
return null;
}

/**
* Aborts a Sirius operation.
*
Expand All @@ -264,7 +269,7 @@ private InputOutputSpecification getIoSpecification(EObject container) {
*/
public static void abortOperation(EObject context) throws OperationCanceledException {
TransactionalEditingDomain edt = Session.of(context).get().getTransactionalEditingDomain();
// Cancel Operation does not cancel !!
// Cancel Operation does not cancel !!
// ChangeContext catches them all !!
// What a trainer ...
((InternalTransactionalEditingDomain) edt).getActiveTransaction().abort(Status.CANCEL_STATUS);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.sirius.diagram.DDiagramElementContainer;
import org.eclipse.sirius.diagram.DNodeContainer;
import org.obeonetwork.bpmn2.design.refactoring.SiriusElementRefactor;
import org.obeonetwork.dsl.bpmn2.Bpmn2Package;
import org.obeonetwork.dsl.bpmn2.BusinessRuleTask;
import org.obeonetwork.dsl.bpmn2.CallActivity;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/**
* Copyright (c) 2024 Obeo.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Obeo - initial API and implementation
*
*/
package org.obeonetwork.bpmn2.design.refactoring;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.eclipse.sirius.business.api.session.Session;
import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter;
import org.eclipse.sirius.common.tools.api.util.RefreshIdsHolder;
import org.eclipse.sirius.diagram.DSemanticDiagram;
import org.eclipse.sirius.diagram.EdgeTarget;
import org.eclipse.sirius.diagram.business.api.componentization.DiagramMappingsManager;
import org.eclipse.sirius.diagram.business.api.componentization.DiagramMappingsManagerRegistry;
import org.eclipse.sirius.diagram.business.internal.helper.decoration.DecorationHelperInternal;
import org.eclipse.sirius.diagram.business.internal.sync.DDiagramElementSynchronizer;
import org.eclipse.sirius.diagram.description.DiagramElementMapping;
import org.eclipse.sirius.diagram.description.EdgeMapping;
import org.eclipse.sirius.diagram.description.MappingBasedDecoration;
import org.eclipse.sirius.ecore.extender.business.api.accessor.ModelAccessor;
import org.eclipse.sirius.tools.api.SiriusPlugin;
import org.eclipse.sirius.tools.api.interpreter.InterpreterUtil;
import org.eclipse.sirius.viewpoint.description.SemanticBasedDecoration;

/**
*
* @author nperansin
*/
@SuppressWarnings("restriction")
class DiagramModifier {

final Session session;
final DSemanticDiagram parent;
final ModelAccessor accessor;
final IInterpreter interpreter;
final DDiagramElementSynchronizer dsync;
final DiagramMappingsManager mmapping;
final RefreshIdsHolder idFactory;

Map<DiagramElementMapping, Collection<EdgeTarget>> mappingsToEdgeTargets = null;
final Map<EdgeMapping, Collection<MappingBasedDecoration>> edgeToMappings = new HashMap<>();
final Map<String, Collection<SemanticBasedDecoration>> edgeToSemantics = new HashMap<>();

protected DiagramModifier(DSemanticDiagram diagram, Session session) {
this.session = session;
parent = diagram;
accessor = SiriusPlugin.getDefault().getModelAccessorRegistry().getModelAccessor(diagram);
mmapping = DiagramMappingsManagerRegistry.INSTANCE.getDiagramMappingsManager(session, diagram);
interpreter = InterpreterUtil.getInterpreter(diagram);
dsync = new DDiagramElementSynchronizer(diagram, interpreter, accessor);
idFactory = RefreshIdsHolder.getOrCreateHolder(diagram);
}

protected void prepareEdges() {
if (mappingsToEdgeTargets != null) {
return;
}
mappingsToEdgeTargets = dsync.computeMappingsToEdgeTargets(session.getSelectedViewpoints(false));
// Initialize cache
new DecorationHelperInternal(parent, interpreter, accessor).computeDecorations(mappingsToEdgeTargets,
edgeToSemantics, edgeToMappings);
// TODO update with new nodes ?
}

}
Loading

0 comments on commit 5c1d3de

Please sign in to comment.