173 impLst.append(n) |
169 impLst.append(n) |
174 elif self.showExternalImports: |
170 elif self.showExternalImports: |
175 impLst.append(n) |
171 impLst.append(n) |
176 if n not in externalMods: |
172 if n not in externalMods: |
177 externalMods.append(n) |
173 externalMods.append(n) |
|
174 |
178 classNames = [] |
175 classNames = [] |
179 for cls in list(modules[module].classes.keys()): |
176 for class_ in list(modules[module].classes.keys()): |
180 className = modules[module].classes[cls].name |
177 className = modules[module].classes[class_].name |
181 if className not in classNames: |
178 if className not in classNames: |
182 classNames.append(className) |
179 classNames.append(className) |
183 shape = self.__addModule(module, classNames, 0.0, 0.0) |
180 shape = self.__addModule(module, classNames, 0.0, 0.0) |
184 shapeRect = shape.sceneBoundingRect() |
181 self.__shapes[module] = (shape, impLst) |
185 shapes[module] = (shape, impLst) |
|
186 pn = p + shapeRect.width() + 10 |
|
187 maxHeight = max(maxHeight, shapeRect.height()) |
|
188 if pn > sceneRect.width(): |
|
189 p = 10 |
|
190 y += maxHeight + 10 |
|
191 maxHeight = shapeRect.height() |
|
192 shape.setPos(p, y) |
|
193 p += shapeRect.width() + 10 |
|
194 else: |
|
195 shape.setPos(p, y) |
|
196 p = pn |
|
197 |
182 |
198 for module in externalMods: |
183 for module in externalMods: |
199 shape = self.__addModule(module, [], 0.0, 0.0) |
184 shape = self.__addModule(module, [], 0.0, 0.0) |
200 shapeRect = shape.sceneBoundingRect() |
185 self.__shapes[module] = (shape, []) |
201 shapes[module] = (shape, []) |
186 |
202 pn = p + shapeRect.width() + 10 |
187 # build a list of routes |
203 maxHeight = max(maxHeight, shapeRect.height()) |
188 nodes = [] |
204 if pn > sceneRect.width(): |
189 routes = [] |
205 p = 10 |
190 for module in self.__shapes: |
206 y += maxHeight + 10 |
191 nodes.append(module) |
207 maxHeight = shapeRect.height() |
192 for rel in self.__shapes[module][1]: |
208 shape.setPos(p, y) |
193 route = (module, rel) |
209 p += shapeRect.width() + 10 |
194 if route not in routes: |
210 else: |
195 routes.append(route) |
211 shape.setPos(p, y) |
196 |
212 p = pn |
197 self.__arrangeNodes(nodes, routes[:]) |
213 |
198 self.__createAssociations(routes) |
214 rect = self.umlView._getDiagramRect(10) |
|
215 sceneRect = self.umlView.sceneRect() |
|
216 if rect.width() > sceneRect.width(): |
|
217 sceneRect.setWidth(rect.width()) |
|
218 if rect.height() > sceneRect.height(): |
|
219 sceneRect.setHeight(rect.height()) |
|
220 self.umlView.setSceneSize(sceneRect.width(), sceneRect.height()) |
|
221 |
|
222 self.__createAssociations(shapes) |
|
223 self.umlView.autoAdjustSceneSize(limit=True) |
199 self.umlView.autoAdjustSceneSize(limit=True) |
224 |
200 |
225 def __addModule(self, name, classes, x, y): |
201 def __addModule(self, name, classes, x, y): |
226 """ |
202 """ |
227 Private method to add a module to the diagram. |
203 Private method to add a module to the diagram. |
239 impW = ModuleItem(impM, x, y, scene=self.scene, |
215 impW = ModuleItem(impM, x, y, scene=self.scene, |
240 colors=self.umlView.getDrawingColors()) |
216 colors=self.umlView.getDrawingColors()) |
241 impW.setId(self.umlView.getItemId()) |
217 impW.setId(self.umlView.getItemId()) |
242 return impW |
218 return impW |
243 |
219 |
244 def __createAssociations(self, shapes): |
220 def __arrangeNodes(self, nodes, routes, whiteSpaceFactor=1.2): |
|
221 """ |
|
222 Private method to arrange the shapes on the canvas. |
|
223 |
|
224 The algorithm is borrowed from Boa Constructor. |
|
225 |
|
226 @param nodes list of nodes to arrange |
|
227 @type list of str |
|
228 @param routes list of routes |
|
229 @type list of tuple of (str, str) |
|
230 @param whiteSpaceFactor factor to increase whitespace between |
|
231 items |
|
232 @type float |
|
233 """ |
|
234 from . import GraphicsUtilities |
|
235 generations = GraphicsUtilities.sort(nodes, routes) |
|
236 |
|
237 # calculate width and height of all elements |
|
238 sizes = [] |
|
239 for generation in generations: |
|
240 sizes.append([]) |
|
241 for child in generation: |
|
242 sizes[-1].append( |
|
243 self.__shapes[child][0].sceneBoundingRect()) |
|
244 |
|
245 # calculate total width and total height |
|
246 width = 0 |
|
247 height = 0 |
|
248 widths = [] |
|
249 heights = [] |
|
250 for generation in sizes: |
|
251 currentWidth = 0 |
|
252 currentHeight = 0 |
|
253 |
|
254 for rect in generation: |
|
255 if rect.height() > currentHeight: |
|
256 currentHeight = rect.height() |
|
257 currentWidth += rect.width() |
|
258 |
|
259 # update totals |
|
260 if currentWidth > width: |
|
261 width = currentWidth |
|
262 height += currentHeight |
|
263 |
|
264 # store generation info |
|
265 widths.append(currentWidth) |
|
266 heights.append(currentHeight) |
|
267 |
|
268 # add in some whitespace |
|
269 width *= whiteSpaceFactor |
|
270 height = height * whiteSpaceFactor - 20 |
|
271 verticalWhiteSpace = 40.0 |
|
272 |
|
273 sceneRect = self.umlView.sceneRect() |
|
274 width += 50.0 |
|
275 height += 50.0 |
|
276 swidth = sceneRect.width() if width < sceneRect.width() else width |
|
277 sheight = sceneRect.height() if height < sceneRect.height() else height |
|
278 self.umlView.setSceneSize(swidth, sheight) |
|
279 |
|
280 # distribute each generation across the width and the |
|
281 # generations across height |
|
282 y = 10.0 |
|
283 for currentWidth, currentHeight, generation in ( |
|
284 zip(reversed(widths), reversed(heights), reversed(generations)) |
|
285 ): |
|
286 x = 10.0 |
|
287 # whiteSpace is the space between any two elements |
|
288 whiteSpace = ( |
|
289 (width - currentWidth - 20) / |
|
290 (len(generation) - 1.0 or 2.0) |
|
291 ) |
|
292 for name in generation: |
|
293 shape = self.__shapes[name][0] |
|
294 shape.setPos(x, y) |
|
295 rect = shape.sceneBoundingRect() |
|
296 x = x + rect.width() + whiteSpace |
|
297 y = y + currentHeight + verticalWhiteSpace |
|
298 |
|
299 def __createAssociations(self, routes): |
245 """ |
300 """ |
246 Private method to generate the associations between the module shapes. |
301 Private method to generate the associations between the module shapes. |
247 |
302 |
248 @param shapes list of shapes |
303 @param routes list of associations |
|
304 @type list of tuple of (str, str) |
249 """ |
305 """ |
250 from .AssociationItem import AssociationItem, AssociationType |
306 from .AssociationItem import AssociationItem, AssociationType |
251 for module in list(shapes.keys()): |
307 for route in routes: |
252 for rel in shapes[module][1]: |
308 assoc = AssociationItem( |
253 assoc = AssociationItem( |
309 self.__shapes[route[0]][0], |
254 shapes[module][0], shapes[rel][0], |
310 self.__shapes[route[1]][0], |
255 AssociationType.IMPORTS, |
311 AssociationType.IMPORTS, |
256 colors=self.umlView.getDrawingColors()) |
312 colors=self.umlView.getDrawingColors()) |
257 self.scene.addItem(assoc) |
313 self.scene.addItem(assoc) |
258 |
314 |
259 def getPersistenceData(self): |
315 def getPersistenceData(self): |
260 """ |
316 """ |
261 Public method to get a string for data to be persisted. |
317 Public method to get a string for data to be persisted. |
262 |
318 |