Skip to content

Commit

Permalink
fix!(context-diagram): Enable derived interfaces per default on `Comp…
Browse files Browse the repository at this point in the history
…onent`s

Also fix bugs:
- False symbols bug
- Correctly calculate the centerbox size
  • Loading branch information
ewuerger committed Nov 19, 2024
1 parent 39f69c2 commit cc3938b
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 45 deletions.
12 changes: 8 additions & 4 deletions capellambse_context_diagrams/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ def register_classes() -> None:
{
"display_symbols_as_boxes": True,
"display_parent_relation": True,
"display_derived_interfaces": True,
"render_styles": styling.BLUE_ACTOR_FNCS,
},
),
Expand All @@ -112,6 +113,7 @@ def register_classes() -> None:
{
"display_symbols_as_boxes": True,
"display_parent_relation": True,
"display_derived_interfaces": True,
"render_styles": styling.BLUE_ACTOR_FNCS,
},
),
Expand All @@ -127,14 +129,16 @@ def register_classes() -> None:
(
pa.PhysicalComponent,
DiagramType.PAB,
{"display_parent_relation": True, "display_port_labels": True},
{
"display_parent_relation": True,
"display_port_labels": True,
"display_derived_interfaces": True,
},
),
(
pa.PhysicalFunction,
DiagramType.PAB,
{
"display_parent_relation": True,
},
{"display_parent_relation": True},
),
]
cap: dict[str, CSSdef] = {
Expand Down
39 changes: 22 additions & 17 deletions capellambse_context_diagrams/collectors/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@
from .. import context

DerivatorFunction: t.TypeAlias = cabc.Callable[
[context.ContextDiagram, _elkjs.ELKInputData, _elkjs.ELKInputChild],
[
context.ContextDiagram,
_elkjs.ELKInputData,
dict[str, _elkjs.ELKInputChild],
],
None,
]

Expand Down Expand Up @@ -90,13 +94,12 @@ def process_context(self):

self.data.children.extend(self.global_boxes.values())
if self.diagram._display_parent_relation:
owner_boxes: dict[str, _elkjs.ELKInputChild] = {
uuid: box for uuid, box in self.made_boxes.items()
}
generic.move_parent_boxes_to_owner(
owner_boxes, self.diagram.target, self.data
self.made_boxes, self.diagram.target, self.data
)
generic.move_edges(
self.made_boxes, self.exchanges.values(), self.data
)
generic.move_edges(owner_boxes, self.exchanges.values(), self.data)

if self.diagram._hide_direct_children:
self.centerbox.children = []
Expand Down Expand Up @@ -327,7 +330,7 @@ def collector(
derivator(
diagram,
data,
processor.made_boxes[diagram.target.uuid],
processor.made_boxes,
)
return data

Expand Down Expand Up @@ -466,7 +469,7 @@ def port_context_collector(
def derive_from_functions(
diagram: context.ContextDiagram,
data: _elkjs.ELKInputData,
centerbox: _elkjs.ELKInputChild,
boxes: dict[str, _elkjs.ELKInputChild],
) -> None:
"""Derive Components from allocated functions of the context target.
Expand All @@ -480,8 +483,7 @@ def derive_from_functions(
inc, out = port_collector(fnc, diagram.type)
ports.extend(inc + out)

context_box_ids = {child.id for child in data.children}
components: dict[str, cs.Component] = {}
derived_components: dict[str, cs.Component] = {}
for port in ports:
for fex in port.exchanges:
if isinstance(port, fa.FunctionOutputPort):
Expand All @@ -493,20 +495,24 @@ def derive_from_functions(
derived_comp = getattr(fex, attr).owner.owner
if (
derived_comp == diagram.target
or derived_comp.uuid in context_box_ids
or derived_comp.uuid in boxes
):
continue

if derived_comp.uuid not in components:
components[derived_comp.uuid] = derived_comp
if derived_comp.uuid not in derived_components:
derived_components[derived_comp.uuid] = derived_comp
except AttributeError: # No owner of owner.
pass

# Idea: Include flow direction of derived interfaces from all functional
# exchanges. Mixed means bidirectional. Just even out bidirectional
# interfaces and keep flow direction of others.

for i, (uuid, derived_component) in enumerate(components.items(), 1):
centerbox = boxes[diagram.target.uuid]
i = 0
for i, (uuid, derived_component) in enumerate(
derived_components.items(), 1
):
box = makers.make_box(
derived_component,
no_symbol=diagram._display_symbols_as_boxes,
Expand All @@ -529,9 +535,8 @@ def derive_from_functions(
)
)

data.children[0].height += (
makers.PORT_PADDING
+ (makers.PORT_SIZE + makers.PORT_PADDING) * len(components) // 2
centerbox.height += (
makers.PORT_PADDING + (makers.PORT_SIZE + makers.PORT_PADDING) * i // 2
)


Expand Down
16 changes: 0 additions & 16 deletions capellambse_context_diagrams/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,10 +393,6 @@ def __len__(self) -> int:
def _create_diagram(self, params: dict[str, t.Any]) -> cdiagram.Diagram:
data = self.elk_input_data(params)
assert not isinstance(data, tuple)
if not isinstance(self, ClassTreeDiagram) and has_single_child(data):
self._display_derived_interfaces = True
data = get_elkdata(self, params)

layout = try_to_layout(data)
is_legend: bool = params.get("is_legend", False) # type: ignore[assignment]
add_context(layout, is_legend)
Expand Down Expand Up @@ -950,18 +946,6 @@ def calculate_label_position(
return (x + width / 2, center_y, tspan_y)


def has_single_child(data: _elkjs.ELKInputData | _elkjs.ELKInputChild) -> bool:
"""Checks if ``data`` has a single or no child."""
if not data.children:
return True

for child in data.children:
if not has_single_child(child):
return False

return len(data.children) == 1


def _get_all_ports(
node: _elkjs.ELKOutputNode, ref: cdiagram.Vector2D
) -> cabc.Iterator[tuple[cdiagram.Vector2D, _elkjs.ELKOutputPort]]:
Expand Down
16 changes: 8 additions & 8 deletions tests/test_context_diagrams.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,31 +114,31 @@ def test_context_diagrams_rerender_on_parameter_change(
),
pytest.param(
[
(TEST_ACTOR_SIZING_UUID, 41, 41),
(TEST_ACTOR_SIZING_UUID, 40, 40),
(TEST_HUMAN_ACTOR_SIZING_UUID, 43, 43),
(TEST_CAP_SIZING_UUID, 141, 141),
],
id="Capability",
),
pytest.param(
[
("e1e48763-7479-4f3a-8134-c82bb6705d58", 126, 201),
("8df45b70-15cc-4d3a-99e4-593516392c5a", 154, 248),
("74af6883-25a0-446a-80f3-656f8a490b11", 266, 435),
("e1e48763-7479-4f3a-8134-c82bb6705d58", 126, 190),
("8df45b70-15cc-4d3a-99e4-593516392c5a", 154, 234),
("74af6883-25a0-446a-80f3-656f8a490b11", 266, 412),
],
id="LogicalComponent",
),
pytest.param(
[
("0c06cc88-8c77-46f2-8542-c08b1e8edd18", 112, 177),
("9f1e1875-9ead-4af2-b428-c390786a436a", 112, 177),
("0c06cc88-8c77-46f2-8542-c08b1e8edd18", 112, 168),
("9f1e1875-9ead-4af2-b428-c390786a436a", 112, 168),
],
id="LogicalFunction",
),
pytest.param(
[
("6241d0c5-65d2-4c0b-b79c-a2a8ed7273f6", 37, 37),
("344a405e-c7e5-4367-8a9a-41d3d9a27f81", 41, 41),
("6241d0c5-65d2-4c0b-b79c-a2a8ed7273f6", 36, 36),
("344a405e-c7e5-4367-8a9a-41d3d9a27f81", 40, 40),
("230c4621-7e0a-4d0a-9db2-d4ba5e97b3df", 42, 60),
],
id="SystemComponent Root",
Expand Down

0 comments on commit cc3938b

Please sign in to comment.