Search in sources :

Example 1 with ModeInstance

use of org.lflang.generator.ModeInstance in project lingua-franca by lf-lang.

the class ModeDiagrams method handleModes.

public void handleModes(List<KNode> nodes, ReactorInstance reactor) {
    if (!reactor.modes.isEmpty()) {
        var modeNodes = new LinkedHashMap<ModeInstance, KNode>();
        var modeDefinitionMap = new LinkedHashMap<Mode, ModeInstance>();
        for (ModeInstance mode : reactor.modes) {
            var node = _kNodeExtensions.createNode();
            associateWith(node, mode.getDefinition());
            NamedInstanceUtil.linkInstance(node, mode);
            _utilityExtensions.setID(node, mode.uniqueID());
            modeNodes.put(mode, node);
            modeDefinitionMap.put(mode.getDefinition(), mode);
            if (mode.isInitial()) {
                DiagramSyntheses.setLayoutOption(node, LayeredOptions.LAYERING_LAYER_CONSTRAINT, LayerConstraint.FIRST);
            }
            DiagramSyntheses.setLayoutOption(node, LayeredOptions.CROSSING_MINIMIZATION_SEMI_INTERACTIVE, true);
            var expansionState = MemorizingExpandCollapseAction.getExpansionState(mode);
            DiagramSyntheses.setLayoutOption(node, KlighdProperties.EXPAND, expansionState != null ? expansionState : !this.getBooleanValue(INITIALLY_COLLAPSE_MODES));
            // Expanded Rectangle
            var expandFigure = addModeFigure(node, mode, true);
            expandFigure.setProperty(KlighdProperties.EXPANDED_RENDERING, true);
            _kRenderingExtensions.addDoubleClickAction(expandFigure, MemorizingExpandCollapseAction.ID);
            if (getBooleanValue(LinguaFrancaSynthesis.SHOW_HYPERLINKS)) {
                // Collapse button
                KText textButton = _linguaFrancaShapeExtensions.addTextButton(expandFigure, LinguaFrancaSynthesis.TEXT_HIDE_ACTION);
                _kRenderingExtensions.to(_kRenderingExtensions.from(_kRenderingExtensions.setGridPlacementData(textButton), _kRenderingExtensions.LEFT, 8, 0, _kRenderingExtensions.TOP, 0, 0), _kRenderingExtensions.RIGHT, 8, 0, _kRenderingExtensions.BOTTOM, 0, 0);
                _kRenderingExtensions.addSingleClickAction(textButton, MemorizingExpandCollapseAction.ID);
                _kRenderingExtensions.addDoubleClickAction(textButton, MemorizingExpandCollapseAction.ID);
            }
            _kContainerRenderingExtensions.addChildArea(expandFigure);
            // Collapse Rectangle
            var collapseFigure = addModeFigure(node, mode, false);
            collapseFigure.setProperty(KlighdProperties.COLLAPSED_RENDERING, true);
            if (this.hasContent(mode)) {
                _kRenderingExtensions.addDoubleClickAction(collapseFigure, MemorizingExpandCollapseAction.ID);
                if (getBooleanValue(LinguaFrancaSynthesis.SHOW_HYPERLINKS)) {
                    // Expand button
                    KText textButton = _linguaFrancaShapeExtensions.addTextButton(collapseFigure, LinguaFrancaSynthesis.TEXT_SHOW_ACTION);
                    _kRenderingExtensions.to(_kRenderingExtensions.from(_kRenderingExtensions.setGridPlacementData(textButton), _kRenderingExtensions.LEFT, 8, 0, _kRenderingExtensions.TOP, 0, 0), _kRenderingExtensions.RIGHT, 8, 0, _kRenderingExtensions.BOTTOM, 8, 0);
                    _kRenderingExtensions.addSingleClickAction(textButton, MemorizingExpandCollapseAction.ID);
                    _kRenderingExtensions.addDoubleClickAction(textButton, MemorizingExpandCollapseAction.ID);
                }
            }
        }
        var modeChildren = LinkedHashMultimap.<ModeInstance, KNode>create();
        var nodeModes = new HashMap<KNode, ModeInstance>();
        for (var node : nodes) {
            var instance = NamedInstanceUtil.getLinkedInstance(node);
            if (instance == null && node.getProperty(CoreOptions.COMMENT_BOX)) {
                var firstEdge = IterableExtensions.<KEdge>head(node.getOutgoingEdges());
                if (firstEdge != null && firstEdge.getTarget() != null) {
                    instance = NamedInstanceUtil.getLinkedInstance(firstEdge.getTarget());
                }
            }
            if (instance != null) {
                var mode = instance.getMode(true);
                modeChildren.put(mode, node);
                nodeModes.put(node, mode);
            } else {
                modeChildren.put(null, node);
            }
        }
        var modeContainer = _kNodeExtensions.createNode();
        modeContainer.getChildren().addAll(modeNodes.values());
        var modeContainerFigure = addModeContainerFigure(modeContainer);
        _kRenderingExtensions.addDoubleClickAction(modeContainerFigure, MemorizingExpandCollapseAction.ID);
        DiagramSyntheses.setLayoutOption(modeContainer, CoreOptions.NODE_SIZE_CONSTRAINTS, SizeConstraint.minimumSizeWithPorts());
        DiagramSyntheses.setLayoutOption(modeContainer, CoreOptions.EDGE_ROUTING, EdgeRouting.SPLINES);
        DiagramSyntheses.setLayoutOption(modeContainer, CoreOptions.DIRECTION, Direction.DOWN);
        DiagramSyntheses.setLayoutOption(modeContainer, CoreOptions.PORT_CONSTRAINTS, PortConstraints.FIXED_ORDER);
        var modeContainerPorts = new HashMap<KPort, KPort>();
        for (var mode : reactor.modes) {
            var modeNode = modeNodes.get(mode);
            var edges = new LinkedHashSet<KEdge>();
            // add children
            for (var child : modeChildren.get(mode)) {
                nodes.remove(child);
                modeNode.getChildren().add(child);
                edges.addAll(child.getIncomingEdges());
                edges.addAll(child.getOutgoingEdges());
            }
            // add transitions
            var representedTargets = new HashSet<Pair<ModeInstance, ModeInstance.ModeTransitionType>>();
            for (var transition : ListExtensions.reverseView(mode.transitions)) {
                if (!representedTargets.contains(new Pair<ModeInstance, ModeInstance.ModeTransitionType>(transition.target, transition.type))) {
                    var edge = _kEdgeExtensions.createEdge();
                    edge.setSource(modeNode);
                    edge.setTarget(modeNodes.get(transition.target));
                    addTransitionFigure(edge, transition);
                    if (getBooleanValue(SHOW_TRANSITION_LABELS)) {
                        associateWith(edge, transition.getDefinition());
                    } else {
                        // Bundle similar transitions
                        representedTargets.add(new Pair<ModeInstance, ModeInstance.ModeTransitionType>(transition.target, transition.type));
                    }
                }
            }
            // handle cross hierarchy edges
            var portCopies = new HashMap<KPort, KPort>();
            var triggerCopies = new HashMap<KNode, KNode>();
            for (var edge : edges) {
                if (!edge.getProperty(CoreOptions.NO_LAYOUT)) {
                    var sourceNodeMode = nodeModes.get(edge.getSource());
                    if (sourceNodeMode == null) {
                        sourceNodeMode = nodeModes.get(edge.getSource().getParent());
                    }
                    var sourceIsInMode = sourceNodeMode != null;
                    var targetNodeMode = nodeModes.get(edge.getTarget());
                    if (targetNodeMode == null) {
                        targetNodeMode = nodeModes.get(edge.getTarget().getParent());
                    }
                    var targetIsInMode = targetNodeMode != null;
                    if (!sourceIsInMode || !targetIsInMode) {
                        var node = sourceIsInMode ? edge.getTarget() : edge.getSource();
                        if (node.getProperty(LinguaFrancaSynthesis.REACTION_SPECIAL_TRIGGER)) {
                            // Duplicate trigger node
                            if (!triggerCopies.containsKey(node)) {
                                var copy = EcoreUtil.copy(node);
                                modeNode.getChildren().add(modeNode.getChildren().indexOf(edge.getTarget()), copy);
                                triggerCopies.put(node, copy);
                                // Adjust copy
                                copy.getOutgoingEdges().forEach(e -> {
                                    e.setTarget(null);
                                    e.setTargetPort(null);
                                });
                                copy.getOutgoingEdges().clear();
                                copy.getData().stream().filter(d -> d instanceof KIdentifier).forEach(d -> {
                                    var kid = (KIdentifier) d;
                                    kid.setId(kid.getId() + "_" + mode.getName());
                                });
                            }
                            var newNode = triggerCopies.get(node);
                            edge.setSource(newNode);
                            // Remove trigger on top level if only used in modes
                            if (node.getOutgoingEdges().isEmpty()) {
                                nodes.remove(node);
                            }
                        } else {
                            var port = sourceIsInMode ? edge.getTargetPort() : edge.getSourcePort();
                            var isLocal = modeChildren.get(null).contains(node);
                            if (isLocal) {
                                // Add port to mode container
                                if (modeContainerPorts.containsKey(port)) {
                                    node = modeContainer;
                                    port = modeContainerPorts.get(port);
                                } else {
                                    var containerPort = _kPortExtensions.createPort();
                                    modeContainerPorts.put(port, containerPort);
                                    modeContainer.getPorts().add(containerPort);
                                    _kPortExtensions.setPortSize(containerPort, 8, 4);
                                    KRectangle rect = _kRenderingExtensions.addRectangle(containerPort);
                                    _kRenderingExtensions.setBackground(rect, Colors.BLACK);
                                    DiagramSyntheses.setLayoutOption(containerPort, CoreOptions.PORT_BORDER_OFFSET, -4.0);
                                    DiagramSyntheses.setLayoutOption(containerPort, CoreOptions.PORT_SIDE, sourceIsInMode ? PortSide.EAST : PortSide.WEST);
                                    var source = _utilityExtensions.sourceElement(node);
                                    var label = "";
                                    if (source instanceof Action) {
                                        label = ((Action) source).getName();
                                    } else if (source instanceof Timer) {
                                        label = ((Timer) source).getName();
                                    }
                                    _kLabelExtensions.addOutsidePortLabel(containerPort, label, 8);
                                    // new connection
                                    var copy = EcoreUtil.copy(edge);
                                    if (sourceIsInMode) {
                                        copy.setSource(modeContainer);
                                        copy.setSourcePort(containerPort);
                                        copy.setTarget(edge.getTarget());
                                    } else {
                                        copy.setTarget(modeContainer);
                                        copy.setTargetPort(containerPort);
                                        copy.setSource(edge.getSource());
                                    }
                                    node = modeContainer;
                                    port = containerPort;
                                }
                            }
                            // Duplicate port
                            if (!portCopies.containsKey(port)) {
                                var copy = EcoreUtil.copy(port);
                                portCopies.put(port, copy);
                                var dummyNode = _kNodeExtensions.createNode();
                                var newID = mode.uniqueID() + "_";
                                if (!port.getLabels().isEmpty()) {
                                    newID += IterableExtensions.head(port.getLabels()).getText();
                                }
                                _utilityExtensions.setID(dummyNode, newID);
                                _kRenderingExtensions.addInvisibleContainerRendering(dummyNode);
                                dummyNode.getPorts().add(copy);
                                DiagramSyntheses.setLayoutOption(dummyNode, LayeredOptions.LAYERING_LAYER_CONSTRAINT, port.getProperty(CoreOptions.PORT_SIDE) == PortSide.WEST ? LayerConstraint.FIRST : LayerConstraint.LAST);
                                modeNode.getChildren().add(dummyNode);
                            }
                            var newPort = portCopies.get(port);
                            if (sourceIsInMode) {
                                edge.setTarget(newPort.getNode());
                                edge.setTargetPort(newPort);
                            } else {
                                edge.setSource(newPort.getNode());
                                edge.setSourcePort(newPort);
                            }
                        }
                    }
                }
            }
        }
        // If mode container is unused (no ports for local connections) -> hide it
        if (modeContainer.getPorts().isEmpty()) {
            _kRenderingExtensions.setInvisible(modeContainerFigure, true);
            DiagramSyntheses.setLayoutOption(modeContainer, CoreOptions.PADDING, new ElkPadding());
        }
        nodes.add(modeContainer);
    }
}
Also used : LinkedHashSet(java.util.LinkedHashSet) Color(java.awt.Color) CoreOptions(org.eclipse.elk.core.options.CoreOptions) MemorizingExpandCollapseAction(org.lflang.diagram.synthesis.action.MemorizingExpandCollapseAction) LinguaFrancaStyleExtensions(org.lflang.diagram.synthesis.styles.LinguaFrancaStyleExtensions) PortSide(org.eclipse.elk.core.options.PortSide) KLabelExtensions(de.cau.cs.kieler.klighd.krendering.extensions.KLabelExtensions) Inject(com.google.inject.Inject) Action(org.lflang.lf.Action) Extension(org.eclipse.xtext.xbase.lib.Extension) AbstractSynthesisExtensions(org.lflang.diagram.synthesis.AbstractSynthesisExtensions) LayeredOptions(org.eclipse.elk.alg.layered.options.LayeredOptions) KIdentifier(de.cau.cs.kieler.klighd.kgraph.KIdentifier) KEdgeExtensions(de.cau.cs.kieler.klighd.krendering.extensions.KEdgeExtensions) KContainerRenderingExtensions(de.cau.cs.kieler.klighd.krendering.extensions.KContainerRenderingExtensions) KRenderingExtensions(de.cau.cs.kieler.klighd.krendering.extensions.KRenderingExtensions) KDecoratorPlacementData(de.cau.cs.kieler.klighd.krendering.KDecoratorPlacementData) KPolyline(de.cau.cs.kieler.klighd.krendering.KPolyline) LineStyle(de.cau.cs.kieler.klighd.krendering.LineStyle) LinguaFrancaSynthesis(org.lflang.diagram.synthesis.LinguaFrancaSynthesis) DiagramSyntheses(de.cau.cs.kieler.klighd.syntheses.DiagramSyntheses) LinkedHashMultimap(com.google.common.collect.LinkedHashMultimap) KEdge(de.cau.cs.kieler.klighd.kgraph.KEdge) KPolylineExtensions(de.cau.cs.kieler.klighd.krendering.extensions.KPolylineExtensions) KPortExtensions(de.cau.cs.kieler.klighd.krendering.extensions.KPortExtensions) SynthesisOption(de.cau.cs.kieler.klighd.SynthesisOption) KEllipse(de.cau.cs.kieler.klighd.krendering.KEllipse) SizeConstraint(org.eclipse.elk.core.options.SizeConstraint) LinguaFrancaShapeExtensions(org.lflang.diagram.synthesis.styles.LinguaFrancaShapeExtensions) Collectors(java.util.stream.Collectors) Mode(org.lflang.lf.Mode) List(java.util.List) KlighdProperties(de.cau.cs.kieler.klighd.util.KlighdProperties) Direction(org.eclipse.elk.core.options.Direction) EdgeRouting(org.eclipse.elk.core.options.EdgeRouting) KLabel(de.cau.cs.kieler.klighd.kgraph.KLabel) Pair(org.eclipse.xtext.xbase.lib.Pair) KNodeExtensions(de.cau.cs.kieler.klighd.krendering.extensions.KNodeExtensions) HashMap(java.util.HashMap) ListExtensions(org.eclipse.xtext.xbase.lib.ListExtensions) HashSet(java.util.HashSet) LinkedHashMap(java.util.LinkedHashMap) ITextRenderingProvider(de.cau.cs.kieler.klighd.labels.decoration.ITextRenderingProvider) ElkPadding(org.eclipse.elk.core.math.ElkPadding) ModeTransitionType(org.lflang.generator.ModeInstance.ModeTransitionType) KRendering(de.cau.cs.kieler.klighd.krendering.KRendering) KText(de.cau.cs.kieler.klighd.krendering.KText) LinkedHashSet(java.util.LinkedHashSet) LinesDecorator(de.cau.cs.kieler.klighd.labels.decoration.LinesDecorator) KNode(de.cau.cs.kieler.klighd.kgraph.KNode) KPort(de.cau.cs.kieler.klighd.kgraph.KPort) Transition(org.lflang.generator.ModeInstance.Transition) PortConstraints(org.eclipse.elk.core.options.PortConstraints) ModeInstance(org.lflang.generator.ModeInstance) KRenderingFactory(de.cau.cs.kieler.klighd.krendering.KRenderingFactory) LabelDecorationConfigurator(de.cau.cs.kieler.klighd.labels.decoration.LabelDecorationConfigurator) EcoreUtil(org.eclipse.emf.ecore.util.EcoreUtil) KContainerRendering(de.cau.cs.kieler.klighd.krendering.KContainerRendering) LayerConstraint(org.eclipse.elk.alg.layered.options.LayerConstraint) ReactorInstance(org.lflang.generator.ReactorInstance) IterableExtensions(org.eclipse.xtext.xbase.lib.IterableExtensions) ViewSynthesisShared(de.cau.cs.kieler.klighd.krendering.ViewSynthesisShared) KRectangle(de.cau.cs.kieler.klighd.krendering.KRectangle) Colors(de.cau.cs.kieler.klighd.krendering.Colors) RectangleDecorator(de.cau.cs.kieler.klighd.labels.decoration.RectangleDecorator) Timer(org.lflang.lf.Timer) ModeInstance(org.lflang.generator.ModeInstance) MemorizingExpandCollapseAction(org.lflang.diagram.synthesis.action.MemorizingExpandCollapseAction) Action(org.lflang.lf.Action) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) KEdge(de.cau.cs.kieler.klighd.kgraph.KEdge) KNode(de.cau.cs.kieler.klighd.kgraph.KNode) KIdentifier(de.cau.cs.kieler.klighd.kgraph.KIdentifier) LinkedHashMap(java.util.LinkedHashMap) KRectangle(de.cau.cs.kieler.klighd.krendering.KRectangle) KText(de.cau.cs.kieler.klighd.krendering.KText) Timer(org.lflang.lf.Timer) ElkPadding(org.eclipse.elk.core.math.ElkPadding) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) ModeTransitionType(org.lflang.generator.ModeInstance.ModeTransitionType) Pair(org.eclipse.xtext.xbase.lib.Pair)

Aggregations

LinkedHashMultimap (com.google.common.collect.LinkedHashMultimap)1 Inject (com.google.inject.Inject)1 SynthesisOption (de.cau.cs.kieler.klighd.SynthesisOption)1 KEdge (de.cau.cs.kieler.klighd.kgraph.KEdge)1 KIdentifier (de.cau.cs.kieler.klighd.kgraph.KIdentifier)1 KLabel (de.cau.cs.kieler.klighd.kgraph.KLabel)1 KNode (de.cau.cs.kieler.klighd.kgraph.KNode)1 KPort (de.cau.cs.kieler.klighd.kgraph.KPort)1 Colors (de.cau.cs.kieler.klighd.krendering.Colors)1 KContainerRendering (de.cau.cs.kieler.klighd.krendering.KContainerRendering)1 KDecoratorPlacementData (de.cau.cs.kieler.klighd.krendering.KDecoratorPlacementData)1 KEllipse (de.cau.cs.kieler.klighd.krendering.KEllipse)1 KPolyline (de.cau.cs.kieler.klighd.krendering.KPolyline)1 KRectangle (de.cau.cs.kieler.klighd.krendering.KRectangle)1 KRendering (de.cau.cs.kieler.klighd.krendering.KRendering)1 KRenderingFactory (de.cau.cs.kieler.klighd.krendering.KRenderingFactory)1 KText (de.cau.cs.kieler.klighd.krendering.KText)1 LineStyle (de.cau.cs.kieler.klighd.krendering.LineStyle)1 ViewSynthesisShared (de.cau.cs.kieler.klighd.krendering.ViewSynthesisShared)1 KContainerRenderingExtensions (de.cau.cs.kieler.klighd.krendering.extensions.KContainerRenderingExtensions)1