--- a/MultiProject/MultiProjectBrowser.py Sun Mar 30 22:00:14 2014 +0200 +++ b/MultiProject/MultiProjectBrowser.py Thu Apr 03 23:05:31 2014 +0200 @@ -10,14 +10,14 @@ from __future__ import unicode_literals from PyQt4.QtCore import Qt -from PyQt4.QtGui import QListWidget, QListWidgetItem, QDialog, QMenu +from PyQt4.QtGui import QTreeWidget, QTreeWidgetItem, QDialog, QMenu from E5Gui.E5Application import e5App import UI.PixmapCache -class MultiProjectBrowser(QListWidget): +class MultiProjectBrowser(QTreeWidget): """ Class implementing the multi project browser. """ @@ -33,6 +33,10 @@ self.setWindowIcon(UI.PixmapCache.getIcon("eric.png")) self.setAlternatingRowColors(True) + self.setHeaderHidden(True) + self.setItemsExpandable(False) + self.setRootIsDecorated(False) + self.setSortingEnabled(True) self.__openingProject = False @@ -73,7 +77,7 @@ for project in self.multiProject.getProjects(): self.__addProject(project) - self.sortItems() + self.sortItems(0, Qt.AscendingOrder) def __multiProjectClosed(self): """ @@ -88,7 +92,7 @@ @param project reference to the project data dictionary """ self.__addProject(project) - self.sortItems() + self.sortItems(0, Qt.AscendingOrder) def __projectRemoved(self, project): """ @@ -96,10 +100,14 @@ @param project reference to the project data dictionary """ - row = self.__findProjectItem(project) - if row > -1: - itm = self.takeItem(row) + itm = self.__findProjectItem(project) + if itm: + parent = itm.parent() + parent.removeChild(itm) del itm + if parent.childCount() == 0: + top = self.takeTopLevelItem(self.indexOfTopLevelItem(parent)) + del top def __projectDataChanged(self, project): """ @@ -107,11 +115,16 @@ @param project reference to the project data dictionary """ - row = self.__findProjectItem(project) - if row > -1: - self.__setItemData(self.item(row), project) + itm = self.__findProjectItem(project) + if itm: + parent = itm.parent() + if parent.text(0) != project["category"]: + self.__projectRemoved(project) + self.__addProject(project) + else: + self.__setItemData(itm, project) - self.sortItems() + self.sortItems(0, Qt.AscendingOrder) def __projectOpened(self, projectfile): """ @@ -124,10 +137,11 @@ 'file': projectfile, 'master': False, 'description': "", + 'category': "", } - row = self.__findProjectItem(project) - if row > -1: - self.item(row).setSelected(True) + itm = self.__findProjectItem(project) + if itm: + itm.setSelected(True) def __contextMenuRequested(self, coord): """ @@ -136,7 +150,7 @@ @param coord the position of the mouse pointer (QPoint) """ itm = self.itemAt(coord) - if itm is None: + if itm is None or itm.parent() is None: self.__backMenu.popup(self.mapToGlobal(coord)) else: self.__menu.popup(self.mapToGlobal(coord)) @@ -145,15 +159,15 @@ """ Private slot to open a project. - @param itm reference to the project item to be opened (QListWidgetItem) + @param itm reference to the project item to be opened (QTreeWidgetItem) """ if itm is None: itm = self.currentItem() - if itm is None: + if itm is None or itm.parent() is None: return if not self.__openingProject: - filename = itm.data(Qt.UserRole) + filename = itm.data(0, Qt.UserRole) if filename: self.__openingProject = True self.multiProject.openProject(filename) @@ -163,54 +177,78 @@ ## Private methods below ########################################################################### + def __findCategoryItem(self, category): + """ + Private method to find the item for a category. + + @param category category to search for (string) + @return reference to the category item or None, if there is + no such item (QTreeWidgetItem or None) + """ + if category == "": + category = self.tr("Not categorized") + for index in range(self.topLevelItemCount()): + itm = self.topLevelItem(index) + if itm.text(0) == category: + return itm + + return None + def __addProject(self, project): """ Private method to add a project to the list. @param project reference to the project data dictionary """ - itm = QListWidgetItem(self) + parent = self.__findCategoryItem(project['category']) + if parent is None: + if project['category']: + parent = QTreeWidgetItem(self, [project['category']]) + else: + parent = QTreeWidgetItem(self, [self.tr("Not categorized")]) + parent.setExpanded(True) + itm = QTreeWidgetItem(parent) self.__setItemData(itm, project) def __setItemData(self, itm, project): """ Private method to set the data of a project item. - @param itm reference to the item to be set (QListWidgetItem) + @param itm reference to the item to be set (QTreeWidgetItem) @param project reference to the project data dictionary """ - itm.setText(project['name']) + itm.setText(0, project['name']) if project['master']: - itm.setIcon(UI.PixmapCache.getIcon("masterProject.png")) + itm.setIcon(0, UI.PixmapCache.getIcon("masterProject.png")) else: - itm.setIcon(UI.PixmapCache.getIcon("empty.png")) - itm.setToolTip(project['file']) - itm.setData(Qt.UserRole, project['file']) + itm.setIcon(0, UI.PixmapCache.getIcon("empty.png")) + itm.setToolTip(0, project['file']) + itm.setData(0, Qt.UserRole, project['file']) def __findProjectItem(self, project): """ Private method to search a specific project item. @param project reference to the project data dictionary - @return row number of the project, -1 if not found (integer) + @return reference to the item (QTreeWidgetItem) or None """ - row = 0 - while row < self.count(): - itm = self.item(row) - data = itm.data(Qt.UserRole) - if data == project['file']: - return row - row += 1 + 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']: + return itm - return -1 + return None def __removeProject(self): """ Private method to handle the Remove context menu entry. """ itm = self.currentItem() - if itm is not None: - filename = itm.data(Qt.UserRole) + if itm is not None and itm.parent() is not None: + filename = itm.data(0, Qt.UserRole) if filename: self.multiProject.removeProject(filename) @@ -219,20 +257,24 @@ Private method to show the data of a project entry. """ itm = self.currentItem() - if itm is not None: - filename = itm.data(Qt.UserRole) + if itm is not None and itm.parent() is not None: + filename = itm.data(0, Qt.UserRole) if filename: project = self.multiProject.getProject(filename) if project is not None: from .AddProjectDialog import AddProjectDialog - dlg = AddProjectDialog(self, project=project) + dlg = AddProjectDialog( + self, project=project, + categories=self.multiProject.getCategories()) if dlg.exec_() == QDialog.Accepted: - name, filename, isMaster, description = dlg.getData() + name, filename, isMaster, description, category = \ + dlg.getData() project = { 'name': name, 'file': filename, 'master': isMaster, 'description': description, + 'category': category, } self.multiProject.changeProjectProperties(project) @@ -247,21 +289,21 @@ Private method to create the popup menu. """ self.__menu = QMenu(self) - self.__menu.addAction(self.trUtf8("Open"), self.__openItem) - self.__menu.addAction(self.trUtf8("Remove"), self.__removeProject) - self.__menu.addAction(self.trUtf8("Properties"), + self.__menu.addAction(self.tr("Open"), self.__openItem) + self.__menu.addAction(self.tr("Remove"), self.__removeProject) + self.__menu.addAction(self.tr("Properties"), self.__showProjectProperties) self.__menu.addSeparator() - self.__menu.addAction(self.trUtf8("Add Project..."), + self.__menu.addAction(self.tr("Add Project..."), self.__addNewProject) self.__menu.addSeparator() - self.__menu.addAction(self.trUtf8("Configure..."), self.__configure) + self.__menu.addAction(self.tr("Configure..."), self.__configure) self.__backMenu = QMenu(self) - self.__backMenu.addAction(self.trUtf8("Add Project..."), + self.__backMenu.addAction(self.tr("Add Project..."), self.__addNewProject) self.__backMenu.addSeparator() - self.__backMenu.addAction(self.trUtf8("Configure..."), + self.__backMenu.addAction(self.tr("Configure..."), self.__configure) def __configure(self):