Graphics/ApplicationDiagramBuilder.py

changeset 2031
c36c2eb62a75
parent 2030
db11a2fe9bbc
child 2033
4b99609f6a87
equal deleted inserted replaced
2030:db11a2fe9bbc 2031:c36c2eb62a75
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2007 - 2012 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a dialog showing an imports diagram of the application.
8 """
9
10 import os
11 import glob
12
13 from PyQt4.QtGui import QApplication, QProgressDialog
14
15 from .UMLDiagramBuilder import UMLDiagramBuilder
16 from .PackageItem import PackageItem, PackageModel
17 from .AssociationItem import AssociationItem, Imports
18
19 import Utilities.ModuleParser
20 import Utilities
21
22 import Preferences
23
24
25 class ApplicationDiagramBuilder(UMLDiagramBuilder):
26 """
27 Class implementing a builder for imports diagrams of the application.
28 """
29 def __init__(self, dialog, view, project, noModules=False):
30 """
31 Constructor
32
33 @param dialog reference to the UML dialog (UMLDialog)
34 @param view reference to the view object (UMLGraphicsView)
35 @param project reference to the project object (Project)
36 @keyparam noModules flag indicating, that no module names should be
37 shown (boolean)
38 """
39 super().__init__(dialog, view, project)
40 self.setObjectName("ApplicationDiagram")
41
42 self.project = project
43 self.noModules = noModules
44
45 self.umlView.setDiagramName(
46 self.trUtf8("Application Diagram {0}").format(project.getProjectName()))
47
48 self.umlView.setPersistenceData(
49 "project={0}".format(self.project.getProjectFile()))
50
51 def __buildModulesDict(self):
52 """
53 Private method to build a dictionary of modules contained in the application.
54
55 @return dictionary of modules contained in the application.
56 """
57 extensions = Preferences.getPython("PythonExtensions") + \
58 Preferences.getPython("Python3Extensions") + ['.rb']
59 moduleDict = {}
60 mods = self.project.pdata["SOURCES"]
61 modules = []
62 for module in mods:
63 modules.append(Utilities.normabsjoinpath(self.project.ppath, module))
64 tot = len(modules)
65 try:
66 prog = 0
67 progress = QProgressDialog(self.trUtf8("Parsing modules..."),
68 None, 0, tot, self.parent())
69 progress.show()
70 QApplication.processEvents()
71 for module in modules:
72 progress.setValue(prog)
73 QApplication.processEvents()
74 prog += 1
75 if module.endswith("__init__.py"):
76 continue
77 try:
78 mod = Utilities.ModuleParser.readModule(module, extensions=extensions)
79 except ImportError:
80 continue
81 else:
82 name = mod.name
83 moduleDict[name] = mod
84 finally:
85 progress.setValue(tot)
86 return moduleDict
87
88 def buildDiagram(self):
89 """
90 Public method to build the packages shapes of the diagram.
91 """
92 project = os.path.splitdrive(self.project.getProjectPath())[1]\
93 .replace(os.sep, '.')[1:]
94 packages = {}
95 shapes = {}
96 p = 10
97 y = 10
98 maxHeight = 0
99 sceneRect = self.umlView.sceneRect()
100
101 modules = self.__buildModulesDict()
102 sortedkeys = sorted(modules.keys())
103
104 # step 1: build a dictionary of packages
105 for module in sortedkeys:
106 l = module.split('.')
107 package = '.'.join(l[:-1])
108 if package in packages:
109 packages[package][0].append(l[-1])
110 else:
111 packages[package] = ([l[-1]], [])
112
113 # step 2: assign modules to dictionaries and update import relationship
114 for module in sortedkeys:
115 l = module.split('.')
116 package = '.'.join(l[:-1])
117 impLst = []
118 for i in modules[module].imports:
119 if i in modules:
120 impLst.append(i)
121 else:
122 if i.find('.') == -1:
123 n = "{0}.{1}".format(modules[module].package, i)
124 if n in modules:
125 impLst.append(n)
126 else:
127 n = "{0}.{1}".format(project, i)
128 if n in modules:
129 impLst.append(n)
130 elif n in packages:
131 n = "{0}.<<Dummy>>".format(n)
132 impLst.append(n)
133 else:
134 n = "{0}.{1}".format(project, i)
135 if n in modules:
136 impLst.append(n)
137 for i in list(modules[module].from_imports.keys()):
138 if i.startswith('.'):
139 dots = len(i) - len(i.lstrip('.'))
140 if dots == 1:
141 i = i[1:]
142 elif dots > 1:
143 packagePath = os.path.dirname(modules[module].file)
144 hasInit = True
145 ppath = packagePath
146 while hasInit:
147 ppath = os.path.dirname(ppath)
148 hasInit = \
149 len(glob.glob(os.path.join(ppath, '__init__.*'))) > 0
150 shortPackage = \
151 packagePath.replace(ppath, '').replace(os.sep, '.')[1:]
152 packageList = shortPackage.split('.')[1:]
153 packageListLen = len(packageList)
154 i = '.'.join(packageList[:packageListLen - dots + 1] + [i[dots:]])
155
156 if i in modules:
157 impLst.append(i)
158 else:
159 if i.find('.') == -1:
160 n = "{0}.{1}".format(modules[module].package, i)
161 if n in modules:
162 impLst.append(n)
163 else:
164 n = "{0}.{1}".format(project, i)
165 if n in modules:
166 impLst.append(n)
167 elif n in packages:
168 n = "{0}.<<Dummy>>".format(n)
169 impLst.append(n)
170 else:
171 n = "{0}.{1}".format(project, i)
172 if n in modules:
173 impLst.append(n)
174 for imp in impLst:
175 impPackage = '.'.join(imp.split('.')[:-1])
176 if not impPackage in packages[package][1] and \
177 not impPackage == package:
178 packages[package][1].append(impPackage)
179
180 sortedkeys = sorted(packages.keys())
181 for package in sortedkeys:
182 if package:
183 relPackage = package.replace(project, '')
184 if relPackage and relPackage[0] == '.':
185 relPackage = relPackage[1:]
186 else:
187 relPackage = self.trUtf8("<<Application>>")
188 else:
189 relPackage = self.trUtf8("<<Others>>")
190 shape = self.__addPackage(relPackage, packages[package][0], 0.0, 0.0)
191 shapeRect = shape.sceneBoundingRect()
192 shapes[package] = (shape, packages[package][1])
193 pn = p + shapeRect.width() + 10
194 maxHeight = max(maxHeight, shapeRect.height())
195 if pn > sceneRect.width():
196 p = 10
197 y += maxHeight + 10
198 maxHeight = shapeRect.height()
199 shape.setPos(p, y)
200 p += shapeRect.width() + 10
201 else:
202 shape.setPos(p, y)
203 p = pn
204
205 rect = self.umlView._getDiagramRect(10)
206 sceneRect = self.umlView.sceneRect()
207 if rect.width() > sceneRect.width():
208 sceneRect.setWidth(rect.width())
209 if rect.height() > sceneRect.height():
210 sceneRect.setHeight(rect.height())
211 self.umlView.setSceneSize(sceneRect.width(), sceneRect.height())
212
213 self.__createAssociations(shapes)
214 self.umlView.autoAdjustSceneSize(limit=True)
215
216 def __addPackage(self, name, modules, x, y):
217 """
218 Private method to add a package to the diagram.
219
220 @param name package name to be shown (string)
221 @param modules list of module names contained in the package
222 (list of strings)
223 @param x x-coordinate (float)
224 @param y y-coordinate (float)
225 """
226 modules.sort()
227 pm = PackageModel(name, modules)
228 pw = PackageItem(pm, x, y, noModules=self.noModules, scene=self.scene)
229 pw.setId(self.umlView.getItemId())
230 return pw
231
232 def __createAssociations(self, shapes):
233 """
234 Private method to generate the associations between the package shapes.
235
236 @param shapes list of shapes
237 """
238 for package in shapes:
239 for rel in shapes[package][1]:
240 assoc = AssociationItem(
241 shapes[package][0], shapes[rel][0],
242 Imports)
243 self.scene.addItem(assoc)

eric ide

mercurial