root/gaphor/trunk/gaphor/diagram/classes/interface.py

Revision 2255, 5.9 kB (checked in by arj..@yirdis.nl, 9 months ago)

moved classes items to seperate package. More unit tests for interface item.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 """
2 Interface item.
3 """
4
5 import itertools
6 from math import pi
7 from gaphas.item import NW, SE, NE, SW
8 from gaphas.state import observed, reversible_property
9
10 from gaphor import UML
11 from dependency import DependencyItem
12 from implementation import ImplementationItem
13 from klass import ClassItem
14 from gaphor.diagram.nameditem import NamedItem
15 from gaphor.diagram.style import ALIGN_TOP, ALIGN_BOTTOM, ALIGN_CENTER
16
17
18 class InterfaceItem(ClassItem):
19     """
20     This item represents an interface drawn as a dot. The class-like
21     representation is provided by ClassItem. These representations can be
22     switched by using the Fold and Unfold actions.
23
24     TODO (see also DependencyItem): when a Usage dependency is connected to
25           the interface, draw a line, but not all the way to the connecting
26           handle. Stop drawing the line 'x' points earlier.
27     """
28
29     __uml__        = UML.Interface
30     __stereotype__ = {'interface': lambda self: self.drawing_style != self.DRAW_ICON}
31     __style__ = {
32         'icon-size': (20, 20),
33         'icon-size-provided': (20, 20),
34         'icon-size-required': (28, 28),
35         'name-outside': False,
36     }
37
38     UNFOLDED_STYLE = {
39         'text-align': (ALIGN_CENTER, ALIGN_TOP),
40         'text-outside': False,
41     }
42
43     FOLDED_STYLE = {
44         'text-align': (ALIGN_CENTER, ALIGN_BOTTOM),
45         'text-outside': True,
46     }
47
48     RADIUS_PROVIDED = 10
49     RADIUS_REQUIRED = 14
50
51     def __init__(self, id=None):
52         ClassItem.__init__(self, id)
53         self._draw_required = False
54         self._draw_provided = False
55
56         self.add_watch(UML.Interface.ownedAttribute, self.on_class_owned_attribute)
57         self.add_watch(UML.Interface.ownedOperation, self.on_class_owned_operation)
58         self.add_watch(UML.Implementation.contract, self.on_implementation_contract)
59         #self.add_watch(UML.Interface.implementation)
60         self.add_watch(UML.Interface.supplierDependency)
61
62
63     @observed
64     def set_drawing_style(self, style):
65         """
66         In addition to setting the drawing style, the handles are
67         make non-movable if the icon (folded) style is used.
68         """
69         ClassItem.set_drawing_style(self, style)
70         # TODO: adjust offsets so the center point is the same
71         if self._drawing_style == self.DRAW_ICON:
72             self._name.style.update(self.FOLDED_STYLE)
73             for h in self._handles: h.movable = False
74             self.request_update()
75         else:
76             self._name.style.update(self.UNFOLDED_STYLE)
77             for h in self._handles: h.movable = True
78             self.request_update()
79
80     drawing_style = reversible_property(lambda self: self._drawing_style, set_drawing_style)
81
82     def is_folded(self):
83         """
84         Returns True if the interface is drawn as a circle/dot.
85         Unfolded means it's drawn like a classifier.
86         """
87         return self.drawing_style == self.DRAW_ICON
88
89     def _set_folded(self, folded):
90         if folded:
91             self.drawing_style = self.DRAW_ICON
92         else:
93             self.drawing_style = self.DRAW_COMPARTMENT
94
95     folded = property(is_folded, _set_folded)
96
97     def on_implementation_contract(self, event):
98         #print 'on_implementation_contract', event, event.element
99         if event is None or event.element.contract is self:
100             self.request_update()
101
102     def pre_update_icon(self, context):
103         """
104         Figure out if this interface represents a required, provided,
105         assembled (wired) or dotted (minimal) look.
106         """
107
108         self._draw_required = self._draw_provided = False
109         for item, handle in self.canvas.get_connected_items(self):
110             if gives_required(item, handle):
111                 self._draw_required = True
112             elif gives_provided(item, handle):
113                 self._draw_provided = True
114         radius = self.RADIUS_PROVIDED
115         self.style.icon_size = self.style.icon_size_provided
116         if self._draw_required:
117             radius = self.RADIUS_REQUIRED
118             self.style.icon_size = self.style.icon_size_required
119
120         self.min_width, self.min_height = self.style.icon_size
121         self.width, self.height = self.style.icon_size
122
123         # change handles first so gaphas.Element.pre_update can
124         # update its state
125         #
126         # update only h_se handle - rest of handles should be updated by
127         # constraints
128         h_nw = self._handles[NW]
129         h_se = self._handles[SE]
130         h_se.x = h_nw.x + self.min_width
131         h_se.y = h_nw.y + self.min_height
132
133         super(InterfaceItem, self).pre_update_icon(context)
134
135     def draw_icon(self, context):
136         cr = context.cairo
137         h_nw = self._handles[NW]
138         cx, cy = h_nw.x + self.width/2, h_nw.y + self.height/2
139         if self._draw_required:
140             cr.move_to(cx, cy + self.RADIUS_REQUIRED)
141             cr.arc_negative(cx, cy, self.RADIUS_REQUIRED, pi/2, pi*1.5)
142             cr.stroke()
143         if self._draw_provided or not self._draw_required:
144             cr.move_to(cx + self.RADIUS_PROVIDED, cy)
145             cr.arc(cx, cy, self.RADIUS_PROVIDED, 0, pi*2)
146             cr.stroke()
147         super(InterfaceItem, self).draw(context)
148
149
150 def gives_provided(item, handle):
151     """
152     Check if an item connected to an interface changes semantics of this
153     interface to be provided.
154
155     handle - handle of an item
156     """
157     return isinstance(item, ImplementationItem)
158
159
160 def gives_required(item, handle):
161     """
162     Check if an item connected to an interface changes semantics of this
163     interface to be required.
164
165     handle - handle of an item
166     TODO: check subject.clientDependency and subject.supplierDependency
167     """
168     # check for dependency item, interfaces is required if
169     # - connecting handle is head one
170     # - is in auto dependency
171     # - if is not in auto dependency then its UML type is Usage
172     return isinstance(item, DependencyItem) and item.handles()[0] == handle \
173         and (not item.auto_dependency and item.dependency_type is UML.Usage
174             or item.auto_dependency)
175
176
177 # vim:sw=4:et
Note: See TracBrowser for help on using the browser.