Skip to content

Commit

Permalink
[333] Store edge routing in parent
Browse files Browse the repository at this point in the history
During the conversion from DDiagram to ELK Graph, the routing styles of
original Sirius DEdge is now stored on the common parent of edges in ELK
Graph.
This property can be overridden by defining the routing style directly
in the VSM.

The tests have also been adapted. Indeed, before this commit the routing
applied was always Rectilinear. Now, it is not the case. The existing
tests have been "duplicated", to have the previous behavior (by forcing
the "Rectilinear routing" in the VSM) and the new behavior for all
existing tests by considering the initial used routing style.

Bug: #333
  • Loading branch information
lredor committed Jun 26, 2024
1 parent e1ffc9d commit 77e6cc0
Show file tree
Hide file tree
Showing 8 changed files with 457 additions and 185 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
import org.eclipse.elk.core.math.KVector;
import org.eclipse.elk.core.options.CoreOptions;
import org.eclipse.elk.core.options.EdgeLabelPlacement;
import org.eclipse.elk.core.options.EdgeRouting;
import org.eclipse.elk.core.options.NodeLabelPlacement;
import org.eclipse.elk.core.options.PortConstraints;
import org.eclipse.elk.core.options.PortLabelPlacement;
Expand Down Expand Up @@ -99,11 +100,13 @@
import org.eclipse.gmf.runtime.draw2d.ui.geometry.LineSeg;
import org.eclipse.gmf.runtime.gef.ui.figures.NodeFigure;
import org.eclipse.gmf.runtime.notation.Node;
import org.eclipse.gmf.runtime.notation.Routing;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.sirius.common.tools.api.util.StringUtil;
import org.eclipse.sirius.diagram.DDiagramElement;
import org.eclipse.sirius.diagram.DDiagramElementContainer;
import org.eclipse.sirius.diagram.DEdge;
import org.eclipse.sirius.diagram.DNode;
import org.eclipse.sirius.diagram.DNodeContainer;
import org.eclipse.sirius.diagram.DNodeList;
Expand All @@ -127,6 +130,7 @@
import org.eclipse.sirius.diagram.model.business.internal.query.DDiagramElementContainerExperimentalQuery;
import org.eclipse.sirius.diagram.model.business.internal.query.DNodeContainerExperimentalQuery;
import org.eclipse.sirius.diagram.ui.business.api.query.EditPartQuery;
import org.eclipse.sirius.diagram.ui.business.internal.query.DEdgeQuery;
import org.eclipse.sirius.diagram.ui.edit.api.part.AbstractDiagramElementContainerEditPart;
import org.eclipse.sirius.diagram.ui.edit.api.part.IAbstractDiagramNodeEditPart;
import org.eclipse.sirius.diagram.ui.edit.api.part.IDDiagramEditPart;
Expand Down Expand Up @@ -1515,6 +1519,8 @@ protected void processConnections(final LayoutMapping mapping, Map<LayoutOptionT
Map<EReference, ElkEdge> reference2EdgeMap = new HashMap<>();

List<ConnectionEditPart> connections = mapping.getProperty(CONNECTIONS).stream().sorted(CONNECTION_COMPARATOR).collect(toList());
Map<ElkNode, Integer> edgeContainerToNbObliqueEdges = new HashMap<>();
Map<ElkNode, Integer> edgeContainerToNbRectilinearEdges = new HashMap<>();
for (ConnectionEditPart connection : connections) {
boolean isOppositeEdge = false;
Optional<EdgeLabelPlacement> edgeLabelPlacement = Optional.empty();
Expand Down Expand Up @@ -1567,9 +1573,71 @@ protected void processConnections(final LayoutMapping mapping, Map<LayoutOptionT
edge.getTargets().add(targetShape);
}

// Store the routing of edge in a map to determine later the best routing style to kept. Indeed, in ELK, the
// routing style is stored in the parent (so all edges with the same parent will have the same routing style
// after the layout).
if (connection instanceof IDiagramElementEditPart) {
IDiagramElementEditPart ideep = (IDiagramElementEditPart) connection;
DDiagramElement dde = ideep.resolveDiagramElement();
if (dde instanceof DEdge) {
DEdgeQuery dEdgeQuery = new DEdgeQuery((DEdge) dde);
Routing routing = dEdgeQuery.getRouting();
if (routing.getValue() == Routing.RECTILINEAR || routing.getValue() == Routing.TREE) {
// Tree routing is count as rectilinear because Tree routing does not exist on ELK Side (see
// EdgeRouting).
addOneEdges(edgeContainer, edgeContainerToNbRectilinearEdges);
} else if (routing.getValue() == Routing.MANUAL) {
addOneEdges(edgeContainer, edgeContainerToNbObliqueEdges);
}
}
}

// process edge labels
processEdgeLabels(mapping, connection, edge, edgeLabelPlacement, offset, elkTargetToOptionsOverrideMap);
}

// Store the routing style of edges for each parent property according to the number of edges (in case of
// equality, the priority is given to Oblique edges).
for (ElkNode edgeContainer : edgeContainerToNbObliqueEdges.keySet()) {
int nbObliques = edgeContainerToNbObliqueEdges.get(edgeContainer).intValue();
Integer nbRectilinears = edgeContainerToNbRectilinearEdges.get(edgeContainer);
if (nbRectilinears == null || nbRectilinears.intValue() <= nbObliques) {
setEgdeRoutingPropertyIfNotDefined(edgeContainer, EdgeRouting.POLYLINE);
} else {
setEgdeRoutingPropertyIfNotDefined(edgeContainer, EdgeRouting.ORTHOGONAL);
}
if (nbRectilinears != null) {
edgeContainerToNbRectilinearEdges.remove(edgeContainer);
}
}
for (ElkNode edgeContainer : edgeContainerToNbRectilinearEdges.keySet()) {
setEgdeRoutingPropertyIfNotDefined(edgeContainer, EdgeRouting.ORTHOGONAL);
}
}

/**
* Set the routing style of the <code>edgeContainer</code>, if it is not already set (for example in the VSM
* configuration).
*
* @param edgesContainer
* the edges container to change the property
* @param routingStyleToSet
* the new value to set
*/
private void setEgdeRoutingPropertyIfNotDefined(ElkNode edgeContainer, EdgeRouting routingStyleToSet) {
EdgeRouting currentEdgeRouting = edgeContainer.getProperty(CoreOptions.EDGE_ROUTING);
if (currentEdgeRouting == null || EdgeRouting.UNDEFINED.equals(currentEdgeRouting)) {
edgeContainer.setProperty(CoreOptions.EDGE_ROUTING, routingStyleToSet);
}
}

private void addOneEdges(ElkNode edgeContainer, Map<ElkNode, Integer> edgeContainerToNbEdges) {
Integer currentNbOfEdges = edgeContainerToNbEdges.get(edgeContainer);
if (currentNbOfEdges == null) {
edgeContainerToNbEdges.put(edgeContainer, 1);
} else {
edgeContainerToNbEdges.put(edgeContainer, currentNbOfEdges + 1);
}
}

private PrecisionPoint getStartingPoint(ElkEdge edge) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2009, 2015 Kiel University and others.
* Copyright (c) 2009, 2024 Kiel University and others.
* 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
Expand Down Expand Up @@ -81,6 +81,8 @@ public static final class EdgeLayoutData {

public String targetTerminal;

public Routing routingToApply;

public EdgeLayoutData() {
}
}
Expand All @@ -94,9 +96,6 @@ public EdgeLayoutData() {
/** list of edge layouts to be applied to edges. */
private List<EdgeLayoutData> edgeLayouts = new LinkedList<EdgeLayoutData>();

/** indicates which style shall be enforced. */
private Routing routingToForce = Routing.RECTILINEAR_LITERAL;

/**
* Creates a command to apply layout.
*
Expand Down Expand Up @@ -145,28 +144,21 @@ public void addShapeLayout(final View view, final Point location, final Dimensio
* new source terminal, encoded as string, or {@code null} if the source terminal shall not be changed
* @param targetTerminal
* new target terminal, encoded as string, or {@code null} if the target terminal shall not be changed
* @param routingToApply
* the routing to apply on the DEdge
*/
public void addEdgeLayout(final Edge edge, final PointList bends, final String sourceTerminal, final String targetTerminal, final String junctionPoints) {
public void addEdgeLayout(final Edge edge, final PointList bends, final String sourceTerminal, final String targetTerminal, final String junctionPoints, final Routing routingToApply) {
assert edge != null;
EdgeLayoutData layout = new EdgeLayoutData();
layout.edge = edge;
layout.bends = bends;
layout.junctionPoints = junctionPoints;
layout.sourceTerminal = sourceTerminal;
layout.targetTerminal = targetTerminal;
layout.routingToApply = routingToApply;
edgeLayouts.add(layout);
}

/**
* Enforces all edges to be drawn with the current routing style.
*
* @param routingStyle
* which routing stlye shall be used
*/
public void setRoutingToForce(final Routing routingStyle) {
this.routingToForce = routingStyle;
}

/**
* {@inheritDoc}
*/
Expand Down Expand Up @@ -238,10 +230,10 @@ protected CommandResult doExecuteWithResult(final IProgressMonitor monitor, fina
style.setStringValue(edgeLayout.junctionPoints);
}

// set routing style to oblique
// Set routing style retrieved in ELK parent of edges
RoutingStyle routingStyle = (RoutingStyle) edgeLayout.edge.getStyle(NotationPackage.eINSTANCE.getRoutingStyle());
if (routingStyle != null) {
routingStyle.setRouting(routingToForce);
if (routingStyle != null && edgeLayout.routingToApply != null) {
routingStyle.setRouting(edgeLayout.routingToApply);
routingStyle.setSmoothness(Smoothness.NONE_LITERAL);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2009, 2021 Kiel University and others.
* Copyright (c) 2009, 2024 Kiel University and others.
* 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
Expand Down Expand Up @@ -132,27 +132,6 @@ public Command getCommand(final Request request) {
}
}

// TODO In ELK example, oblique routing is handled globally for all command. We can imagine to have
// several kind of routing. Currently in ELK, the routing style is on the parent and not on each
// edges... For the time being, we set the routing style according to the property value of the root
// element.
if (layoutRequest.getElements().size() > 0) {
ElkGraphElement graphElement = layoutRequest.getElements().get(0).getFirst();
ElkNode rootElement = ElkGraphUtil.containingGraph(graphElement);
if (rootElement == null && graphElement instanceof ElkNode) {
// The first item of the list elements to layout is the root.
rootElement = (ElkNode) graphElement;
}
if (rootElement != null) {
EdgeRouting edgeRouting = rootElement.getProperty(CoreOptions.EDGE_ROUTING);
if (edgeRouting.equals(EdgeRouting.ORTHOGONAL)) {
command.setRoutingToForce(Routing.RECTILINEAR_LITERAL);
} else {
command.setRoutingToForce(Routing.MANUAL_LITERAL);
}
}
}

pointListMap.clear();
return new ICommandProxy(command);
} else {
Expand Down Expand Up @@ -423,7 +402,12 @@ private void addEdgeLayout(final GmfLayoutCommand command, final ElkEdge elkEdge
serializedJP = junctionPoints.toString();
}

command.addEdgeLayout((Edge) connectionEditPart.getModel(), currentEdgeBendpoints, sourceTerminal, targetTerminal, serializedJP);
EdgeRouting edgeRouting = elkEdge.getContainingNode().getProperty(CoreOptions.EDGE_ROUTING);
Routing routingToSet = Routing.MANUAL_LITERAL;
if (edgeRouting.equals(EdgeRouting.ORTHOGONAL)) {
routingToSet = Routing.RECTILINEAR_LITERAL;
}
command.addEdgeLayout((Edge) connectionEditPart.getModel(), currentEdgeBendpoints, sourceTerminal, targetTerminal, serializedJP, routingToSet);
}
}

Expand Down
Loading

0 comments on commit 77e6cc0

Please sign in to comment.