Skip to content

realization_view

Collector for the realization view diagram.

COLLECTORS module-attribute 🔗

COLLECTORS: dict[str, Collector] = {
    "ALL": collect_all,
    "ABOVE": collect_realized,
    "BELOW": collect_realizing,
}

The functions to receive the diagram elements for every layer.

collect_all 🔗

collect_all(
    start: ModelElement, depth: int
) -> dict[LayerLiteral, list[dict[str, t.Any]]]

Collect all elements in both ABOVE and BELOW directions.

Source code in src/capellambse_context_diagrams/collectors/realization_view.py
135
136
137
138
139
140
141
def collect_all(
    start: m.ModelElement, depth: int
) -> 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)
    return above | below

collect_elements 🔗

collect_elements(
    start: ModelElement,
    depth: int,
    direction: str,
    attribute_prefix: str,
    origin: ModelElement | None = None,
) -> dict[LayerLiteral, list[dict[str, t.Any]]]

Collect elements based on the specified direction and attribute name.

Source code in src/capellambse_context_diagrams/collectors/realization_view.py
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
def collect_elements(
    start: m.ModelElement,
    depth: int,
    direction: str,
    attribute_prefix: str,
    origin: m.ModelElement | 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)
    collected_elements: dict[LayerLiteral, list[dict[str, t.Any]]] = {}
    if direction == "ABOVE" or origin is None:
        collected_elements = {
            layer: [{"element": start, "origin": origin, "layer": layer_obj}]
        }
    elif direction == "BELOW" and origin is not None:
        collected_elements = {
            layer: [
                {
                    "element": origin,
                    "origin": start,
                    "layer": layer_obj,
                    "reverse": True,
                }
            ]
        }

    if (
        (direction == "ABOVE" and layer == "Operational")
        or (direction == "BELOW" and layer == "Physical")
        or depth == 0
    ):
        return collected_elements

    if isinstance(start, fa.AbstractFunction):
        attribute_name = f"{attribute_prefix}_functions"
    elif isinstance(start, oa.OperationalActivity):
        attribute_name = f"{attribute_prefix}_system_functions"
    else:
        assert isinstance(start, cs.Component)
        attribute_name = f"{attribute_prefix}_components"

    for element in getattr(start, attribute_name, []):
        sub_collected = collect_elements(
            element, depth - 1, direction, attribute_prefix, origin=start
        )
        for sub_layer, sub_elements in sub_collected.items():
            collected_elements.setdefault(sub_layer, []).extend(sub_elements)
    return collected_elements

collect_realized 🔗

collect_realized(
    start: ModelElement, depth: int
) -> dict[LayerLiteral, list[dict[str, t.Any]]]

Collect all elements from realized_ attributes up to depth.

Source code in src/capellambse_context_diagrams/collectors/realization_view.py
121
122
123
124
125
def collect_realized(
    start: m.ModelElement, depth: int
) -> dict[LayerLiteral, list[dict[str, t.Any]]]:
    """Collect all elements from ``realized_`` attributes up to depth."""
    return collect_elements(start, depth, "ABOVE", "realized")

collect_realizing 🔗

collect_realizing(
    start: ModelElement, depth: int
) -> dict[LayerLiteral, list[dict[str, t.Any]]]

Collect all elements from realizing_ attributes down to depth.

Source code in src/capellambse_context_diagrams/collectors/realization_view.py
128
129
130
131
132
def collect_realizing(
    start: m.ModelElement, depth: int
) -> dict[LayerLiteral, list[dict[str, t.Any]]]:
    """Collect all elements from ``realizing_`` attributes down to depth."""
    return collect_elements(start, depth, "BELOW", "realizing")

collector 🔗

collector(
    diagram: RealizationViewDiagram, params: dict[str, Any]
) -> tuple[_elkjs.ELKInputData, list[_elkjs.ELKInputEdge]]

Return the class tree data for ELK.

Source code in src/capellambse_context_diagrams/collectors/realization_view.py
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
def collector(
    diagram: context.RealizationViewDiagram, params: dict[str, t.Any]
) -> tuple[_elkjs.ELKInputData, list[_elkjs.ELKInputEdge]]:
    """Return the class tree data for ELK."""
    del params
    data = _makers.make_diagram(diagram)
    layout_options: _elkjs.LayoutOptions = copy.deepcopy(
        _elkjs.RECT_PACKING_LAYOUT_OPTIONS  # type:ignore[arg-type]
    )
    layout_options["elk.contentAlignment"] = "V_CENTER H_CENTER"
    del layout_options["widthApproximation.targetWidth"]
    data.layoutOptions = layout_options
    _collector = COLLECTORS[diagram._search_direction]
    lay_to_els = _collector(diagram.target, diagram._depth)
    layer_layout_options: _elkjs.LayoutOptions = layout_options | {  # type: ignore[operator]
        "nodeSize.constraints": "[NODE_LABELS,MINIMUM_SIZE]",
    }
    edges: list[_elkjs.ELKInputEdge] = []
    for layer in ("Operational", "System", "Logical", "Physical"):
        if not (elements := lay_to_els.get(layer)):
            continue

        labels = _makers.make_label(layer)
        width, height = _makers.calculate_height_and_width(labels)
        layer_box = _elkjs.ELKInputChild(
            id=elements[0]["layer"].uuid,
            children=[],
            height=width,
            width=height,
            layoutOptions=layer_layout_options,
        )
        children: dict[str, _elkjs.ELKInputChild] = {}
        for elt in elements:
            assert elt["element"] is not None
            if elt["origin"] is not None:
                edges.append(
                    _elkjs.ELKInputEdge(
                        id=f"{elt['origin'].uuid}_{elt['element'].uuid}",
                        sources=[elt["origin"].uuid],
                        targets=[elt["element"].uuid],
                    )
                )

            if elt.get("reverse", False):
                source = elt["element"]
                target = elt["origin"]
            else:
                source = elt["origin"]
                target = elt["element"]

            if not (element_box := children.get(target.uuid)):
                element_box = _makers.make_box(target, no_symbol=True)
                children[target.uuid] = element_box
                layer_box.children.append(element_box)
                index = len(layer_box.children) - 1

                if diagram._show_owners:
                    owner = target.owner
                    if not isinstance(
                        owner, fa.AbstractFunction | cs.Component
                    ):
                        continue

                    if not (owner_box := children.get(owner.uuid)):
                        owner_box = _makers.make_box(
                            owner,
                            no_symbol=True,
                            layout_options=_makers.DEFAULT_LABEL_LAYOUT_OPTIONS,
                        )
                        owner_box.height += element_box.height
                        children[owner.uuid] = owner_box
                        layer_box.children.append(owner_box)

                    del layer_box.children[index]
                    owner_box.children.append(element_box)
                    owner_box.width += element_box.width
                    for label in owner_box.labels:
                        label.layoutOptions.update(
                            _makers.DEFAULT_LABEL_LAYOUT_OPTIONS
                        )

                    if (
                        source is not None
                        and source.owner is not None
                        and source.owner.uuid in children
                        and owner.uuid in children
                    ):
                        eid = f"{source.owner.uuid}_{owner.uuid}"
                        edges.append(
                            _elkjs.ELKInputEdge(
                                id=eid,
                                sources=[source.owner.uuid],
                                targets=[owner.uuid],
                            )
                        )

        data.children.append(layer_box)
    return data, edges

find_layer 🔗

find_layer(obj: ModelElement) -> tuple[cs.ComponentArchitecture, LayerLiteral]

Return the layer object and its literal.

Return either one of the following: * Operational * System * Logical * Physical

Source code in src/capellambse_context_diagrams/collectors/realization_view.py
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
def find_layer(
    obj: m.ModelElement,
) -> tuple[cs.ComponentArchitecture, LayerLiteral]:
    """Return the layer object and its literal.

    Return either one of the following:
      * ``Operational``
      * ``System``
      * ``Logical``
      * ``Physical``
    """
    parent = obj
    while not isinstance(parent, cs.ComponentArchitecture):
        parent = parent.parent
    if not (match := RE_LAYER_PTRN.match(type(parent).__name__)):
        raise ValueError("No layer was found.")
    return parent, match.group(1)  # type:ignore[return-value]