Fixed some weaknesses in the multi project code.

Wed, 04 Oct 2017 20:06:26 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Wed, 04 Oct 2017 20:06:26 +0200
changeset 5889
092d06e0193f
parent 5888
f23f3d2b7516
child 5890
22ec89341f5e

Fixed some weaknesses in the multi project code.

APIs/Python3/eric6.api file | annotate | diff | comparison | revisions
Documentation/Help/source.qch file | annotate | diff | comparison | revisions
Documentation/Help/source.qhp file | annotate | diff | comparison | revisions
Documentation/Source/eric6.MultiProject.MultiProject.html file | annotate | diff | comparison | revisions
Documentation/Source/eric6.MultiProject.MultiProjectBrowser.html file | annotate | diff | comparison | revisions
E5XML/MultiProjectReader.py file | annotate | diff | comparison | revisions
MultiProject/MultiProject.py file | annotate | diff | comparison | revisions
MultiProject/MultiProjectBrowser.py file | annotate | diff | comparison | revisions
--- a/APIs/Python3/eric6.api	Tue Oct 03 19:37:44 2017 +0200
+++ b/APIs/Python3/eric6.api	Wed Oct 04 20:06:26 2017 +0200
@@ -3556,7 +3556,8 @@
 eric6.MultiProject.AddProjectDialog.AddProjectDialog.on_nameEdit_textChanged?4(txt)
 eric6.MultiProject.AddProjectDialog.AddProjectDialog?1(parent=None, startdir=None, project=None, categories=None)
 eric6.MultiProject.MultiProject.MultiProject.addE5Actions?4(actions)
-eric6.MultiProject.MultiProject.MultiProject.addProject?4(startdir=None)
+eric6.MultiProject.MultiProject.MultiProject.addNewProject?4(startdir=None)
+eric6.MultiProject.MultiProject.MultiProject.addProject?4(project)
 eric6.MultiProject.MultiProject.MultiProject.changeProjectProperties?4(pro)
 eric6.MultiProject.MultiProject.MultiProject.checkDirty?4()
 eric6.MultiProject.MultiProject.MultiProject.clearRecent?4()
@@ -3570,7 +3571,7 @@
 eric6.MultiProject.MultiProject.MultiProject.getMostRecent?4()
 eric6.MultiProject.MultiProject.MultiProject.getMultiProjectFile?4()
 eric6.MultiProject.MultiProject.MultiProject.getMultiProjectPath?4()
-eric6.MultiProject.MultiProject.MultiProject.getProject?4(fn)
+eric6.MultiProject.MultiProject.MultiProject.getProject?4(uid)
 eric6.MultiProject.MultiProject.MultiProject.getProjects?4()
 eric6.MultiProject.MultiProject.MultiProject.initActions?4()
 eric6.MultiProject.MultiProject.MultiProject.initMenu?4()
@@ -3588,12 +3589,14 @@
 eric6.MultiProject.MultiProject.MultiProject.projectOpened?7
 eric6.MultiProject.MultiProject.MultiProject.projectRemoved?7
 eric6.MultiProject.MultiProject.MultiProject.removeE5Actions?4(actions)
-eric6.MultiProject.MultiProject.MultiProject.removeProject?4(fn)
+eric6.MultiProject.MultiProject.MultiProject.removeProject?4(uid)
 eric6.MultiProject.MultiProject.MultiProject.saveMultiProject?4()
 eric6.MultiProject.MultiProject.MultiProject.saveMultiProjectAs?4()
 eric6.MultiProject.MultiProject.MultiProject.setDirty?4(b)
 eric6.MultiProject.MultiProject.MultiProject.showMenu?7
 eric6.MultiProject.MultiProject.MultiProject?1(project, parent=None, filename=None)
+eric6.MultiProject.MultiProjectBrowser.MultiProjectBrowser.ProjectFileNameRole?7
+eric6.MultiProject.MultiProjectBrowser.MultiProjectBrowser.ProjectUidRole?7
 eric6.MultiProject.MultiProjectBrowser.MultiProjectBrowser?1(multiProject, project, parent=None)
 eric6.MultiProject.PropertiesDialog.PropertiesDialog.storeData?4()
 eric6.MultiProject.PropertiesDialog.PropertiesDialog?1(multiProject, new=True, parent=None)
Binary file Documentation/Help/source.qch has changed
--- a/Documentation/Help/source.qhp	Tue Oct 03 19:37:44 2017 +0200
+++ b/Documentation/Help/source.qhp	Wed Oct 04 20:06:26 2017 +0200
@@ -9947,6 +9947,7 @@
       <keyword name="MultiProject.__syncRecent" id="MultiProject.__syncRecent" ref="eric6.MultiProject.MultiProject.html#MultiProject.__syncRecent" />
       <keyword name="MultiProject.__writeMultiProject" id="MultiProject.__writeMultiProject" ref="eric6.MultiProject.MultiProject.html#MultiProject.__writeMultiProject" />
       <keyword name="MultiProject.addE5Actions" id="MultiProject.addE5Actions" ref="eric6.MultiProject.MultiProject.html#MultiProject.addE5Actions" />
+      <keyword name="MultiProject.addNewProject" id="MultiProject.addNewProject" ref="eric6.MultiProject.MultiProject.html#MultiProject.addNewProject" />
       <keyword name="MultiProject.addProject" id="MultiProject.addProject" ref="eric6.MultiProject.MultiProject.html#MultiProject.addProject" />
       <keyword name="MultiProject.changeProjectProperties" id="MultiProject.changeProjectProperties" ref="eric6.MultiProject.MultiProject.html#MultiProject.changeProjectProperties" />
       <keyword name="MultiProject.checkDirty" id="MultiProject.checkDirty" ref="eric6.MultiProject.MultiProject.html#MultiProject.checkDirty" />
--- a/Documentation/Source/eric6.MultiProject.MultiProject.html	Tue Oct 03 19:37:44 2017 +0200
+++ b/Documentation/Source/eric6.MultiProject.MultiProject.html	Wed Oct 04 20:06:26 2017 +0200
@@ -143,8 +143,11 @@
 <td><a href="#MultiProject.addE5Actions">addE5Actions</a></td>
 <td>Public method to add actions to the list of actions.</td>
 </tr><tr>
+<td><a href="#MultiProject.addNewProject">addNewProject</a></td>
+<td>Public slot used to add a new project to the multi-project.</td>
+</tr><tr>
 <td><a href="#MultiProject.addProject">addProject</a></td>
-<td>Public slot used to add files to the project.</td>
+<td>Public method to add a project to the multi-project.</td>
 </tr><tr>
 <td><a href="#MultiProject.changeProjectProperties">changeProjectProperties</a></td>
 <td>Public method to change the data of a project entry.</td>
@@ -370,16 +373,26 @@
 <dd>
 list of actions (list of E5Action)
 </dd>
-</dl><a NAME="MultiProject.addProject" ID="MultiProject.addProject"></a>
-<h4>MultiProject.addProject</h4>
-<b>addProject</b>(<i>startdir=None</i>)
+</dl><a NAME="MultiProject.addNewProject" ID="MultiProject.addNewProject"></a>
+<h4>MultiProject.addNewProject</h4>
+<b>addNewProject</b>(<i>startdir=None</i>)
 <p>
-        Public slot used to add files to the project.
+        Public slot used to add a new project to the multi-project.
 </p><dl>
 <dt><i>startdir</i></dt>
 <dd>
 start directory for the selection dialog (string)
 </dd>
+</dl><a NAME="MultiProject.addProject" ID="MultiProject.addProject"></a>
+<h4>MultiProject.addProject</h4>
+<b>addProject</b>(<i>project</i>)
+<p>
+        Public method to add a project to the multi-project.
+</p><dl>
+<dt><i>project</i> (dict)</dt>
+<dd>
+dictionary containing the project data to be added
+</dd>
 </dl><a NAME="MultiProject.changeProjectProperties" ID="MultiProject.changeProjectProperties"></a>
 <h4>MultiProject.changeProjectProperties</h4>
 <b>changeProjectProperties</b>(<i>pro</i>)
@@ -502,19 +515,24 @@
 </dd>
 </dl><a NAME="MultiProject.getProject" ID="MultiProject.getProject"></a>
 <h4>MultiProject.getProject</h4>
-<b>getProject</b>(<i>fn</i>)
+<b>getProject</b>(<i>uid</i>)
 <p>
         Public method to get a reference to a project entry.
 </p><dl>
-<dt><i>fn</i></dt>
+<dt><i>uid</i> (str)</dt>
 <dd>
-filename of the project (string)
+UID of the project to get
 </dd>
 </dl><dl>
 <dt>Returns:</dt>
 <dd>
 dictionary containing the project data
 </dd>
+</dl><dl>
+<dt>Return Type:</dt>
+<dd>
+dict
+</dd>
 </dl><a NAME="MultiProject.getProjects" ID="MultiProject.getProjects"></a>
 <h4>MultiProject.getProjects</h4>
 <b>getProjects</b>(<i></i>)
@@ -613,14 +631,14 @@
 </dd>
 </dl><a NAME="MultiProject.removeProject" ID="MultiProject.removeProject"></a>
 <h4>MultiProject.removeProject</h4>
-<b>removeProject</b>(<i>fn</i>)
+<b>removeProject</b>(<i>uid</i>)
 <p>
         Public slot to remove a project from the multi project.
 </p><dl>
-<dt><i>fn</i></dt>
+<dt><i>uid</i> (str)</dt>
 <dd>
-filename of the project to be removed from the multi
-            project (string)
+UID of the project to be removed from the multi
+            project
 </dd>
 </dl><a NAME="MultiProject.saveMultiProject" ID="MultiProject.saveMultiProject"></a>
 <h4>MultiProject.saveMultiProject</h4>
--- a/Documentation/Source/eric6.MultiProject.MultiProjectBrowser.html	Tue Oct 03 19:37:44 2017 +0200
+++ b/Documentation/Source/eric6.MultiProject.MultiProjectBrowser.html	Wed Oct 04 20:06:26 2017 +0200
@@ -48,7 +48,7 @@
 QTreeWidget
 <h3>Class Attributes</h3>
 <table>
-<tr><td>None</td></tr>
+<tr><td>ProjectFileNameRole</td></tr><tr><td>ProjectUidRole</td></tr>
 </table>
 <h3>Class Methods</h3>
 <table>
--- a/E5XML/MultiProjectReader.py	Tue Oct 03 19:37:44 2017 +0200
+++ b/E5XML/MultiProjectReader.py	Wed Oct 04 20:06:26 2017 +0200
@@ -96,7 +96,7 @@
                 if 'category' not in project:
                     # upgrade from 4.2 format
                     project["category"] = ""
-                self.multiProject.projects.append(project)
+                self.multiProject.addProject(project)
                 break
             
             if self.isStartElement():
--- a/MultiProject/MultiProject.py	Tue Oct 03 19:37:44 2017 +0200
+++ b/MultiProject/MultiProject.py	Wed Oct 04 20:06:26 2017 +0200
@@ -91,8 +91,8 @@
         self.description = ""   # description of the multi project
         self.name = ""
         self.opened = False
-        self.projects = []
-        # list of project info; each info entry is a dictionary
+        self.__projects = {}
+        # dict of project info keyed by 'uid'; each info entry is a dictionary
         # 'name'        : name of the project
         # 'file'        : project file name
         # 'master'      : flag indicating the master
@@ -186,20 +186,20 @@
         dirty state of the multi project is changed accordingly.
         """
         removelist = []
-        for project in self.projects:
+        for key, project in self.__projects.items():
             if not os.path.exists(project['file']):
-                removelist.append(project)
+                removelist.append(key)
         
         if removelist:
-            for project in removelist:
-                self.projects.remove(project)
+            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:
+        for project in self.__projects.values():
             if project['category'] and \
                     project['category'] not in self.categories:
                 self.categories.append(project['category'])
@@ -293,10 +293,19 @@
         
         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
+    
     @pyqtSlot()
-    def addProject(self, startdir=None):
+    def addNewProject(self, startdir=None):
         """
-        Public slot used to add files to the project.
+        Public slot used to add a new project to the multi-project.
         
         @param startdir start directory for the selection dialog (string)
         """
@@ -312,13 +321,13 @@
                 dlg.getData()
             
             # step 1: check, if project was already added
-            for project in self.projects:
+            for project in self.__projects.values():
                 if project['file'] == filename:
                     return
             
             # step 2: check, if master should be changed
             if isMaster:
-                for project in self.projects:
+                for project in self.__projects.values():
                     if project['master']:
                         project['master'] = False
                         self.projectDataChanged.emit(project)
@@ -334,7 +343,7 @@
                 'category': category,
                 'uid': uid,
             }
-            self.projects.append(project)
+            self.__projects[uid] = project
             if category not in self.categories:
                 self.categories.append(category)
             self.projectAdded.emit(project)
@@ -348,7 +357,7 @@
         """
         # step 1: check, if master should be changed
         if pro['master']:
-            for project in self.projects:
+            for project in self.__projects.values():
                 if project['master']:
                     if project['uid'] != pro['uid']:
                         project['master'] = False
@@ -357,18 +366,17 @@
                     break
         
         # step 2: change the entry
-        for project in self.projects:
-            if project['uid'] == 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'])
-                self.projectDataChanged.emit(project)
-                self.setDirty(True)
+        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'])
+        self.projectDataChanged.emit(project)
+        self.setDirty(True)
     
     def getProjects(self):
         """
@@ -376,34 +384,35 @@
         
         @return list of all project entries (list of dictionaries)
         """
-        return self.projects
+        return self.__projects.values()
     
-    def getProject(self, fn):
+    def getProject(self, uid):
         """
         Public method to get a reference to a project entry.
         
-        @param fn filename of the project (string)
+        @param uid UID of the project to get
+        @type str
         @return dictionary containing the project data
+        @rtype dict
         """
-        for project in self.projects:
-            if project['file'] == fn:
-                return project
-        
-        return None
+        if uid in self.__projects:
+            return self.__projects[uid]
+        else:
+            return None
     
-    def removeProject(self, fn):
+    def removeProject(self, uid):
         """
         Public slot to remove a project from the multi project.
         
-        @param fn filename of the project to be removed from the multi
-            project (string)
+        @param uid UID of the project to be removed from the multi
+            project
+        @type str
         """
-        for project in self.projects:
-            if project['file'] == fn:
-                self.projects.remove(project)
-                self.projectRemoved.emit(project)
-                self.setDirty(True)
-                break
+        if uid in self.__projects:
+            project = self.__projects[uid]
+            del self.__projects[uid]
+            self.projectRemoved.emit(project)
+            self.setDirty(True)
     
     def __newMultiProject(self):
         """
@@ -587,7 +596,7 @@
         # now close the current project, if it belongs to the multi project
         pfile = self.projectObject.getProjectFile()
         if pfile:
-            for project in self.projects:
+            for project in self.__projects.values():
                 if project['file'] == pfile:
                     if not self.projectObject.closeProject():
                         return False
@@ -690,7 +699,7 @@
             """<p>This opens a dialog for adding a project"""
             """ to the current multiproject.</p>"""
         ))
-        self.addProjectAct.triggered.connect(self.addProject)
+        self.addProjectAct.triggered.connect(self.addNewProject)
         self.actions.append(self.addProjectAct)
 
         self.propsAct = E5Action(
@@ -897,7 +906,7 @@
         @param reopen flag indicating, that the master project should be
             reopened, if it has been opened already (boolean)
         """
-        for project in self.projects:
+        for project in self.__projects.values():
             if project['master']:
                 if reopen or \
                    not self.projectObject.isOpen() or \
@@ -911,7 +920,7 @@
         
         @return name of the master project file (string)
         """
-        for project in self.projects:
+        for project in self.__projects:
             if project['master']:
                 return project['file']
         
@@ -924,7 +933,7 @@
         @return names of the dependent project files (list of strings)
         """
         files = []
-        for project in self.projects:
+        for project in self.__projects.values():
             if not project['master']:
                 files.append(project['file'])
         return files
--- a/MultiProject/MultiProjectBrowser.py	Tue Oct 03 19:37:44 2017 +0200
+++ b/MultiProject/MultiProjectBrowser.py	Wed Oct 04 20:06:26 2017 +0200
@@ -21,6 +21,9 @@
     """
     Class implementing the multi project browser.
     """
+    ProjectFileNameRole = Qt.UserRole
+    ProjectUidRole = Qt.UserRole + 1
+    
     def __init__(self, multiProject, project, parent=None):
         """
         Constructor
@@ -150,6 +153,7 @@
             'master': False,
             'description': "",
             'category': "",
+            'uid': "",
         }
         itm = self.__findProjectItem(project)
         if itm:
@@ -193,7 +197,7 @@
                 return
         
         if not self.__openingProject:
-            filename = itm.data(0, Qt.UserRole)
+            filename = itm.data(0, MultiProjectBrowser.ProjectFileNameRole)
             if filename:
                 self.__openingProject = True
                 self.multiProject.openProject(filename)
@@ -249,7 +253,9 @@
         else:
             itm.setIcon(0, UI.PixmapCache.getIcon("empty.png"))
         itm.setToolTip(0, project['file'])
-        itm.setData(0, Qt.UserRole, project['file'])
+        itm.setData(0, MultiProjectBrowser.ProjectFileNameRole,
+                    project['file'])
+        itm.setData(0, MultiProjectBrowser.ProjectUidRole, project['uid'])
     
     def __findProjectItem(self, project):
         """
@@ -258,12 +264,19 @@
         @param project reference to the project data dictionary
         @return reference to the item (QTreeWidgetItem) or None
         """
+        if project["uid"]:
+            compareData = project["uid"]
+            compareRole = MultiProjectBrowser.ProjectUidRole
+        else:
+            compareData = project["file"]
+            compareRole = MultiProjectBrowser.ProjectFileNameRole
+        
         for topIndex in range(self.topLevelItemCount()):
             topItm = self.topLevelItem(topIndex)
             for childIndex in range(topItm.childCount()):
                 itm = topItm.child(childIndex)
-                data = itm.data(0, Qt.UserRole)
-                if data == project['file']:
+                data = itm.data(0, compareRole)
+                if data == compareData:
                     return itm
         
         return None
@@ -274,9 +287,9 @@
         """
         itm = self.currentItem()
         if itm is not None and itm.parent() is not None:
-            filename = itm.data(0, Qt.UserRole)
-            if filename:
-                self.multiProject.removeProject(filename)
+            uid = itm.data(0, MultiProjectBrowser.ProjectUidRole)
+            if uid:
+                self.multiProject.removeProject(uid)
     
     def __showProjectProperties(self):
         """
@@ -284,9 +297,9 @@
         """
         itm = self.currentItem()
         if itm is not None and itm.parent() is not None:
-            filename = itm.data(0, Qt.UserRole)
-            if filename:
-                project = self.multiProject.getProject(filename)
+            uid = itm.data(0, MultiProjectBrowser.ProjectUidRole)
+            if uid:
+                project = self.multiProject.getProject(uid)
                 if project is not None:
                     from .AddProjectDialog import AddProjectDialog
                     dlg = AddProjectDialog(
@@ -309,7 +322,7 @@
         """
         Private method to add a new project entry.
         """
-        self.multiProject.addProject()
+        self.multiProject.addNewProject()
     
     def __createPopupMenu(self):
         """

eric ide

mercurial