root/gaphor/tags/gaphor-0.12.0/gaphor/diagram/interface.py

Revision 1559, 5.4 kB (checked in by arj..@yirdis.nl, 2 years ago)

fixed bug in storage module. Make constraints connect properly when loading a model.

  • 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 gaphor.diagram.dependency import DependencyItem
12 from gaphor.diagram.implementation import ImplementationItem
13 from gaphor.diagram.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     @observed
57     def set_drawing_style(self, style):
58         """
59         In addition to setting the drawing style, the handles are
60         make non-movable if the icon (folded) style is used.
61         """
62         ClassItem.set_drawing_style(self, style)
63         # TODO: adjust offsets so the center point is the same
64         if self._drawing_style == self.DRAW_ICON:
65             self._name.style.update(self.FOLDED_STYLE)
66             for h in self._handles: h.movable = False
67             self.request_update()
68         else:
69             self._name.style.update(self.UNFOLDED_STYLE)
70             for h in self._handles: h.movable = True
71             self.request_update()
72
73     drawing_style = reversible_property(lambda self: self._drawing_style, set_drawing_style)
74
75     def is_folded(self):
76         """
77         Returns True if the interface is drawn as a circle/dot.
78         Unfolded means it's drawn like a classifier.
79         """
80         return self.drawing_style == self.DRAW_ICON
81
82     def _set_folded(self, folded):
83         if folded:
84             self.drawing_style = self.DRAW_ICON
85         else:
86             self.drawing_style = self.DRAW_COMPARTMENT
87
88     folded = property(is_folded, _set_folded)
89
90     def pre_update_icon(self, context):
91         """
92         Figure out if this interface represents a required, provided,
93         assembled (wired) or dotted (minimal) look.
94         """
95
96         self._draw_required = self._draw_provided = False
97         for item, handle in self.canvas.get_connected_items(self):
98             if gives_required(item, handle):
99                 self._draw_required = True
100             elif gives_provided(item, handle):
101                 self._draw_provided = True
102         radius = self.RADIUS_PROVIDED
103         self.style.icon_size = self.style.icon_size_provided
104         if self._draw_required:
105             radius = self.RADIUS_REQUIRED
106             self.style.icon_size = self.style.icon_size_required
107
108         self.min_width, self.min_height = self.style.icon_size
109         self.width, self.height = self.style.icon_size
110
111         # change handles first so gaphas.Element.pre_update can
112         # update its state
113         #
114         # update only h_se handle - rest of handles should be updated by
115         # constraints
116         h_nw = self._handles[NW]
117         h_se = self._handles[SE]
118         h_se.x = h_nw.x + self.min_width
119         h_se.y = h_nw.y + self.min_height
120
121         super(InterfaceItem, self).pre_update_icon(context)
122
123     def draw_icon(self, context):
124         cr = context.cairo
125         h_nw = self._handles[NW]
126         cx, cy = h_nw.x + self.width/2, h_nw.y + self.height/2
127         if self._draw_required:
128             cr.move_to(cx, cy + self.RADIUS_REQUIRED)
129             cr.arc_negative(cx, cy, self.RADIUS_REQUIRED, pi/2, pi*1.5)
130             cr.stroke()
131         if self._draw_provided or not self._draw_required:
132             cr.move_to(cx + self.RADIUS_PROVIDED, cy)
133             cr.arc(cx, cy, self.RADIUS_PROVIDED, 0, pi*2)
134             cr.stroke()
135         super(InterfaceItem, self).draw(context)
136
137
138 def gives_provided(item, handle):
139     """
140     Check if an item connected to an interface changes semantics of this
141     interface to be provided.
142
143     handle - handle of an item
144     """
145     return isinstance(item, ImplementationItem)
146
147
148 def gives_required(item, handle):
149     """
150     Check if an item connected to an interface changes semantics of this
151     interface to be required.
152
153     handle - handle of an item
154     TODO: check subject.clientDependency and subject.supplierDependency
155     """
156     # check for dependency item, interfaces is required if
157     # - connecting handle is head one
158     # - is in auto dependency
159     # - if is not in auto dependency then its UML type is Usage
160     return isinstance(item, DependencyItem) and item.handles()[0] == handle \
161         and (not item.auto_dependency and item.dependency_type is UML.Usage
162             or item.auto_dependency)
163
164
165 # vim:sw=4:et
Note: See TracBrowser for help on using the browser.