root/gaphor/trunk/gaphor/diagram/lifeline.py

Revision 1989, 5.3 kB (checked in by wrobe..@pld-linux.org, 1 year ago)

- code cleanup

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 """
2 Lifeline diagram item.
3
4 Implementation Details
5 ======================
6
7 Represented Classifier
8 ----------------------
9 It is not clear how to attach a connectable element to a lifeline. For now,
10 ``Lifeline.represents`` is ``None``. Ideas:
11 - drag and drop classifier from tree onto a lifeline
12 - match lifeline's name with classifier's name (what about namespace?)
13 - connect message to classifier, then classifier becomes a lifeline
14
15 Destruction Event
16 -----------------
17 Occurence specification is not implemented, therefore destruction event
18 cannot be supported. Still, destruction event notation is shown at the
19 bottom of the lifeline's lifetime when delete message is connected to a
20 lifeline.
21 """
22
23 import gaphas
24 from gaphas.item import SW, SE
25 from gaphas.solver import STRONG
26 from gaphas.geometry import distance_line_point, Rectangle
27 from gaphas.constraint import LessThanConstraint, EqualsConstraint, CenterConstraint
28
29 from gaphor import UML
30 from gaphor.diagram.nameditem import NamedItem
31 from gaphor.diagram.style import ALIGN_CENTER, ALIGN_MIDDLE
32
33 class LifetimeItem(object):
34     """
35     Attributes:
36
37     - is_visible: check if lifeline's lifetime is visible
38     - is_destroyed: check if delete message is connected
39     - _messages_count: amount of messages conntected to a lifeline
40     - _c_length: lifeline's lifetime length constraint
41     """
42
43     MIN_LENGTH = 10
44
45     def __init__(self):
46         super(LifetimeItem, self).__init__()
47         self._handles = [gaphas.Handle(strength=STRONG - 1), gaphas.Handle(strength=STRONG)]
48
49         self._handles[0].movable = False
50         self._handles[0].visible = False
51         self._messages_count = 0
52         self._is_destroyed = False
53
54         # create constraint to keep bottom handle below top handle
55         top, bottom = self._handles
56         self._c_length = LessThanConstraint(smaller=top.y,
57                 bigger=bottom.y,
58                 delta=LifetimeItem.MIN_LENGTH)
59
60
61     top = property(lambda s: s._handles[0])
62
63     bottom = property(lambda s: s._handles[1])
64
65     length = property(lambda s: s._handles[1].y - s._handles[0].y)
66
67     def _set_destroyed(self, is_destroyed):
68         self._is_destroyed = is_destroyed
69
70     is_destroyed = property(lambda s: s._is_destroyed, _set_destroyed)
71
72
73     def _is_visible(self):
74         return self.length > self.MIN_LENGTH
75
76     is_visible = property(_is_visible)
77
78
79     def pre_update(self, context):
80         # if lifetime is visible and there are messages connected, then
81         # disallow hiding of lifetime
82         if not self.is_visible and self._messages_count > 0:
83             self._c_length.delta = LifetimeItem.MIN_LENGTH * 3
84         elif self._messages_count == 0:
85             self._c_length.delta = LifetimeItem.MIN_LENGTH
86
87         if not self.bottom.movable:
88             self.bottom.y = self.top.y + LifetimeItem.MIN_LENGTH
89             self._c_length.delta = LifetimeItem.MIN_LENGTH
90
91            
92     def draw(self, context):
93         if context.hovered or context.focused or self.is_visible:
94             cr = context.cairo
95             cr.save()
96             cr.set_dash((7.0, 5.0), 0)
97             th, bh = self._handles
98             cr.move_to(th.x, th.y)
99             cr.line_to(bh.x, bh.y)
100             cr.stroke()
101             cr.restore()
102
103             # draw destruction event
104             if self._is_destroyed:
105                 d1 = 8
106                 d2 = d1 * 2
107                 cr.move_to(bh.x - d1, bh.y - d2)
108                 cr.line_to(bh.x + d1, bh.y)
109                 cr.move_to(bh.x - d1, bh.y)
110                 cr.line_to(bh.x + d1, bh.y - d2)
111                 cr.stroke()
112
113     def handles(self):
114         return self._handles
115
116
117 class LifelineItem(NamedItem):
118
119     __uml__      = UML.Lifeline
120     __style__ = {
121         'name-align': (ALIGN_CENTER, ALIGN_MIDDLE),
122     }
123
124     def __init__(self, id = None):
125         NamedItem.__init__(self, id)
126
127         self._lifetime = LifetimeItem()
128         top, bottom = self._lifetime.handles()
129         self._handles.append(top)
130         self._handles.append(bottom)
131
132         constraints = [
133             # Apply constraint to bottom, since bottom can be moved (top can't)
134             CenterConstraint(self._handles[SW].x, self._handles[SE].x, bottom.x),
135             EqualsConstraint(top.x, bottom.x),
136             EqualsConstraint(self._handles[SW].y, top.y),
137             self._lifetime._c_length,
138         ]
139         self._constraints.extend(constraints)
140
141
142     lifetime = property(lambda s: s._lifetime)
143
144
145     def save(self, save_func):
146         super(LifelineItem, self).save(save_func)
147         save_func("lifetime-length", self._lifetime.length)
148
149
150     def load(self, name, value):
151         if name == 'lifetime-length':
152             top, bottom = self._lifetime.handles()
153             bottom.y = self.height + float(value)
154         else:
155             super(LifelineItem, self).load(name, value)
156
157
158     def pre_update(self, context):
159         super(LifelineItem, self).pre_update(context)
160         self._lifetime.pre_update(context)
161
162
163     def draw(self, context):
164         super(LifelineItem, self).draw(context)
165         cr = context.cairo
166         cr.rectangle(0, 0, self.width, self.height)
167         cr.stroke()
168         self._lifetime.draw(context)
169
170
171     def point(self, x, y):
172         d1 = super(LifelineItem, self).point(x, y)
173         h1, h2 = self._lifetime.handles()
174         d2 = distance_line_point(h1.pos, h2.pos, (x, y))[0]
175         return min(d1, d2)
176
177
178 # vim:sw=4:et
Note: See TracBrowser for help on using the browser.