src/eric7/Graphics/ApplicationDiagramBuilder.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
--- a/src/eric7/Graphics/ApplicationDiagramBuilder.py	Wed Jul 13 11:16:20 2022 +0200
+++ b/src/eric7/Graphics/ApplicationDiagramBuilder.py	Wed Jul 13 14:55:47 2022 +0200
@@ -26,10 +26,11 @@
     """
     Class implementing a builder for imports diagrams of the application.
     """
+
     def __init__(self, dialog, view, project, noModules=False):
         """
         Constructor
-        
+
         @param dialog reference to the UML dialog
         @type UMLDialog
         @param view reference to the view object
@@ -42,41 +43,43 @@
         """
         super().__init__(dialog, view, project)
         self.setObjectName("ApplicationDiagram")
-        
+
         self.noModules = noModules
-        
+
         self.umlView.setDiagramName(
-            self.tr("Application Diagram {0}").format(
-                self.project.getProjectName()))
-        
+            self.tr("Application Diagram {0}").format(self.project.getProjectName())
+        )
+
     def __buildModulesDict(self):
         """
         Private method to build a dictionary of modules contained in the
         application.
-        
+
         @return dictionary of modules contained in the application
         @rtype dict
         """
         import Utilities.ModuleParser
-        extensions = (
-            Preferences.getPython("Python3Extensions") +
-            ['.rb']
-        )
+
+        extensions = Preferences.getPython("Python3Extensions") + [".rb"]
         moduleDict = {}
         mods = self.project.pdata["SOURCES"]
         modules = []
         for module in mods:
-            modules.append(Utilities.normabsjoinpath(
-                self.project.ppath, module))
+            modules.append(Utilities.normabsjoinpath(self.project.ppath, module))
         tot = len(modules)
         progress = EricProgressDialog(
             self.tr("Parsing modules..."),
-            None, 0, tot, self.tr("%v/%m Modules"), self.parent())
+            None,
+            0,
+            tot,
+            self.tr("%v/%m Modules"),
+            self.parent(),
+        )
         progress.setWindowTitle(self.tr("Application Diagram"))
         try:
             progress.show()
             QApplication.processEvents()
-            
+
             now = time.monotonic()
             for prog, module in enumerate(modules):
                 progress.setValue(prog)
@@ -87,7 +90,8 @@
                     continue
                 try:
                     mod = Utilities.ModuleParser.readModule(
-                        module, extensions=extensions, caching=False)
+                        module, extensions=extensions, caching=False
+                    )
                 except ImportError:
                     continue
                 else:
@@ -97,11 +101,11 @@
             progress.setValue(tot)
             progress.deleteLater()
         return moduleDict
-    
+
     def __findApplicationRoot(self):
         """
         Private method to find the application root path.
-        
+
         @return application root path
         @rtype str
         """
@@ -119,7 +123,7 @@
                     init = os.path.join(fullpath, "__init__.py")
                     if os.path.exists(init):
                         candidates.append(fullpath)
-            
+
             # check, if project uses the 'src' layout
             if os.path.exists(os.path.join(path, "src")):
                 srcPath = os.path.join(path, "src")
@@ -129,7 +133,7 @@
                         init = os.path.join(fullpath, "__init__.py")
                         if os.path.exists(init):
                             candidates.append(fullpath)
-            
+
             if len(candidates) == 1:
                 return candidates[0]
             elif len(candidates) > 1:
@@ -138,17 +142,22 @@
                     self.tr("Application Diagram"),
                     self.tr("Select the application directory:"),
                     sorted(candidates),
-                    0, True)
+                    0,
+                    True,
+                )
                 if ok:
                     return root
             else:
                 EricMessageBox.warning(
                     None,
                     self.tr("Application Diagram"),
-                    self.tr("""No application package could be detected."""
-                            """ Aborting..."""))
+                    self.tr(
+                        """No application package could be detected."""
+                        """ Aborting..."""
+                    ),
+                )
         return None
-        
+
     def buildDiagram(self):
         """
         Public method to build the packages shapes of the diagram.
@@ -157,14 +166,14 @@
         if rpath is None:
             # no root path detected
             return
-        
-        root = os.path.splitdrive(rpath)[1].replace(os.sep, '.')[1:]
-        
+
+        root = os.path.splitdrive(rpath)[1].replace(os.sep, ".")[1:]
+
         packages = {}
         self.__shapes = {}
-        
+
         modules = self.__buildModulesDict()
-        
+
         # step 1: build a dictionary of packages
         for module in sorted(modules.keys()):
             if "." in module:
@@ -175,7 +184,7 @@
                 packages[packageName][0].append(moduleName)
             else:
                 packages[packageName] = ([moduleName], [])
-                
+
         # step 2: assign modules to dictionaries and update import relationship
         for module in sorted(modules.keys()):
             package = module.rsplit(".", 1)[0]
@@ -184,9 +193,8 @@
                 if moduleImport in modules:
                     impLst.append(moduleImport)
                 else:
-                    if moduleImport.find('.') == -1:
-                        n = "{0}.{1}".format(modules[module].package,
-                                             moduleImport)
+                    if moduleImport.find(".") == -1:
+                        n = "{0}.{1}".format(modules[module].package, moduleImport)
                         if n in modules:
                             impLst.append(n)
                         else:
@@ -201,8 +209,8 @@
                         if n in modules:
                             impLst.append(n)
             for moduleImport in list(modules[module].from_imports.keys()):
-                if moduleImport.startswith('.'):
-                    dots = len(moduleImport) - len(moduleImport.lstrip('.'))
+                if moduleImport.startswith("."):
+                    dots = len(moduleImport) - len(moduleImport.lstrip("."))
                     if dots == 1:
                         moduleImport = moduleImport[1:]
                     elif dots > 1:
@@ -211,24 +219,24 @@
                         ppath = packagePath
                         while hasInit:
                             ppath = os.path.dirname(ppath)
-                            hasInit = len(glob.glob(os.path.join(
-                                ppath, '__init__.*'))) > 0
-                        shortPackage = (
-                            packagePath.replace(ppath, '')
-                            .replace(os.sep, '.')[1:]
+                            hasInit = (
+                                len(glob.glob(os.path.join(ppath, "__init__.*"))) > 0
+                            )
+                        shortPackage = packagePath.replace(ppath, "").replace(
+                            os.sep, "."
+                        )[1:]
+                        packageList = shortPackage.split(".")[1:]
+                        packageListLen = len(packageList)
+                        moduleImport = ".".join(
+                            packageList[: packageListLen - dots + 1]
+                            + [moduleImport[dots:]]
                         )
-                        packageList = shortPackage.split('.')[1:]
-                        packageListLen = len(packageList)
-                        moduleImport = '.'.join(
-                            packageList[:packageListLen - dots + 1] +
-                            [moduleImport[dots:]])
-                
+
                 if moduleImport in modules:
                     impLst.append(moduleImport)
                 else:
-                    if moduleImport.find('.') == -1:
-                        n = "{0}.{1}".format(modules[module].package,
-                                             moduleImport)
+                    if moduleImport.find(".") == -1:
+                        n = "{0}.{1}".format(modules[module].package, moduleImport)
                         if n in modules:
                             impLst.append(n)
                         else:
@@ -245,27 +253,23 @@
             for moduleImport in impLst:
                 impPackage = moduleImport.rsplit(".", 1)[0]
                 try:
-                    if (
-                        impPackage not in packages[package][1] and
-                        impPackage != package
-                    ):
+                    if impPackage not in packages[package][1] and impPackage != package:
                         packages[package][1].append(impPackage)
                 except KeyError:
                     continue
-        
+
         for package in sorted(packages.keys()):
             if package:
-                relPackage = package.replace(root, '')
-                if relPackage and relPackage[0] == '.':
+                relPackage = package.replace(root, "")
+                if relPackage and relPackage[0] == ".":
                     relPackage = relPackage[1:]
                 else:
                     relPackage = self.tr("<<Application>>")
             else:
                 relPackage = self.tr("<<Others>>")
-            shape = self.__addPackage(
-                relPackage, packages[package][0], 0.0, 0.0)
+            shape = self.__addPackage(relPackage, packages[package][0], 0.0, 0.0)
             self.__shapes[package] = (shape, packages[package][1])
-        
+
         # build a list of routes
         nodes = []
         routes = []
@@ -275,15 +279,15 @@
                 route = (module, rel)
                 if route not in routes:
                     routes.append(route)
-        
+
         self.__arrangeNodes(nodes, routes[:])
         self.__createAssociations(routes)
         self.umlView.autoAdjustSceneSize(limit=True)
-    
+
     def __addPackage(self, name, modules, x, y):
         """
         Private method to add a package to the diagram.
-        
+
         @param name package name to be shown
         @type str
         @param modules list of module names contained in the package
@@ -296,19 +300,26 @@
         @rtype PackageItem
         """
         from .PackageItem import PackageItem, PackageModel
+
         modules.sort()
         pm = PackageModel(name, modules)
-        pw = PackageItem(pm, x, y, noModules=self.noModules, scene=self.scene,
-                         colors=self.umlView.getDrawingColors())
+        pw = PackageItem(
+            pm,
+            x,
+            y,
+            noModules=self.noModules,
+            scene=self.scene,
+            colors=self.umlView.getDrawingColors(),
+        )
         pw.setId(self.umlView.getItemId())
         return pw
-    
+
     def __arrangeNodes(self, nodes, routes, whiteSpaceFactor=1.2):
         """
         Private method to arrange the shapes on the canvas.
-        
+
         The algorithm is borrowed from Boa Constructor.
-        
+
         @param nodes list of nodes to arrange
         @type list of str
         @param routes list of routes
@@ -318,16 +329,16 @@
         @type float
         """
         from . import GraphicsUtilities
+
         generations = GraphicsUtilities.sort(nodes, routes)
-        
+
         # calculate width and height of all elements
         sizes = []
         for generation in generations:
             sizes.append([])
             for child in generation:
-                sizes[-1].append(
-                    self.__shapes[child][0].sceneBoundingRect())
-                
+                sizes[-1].append(self.__shapes[child][0].sceneBoundingRect())
+
         # calculate total width and total height
         width = 0
         height = 0
@@ -336,72 +347,71 @@
         for generation in sizes:
             currentWidth = 0
             currentHeight = 0
-            
+
             for rect in generation:
                 if rect.height() > currentHeight:
                     currentHeight = rect.height()
                 currentWidth += rect.width()
-                
+
             # update totals
             if currentWidth > width:
                 width = currentWidth
             height += currentHeight
-            
+
             # store generation info
             widths.append(currentWidth)
             heights.append(currentHeight)
-        
+
         # add in some whitespace
         width *= whiteSpaceFactor
         height = height * whiteSpaceFactor - 20
         verticalWhiteSpace = 40.0
-        
+
         sceneRect = self.umlView.sceneRect()
         width += 50.0
         height += 50.0
         swidth = sceneRect.width() if width < sceneRect.width() else width
         sheight = sceneRect.height() if height < sceneRect.height() else height
         self.umlView.setSceneSize(swidth, sheight)
-        
+
         # distribute each generation across the width and the
         # generations across height
         y = 10.0
-        for currentWidth, currentHeight, generation in (
-            zip(reversed(widths), reversed(heights), reversed(generations))
+        for currentWidth, currentHeight, generation in zip(
+            reversed(widths), reversed(heights), reversed(generations)
         ):
             x = 10.0
             # whiteSpace is the space between any two elements
-            whiteSpace = (
-                (width - currentWidth - 20) /
-                (len(generation) - 1.0 or 2.0)
-            )
+            whiteSpace = (width - currentWidth - 20) / (len(generation) - 1.0 or 2.0)
             for name in generation:
                 shape = self.__shapes[name][0]
                 shape.setPos(x, y)
                 rect = shape.sceneBoundingRect()
                 x = x + rect.width() + whiteSpace
             y = y + currentHeight + verticalWhiteSpace
-    
+
     def __createAssociations(self, routes):
         """
         Private method to generate the associations between the module shapes.
-        
+
         @param routes list of associations
         @type list of tuple of (str, str)
         """
         from .AssociationItem import AssociationItem, AssociationType
+
         for route in routes:
             assoc = AssociationItem(
                 self.__shapes[route[0]][0],
                 self.__shapes[route[1]][0],
                 AssociationType.IMPORTS,
-                colors=self.umlView.getDrawingColors())
+                colors=self.umlView.getDrawingColors(),
+            )
             self.scene.addItem(assoc)
-    
+
     def parsePersistenceData(self, version, data):
         """
         Public method to parse persisted data.
-        
+
         @param version version of the data
         @type str
         @param data persisted data to be parsed
@@ -411,12 +421,12 @@
         """
         parts = data.split(", ")
         if (
-            len(parts) != 2 or
-            not parts[0].startswith("project=") or
-            not parts[1].startswith("no_modules=")
+            len(parts) != 2
+            or not parts[0].startswith("project=")
+            or not parts[1].startswith("no_modules=")
         ):
             return False
-        
+
         projectFile = parts[0].split("=", 1)[1].strip()
         if projectFile != self.project.getProjectFile():
             res = EricMessageBox.yesNo(
@@ -424,21 +434,22 @@
                 self.tr("Load Diagram"),
                 self.tr(
                     """<p>The diagram belongs to the project <b>{0}</b>."""
-                    """ Shall this project be opened?</p>""").format(
-                    projectFile))
+                    """ Shall this project be opened?</p>"""
+                ).format(projectFile),
+            )
             if res:
                 self.project.openProject(projectFile)
-            
+
         self.noModules = Utilities.toBool(parts[1].split("=", 1)[1].strip())
-        
+
         self.initialize()
-        
+
         return True
-    
+
     def toDict(self):
         """
         Public method to collect data to be persisted.
-        
+
         @return dictionary containing data to be persisted
         @rtype dict
         """
@@ -446,11 +457,11 @@
             "project_name": self.project.getProjectName(),
             "no_modules": self.noModules,
         }
-    
+
     def fromDict(self, version, data):
         """
         Public method to populate the class with data persisted by 'toDict()'.
-        
+
         @param version version of the data
         @type str
         @param data dictionary containing the persisted data
@@ -461,7 +472,7 @@
         """
         try:
             self.noModules = data["no_modules"]
-            
+
             if data["project_name"] != self.project.getProjectName():
                 msg = self.tr(
                     "<p>The diagram belongs to project <b>{0}</b>."
@@ -470,7 +481,7 @@
                 return False, msg
         except KeyError:
             return False, ""
-        
+
         self.initialize()
-        
+
         return True, ""

eric ide

mercurial