UML Diagrams

Mon, 03 May 2021 19:42:27 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Mon, 03 May 2021 19:42:27 +0200
changeset 8286
62ae22eae123
parent 8285
1816b622aef2
child 8287
30eb7bc13d63

UML Diagrams
- improved the diagram layout of the Import Diagram and the Application Diagram

docs/changelog file | annotate | diff | comparison | revisions
eric6/Documentation/Help/source.qch file | annotate | diff | comparison | revisions
eric6/Documentation/Help/source.qhp file | annotate | diff | comparison | revisions
eric6/Documentation/Source/eric6.Graphics.ApplicationDiagramBuilder.html file | annotate | diff | comparison | revisions
eric6/Documentation/Source/eric6.Graphics.ImportsDiagramBuilder.html file | annotate | diff | comparison | revisions
eric6/Graphics/ApplicationDiagramBuilder.py file | annotate | diff | comparison | revisions
eric6/Graphics/GraphicsUtilities.py file | annotate | diff | comparison | revisions
eric6/Graphics/ImportsDiagramBuilder.py file | annotate | diff | comparison | revisions
eric6/Graphics/PackageDiagramBuilder.py file | annotate | diff | comparison | revisions
eric6/Utilities/ModuleParser.py file | annotate | diff | comparison | revisions
eric6/i18n/eric6_cs.ts file | annotate | diff | comparison | revisions
eric6/i18n/eric6_de.qm file | annotate | diff | comparison | revisions
eric6/i18n/eric6_de.ts file | annotate | diff | comparison | revisions
eric6/i18n/eric6_empty.ts file | annotate | diff | comparison | revisions
eric6/i18n/eric6_en.ts file | annotate | diff | comparison | revisions
eric6/i18n/eric6_es.ts file | annotate | diff | comparison | revisions
eric6/i18n/eric6_fr.ts file | annotate | diff | comparison | revisions
eric6/i18n/eric6_it.ts file | annotate | diff | comparison | revisions
eric6/i18n/eric6_pt.ts file | annotate | diff | comparison | revisions
eric6/i18n/eric6_ru.ts file | annotate | diff | comparison | revisions
eric6/i18n/eric6_tr.ts file | annotate | diff | comparison | revisions
eric6/i18n/eric6_zh_CN.ts file | annotate | diff | comparison | revisions
--- a/docs/changelog	Sun May 02 18:16:54 2021 +0200
+++ b/docs/changelog	Mon May 03 19:42:27 2021 +0200
@@ -9,6 +9,8 @@
   -- extended the class items to show class attributes
   -- added code to load a saved UML diagram via the file browser or
      the project others browser
+  -- improved the diagram layout of the Import Diagram and the
+     Application Diagram
 
 Version 21.5:
 - bug fixes
Binary file eric6/Documentation/Help/source.qch has changed
--- a/eric6/Documentation/Help/source.qhp	Sun May 02 18:16:54 2021 +0200
+++ b/eric6/Documentation/Help/source.qhp	Mon May 03 19:42:27 2021 +0200
@@ -1776,8 +1776,10 @@
       <keyword name="ApplicationDiagramBuilder (Constructor)" id="ApplicationDiagramBuilder (Constructor)" ref="eric6.Graphics.ApplicationDiagramBuilder.html#ApplicationDiagramBuilder.__init__" />
       <keyword name="ApplicationDiagramBuilder (Module)" id="ApplicationDiagramBuilder (Module)" ref="eric6.Graphics.ApplicationDiagramBuilder.html" />
       <keyword name="ApplicationDiagramBuilder.__addPackage" id="ApplicationDiagramBuilder.__addPackage" ref="eric6.Graphics.ApplicationDiagramBuilder.html#ApplicationDiagramBuilder.__addPackage" />
+      <keyword name="ApplicationDiagramBuilder.__arrangeNodes" id="ApplicationDiagramBuilder.__arrangeNodes" ref="eric6.Graphics.ApplicationDiagramBuilder.html#ApplicationDiagramBuilder.__arrangeNodes" />
       <keyword name="ApplicationDiagramBuilder.__buildModulesDict" id="ApplicationDiagramBuilder.__buildModulesDict" ref="eric6.Graphics.ApplicationDiagramBuilder.html#ApplicationDiagramBuilder.__buildModulesDict" />
       <keyword name="ApplicationDiagramBuilder.__createAssociations" id="ApplicationDiagramBuilder.__createAssociations" ref="eric6.Graphics.ApplicationDiagramBuilder.html#ApplicationDiagramBuilder.__createAssociations" />
+      <keyword name="ApplicationDiagramBuilder.__findApplicationRoot" id="ApplicationDiagramBuilder.__findApplicationRoot" ref="eric6.Graphics.ApplicationDiagramBuilder.html#ApplicationDiagramBuilder.__findApplicationRoot" />
       <keyword name="ApplicationDiagramBuilder.buildDiagram" id="ApplicationDiagramBuilder.buildDiagram" ref="eric6.Graphics.ApplicationDiagramBuilder.html#ApplicationDiagramBuilder.buildDiagram" />
       <keyword name="ApplicationDiagramBuilder.getPersistenceData" id="ApplicationDiagramBuilder.getPersistenceData" ref="eric6.Graphics.ApplicationDiagramBuilder.html#ApplicationDiagramBuilder.getPersistenceData" />
       <keyword name="ApplicationDiagramBuilder.parsePersistenceData" id="ApplicationDiagramBuilder.parsePersistenceData" ref="eric6.Graphics.ApplicationDiagramBuilder.html#ApplicationDiagramBuilder.parsePersistenceData" />
@@ -8815,6 +8817,7 @@
       <keyword name="ImportsDiagramBuilder (Constructor)" id="ImportsDiagramBuilder (Constructor)" ref="eric6.Graphics.ImportsDiagramBuilder.html#ImportsDiagramBuilder.__init__" />
       <keyword name="ImportsDiagramBuilder (Module)" id="ImportsDiagramBuilder (Module)" ref="eric6.Graphics.ImportsDiagramBuilder.html" />
       <keyword name="ImportsDiagramBuilder.__addModule" id="ImportsDiagramBuilder.__addModule" ref="eric6.Graphics.ImportsDiagramBuilder.html#ImportsDiagramBuilder.__addModule" />
+      <keyword name="ImportsDiagramBuilder.__arrangeNodes" id="ImportsDiagramBuilder.__arrangeNodes" ref="eric6.Graphics.ImportsDiagramBuilder.html#ImportsDiagramBuilder.__arrangeNodes" />
       <keyword name="ImportsDiagramBuilder.__buildModulesDict" id="ImportsDiagramBuilder.__buildModulesDict" ref="eric6.Graphics.ImportsDiagramBuilder.html#ImportsDiagramBuilder.__buildModulesDict" />
       <keyword name="ImportsDiagramBuilder.__createAssociations" id="ImportsDiagramBuilder.__createAssociations" ref="eric6.Graphics.ImportsDiagramBuilder.html#ImportsDiagramBuilder.__createAssociations" />
       <keyword name="ImportsDiagramBuilder.buildDiagram" id="ImportsDiagramBuilder.buildDiagram" ref="eric6.Graphics.ImportsDiagramBuilder.html#ImportsDiagramBuilder.buildDiagram" />
--- a/eric6/Documentation/Source/eric6.Graphics.ApplicationDiagramBuilder.html	Sun May 02 18:16:54 2021 +0200
+++ b/eric6/Documentation/Source/eric6.Graphics.ApplicationDiagramBuilder.html	Mon May 03 19:42:27 2021 +0200
@@ -77,12 +77,20 @@
 <td>Private method to add a package to the diagram.</td>
 </tr>
 <tr>
+<td><a href="#ApplicationDiagramBuilder.__arrangeNodes">__arrangeNodes</a></td>
+<td>Private method to arrange the shapes on the canvas.</td>
+</tr>
+<tr>
 <td><a href="#ApplicationDiagramBuilder.__buildModulesDict">__buildModulesDict</a></td>
 <td>Private method to build a dictionary of modules contained in the application.</td>
 </tr>
 <tr>
 <td><a href="#ApplicationDiagramBuilder.__createAssociations">__createAssociations</a></td>
-<td>Private method to generate the associations between the package shapes.</td>
+<td>Private method to generate the associations between the module shapes.</td>
+</tr>
+<tr>
+<td><a href="#ApplicationDiagramBuilder.__findApplicationRoot">__findApplicationRoot</a></td>
+<td>Private method to find the application root path.</td>
 </tr>
 <tr>
 <td><a href="#ApplicationDiagramBuilder.buildDiagram">buildDiagram</a></td>
@@ -163,6 +171,32 @@
 reference to the package item (PackageItem)
 </dd>
 </dl>
+<a NAME="ApplicationDiagramBuilder.__arrangeNodes" ID="ApplicationDiagramBuilder.__arrangeNodes"></a>
+<h4>ApplicationDiagramBuilder.__arrangeNodes</h4>
+<b>__arrangeNodes</b>(<i>nodes, routes, whiteSpaceFactor=1.2</i>)
+
+<p>
+        Private method to arrange the shapes on the canvas.
+</p>
+<p>
+        The algorithm is borrowed from Boa Constructor.
+</p>
+<dl>
+
+<dt><i>nodes</i> (list of str)</dt>
+<dd>
+list of nodes to arrange
+</dd>
+<dt><i>routes</i> (list of tuple of (str, str))</dt>
+<dd>
+list of routes
+</dd>
+<dt><i>whiteSpaceFactor</i> (float)</dt>
+<dd>
+factor to increase whitespace between
+            items
+</dd>
+</dl>
 <a NAME="ApplicationDiagramBuilder.__buildModulesDict" ID="ApplicationDiagramBuilder.__buildModulesDict"></a>
 <h4>ApplicationDiagramBuilder.__buildModulesDict</h4>
 <b>__buildModulesDict</b>(<i></i>)
@@ -179,16 +213,35 @@
 </dl>
 <a NAME="ApplicationDiagramBuilder.__createAssociations" ID="ApplicationDiagramBuilder.__createAssociations"></a>
 <h4>ApplicationDiagramBuilder.__createAssociations</h4>
-<b>__createAssociations</b>(<i>shapes</i>)
+<b>__createAssociations</b>(<i>routes</i>)
 
 <p>
-        Private method to generate the associations between the package shapes.
+        Private method to generate the associations between the module shapes.
 </p>
 <dl>
 
-<dt><i>shapes</i></dt>
+<dt><i>routes</i> (list of tuple of (str, str))</dt>
 <dd>
-list of shapes
+list of associations
+</dd>
+</dl>
+<a NAME="ApplicationDiagramBuilder.__findApplicationRoot" ID="ApplicationDiagramBuilder.__findApplicationRoot"></a>
+<h4>ApplicationDiagramBuilder.__findApplicationRoot</h4>
+<b>__findApplicationRoot</b>(<i></i>)
+
+<p>
+        Private method to find the application root path.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+application root path
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+str
 </dd>
 </dl>
 <a NAME="ApplicationDiagramBuilder.buildDiagram" ID="ApplicationDiagramBuilder.buildDiagram"></a>
--- a/eric6/Documentation/Source/eric6.Graphics.ImportsDiagramBuilder.html	Sun May 02 18:16:54 2021 +0200
+++ b/eric6/Documentation/Source/eric6.Graphics.ImportsDiagramBuilder.html	Mon May 03 19:42:27 2021 +0200
@@ -81,6 +81,10 @@
 <td>Private method to add a module to the diagram.</td>
 </tr>
 <tr>
+<td><a href="#ImportsDiagramBuilder.__arrangeNodes">__arrangeNodes</a></td>
+<td>Private method to arrange the shapes on the canvas.</td>
+</tr>
+<tr>
 <td><a href="#ImportsDiagramBuilder.__buildModulesDict">__buildModulesDict</a></td>
 <td>Private method to build a dictionary of modules contained in the package.</td>
 </tr>
@@ -176,6 +180,32 @@
 reference to the imports item (ModuleItem)
 </dd>
 </dl>
+<a NAME="ImportsDiagramBuilder.__arrangeNodes" ID="ImportsDiagramBuilder.__arrangeNodes"></a>
+<h4>ImportsDiagramBuilder.__arrangeNodes</h4>
+<b>__arrangeNodes</b>(<i>nodes, routes, whiteSpaceFactor=1.2</i>)
+
+<p>
+        Private method to arrange the shapes on the canvas.
+</p>
+<p>
+        The algorithm is borrowed from Boa Constructor.
+</p>
+<dl>
+
+<dt><i>nodes</i> (list of str)</dt>
+<dd>
+list of nodes to arrange
+</dd>
+<dt><i>routes</i> (list of tuple of (str, str))</dt>
+<dd>
+list of routes
+</dd>
+<dt><i>whiteSpaceFactor</i> (float)</dt>
+<dd>
+factor to increase whitespace between
+            items
+</dd>
+</dl>
 <a NAME="ImportsDiagramBuilder.__buildModulesDict" ID="ImportsDiagramBuilder.__buildModulesDict"></a>
 <h4>ImportsDiagramBuilder.__buildModulesDict</h4>
 <b>__buildModulesDict</b>(<i></i>)
@@ -192,16 +222,16 @@
 </dl>
 <a NAME="ImportsDiagramBuilder.__createAssociations" ID="ImportsDiagramBuilder.__createAssociations"></a>
 <h4>ImportsDiagramBuilder.__createAssociations</h4>
-<b>__createAssociations</b>(<i>shapes</i>)
+<b>__createAssociations</b>(<i>routes</i>)
 
 <p>
         Private method to generate the associations between the module shapes.
 </p>
 <dl>
 
-<dt><i>shapes</i></dt>
+<dt><i>routes</i> (list of tuple of (str, str))</dt>
 <dd>
-list of shapes
+list of associations
 </dd>
 </dl>
 <a NAME="ImportsDiagramBuilder.buildDiagram" ID="ImportsDiagramBuilder.buildDiagram"></a>
--- a/eric6/Graphics/ApplicationDiagramBuilder.py	Sun May 02 18:16:54 2021 +0200
+++ b/eric6/Graphics/ApplicationDiagramBuilder.py	Mon May 03 19:42:27 2021 +0200
@@ -10,7 +10,7 @@
 import os
 import glob
 
-from PyQt5.QtWidgets import QApplication
+from PyQt5.QtWidgets import QApplication, QInputDialog
 
 from E5Gui import E5MessageBox
 from E5Gui.E5ProgressDialog import E5ProgressDialog
@@ -88,27 +88,74 @@
             progress.setValue(tot)
             progress.deleteLater()
         return moduleDict
+    
+    def __findApplicationRoot(self):
+        """
+        Private method to find the application root path.
+        
+        @return application root path
+        @rtype str
+        """
+        candidates = []
+        path = self.project.getProjectPath()
+        init = os.path.join(path, "__init__.py")
+        if os.path.exists(init):
+            # project is a package
+            return path
+        else:
+            # check, if one of the top directories is a package
+            for entry in os.listdir(path):
+                if entry.startswith("."):
+                    # ignore hidden files and directories
+                    continue
+                
+                fullpath = os.path.join(path, entry)
+                if os.path.isdir(fullpath):
+                    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:
+                root, ok = QInputDialog.getItem(
+                    None,
+                    self.tr("Application Diagram"),
+                    self.tr("Select the application directory:"),
+                    sorted(candidates),
+                    0, True)
+                if ok:
+                    return root
+            else:
+                E5MessageBox.warning(
+                    None,
+                    self.tr("Application Diagram"),
+                    self.tr("""No application package could be detected."""
+                            """ Aborting..."""))
+        return None
         
     def buildDiagram(self):
         """
         Public method to build the packages shapes of the diagram.
         """
-        project = (
-            os.path.splitdrive(self.project.getProjectPath())[1]
-            .replace(os.sep, '.')[1:]
-        )
+        rpath = self.__findApplicationRoot()
+        if rpath is None:
+            # no root path detected
+            return
+        
+        root = os.path.splitdrive(rpath)[1].replace(os.sep, '.')[1:]
+        
         packages = {}
-        shapes = {}
-        p = 10
-        y = 10
-        maxHeight = 0
-        sceneRect = self.umlView.sceneRect()
+        self.__shapes = {}
         
         modules = self.__buildModulesDict()
         
         # step 1: build a dictionary of packages
         for module in sorted(modules.keys()):
-            packageName, moduleName = module.rsplit(".", 1)
+            if "." in module:
+                packageName, moduleName = module.rsplit(".", 1)
+            else:
+                packageName, moduleName = "", module
             if packageName in packages:
                 packages[packageName][0].append(moduleName)
             else:
@@ -128,14 +175,14 @@
                         if n in modules:
                             impLst.append(n)
                         else:
-                            n = "{0}.{1}".format(project, moduleImport)
+                            n = "{0}.{1}".format(root, moduleImport)
                             if n in modules:
                                 impLst.append(n)
                             elif n in packages:
                                 n = "{0}.<<Dummy>>".format(n)
                                 impLst.append(n)
                     else:
-                        n = "{0}.{1}".format(project, moduleImport)
+                        n = "{0}.{1}".format(root, moduleImport)
                         if n in modules:
                             impLst.append(n)
             for moduleImport in list(modules[module].from_imports.keys()):
@@ -170,27 +217,30 @@
                         if n in modules:
                             impLst.append(n)
                         else:
-                            n = "{0}.{1}".format(project, moduleImport)
+                            n = "{0}.{1}".format(root, moduleImport)
                             if n in modules:
                                 impLst.append(n)
                             elif n in packages:
                                 n = "{0}.<<Dummy>>".format(n)
                                 impLst.append(n)
                     else:
-                        n = "{0}.{1}".format(project, moduleImport)
+                        n = "{0}.{1}".format(root, moduleImport)
                         if n in modules:
                             impLst.append(n)
             for moduleImport in impLst:
                 impPackage = moduleImport.rsplit(".", 1)[0]
-                if (
-                    impPackage not in packages[package][1] and
-                    impPackage != package
-                ):
-                    packages[package][1].append(impPackage)
-                    
+                try:
+                    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(project, '')
+                relPackage = package.replace(root, '')
                 if relPackage and relPackage[0] == '.':
                     relPackage = relPackage[1:]
                 else:
@@ -199,31 +249,22 @@
                 relPackage = self.tr("<<Others>>")
             shape = self.__addPackage(
                 relPackage, packages[package][0], 0.0, 0.0)
-            shapeRect = shape.sceneBoundingRect()
-            shapes[package] = (shape, packages[package][1])
-            pn = p + shapeRect.width() + 10
-            maxHeight = max(maxHeight, shapeRect.height())
-            if pn > sceneRect.width():
-                p = 10
-                y += maxHeight + 10
-                maxHeight = shapeRect.height()
-                shape.setPos(p, y)
-                p += shapeRect.width() + 10
-            else:
-                shape.setPos(p, y)
-                p = pn
+            self.__shapes[package] = (shape, packages[package][1])
         
-        rect = self.umlView._getDiagramRect(10)
-        sceneRect = self.umlView.sceneRect()
-        if rect.width() > sceneRect.width():
-            sceneRect.setWidth(rect.width())
-        if rect.height() > sceneRect.height():
-            sceneRect.setHeight(rect.height())
-        self.umlView.setSceneSize(sceneRect.width(), sceneRect.height())
+        # build a list of routes
+        nodes = []
+        routes = []
+        for module in self.__shapes:
+            nodes.append(module)
+            for rel in self.__shapes[module][1]:
+                route = (module, rel)
+                if route not in routes:
+                    routes.append(route)
         
-        self.__createAssociations(shapes)
+        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.
@@ -242,21 +283,101 @@
                          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.
         
-    def __createAssociations(self, shapes):
+        The algorithm is borrowed from Boa Constructor.
+        
+        @param nodes list of nodes to arrange
+        @type list of str
+        @param routes list of routes
+        @type list of tuple of (str, str)
+        @param whiteSpaceFactor factor to increase whitespace between
+            items
+        @type float
         """
-        Private method to generate the associations between the package shapes.
+        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())
+                
+        # calculate total width and total height
+        width = 0
+        height = 0
+        widths = []
+        heights = []
+        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)
         
-        @param shapes list of shapes
+        # 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))
+        ):
+            x = 10.0
+            # whiteSpace is the space between any two elements
+            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 package in shapes:
-            for rel in shapes[package][1]:
-                assoc = AssociationItem(
-                    shapes[package][0], shapes[rel][0],
-                    AssociationType.IMPORTS,
-                    colors=self.umlView.getDrawingColors())
-                self.scene.addItem(assoc)
+        for route in routes:
+            assoc = AssociationItem(
+                self.__shapes[route[0]][0],
+                self.__shapes[route[1]][0],
+                AssociationType.IMPORTS,
+                colors=self.umlView.getDrawingColors())
+            self.scene.addItem(assoc)
     
     def getPersistenceData(self):
         """
--- a/eric6/Graphics/GraphicsUtilities.py	Sun May 02 18:16:54 2021 +0200
+++ b/eric6/Graphics/GraphicsUtilities.py	Mon May 03 19:42:27 2021 +0200
@@ -27,8 +27,8 @@
     @param nodes list of nodes to be sorted
     @param routes list of routes between the nodes
     @param noRecursion flag indicating, if recursion errors should be raised
+    @return list of stages
     @exception RecursionError a recursion error was detected
-    @return list of stages
     """
     children, parents = _buildChildrenLists(routes)
     
--- a/eric6/Graphics/ImportsDiagramBuilder.py	Sun May 02 18:16:54 2021 +0200
+++ b/eric6/Graphics/ImportsDiagramBuilder.py	Mon May 03 19:42:27 2021 +0200
@@ -128,11 +128,7 @@
             self.scene.addItem(ct)
             return
         
-        shapes = {}
-        p = 10
-        y = 10
-        maxHeight = 0
-        sceneRect = self.umlView.sceneRect()
+        self.__shapes = {}
         
         modules = self.__buildModulesDict()
         externalMods = []
@@ -175,51 +171,31 @@
                     impLst.append(n)
                     if n not in externalMods:
                         externalMods.append(n)
+            
             classNames = []
-            for cls in list(modules[module].classes.keys()):
-                className = modules[module].classes[cls].name
+            for class_ in list(modules[module].classes.keys()):
+                className = modules[module].classes[class_].name
                 if className not in classNames:
                     classNames.append(className)
             shape = self.__addModule(module, classNames, 0.0, 0.0)
-            shapeRect = shape.sceneBoundingRect()
-            shapes[module] = (shape, impLst)
-            pn = p + shapeRect.width() + 10
-            maxHeight = max(maxHeight, shapeRect.height())
-            if pn > sceneRect.width():
-                p = 10
-                y += maxHeight + 10
-                maxHeight = shapeRect.height()
-                shape.setPos(p, y)
-                p += shapeRect.width() + 10
-            else:
-                shape.setPos(p, y)
-                p = pn
+            self.__shapes[module] = (shape, impLst)
         
         for module in externalMods:
             shape = self.__addModule(module, [], 0.0, 0.0)
-            shapeRect = shape.sceneBoundingRect()
-            shapes[module] = (shape, [])
-            pn = p + shapeRect.width() + 10
-            maxHeight = max(maxHeight, shapeRect.height())
-            if pn > sceneRect.width():
-                p = 10
-                y += maxHeight + 10
-                maxHeight = shapeRect.height()
-                shape.setPos(p, y)
-                p += shapeRect.width() + 10
-            else:
-                shape.setPos(p, y)
-                p = pn
+            self.__shapes[module] = (shape, [])
         
-        rect = self.umlView._getDiagramRect(10)
-        sceneRect = self.umlView.sceneRect()
-        if rect.width() > sceneRect.width():
-            sceneRect.setWidth(rect.width())
-        if rect.height() > sceneRect.height():
-            sceneRect.setHeight(rect.height())
-        self.umlView.setSceneSize(sceneRect.width(), sceneRect.height())
+        # build a list of routes
+        nodes = []
+        routes = []
+        for module in self.__shapes:
+            nodes.append(module)
+            for rel in self.__shapes[module][1]:
+                route = (module, rel)
+                if route not in routes:
+                    routes.append(route)
         
-        self.__createAssociations(shapes)
+        self.__arrangeNodes(nodes, routes[:])
+        self.__createAssociations(routes)
         self.umlView.autoAdjustSceneSize(limit=True)
     
     def __addModule(self, name, classes, x, y):
@@ -241,20 +217,100 @@
         impW.setId(self.umlView.getItemId())
         return impW
     
-    def __createAssociations(self, shapes):
+    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
+        @type list of tuple of (str, str)
+        @param whiteSpaceFactor factor to increase whitespace between
+            items
+        @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())
+                
+        # calculate total width and total height
+        width = 0
+        height = 0
+        widths = []
+        heights = []
+        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))
+        ):
+            x = 10.0
+            # whiteSpace is the space between any two elements
+            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 shapes list of shapes
+        @param routes list of associations
+        @type list of tuple of (str, str)
         """
         from .AssociationItem import AssociationItem, AssociationType
-        for module in list(shapes.keys()):
-            for rel in shapes[module][1]:
-                assoc = AssociationItem(
-                    shapes[module][0], shapes[rel][0],
-                    AssociationType.IMPORTS,
-                    colors=self.umlView.getDrawingColors())
-                self.scene.addItem(assoc)
+        for route in routes:
+            assoc = AssociationItem(
+                self.__shapes[route[0]][0],
+                self.__shapes[route[1]][0],
+                AssociationType.IMPORTS,
+                colors=self.umlView.getDrawingColors())
+            self.scene.addItem(assoc)
     
     def getPersistenceData(self):
         """
--- a/eric6/Graphics/PackageDiagramBuilder.py	Sun May 02 18:16:54 2021 +0200
+++ b/eric6/Graphics/PackageDiagramBuilder.py	Mon May 03 19:42:27 2021 +0200
@@ -243,7 +243,7 @@
             todo = [module.createHierarchy()]
             while todo:
                 hierarchy = todo[0]
-                for className in list(hierarchy.keys()):
+                for className in hierarchy:
                     cw = self.__getCurrentShape(className)
                     if not cw and className.find('.') >= 0:
                         cw = self.__getCurrentShape(className.split('.')[-1])
@@ -335,7 +335,7 @@
             # store generation info
             widths.append(currentWidth)
             heights.append(currentHeight)
-            
+        
         # add in some whitespace
         width *= whiteSpaceFactor
         height = height * whiteSpaceFactor - 20
@@ -344,8 +344,8 @@
         sceneRect = self.umlView.sceneRect()
         width += 50.0
         height += 50.0
-        swidth = width < sceneRect.width() and sceneRect.width() or width
-        sheight = height < sceneRect.height() and sceneRect.height() or height
+        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
--- a/eric6/Utilities/ModuleParser.py	Sun May 02 18:16:54 2021 +0200
+++ b/eric6/Utilities/ModuleParser.py	Mon May 03 19:42:27 2021 +0200
@@ -1213,10 +1213,10 @@
         @return A dictionary with inheritance hierarchies.
         """
         hierarchy = {}
-        for cls in list(list(self.classes.keys())):
-            self.assembleHierarchy(cls, self.classes, [cls], hierarchy)
-        for mod in list(list(self.modules.keys())):
-            self.assembleHierarchy(mod, self.modules, [mod], hierarchy)
+        for class_ in self.classes:
+            self.assembleHierarchy(class_, self.classes, [class_], hierarchy)
+        for module in self.modules:
+            self.assembleHierarchy(module, self.modules, [module], hierarchy)
         return hierarchy
     
     def assembleHierarchy(self, name, classes, path, result):
@@ -1236,16 +1236,16 @@
         """
         rv = {}
         if name in classes:
-            for cls in classes[name].super:
-                if cls not in classes:
-                    rv[cls] = {}
-                    exhausted = path + [cls]
+            for class_ in classes[name].super:
+                if class_ not in classes:
+                    rv[class_] = {}
+                    exhausted = path + [class_]
                     exhausted.reverse()
                     self.addPathToHierarchy(
                         exhausted, result, self.addPathToHierarchy)
                 else:
-                    rv[cls] = self.assembleHierarchy(
-                        cls, classes, path + [cls], result)
+                    rv[class_] = self.assembleHierarchy(
+                        class_, classes, path + [class_], result)
         
         if len(rv) == 0:
             exhausted = path
--- a/eric6/i18n/eric6_cs.ts	Sun May 02 18:16:54 2021 +0200
+++ b/eric6/i18n/eric6_cs.ts	Mon May 03 19:42:27 2021 +0200
@@ -1273,22 +1273,22 @@
         <translation type="unfinished">Parsování modulů...</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="197"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="247"/>
         <source>&lt;&lt;Application&gt;&gt;</source>
         <translation type="unfinished">&lt;&lt;Aplikace&gt;&gt;</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="199"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="249"/>
         <source>&lt;&lt;Others&gt;&gt;</source>
         <translation type="unfinished">&lt;&lt;Ostatní&gt;&gt;</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="288"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="409"/>
         <source>Load Diagram</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="288"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="409"/>
         <source>&lt;p&gt;The diagram belongs to the project &lt;b&gt;{0}&lt;/b&gt;. Shall this project be opened?&lt;/p&gt;</source>
         <translation type="unfinished"></translation>
     </message>
@@ -1298,10 +1298,20 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="69"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="130"/>
         <source>Application Diagram</source>
         <translation type="unfinished">Diagram aplikace</translation>
     </message>
+    <message>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="121"/>
+        <source>Select the application directory:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="130"/>
+        <source>No application package could be detected. Aborting...</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>ApplicationPage</name>
Binary file eric6/i18n/eric6_de.qm has changed
--- a/eric6/i18n/eric6_de.ts	Sun May 02 18:16:54 2021 +0200
+++ b/eric6/i18n/eric6_de.ts	Mon May 03 19:42:27 2021 +0200
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE TS><TS version="2.0" language="de" sourcelanguage="">
+<!DOCTYPE TS>
+<TS version="2.1" language="de">
 <context>
     <name>AboutDialog</name>
     <message>
@@ -1255,22 +1256,22 @@
         <translation>Module werden gelesen …</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="197"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="247"/>
         <source>&lt;&lt;Application&gt;&gt;</source>
         <translation>&lt;&lt;Applikation&gt;&gt;</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="199"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="249"/>
         <source>&lt;&lt;Others&gt;&gt;</source>
         <translation>&lt;&lt;Sonstige&gt;&gt;</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="288"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="409"/>
         <source>Load Diagram</source>
         <translation>Diagramm laden</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="288"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="409"/>
         <source>&lt;p&gt;The diagram belongs to the project &lt;b&gt;{0}&lt;/b&gt;. Shall this project be opened?&lt;/p&gt;</source>
         <translation>&lt;p&gt;Das Diagramm gehört zum Projekt &lt;b&gt;{0}&lt;/b&gt;. Soll dieses Projekt geöffnet werden?&lt;/p&gt;</translation>
     </message>
@@ -1280,10 +1281,20 @@
         <translation>%v/%m Module</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="69"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="130"/>
         <source>Application Diagram</source>
         <translation>Applikations-Diagramm</translation>
     </message>
+    <message>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="121"/>
+        <source>Select the application directory:</source>
+        <translation>Wähle das Applikationsverzeichnis:</translation>
+    </message>
+    <message>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="130"/>
+        <source>No application package could be detected. Aborting...</source>
+        <translation>Es konnte kein Applikationspaket gefunden werden. Abbruch...</translation>
+    </message>
 </context>
 <context>
     <name>ApplicationPage</name>
@@ -2130,8 +2141,8 @@
     </message>
     <message>
         <location filename="../WebBrowser/Bookmarks/BookmarksMenu.py" line="170"/>
-        <source>Open in New Tab<byte value="x9"/>Ctrl+LMB</source>
-        <translation>In neuem Register öffnen<byte value="x9"/>Strg+LMK</translation>
+        <source>Open in New Tab	Ctrl+LMB</source>
+        <translation>In neuem Register öffnen	Strg+LMK</translation>
     </message>
     <message>
         <location filename="../WebBrowser/Bookmarks/BookmarksMenu.py" line="174"/>
@@ -2199,8 +2210,8 @@
     </message>
     <message>
         <location filename="../WebBrowser/Bookmarks/BookmarksToolBar.py" line="90"/>
-        <source>Open in New Tab<byte value="x9"/>Ctrl+LMB</source>
-        <translation>In neuem Register öffnen<byte value="x9"/>Strg+LMK</translation>
+        <source>Open in New Tab	Ctrl+LMB</source>
+        <translation>In neuem Register öffnen	Strg+LMK</translation>
     </message>
     <message>
         <location filename="../WebBrowser/Bookmarks/BookmarksToolBar.py" line="94"/>
@@ -44935,12 +44946,12 @@
     </message>
     <message>
         <location filename="../MicroPython/MicroPythonWidget.py" line="1195"/>
-        <source>&#xc2;&#xb5;Py Chart</source>
+        <source>µPy Chart</source>
         <translation>µPy Chart</translation>
     </message>
     <message>
         <location filename="../MicroPython/MicroPythonWidget.py" line="1278"/>
-        <source>&#xc2;&#xb5;Py Files</source>
+        <source>µPy Files</source>
         <translation>µPy Dateien</translation>
     </message>
     <message>
@@ -84934,8 +84945,8 @@
     </message>
     <message>
         <location filename="../WebBrowser/WebBrowserView.py" line="657"/>
-        <source>Open Link in New Tab<byte value="x9"/>Ctrl+LMB</source>
-        <translation>Link in neuem Fenster öffnen<byte value="x9"/>Strg+LMK</translation>
+        <source>Open Link in New Tab	Ctrl+LMB</source>
+        <translation>Link in neuem Fenster öffnen	Strg+LMK</translation>
     </message>
     <message>
         <location filename="../WebBrowser/WebBrowserView.py" line="663"/>
--- a/eric6/i18n/eric6_empty.ts	Sun May 02 18:16:54 2021 +0200
+++ b/eric6/i18n/eric6_empty.ts	Mon May 03 19:42:27 2021 +0200
@@ -1244,30 +1244,40 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="69"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="130"/>
         <source>Application Diagram</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="197"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="247"/>
         <source>&lt;&lt;Application&gt;&gt;</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="199"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="249"/>
         <source>&lt;&lt;Others&gt;&gt;</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="288"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="409"/>
         <source>Load Diagram</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="288"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="409"/>
         <source>&lt;p&gt;The diagram belongs to the project &lt;b&gt;{0}&lt;/b&gt;. Shall this project be opened?&lt;/p&gt;</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="121"/>
+        <source>Select the application directory:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="130"/>
+        <source>No application package could be detected. Aborting...</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>ApplicationPage</name>
--- a/eric6/i18n/eric6_en.ts	Sun May 02 18:16:54 2021 +0200
+++ b/eric6/i18n/eric6_en.ts	Mon May 03 19:42:27 2021 +0200
@@ -1239,22 +1239,22 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="197"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="247"/>
         <source>&lt;&lt;Application&gt;&gt;</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="199"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="249"/>
         <source>&lt;&lt;Others&gt;&gt;</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="288"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="409"/>
         <source>Load Diagram</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="288"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="409"/>
         <source>&lt;p&gt;The diagram belongs to the project &lt;b&gt;{0}&lt;/b&gt;. Shall this project be opened?&lt;/p&gt;</source>
         <translation type="unfinished"></translation>
     </message>
@@ -1264,10 +1264,20 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="69"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="130"/>
         <source>Application Diagram</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="121"/>
+        <source>Select the application directory:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="130"/>
+        <source>No application package could be detected. Aborting...</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>ApplicationPage</name>
--- a/eric6/i18n/eric6_es.ts	Sun May 02 18:16:54 2021 +0200
+++ b/eric6/i18n/eric6_es.ts	Mon May 03 19:42:27 2021 +0200
@@ -1252,22 +1252,22 @@
         <translation>Analizando módulos...</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="197"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="247"/>
         <source>&lt;&lt;Application&gt;&gt;</source>
         <translation>&lt;&lt;Aplicación&gt;&gt;</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="199"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="249"/>
         <source>&lt;&lt;Others&gt;&gt;</source>
         <translation>&lt;&lt;Otros&gt;&gt;</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="288"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="409"/>
         <source>Load Diagram</source>
         <translation>Cargar Diagrama</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="288"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="409"/>
         <source>&lt;p&gt;The diagram belongs to the project &lt;b&gt;{0}&lt;/b&gt;. Shall this project be opened?&lt;/p&gt;</source>
         <translation>&lt;p&gt;El diagrama pertenece al proyecto &lt;b&gt;{0}&lt;/b&gt;. ¿Abrir proyecto?&lt;/p&gt;</translation>
     </message>
@@ -1277,10 +1277,20 @@
         <translation>%v/%m Módulos</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="69"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="130"/>
         <source>Application Diagram</source>
         <translation>Diagrama de aplicación</translation>
     </message>
+    <message>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="121"/>
+        <source>Select the application directory:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="130"/>
+        <source>No application package could be detected. Aborting...</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>ApplicationPage</name>
--- a/eric6/i18n/eric6_fr.ts	Sun May 02 18:16:54 2021 +0200
+++ b/eric6/i18n/eric6_fr.ts	Mon May 03 19:42:27 2021 +0200
@@ -1300,22 +1300,22 @@
         <translation>Analyse des modules...</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="197"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="247"/>
         <source>&lt;&lt;Application&gt;&gt;</source>
         <translation>&lt;&lt;Application&gt;&gt;</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="199"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="249"/>
         <source>&lt;&lt;Others&gt;&gt;</source>
         <translation>&lt;&lt;Autres&gt;&gt;</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="288"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="409"/>
         <source>Load Diagram</source>
         <translation>Charger le diagramme</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="288"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="409"/>
         <source>&lt;p&gt;The diagram belongs to the project &lt;b&gt;{0}&lt;/b&gt;. Shall this project be opened?&lt;/p&gt;</source>
         <translation>&lt;p&gt; Le diagramme appartient au projet &lt;b&gt;{0}&lt;/b&gt;. Est-ce que ce projet devrqit être ouvert ? &lt;/p&gt;</translation>
     </message>
@@ -1325,10 +1325,20 @@
         <translation>Modules %v/%m</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="69"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="130"/>
         <source>Application Diagram</source>
         <translation>Application Diagramme</translation>
     </message>
+    <message>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="121"/>
+        <source>Select the application directory:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="130"/>
+        <source>No application package could be detected. Aborting...</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>ApplicationPage</name>
--- a/eric6/i18n/eric6_it.ts	Sun May 02 18:16:54 2021 +0200
+++ b/eric6/i18n/eric6_it.ts	Mon May 03 19:42:27 2021 +0200
@@ -1297,22 +1297,22 @@
         <translation>Analisi moduli...</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="197"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="247"/>
         <source>&lt;&lt;Application&gt;&gt;</source>
         <translation>&lt;&lt;Applicazione&gt;&gt;</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="199"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="249"/>
         <source>&lt;&lt;Others&gt;&gt;</source>
         <translation>&lt;&lt;Altri&gt;&gt;</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="288"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="409"/>
         <source>Load Diagram</source>
         <translation>Carico Diagramma</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="288"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="409"/>
         <source>&lt;p&gt;The diagram belongs to the project &lt;b&gt;{0}&lt;/b&gt;. Shall this project be opened?&lt;/p&gt;</source>
         <translation>&lt;p&gt;Il Diagramma appartiene al progetto &lt;b&gt;{0}&lt;/b&gt;. Si deve aprire il progetto?&lt;/p&gt;</translation>
     </message>
@@ -1322,10 +1322,20 @@
         <translation>Moduli %v/%m</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="69"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="130"/>
         <source>Application Diagram</source>
         <translation type="unfinished">Diagrammi dell&apos;applicazione</translation>
     </message>
+    <message>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="121"/>
+        <source>Select the application directory:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="130"/>
+        <source>No application package could be detected. Aborting...</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>ApplicationPage</name>
--- a/eric6/i18n/eric6_pt.ts	Sun May 02 18:16:54 2021 +0200
+++ b/eric6/i18n/eric6_pt.ts	Mon May 03 19:42:27 2021 +0200
@@ -1299,22 +1299,22 @@
         <translation>A analisar módulos...</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="197"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="247"/>
         <source>&lt;&lt;Application&gt;&gt;</source>
         <translation>&lt;&lt;Aplicação&gt;&gt;</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="199"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="249"/>
         <source>&lt;&lt;Others&gt;&gt;</source>
         <translation>&lt;&lt;Outros&gt;&gt;</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="288"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="409"/>
         <source>Load Diagram</source>
         <translation>Carregar Diagrama</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="288"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="409"/>
         <source>&lt;p&gt;The diagram belongs to the project &lt;b&gt;{0}&lt;/b&gt;. Shall this project be opened?&lt;/p&gt;</source>
         <translation>&lt;p&gt;O diagrama pertence ao projeto &lt;b&gt;{0}&lt;/b&gt;. Abrir este projeto?&lt;/p&gt;</translation>
     </message>
@@ -1324,10 +1324,20 @@
         <translation>%v%m Módulos</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="69"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="130"/>
         <source>Application Diagram</source>
         <translation>Diagrama da Aplicação</translation>
     </message>
+    <message>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="121"/>
+        <source>Select the application directory:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="130"/>
+        <source>No application package could be detected. Aborting...</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>ApplicationPage</name>
--- a/eric6/i18n/eric6_ru.ts	Sun May 02 18:16:54 2021 +0200
+++ b/eric6/i18n/eric6_ru.ts	Mon May 03 19:42:27 2021 +0200
@@ -1257,22 +1257,22 @@
         <translation>Разбор модулей...</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="197"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="247"/>
         <source>&lt;&lt;Application&gt;&gt;</source>
         <translation>&lt;&lt;Приложение&gt;&gt;</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="199"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="249"/>
         <source>&lt;&lt;Others&gt;&gt;</source>
         <translation>&lt;&lt;Другие&gt;&gt;</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="288"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="409"/>
         <source>Load Diagram</source>
         <translation>Загрузить диаграмму</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="288"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="409"/>
         <source>&lt;p&gt;The diagram belongs to the project &lt;b&gt;{0}&lt;/b&gt;. Shall this project be opened?&lt;/p&gt;</source>
         <translation>&lt;p&gt;Диаграмма относится к проекту&lt;b&gt;{0}&lt;/b&gt;.Хотите открыть этот проект?&lt;/p&gt;</translation>
     </message>
@@ -1282,10 +1282,20 @@
         <translation>%v из %m модулей</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="69"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="130"/>
         <source>Application Diagram</source>
         <translation>Диаграмма приложения</translation>
     </message>
+    <message>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="121"/>
+        <source>Select the application directory:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="130"/>
+        <source>No application package could be detected. Aborting...</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>ApplicationPage</name>
--- a/eric6/i18n/eric6_tr.ts	Sun May 02 18:16:54 2021 +0200
+++ b/eric6/i18n/eric6_tr.ts	Mon May 03 19:42:27 2021 +0200
@@ -1274,22 +1274,22 @@
         <translation type="unfinished">Moduller İnceleniyor...</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="197"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="247"/>
         <source>&lt;&lt;Application&gt;&gt;</source>
         <translation type="unfinished">&lt;&lt;Uygulama&gt;&gt;</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="199"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="249"/>
         <source>&lt;&lt;Others&gt;&gt;</source>
         <translation type="unfinished">&lt;&lt;Diğerleri&gt;&gt;</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="288"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="409"/>
         <source>Load Diagram</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="288"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="409"/>
         <source>&lt;p&gt;The diagram belongs to the project &lt;b&gt;{0}&lt;/b&gt;. Shall this project be opened?&lt;/p&gt;</source>
         <translation type="unfinished"></translation>
     </message>
@@ -1299,10 +1299,20 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="69"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="130"/>
         <source>Application Diagram</source>
         <translation type="unfinished">Uygulama Şeması</translation>
     </message>
+    <message>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="121"/>
+        <source>Select the application directory:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="130"/>
+        <source>No application package could be detected. Aborting...</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>ApplicationPage</name>
--- a/eric6/i18n/eric6_zh_CN.ts	Sun May 02 18:16:54 2021 +0200
+++ b/eric6/i18n/eric6_zh_CN.ts	Mon May 03 19:42:27 2021 +0200
@@ -1293,22 +1293,22 @@
         <translation>正在分析模块…</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="197"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="247"/>
         <source>&lt;&lt;Application&gt;&gt;</source>
         <translation>&lt;&lt;应用&gt;&gt;</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="199"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="249"/>
         <source>&lt;&lt;Others&gt;&gt;</source>
         <translation>&lt;&lt;其它&gt;&gt;</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="288"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="409"/>
         <source>Load Diagram</source>
         <translation>加载图表</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="288"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="409"/>
         <source>&lt;p&gt;The diagram belongs to the project &lt;b&gt;{0}&lt;/b&gt;. Shall this project be opened?&lt;/p&gt;</source>
         <translation>&lt;p&gt; 该图表在工程下 &lt;b&gt;{0}&lt;/b&gt;. 打开该工程? &lt;/p&gt;</translation>
     </message>
@@ -1318,10 +1318,20 @@
         <translation>%v/%m 模块</translation>
     </message>
     <message>
-        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="69"/>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="130"/>
         <source>Application Diagram</source>
         <translation>应用图表</translation>
     </message>
+    <message>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="121"/>
+        <source>Select the application directory:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../Graphics/ApplicationDiagramBuilder.py" line="130"/>
+        <source>No application package could be detected. Aborting...</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>ApplicationPage</name>

eric ide

mercurial