From 605a6ea7d6c5ac8a153f52f96ba988a748d1aecd Mon Sep 17 00:00:00 2001 From: Huyen Nguyen <48179958+huyenngn@users.noreply.github.com> Date: Mon, 12 Feb 2024 13:35:19 +0100 Subject: [PATCH] feat: Add context to elements and dataflow-view Co-authored-by: ewuerger --- capellambse_context_diagrams/_elkjs.py | 1 + .../collectors/dataflow_view.py | 2 +- .../collectors/realization_view.py | 4 +- capellambse_context_diagrams/context.py | 61 +++++++++++++++++-- capellambse_context_diagrams/serializers.py | 3 + 5 files changed, 62 insertions(+), 9 deletions(-) diff --git a/capellambse_context_diagrams/_elkjs.py b/capellambse_context_diagrams/_elkjs.py index b84053e0..719b08ce 100644 --- a/capellambse_context_diagrams/_elkjs.py +++ b/capellambse_context_diagrams/_elkjs.py @@ -178,6 +178,7 @@ class ELKOutputJunction(ELKOutputElement): """Exchange-Junction that comes out of ELK.""" type: t.Literal["junction"] + children: cabc.MutableSequence[ELKOutputLabel] position: ELKPoint size: ELKSize diff --git a/capellambse_context_diagrams/collectors/dataflow_view.py b/capellambse_context_diagrams/collectors/dataflow_view.py index 6d95ef59..3802e347 100644 --- a/capellambse_context_diagrams/collectors/dataflow_view.py +++ b/capellambse_context_diagrams/collectors/dataflow_view.py @@ -1,7 +1,7 @@ # SPDX-FileCopyrightText: 2022 Copyright DB InfraGO AG and the capellambse-context-diagrams contributors # SPDX-License-Identifier: Apache-2.0 -"""...""" +"""This module defines the collectors for the DataFlowDiagram.""" from __future__ import annotations import collections.abc as cabc diff --git a/capellambse_context_diagrams/collectors/realization_view.py b/capellambse_context_diagrams/collectors/realization_view.py index f73d585f..03c35c2b 100644 --- a/capellambse_context_diagrams/collectors/realization_view.py +++ b/capellambse_context_diagrams/collectors/realization_view.py @@ -121,7 +121,7 @@ def collect_realizing( def collect_all( start: common.GenericElement, depth: int -) -> dict[LayerLiteral, list[common.GenericElement]]: +) -> dict[LayerLiteral, list[dict[str, t.Any]]]: """Collect all elements in both ABOVE and BELOW directions.""" above = collect_realized(start, depth) below = collect_realizing(start, depth) @@ -133,7 +133,7 @@ def collect_elements( depth: int, direction: str, attribute_prefix: str, - origin: common.GenericElement = None, + origin: common.GenericElement | None = None, ) -> dict[LayerLiteral, list[dict[str, t.Any]]]: """Collect elements based on the specified direction and attribute name.""" layer_obj, layer = find_layer(start) diff --git a/capellambse_context_diagrams/context.py b/capellambse_context_diagrams/context.py index 53b84cb3..ab8b5639 100644 --- a/capellambse_context_diagrams/context.py +++ b/capellambse_context_diagrams/context.py @@ -338,6 +338,7 @@ def render(self, fmt: str | None, /, **params) -> t.Any: def _create_diagram(self, params: dict[str, t.Any]) -> cdiagram.Diagram: data = params.get("elkdata") or get_elkdata(self, params) layout = try_to_layout(data) + add_context(layout, params.get("is_legend", False)) return self.serializer.make_diagram(layout) @property # type: ignore @@ -431,11 +432,54 @@ def _create_diagram(self, params: dict[str, t.Any]) -> cdiagram.Diagram: legend["layoutOptions"]["aspectRatio"] = width axis = "y" params["elkdata"] = legend + params["is_legend"] = True legend_diagram = super()._create_diagram(params) stack_diagrams(class_diagram, legend_diagram, axis) return class_diagram +def add_context(data: _elkjs.ELKOutputData, is_legend: bool = False) -> None: + """Add all connected nodes as context to all elements.""" + if is_legend: + for child in data["children"]: + if child["type"] == "node": + child["context"] = [child["id"]] # type: ignore[typeddict-unknown-key] + return + + ids: set[str] = set() + + def get_ids( + obj: ( + _elkjs.ELKOutputNode + | _elkjs.ELKOutputPort + | _elkjs.ELKOutputJunction + | _elkjs.ELKOutputEdge + ), + ) -> None: + if obj["id"] and not obj["id"].startswith("g_"): + ids.add(obj["id"]) + for child in obj.get("children", []): + if child["type"] in {"node", "port", "junction", "edge"}: + assert child["type"] != "label" + get_ids(child) + + def set_ids( + obj: _elkjs.ELKOutputChild, + ids: set[str], + ) -> None: + obj["context"] = list(ids) # type: ignore[typeddict-unknown-key] + for child in obj.get("children", []): # type: ignore[attr-defined] + set_ids(child, ids) + + for child in data["children"]: + if child["type"] in {"node", "port", "junction", "edge"}: + assert child["type"] != "label" + get_ids(child) + + for child in data["children"]: + set_ids(child, ids) + + class RealizationViewDiagram(ContextDiagram): """An automatically generated RealizationViewDiagram Diagram. @@ -566,12 +610,17 @@ def stack_diagrams( axis: t.Literal["x", "y"] = "x", ) -> None: """Add the diagram elements from ``right`` to left inline.""" - offset = first.viewport.pos + first.viewport.size - offset @= (1, 0) if axis == "x" else (0, 1) - for element in second: - new = copy.deepcopy(element) - new.move(offset) - first += new + if first.viewport: + offset = first.viewport.pos + first.viewport.size + offset @= (1, 0) if axis == "x" else (0, 1) + for element in second: + new = copy.deepcopy(element) + new.move(offset) + first += new + else: + for element in second: + new = copy.deepcopy(element) + first += new def calculate_label_position( diff --git a/capellambse_context_diagrams/serializers.py b/capellambse_context_diagrams/serializers.py index cbfb7eb3..bae440ac 100644 --- a/capellambse_context_diagrams/serializers.py +++ b/capellambse_context_diagrams/serializers.py @@ -141,6 +141,7 @@ class type that stores all previously named classes. styleclass=styleclass, styleoverrides=self.get_styleoverrides(child), features=features, + context=child.get("context"), ) element.JSON_TYPE = box_type self.diagram.add_element(element) @@ -165,6 +166,7 @@ class type that stores all previously named classes. target=self.diagram[child["targetId"]], styleclass=styleclass, styleoverrides=self.get_styleoverrides(child), + context=child.get("context"), ) self.diagram.add_element(element) self._cache[child["id"]] = element @@ -205,6 +207,7 @@ class type that stores all previously named classes. uuid=child["id"], styleclass=self.get_styleclass(uuid), styleoverrides=self.get_styleoverrides(child), + context=child.get("context"), ) self.diagram.add_element(element) else: