Exemple #1
0
def test_derivedunion():
    class A(Element):
        a: relation_many[A]
        b: relation_one[A]
        u: relation_many[A]

    A.a = association("a", A)
    A.b = association("b", A, 0, 1)
    A.u = derivedunion("u", object, 0, "*", A.a, A.b)

    a = A()
    assert len(a.a) == 0, f"a.a = {a.a}"
    assert len(a.u) == 0, f"a.u = {a.u}"
    a.a = b = A()
    a.a = c = A()
    assert len(a.a) == 2, f"a.a = {a.a}"
    assert b in a.a
    assert c in a.a
    assert len(a.u) == 2, f"a.u = {a.u}"
    assert b in a.u
    assert c in a.u

    a.b = d = A()
    assert len(a.a) == 2, f"a.a = {a.a}"
    assert b in a.a
    assert c in a.a
    assert d == a.b
    assert len(a.u) == 3, f"a.u = {a.u}"
    assert b in a.u
    assert c in a.u
    assert d in a.u
Exemple #2
0
def test_association_1_x():
    #
    # 1:-
    #
    class A(Element):
        one: relation_one[Optional[B]]

    class B(Element):
        two: relation_one[A]

    A.one = association("one", B, 0, 1, opposite="two")
    B.two = association("two", A, 0, 1)
    a = A()
    b = B()
    a.one = b
    assert a.one is b
    assert b.two is a

    a.one = None
    assert a.one is None
    assert b.two is None

    a.one = b
    assert a.one is b
    assert b.two is a

    del a.one
    assert a.one is None
    assert b.two is None
Exemple #3
0
def test_composite():
    class A(Element):
        is_unlinked = False
        name: str
        comp: relation_many[A]
        other: relation_many[A]

        def unlink(self):
            self.is_unlinked = True
            Element.unlink(self)

    A.comp = association("comp", A, composite=True, opposite="other")
    A.other = association("other", A, composite=False, opposite="comp")

    a = A()
    a.name = "a"
    b = A()
    b.name = "b"
    a.comp = b
    assert b in a.comp
    assert a in b.other

    a.unlink()
    assert a.is_unlinked
    assert b.is_unlinked
Exemple #4
0
def test_association_n_n():
    #
    # n:n
    #
    class A(Element):
        one: relation_many[B]

    class B(Element):
        two: relation_many[A]

    class C(Element):
        pass

    A.one = association("one", B, 0, "*", opposite="two")
    B.two = association("two", A, 0, "*", opposite="one")

    a1 = A()
    a2 = A()
    b1 = B()
    b2 = B()

    a1.one = b1
    assert b1 in a1.one
    assert a1 in b1.two
    assert not a2.one
    assert not b2.two

    a1.one = b2
    assert b1 in a1.one
    assert b2 in a1.one
    assert a1 in b1.two
    assert a1 in b2.two
    assert not a2.one

    a2.one = b1
    assert len(a1.one) == 2
    assert len(a2.one) == 1
    assert len(b1.two) == 2
    assert len(b2.two) == 1
    assert b1 in a1.one
    assert b2 in a1.one
    assert a1 in b1.two
    assert a1 in b2.two
    assert b1 in a2.one
    assert a2 in b1.two

    del a1.one[b1]
    assert len(a1.one) == 1
    assert len(a2.one) == 1
    assert len(b1.two) == 1
    assert len(b2.two) == 1
    assert b1 not in a1.one
    assert b2 in a1.one
    assert a1 not in b1.two
    assert a1 in b2.two
    assert b1 in a2.one
    assert a2 in b1.two
Exemple #5
0
    def test_undo_association_1_n(self):
        from gaphor.core.modeling import Element
        from gaphor.core.modeling.properties import association

        event_manager = EventManager()
        undo_manager = UndoManager(event_manager)
        element_factory = ElementFactory(event_manager)

        class A(Element):
            pass

        class B(Element):
            pass

        A.one = association("one", B, lower=0, upper=1, opposite="two")
        B.two = association("two", A, lower=0, upper="*", opposite="one")

        a1 = element_factory.create(A)
        a2 = element_factory.create(A)
        b1 = element_factory.create(B)
        element_factory.create(B)

        undo_manager.begin_transaction()
        b1.two = a1

        undo_manager.commit_transaction()
        assert a1 in b1.two
        assert b1 is a1.one
        assert len(undo_manager._undo_stack) == 1
        assert len(undo_manager._undo_stack[0]._actions) == 2, undo_manager._undo_stack[
            0
        ]._actions

        undo_manager.undo_transaction()
        assert len(b1.two) == 0
        assert a1.one is None
        assert undo_manager.can_redo()
        assert len(undo_manager._redo_stack) == 1
        assert len(undo_manager._redo_stack[0]._actions) == 2, undo_manager._redo_stack[
            0
        ]._actions

        undo_manager.redo_transaction()
        assert a1 in b1.two
        assert b1 is a1.one

        undo_manager.begin_transaction()
        b1.two = a2

        undo_manager.commit_transaction()
        assert a1 in b1.two
        assert a2 in b1.two
        assert b1 is a1.one
        assert b1 is a2.one

        undo_manager.shutdown()
Exemple #6
0
    def test_uml_associations(self):

        from gaphor.core.modeling.event import AssociationUpdated
        from gaphor.core.modeling.properties import association, derivedunion
        from gaphor.UML import Element

        event_manager = EventManager()
        undo_manager = UndoManager(event_manager)
        element_factory = ElementFactory(event_manager)

        class A(Element):
            is_unlinked = False

            def unlink(self):
                self.is_unlinked = True
                Element.unlink(self)

        A.a1 = association("a1", A, upper=1)
        A.a2 = association("a2", A, upper=1)
        A.b1 = association("b1", A, upper="*")
        A.b2 = association("b2", A, upper="*")
        A.b3 = association("b3", A, upper=1)

        A.derived_a = derivedunion("derived_a", A, 0, 1, A.a1, A.a2)
        A.derived_b = derivedunion("derived_b", A, 0, "*", A.b1, A.b2, A.b3)

        events = []

        @event_handler(AssociationUpdated)
        def handler(event, events=events):
            events.append(event)

        event_manager.subscribe(handler)
        try:
            a = element_factory.create(A)

            undo_manager.begin_transaction()

            a.a1 = element_factory.create(A)
            undo_manager.commit_transaction()

            assert (
                len(events) == 2
            ), events  # both  AssociationSet and DerivedSet events
            assert events[0].property is A.a1
            assert undo_manager.can_undo()

            undo_manager.undo_transaction()
            assert not undo_manager.can_undo()
            assert undo_manager.can_redo()
            assert len(events) == 4, events
            assert events[2].property is A.a1

        finally:
            event_manager.unsubscribe(handler)
            undo_manager.shutdown()
Exemple #7
0
    def test_undo_association_1_x(self):
        from gaphor.core.modeling import Element
        from gaphor.core.modeling.properties import association

        event_manager = EventManager()
        undo_manager = UndoManager(event_manager)
        element_factory = ElementFactory(event_manager)

        class A(Element):
            pass

        class B(Element):
            pass

        A.one = association("one", B, 0, 1, opposite="two")
        B.two = association("two", A, 0, 1)

        a = element_factory.create(A)
        b = element_factory.create(B)

        assert a.one is None
        assert b.two is None

        undo_manager.begin_transaction()
        a.one = b

        undo_manager.commit_transaction()
        assert a.one is b
        assert b.two is a
        assert len(undo_manager._undo_stack) == 1
        assert len(undo_manager._undo_stack[0]._actions) == 2, undo_manager._undo_stack[
            0
        ]._actions

        undo_manager.undo_transaction()
        assert a.one is None
        assert b.two is None
        assert undo_manager.can_redo()
        assert len(undo_manager._redo_stack) == 1
        assert len(undo_manager._redo_stack[0]._actions) == 2, undo_manager._redo_stack[
            0
        ]._actions

        undo_manager.redo_transaction()
        assert len(undo_manager._undo_stack) == 1
        assert len(undo_manager._undo_stack[0]._actions) == 2, undo_manager._undo_stack[
            0
        ]._actions
        assert b.two is a
        assert a.one is b

        undo_manager.shutdown()
Exemple #8
0
def test_undo_association_1_n(event_manager, element_factory, undo_manager):
    class A(Element):
        pass

    class B(Element):
        pass

    A.one = association("one", B, lower=0, upper=1, opposite="two")
    B.two = association("two", A, lower=0, upper="*", opposite="one")

    with Transaction(event_manager):
        a1 = element_factory.create(A)
        a2 = element_factory.create(A)
        b1 = element_factory.create(B)
        element_factory.create(B)

    undo_manager.clear_undo_stack()

    undo_manager.begin_transaction()
    b1.two = a1

    undo_manager.commit_transaction()
    assert a1 in b1.two
    assert b1 is a1.one
    assert len(undo_manager._undo_stack) == 1
    assert len(undo_manager._undo_stack[0]._actions
               ) == 2, undo_manager._undo_stack[0]._actions

    undo_manager.undo_transaction()
    assert len(b1.two) == 0
    assert a1.one is None
    assert undo_manager.can_redo()
    assert len(undo_manager._redo_stack) == 1
    assert len(undo_manager._redo_stack[0]._actions
               ) == 2, undo_manager._redo_stack[0]._actions

    undo_manager.redo_transaction()
    assert a1 in b1.two
    assert b1 is a1.one

    undo_manager.begin_transaction()
    b1.two = a2

    undo_manager.commit_transaction()
    assert a1 in b1.two
    assert a2 in b1.two
    assert b1 is a1.one
    assert b1 is a2.one
Exemple #9
0
def test_set_association_outside_transaction(undo_manager, element_factory,
                                             event_manager):
    class A(Element):
        pass

    A.a = association("a", A, upper=1, opposite="b")
    A.b = association("b", A, opposite="a")

    with Transaction(event_manager):
        a = element_factory.create(A)

    with pytest.raises(NotInTransactionException):
        a.a = a

    assert not a.b
    assert a.a is None
Exemple #10
0
def test_association_swap():
    class A(Element):
        one: relation_many[B]

    class B(Element):
        pass

    class C(Element):
        pass

    A.one = association("one", B, 0, "*")

    a = A()
    b1 = B()
    b2 = B()

    a.one = b1
    a.one = b2
    assert a.one.size() == 2
    assert a.one[0] is b1
    assert a.one[1] is b2

    events: List[object] = []

    @event_handler(AssociationUpdated)
    def handler(event, events=events):
        events.append(event)

    a.one.swap(b1, b2)

    assert a.one.size() == 2
    assert a.one[0] is b2
    assert a.one[1] is b1
Exemple #11
0
def test_association_unlink_1():
    class A(Element):
        one: relation_many[B]

    class B(Element):
        pass

    class C(Element):
        pass

    A.one = association("one", B, 0, "*")

    a1 = A()
    a2 = A()
    b1 = B()
    b2 = B()

    a1.one = b1
    a1.one = b2
    assert b1 in a1.one
    assert b2 in a1.one

    a2.one = b1

    # remove b1 from all elements connected to b1
    # also the signal should be removed
    b1.unlink()

    assert b1 not in a1.one
    assert b2 in a1.one
Exemple #12
0
class Presentation(Element, Generic[S]):
    """
    This presentation is used to link the behaviors of `gaphor.core.modeling` and `gaphas.Item`.
    """
    def __init__(self, id=None, model=None):
        super().__init__(id, model)

        def update(event):
            self.request_update()

        self._watcher = self.watcher(default_handler=update)

        self.watch("subject")

    subject: relation_one[S] = association("subject",
                                           Element,
                                           upper=1,
                                           opposite="presentation")

    handles: Callable[[Presentation], List[Handle]]
    request_update: Callable[[Presentation], None]

    canvas: Optional[Canvas]

    matrix: Matrix

    def watch(self, path, handler=None):
        """
        Watch a certain path of elements starting with the DiagramItem.
        The handler is optional and will default to a simple
        self.request_update().

        Watches should be set in the constructor, so they can be registered
        and unregistered in one shot.

        This interface is fluent(returns self).
        """
        self._watcher.watch(path, handler)
        return self

    def subscribe_all(self):
        """
        Subscribe all watched paths, as defined through `watch()`.
        """
        self._watcher.subscribe_all()

    def unsubscribe_all(self):
        """
        Subscribe all watched paths, as defined through `watch()`.
        """
        self._watcher.unsubscribe_all()

    def unlink(self):
        """
        Remove the item from the canvas and set subject to None.
        """
        if self.canvas:
            self.canvas.remove(self)
        super().unlink()
Exemple #13
0
def test_association_n_x():
    #
    # n:-
    #
    class A(Element):
        one: relation_many[B]

    class B(Element):
        two: relation_one[A]

    A.one = association("one", B, 0, "*", opposite="two")
    B.two = association("two", A, 0, 1)

    a = A()
    b = B()
    a.one = b
    assert b in a.one
    assert b.two is a
Exemple #14
0
def test_undo_association_1_x(event_manager, element_factory, undo_manager):
    class A(Element):
        pass

    class B(Element):
        pass

    A.one = association("one", B, 0, 1, opposite="two")
    B.two = association("two", A, 0, 1)

    with Transaction(event_manager):
        a = element_factory.create(A)
        b = element_factory.create(B)
    undo_manager.clear_undo_stack()

    assert a.one is None
    assert b.two is None

    undo_manager.begin_transaction()
    a.one = b

    undo_manager.commit_transaction()
    assert a.one is b
    assert b.two is a
    assert len(undo_manager._undo_stack) == 1
    assert len(undo_manager._undo_stack[0]._actions
               ) == 2, undo_manager._undo_stack[0]._actions

    undo_manager.undo_transaction()
    assert a.one is None
    assert b.two is None
    assert undo_manager.can_redo()
    assert len(undo_manager._redo_stack) == 1
    assert len(undo_manager._redo_stack[0]._actions
               ) == 2, undo_manager._redo_stack[0]._actions

    undo_manager.redo_transaction()
    assert len(undo_manager._undo_stack) == 1
    assert len(undo_manager._undo_stack[0]._actions
               ) == 2, undo_manager._undo_stack[0]._actions
    assert b.two is a
    assert a.one is b
Exemple #15
0
def test_uml_associations(event_manager, element_factory, undo_manager):
    class A(Element):
        is_unlinked = False

        def unlink(self):
            self.is_unlinked = True
            Element.unlink(self)

    A.a1 = association("a1", A, upper=1)
    A.a2 = association("a2", A, upper=1)
    A.b1 = association("b1", A, upper="*")
    A.b2 = association("b2", A, upper="*")
    A.b3 = association("b3", A, upper=1)

    A.derived_a = derivedunion("derived_a", A, 0, 1, A.a1, A.a2)
    A.derived_b = derivedunion("derived_b", A, 0, "*", A.b1, A.b2, A.b3)

    events = []

    @event_handler(AssociationUpdated)
    def handler(event, events=events):
        events.append(event)

    event_manager.subscribe(handler)

    undo_manager.begin_transaction()

    a = element_factory.create(A)
    a.a1 = element_factory.create(A)
    undo_manager.commit_transaction()

    assert len(
        events) == 2, events  # both  AssociationSet and DerivedSet events
    assert events[0].property is A.a1
    assert undo_manager.can_undo()

    undo_manager.undo_transaction()
    assert not undo_manager.can_undo()
    assert undo_manager.can_redo()
    assert len(events) == 4, events
    assert events[2].property is A.a1
Exemple #16
0
def test_association_1_1():
    #
    # 1:1
    #
    class A(Element):
        one: relation_one[B]

    class B(Element):
        two: relation_one[A]

    class C(Element):
        pass

    A.one = association("one", B, 0, 1, opposite="two")
    B.two = association("two", A, 0, 1, opposite="one")

    a = A()
    b = B()
    a.one = b
    a.one = b

    assert a.one is b
    assert b.two is a

    a.one = B()
    assert a.one is not b
    assert b.two is None

    c = C()
    try:
        a.one = c
    except Exception:
        pass
    else:
        assert a.one is not c

    del a.one
    assert a.one is None
    assert b.two is None
Exemple #17
0
def test_derivedunion_listmixins():
    class A(Element):
        a: relation_many[A]
        b: relation_many[A]
        u: relation_many[A]
        name: attribute[str]

    A.a = association("a", A)
    A.b = association("b", A)
    A.u = derivedunion("u", A, 0, "*", A.a, A.b)
    A.name = attribute("name", str, "default")

    a = A()
    a.a = A()
    a.a = A()
    a.b = A()
    a.a[0].name = "foo"
    a.a[1].name = "bar"
    a.b[0].name = "baz"

    assert list(a.a[:].name) == ["foo", "bar"]
    assert sorted(list(a.u[:].name)) == ["bar", "baz", "foo"]
Exemple #18
0
def test_association_unlink_2():
    #
    # unlink
    #
    class A(Element):
        one: relation_many[B]

    class B(Element):
        two: relation_many[A]

    class C(Element):
        pass

    A.one = association("one", B, 0, "*", opposite="two")
    B.two = association("two", A, 0, "*")

    a1 = A()
    a2 = A()
    b1 = B()
    b2 = B()

    a1.one = b1
    a1.one = b2
    assert b1 in a1.one
    assert b2 in a1.one
    assert a1 in b1.two
    assert a1 in b2.two

    a2.one = b1

    # remove b1 from all elements connected to b1
    # also the signal should be removed
    b1.unlink()

    assert b1 not in a1.one
    assert b2 in a1.one
    assert a1 not in b1.two
    assert a1 in b2.two
Exemple #19
0
def test_derivedunion_notify_for_multiple_derived_properties():
    class A(Element):
        pass

    class E(Element):
        notified = False

        a: relation_many[A]
        aa: relation_many[A]
        u: relation_many[A]

        def handle(self, event):
            if event.property is E.u:
                self.notified = True

    E.a = association("a", A)
    E.aa = association("aa", A)
    E.u = derivedunion("u", A, 0, "*", E.a, E.aa)

    e = E()
    e.a = A()

    assert e.notified is True
Exemple #20
0
def test_set_derived_union_outside_transaction(undo_manager, element_factory,
                                               event_manager):
    class A(Element):
        pass

    A.a = association("a", A, upper=1, opposite="b")
    A.b = association("b", A, opposite="a")
    A.derived_a = derivedunion("derived_a", A, 0, 1, A.a)
    A.derived_b = derivedunion("derived_b", A, 0, "*", A.b)

    with Transaction(event_manager):
        a = element_factory.create(A)

    with pytest.raises(NotInTransactionException):
        a.a = a

    with pytest.raises(NotInTransactionException):
        a.b = a

    assert not a.b
    assert not a.a
    assert not a.derived_a
    assert not a.derived_b
Exemple #21
0
def test_association_swap():
    class A(Element):
        one: relation_many[B]

    class B(Element):
        pass

    class C(Element):
        pass

    A.one = association("one", B, 0, "*")

    a = A()
    b1 = B()
    b2 = B()

    a.one = b1
    a.one = b2
    assert a.one.size() == 2
    assert a.one[0] is b1
    assert a.one[1] is b2

    events: List[object] = []

    @event_handler(AssociationUpdated)
    def handler(event, events=events):
        events.append(event)

    #        Application.register_handler(handler)
    #        try:
    a.one.swap(b1, b2)
    #            assert len(events) == 1
    #            assert events[0].property is A.one
    #            assert events[0].element is a
    #        finally:
    #            Application.unregister_handler(handler)

    assert a.one.size() == 2
    assert a.one[0] is b2
    assert a.one[1] is b1
Exemple #22
0
class DecisionNodeItem(ElementPresentation, ActivityNodeItem):
    """Representation of decision or merge node."""

    def __init__(self, diagram, id=None):
        super().__init__(diagram, id, width=20, height=30)
        no_movable_handles(self)

        self.shape = IconBox(
            Box(draw=draw_decision_node),
            # Text should be left-top
            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")

    combined: relation_one[UML.ControlNode] = association(
        "combined", UML.ControlNode, upper=1
    )
Exemple #23
0
class Diagram(PackageableElement):
    """Diagrams may contain model elements and can be owned by a Package."""

    package: relation_one[Package]

    def __init__(
        self, id: Optional[Id] = None, model: Optional[RepositoryProtocol] = None
    ):
        """Initialize the diagram with an optional id and element model.

        The diagram also has a canvas.
        """

        super().__init__(id, model)
        self._connections = gaphas.connections.Connections()
        self._connections.add_handler(self._on_constraint_solved)

        self._registered_views: Set[gaphas.view.model.View] = set()

        self._watcher = self.watcher()
        self._watcher.watch("ownedPresentation", self._presentation_removed)

        # Record all items changed during constraint solving,
        # so their `post_update()` method can be called.
        self._resolved_items: Set[gaphas.item.Item] = set()

    ownedPresentation: relation_many[Presentation] = association(
        "ownedPresentation", Presentation, composite=True, opposite="diagram"
    )

    def _presentation_removed(self, event):
        if isinstance(event, AssociationDeleted) and event.old_value:
            self._update_views(removed_items=(event.old_value,))

    @property
    def styleSheet(self) -> Optional[StyleSheet]:
        return next(self.model.select(StyleSheet), None)

    def style(self, node: StyleNode) -> Style:
        style_sheet = self.styleSheet
        return {
            **FALLBACK_STYLE,  # type: ignore[misc]
            **(style_sheet.match(node) if style_sheet else {}),
        }

    def save(self, save_func):
        """Apply the supplied save function to this diagram and the canvas."""

        super().save(save_func)
        save_func("canvas", PseudoCanvas(self))

    def postload(self):
        """Handle post-load functionality for the diagram."""
        super().postload()

    def create(self, type, parent=None, subject=None):
        """Create a new diagram item on the diagram.

        It is created with a unique ID and it is attached to the
        diagram's root item.  The type parameter is the element class to
        create.  The new element also has an optional parent and
        subject.
        """

        return self.create_as(type, str(uuid.uuid1()), parent, subject)

    def create_as(self, type, id, parent=None, subject=None):
        if not (type and issubclass(type, Presentation)):
            raise TypeError(
                f"Type {type} can not be added to a diagram as it is not a diagram item"
            )
        # Avoid events that reference this element before its created-event is emitted.
        with self.model.block_events():
            item = type(diagram=self, id=id)
        assert isinstance(
            item, gaphas.Item
        ), f"Type {type} does not comply with Item protocol"
        self.model.handle(DiagramItemCreated(self, item))
        if subject:
            item.subject = subject
        if parent:
            item.parent = parent
        self.request_update(item)
        return item

    def lookup(self, id):
        for item in self.get_all_items():
            if item.id == id:
                return item

    def unlink(self):
        """Unlink all canvas items then unlink this diagram."""
        for item in self.ownedPresentation:
            self.connections.remove_connections_to_item(item)
        self._watcher.unsubscribe_all()
        super().unlink()

    def select(self, expression=None) -> Iterator[Presentation]:
        """Return a iterator of all canvas items that match expression."""
        if expression is None:
            yield from self.get_all_items()
        elif isinstance(expression, type):
            yield from (e for e in self.get_all_items() if isinstance(e, expression))
        else:
            yield from (e for e in self.get_all_items() if expression(e))

    @property
    def connections(self) -> gaphas.connections.Connections:
        return self._connections

    def get_all_items(self) -> Iterable[Presentation]:
        """Get all items owned by this diagram, ordered depth-first."""

        def iter_children(item):
            for child in item.children:
                yield child
                yield from iter_children(child)

        for root in self.ownedPresentation:
            if not root.parent:
                yield root
                yield from iter_children(root)

    def get_parent(self, item: Presentation) -> Optional[Presentation]:
        return item.parent

    def get_children(self, item: Presentation) -> Iterable[Presentation]:
        return iter(item.children)

    def sort(self, items: Sequence[Presentation]) -> Iterable[Presentation]:
        items_set = set(items)
        return (n for n in self.get_all_items() if n in items_set)

    def request_update(
        self, item: gaphas.item.Item, update: bool = True, matrix: bool = True
    ) -> None:
        if update and matrix:
            self._update_views(dirty_items=(item,), dirty_matrix_items=(item,))
        elif update:
            self._update_views(dirty_items=(item,))
        elif matrix:
            self._update_views(dirty_matrix_items=(item,))

    def _update_views(self, dirty_items=(), dirty_matrix_items=(), removed_items=()):
        """Send an update notification to all registered views."""
        for v in self._registered_views:
            v.request_update(dirty_items, dirty_matrix_items, removed_items)

    @gaphas.decorators.nonrecursive
    def update_now(
        self,
        dirty_items: Sequence[Presentation],
        dirty_matrix_items: Sequence[Presentation] = (),
    ) -> None:
        """Update the diagram canvas."""

        sort = self.sort

        def dirty_items_with_ancestors():
            for item in set(dirty_items):
                yield item
                yield from gaphas.canvas.ancestors(self, item)

        all_dirty_items = list(reversed(list(sort(dirty_items_with_ancestors()))))
        contexts = self._pre_update_items(all_dirty_items)

        self._resolved_items.clear()

        self._connections.solve()

        all_dirty_items.extend(self._resolved_items)
        self._post_update_items(reversed(list(sort(all_dirty_items))), contexts)

    def _pre_update_items(self, items):
        contexts = {}
        for item in items:
            context = UpdateContext(style=self.style(StyledItem(item)))
            item.pre_update(context)
            contexts[item] = context
        return contexts

    def _post_update_items(self, items, contexts):
        for item in items:
            context = contexts.get(item)
            if not context:
                context = UpdateContext(style=self.style(StyledItem(item)))
            item.post_update(context)

    def _on_constraint_solved(self, cinfo: gaphas.connections.Connection) -> None:
        dirty_items = set()
        if cinfo.item:
            dirty_items.add(cinfo.item)
            self._resolved_items.add(cinfo.item)
        if cinfo.connected:
            dirty_items.add(cinfo.connected)
            self._resolved_items.add(cinfo.connected)
        if dirty_items:
            self._update_views(dirty_items)

    def register_view(self, view: gaphas.view.model.View[Presentation]) -> None:
        self._registered_views.add(view)

    def unregister_view(self, view: gaphas.view.model.View[Presentation]) -> None:
        self._registered_views.discard(view)
Exemple #24
0
        return contexts

    def _post_update_items(self, items, contexts):
        for item in items:
            context = contexts.get(item)
            if not context:
                context = UpdateContext(style=self.style(StyledItem(item)))
            item.post_update(context)

    def _on_constraint_solved(self, cinfo: gaphas.connections.Connection) -> None:
        dirty_items = set()
        if cinfo.item:
            dirty_items.add(cinfo.item)
            self._resolved_items.add(cinfo.item)
        if cinfo.connected:
            dirty_items.add(cinfo.connected)
            self._resolved_items.add(cinfo.connected)
        if dirty_items:
            self._update_views(dirty_items)

    def register_view(self, view: gaphas.view.model.View[Presentation]) -> None:
        self._registered_views.add(view)

    def unregister_view(self, view: gaphas.view.model.View[Presentation]) -> None:
        self._registered_views.discard(view)


Presentation.diagram = association(
    "diagram", Diagram, upper=1, opposite="ownedPresentation"
)
Exemple #25
0
    type: attribute[str]


class C4Database(C4Container):
    pass


class C4Person(Actor):
    description: attribute[str]
    location: attribute[str]


C4Container.description = attribute("description", str)
C4Container.location = attribute("location", str)
C4Container.ownerContainer = association("ownerContainer",
                                         C4Container,
                                         upper=1,
                                         opposite="owningContainer")
C4Container.owningContainer = association("owningContainer",
                                          C4Container,
                                          composite=True,
                                          opposite="ownerContainer")
C4Container.technology = attribute("technology", str)
C4Container.type = attribute("type", str)
C4Person.description = attribute("description", str)
C4Person.location = attribute("location", str)
C4Container.namespace.subsets.add(
    C4Container.ownerContainer)  # type: ignore[attr-defined]
C4Container.ownedMember.subsets.add(
    C4Container.owningContainer)  # type: ignore[attr-defined]
Exemple #26
0
class PartitionItem(ElementPresentation):
    def __init__(self, diagram, id=None):
        super().__init__(diagram, id)
        self.min_height = 300

        self.shape = Box(
            style={
                "line-width": 2.4,
                "padding": (2, 2, 2, 2),
                "vertical-align": VerticalAlign.TOP,
            },
            draw=self.draw_swimlanes,
        )
        self.watch("subject[NamedElement].name")
        self.watch("subject.appliedStereotype.classifier.name")
        self.watch("partition.name")
        self.watch("partition")

    partition = association("partition", UML.ActivityPartition, composite=True)

    def postload(self):
        super().postload()
        if self.subject and self.subject not in self.partition:
            self.partition = self.subject

    def pre_update(self, context: DrawContext) -> None:
        """Set the min width of all the swimlanes."""
        self.min_width = 150 * len(self.partition)

    def draw_swimlanes(self, box: Box, context: DrawContext,
                       bounding_box: Rectangle) -> None:
        """Draw the vertical partitions as connected swimlanes.

        The partitions are open on the bottom. We divide the total size
        by the total number of partitions and space them evenly.
        """
        cr = context.cairo
        cr.set_line_width(context.style["line-width"])
        self.draw_outline(bounding_box, context)
        self.draw_partitions(bounding_box, context)
        stroke(context)
        self.draw_hover(bounding_box, context)

    def draw_hover(self, bounding_box: Rectangle,
                   context: DrawContext) -> None:
        """Add dashed line on bottom of swimlanes when hovered."""
        if context.hovered or context.dropzone:
            cr = context.cairo
            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)
                cr.stroke()

    def draw_partitions(self, bounding_box: Rectangle,
                        context: DrawContext) -> None:
        """Draw partition separators and add the name."""
        cr = context.cairo
        if self.partition:
            partition_width = bounding_box.width / len(self.partition)
        else:
            partition_width = bounding_box.width / 2
        layout = Layout()
        style = context.style
        padding_top = context.style["padding"][0]
        for num, partition in enumerate(self.partition):
            cr.move_to(partition_width * num, 0)
            cr.line_to(partition_width * num, bounding_box.height)
            layout.set(text=partition.name, font=style)
            cr.move_to(partition_width * num, padding_top * 3)
            layout.show_layout(
                cr,
                partition_width,
                default_size=(partition_width, HEADER_HEIGHT),
            )

    def draw_outline(self, bounding_box: Rectangle,
                     context: DrawContext) -> None:
        """Draw the outline and header of the swimlanes."""
        cr = context.cairo
        cr.move_to(0, bounding_box.height)
        cr.line_to(0, 0)
        cr.line_to(bounding_box.width, 0)
        cr.line_to(bounding_box.width, bounding_box.height)
        cr.move_to(0, bounding_box.height)
        cr.line_to(0, HEADER_HEIGHT)
        cr.line_to(0 + bounding_box.width, HEADER_HEIGHT)
        cr.line_to(0 + bounding_box.width, bounding_box.height)
Exemple #27
0
class Viewpoint(Class):
    concernList: relation_many[Comment]
    language: attribute[str]
    presentation: attribute[str]
    purpose: attribute[str]
    stakeholder: relation_many[Stakeholder]


class _Refine:
    pass


AbstractRequirement.externalId = attribute("externalId", str)
AbstractRequirement.text = attribute("text", str)
AdjuntProperty.principal = association("principal", Element, upper=1)
Block.isEncapsulated = attribute("isEncapsulated", int)
BoundReference.boundend = association("boundend", ConnectorEnd, upper=1)
ChangeSructuralFeatureEvent.structuralFeature = association(
    "structuralFeature", StructuralFeature, upper=1
)
ConnectorProperty.connector = association("connector", Connector, upper=1)
DirectedFeature.featureDirection = enumeration(
    "kind", ("required", "providedRequired", "provided"), "required"
)
DirectedRelationshipPropertyPath.sourceContext = association(
    "sourceContext", Classifier, upper=1
)
DirectedRelationshipPropertyPath.sourcePropertyPath = association(
    "sourcePropertyPath", Property
)
Exemple #28
0
# 40: override StyleSheet
# defined in gaphor.core.modeling.presentation

NamedElement.name = attribute("name", str)
Comment.body = attribute("body", str)
# 43: override StyleSheet.styleSheet
# defined in gaphor.core.modeling.presentation

# 52: override Presentation.subject
# defined in gaphor.core.modeling.presentation

# 49: override Element.presentation
# defined in gaphor.core.modeling.presentation

Comment.annotatedElement = association("annotatedElement",
                                       Element,
                                       opposite="ownedComment")
Element.ownedComment = association("ownedComment",
                                   Comment,
                                   opposite="annotatedElement")
# 20: override NamedElement.qualifiedName(NamedElement.namespace): derived[List[str]]


def _namedelement_qualifiedname(self) -> List[str]:
    """
    Returns the qualified name of the element as a tuple
    """
    if self.namespace:
        return _namedelement_qualifiedname(self.namespace) + [self.name]
    else:
        return [self.name]
Exemple #29
0
# 43: override StyleSheet
# defined in gaphor.core.modeling.presentation


NamedElement.name = attribute("name", str)
Comment.body = attribute("body", str)
# 46: override StyleSheet.styleSheet
# defined in gaphor.core.modeling.presentation

# 58: override Presentation.subject
# defined in gaphor.core.modeling.presentation

# 52: override Element.presentation
# defined in gaphor.core.modeling.presentation

Comment.annotatedElement = association("annotatedElement", Element, opposite="comment")
Element.comment = association("comment", Comment, opposite="annotatedElement")
# 70: override Diagram.ownedPresentation
# defined in gaphor.core.modeling.presentation

# 55: override Presentation.diagram
# defined in gaphor.core.modeling.presentation

# 61: override Presentation.parent
# defined in gaphor.core.modeling.presentation

# 64: override Presentation.children
# defined in gaphor.core.modeling.presentation

# 22: override NamedElement.qualifiedName(NamedElement.namespace): derived[List[str]]
Exemple #30
0
def test_association_1_n():
    #
    # 1:n
    #
    class A(Element):
        one: relation_one[B]

    class B(Element):
        two: relation_many[A]

    class C(Element):
        pass

    A.one = association("one", B, lower=0, upper=1, opposite="two")
    B.two = association("two", A, lower=0, upper="*", opposite="one")

    a1 = A()
    a2 = A()
    b1 = B()
    b2 = B()

    b1.two = a1
    assert len(b1.two) == 1, "len(b1.two) == %d" % len(b1.two)
    assert a1 in b1.two
    assert a1.one is b1, f"{a1.one}/{b1}"
    b1.two = a1
    b1.two = a1
    assert len(b1.two) == 1, "len(b1.two) == %d" % len(b1.two)
    assert a1 in b1.two
    assert a1.one is b1, f"{a1.one}/{b1}"

    b1.two = a2
    assert a1 in b1.two
    assert a2 in b1.two
    assert a1.one is b1
    assert a2.one is b1

    try:
        del b1.two
    except Exception:
        pass  # ok
    else:
        assert b1.two != []

    assert a1 in b1.two
    assert a2 in b1.two
    assert a1.one is b1
    assert a2.one is b1

    b1.two.remove(a1)

    assert len(b1.two) == 1
    assert a1 not in b1.two
    assert a2 in b1.two
    assert a1.one is None
    assert a2.one is b1

    a2.one = b2

    assert len(b1.two) == 0
    assert len(b2.two) == 1
    assert a2 in b2.two
    assert a1.one is None
    assert a2.one is b2

    del b1.two[a1]