diff --git a/capellambse_context_diagrams/collectors/exchanges.py b/capellambse_context_diagrams/collectors/exchanges.py index f4eaab46..baa3b54d 100644 --- a/capellambse_context_diagrams/collectors/exchanges.py +++ b/capellambse_context_diagrams/collectors/exchanges.py @@ -9,6 +9,7 @@ import typing as t from capellambse.model import common +from capellambse.model.crosslayer import cs from capellambse.model.modeltypes import DiagramType as DT from .. import _elkjs, context @@ -90,6 +91,28 @@ def get_functions_and_exchanges( return functions, incomings, outgoings + def collect_context( + self, comp: common.GenericElement, interface: common.GenericElement + ) -> dict[str, t.Any]: + functions, outgoings, incomings = self.get_functions_and_exchanges( + comp, interface + ) + components = [] + for cmp in comp.components: + fncs, incs, outs = self.get_functions_and_exchanges(cmp, interface) + functions.extend(fncs) + outgoings.extend(outs) + incomings.extend(incs) + if fncs: + components.append(self.collect_context(cmp, interface)) + return { + "element": comp, + "functions": functions, + "outgoings": outgoings, + "incomings": incomings, + "components": components, + } + def make_ports_and_update_children_size( self, data: _elkjs.ELKInputChild, @@ -100,6 +123,9 @@ def make_ports_and_update_children_size( for child in data["children"]: inputs, outputs = [], [] obj = self.obj._model.by_uuid(child["id"]) + if isinstance(obj, cs.Component): + self.make_ports_and_update_children_size(child, exchanges) + return port_ids = {p.uuid for p in obj.inputs + obj.outputs} for ex in exchanges: source, target = ex["sources"][0], ex["targets"][0] @@ -178,15 +204,19 @@ def get_capella_order( alloc_functions = self.get_alloc_functions(comp) return [fnc for fnc in alloc_functions if fnc in functions] - def make_boxes( - comp: common.GenericElement, functions: list[common.GenericElement] - ) -> None: + def make_boxes(cntxt: dict[str, t.Any]) -> _elkjs.ELKInputChild | None: + comp = cntxt["element"] + functions = cntxt["functions"] + components = cntxt["components"] if comp.uuid not in made_children: children = [ makers.make_box(c) for c in functions if c in self.get_alloc_functions(comp) ] + for c in components: + if child := make_boxes(c): + children.append(child) if children: layout_options = makers.DEFAULT_LABEL_LAYOUT_OPTIONS else: @@ -196,45 +226,49 @@ def make_boxes( comp, no_symbol=True, layout_options=layout_options ) box["children"] = children - self.data["children"].append(box) made_children.add(comp.uuid) + return box + return None try: comp = self.get_source(self.obj) - functions, incs, outs = self.get_functions_and_exchanges( - comp, self.obj + left_context = self.collect_context(comp, self.obj) + functions = left_context["functions"] + inc_port_ids = set( + ex.target.uuid for ex in left_context["incomings"] + ) + out_port_ids = set( + ex.source.uuid for ex in left_context["outgoings"] ) - inc_port_ids = set(ex.target.uuid for ex in incs) - out_port_ids = set(ex.source.uuid for ex in outs) port_spread = len(out_port_ids) - len(inc_port_ids) _comp = self.get_target(self.obj) - _functions, _, _ = self.get_functions_and_exchanges( - _comp, self.obj + right_context = self.collect_context(_comp, self.obj) + _functions = right_context["functions"] + _inc_port_ids = set( + ex.target.uuid for ex in left_context["outgoings"] + ) + _out_port_ids = set( + ex.source.uuid for ex in left_context["incomings"] ) - _inc_port_ids = set(ex.target.uuid for ex in outs) - _out_port_ids = set(ex.source.uuid for ex in incs) _port_spread = len(_out_port_ids) - len(_inc_port_ids) functions = get_capella_order(comp, functions) _functions = get_capella_order(_comp, _functions) if port_spread >= _port_spread: - self.left = comp - self.right = _comp - self.outgoing_edges = outs - self.incoming_edges = incs - left_functions = functions - right_functions = _functions + self.outgoing_edges = left_context["outgoings"] + self.incoming_edges = left_context["incomings"] else: - self.left = _comp - self.right = comp - self.outgoing_edges = incs - self.incoming_edges = outs - left_functions = _functions - right_functions = functions - - make_boxes(self.left, left_functions) - make_boxes(self.right, right_functions) + temp = left_context + left_context = right_context + right_context = temp + self.outgoing_edges = left_context["incomings"] + self.incoming_edges = left_context["outgoings"] + + if left_child := make_boxes(left_context): + self.data["children"].append(left_child) + if right_child := make_boxes(right_context): + self.data["children"].append(right_child) except AttributeError: pass