Search in sources :

Example 1 with ElkGraphElement

use of org.eclipse.elk.graph.ElkGraphElement in project sirius-components by eclipse-sirius.

the class LayoutService method layout.

@Override
public Diagram layout(IEditingContext editingContext, Diagram diagram) {
    ELKConvertedDiagram convertedDiagram = this.elkDiagramConverter.convert(diagram);
    ElkNode elkDiagram = convertedDiagram.getElkDiagram();
    // @formatter:off
    var optionalDiagramDescription = this.representationDescriptionSearchService.findById(editingContext, diagram.getDescriptionId()).filter(DiagramDescription.class::isInstance).map(DiagramDescription.class::cast);
    // @formatter:on
    ISiriusWebLayoutConfigurator layoutConfigurator;
    if (optionalDiagramDescription.isPresent()) {
        var diagramDescription = optionalDiagramDescription.get();
        elkDiagram = this.layoutConfiguratorRegistry.applyBeforeLayout(elkDiagram, editingContext, diagram, diagramDescription);
        layoutConfigurator = this.layoutConfiguratorRegistry.getLayoutConfigurator(diagram, diagramDescription);
    } else {
        layoutConfigurator = this.layoutConfiguratorRegistry.getDefaultLayoutConfigurator();
    }
    ElkUtil.applyVisitors(elkDiagram, layoutConfigurator);
    IGraphLayoutEngine engine = new RecursiveGraphLayoutEngine();
    engine.layout(elkDiagram, new BasicProgressMonitor());
    if (optionalDiagramDescription.isPresent()) {
        var diagramDescription = optionalDiagramDescription.get();
        elkDiagram = this.layoutConfiguratorRegistry.applyAfterLayout(elkDiagram, editingContext, diagram, diagramDescription);
    }
    Map<String, ElkGraphElement> id2ElkGraphElements = convertedDiagram.getId2ElkGraphElements();
    Diagram layoutedDiagram = this.elkLayoutedDiagramProvider.getLayoutedDiagram(diagram, elkDiagram, id2ElkGraphElements);
    if (this.logger.isDebugEnabled()) {
        // @formatter:off
        String json = ElkGraphJson.forGraph(elkDiagram).omitLayout(true).omitZeroDimension(true).omitZeroPositions(true).shortLayoutOptionKeys(false).prettyPrint(true).toJson();
        // @formatter:on
        this.logger.debug(json);
    }
    return layoutedDiagram;
}
Also used : IGraphLayoutEngine(org.eclipse.elk.core.IGraphLayoutEngine) ElkNode(org.eclipse.elk.graph.ElkNode) RecursiveGraphLayoutEngine(org.eclipse.elk.core.RecursiveGraphLayoutEngine) BasicProgressMonitor(org.eclipse.elk.core.util.BasicProgressMonitor) DiagramDescription(org.eclipse.sirius.components.diagrams.description.DiagramDescription) ElkGraphElement(org.eclipse.elk.graph.ElkGraphElement) IncrementalLayoutConvertedDiagram(org.eclipse.sirius.components.diagrams.layout.incremental.IncrementalLayoutConvertedDiagram) Diagram(org.eclipse.sirius.components.diagrams.Diagram)

Example 2 with ElkGraphElement

use of org.eclipse.elk.graph.ElkGraphElement in project sirius-components by eclipse-sirius.

the class ELKDiagramConverter method convert.

@Override
public ELKConvertedDiagram convert(Diagram diagram) {
    Diagram initializedDiagram = this.initializeDiagram(diagram);
    ElkNode elkDiagram = this.convertDiagram(initializedDiagram);
    Map<String, ElkGraphElement> id2ElkGraphElements = new HashMap<>();
    Map<String, ElkConnectableShape> connectableShapeIndex = new LinkedHashMap<>();
    initializedDiagram.getNodes().stream().forEach(node -> this.convertNode(node, elkDiagram, connectableShapeIndex, id2ElkGraphElements));
    initializedDiagram.getEdges().stream().forEach(edge -> this.convertEdge(edge, elkDiagram, connectableShapeIndex, id2ElkGraphElements));
    return new ELKConvertedDiagram(elkDiagram, id2ElkGraphElements);
}
Also used : ElkNode(org.eclipse.elk.graph.ElkNode) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) ElkConnectableShape(org.eclipse.elk.graph.ElkConnectableShape) ElkGraphElement(org.eclipse.elk.graph.ElkGraphElement) Diagram(org.eclipse.sirius.components.diagrams.Diagram) LinkedHashMap(java.util.LinkedHashMap)

Example 3 with ElkGraphElement

use of org.eclipse.elk.graph.ElkGraphElement in project osate2 by osate.

the class DiagramElementLayoutUtil method layout.

private static void layout(final DiagramModification m, final Collection<? extends DiagramNode> nodesToLayout, final StyleProvider styleProvider, final LayoutInfoProvider layoutInfoProvider, final LayoutOptions options) {
    Objects.requireNonNull(nodesToLayout, "nodesToLayout must not be null");
    try {
        // Layout the nodes
        final RecursiveGraphLayoutEngine layoutEngine = new RecursiveGraphLayoutEngine();
        for (final DiagramNode dn : nodesToLayout) {
            LayoutMapping mapping;
            ElkNode layoutGraph;
            // Perform the first layout. This layout will not include nested ports. This will allow ELK additional flexibility when determining port
            // placement.
            mapping = ElkGraphBuilder.buildLayoutGraph(dn, styleProvider, layoutInfoProvider, options, !options.layoutPortsOnDefaultSides, ElkGraphBuilder.FixedPortPositionProvider.NO_OP);
            layoutGraph = mapping.getLayoutGraph();
            layoutGraph.setProperty(CoreOptions.ALGORITHM, LAYOUT_ALGORITHM);
            applyProperties(dn, mapping);
            LayoutDebugUtil.saveElkGraphToDebugProject(layoutGraph, "pass1");
            layoutEngine.layout(layoutGraph, new BasicProgressMonitor());
            // nested ports and performing edge routing.
            if (layoutGraph.getProperty(AgeLayoutOptions.NESTED_PORTS_WERE_OMITTED)) {
                final LayoutMapping initialLayoutMapping = mapping;
                mapping = ElkGraphBuilder.buildLayoutGraph(dn, styleProvider, layoutInfoProvider, options, false, new ElkGraphBuilder.FixedPortPositionProvider() {

                    @Override
                    public PortSide getPortSide(final DiagramElement de) {
                        final ElkGraphElement ge = initialLayoutMapping.getGraphMap().inverse().get(de);
                        if (ge instanceof ElkPort) {
                            return ge.getProperty(CoreOptions.PORT_SIDE);
                        }
                        return null;
                    }

                    @Override
                    public Double getPortPosition(final DiagramElement de) {
                        final ElkGraphElement ge = initialLayoutMapping.getGraphMap().inverse().get(de);
                        if (ge instanceof ElkPort) {
                            final ElkPort port = (ElkPort) ge;
                            final PortSide ps = port.getProperty(CoreOptions.PORT_SIDE);
                            if (PortSide.SIDES_EAST_WEST.contains(ps)) {
                                return port.getY();
                            } else {
                                return port.getX();
                            }
                        }
                        return null;
                    }
                });
                layoutGraph = mapping.getLayoutGraph();
                layoutGraph.setProperty(CoreOptions.ALGORITHM, LAYOUT_ALGORITHM);
                applyProperties(dn, mapping);
                LayoutDebugUtil.saveElkGraphToDebugProject(layoutGraph, "pass2");
                layoutEngine.layout(layoutGraph, new BasicProgressMonitor());
            }
            LayoutDebugUtil.saveElkGraphToDebugProject(layoutGraph, "final");
            applyShapeLayout(mapping, m);
            applyConnectionLayout(mapping, m);
            // Layout feature self loop connections. These are omitted from the ELK based layout.
            dn.getAllDiagramNodes().filter(DiagramElementLayoutUtil::isFeatureSelfLoopConnection).map(DiagramElement.class::cast).forEachOrdered(de -> layoutFeatureSelfLoopConnection(de, m, layoutInfoProvider));
        }
    } catch (final RuntimeException ex) {
        // If a layout error occurs, display the exception but do not rethrow. This is so that the operation that attempted to do the layout will continue.
        // This is important because otherwise simple operations such a adding elements to the diagram will completely fail. Suppressing the error will
        // degrade performance but allow the user to keep working and should ensure things stay in a valid state.
        // It would be best for other parts of the code to handle exceptions properly to avoid entering into an invalid state but this is the best
        // workaround.
        final Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, "A layout error occured.", ex);
        StatusManager.getManager().handle(status, StatusManager.SHOW | StatusManager.LOG);
    }
}
Also used : IStatus(org.eclipse.core.runtime.IStatus) Status(org.eclipse.core.runtime.Status) DiagramNode(org.osate.ge.internal.diagram.runtime.DiagramNode) ElkNode(org.eclipse.elk.graph.ElkNode) ElkPort(org.eclipse.elk.graph.ElkPort) RecursiveGraphLayoutEngine(org.eclipse.elk.core.RecursiveGraphLayoutEngine) DiagramElement(org.osate.ge.internal.diagram.runtime.DiagramElement) BasicProgressMonitor(org.eclipse.elk.core.util.BasicProgressMonitor) PortSide(org.eclipse.elk.core.options.PortSide) LayoutMapping(org.eclipse.elk.core.service.LayoutMapping) ElkGraphElement(org.eclipse.elk.graph.ElkGraphElement)

Example 4 with ElkGraphElement

use of org.eclipse.elk.graph.ElkGraphElement in project osate2 by osate.

the class ElkGraphBuilder method createElkLabels.

private void createElkLabels(final DiagramElement parentElement, final ElkGraphElement parentLayoutElement, final LayoutMapping mapping) {
    // Don't create labels for ElkPort. The bounds of the port contain their labels.
    if (parentLayoutElement instanceof ElkPort) {
        return;
    }
    final boolean isConnection = parentElement.getGraphic() instanceof AgeConnection;
    final Style style = styleProvider.getStyle(parentElement);
    if (style.getPrimaryLabelVisible()) {
        // Create Primary Label
        if (parentElement.getLabelName() != null) {
            final ElkLabel elkLabel = createElkLabel(parentLayoutElement, parentElement.getLabelName(), layoutInfoProvider.getPrimaryLabelSize(parentElement));
            if (isConnection) {
                if (!layoutConnectionLabels) {
                    elkLabel.setProperty(CoreOptions.NO_LAYOUT, true);
                }
                mapping.getGraphMap().put(elkLabel, new PrimaryConnectionLabelReference(parentElement));
            }
        }
    }
    // Create label for annotations which are part of the graphic configuration. These are only supported by non-connections.
    if (!isConnection && parentElement.getGraphicalConfiguration().getAnnotation() != null) {
        createElkLabel(parentLayoutElement, parentElement.getGraphicalConfiguration().getAnnotation(), layoutInfoProvider.getAnnotationLabelSize(parentElement));
    }
    // Create Secondary Labels
    parentElement.getChildren().stream().filter(c -> c.getGraphic() instanceof Label).forEachOrdered(labelElement -> {
        final ElkLabel elkLabel = createElkLabel(parentLayoutElement, labelElement.getLabelName(), layoutInfoProvider.getPrimaryLabelSize(labelElement));
        if (isConnection) {
            if (!layoutConnectionLabels) {
                elkLabel.setProperty(CoreOptions.NO_LAYOUT, true);
            }
            mapping.getGraphMap().put(elkLabel, new SecondaryConnectionLabelReference(labelElement));
        }
    });
    if (parentLayoutElement instanceof ElkNode) {
        parentLayoutElement.setProperty(CoreOptions.NODE_LABELS_PLACEMENT, getNodeLabelPlacement(style));
    }
}
Also used : CoreOptions(org.eclipse.elk.core.options.CoreOptions) DiagramElement(org.osate.ge.internal.diagram.runtime.DiagramElement) PortSide(org.eclipse.elk.core.options.PortSide) Dimension(org.osate.ge.graphics.Dimension) HashMap(java.util.HashMap) LayoutMapping(org.eclipse.elk.core.service.LayoutMapping) ElkNode(org.eclipse.elk.graph.ElkNode) ElkPort(org.eclipse.elk.graph.ElkPort) ArrayList(java.util.ArrayList) Style(org.osate.ge.graphics.Style) DockArea(org.osate.ge.internal.diagram.runtime.DockArea) ElkPadding(org.eclipse.elk.core.math.ElkPadding) Map(java.util.Map) AgeShape(org.osate.ge.graphics.internal.AgeShape) DiagramElementPredicates(org.osate.ge.internal.diagram.runtime.DiagramElementPredicates) HierarchyHandling(org.eclipse.elk.core.options.HierarchyHandling) EnumSet(java.util.EnumSet) PortConstraints(org.eclipse.elk.core.options.PortConstraints) ElkLabel(org.eclipse.elk.graph.ElkLabel) Predicate(java.util.function.Predicate) KVector(org.eclipse.elk.core.math.KVector) Collection(java.util.Collection) Label(org.osate.ge.graphics.internal.Label) SizeOptions(org.eclipse.elk.core.options.SizeOptions) EcoreUtil(org.eclipse.emf.ecore.util.EcoreUtil) SizeConstraint(org.eclipse.elk.core.options.SizeConstraint) Collectors(java.util.stream.Collectors) ElkConnectableShape(org.eclipse.elk.graph.ElkConnectableShape) DiagramElementUtil(org.osate.ge.internal.util.DiagramElementUtil) DockingPosition(org.osate.ge.DockingPosition) Objects(java.util.Objects) AgeDiagram(org.osate.ge.internal.diagram.runtime.AgeDiagram) List(java.util.List) ElkGraphElement(org.eclipse.elk.graph.ElkGraphElement) NodeLabelPlacement(org.eclipse.elk.core.options.NodeLabelPlacement) Direction(org.eclipse.elk.core.options.Direction) Entry(java.util.Map.Entry) Optional(java.util.Optional) ElkEdge(org.eclipse.elk.graph.ElkEdge) AgeConnection(org.osate.ge.graphics.internal.AgeConnection) ElkGraphUtil(org.eclipse.elk.graph.util.ElkGraphUtil) StyleProvider(org.osate.ge.internal.diagram.runtime.styling.StyleProvider) Collections(java.util.Collections) DiagramNode(org.osate.ge.internal.diagram.runtime.DiagramNode) AgeConnection(org.osate.ge.graphics.internal.AgeConnection) ElkNode(org.eclipse.elk.graph.ElkNode) ElkLabel(org.eclipse.elk.graph.ElkLabel) ElkPort(org.eclipse.elk.graph.ElkPort) ElkLabel(org.eclipse.elk.graph.ElkLabel) Label(org.osate.ge.graphics.internal.Label) Style(org.osate.ge.graphics.Style)

Example 5 with ElkGraphElement

use of org.eclipse.elk.graph.ElkGraphElement in project elk by eclipse.

the class GmfDiagramLayoutConnector method processConnections.

/**
 * Creates new edges and takes care of the labels for each connection identified in the
 * {@code buildLayoutGraphRecursively} method.
 *
 * @param mapping
 *            the layout mapping
 */
protected void processConnections(final LayoutMapping mapping) {
    Map<EReference, ElkEdge> reference2EdgeMap = new HashMap<>();
    for (ConnectionEditPart connection : mapping.getProperty(CONNECTIONS)) {
        boolean isOppositeEdge = false;
        Optional<EdgeLabelPlacement> edgeLabelPlacement = Optional.empty();
        ElkEdge edge;
        // Check whether the edge belongs to an Ecore reference, which may have opposites.
        // This is required for the layout of Ecore diagrams, since the bend points of
        // opposite references are kept synchronized by the editor.
        EObject modelObject = connection.getNotationView().getElement();
        if (modelObject instanceof EReference) {
            EReference reference = (EReference) modelObject;
            edge = reference2EdgeMap.get(reference.getEOpposite());
            if (edge != null) {
                edgeLabelPlacement = Optional.of(EdgeLabelPlacement.TAIL);
                isOppositeEdge = true;
            } else {
                edge = ElkGraphUtil.createEdge(null);
                reference2EdgeMap.put(reference, edge);
            }
        } else {
            edge = ElkGraphUtil.createEdge(null);
        }
        BiMap<Object, ElkGraphElement> inverseGraphMap = mapping.getGraphMap().inverse();
        // find a proper source node and source port
        ElkGraphElement sourceElem;
        EditPart sourceObj = connection.getSource();
        if (sourceObj instanceof ConnectionEditPart) {
            sourceElem = inverseGraphMap.get(((ConnectionEditPart) sourceObj).getSource());
            if (sourceElem == null) {
                sourceElem = inverseGraphMap.get(((ConnectionEditPart) sourceObj).getTarget());
            }
        } else {
            sourceElem = inverseGraphMap.get(sourceObj);
        }
        ElkConnectableShape sourceShape = null;
        ElkPort sourcePort = null;
        ElkNode sourceNode = null;
        if (sourceElem instanceof ElkNode) {
            sourceNode = (ElkNode) sourceElem;
            sourceShape = sourceNode;
        } else if (sourceElem instanceof ElkPort) {
            sourcePort = (ElkPort) sourceElem;
            sourceNode = sourcePort.getParent();
            sourceShape = sourcePort;
        } else {
            continue;
        }
        // find a proper target node and target port
        ElkGraphElement targetElem;
        EditPart targetObj = connection.getTarget();
        if (targetObj instanceof ConnectionEditPart) {
            targetElem = inverseGraphMap.get(((ConnectionEditPart) targetObj).getTarget());
            if (targetElem == null) {
                targetElem = inverseGraphMap.get(((ConnectionEditPart) targetObj).getSource());
            }
        } else {
            targetElem = inverseGraphMap.get(targetObj);
        }
        ElkConnectableShape targetShape = null;
        ElkNode targetNode = null;
        ElkPort targetPort = null;
        if (targetElem instanceof ElkNode) {
            targetNode = (ElkNode) targetElem;
            targetShape = targetNode;
        } else if (targetElem instanceof ElkPort) {
            targetPort = (ElkPort) targetElem;
            targetNode = targetPort.getParent();
            targetShape = targetPort;
        } else {
            continue;
        }
        // calculate offset for edge and label coordinates
        ElkNode edgeContainment = ElkGraphUtil.findLowestCommonAncestor(sourceNode, targetNode);
        KVector offset = new KVector();
        ElkUtil.toAbsolute(offset, edgeContainment);
        if (!isOppositeEdge) {
            // set source and target
            edge.getSources().add(sourceShape);
            edge.getTargets().add(targetShape);
            // now that source and target are set, put the edge into the graph
            edgeContainment.getContainedEdges().add(edge);
            mapping.getGraphMap().put(edge, connection);
            // store the current coordinates of the edge
            setEdgeLayout(edge, connection, offset);
        }
        // process edge labels
        processEdgeLabels(mapping, connection, edge, edgeLabelPlacement, offset);
    }
}
Also used : ConnectionEditPart(org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionEditPart) ElkNode(org.eclipse.elk.graph.ElkNode) HashMap(java.util.HashMap) ElkPort(org.eclipse.elk.graph.ElkPort) ResizableCompartmentEditPart(org.eclipse.gmf.runtime.diagram.ui.editparts.ResizableCompartmentEditPart) ShapeNodeEditPart(org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeNodeEditPart) RootEditPart(org.eclipse.gef.RootEditPart) CompartmentEditPart(org.eclipse.gmf.runtime.diagram.ui.editparts.CompartmentEditPart) RenderedDiagramRootEditPart(org.eclipse.gmf.runtime.diagram.ui.render.editparts.RenderedDiagramRootEditPart) EditPart(org.eclipse.gef.EditPart) IGraphicalEditPart(org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart) AbstractBorderItemEditPart(org.eclipse.gmf.runtime.diagram.ui.editparts.AbstractBorderItemEditPart) LabelEditPart(org.eclipse.gmf.runtime.diagram.ui.editparts.LabelEditPart) ConnectionEditPart(org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionEditPart) DiagramEditPart(org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart) ElkConnectableShape(org.eclipse.elk.graph.ElkConnectableShape) EObject(org.eclipse.emf.ecore.EObject) EObject(org.eclipse.emf.ecore.EObject) EdgeLabelPlacement(org.eclipse.elk.core.options.EdgeLabelPlacement) KVector(org.eclipse.elk.core.math.KVector) ElkGraphElement(org.eclipse.elk.graph.ElkGraphElement) EReference(org.eclipse.emf.ecore.EReference) ElkEdge(org.eclipse.elk.graph.ElkEdge)

Aggregations

ElkGraphElement (org.eclipse.elk.graph.ElkGraphElement)23 ElkNode (org.eclipse.elk.graph.ElkNode)16 ElkEdge (org.eclipse.elk.graph.ElkEdge)10 ElkLabel (org.eclipse.elk.graph.ElkLabel)9 ElkPort (org.eclipse.elk.graph.ElkPort)9 KVector (org.eclipse.elk.core.math.KVector)7 PortSide (org.eclipse.elk.core.options.PortSide)5 DiagramElement (org.osate.ge.internal.diagram.runtime.DiagramElement)5 RecursiveGraphLayoutEngine (org.eclipse.elk.core.RecursiveGraphLayoutEngine)4 ElkConnectableShape (org.eclipse.elk.graph.ElkConnectableShape)4 ElkEdgeSection (org.eclipse.elk.graph.ElkEdgeSection)4 Collection (java.util.Collection)3 Collections (java.util.Collections)3 EnumSet (java.util.EnumSet)3 HashMap (java.util.HashMap)3 LinkedList (java.util.LinkedList)3 List (java.util.List)3 Entry (java.util.Map.Entry)3 Objects (java.util.Objects)3 Optional (java.util.Optional)3