eric6/Graphics/ImportsDiagramBuilder.py

changeset 8286
62ae22eae123
parent 8277
ea734702ae94
child 8287
30eb7bc13d63
equal deleted inserted replaced
8285:1816b622aef2 8286:62ae22eae123
126 "The directory <b>'{0}'</b> is not a Python package.") 126 "The directory <b>'{0}'</b> is not a Python package.")
127 .format(self.package)) 127 .format(self.package))
128 self.scene.addItem(ct) 128 self.scene.addItem(ct)
129 return 129 return
130 130
131 shapes = {} 131 self.__shapes = {}
132 p = 10
133 y = 10
134 maxHeight = 0
135 sceneRect = self.umlView.sceneRect()
136 132
137 modules = self.__buildModulesDict() 133 modules = self.__buildModulesDict()
138 externalMods = [] 134 externalMods = []
139 packageList = self.shortPackage.split('.') 135 packageList = self.shortPackage.split('.')
140 packageListLen = len(packageList) 136 packageListLen = len(packageList)
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

eric ide

mercurial