Graphics/ApplicationDiagram.py

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

eric ide

mercurial