Wed, 04 Oct 2017 20:06:26 +0200
Fixed some weaknesses in the multi project code.
--- 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)
--- 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): """