src/eric7/Graphics/PackageDiagramBuilder.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9278
36448ca469c2
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
24 24
25 class PackageDiagramBuilder(UMLDiagramBuilder): 25 class PackageDiagramBuilder(UMLDiagramBuilder):
26 """ 26 """
27 Class implementing a builder for UML like class diagrams of a package. 27 Class implementing a builder for UML like class diagrams of a package.
28 """ 28 """
29
29 def __init__(self, dialog, view, project, package, noAttrs=False): 30 def __init__(self, dialog, view, project, package, noAttrs=False):
30 """ 31 """
31 Constructor 32 Constructor
32 33
33 @param dialog reference to the UML dialog 34 @param dialog reference to the UML dialog
34 @type UMLDialog 35 @type UMLDialog
35 @param view reference to the view object 36 @param view reference to the view object
36 @type UMLGraphicsView 37 @type UMLGraphicsView
37 @param project reference to the project object 38 @param project reference to the project object
41 @param noAttrs flag indicating, that no attributes should be shown 42 @param noAttrs flag indicating, that no attributes should be shown
42 @type bool 43 @type bool
43 """ 44 """
44 super().__init__(dialog, view, project) 45 super().__init__(dialog, view, project)
45 self.setObjectName("PackageDiagram") 46 self.setObjectName("PackageDiagram")
46 47
47 self.package = os.path.abspath(package) 48 self.package = os.path.abspath(package)
48 self.noAttrs = noAttrs 49 self.noAttrs = noAttrs
49 50
50 self.__relPackage = ( 51 self.__relPackage = (
51 self.project.getRelativePath(self.package) 52 self.project.getRelativePath(self.package)
52 if self.project.isProjectSource(self.package) else 53 if self.project.isProjectSource(self.package)
53 "" 54 else ""
54 ) 55 )
55 56
56 def initialize(self): 57 def initialize(self):
57 """ 58 """
58 Public method to initialize the object. 59 Public method to initialize the object.
59 """ 60 """
60 pname = self.project.getProjectName() 61 pname = self.project.getProjectName()
61 name = ( 62 name = (
62 self.tr("Package Diagram {0}: {1}").format( 63 self.tr("Package Diagram {0}: {1}").format(
63 pname, self.project.getRelativePath(self.package)) 64 pname, self.project.getRelativePath(self.package)
64 if pname else 65 )
65 self.tr("Package Diagram: {0}").format(self.package) 66 if pname
67 else self.tr("Package Diagram: {0}").format(self.package)
66 ) 68 )
67 self.umlView.setDiagramName(name) 69 self.umlView.setDiagramName(name)
68 70
69 def __getCurrentShape(self, name): 71 def __getCurrentShape(self, name):
70 """ 72 """
71 Private method to get the named shape. 73 Private method to get the named shape.
72 74
73 @param name name of the shape 75 @param name name of the shape
74 @type str 76 @type str
75 @return shape 77 @return shape
76 @rtype QCanvasItem 78 @rtype QCanvasItem
77 """ 79 """
78 return self.allClasses.get(name) 80 return self.allClasses.get(name)
79 81
80 def __buildModulesDict(self): 82 def __buildModulesDict(self):
81 """ 83 """
82 Private method to build a dictionary of modules contained in the 84 Private method to build a dictionary of modules contained in the
83 package. 85 package.
84 86
85 @return dictionary of modules contained in the package 87 @return dictionary of modules contained in the package
86 @rtype dict 88 @rtype dict
87 """ 89 """
88 import Utilities.ModuleParser 90 import Utilities.ModuleParser
89 91
90 supportedExt = ( 92 supportedExt = [
91 ['*{0}'.format(ext) for ext in 93 "*{0}".format(ext) for ext in Preferences.getPython("Python3Extensions")
92 Preferences.getPython("Python3Extensions")] + 94 ] + ["*.rb"]
93 ['*.rb'] 95 extensions = Preferences.getPython("Python3Extensions") + [".rb"]
94 ) 96
95 extensions = (
96 Preferences.getPython("Python3Extensions") +
97 ['.rb']
98 )
99
100 moduleDict = {} 97 moduleDict = {}
101 modules = [] 98 modules = []
102 for ext in supportedExt: 99 for ext in supportedExt:
103 modules.extend(glob.glob( 100 modules.extend(glob.glob(Utilities.normjoinpath(self.package, ext)))
104 Utilities.normjoinpath(self.package, ext)))
105 tot = len(modules) 101 tot = len(modules)
106 progress = EricProgressDialog( 102 progress = EricProgressDialog(
107 self.tr("Parsing modules..."), 103 self.tr("Parsing modules..."),
108 None, 0, tot, self.tr("%v/%m Modules"), self.parent()) 104 None,
105 0,
106 tot,
107 self.tr("%v/%m Modules"),
108 self.parent(),
109 )
109 progress.setWindowTitle(self.tr("Package Diagram")) 110 progress.setWindowTitle(self.tr("Package Diagram"))
110 try: 111 try:
111 progress.show() 112 progress.show()
112 QApplication.processEvents() 113 QApplication.processEvents()
113 114
114 now = time.monotonic() 115 now = time.monotonic()
115 for prog, module in enumerate(modules): 116 for prog, module in enumerate(modules):
116 progress.setValue(prog) 117 progress.setValue(prog)
117 if time.monotonic() - now > 0.01: 118 if time.monotonic() - now > 0.01:
118 QApplication.processEvents() 119 QApplication.processEvents()
119 now = time.monotonic() 120 now = time.monotonic()
120 try: 121 try:
121 mod = Utilities.ModuleParser.readModule( 122 mod = Utilities.ModuleParser.readModule(
122 module, extensions=extensions, caching=False) 123 module, extensions=extensions, caching=False
124 )
123 except ImportError: 125 except ImportError:
124 continue 126 continue
125 else: 127 else:
126 name = mod.name 128 name = mod.name
127 if name.startswith(self.package): 129 if name.startswith(self.package):
128 name = name[len(self.package) + 1:] 130 name = name[len(self.package) + 1 :]
129 moduleDict[name] = mod 131 moduleDict[name] = mod
130 finally: 132 finally:
131 progress.setValue(tot) 133 progress.setValue(tot)
132 progress.deleteLater() 134 progress.deleteLater()
133 return moduleDict 135 return moduleDict
134 136
135 def __buildSubpackagesDict(self): 137 def __buildSubpackagesDict(self):
136 """ 138 """
137 Private method to build a dictionary of sub-packages contained in this 139 Private method to build a dictionary of sub-packages contained in this
138 package. 140 package.
139 141
140 @return dictionary of sub-packages contained in this package 142 @return dictionary of sub-packages contained in this package
141 @rtype dict 143 @rtype dict
142 """ 144 """
143 import Utilities.ModuleParser 145 import Utilities.ModuleParser
144 146
145 supportedExt = ( 147 supportedExt = [
146 ['*{0}'.format(ext) for ext in 148 "*{0}".format(ext) for ext in Preferences.getPython("Python3Extensions")
147 Preferences.getPython("Python3Extensions")] + 149 ] + ["*.rb"]
148 ['*.rb'] 150 extensions = Preferences.getPython("Python3Extensions") + [".rb"]
149 ) 151
150 extensions = (
151 Preferences.getPython("Python3Extensions") +
152 ['.rb']
153 )
154
155 subpackagesDict = {} 152 subpackagesDict = {}
156 subpackagesList = [] 153 subpackagesList = []
157 154
158 for subpackage in os.listdir(self.package): 155 for subpackage in os.listdir(self.package):
159 subpackagePath = os.path.join(self.package, subpackage) 156 subpackagePath = os.path.join(self.package, subpackage)
160 if ( 157 if (
161 os.path.isdir(subpackagePath) and 158 os.path.isdir(subpackagePath)
162 subpackage != "__pycache__" and 159 and subpackage != "__pycache__"
163 len(glob.glob( 160 and len(glob.glob(os.path.join(subpackagePath, "__init__.*"))) != 0
164 os.path.join(subpackagePath, "__init__.*")
165 )) != 0
166 ): 161 ):
167 subpackagesList.append(subpackagePath) 162 subpackagesList.append(subpackagePath)
168 163
169 tot = 0 164 tot = 0
170 for ext in supportedExt: 165 for ext in supportedExt:
171 for subpackage in subpackagesList: 166 for subpackage in subpackagesList:
172 tot += len(glob.glob(Utilities.normjoinpath(subpackage, ext))) 167 tot += len(glob.glob(Utilities.normjoinpath(subpackage, ext)))
173 progress = EricProgressDialog( 168 progress = EricProgressDialog(
174 self.tr("Parsing modules..."), 169 self.tr("Parsing modules..."),
175 None, 0, tot, self.tr("%v/%m Modules"), self.parent()) 170 None,
171 0,
172 tot,
173 self.tr("%v/%m Modules"),
174 self.parent(),
175 )
176 progress.setWindowTitle(self.tr("Package Diagram")) 176 progress.setWindowTitle(self.tr("Package Diagram"))
177 try: 177 try:
178 progress.show() 178 progress.show()
179 QApplication.processEvents() 179 QApplication.processEvents()
180 180
181 now = time.monotonic() 181 now = time.monotonic()
182 for subpackage in subpackagesList: 182 for subpackage in subpackagesList:
183 packageName = os.path.basename(subpackage) 183 packageName = os.path.basename(subpackage)
184 subpackagesDict[packageName] = [] 184 subpackagesDict[packageName] = []
185 modules = [] 185 modules = []
186 for ext in supportedExt: 186 for ext in supportedExt:
187 modules.extend(glob.glob( 187 modules.extend(glob.glob(Utilities.normjoinpath(subpackage, ext)))
188 Utilities.normjoinpath(subpackage, ext)))
189 for prog, module in enumerate(modules): 188 for prog, module in enumerate(modules):
190 progress.setValue(prog) 189 progress.setValue(prog)
191 if time.monotonic() - now > 0.01: 190 if time.monotonic() - now > 0.01:
192 QApplication.processEvents() 191 QApplication.processEvents()
193 now = time.monotonic() 192 now = time.monotonic()
194 try: 193 try:
195 mod = Utilities.ModuleParser.readModule( 194 mod = Utilities.ModuleParser.readModule(
196 module, extensions=extensions, caching=False) 195 module, extensions=extensions, caching=False
196 )
197 except ImportError: 197 except ImportError:
198 continue 198 continue
199 else: 199 else:
200 name = mod.name 200 name = mod.name
201 if "." in name: 201 if "." in name:
208 subpackagesDict[packageName].insert(0, "__init__") 208 subpackagesDict[packageName].insert(0, "__init__")
209 finally: 209 finally:
210 progress.setValue(tot) 210 progress.setValue(tot)
211 progress.deleteLater() 211 progress.deleteLater()
212 return subpackagesDict 212 return subpackagesDict
213 213
214 def buildDiagram(self): 214 def buildDiagram(self):
215 """ 215 """
216 Public method to build the class shapes of the package diagram. 216 Public method to build the class shapes of the package diagram.
217 217
218 The algorithm is borrowed from Boa Constructor. 218 The algorithm is borrowed from Boa Constructor.
219 """ 219 """
220 self.allClasses = {} 220 self.allClasses = {}
221 221
222 initlist = glob.glob(os.path.join(self.package, '__init__.*')) 222 initlist = glob.glob(os.path.join(self.package, "__init__.*"))
223 if len(initlist) == 0: 223 if len(initlist) == 0:
224 ct = QGraphicsTextItem(None) 224 ct = QGraphicsTextItem(None)
225 self.scene.addItem(ct) 225 self.scene.addItem(ct)
226 ct.setHtml( 226 ct.setHtml(
227 self.tr("The directory <b>'{0}'</b> is not a package.") 227 self.tr("The directory <b>'{0}'</b> is not a package.").format(
228 .format(self.package)) 228 self.package
229 )
230 )
229 return 231 return
230 232
231 modules = self.__buildModulesDict() 233 modules = self.__buildModulesDict()
232 subpackages = self.__buildSubpackagesDict() 234 subpackages = self.__buildSubpackagesDict()
233 235
234 if not modules and not subpackages: 236 if not modules and not subpackages:
235 ct = QGraphicsTextItem(None) 237 ct = QGraphicsTextItem(None)
236 self.scene.addItem(ct) 238 self.scene.addItem(ct)
237 ct.setHtml(self.buildErrorMessage( 239 ct.setHtml(
238 self.tr("The package <b>'{0}'</b> does not contain any modules" 240 self.buildErrorMessage(
239 " or subpackages.").format(self.package) 241 self.tr(
240 )) 242 "The package <b>'{0}'</b> does not contain any modules"
243 " or subpackages."
244 ).format(self.package)
245 )
246 )
241 return 247 return
242 248
243 # step 1: build all classes found in the modules 249 # step 1: build all classes found in the modules
244 classesFound = False 250 classesFound = False
245 251
246 for modName in list(modules.keys()): 252 for modName in list(modules.keys()):
247 module = modules[modName] 253 module = modules[modName]
248 for cls in list(module.classes.keys()): 254 for cls in list(module.classes.keys()):
249 classesFound = True 255 classesFound = True
250 self.__addLocalClass(cls, module.classes[cls], 0, 0) 256 self.__addLocalClass(cls, module.classes[cls], 0, 0)
251 if not classesFound and not subpackages: 257 if not classesFound and not subpackages:
252 ct = QGraphicsTextItem(None) 258 ct = QGraphicsTextItem(None)
253 self.scene.addItem(ct) 259 self.scene.addItem(ct)
254 ct.setHtml(self.buildErrorMessage( 260 ct.setHtml(
255 self.tr("The package <b>'{0}'</b> does not contain any" 261 self.buildErrorMessage(
256 " classes or subpackages.").format(self.package) 262 self.tr(
257 )) 263 "The package <b>'{0}'</b> does not contain any"
264 " classes or subpackages."
265 ).format(self.package)
266 )
267 )
258 return 268 return
259 269
260 # step 2: build the class hierarchies 270 # step 2: build the class hierarchies
261 routes = [] 271 routes = []
262 nodes = [] 272 nodes = []
263 273
264 for modName in list(modules.keys()): 274 for modName in list(modules.keys()):
265 module = modules[modName] 275 module = modules[modName]
266 todo = [module.createHierarchy()] 276 todo = [module.createHierarchy()]
267 while todo: 277 while todo:
268 hierarchy = todo[0] 278 hierarchy = todo[0]
269 for className in hierarchy: 279 for className in hierarchy:
270 cw = self.__getCurrentShape(className) 280 cw = self.__getCurrentShape(className)
271 if not cw and className.find('.') >= 0: 281 if not cw and className.find(".") >= 0:
272 cw = self.__getCurrentShape(className.split('.')[-1]) 282 cw = self.__getCurrentShape(className.split(".")[-1])
273 if cw: 283 if cw:
274 self.allClasses[className] = cw 284 self.allClasses[className] = cw
275 if cw and cw.noAttrs != self.noAttrs: 285 if cw and cw.noAttrs != self.noAttrs:
276 cw = None 286 cw = None
277 if cw and not (cw.external and 287 if cw and not (
278 (className in module.classes or 288 cw.external
279 className in module.modules) 289 and (className in module.classes or className in module.modules)
280 ): 290 ):
281 if className not in nodes: 291 if className not in nodes:
282 nodes.append(className) 292 nodes.append(className)
283 else: 293 else:
284 if className in module.classes: 294 if className in module.classes:
285 # this is a local class (defined in this module) 295 # this is a local class (defined in this module)
286 self.__addLocalClass( 296 self.__addLocalClass(
287 className, module.classes[className], 297 className, module.classes[className], 0, 0
288 0, 0) 298 )
289 elif className in module.modules: 299 elif className in module.modules:
290 # this is a local module (defined in this module) 300 # this is a local module (defined in this module)
291 self.__addLocalClass( 301 self.__addLocalClass(
292 className, module.modules[className], 302 className, module.modules[className], 0, 0, True
293 0, 0, True) 303 )
294 else: 304 else:
295 self.__addExternalClass(className, 0, 0) 305 self.__addExternalClass(className, 0, 0)
296 nodes.append(className) 306 nodes.append(className)
297 307
298 if hierarchy.get(className): 308 if hierarchy.get(className):
299 todo.append(hierarchy.get(className)) 309 todo.append(hierarchy.get(className))
300 children = list(hierarchy.get(className).keys()) 310 children = list(hierarchy.get(className).keys())
301 for child in children: 311 for child in children:
302 if (className, child) not in routes: 312 if (className, child) not in routes:
303 routes.append((className, child)) 313 routes.append((className, child))
304 314
305 del todo[0] 315 del todo[0]
306 316
307 # step 3: build the subpackages 317 # step 3: build the subpackages
308 for subpackage in sorted(subpackages.keys()): 318 for subpackage in sorted(subpackages.keys()):
309 self.__addPackage(subpackage, subpackages[subpackage], 0, 0) 319 self.__addPackage(subpackage, subpackages[subpackage], 0, 0)
310 nodes.append(subpackage) 320 nodes.append(subpackage)
311 321
312 self.__arrangeClasses(nodes, routes[:]) 322 self.__arrangeClasses(nodes, routes[:])
313 self.__createAssociations(routes) 323 self.__createAssociations(routes)
314 self.umlView.autoAdjustSceneSize(limit=True) 324 self.umlView.autoAdjustSceneSize(limit=True)
315 325
316 def __arrangeClasses(self, nodes, routes, whiteSpaceFactor=1.2): 326 def __arrangeClasses(self, nodes, routes, whiteSpaceFactor=1.2):
317 """ 327 """
318 Private method to arrange the shapes on the canvas. 328 Private method to arrange the shapes on the canvas.
319 329
320 The algorithm is borrowed from Boa Constructor. 330 The algorithm is borrowed from Boa Constructor.
321 331
322 @param nodes list of nodes to arrange 332 @param nodes list of nodes to arrange
323 @type list of str 333 @type list of str
324 @param routes list of routes 334 @param routes list of routes
325 @type list of tuple of (str, str) 335 @type list of tuple of (str, str)
326 @param whiteSpaceFactor factor to increase whitespace between 336 @param whiteSpaceFactor factor to increase whitespace between
327 items 337 items
328 @type float 338 @type float
329 """ 339 """
330 from . import GraphicsUtilities 340 from . import GraphicsUtilities
341
331 generations = GraphicsUtilities.sort(nodes, routes) 342 generations = GraphicsUtilities.sort(nodes, routes)
332 343
333 # calculate width and height of all elements 344 # calculate width and height of all elements
334 sizes = [] 345 sizes = []
335 for generation in generations: 346 for generation in generations:
336 sizes.append([]) 347 sizes.append([])
337 for child in generation: 348 for child in generation:
338 sizes[-1].append( 349 sizes[-1].append(self.__getCurrentShape(child).sceneBoundingRect())
339 self.__getCurrentShape(child).sceneBoundingRect()) 350
340
341 # calculate total width and total height 351 # calculate total width and total height
342 width = 0 352 width = 0
343 height = 0 353 height = 0
344 widths = [] 354 widths = []
345 heights = [] 355 heights = []
346 for generation in sizes: 356 for generation in sizes:
347 currentWidth = 0 357 currentWidth = 0
348 currentHeight = 0 358 currentHeight = 0
349 359
350 for rect in generation: 360 for rect in generation:
351 if rect.bottom() > currentHeight: 361 if rect.bottom() > currentHeight:
352 currentHeight = rect.bottom() 362 currentHeight = rect.bottom()
353 currentWidth += rect.right() 363 currentWidth += rect.right()
354 364
355 # update totals 365 # update totals
356 if currentWidth > width: 366 if currentWidth > width:
357 width = currentWidth 367 width = currentWidth
358 height += currentHeight 368 height += currentHeight
359 369
360 # store generation info 370 # store generation info
361 widths.append(currentWidth) 371 widths.append(currentWidth)
362 heights.append(currentHeight) 372 heights.append(currentHeight)
363 373
364 # add in some whitespace 374 # add in some whitespace
365 width *= whiteSpaceFactor 375 width *= whiteSpaceFactor
366 height = height * whiteSpaceFactor - 20 376 height = height * whiteSpaceFactor - 20
367 verticalWhiteSpace = 40.0 377 verticalWhiteSpace = 40.0
368 378
369 sceneRect = self.umlView.sceneRect() 379 sceneRect = self.umlView.sceneRect()
370 width += 50.0 380 width += 50.0
371 height += 50.0 381 height += 50.0
372 swidth = sceneRect.width() if width < sceneRect.width() else width 382 swidth = sceneRect.width() if width < sceneRect.width() else width
373 sheight = sceneRect.height() if height < sceneRect.height() else height 383 sheight = sceneRect.height() if height < sceneRect.height() else height
374 self.umlView.setSceneSize(swidth, sheight) 384 self.umlView.setSceneSize(swidth, sheight)
375 385
376 # distribute each generation across the width and the 386 # distribute each generation across the width and the
377 # generations across height 387 # generations across height
378 y = 10.0 388 y = 10.0
379 for currentWidth, currentHeight, generation in ( 389 for currentWidth, currentHeight, generation in zip_longest(
380 zip_longest(widths, heights, generations) 390 widths, heights, generations
381 ): 391 ):
382 x = 10.0 392 x = 10.0
383 # whiteSpace is the space between any two elements 393 # whiteSpace is the space between any two elements
384 whiteSpace = ( 394 whiteSpace = (width - currentWidth - 20) / (len(generation) - 1.0 or 2.0)
385 (width - currentWidth - 20) /
386 (len(generation) - 1.0 or 2.0)
387 )
388 for className in generation: 395 for className in generation:
389 cw = self.__getCurrentShape(className) 396 cw = self.__getCurrentShape(className)
390 cw.setPos(x, y) 397 cw.setPos(x, y)
391 rect = cw.sceneBoundingRect() 398 rect = cw.sceneBoundingRect()
392 x = x + rect.width() + whiteSpace 399 x = x + rect.width() + whiteSpace
393 y = y + currentHeight + verticalWhiteSpace 400 y = y + currentHeight + verticalWhiteSpace
394 401
395 def __addLocalClass(self, className, _class, x, y, isRbModule=False): 402 def __addLocalClass(self, className, _class, x, y, isRbModule=False):
396 """ 403 """
397 Private method to add a class defined in the module. 404 Private method to add a class defined in the module.
398 405
399 @param className name of the class to be as a dictionary key 406 @param className name of the class to be as a dictionary key
400 @type str 407 @type str
401 @param _class class to be shown 408 @param _class class to be shown
402 @type ModuleParser.Class 409 @type ModuleParser.Class
403 @param x x-coordinate 410 @param x x-coordinate
406 @type float 413 @type float
407 @param isRbModule flag indicating a Ruby module 414 @param isRbModule flag indicating a Ruby module
408 @type bool 415 @type bool
409 """ 416 """
410 from .ClassItem import ClassItem, ClassModel 417 from .ClassItem import ClassItem, ClassModel
418
411 name = _class.name 419 name = _class.name
412 if isRbModule: 420 if isRbModule:
413 name = "{0} (Module)".format(name) 421 name = "{0} (Module)".format(name)
414 cl = ClassModel( 422 cl = ClassModel(
415 name, 423 name,
416 sorted(_class.methods.keys())[:], 424 sorted(_class.methods.keys())[:],
417 sorted(_class.attributes.keys())[:], 425 sorted(_class.attributes.keys())[:],
418 sorted(_class.globals.keys())[:] 426 sorted(_class.globals.keys())[:],
419 ) 427 )
420 cw = ClassItem(cl, False, x, y, noAttrs=self.noAttrs, scene=self.scene, 428 cw = ClassItem(
421 colors=self.umlView.getDrawingColors()) 429 cl,
430 False,
431 x,
432 y,
433 noAttrs=self.noAttrs,
434 scene=self.scene,
435 colors=self.umlView.getDrawingColors(),
436 )
422 cw.setId(self.umlView.getItemId()) 437 cw.setId(self.umlView.getItemId())
423 self.allClasses[className] = cw 438 self.allClasses[className] = cw
424 439
425 def __addExternalClass(self, _class, x, y): 440 def __addExternalClass(self, _class, x, y):
426 """ 441 """
427 Private method to add a class defined outside the module. 442 Private method to add a class defined outside the module.
428 443
429 If the canvas is too small to take the shape, it 444 If the canvas is too small to take the shape, it
430 is enlarged. 445 is enlarged.
431 446
432 @param _class class to be shown 447 @param _class class to be shown
433 @type ModuleParser.Class 448 @type ModuleParser.Class
434 @param x x-coordinate 449 @param x x-coordinate
435 @type float 450 @type float
436 @param y y-coordinate 451 @param y y-coordinate
437 @type float 452 @type float
438 """ 453 """
439 from .ClassItem import ClassItem, ClassModel 454 from .ClassItem import ClassItem, ClassModel
455
440 cl = ClassModel(_class) 456 cl = ClassModel(_class)
441 cw = ClassItem(cl, True, x, y, noAttrs=self.noAttrs, scene=self.scene, 457 cw = ClassItem(
442 colors=self.umlView.getDrawingColors()) 458 cl,
459 True,
460 x,
461 y,
462 noAttrs=self.noAttrs,
463 scene=self.scene,
464 colors=self.umlView.getDrawingColors(),
465 )
443 cw.setId(self.umlView.getItemId()) 466 cw.setId(self.umlView.getItemId())
444 self.allClasses[_class] = cw 467 self.allClasses[_class] = cw
445 468
446 def __addPackage(self, name, modules, x, y): 469 def __addPackage(self, name, modules, x, y):
447 """ 470 """
448 Private method to add a package to the diagram. 471 Private method to add a package to the diagram.
449 472
450 @param name package name to be shown 473 @param name package name to be shown
451 @type str 474 @type str
452 @param modules list of module names contained in the package 475 @param modules list of module names contained in the package
453 @type list of str 476 @type list of str
454 @param x x-coordinate 477 @param x x-coordinate
455 @type float 478 @type float
456 @param y y-coordinate 479 @param y y-coordinate
457 @type float 480 @type float
458 """ 481 """
459 from .PackageItem import PackageItem, PackageModel 482 from .PackageItem import PackageItem, PackageModel
483
460 pm = PackageModel(name, modules) 484 pm = PackageModel(name, modules)
461 pw = PackageItem(pm, x, y, scene=self.scene, 485 pw = PackageItem(
462 colors=self.umlView.getDrawingColors()) 486 pm, x, y, scene=self.scene, colors=self.umlView.getDrawingColors()
487 )
463 pw.setId(self.umlView.getItemId()) 488 pw.setId(self.umlView.getItemId())
464 self.allClasses[name] = pw 489 self.allClasses[name] = pw
465 490
466 def __createAssociations(self, routes): 491 def __createAssociations(self, routes):
467 """ 492 """
468 Private method to generate the associations between the class shapes. 493 Private method to generate the associations between the class shapes.
469 494
470 @param routes list of relationsships 495 @param routes list of relationsships
471 @type list of tuple of (str, str) 496 @type list of tuple of (str, str)
472 """ 497 """
473 from .AssociationItem import AssociationItem, AssociationType 498 from .AssociationItem import AssociationItem, AssociationType
499
474 for route in routes: 500 for route in routes:
475 if len(route) > 1: 501 if len(route) > 1:
476 assoc = AssociationItem( 502 assoc = AssociationItem(
477 self.__getCurrentShape(route[1]), 503 self.__getCurrentShape(route[1]),
478 self.__getCurrentShape(route[0]), 504 self.__getCurrentShape(route[0]),
479 AssociationType.GENERALISATION, 505 AssociationType.GENERALISATION,
480 topToBottom=True, 506 topToBottom=True,
481 colors=self.umlView.getDrawingColors()) 507 colors=self.umlView.getDrawingColors(),
508 )
482 self.scene.addItem(assoc) 509 self.scene.addItem(assoc)
483 510
484 def parsePersistenceData(self, version, data): 511 def parsePersistenceData(self, version, data):
485 """ 512 """
486 Public method to parse persisted data. 513 Public method to parse persisted data.
487 514
488 @param version version of the data 515 @param version version of the data
489 @type str 516 @type str
490 @param data persisted data to be parsed 517 @param data persisted data to be parsed
491 @type str 518 @type str
492 @return flag indicating success 519 @return flag indicating success
493 @rtype bool 520 @rtype bool
494 """ 521 """
495 parts = data.split(", ") 522 parts = data.split(", ")
496 if ( 523 if (
497 len(parts) != 2 or 524 len(parts) != 2
498 not parts[0].startswith("package=") or 525 or not parts[0].startswith("package=")
499 not parts[1].startswith("no_attributes=") 526 or not parts[1].startswith("no_attributes=")
500 ): 527 ):
501 return False 528 return False
502 529
503 self.package = parts[0].split("=", 1)[1].strip() 530 self.package = parts[0].split("=", 1)[1].strip()
504 self.noAttrs = Utilities.toBool(parts[1].split("=", 1)[1].strip()) 531 self.noAttrs = Utilities.toBool(parts[1].split("=", 1)[1].strip())
505 532
506 self.initialize() 533 self.initialize()
507 534
508 return True 535 return True
509 536
510 def toDict(self): 537 def toDict(self):
511 """ 538 """
512 Public method to collect data to be persisted. 539 Public method to collect data to be persisted.
513 540
514 @return dictionary containing data to be persisted 541 @return dictionary containing data to be persisted
515 @rtype dict 542 @rtype dict
516 """ 543 """
517 data = { 544 data = {
518 "project_name": self.project.getProjectName(), 545 "project_name": self.project.getProjectName(),
519 "no_attributes": self.noAttrs, 546 "no_attributes": self.noAttrs,
520 } 547 }
521 548
522 data["package"] = ( 549 data["package"] = (
523 Utilities.fromNativeSeparators(self.__relPackage) 550 Utilities.fromNativeSeparators(self.__relPackage)
524 if self.__relPackage else 551 if self.__relPackage
525 Utilities.fromNativeSeparators(self.package) 552 else Utilities.fromNativeSeparators(self.package)
526 ) 553 )
527 554
528 return data 555 return data
529 556
530 def fromDict(self, version, data): 557 def fromDict(self, version, data):
531 """ 558 """
532 Public method to populate the class with data persisted by 'toDict()'. 559 Public method to populate the class with data persisted by 'toDict()'.
533 560
534 @param version version of the data 561 @param version version of the data
535 @type str 562 @type str
536 @param data dictionary containing the persisted data 563 @param data dictionary containing the persisted data
537 @type dict 564 @type dict
538 @return tuple containing a flag indicating success and an info 565 @return tuple containing a flag indicating success and an info
539 message in case the diagram belongs to a different project 566 message in case the diagram belongs to a different project
540 @rtype tuple of (bool, str) 567 @rtype tuple of (bool, str)
541 """ 568 """
542 try: 569 try:
543 self.noAttrs = data["no_attributes"] 570 self.noAttrs = data["no_attributes"]
544 571
545 package = Utilities.toNativeSeparators(data["package"]) 572 package = Utilities.toNativeSeparators(data["package"])
546 if os.path.isabs(package): 573 if os.path.isabs(package):
547 self.package = package 574 self.package = package
548 self.__relPackage = "" 575 self.__relPackage = ""
549 else: 576 else:
552 msg = self.tr( 579 msg = self.tr(
553 "<p>The diagram belongs to project <b>{0}</b>." 580 "<p>The diagram belongs to project <b>{0}</b>."
554 " Please open it and try again.</p>" 581 " Please open it and try again.</p>"
555 ).format(data["project_name"]) 582 ).format(data["project_name"])
556 return False, msg 583 return False, msg
557 584
558 self.__relPackage = package 585 self.__relPackage = package
559 self.package = self.project.getAbsolutePath(package) 586 self.package = self.project.getAbsolutePath(package)
560 except KeyError: 587 except KeyError:
561 return False, "" 588 return False, ""
562 589
563 self.initialize() 590 self.initialize()
564 591
565 return True, "" 592 return True, ""

eric ide

mercurial