|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2004 - 2019 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing the UMLItem base class. |
|
8 """ |
|
9 |
|
10 from __future__ import unicode_literals |
|
11 |
|
12 from PyQt5.QtCore import Qt, QSizeF |
|
13 from PyQt5.QtWidgets import QGraphicsItem, QGraphicsRectItem, QStyle |
|
14 |
|
15 import Preferences |
|
16 |
|
17 |
|
18 class UMLModel(object): |
|
19 """ |
|
20 Class implementing the UMLModel base class. |
|
21 """ |
|
22 def __init__(self, name): |
|
23 """ |
|
24 Constructor |
|
25 |
|
26 @param name package name (string) |
|
27 """ |
|
28 self.name = name |
|
29 |
|
30 def getName(self): |
|
31 """ |
|
32 Public method to retrieve the model name. |
|
33 |
|
34 @return model name (string) |
|
35 """ |
|
36 return self.name |
|
37 |
|
38 |
|
39 class UMLItem(QGraphicsRectItem): |
|
40 """ |
|
41 Class implementing the UMLItem base class. |
|
42 """ |
|
43 ItemType = "UMLItem" |
|
44 |
|
45 def __init__(self, model=None, x=0, y=0, rounded=False, parent=None): |
|
46 """ |
|
47 Constructor |
|
48 |
|
49 @param model UML model containing the item data (UMLModel) |
|
50 @param x x-coordinate (integer) |
|
51 @param y y-coordinate (integer) |
|
52 @param rounded flag indicating a rounded corner (boolean) |
|
53 @keyparam parent reference to the parent object (QGraphicsItem) |
|
54 """ |
|
55 super(UMLItem, self).__init__(parent) |
|
56 self.model = model |
|
57 |
|
58 self.font = Preferences.getGraphics("Font") |
|
59 self.margin = 5 |
|
60 self.associations = [] |
|
61 self.shouldAdjustAssociations = False |
|
62 self.__id = -1 |
|
63 |
|
64 self.setRect(x, y, 60, 30) |
|
65 |
|
66 if rounded: |
|
67 p = self.pen() |
|
68 p.setCapStyle(Qt.RoundCap) |
|
69 p.setJoinStyle(Qt.RoundJoin) |
|
70 |
|
71 self.setFlag(QGraphicsItem.ItemIsMovable, True) |
|
72 self.setFlag(QGraphicsItem.ItemIsSelectable, True) |
|
73 try: |
|
74 self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True) |
|
75 except AttributeError: |
|
76 # only available for Qt 4.6.0 and newer |
|
77 pass |
|
78 |
|
79 def getName(self): |
|
80 """ |
|
81 Public method to retrieve the item name. |
|
82 |
|
83 @return item name (string) |
|
84 """ |
|
85 if self.model: |
|
86 return self.model.name |
|
87 else: |
|
88 return "" |
|
89 |
|
90 def setSize(self, width, height): |
|
91 """ |
|
92 Public method to set the rectangles size. |
|
93 |
|
94 @param width width of the rectangle (float) |
|
95 @param height height of the rectangle (float) |
|
96 """ |
|
97 rect = self.rect() |
|
98 rect.setSize(QSizeF(width, height)) |
|
99 self.setRect(rect) |
|
100 |
|
101 def addAssociation(self, assoc): |
|
102 """ |
|
103 Public method to add an association to this widget. |
|
104 |
|
105 @param assoc association to be added (AssociationWidget) |
|
106 """ |
|
107 if assoc and assoc not in self.associations: |
|
108 self.associations.append(assoc) |
|
109 |
|
110 def removeAssociation(self, assoc): |
|
111 """ |
|
112 Public method to remove an association to this widget. |
|
113 |
|
114 @param assoc association to be removed (AssociationWidget) |
|
115 """ |
|
116 if assoc and assoc in self.associations: |
|
117 self.associations.remove(assoc) |
|
118 |
|
119 def removeAssociations(self): |
|
120 """ |
|
121 Public method to remove all associations of this widget. |
|
122 """ |
|
123 for assoc in self.associations[:]: |
|
124 assoc.unassociate() |
|
125 assoc.hide() |
|
126 del assoc |
|
127 |
|
128 def adjustAssociations(self): |
|
129 """ |
|
130 Public method to adjust the associations to widget movements. |
|
131 """ |
|
132 if self.shouldAdjustAssociations: |
|
133 for assoc in self.associations: |
|
134 assoc.widgetMoved() |
|
135 self.shouldAdjustAssociations = False |
|
136 |
|
137 def moveBy(self, dx, dy): |
|
138 """ |
|
139 Public overriden method to move the widget relative. |
|
140 |
|
141 @param dx relative movement in x-direction (float) |
|
142 @param dy relative movement in y-direction (float) |
|
143 """ |
|
144 super(UMLItem, self).moveBy(dx, dy) |
|
145 self.adjustAssociations() |
|
146 |
|
147 def setPos(self, x, y): |
|
148 """ |
|
149 Public overriden method to set the items position. |
|
150 |
|
151 @param x absolute x-position (float) |
|
152 @param y absolute y-position (float) |
|
153 """ |
|
154 super(UMLItem, self).setPos(x, y) |
|
155 self.adjustAssociations() |
|
156 |
|
157 def itemChange(self, change, value): |
|
158 """ |
|
159 Public method called when an items state changes. |
|
160 |
|
161 @param change the item's change (QGraphicsItem.GraphicsItemChange) |
|
162 @param value the value of the change |
|
163 @return adjusted values |
|
164 """ |
|
165 if change == QGraphicsItem.ItemPositionChange: |
|
166 # 1. remember to adjust associations |
|
167 self.shouldAdjustAssociations = True |
|
168 |
|
169 # 2. ensure the new position is inside the scene |
|
170 rect = self.scene().sceneRect() |
|
171 if not rect.contains(value): |
|
172 # keep the item inside the scene |
|
173 value.setX(min(rect.right(), max(value.x(), rect.left()))) |
|
174 value.setY(min(rect.bottom(), max(value.y(), rect.top()))) |
|
175 return value |
|
176 |
|
177 return QGraphicsItem.itemChange(self, change, value) |
|
178 |
|
179 def paint(self, painter, option, widget=None): |
|
180 """ |
|
181 Public method to paint the item in local coordinates. |
|
182 |
|
183 @param painter reference to the painter object (QPainter) |
|
184 @param option style options (QStyleOptionGraphicsItem) |
|
185 @param widget optional reference to the widget painted on (QWidget) |
|
186 """ |
|
187 pen = self.pen() |
|
188 if (option.state & QStyle.State_Selected) == \ |
|
189 QStyle.State(QStyle.State_Selected): |
|
190 pen.setWidth(2) |
|
191 else: |
|
192 pen.setWidth(1) |
|
193 |
|
194 painter.setPen(pen) |
|
195 painter.setBrush(self.brush()) |
|
196 painter.drawRect(self.rect()) |
|
197 self.adjustAssociations() |
|
198 |
|
199 def setId(self, itemId): |
|
200 """ |
|
201 Public method to assign an ID to the item. |
|
202 |
|
203 @param itemId assigned ID (integer) |
|
204 """ |
|
205 self.__id = itemId |
|
206 |
|
207 def getId(self): |
|
208 """ |
|
209 Public method to get the item ID. |
|
210 |
|
211 @return ID of the item (integer) |
|
212 """ |
|
213 return self.__id |
|
214 |
|
215 def getItemType(self): |
|
216 """ |
|
217 Public method to get the item's type. |
|
218 |
|
219 @return item type (string) |
|
220 """ |
|
221 return self.ItemType |
|
222 |
|
223 def buildItemDataString(self): |
|
224 """ |
|
225 Public method to build a string to persist the specific item data. |
|
226 |
|
227 This string must start with ", " and should be built like |
|
228 "attribute=value" with pairs separated by ", ". value must not |
|
229 contain ", " or newlines. |
|
230 |
|
231 @return persistence data (string) |
|
232 """ |
|
233 return "" |
|
234 |
|
235 def parseItemDataString(self, version, data): |
|
236 """ |
|
237 Public method to parse the given persistence data. |
|
238 |
|
239 @param version version of the data (string) |
|
240 @param data persisted data to be parsed (string) |
|
241 @return flag indicating success (boolean) |
|
242 """ |
|
243 return True |