Search in sources :

Example 6 with DiagramElement

use of org.osate.ge.internal.diagram.runtime.DiagramElement in project osate2 by osate.

the class DiagramElementLayoutUtil method getNodesToLayoutIncrementally.

private static Set<DiagramNode> getNodesToLayoutIncrementally(final DiagramNode node, final IncrementalLayoutMode mode, final Set<DiagramNode> results) {
    final boolean alwaysLayoutContainer = mode != IncrementalLayoutMode.LAYOUT_CONTENTS;
    for (final DiagramElement child : node.getChildren()) {
        if (DiagramElementPredicates.isShape(child)) {
            final boolean positionIsSet = child.hasPosition() || !DiagramElementPredicates.isMoveableShape(child);
            final boolean sizeIsSet = child.hasSize() || !DiagramElementPredicates.isResizeable(child);
            // This occurs when a user has created an element using the palette
            if (positionIsSet && !sizeIsSet) {
                results.add(child);
            } else {
                if (sizeIsSet && positionIsSet) {
                    getNodesToLayoutIncrementally(child, mode, results);
                } else {
                    // If always layout container is specified, layout container
                    // If container does not have any layed out shapes, layout container.
                    final boolean layoutContainer = alwaysLayoutContainer || !hasLayedOutShapes(node.getChildren());
                    if (layoutContainer) {
                        results.add(node);
                        break;
                    } else {
                        results.add(child);
                    }
                }
            }
        } else if (DiagramElementPredicates.isConnection(child)) {
            final AgeConnection c = (AgeConnection) child.getGraphic();
            if (c.isFlowIndicator) {
                // Layout the flow indicator's not docked container if its position has not been set
                if (child.getStartElement() != null && (!child.isBendpointsSet() || !child.hasPosition())) {
                    // If we should lay out container than lay out the container of the flow indicator
                    if (alwaysLayoutContainer) {
                        DiagramElement undockedContainer = DiagramElementUtil.getUndockedDiagramElement(child.getStartElement().getParent());
                        if (undockedContainer != null) {
                            results.add(undockedContainer);
                        }
                    } else {
                        // Otherwise, layout the flow indicator
                        results.add(child);
                    }
                }
            } else if (alwaysLayoutContainer) {
                // Only layout the connection if its bendpoints have not been set regardless of whether it has any bendpoints.
                if (child.getStartElement() != null && child.getEndElement() != null && !child.isBendpointsSet()) {
                    final Optional<BusinessObjectContext> ancestor = BusinessObjectContext.getFirstCommonAncestor(child.getStartElement().getParent(), child.getEndElement().getParent());
                    if (ancestor.isPresent()) {
                        results.add((DiagramNode) ancestor.get());
                    }
                }
            } else if (isFeatureSelfLoopConnection(child) && !child.isBendpointsSet()) {
                results.add(child);
            }
        }
    }
    return results;
}
Also used : DiagramElement(org.osate.ge.internal.diagram.runtime.DiagramElement) AgeConnection(org.osate.ge.graphics.internal.AgeConnection) BusinessObjectContext(org.osate.ge.BusinessObjectContext)

Example 7 with DiagramElement

use of org.osate.ge.internal.diagram.runtime.DiagramElement in project osate2 by osate.

the class DiagramElementLayoutUtil method getNonGroupDockArea.

/**
 * Walks up the tree from the given node and returns the first dock area that isn't the group dock area.
 * Checks the specified diagram node and then ancestors.
 * @param diagramNode is the diagram for which to return the non group docker area.
 * @return the first dock area that isn't the group dock area.
 */
public static DockArea getNonGroupDockArea(DiagramNode diagramNode) {
    DockArea result = null;
    do {
        if (!(diagramNode instanceof DiagramElement)) {
            result = null;
            break;
        }
        result = ((DiagramElement) diagramNode).getDockArea();
        diagramNode = diagramNode.getParent();
    } while (result != null && result == DockArea.GROUP);
    return result;
}
Also used : DiagramElement(org.osate.ge.internal.diagram.runtime.DiagramElement) DockArea(org.osate.ge.internal.diagram.runtime.DockArea)

Example 8 with DiagramElement

use of org.osate.ge.internal.diagram.runtime.DiagramElement in project osate2 by osate.

the class DiagramElementLayoutUtil method getAbsolutePosition.

/**
 * Gets the absolute position of a node. This absolute position only considers the positions of shapes.
 * Connections are ignored.
 * @param dn the node for which to get the absolute position.
 * @return the absolute position.
 */
public static Point getAbsolutePosition(final DiagramNode dn) {
    int x = 0;
    int y = 0;
    for (DiagramNode tmp = dn; tmp instanceof DiagramElement; tmp = tmp.getParent()) {
        final DiagramElement tmpDe = (DiagramElement) tmp;
        if (tmpDe.getGraphic() instanceof AgeShape) {
            // Ignore connections in case the X and Y values are not 0.
            x += tmpDe.getX();
            y += tmpDe.getY();
        }
    }
    return new Point(x, y);
}
Also used : DiagramElement(org.osate.ge.internal.diagram.runtime.DiagramElement) DiagramNode(org.osate.ge.internal.diagram.runtime.DiagramNode) AgeShape(org.osate.ge.graphics.internal.AgeShape) Point(org.osate.ge.graphics.Point) SizeConstraint(org.eclipse.elk.core.options.SizeConstraint) Point(org.osate.ge.graphics.Point)

Example 9 with DiagramElement

use of org.osate.ge.internal.diagram.runtime.DiagramElement 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 10 with DiagramElement

use of org.osate.ge.internal.diagram.runtime.DiagramElement in project osate2 by osate.

the class DiagramElementLayoutUtil method layoutIncrementally.

/**
 * Performs layout on elements in the specified diagram which have not been laid out.
 * @param diagram the diagram for which to perform the incremental layout
 * @param mod the modification to use to modify the diagram
 * @param layoutInfoProvider the layout info provider which provides additional information required for laying out the diagram
 */
public static void layoutIncrementally(final AgeDiagram diagram, final DiagramModification mod, final LayoutInfoProvider layoutInfoProvider) {
    Objects.requireNonNull(diagram, "diagram must not be null");
    Objects.requireNonNull(mod, "mod must not be null");
    Objects.requireNonNull(layoutInfoProvider, "layoutInfoProvider must not be null");
    final IncrementalLayoutMode currentLayoutMode = LayoutPreferences.getCurrentIncrementalLayoutMode();
    // Get all the nodes that need to be layed out.
    final Set<DiagramNode> unfilteredNodesToLayout = getNodesToLayoutIncrementally(diagram, currentLayoutMode, new HashSet<>());
    if (unfilteredNodesToLayout.size() == 0) {
        return;
    }
    // Lay our flow indicators. In the container is eventually layed out, this will be replaced but in cases where that is not the case,
    // we provide a default layout. Flow indicators are connections and as such will be filtered in the next step.
    layoutFlowIndicators(mod, unfilteredNodesToLayout.stream().filter(DiagramNodePredicates::isFlowIndicator).map(DiagramElement.class::cast), layoutInfoProvider);
    final Collection<DiagramNode> nodesToLayout = DiagramElementLayoutUtil.filterUnnecessaryNodes(unfilteredNodesToLayout, currentLayoutMode == IncrementalLayoutMode.LAYOUT_DIAGRAM);
    if (nodesToLayout.size() == 0) {
        // If the filtered node list is empty then the unfiltered list still contain feature self loop connections that need to be layed out.
        unfilteredNodesToLayout.stream().filter(DiagramElementLayoutUtil::isFeatureSelfLoopConnection).map(DiagramElement.class::cast).forEachOrdered(de -> layoutFeatureSelfLoopConnection(de, mod, layoutInfoProvider));
        return;
    }
    final LayoutOptions layoutOptions = LayoutOptions.createFromPreferences();
    if (currentLayoutMode == IncrementalLayoutMode.LAYOUT_DIAGRAM) {
        layout(INCREMENTAL_LAYOUT_LABEL, diagram, layoutInfoProvider, layoutOptions);
    } else {
        layout(mod, nodesToLayout, new StyleCalculator(diagram.getConfiguration(), StyleProvider.EMPTY), layoutInfoProvider, layoutOptions);
        // Set Positions of elements which do not have a position set.
        for (final DiagramNode dn : nodesToLayout) {
            if (dn instanceof DiagramElement) {
                final DiagramElement de = (DiagramElement) dn;
                if (!de.hasPosition()) {
                    if (de.getDockArea() == null) {
                        mod.setPosition(de, new Point(0.0, 0.0));
                    } else if (de.getDockArea() != DockArea.GROUP && de.getParent() instanceof DiagramElement) {
                        final DiagramElement parent = (DiagramElement) de.getParent();
                        final DockingPosition defaultDockingPosition = de.getGraphicalConfiguration().getDefaultDockingPosition();
                        final DockArea defaultDockArea = DockArea.fromDockingPosition(defaultDockingPosition);
                        if (parent.hasSize()) {
                            final Stream<DiagramElement> otherElementsAlongSide = parent.getChildren().stream().filter(c -> c.hasPosition() && c.hasSize() && c.getDockArea() == defaultDockArea);
                            // Determine the position of the new element along it's preferred docking position.
                            double locationAlongSide;
                            if (defaultDockingPosition == DockingPosition.TOP || defaultDockingPosition == DockingPosition.BOTTOM) {
                                locationAlongSide = otherElementsAlongSide.max(Comparator.comparingDouble(c -> c.getY())).map(c -> c.getX() + c.getWidth()).orElse(0.0);
                            } else {
                                locationAlongSide = otherElementsAlongSide.max(Comparator.comparingDouble(c -> c.getY())).map(c -> c.getY() + c.getHeight()).orElse(0.0);
                            }
                            // Set position based on the docking position
                            switch(defaultDockingPosition) {
                                case TOP:
                                    mod.setPosition(de, new Point(locationAlongSide, 0));
                                    break;
                                case BOTTOM:
                                    mod.setPosition(de, new Point(locationAlongSide, parent.getHeight()));
                                    break;
                                case LEFT:
                                    mod.setPosition(de, new Point(0, locationAlongSide));
                                    break;
                                case RIGHT:
                                    mod.setPosition(de, new Point(parent.getWidth(), locationAlongSide));
                                    break;
                                default:
                                    break;
                            }
                        }
                        mod.setDockArea(de, defaultDockArea);
                    }
                }
            }
        }
    }
}
Also used : CoreOptions(org.eclipse.elk.core.options.CoreOptions) ArrayListMultimap(com.google.common.collect.ArrayListMultimap) PortSide(org.eclipse.elk.core.options.PortSide) LayoutMapping(org.eclipse.elk.core.service.LayoutMapping) ElkNode(org.eclipse.elk.graph.ElkNode) ElkPort(org.eclipse.elk.graph.ElkPort) IGraphElementVisitor(org.eclipse.elk.core.util.IGraphElementVisitor) RecursiveGraphLayoutEngine(org.eclipse.elk.core.RecursiveGraphLayoutEngine) DockArea(org.osate.ge.internal.diagram.runtime.DockArea) IStatus(org.eclipse.core.runtime.IStatus) BusinessObjectContext(org.osate.ge.BusinessObjectContext) Graphic(org.osate.ge.graphics.Graphic) DiagramNodePredicates(org.osate.ge.internal.diagram.runtime.DiagramNodePredicates) StatusManager(org.eclipse.ui.statushandlers.StatusManager) IEditorPart(org.eclipse.ui.IEditorPart) EnumSet(java.util.EnumSet) Collection(java.util.Collection) Set(java.util.Set) Status(org.eclipse.core.runtime.Status) SizeConstraint(org.eclipse.elk.core.options.SizeConstraint) Point(org.osate.ge.graphics.Point) Collectors(java.util.stream.Collectors) DiagramElementUtil(org.osate.ge.internal.util.DiagramElementUtil) DockingPosition(org.osate.ge.DockingPosition) Objects(java.util.Objects) List(java.util.List) Stream(java.util.stream.Stream) ElkGraphElement(org.eclipse.elk.graph.ElkGraphElement) NodeLabelPlacement(org.eclipse.elk.core.options.NodeLabelPlacement) GraphicalEditorException(org.osate.ge.internal.GraphicalEditorException) ElkEdgeSection(org.eclipse.elk.graph.ElkEdgeSection) Entry(java.util.Map.Entry) Optional(java.util.Optional) ElkEdge(org.eclipse.elk.graph.ElkEdge) AgeConnection(org.osate.ge.graphics.internal.AgeConnection) DiagramNode(org.osate.ge.internal.diagram.runtime.DiagramNode) DiagramElement(org.osate.ge.internal.diagram.runtime.DiagramElement) Dimension(org.osate.ge.graphics.Dimension) ElkGraphPackage(org.eclipse.elk.graph.ElkGraphPackage) ModeGraphic(org.osate.ge.graphics.internal.ModeGraphic) DiagramModification(org.osate.ge.internal.diagram.runtime.DiagramModification) HashSet(java.util.HashSet) ElkUtil(org.eclipse.elk.core.util.ElkUtil) Style(org.osate.ge.graphics.Style) InternalDiagramEditor(org.osate.ge.internal.ui.editor.InternalDiagramEditor) Lists(com.google.common.collect.Lists) ImmutableList(com.google.common.collect.ImmutableList) AgeShape(org.osate.ge.graphics.internal.AgeShape) LinkedList(java.util.LinkedList) Activator(org.osate.ge.internal.Activator) DiagramElementPredicates(org.osate.ge.internal.diagram.runtime.DiagramElementPredicates) ElkLabel(org.eclipse.elk.graph.ElkLabel) KVector(org.eclipse.elk.core.math.KVector) Label(org.osate.ge.graphics.internal.Label) BasicProgressMonitor(org.eclipse.elk.core.util.BasicProgressMonitor) ElkShape(org.eclipse.elk.graph.ElkShape) Adapters(org.eclipse.core.runtime.Adapters) AgeDiagram(org.osate.ge.internal.diagram.runtime.AgeDiagram) AgeDiagramUtil(org.osate.ge.internal.diagram.runtime.AgeDiagramUtil) Comparator(java.util.Comparator) StyleProvider(org.osate.ge.internal.diagram.runtime.styling.StyleProvider) Collections(java.util.Collections) StyleCalculator(org.osate.ge.internal.diagram.runtime.styling.StyleCalculator) StyleCalculator(org.osate.ge.internal.diagram.runtime.styling.StyleCalculator) DiagramNode(org.osate.ge.internal.diagram.runtime.DiagramNode) Point(org.osate.ge.graphics.Point) DiagramNodePredicates(org.osate.ge.internal.diagram.runtime.DiagramNodePredicates) DiagramElement(org.osate.ge.internal.diagram.runtime.DiagramElement) DockArea(org.osate.ge.internal.diagram.runtime.DockArea) DockingPosition(org.osate.ge.DockingPosition) Stream(java.util.stream.Stream)

Aggregations

DiagramElement (org.osate.ge.internal.diagram.runtime.DiagramElement)131 AgeDiagram (org.osate.ge.internal.diagram.runtime.AgeDiagram)45 List (java.util.List)31 Point (org.osate.ge.graphics.Point)29 DiagramNode (org.osate.ge.internal.diagram.runtime.DiagramNode)29 InternalDiagramEditor (org.osate.ge.internal.ui.editor.InternalDiagramEditor)26 Objects (java.util.Objects)25 IEditorPart (org.eclipse.ui.IEditorPart)23 ArrayList (java.util.ArrayList)22 Collectors (java.util.stream.Collectors)22 BusinessObjectContext (org.osate.ge.BusinessObjectContext)21 Collection (java.util.Collection)19 Collections (java.util.Collections)18 Dimension (org.osate.ge.graphics.Dimension)18 DockArea (org.osate.ge.internal.diagram.runtime.DockArea)18 Optional (java.util.Optional)16 AgeConnection (org.osate.ge.graphics.internal.AgeConnection)16 DiagramElementUtil (org.osate.ge.internal.util.DiagramElementUtil)16 ElkPort (org.eclipse.elk.graph.ElkPort)14 Node (javafx.scene.Node)13