<commit_before>"""
Association item - graphical representation of an association.

Plan:
 - transform AssociationEnd in a (dumb) data class
 - for assocation name and direction tag, use the same trick as is used
   for line ends.
"""

# TODO: for Association.postload(): in some cases where the association ends
#   are connected to the same Class, the head_end property is connected to the
#   tail end and visa versa.

from gaphas.geometry import Rectangle, distance_point_point_fast
from gaphas.geometry import distance_rectangle_point
from gaphas.state import reversible_property

from gaphor import UML
from gaphor.diagram.diagramline import NamedLine
from gaphor.diagram.textelement import text_extents, text_multiline


class AssociationItem(NamedLine):
    """
    AssociationItem represents associations. 
    An AssociationItem has two AssociationEnd items. Each AssociationEnd item
    represents a Property (with Property.association == my association).
    """

    __uml__ = UML.Association

    def __init__(self, id=None):
        NamedLine.__init__(self, id)

        # 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.watch('subject<Association>.ownedEnd')\
        # .watch('subject<Association>.memberEnd')

        # For the association ends:
        base = "subject<Association>.memberEnd<Property>."
        self.watch(base + "name", self.on_association_end_value).watch(
            base + "aggregation", self.on_association_end_value
        ).watch(base + "classifier", self.on_association_end_value).watch(
            base + "visibility", self.on_association_end_value
        ).watch(
            base + "lowerValue", self.on_association_end_value
        ).watch(
            base + "upperValue", self.on_association_end_value
        ).watch(
            base + "owningAssociation", self.on_association_end_value
        ).watch(
            base + "type<Class>.ownedAttribute", self.on_association_end_value
        ).watch(
            base + "type<Interface>.ownedAttribute", self.on_association_end_value
        ).watch(
            "subject<Association>.ownedEnd"
        ).watch(
            "subject<Association>.navigableOwnedEnd"
        )

    def set_show_direction(self, dir):
        self._show_direction = dir
        self.request_update()

    show_direction = reversible_property(
        lambda s: s._show_direction, set_show_direction<commit_msg>Association end now also updates when stereotype info changes<commit_after>"""
Association item - graphical representation of an association.

Plan:
 - transform AssociationEnd in a (dumb) data class
 - for assocation name and direction tag, use the same trick as is used
   for line ends.
"""

# TODO: for Association.postload(): in some cases where the association ends
#   are connected to the same Class, the head_end property is connected to the
#   tail end and visa versa.

from gaphas.geometry import Rectangle, distance_point_point_fast
from gaphas.geometry import distance_rectangle_point
from gaphas.state import reversible_property

from gaphor import UML
from gaphor.diagram.diagramline import NamedLine
from gaphor.diagram.textelement import text_extents, text_multiline


class AssociationItem(NamedLine):
    """
    AssociationItem represents associations.
    An AssociationItem has two AssociationEnd items. Each AssociationEnd item
    represents a Property (with Property.association == my association).
    """

    __uml__ = UML.Association

    def __init__(self, id=None):
        NamedLine.__init__(self, id)

        # 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.watch('subject<Association>.ownedEnd')\
        # .watch('subject<Association>.memberEnd')

        # For the association ends:
        base = "subject<Association>.memberEnd<Property>."
        self.watch(base + "name", self.on_association_end_value).watch(
            base + "aggregation", self.on_association_end_value
        ).watch(base + "classifier", self.on_association_end_value).watch(
            base + "visibility", self.on_association_end_value
        ).watch(
            base + "lowerValue", self.on_association_end_value
        ).watch(
            base + "upperValue", self.on_association_end_value
        ).watch(
            base + "owningAssociation", self.on_association_end_value
        ).watch(
            base + "type<Class>.ownedAttribute", self.on_association_end_value
        ).watch(
            base + "type<Interface>.ownedAttribute", self.on_association_end_value
        ).watch(
            base + "appliedStereotype", self.on_association_end_value
        ).watch(
            base + "appliedStereotype.slot", self.on_association_end_value
        ).watch(
            base + "appliedStereotype.slot.definingFeature.name",
            self.on_association_end_value,
        ).watch(
            base + "appliedStereotype.slot.value", self.on_association_end_value
        ).watch(
            "subject<Association>.ownedEnd"
        ).watch(
            "subject<Association>.navigableOwnedEnd"
        )

    def set_show_direction(self, dir):
        self._show_direction = dir
        self.request_update()

    show_direction = reversible_property(
        lambda s: s._show_direction, set_show_direction
{'fraction_non_alphanumeric': 0.08419129857190302, 'fraction_numerical': 0.0009963467286615742, 'mean_word_length': 3.020694259012016, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3731018', 'n_tokens_mistral': 1679, 'n_tokens_neox': 1612, 'n_words': 443}