Пример #1
0
    def __init__(self, diagram, id=None):
        super().__init__(diagram, id)
        for h in self.handles():
            h.movable = False

        self.shape = IconBox(
            Box(style={
                "min-width": 30,
                "min-height": 30
            },
                draw=draw_final_state),
            Text(text=lambda: stereotypes_str(self.subject), ),
            EditableText(
                text=lambda: self.subject and self.subject.name or ""),
        )

        self.watch("subject[NamedElement].name")
        self.watch("subject.appliedStereotype.classifier.name")
Пример #2
0
    def __init__(self, id=None, model=None):
        super().__init__(id, model)

        self.shape_tail = Box(
            Text(text=lambda: stereotypes_str(self.subject), ),
            EditableText(text=lambda: self.subject.name or ""),
        )

        self.watch("subject[NamedElement].name")
        self.watch("subject.appliedStereotype.classifier.name")

        self.shape_middle = EditableText(
            text=lambda: self.subject and self.subject.guard or "")

        self.watch("subject[ControlFlow].guard")
        self.watch("subject[ObjectFlow].guard")

        self.draw_tail = draw_arrow_tail
Пример #3
0
    def __init__(self, connections, id=None, model=None):
        super().__init__(connections, id, model)

        self.shape_tail = Box(
            Text(text=lambda: stereotypes_str(self.subject), ),
            EditableText(text=lambda: self.subject.name or ""),
        )

        self.watch("subject[NamedElement].name")
        self.watch("subject.appliedStereotype.classifier.name")

        self.shape_middle = EditableText(
            text=lambda: self.subject and self.subject.guard and self.subject.
            guard.specification or "")

        self.watch("subject[Transition].guard[Constraint].specification")

        self.draw_tail = draw_arrow_tail
Пример #4
0
    def __init__(self, id=None, model=None):
        super().__init__(id, model)
        no_movable_handles(self)

        self.shape = IconBox(
            Box(style={
                "min-width": 30,
                "min-height": 30
            },
                draw=draw_activity_final_node),
            # Text should be right-bottom
            Text(text=lambda: stereotypes_str(self.subject), ),
            EditableText(
                text=lambda: self.subject and self.subject.name or ""),
        )

        self.watch("subject[NamedElement].name")
        self.watch("subject.appliedStereotype.classifier.name")
Пример #5
0
    def __init__(self, diagram, id=None):
        super().__init__(diagram, id, width=ARM * 2, height=HEAD + NECK + BODY + ARM)

        self.shape = IconBox(
            Box(
                draw=draw_actor,
            ),
            Text(
                text=lambda: stereotypes_str(self.subject),
            ),
            EditableText(
                text=lambda: self.subject.name or "",
                style={"font-weight": FontWeight.BOLD},
            ),
        )

        self.watch("subject[NamedElement].name")
        self.watch("subject.appliedStereotype.classifier.name")
Пример #6
0
    def __init__(self, id=None, model=None):
        super().__init__(id, model, style={"dash-style": (7.0, 5.0)})

        self.shape_middle = Box(
            Text(
                text=lambda: stereotypes_str(self.subject,
                                             (self.relation_type, )),
                style={
                    "min-width": 0,
                    "min-height": 0
                },
            ),
            EditableText(text=lambda: self.subject.name or ""),
        )

        self.draw_head = draw_arrow_head
        self.watch("subject[NamedElement].name").watch(
            "subject.appliedStereotype.classifier.name")
Пример #7
0
    def __init__(self, id=None, model=None):
        super().__init__(id, model)

        # AssociationEnds are really inseperable from the AssociationItem.
        # We give them the same id as the association item.
        self._head_end = AssociationEnd(owner=self, end="head")
        self._tail_end = AssociationEnd(owner=self, end="tail")

        # Direction depends on the ends that hold the ownedEnd attributes.
        self._show_direction = False
        self._dir_angle = 0
        self._dir_pos = 0, 0

        self.shape_middle = Box(
            Text(
                text=lambda: stereotypes_str(self.subject),
                style={
                    "min-width": 0,
                    "min-height": 0
                },
            ),
            EditableText(text=lambda: self.subject.name or ""),
        )

        # For the association ends:
        base = "subject[Association].memberEnd[Property]"
        self.watch("subject[NamedElement].name").watch(
            "subject.appliedStereotype.classifier.name"
        ).watch(f"{base}.name", self.on_association_end_value).watch(
            f"{base}.aggregation", self.on_association_end_value
        ).watch(f"{base}.classifier", self.on_association_end_value).watch(
            f"{base}.visibility", self.on_association_end_value).watch(
                f"{base}.lowerValue", self.on_association_end_value).watch(
                    f"{base}.upperValue", self.on_association_end_value).watch(
                        f"{base}.owningAssociation",
                        self.on_association_end_value).watch(
                            f"{base}.type[Class].ownedAttribute",
                            self.on_association_end_value).watch(
                                f"{base}.type[Interface].ownedAttribute",
                                self.on_association_end_value).watch(
                                    f"{base}.appliedStereotype.classifier",
                                    self.on_association_end_value
                                ).watch("subject[Association].ownedEnd").watch(
                                    "subject[Association].navigableOwnedEnd")
Пример #8
0
    def __init__(self, id=None, model=None):
        super().__init__(id, model)
        for h in self.handles():
            h.movable = False
        self.shape = IconBox(
            Box(draw=draw_history_pseudostate),
            Text(
                text=lambda: stereotypes_str(self.subject),
                style={
                    "min-width": 0,
                    "min-height": 0
                },
            ),
            EditableText(
                text=lambda: self.subject and self.subject.name or ""),
        )

        self.watch("subject<NamedElement>.name")
        self.watch("subject.appliedStereotype.classifier.name")
Пример #9
0
    def __init__(self, connections, id=None, model=None):
        super().__init__(connections, id, model)

        self.shape = Box(
            Text(
                text=lambda: stereotypes_str(self.subject),
            ),
            EditableText(text=lambda: self.subject.name or ""),
            style={
                "min-width": 50,
                "min-height": 30,
                "padding": (5, 10, 5, 10),
                "border-radius": 15,
            },
            draw=draw_border,
        )

        self.watch("subject[NamedElement].name")
        self.watch("subject.appliedStereotype.classifier.name")
Пример #10
0
    def __init__(self, id=None, model=None):
        super().__init__(id, model)

        h1, h2 = Handle(), Handle()
        self._handles.append(h1)
        self._handles.append(h2)
        self._ports.append(LinePort(h1.pos, h2.pos))

        self._combined = None

        self.shape = IconBox(
            Box(style={
                "min-width": 0,
                "min-height": 45
            },
                draw=self.draw_fork_node),
            Text(
                text=lambda: stereotypes_str(self.subject),
                style={
                    "min-width": 0,
                    "min-height": 0
                },
            ),
            EditableText(
                text=lambda: self.subject and self.subject.name or ""),
            Text(
                text=lambda: isinstance(self.subject, UML.JoinNode) and self.
                subject.joinSpec not in (None, DEFAULT_JOIN_SPEC) and
                f"{{ joinSpec = {self.subject.joinSpec} }}" or "",
                style={
                    "min-width": 0,
                    "min-height": 0
                },
            ),
        )

        self.watch("subject[NamedElement].name")
        self.watch("subject.appliedStereotype.classifier.name")
        self.watch("subject[JoinNode].joinSpec")

        self.constraint(vertical=(h1.pos, h2.pos))
        self.constraint(above=(h1.pos, h2.pos), delta=30)
Пример #11
0
def attributes_compartment(subject):
    # We need to fix the attribute value, since the for loop changes it.
    def lazy_format(attribute):
        return lambda: format(attribute)

    return Box(
        *(Text(
            text=lazy_format(attribute),
            style={
                "text-align":
                TextAlign.LEFT,
                "text-decoration":
                TextDecoration.UNDERLINE
                if attribute.isStatic else TextDecoration.NONE,
            },
        ) for attribute in subject.ownedAttribute
          if not attribute.association),
        style={"padding": (4, 4, 4, 4)},
        draw=draw_top_separator,
    )
Пример #12
0
    def __init__(self, id=None, model=None):
        super().__init__(id, model)

        self.shape = IconBox(
            Box(
                style={
                    "min-width": ARM * 2,
                    "min-height": HEAD + NECK + BODY + ARM
                },
                draw=draw_actor,
            ),
            Text(text=lambda: stereotypes_str(self.subject), ),
            EditableText(
                text=lambda: self.subject.name or "",
                style={"font-weight": FontWeight.BOLD},
            ),
        )

        self.watch("subject[NamedElement].name")
        self.watch("subject.appliedStereotype.classifier.name")
Пример #13
0
def test_icon_box_child_placement_center_bottom(context):
    style = {
        "text-align": TextAlign.CENTER,
        "vertical-align": VerticalAlign.BOTTOM
    }

    text = Text(text="some text")
    shape = IconBox(
        Box(),
        text,
    )
    shape.size(context)

    w, h = shape.sizes[0]
    bounding_box = Rectangle(0, 0, 10, 20)

    x, y, _, _ = shape.child_pos(style, bounding_box)

    assert x == (bounding_box.width - w) / 2
    assert y == bounding_box.height
Пример #14
0
def test_icon_box_child_placement_left_middle(context):
    style = {
        "text-align": TextAlign.LEFT,
        "vertical-align": VerticalAlign.MIDDLE
    }

    text = Text(text="some text")
    shape = IconBox(
        Box(),
        text,
    )
    shape.size(context)

    w, h = shape.sizes[0]
    bounding_box = Rectangle(0, 0, 10, 20)

    x, y, _, _ = shape.child_pos(style, bounding_box)

    assert x == -w
    assert y == (bounding_box.height - h) / 2
Пример #15
0
 def ball_and_socket_shape(self, connectors=None):
     if connectors is None:
         # distinguish between None and []
         connected_items = [
             c.item for c in self.diagram.connections.get_connections(
                 connected=self)
         ]
         connectors = any(
             map(lambda i: isinstance(i.subject, UML.Connector),
                 connected_items))
     return IconBox(
         Box(draw=self.draw_interface_ball_and_socket, ),
         Text(text=lambda: UML.model.stereotypes_str(self.subject), ),
         EditableText(
             text=lambda: self.subject.name or "",
             style={
                 "font-weight":
                 FontWeight.NORMAL if connectors else FontWeight.BOLD
             },
         ),
     )
Пример #16
0
def _create_stereotype_compartment(appliedStereotype):
    def lazy_format(slot):
        return lambda: format(slot)

    slots = [slot for slot in appliedStereotype.slot if slot.value]

    if slots:
        return Box(
            Text(
                text=lazy_format(appliedStereotype.classifier[0]),
                style={"padding": (0, 0, 4, 0)},
            ),
            *(
                Text(text=lazy_format(slot), style={"text-align": TextAlign.LEFT})
                for slot in slots
            ),
            style={"padding": (4, 4, 4, 4), "vertical-align": VerticalAlign.TOP},
            draw=draw_top_separator,
        )
    else:
        return None
Пример #17
0
    def __init__(self, diagram, id=None):
        super().__init__(diagram, id, style={"dash-style": (7.0, 5.0)})

        self._dependency_type = UML.Dependency
        # auto_dependency is used by connection logic, not in this class itself
        self.auto_dependency = True

        additional_stereotype = {
            UML.Usage: ("use", ),
            UML.Realization: ("realize", ),
            UML.InterfaceRealization: ("implements", ),
        }

        self.shape_middle = Box(
            Text(text=lambda: stereotypes_str(
                self.subject,
                additional_stereotype.get(self._dependency_type, ())), ),
            EditableText(text=lambda: self.subject.name or ""),
        )
        self.watch("subject[NamedElement].name")
        self.watch("subject.appliedStereotype.classifier.name")
Пример #18
0
    def block_compartment(self, name, predicate):
        # We need to fix the attribute value, since the for loop changes it.
        def lazy_format(attribute):
            return lambda: format_property(attribute) or gettext("unnamed")

        return Box(
            Text(
                text=name,
                style={
                    "padding": (0, 0, 4, 0),
                    "font-size": "x-small",
                    "font-style": FontStyle.ITALIC,
                },
            ),
            *(Text(text=lazy_format(attribute),
                   style={"text-align": TextAlign.LEFT})
              for attribute in self.subject.ownedAttribute
              if predicate(attribute)),
            style={"padding": (4, 4, 4, 4)},
            draw=draw_top_separator,
        )
Пример #19
0
    def __init__(self, id=None, model=None):
        super().__init__(
            id,
            model,
            shape_middle=Box(
                Text(
                    text=lambda: stereotypes_str(self.subject),
                    style={
                        "min-width": 0,
                        "min-height": 0
                    },
                ),
                EditableText(text=lambda: self.subject.name or ""),
            ),
        )

        self._is_communication = False
        self._arrow_pos = 0, 0
        self._arrow_angle = 0

        self.watch("subject[NamedElement].name")
        self.watch("subject.appliedStereotype.classifier.name")
Пример #20
0
    def __init__(self, id=None, model=None):
        super().__init__(id, model)

        self.shape = Box(
            Text(
                text=lambda: stereotypes_str(
                    self.subject,
                    isinstance(self.subject, UML.Profile) and ("profile", ) or
                    (),
                ),
                style={
                    "min-width": 0,
                    "min-height": 0
                },
            ),
            EditableText(
                text=lambda: self.subject and self.subject.name or "",
                style={"font-weight": FontWeight.BOLD},
            ),
            Text(
                text=lambda: from_package_str(self),
                style={
                    "font": "sans 8",
                    "min-width": 0,
                    "min-height": 0
                },
            ),
            style={
                "min-width": 50,
                "min-height": 70,
                "padding": (25, 10, 5, 10)
            },
            draw=draw_package,
        )

        self.watch("subject[NamedElement].name")
        self.watch("subject[NamedElement].namespace")
        self.watch("subject.appliedStereotype.classifier.name")
Пример #21
0
    def __init__(self, id=None, model=None):
        super().__init__(id, model)
        OFFSET = 5
        ear = self.EAR
        self.min_width = ear + 2 * OFFSET
        self.height = 50
        self.width = 100

        self.body = Text(
            text=lambda: self.subject.body or "",
            width=lambda: self.width - ear - 2 * OFFSET,
            style={
                "text-align": TextAlign.LEFT,
                "vertical-align": VerticalAlign.TOP
            },
        )

        self.shape = Box(
            self.body,
            style={"padding": (OFFSET, ear + OFFSET, OFFSET, OFFSET)},
            draw=self.draw_border,
        )
        self.watch("subject[Comment].body")
Пример #22
0
def attributes_compartment(subject):
    # We need to fix the attribute value, since the for loop changes it.
    def lazy_format(attribute):
        # str(), so we never ever get an error on a property part of an association
        return lambda: (UML.format(attribute))

    return Box(
        *(
            Text(
                text=lazy_format(attribute),
                style={
                    "text-align": TextAlign.LEFT,
                    "text-decoration": TextDecoration.UNDERLINE
                    if attribute.isStatic
                    else TextDecoration.NONE,
                },
            )
            for attribute in subject.ownedAttribute
            if not attribute.association
        ),
        style={"padding": (4, 4, 4, 4), "min-height": 8},
        draw=draw_top_separator,
    )
Пример #23
0
    def __init__(self, id=None, model=None):
        super().__init__(id, model)
        self.shape = Box(
            Text(
                text=lambda: stereotypes_str(self.subject),
                style={
                    "min-width": 0,
                    "min-height": 0
                },
            ),
            EditableText(
                text=lambda: self.subject.name or "",
                style={"font-weight": FontWeight.BOLD},
            ),
            style={
                "min-width": 50,
                "min-height": 30
            },
            draw=draw_usecase,
        )

        self.watch("subject[NamedElement].name")
        self.watch("subject.appliedStereotype.classifier.name")
Пример #24
0
    def __init__(self, id=None, model=None):
        super().__init__(id, model)

        self.shape_tail = Box(
            Text(
                text=lambda: stereotypes_str(self.subject),
                style={
                    "min-width": 0,
                    "min-height": 0
                },
            ),
            EditableText(text=lambda: self.subject.name or ""),
        )

        self.watch("subject<NamedElement>.name")
        self.watch("subject.appliedStereotype.classifier.name")

        self.shape_middle = EditableText(
            text=lambda: self.subject and self.subject.guard or "")

        self.watch("subject<ControlFlow>.guard")
        self.watch("subject<ObjectFlow>.guard")

        self.draw_tail = draw_arrow_tail
Пример #25
0
 def update_shapes(self, event=None):
     text_align = (TextAlign.LEFT
                   if self.diagram and self.children else TextAlign.CENTER)
     self.shape = Box(
         EditableText(
             text=lambda: self.subject.name or "",
             style={
                 "font-weight": FontWeight.BOLD,
                 "text-align": text_align
             },
         ),
         Text(
             text=lambda: self.subject.technology and
             f"[{gettext(self.subject.type)}: {self.subject.technology}]" or
             f"[{gettext(self.subject.type)}]",
             style={
                 "font-size": "x-small",
                 "text-align": text_align
             },
         ),
         *(() if self.children else (Text(
             text=lambda: self.subject.description or "",
             width=lambda: self.width - 8,
             style={
                 "padding": (4, 0, 0, 0),
                 "text-align": text_align
             },
         ), )),
         style={
             "padding": (4, 4, 4, 4),
             "vertical-align":
             VerticalAlign.BOTTOM
             if self.diagram and self.children else VerticalAlign.MIDDLE,
         },
         draw=draw_border,
     )
Пример #26
0
def operations_compartment(subject):
    def lazy_format(operation):
        return lambda: format(operation,
                              visibility=True,
                              type=True,
                              multiplicity=True,
                              default=True)

    return Box(
        *(Text(
            text=lazy_format(operation),
            style={
                "text-align":
                TextAlign.LEFT,
                "font-style":
                FontStyle.ITALIC if operation.isAbstract else FontStyle.NORMAL,
                "text-decoration":
                TextDecoration.UNDERLINE
                if operation.isStatic else TextDecoration.NONE,
            },
        ) for operation in subject.ownedOperation),
        style={"padding": (4, 4, 4, 4)},
        draw=draw_top_separator,
    )
Пример #27
0
def test_draw_empty_box():
    box = Box(draw=None)

    box.draw(context=None, bounding_box=Rectangle())
Пример #28
0
def test_box_size():
    box = Box()

    assert box.size(cr=None) == (0, 0)
Пример #29
0
class PartitionItem(ElementPresentation, Named):

    DELTA = 30

    def __init__(self, id=None, model=None):
        super().__init__(id, model)
        self._toplevel = False
        self._bottom = False
        self._subpart = False
        self._hdmax = 0  # maximum subpartition header height

        self.shape = Box(
            Text(
                text=lambda: stereotypes_str(
                    self.subject,
                    self.subject and self.subject.isExternal and ("external",) or (),
                ),
            ),
            Text(text=lambda: self.subject.name or ""),
            style={
                "min-width": 0,
                "min-height": 0,
                "line-width": 2.4,
                "vertical-align": VerticalAlign.TOP,
                "padding": (2, 2, 2, 2),
            },
            draw=self.draw_partition,
        )
        self.min_width = 100
        self.min_height = 300

    @property
    def toplevel(self):
        return self._toplevel

    def pre_update(self, context):
        assert self.canvas

        self._header_size = self.shape.size(
            SizeContext.from_context(context, self.style)
        )

        # get subpartitions
        children: List[PartitionItem] = list(
            k for k in self.canvas.get_children(self) if isinstance(k, PartitionItem)
        )

        self._toplevel = self.canvas.get_parent(self) is None
        self._subpart = len(children) > 0
        self._bottom = not self._toplevel and not self._subpart

        if self._toplevel:
            self._header_size = self._header_size[0], self.DELTA

        handles = self.handles()

        # toplevel partition controls the height
        # partitions at the very bottom control the width
        # middle partitions control nothing
        for h in handles:
            h.movable = False
            h.visible = False
        if self._bottom:
            h = handles[1]
            h.visible = h.movable = True
        if self._toplevel:
            h1, h2 = handles[2:4]
            h1.visible = h1.movable = True
            h2.visible = h2.movable = True

        if self._subpart:
            wsum: int = sum(sl.width for sl in children)
            self._hdmax = max(sl._header_size[1] for sl in children)

            # extend width of swimline due the children but keep the height
            # untouched
            self.width = wsum

            dp = 0
            for sl in self.canvas.get_children(self):
                x, y = sl.matrix[4], sl.matrix[5]

                x = dp - x
                y = -y + self._header_size[1] + self._hdmax - sl._header_size[1]
                sl.matrix.translate(x, y)

                sl.height = sl.min_height = max(0, self.height - self._header_size[1])
                dp += sl.width

    def draw_partition(self, box, context, bounding_box):
        """
        By default vertical partition is drawn. It is open on the bottom.
        """
        assert self.canvas

        cr = context.cairo
        cr.set_line_width(context.style["line-width"])

        if self.subject and not self.subject.isDimension and self._toplevel:
            cr.move_to(0, 0)
            cr.line_to(bounding_box.width, 0)

        h = self._header_size[1]

        # draw outside lines if this item is toplevel partition
        if self._toplevel:
            cr.move_to(0, bounding_box.height)
            cr.line_to(0, h)
            cr.line_to(bounding_box.width, h)
            cr.line_to(bounding_box.width, bounding_box.height)

        if self._subpart:
            # header line for all subparitions
            hd = h + self._hdmax
            cr.move_to(0, hd)
            cr.line_to(bounding_box.width, hd)

        if self._subpart:
            # draw inside lines for all children but last one
            dp = 0
            for sl in self.canvas.get_children(self)[:-1]:
                dp += sl.width
                cr.move_to(dp, h)
                cr.line_to(dp, bounding_box.height)

        stroke(context)

        if context.hovered or context.dropzone:
            with cairo_state(cr):
                cr.set_dash((1.0, 5.0), 0)
                cr.set_line_width(1.0)
                cr.rectangle(0, 0, bounding_box.width, bounding_box.height)
                draw_highlight(context)
                cr.stroke()
Пример #30
0
class ExecutionSpecificationItem(Presentation[UML.ExecutionSpecification],
                                 Item):
    """
    Representation of interaction execution specification.
    """
    def __init__(self, id=None, model=None):
        super().__init__(id, model)
        self.bar_width = 12

        ht, hb = Handle(), Handle()
        ht.connectable = True

        # TODO: need better interface for this!
        self._handles.append(ht)
        self._handles.append(hb)

        self.constraint(vertical=(ht.pos, hb.pos))

        r = self.bar_width / 2
        nw = Position((-r, 0), strength=WEAK)
        ne = Position((r, 0), strength=WEAK)
        se = Position((r, 0), strength=WEAK)
        sw = Position((-r, 0), strength=WEAK)

        self.constraint(horizontal=(sw, hb.pos))
        self.constraint(horizontal=(se, hb.pos))

        self._ports.append(LinePort(nw, sw))
        self._ports.append(LinePort(ne, se))

        self.shape = Box(style={"fill": "white"}, draw=draw_border)

    @property
    def top(self):
        return self._handles[0]

    @property
    def bottom(self):
        return self._handles[1]

    def dimensions(self):
        d = self.bar_width
        pt, pb = (h.pos for h in self._handles)
        return Rectangle(pt.x - d / 2, pt.y, d, y1=pb.y)

    def draw(self, context):
        self.shape.draw(context, self.dimensions())

    def point(self, pos):
        return distance_rectangle_point(self.dimensions(), pos)

    def save(self, save_func):
        def save_connection(name, handle):
            assert self.canvas
            c = self.canvas.get_connection(handle)
            if c:
                save_func(name, c.connected, reference=True)

        points = [tuple(map(float, h.pos)) for h in self.handles()]

        save_func("matrix", tuple(self.matrix))
        save_func("points", points)
        save_connection("head-connection", self.handles()[0])
        super().save(save_func)

    def load(self, name, value):
        if name == "matrix":
            self.matrix = ast.literal_eval(value)
        elif name == "points":
            points = ast.literal_eval(value)
            for h, p in zip(self.handles(), points):
                h.pos = p
        elif name == "head-connection":
            self._load_head_connection = value
        else:
            super().load(name, value)

    def postload(self):
        if hasattr(self, "_load_head_connection"):
            postload_connect(self,
                             self.handles()[0], self._load_head_connection)
            del self._load_head_connection

        super().postload()