src/eric7/MultiProject/MultiProject.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9238
a7cbf3d61498
--- a/src/eric7/MultiProject/MultiProject.py	Wed Jul 13 11:16:20 2022 +0200
+++ b/src/eric7/MultiProject/MultiProject.py	Wed Jul 13 14:55:47 2022 +0200
@@ -12,9 +12,7 @@
 import contextlib
 import pathlib
 
-from PyQt6.QtCore import (
-    pyqtSignal, pyqtSlot, QFile, QIODevice, QObject, QUuid
-)
+from PyQt6.QtCore import pyqtSignal, pyqtSlot, QFile, QIODevice, QObject, QUuid
 from PyQt6.QtWidgets import QMenu, QDialog, QToolBar
 
 from Globals import recentNameMultiProject
@@ -35,7 +33,7 @@
 class MultiProject(QObject):
     """
     Class implementing the project management functionality.
-    
+
     @signal dirty(bool) emitted when the dirty state changes
     @signal newMultiProject() emitted after a new multi project was generated
     @signal multiProjectOpened() emitted after a multi project file was read
@@ -52,6 +50,7 @@
             has been removed
     @signal projectOpened(filename) emitted after the project has been opened
     """
+
     dirty = pyqtSignal(bool)
     newMultiProject = pyqtSignal()
     multiProjectOpened = pyqtSignal()
@@ -62,40 +61,40 @@
     projectAdded = pyqtSignal(dict)
     projectRemoved = pyqtSignal(dict)
     projectOpened = pyqtSignal(str)
-    
+
     def __init__(self, project, parent=None, filename=None):
         """
         Constructor
-        
+
         @param project reference to the project object (Project.Project)
         @param parent parent widget (usually the ui object) (QWidget)
         @param filename optional filename of a multi project file to open
             (string)
         """
         super().__init__(parent)
-        
+
         self.ui = parent
         self.projectObject = project
-        
+
         self.__initData()
-        
+
         self.__multiProjectFile = MultiProjectFile(self)
-        
+
         self.recent = []
         self.__loadRecent()
-        
+
         if filename is not None:
             self.openMultiProject(filename)
-    
+
     def __initData(self):
         """
         Private method to initialize the multi project data part.
         """
-        self.loaded = False     # flag for the loaded status
-        self.__dirty = False      # dirty flag
-        self.pfile = ""         # name of the multi project file
-        self.ppath = ""         # name of the multi project directory
-        self.description = ""   # description of the multi project
+        self.loaded = False  # flag for the loaded status
+        self.__dirty = False  # dirty flag
+        self.pfile = ""  # name of the multi project file
+        self.ppath = ""  # name of the multi project directory
+        self.description = ""  # description of the multi project
         self.name = ""
         self.opened = False
         self.__projects = {}
@@ -108,7 +107,7 @@
         # 'category'    : name of the group
         # 'uid'         : unique identifier
         self.categories = []
-    
+
     def __loadRecent(self):
         """
         Private method to load the recently opened multi project filenames.
@@ -120,111 +119,107 @@
             for f in rp:
                 if pathlib.Path(f).exists():
                     self.recent.append(f)
-    
+
     def __saveRecent(self):
         """
         Private method to save the list of recently opened filenames.
         """
-        Preferences.Prefs.rsettings.setValue(
-            recentNameMultiProject, self.recent)
+        Preferences.Prefs.rsettings.setValue(recentNameMultiProject, self.recent)
         Preferences.Prefs.rsettings.sync()
-    
+
     def getMostRecent(self):
         """
         Public method to get the most recently opened multiproject.
-        
+
         @return path of the most recently opened multiproject (string)
         """
         if len(self.recent):
             return self.recent[0]
         else:
             return None
-        
+
     def setDirty(self, b):
         """
         Public method to set the dirty state.
-        
+
         It emits the signal dirty(int).
-        
+
         @param b dirty state (boolean)
         """
         self.__dirty = b
         self.saveAct.setEnabled(b)
         self.dirty.emit(bool(b))
-    
+
     def isDirty(self):
         """
         Public method to return the dirty state.
-        
+
         @return dirty state (boolean)
         """
         return self.__dirty
-    
+
     def isOpen(self):
         """
         Public method to return the opened state.
-        
+
         @return open state (boolean)
         """
         return self.opened
-    
+
     def getMultiProjectPath(self):
         """
         Public method to get the multi project path.
-        
+
         @return multi project path (string)
         """
         return self.ppath
-    
+
     def getMultiProjectFile(self):
         """
         Public method to get the path of the multi project file.
-        
+
         @return path of the multi project file (string)
         """
         return self.pfile
-    
+
     def __checkFilesExist(self):
         """
         Private method to check, if the files in a list exist.
-        
+
         The project files are checked for existance in the
         filesystem. Non existant projects are removed from the list and the
         dirty state of the multi project is changed accordingly.
         """
         removelist = []
         for key, project in self.__projects.items():
-            if not os.path.exists(project['file']):
+            if not os.path.exists(project["file"]):
                 removelist.append(key)
-        
+
         if removelist:
             for key in removelist:
                 del self.__projects[key]
             self.setDirty(True)
-    
+
     def __extractCategories(self):
         """
         Private slot to extract the categories used in the project definitions.
         """
         for project in self.__projects.values():
-            if (
-                project['category'] and
-                project['category'] not in self.categories
-            ):
-                self.categories.append(project['category'])
-    
+            if project["category"] and project["category"] not in self.categories:
+                self.categories.append(project["category"])
+
     def getCategories(self):
         """
         Public method to get the list of defined categories.
-        
+
         @return list of categories (list of string)
         """
         return [c for c in self.categories if c]
-    
+
     def __readMultiProject(self, fn):
         """
         Private method to read in a multi project (.emj, .e4m, .e5m) file.
-        
+
         @param fn filename of the multi project file to be read (string)
         @return flag indicating success
         """
@@ -238,6 +233,7 @@
             if f.open(QIODevice.OpenModeFlag.ReadOnly):
                 with EricOverrideCursor():
                     from EricXML.MultiProjectReader import MultiProjectReader
+
                     reader = MultiProjectReader(f, self)
                     reader.readXML()
                     f.close()
@@ -247,30 +243,31 @@
                     self.ui,
                     self.tr("Read Multi Project File"),
                     self.tr(
-                        "<p>The multi project file <b>{0}</b> could not be"
-                        " read.</p>").format(fn))
+                        "<p>The multi project file <b>{0}</b> could not be" " read.</p>"
+                    ).format(fn),
+                )
                 res = False
-        
+
         if res:
             self.pfile = os.path.abspath(fn)
             self.ppath = os.path.abspath(os.path.dirname(fn))
-            
+
             self.__extractCategories()
-            
+
             # insert filename into list of recently opened multi projects
             self.__syncRecent()
-            
+
             self.name = os.path.splitext(os.path.basename(fn))[0]
-            
+
             # check, if the files of the multi project still exist
             self.__checkFilesExist()
-        
+
         return res
 
     def __writeMultiProject(self, fn=None):
         """
         Private method to save the multi project infos to a multi project file.
-        
+
         @param fn optional filename of the multi project file to be written.
             If fn is None, the filename stored in the multi project object
             is used. This is the 'save' action. If fn is given, this filename
@@ -280,83 +277,83 @@
         """
         if fn is None:
             fn = self.pfile
-        
+
         res = self.__multiProjectFile.writeFile(fn)
         if res:
             self.pfile = os.path.abspath(fn)
             self.ppath = os.path.abspath(os.path.dirname(fn))
             self.name = os.path.splitext(os.path.basename(fn))[0]
             self.setDirty(False)
-            
+
             # insert filename into list of recently opened projects
             self.__syncRecent()
-        
+
         return res
-    
+
     def addProject(self, project):
         """
         Public method to add a project to the multi-project.
-        
+
         @param project dictionary containing the project data to be added
         @type dict
         """
-        self.__projects[project['uid']] = project
-    
+        self.__projects[project["uid"]] = project
+
     @pyqtSlot()
     def addNewProject(self, startdir="", category=""):
         """
         Public slot used to add a new project to the multi-project.
-        
+
         @param startdir start directory for the selection dialog
         @type str
         @param category category to be preset
         @type str
         """
         from .AddProjectDialog import AddProjectDialog
+
         if not startdir:
             startdir = self.ppath
         if not startdir:
             startdir = Preferences.getMultiProject("Workspace")
-        dlg = AddProjectDialog(self.ui, startdir=startdir,
-                               categories=self.categories, category=category)
+        dlg = AddProjectDialog(
+            self.ui, startdir=startdir, categories=self.categories, category=category
+        )
         if dlg.exec() == QDialog.DialogCode.Accepted:
-            name, filename, isMaster, description, category, uid = (
-                dlg.getData()
-            )
-            
+            name, filename, isMaster, description, category, uid = dlg.getData()
+
             # step 1: check, if project was already added
             for project in self.__projects.values():
-                if project['file'] == filename:
+                if project["file"] == filename:
                     return
-            
+
             # step 2: check, if master should be changed
             if isMaster:
                 for project in self.__projects.values():
-                    if project['master']:
-                        project['master'] = False
+                    if project["master"]:
+                        project["master"] = False
                         self.projectDataChanged.emit(project)
                         self.setDirty(True)
                         break
-            
+
             # step 3: add the project entry
             project = {
-                'name': name,
-                'file': filename,
-                'master': isMaster,
-                'description': description,
-                'category': category,
-                'uid': uid,
+                "name": name,
+                "file": filename,
+                "master": isMaster,
+                "description": description,
+                "category": category,
+                "uid": uid,
             }
             self.__projects[uid] = project
             if category not in self.categories:
                 self.categories.append(category)
             self.projectAdded.emit(project)
             self.setDirty(True)
-    
+
     def copyProject(self, uid):
         """
         Public method to copy the project with given UID on disk.
-        
+
         @param uid UID of the project to copy
         @type str
         """
@@ -369,84 +366,84 @@
             dstProjectDirectory, ok = EricPathPickerDialog.getPath(
                 self.parent(),
                 self.tr("Copy Project"),
-                self.tr("Enter directory for the new project (must not exist"
-                        " already):"),
+                self.tr(
+                    "Enter directory for the new project (must not exist" " already):"
+                ),
                 mode=EricPathPickerModes.DIRECTORY_MODE,
                 path=srcProjectDirectory,
                 defaultDirectory=startdir,
             )
-            if (
-                ok and
-                dstProjectDirectory and
-                not os.path.exists(dstProjectDirectory)
-            ):
+            if ok and dstProjectDirectory and not os.path.exists(dstProjectDirectory):
                 try:
                     shutil.copytree(srcProjectDirectory, dstProjectDirectory)
                 except shutil.Error:
                     EricMessageBox.critical(
                         self.parent(),
                         self.tr("Copy Project"),
-                        self.tr("<p>The source project <b>{0}</b> could not"
-                                " be copied to its destination <b>{1}</b>."
-                                "</p>").format(srcProjectDirectory,
-                                               dstProjectDirectory))
+                        self.tr(
+                            "<p>The source project <b>{0}</b> could not"
+                            " be copied to its destination <b>{1}</b>."
+                            "</p>"
+                        ).format(srcProjectDirectory, dstProjectDirectory),
+                    )
                     return
-                
+
                 dstUid = QUuid.createUuid().toString()
                 dstProject = {
-                    'name': self.tr("{0} - Copy").format(srcProject["name"]),
-                    'file': os.path.join(dstProjectDirectory,
-                                         os.path.basename(srcProject["file"])),
-                    'master': False,
-                    'description': srcProject["description"],
-                    'category': srcProject["category"],
-                    'uid': dstUid,
+                    "name": self.tr("{0} - Copy").format(srcProject["name"]),
+                    "file": os.path.join(
+                        dstProjectDirectory, os.path.basename(srcProject["file"])
+                    ),
+                    "master": False,
+                    "description": srcProject["description"],
+                    "category": srcProject["category"],
+                    "uid": dstUid,
                 }
                 self.__projects[dstUid] = dstProject
                 self.projectAdded.emit(dstProject)
                 self.setDirty(True)
-    
+
     def changeProjectProperties(self, pro):
         """
         Public method to change the data of a project entry.
-        
+
         @param pro dictionary with the project data (string)
         """
         # step 1: check, if master should be changed
-        if pro['master']:
+        if pro["master"]:
             for project in self.__projects.values():
-                if project['master']:
-                    if project['uid'] != pro['uid']:
-                        project['master'] = False
+                if project["master"]:
+                    if project["uid"] != pro["uid"]:
+                        project["master"] = False
                         self.projectDataChanged.emit(project)
                         self.setDirty(True)
                     break
-        
+
         # step 2: change the entry
-        project = self.__projects[pro['uid']]
+        project = self.__projects[pro["uid"]]
         # project UID is not changeable via interface
-        project['file'] = pro['file']
-        project['name'] = pro['name']
-        project['master'] = pro['master']
-        project['description'] = pro['description']
-        project['category'] = pro['category']
-        if project['category'] not in self.categories:
-            self.categories.append(project['category'])
+        project["file"] = pro["file"]
+        project["name"] = pro["name"]
+        project["master"] = pro["master"]
+        project["description"] = pro["description"]
+        project["category"] = pro["category"]
+        if project["category"] not in self.categories:
+            self.categories.append(project["category"])
         self.projectDataChanged.emit(project)
         self.setDirty(True)
-    
+
     def getProjects(self):
         """
         Public method to get all project entries.
-        
+
         @return list of all project entries (list of dictionaries)
         """
         return self.__projects.values()
-    
+
     def getProject(self, uid):
         """
         Public method to get a reference to a project entry.
-        
+
         @param uid UID of the project to get
         @type str
         @return dictionary containing the project data
@@ -456,11 +453,11 @@
             return self.__projects[uid]
         else:
             return None
-    
+
     def removeProject(self, uid):
         """
         Public slot to remove a project from the multi project.
-        
+
         @param uid UID of the project to be removed from the multi
             project
         @type str
@@ -470,11 +467,11 @@
             del self.__projects[uid]
             self.projectRemoved.emit(project)
             self.setDirty(True)
-    
+
     def deleteProject(self, uid):
         """
         Public slot to delete project(s) from the multi project and disk.
-        
+
         @param uid UID of the project to be removed from the multi
             project
         @type str
@@ -483,20 +480,21 @@
             project = self.__projects[uid]
             projectPath = os.path.dirname(project["file"])
             shutil.rmtree(projectPath, True)
-            
+
             self.removeProject(uid)
-    
+
     def __newMultiProject(self):
         """
         Private slot to build a new multi project.
-        
+
         This method displays the new multi project dialog and initializes
         the multi project object with the data entered.
         """
         if not self.checkDirty():
             return
-            
+
         from .PropertiesDialog import PropertiesDialog
+
         dlg = PropertiesDialog(self, True)
         if dlg.exec() == QDialog.DialogCode.Accepted:
             self.closeMultiProject()
@@ -508,24 +506,25 @@
             self.addProjectAct.setEnabled(True)
             self.propsAct.setEnabled(True)
             self.newMultiProject.emit()
-    
+
     def __showProperties(self):
         """
         Private slot to display the properties dialog.
         """
         from .PropertiesDialog import PropertiesDialog
+
         dlg = PropertiesDialog(self, False)
         if dlg.exec() == QDialog.DialogCode.Accepted:
             dlg.storeData()
             self.setDirty(True)
             self.multiProjectPropertiesChanged.emit()
-    
+
     @pyqtSlot()
     @pyqtSlot(str)
     def openMultiProject(self, fn=None, openMaster=True):
         """
         Public slot to open a multi project.
-        
+
         @param fn optional filename of the multi project file to be
             read
         @type str
@@ -535,49 +534,52 @@
         """
         if not self.checkDirty():
             return
-        
+
         if fn is None:
             fn = EricFileDialog.getOpenFileName(
                 self.parent(),
                 self.tr("Open Multi Project"),
-                Preferences.getMultiProject("Workspace") or
-                Utilities.getHomeDir(),
-                self.tr("Multi Project Files (*.emj);;"
-                        "XML Multi Project Files (*.e5m *.e4m)"))
-            
+                Preferences.getMultiProject("Workspace") or Utilities.getHomeDir(),
+                self.tr(
+                    "Multi Project Files (*.emj);;"
+                    "XML Multi Project Files (*.e5m *.e4m)"
+                ),
+            )
+
             if fn == "":
                 fn = None
-        
+
         if fn is not None:
             self.closeMultiProject()
             ok = self.__readMultiProject(fn)
             if ok:
                 self.opened = True
-                
+
                 self.closeAct.setEnabled(True)
                 self.saveasAct.setEnabled(True)
                 self.addProjectAct.setEnabled(True)
                 self.propsAct.setEnabled(True)
-                
+
                 self.multiProjectOpened.emit()
-                
+
                 if openMaster and Preferences.getMultiProject(
-                        "OpenMasterAutomatically"):
+                    "OpenMasterAutomatically"
+                ):
                     self.__openMasterProject(False)
-    
+
     def saveMultiProject(self):
         """
         Public slot to save the current multi project.
-        
+
         @return flag indicating success
         @rtype bool
         """
         if self.isDirty():
             if len(self.pfile) > 0:
                 if self.pfile.endswith((".e4m", ".e5m")):
-                    self.pfile = (self.pfile
-                                  .replace(".e4m", ".emj")
-                                  .replace(".e5m", ".emj"))
+                    self.pfile = self.pfile.replace(".e4m", ".emj").replace(
+                        ".e5m", ".emj"
+                    )
                     self.__syncRecent()
                 ok = self.__writeMultiProject()
             else:
@@ -585,20 +587,19 @@
         else:
             ok = True
         return ok
-    
+
     def saveMultiProjectAs(self):
         """
         Public slot to save the current multi project to a different file.
-        
+
         @return flag indicating success
         @rtype bool
         """
         defaultFilter = self.tr("Multi Project Files (*.emj)")
         defaultPath = (
             self.ppath
-            if self.ppath else
-            (Preferences.getMultiProject("Workspace") or
-             Utilities.getHomeDir())
+            if self.ppath
+            else (Preferences.getMultiProject("Workspace") or Utilities.getHomeDir())
         )
         fn, selectedFilter = EricFileDialog.getSaveFileNameAndFilter(
             self.parent(),
@@ -606,8 +607,9 @@
             defaultPath,
             self.tr("Multi Project Files (*.emj)"),
             defaultFilter,
-            EricFileDialog.DontConfirmOverwrite)
-        
+            EricFileDialog.DontConfirmOverwrite,
+        )
+
         if fn:
             fpath = pathlib.Path(fn)
             if not fpath.suffix:
@@ -618,25 +620,27 @@
                 res = EricMessageBox.yesNo(
                     self.parent(),
                     self.tr("Save File"),
-                    self.tr("<p>The file <b>{0}</b> already exists."
-                            " Overwrite it?</p>").format(fn),
-                    icon=EricMessageBox.Warning)
+                    self.tr(
+                        "<p>The file <b>{0}</b> already exists." " Overwrite it?</p>"
+                    ).format(fn),
+                    icon=EricMessageBox.Warning,
+                )
                 if not res:
                     return False
-                
+
             self.name = fpath.stem
             self.__writeMultiProject(str(fpath))
-            
+
             self.multiProjectClosed.emit()
             self.multiProjectOpened.emit()
             return True
         else:
             return False
-    
+
     def checkDirty(self):
         """
         Public method to check the dirty status and open a message window.
-        
+
         @return flag indicating whether this operation was successful (boolean)
         """
         if self.isDirty():
@@ -644,46 +648,47 @@
                 self.parent(),
                 self.tr("Close Multiproject"),
                 self.tr("The current multiproject has unsaved changes."),
-                self.saveMultiProject)
+                self.saveMultiProject,
+            )
             if res:
                 self.setDirty(False)
             return res
-        
+
         return True
-    
+
     def closeMultiProject(self):
         """
         Public slot to close the current multi project.
-        
+
         @return flag indicating success (boolean)
         """
         # save the list of recently opened projects
         self.__saveRecent()
-        
+
         if not self.isOpen():
             return True
-        
+
         if not self.checkDirty():
             return False
-        
+
         # now close the current project, if it belongs to the multi project
         pfile = self.projectObject.getProjectFile()
         if pfile:
             for project in self.__projects.values():
-                if project['file'] == pfile:
+                if project["file"] == pfile:
                     if not self.projectObject.closeProject():
                         return False
                     break
-        
+
         self.__initData()
         self.closeAct.setEnabled(False)
         self.saveasAct.setEnabled(False)
         self.saveAct.setEnabled(False)
         self.addProjectAct.setEnabled(False)
         self.propsAct.setEnabled(False)
-        
+
         self.multiProjectClosed.emit()
-        
+
         return True
 
     def initActions(self):
@@ -691,102 +696,141 @@
         Public slot to initialize the multi project related actions.
         """
         self.actions = []
-        
+
         self.actGrp1 = createActionGroup(self)
-        
+
         act = EricAction(
-            self.tr('New multiproject'),
+            self.tr("New multiproject"),
             UI.PixmapCache.getIcon("multiProjectNew"),
-            self.tr('&New...'), 0, 0,
-            self.actGrp1, 'multi_project_new')
-        act.setStatusTip(self.tr('Generate a new multiproject'))
-        act.setWhatsThis(self.tr(
-            """<b>New...</b>"""
-            """<p>This opens a dialog for entering the info for a"""
-            """ new multiproject.</p>"""
-        ))
+            self.tr("&New..."),
+            0,
+            0,
+            self.actGrp1,
+            "multi_project_new",
+        )
+        act.setStatusTip(self.tr("Generate a new multiproject"))
+        act.setWhatsThis(
+            self.tr(
+                """<b>New...</b>"""
+                """<p>This opens a dialog for entering the info for a"""
+                """ new multiproject.</p>"""
+            )
+        )
         act.triggered.connect(self.__newMultiProject)
         self.actions.append(act)
 
         act = EricAction(
-            self.tr('Open multiproject'),
+            self.tr("Open multiproject"),
             UI.PixmapCache.getIcon("multiProjectOpen"),
-            self.tr('&Open...'), 0, 0,
-            self.actGrp1, 'multi_project_open')
-        act.setStatusTip(self.tr('Open an existing multiproject'))
-        act.setWhatsThis(self.tr(
-            """<b>Open...</b>"""
-            """<p>This opens an existing multiproject.</p>"""
-        ))
+            self.tr("&Open..."),
+            0,
+            0,
+            self.actGrp1,
+            "multi_project_open",
+        )
+        act.setStatusTip(self.tr("Open an existing multiproject"))
+        act.setWhatsThis(
+            self.tr(
+                """<b>Open...</b>""" """<p>This opens an existing multiproject.</p>"""
+            )
+        )
         act.triggered.connect(self.openMultiProject)
         self.actions.append(act)
 
         self.closeAct = EricAction(
-            self.tr('Close multiproject'),
+            self.tr("Close multiproject"),
             UI.PixmapCache.getIcon("multiProjectClose"),
-            self.tr('&Close'), 0, 0, self, 'multi_project_close')
-        self.closeAct.setStatusTip(self.tr(
-            'Close the current multiproject'))
-        self.closeAct.setWhatsThis(self.tr(
-            """<b>Close</b>"""
-            """<p>This closes the current multiproject.</p>"""
-        ))
+            self.tr("&Close"),
+            0,
+            0,
+            self,
+            "multi_project_close",
+        )
+        self.closeAct.setStatusTip(self.tr("Close the current multiproject"))
+        self.closeAct.setWhatsThis(
+            self.tr(
+                """<b>Close</b>""" """<p>This closes the current multiproject.</p>"""
+            )
+        )
         self.closeAct.triggered.connect(self.closeMultiProject)
         self.actions.append(self.closeAct)
 
         self.saveAct = EricAction(
-            self.tr('Save multiproject'),
+            self.tr("Save multiproject"),
             UI.PixmapCache.getIcon("multiProjectSave"),
-            self.tr('&Save'), 0, 0, self, 'multi_project_save')
-        self.saveAct.setStatusTip(self.tr('Save the current multiproject'))
-        self.saveAct.setWhatsThis(self.tr(
-            """<b>Save</b>"""
-            """<p>This saves the current multiproject.</p>"""
-        ))
+            self.tr("&Save"),
+            0,
+            0,
+            self,
+            "multi_project_save",
+        )
+        self.saveAct.setStatusTip(self.tr("Save the current multiproject"))
+        self.saveAct.setWhatsThis(
+            self.tr("""<b>Save</b>""" """<p>This saves the current multiproject.</p>""")
+        )
         self.saveAct.triggered.connect(self.saveMultiProject)
         self.actions.append(self.saveAct)
 
         self.saveasAct = EricAction(
-            self.tr('Save multiproject as'),
+            self.tr("Save multiproject as"),
             UI.PixmapCache.getIcon("multiProjectSaveAs"),
-            self.tr('Save &as...'), 0, 0, self,
-            'multi_project_save_as')
-        self.saveasAct.setStatusTip(self.tr(
-            'Save the current multiproject to a new file'))
-        self.saveasAct.setWhatsThis(self.tr(
-            """<b>Save as</b>"""
-            """<p>This saves the current multiproject to a new file.</p>"""
-        ))
+            self.tr("Save &as..."),
+            0,
+            0,
+            self,
+            "multi_project_save_as",
+        )
+        self.saveasAct.setStatusTip(
+            self.tr("Save the current multiproject to a new file")
+        )
+        self.saveasAct.setWhatsThis(
+            self.tr(
+                """<b>Save as</b>"""
+                """<p>This saves the current multiproject to a new file.</p>"""
+            )
+        )
         self.saveasAct.triggered.connect(self.saveMultiProjectAs)
         self.actions.append(self.saveasAct)
 
         self.addProjectAct = EricAction(
-            self.tr('Add project to multiproject'),
+            self.tr("Add project to multiproject"),
             UI.PixmapCache.getIcon("fileProject"),
-            self.tr('Add &project...'), 0, 0,
-            self, 'multi_project_add_project')
-        self.addProjectAct.setStatusTip(self.tr(
-            'Add a project to the current multiproject'))
-        self.addProjectAct.setWhatsThis(self.tr(
-            """<b>Add project...</b>"""
-            """<p>This opens a dialog for adding a project"""
-            """ to the current multiproject.</p>"""
-        ))
+            self.tr("Add &project..."),
+            0,
+            0,
+            self,
+            "multi_project_add_project",
+        )
+        self.addProjectAct.setStatusTip(
+            self.tr("Add a project to the current multiproject")
+        )
+        self.addProjectAct.setWhatsThis(
+            self.tr(
+                """<b>Add project...</b>"""
+                """<p>This opens a dialog for adding a project"""
+                """ to the current multiproject.</p>"""
+            )
+        )
         self.addProjectAct.triggered.connect(self.addNewProject)
         self.actions.append(self.addProjectAct)
 
         self.propsAct = EricAction(
-            self.tr('Multiproject properties'),
+            self.tr("Multiproject properties"),
             UI.PixmapCache.getIcon("multiProjectProps"),
-            self.tr('&Properties...'), 0, 0, self,
-            'multi_project_properties')
-        self.propsAct.setStatusTip(self.tr(
-            'Show the multiproject properties'))
-        self.propsAct.setWhatsThis(self.tr(
-            """<b>Properties...</b>"""
-            """<p>This shows a dialog to edit the multiproject"""
-            """ properties.</p>"""
-        ))
+            self.tr("&Properties..."),
+            0,
+            0,
+            self,
+            "multi_project_properties",
+        )
+        self.propsAct.setStatusTip(self.tr("Show the multiproject properties"))
+        self.propsAct.setWhatsThis(
+            self.tr(
+                """<b>Properties...</b>"""
+                """<p>This shows a dialog to edit the multiproject"""
+                """ properties.</p>"""
+            )
+        )
         self.propsAct.triggered.connect(self.__showProperties)
         self.actions.append(self.propsAct)
 
@@ -795,27 +839,26 @@
         self.saveasAct.setEnabled(False)
         self.addProjectAct.setEnabled(False)
         self.propsAct.setEnabled(False)
-    
+
     def initMenu(self):
         """
         Public slot to initialize the multi project menu.
-        
+
         @return the menu generated (QMenu)
         """
-        menu = QMenu(self.tr('&Multiproject'), self.parent())
-        self.recentMenu = QMenu(self.tr('Open &Recent Multiprojects'),
-                                menu)
-        
+        menu = QMenu(self.tr("&Multiproject"), self.parent())
+        self.recentMenu = QMenu(self.tr("Open &Recent Multiprojects"), menu)
+
         self.__menus = {
             "Main": menu,
             "Recent": self.recentMenu,
         }
-        
+
         # connect the aboutToShow signals
         self.recentMenu.aboutToShow.connect(self.__showContextMenuRecent)
         self.recentMenu.triggered.connect(self.__openRecent)
         menu.aboutToShow.connect(self.__showMenu)
-        
+
         # build the main menu
         menu.setTearOffEnabled(True)
         menu.addActions(self.actGrp1.actions())
@@ -829,14 +872,14 @@
         menu.addAction(self.addProjectAct)
         menu.addSeparator()
         menu.addAction(self.propsAct)
-        
+
         self.menu = menu
         return menu
-    
+
     def initToolbar(self, toolbarManager):
         """
         Public slot to initialize the multi project toolbar.
-        
+
         @param toolbarManager reference to a toolbar manager object
             (EricToolBarManager)
         @return the toolbar generated (QToolBar)
@@ -844,28 +887,28 @@
         tb = QToolBar(self.tr("Multiproject"), self.ui)
         tb.setIconSize(UI.Config.ToolBarIconSize)
         tb.setObjectName("MultiProjectToolbar")
-        tb.setToolTip(self.tr('Multiproject'))
-        
+        tb.setToolTip(self.tr("Multiproject"))
+
         tb.addActions(self.actGrp1.actions())
         tb.addAction(self.closeAct)
         tb.addSeparator()
         tb.addAction(self.saveAct)
         tb.addAction(self.saveasAct)
-        
+
         toolbarManager.addToolBar(tb, tb.windowTitle())
         toolbarManager.addAction(self.addProjectAct, tb.windowTitle())
         toolbarManager.addAction(self.propsAct, tb.windowTitle())
-        
+
         return tb
-    
+
     def __showMenu(self):
         """
         Private method to set up the multi project menu.
         """
         self.menuRecentAct.setEnabled(len(self.recent) > 0)
-        
+
         self.showMenu.emit("Main", self.__menus["Main"])
-    
+
     def __syncRecent(self):
         """
         Private method to synchronize the list of recently opened multi
@@ -879,75 +922,76 @@
         if len(self.recent) > maxRecent:
             self.recent = self.recent[:maxRecent]
         self.__saveRecent()
-    
+
     def __showContextMenuRecent(self):
         """
         Private method to set up the recent multi projects menu.
         """
         self.__loadRecent()
-        
+
         self.recentMenu.clear()
-        
+
         for idx, rp in enumerate(self.recent, start=1):
-            formatStr = '&{0:d}. {1}' if idx < 10 else '{0:d}. {1}'
+            formatStr = "&{0:d}. {1}" if idx < 10 else "{0:d}. {1}"
             act = self.recentMenu.addAction(
                 formatStr.format(
-                    idx,
-                    Utilities.compactPath(rp, self.ui.maxMenuFilePathLen)))
+                    idx, Utilities.compactPath(rp, self.ui.maxMenuFilePathLen)
+                )
+            )
             act.setData(rp)
             act.setEnabled(pathlib.Path(rp).exists())
-        
+
         self.recentMenu.addSeparator()
-        self.recentMenu.addAction(self.tr('&Clear'), self.clearRecent)
-    
+        self.recentMenu.addAction(self.tr("&Clear"), self.clearRecent)
+
     def __openRecent(self, act):
         """
         Private method to open a multi project from the list of rencently
         opened multi projects.
-        
+
         @param act reference to the action that triggered (QAction)
         """
         file = act.data()
         if file:
             self.openMultiProject(file)
-    
+
     def clearRecent(self):
         """
         Public method to clear the recent multi projects menu.
         """
         self.recent = []
         self.__saveRecent()
-    
+
     def getActions(self):
         """
         Public method to get a list of all actions.
-        
+
         @return list of all actions (list of EricAction)
         """
         return self.actions[:]
-    
+
     def addEricActions(self, actions):
         """
         Public method to add actions to the list of actions.
-        
+
         @param actions list of actions (list of EricAction)
         """
         self.actions.extend(actions)
-    
+
     def removeEricActions(self, actions):
         """
         Public method to remove actions from the list of actions.
-        
+
         @param actions list of actions (list of EricAction)
         """
         for act in actions:
             with contextlib.suppress(ValueError):
                 self.actions.remove(act)
-    
+
     def getMenu(self, menuName):
         """
         Public method to get a reference to the main menu or a submenu.
-        
+
         @param menuName name of the menu (string)
         @return reference to the requested menu (QMenu) or None
         """
@@ -955,53 +999,52 @@
             return self.__menus[menuName]
         except KeyError:
             return None
-    
+
     def openProject(self, filename):
         """
         Public slot to open a project.
-        
+
         @param filename filename of the project file (string)
         """
         self.projectObject.openProject(filename)
         self.projectOpened.emit(filename)
-    
+
     def __openMasterProject(self, reopen=True):
         """
         Private slot to open the master project.
-        
+
         @param reopen flag indicating, that the master project should be
             reopened, if it has been opened already (boolean)
         """
         for project in self.__projects.values():
-            if (
-                project['master'] and
-                (reopen or
-                 not self.projectObject.isOpen() or
-                 self.projectObject.getProjectFile() != project['file'])
+            if project["master"] and (
+                reopen
+                or not self.projectObject.isOpen()
+                or self.projectObject.getProjectFile() != project["file"]
             ):
-                self.openProject(project['file'])
+                self.openProject(project["file"])
                 return
-    
+
     def getMasterProjectFile(self):
         """
         Public method to get the filename of the master project.
-        
+
         @return name of the master project file (string)
         """
         for project in self.__projects:
-            if project['master']:
-                return project['file']
-        
+            if project["master"]:
+                return project["file"]
+
         return None
-    
+
     def getDependantProjectFiles(self):
         """
         Public method to get the filenames of the dependent projects.
-        
+
         @return names of the dependent project files (list of strings)
         """
         files = []
         for project in self.__projects.values():
-            if not project['master']:
-                files.append(project['file'])
+            if not project["master"]:
+                files.append(project["file"])
         return files

eric ide

mercurial