use of de.cau.cs.kieler.klighd.kgraph.KEdge in project lingua-franca by lf-lang.
the class LinguaFrancaSynthesis method createDependencyEdge.
private KEdge createDependencyEdge(Object associate) {
KEdge edge = _kEdgeExtensions.createEdge();
if (associate != null) {
associateWith(edge, associate);
}
KPolyline line = _kEdgeExtensions.addPolyline(edge);
_linguaFrancaStyleExtensions.boldLineSelectionStyle(line);
_kPolylineExtensions.addJunctionPointDecorator(line);
if (getBooleanValue(USE_ALTERNATIVE_DASH_PATTERN)) {
_kRenderingExtensions.setLineStyle(line, LineStyle.CUSTOM);
_kRenderingExtensions.getLineStyle(line).getDashPattern().addAll(ALTERNATIVE_DASH_PATTERN);
} else {
_kRenderingExtensions.setLineStyle(line, LineStyle.DASH);
}
return edge;
}
use of de.cau.cs.kieler.klighd.kgraph.KEdge in project lingua-franca by lf-lang.
the class LinguaFrancaSynthesis method detectAndAnnotateCycles.
private KNode detectAndAnnotateCycles(KNode node, ReactorInstance reactorInstance, Map<ReactorInstance, KNode> allReactorNodes) {
if (node.getProperty(REACTOR_RECURSIVE_INSTANTIATION)) {
_filterCycleAction.resetCycleFiltering(node);
return addErrorComment(node, TEXT_ERROR_CONTAINS_RECURSION);
} else {
// only detect dependency cycles if not recursive
try {
boolean hasCycle = _cycleVisualization.detectAndHighlightCycles(reactorInstance, allReactorNodes, it -> {
if (it instanceof KNode) {
List<KRendering> renderings = IterableExtensions.toList(Iterables.filter(((KNode) it).getData(), KRendering.class));
if (renderings.size() == 1) {
_linguaFrancaStyleExtensions.errorStyle(IterableExtensions.head(renderings));
} else {
IterableExtensions.filter(renderings, rendering -> {
return rendering.getProperty(KlighdProperties.COLLAPSED_RENDERING);
}).forEach(_linguaFrancaStyleExtensions::errorStyle);
}
} else if (it instanceof KEdge) {
Iterables.filter(((KEdge) it).getData(), KRendering.class).forEach(_linguaFrancaStyleExtensions::errorStyle);
// TODO initiallyHide does not work with incremental (https://github.com/kieler/KLighD/issues/37)
// cycleEgde.initiallyShow() // Show hidden order dependencies
_kRenderingExtensions.setInvisible(_kRenderingExtensions.getKRendering(it), false);
} else if (it instanceof KPort) {
Iterables.filter(((KPort) it).getData(), KRendering.class).forEach(_linguaFrancaStyleExtensions::errorStyle);
// it.reverseTrianglePort()
}
});
if (hasCycle) {
KNode err = addErrorComment(node, TEXT_ERROR_CONTAINS_CYCLE);
// Add to existing figure
KRectangle rectangle = _kContainerRenderingExtensions.addRectangle(_kRenderingExtensions.getKContainerRendering(err));
_kRenderingExtensions.to(_kRenderingExtensions.from(_kRenderingExtensions.setGridPlacementData(rectangle), _kRenderingExtensions.LEFT, 3, 0, _kRenderingExtensions.TOP, (-1), 0), _kRenderingExtensions.RIGHT, 3, 0, _kRenderingExtensions.BOTTOM, 3, 0);
_linguaFrancaStyleExtensions.noSelectionStyle(rectangle);
_kRenderingExtensions.setInvisible(rectangle, true);
_kContainerRenderingExtensions.setGridPlacement(rectangle, 2);
KRectangle subrectangle = _kContainerRenderingExtensions.addRectangle(rectangle);
_kRenderingExtensions.to(_kRenderingExtensions.from(_kRenderingExtensions.setGridPlacementData(subrectangle), _kRenderingExtensions.LEFT, 0, 0, _kRenderingExtensions.TOP, 0, 0), _kRenderingExtensions.RIGHT, 2, 0, _kRenderingExtensions.BOTTOM, 0, 0);
_linguaFrancaStyleExtensions.noSelectionStyle(subrectangle);
_kRenderingExtensions.addSingleClickAction(subrectangle, ShowCycleAction.ID);
KText subrectangleText = _kContainerRenderingExtensions.addText(subrectangle, TEXT_ERROR_CYCLE_BTN_SHOW);
// Copy text style
List<KStyle> styles = ListExtensions.map(IterableExtensions.head(_kRenderingExtensions.getKContainerRendering(err).getChildren()).getStyles(), EcoreUtil::copy);
subrectangleText.getStyles().addAll(styles);
_kRenderingExtensions.setFontSize(subrectangleText, 5);
_kRenderingExtensions.setSurroundingSpace(subrectangleText, 1, 0);
_linguaFrancaStyleExtensions.noSelectionStyle(subrectangleText);
_kRenderingExtensions.addSingleClickAction(subrectangleText, ShowCycleAction.ID);
subrectangle = _kContainerRenderingExtensions.addRectangle(rectangle);
_kRenderingExtensions.to(_kRenderingExtensions.from(_kRenderingExtensions.setGridPlacementData(subrectangle), _kRenderingExtensions.LEFT, 0, 0, _kRenderingExtensions.TOP, 0, 0), _kRenderingExtensions.RIGHT, 0, 0, _kRenderingExtensions.BOTTOM, 0, 0);
_linguaFrancaStyleExtensions.noSelectionStyle(subrectangle);
_kRenderingExtensions.addSingleClickAction(subrectangle, FilterCycleAction.ID);
subrectangleText = _kContainerRenderingExtensions.addText(subrectangle, _filterCycleAction.isCycleFiltered(node) ? TEXT_ERROR_CYCLE_BTN_UNFILTER : TEXT_ERROR_CYCLE_BTN_FILTER);
// Copy text style
styles = ListExtensions.map(IterableExtensions.head(_kRenderingExtensions.getKContainerRendering(err).getChildren()).getStyles(), EcoreUtil::copy);
subrectangleText.getStyles().addAll(styles);
_kRenderingExtensions.setFontSize(subrectangleText, 5);
_kRenderingExtensions.setSurroundingSpace(subrectangleText, 1, 0);
_linguaFrancaStyleExtensions.noSelectionStyle(subrectangleText);
_kRenderingExtensions.addSingleClickAction(subrectangleText, FilterCycleAction.ID);
_filterCycleAction.markCycleFilterText(subrectangleText, err);
// if user interactively requested a filtered diagram keep it filtered during updates
if (_filterCycleAction.isCycleFiltered(node)) {
_filterCycleAction.filterCycle(node);
}
return err;
}
} catch (Exception e) {
_filterCycleAction.resetCycleFiltering(node);
e.printStackTrace();
return addErrorComment(node, TEXT_ERROR_CYCLE_DETECTION);
}
}
return null;
}
use of de.cau.cs.kieler.klighd.kgraph.KEdge in project lingua-franca by lf-lang.
the class LinguaFrancaSynthesis method createUserComments.
private Iterable<KNode> createUserComments(EObject element, KNode targetNode) {
if (getBooleanValue(SHOW_USER_LABELS)) {
String commentText = ASTUtils.findAnnotationInComments(element, "@label");
if (!StringExtensions.isNullOrEmpty(commentText)) {
KNode comment = _kNodeExtensions.createNode();
setLayoutOption(comment, CoreOptions.COMMENT_BOX, true);
KRoundedRectangle commentFigure = _linguaFrancaShapeExtensions.addCommentFigure(comment, commentText);
_linguaFrancaStyleExtensions.commentStyle(commentFigure);
// connect
KEdge edge = _kEdgeExtensions.createEdge();
edge.setSource(comment);
edge.setTarget(targetNode);
_linguaFrancaStyleExtensions.commentStyle(_linguaFrancaShapeExtensions.addCommentPolyline(edge));
return List.of(comment);
}
}
return List.of();
}
use of de.cau.cs.kieler.klighd.kgraph.KEdge in project lingua-franca by lf-lang.
the class FilterCycleAction method filterCycle.
public void filterCycle(KNode root) {
Predicate<KNode> knodeNotInCycle = it -> {
return !it.getProperty(CycleVisualization.DEPENDENCY_CYCLE);
};
Predicate<KEdge> kedgeNotInCycle = it -> {
return !it.getProperty(CycleVisualization.DEPENDENCY_CYCLE);
};
root.getChildren().removeIf(knodeNotInCycle);
for (KNode node : root.getChildren()) {
node.getOutgoingEdges().removeIf(kedgeNotInCycle);
this.filterCycle(node);
}
}
use of de.cau.cs.kieler.klighd.kgraph.KEdge 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 = HashMultimap.<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 fig = addModeContainerFigure(modeContainer);
_kRenderingExtensions.addDoubleClickAction(fig, MemorizingExpandCollapseAction.ID);
if (modeChildren.get(null).isEmpty()) {
_kRenderingExtensions.setInvisible(fig, true);
DiagramSyntheses.setLayoutOption(modeContainer, CoreOptions.PADDING, new ElkPadding());
}
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 : ListExtensions.reverseView(reactor.modes)) {
var modeNode = modeNodes.get(mode);
var edges = new HashSet<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>();
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();
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);
}
}
}
}
}
nodes.add(modeContainer);
}
}
Aggregations