def __init__(self, headerData, parent=None): QAbstractItemModel.__init__(self, parent) self.rootItem = TreeViewItem(None, headerData) self.globalData = GlobalData() self.projectTopLevelDirs = [] self.showTooltips = True return
def __init__( self, headerData, parent = None ): QAbstractItemModel.__init__( self, parent ) self.rootItem = TreeViewItem( None, headerData ) self.globalData = GlobalData() self.projectTopLevelDirs = [] self.showTooltips = True return
class BrowserModelBase( QAbstractItemModel ): " Class implementing the file system browser model " def __init__( self, headerData, parent = None ): QAbstractItemModel.__init__( self, parent ) self.rootItem = TreeViewItem( None, headerData ) self.globalData = GlobalData() self.projectTopLevelDirs = [] self.showTooltips = True return def setTooltips( self, switchOn ): " Sets the tooltip mode: to show or not to show them " self.showTooltips = switchOn return def columnCount( self, parent = QModelIndex() ): " Provides the number of columns " if parent.isValid(): return parent.internalPointer().columnCount() return self.rootItem.columnCount() def updateRootData( self, column, value ): " Updates the root entry, i.e. header " self.rootItem.setData( column, value ) self.headerDataChanged.emit( Qt.Horizontal, column, column ) return def data( self, index, role ): " Provides data of an item " if not index.isValid(): return QVariant() column = index.column() if role == Qt.DisplayRole: item = index.internalPointer() if column < item.columnCount(): return QVariant( item.data( column ) ) if column == item.columnCount() and \ column < self.columnCount( self.parent( index ) ): # This is for the case when an item under a multi-column # parent doesn't have a value for all the columns return QVariant( "" ) elif role == Qt.DecorationRole: if column == 0: return QVariant( index.internalPointer().getIcon() ) elif role == Qt.ToolTipRole: item = index.internalPointer() if column == 1 and item.path is not None: return QVariant( item.path ) if self.showTooltips and column == 0 and item.toolTip != "": return QVariant( item.toolTip ) return QVariant() def flags( self, index ): " Provides the item flags " if not index.isValid(): return Qt.ItemIsEnabled return Qt.ItemIsEnabled | Qt.ItemIsSelectable def headerData( self, section, orientation, role = Qt.DisplayRole ): " Provides the header data " if orientation == Qt.Horizontal and role == Qt.DisplayRole: if section >= self.rootItem.columnCount(): return QVariant( "" ) return self.rootItem.data( section ) return QVariant() def index( self, row, column, parent = QModelIndex() ): " Creates an index " # The model/view framework considers negative values out-of-bounds, # however in python they work when indexing into lists. So make sure # we return an invalid index for out-of-bounds row/col if row < 0 or column < 0 or \ row >= self.rowCount( parent ) or \ column >= self.columnCount( parent ): return QModelIndex() if parent.isValid(): parentItem = parent.internalPointer() else: parentItem = self.rootItem try: if not parentItem.populated: self.populateItem( parentItem ) childItem = parentItem.child( row ) except IndexError: return QModelIndex() if childItem: return self.createIndex( row, column, childItem ) return QModelIndex() def buildIndex( self, rowPath ): " Builds index for the path (path is like [ 1, 2, 1, 16 ]) " result = QModelIndex() for row in rowPath: result = self.index( row, 0, result ) return result def parent( self, index ): " Provides the index of the parent object " if not index.isValid(): return QModelIndex() childItem = index.internalPointer() parentItem = childItem.parent() if parentItem == self.rootItem: return QModelIndex() return self.createIndex( parentItem.row(), 0, parentItem ) def totalRowCount( self ): " Provides the total number of rows " return self.rootItem.childCount() def rowCount( self, parent = QModelIndex() ): " Provides the number of rows " # Only the first column should have children if parent.column() > 0: return 0 if not parent.isValid(): return self.rootItem.childCount() parentItem = parent.internalPointer() if not parentItem.populated: # lazy population self.populateItem( parentItem ) return parentItem.childCount() def hasChildren( self, parent = QModelIndex() ): " Returns True if the parent has children " # Only the first column should have children if parent.column() > 0: return False if not parent.isValid(): return self.rootItem.childCount() > 0 if parent.internalPointer().lazyPopulation: return True return parent.internalPointer().childCount() > 0 def clear( self ): " Clears the model " self.rootItem.removeChildren() self.reset() return def item( self, index ): " Provides a reference to an item " if not index.isValid(): return None return index.internalPointer() @staticmethod def _addItem( itm, parentItem ): " Adds an item " parentItem.appendChild( itm ) return def addItem( self, itm, parent = QModelIndex() ): " Adds an item " if not parent.isValid(): parentItem = self.rootItem else: parentItem = parent.internalPointer() cnt = parentItem.childCount() self.beginInsertRows( parent, cnt, cnt ) self._addItem( itm, parentItem ) self.endInsertRows() return def populateItem( self, parentItem, repopulate = False ): " Populates an item's subtree " if parentItem.itemType == DirectoryItemType: self.populateDirectoryItem( parentItem, repopulate ) elif parentItem.itemType == SysPathItemType: self.populateSysPathItem( parentItem, repopulate ) elif parentItem.itemType == FileItemType: self.populateFileItem( parentItem, repopulate ) elif parentItem.itemType == GlobalsItemType: self.populateGlobalsItem( parentItem, repopulate ) elif parentItem.itemType == ImportsItemType: self.populateImportsItem( parentItem, repopulate ) elif parentItem.itemType == FunctionsItemType: self.populateFunctionsItem( parentItem, repopulate ) elif parentItem.itemType == ClassesItemType: self.populateClassesItem( parentItem, repopulate ) elif parentItem.itemType == ClassItemType: self.populateClassItem( parentItem, repopulate ) elif parentItem.itemType == StaticAttributesItemType: self.populateStaticAttributesItem( parentItem, repopulate ) elif parentItem.itemType == InstanceAttributesItemType: self.populateInstanceAttributesItem( parentItem, repopulate ) elif parentItem.itemType == FunctionItemType: self.populateFunctionItem( parentItem, repopulate ) elif parentItem.itemType == ImportItemType: self.populateImportItem( parentItem, repopulate ) parentItem.populated = True return def populateDirectoryItem( self, parentItem, repopulate = False ): " Populates a directory item's subtree " path = parentItem.getPath() if not os.path.exists( path ): return QApplication.setOverrideCursor( QCursor( Qt.WaitCursor ) ) try: items = os.listdir( path ) except Exception, exc: QApplication.restoreOverrideCursor() logging.error( "Cannot populate directory. " + str( exc ) ) return excludes = [ '.svn', '.cvs', '.hg', '.git' ] items = [ itm for itm in items if itm not in excludes ] if parentItem.needVCSStatus: # That's the project browser. Filter out what not needed. excludeFunctor = GlobalData().project.shouldExclude items = [ itm for itm in items if not excludeFunctor( itm ) ] pathsToRequest = [] if items: infoSrc = self.globalData.briefModinfoCache if repopulate: self.beginInsertRows( self.createIndex( parentItem.row(), 0, parentItem ), 0, len( items ) - 1 ) path = os.path.realpath( path ) + os.path.sep for item in items: fullPath = path + item if os.path.isdir( fullPath ): node = TreeViewDirectoryItem( parentItem, fullPath, False ) if parentItem.needVCSStatus: pathsToRequest.append( fullPath + os.path.sep ) else: node = TreeViewFileItem( parentItem, fullPath ) if parentItem.needVCSStatus: pathsToRequest.append( fullPath ) if node.fileType in [ PythonFileType, Python3FileType ]: modInfo = infoSrc.get( fullPath ) node.toolTip = "" if modInfo.docstring is not None: node.toolTip = modInfo.docstring.text if modInfo.isOK == False: # Substitute icon and change the tooltip node.icon = PixmapCache().getIcon( 'filepythonbroken.png' ) if node.toolTip != "": node.toolTip += "\n\n" node.toolTip += "Parsing errors:\n" + \ "\n".join( modInfo.lexerErrors + \ modInfo.errors ) node.parsingErrors = True if modInfo.encoding is None and \ not modInfo.imports and \ not modInfo.globals and \ not modInfo.functions and \ not modInfo.classes: node.populated = True node.lazyPopulation = False node.needVCSStatus = parentItem.needVCSStatus self._addItem( node, parentItem ) if repopulate: self.endInsertRows() parentItem.populated = True # Request statuses of the populated items. The request must be sent # after the items are added, otherwise the status received by the model # before the items are populated thus not updated properly. for path in pathsToRequest: GlobalData().mainWindow.vcsManager.requestStatus( path ) QApplication.restoreOverrideCursor() return
class BrowserModelBase(QAbstractItemModel): " Class implementing the file system browser model " def __init__(self, headerData, parent=None): QAbstractItemModel.__init__(self, parent) self.rootItem = TreeViewItem(None, headerData) self.globalData = GlobalData() self.projectTopLevelDirs = [] self.showTooltips = True return def setTooltips(self, switchOn): " Sets the tooltip mode: to show or not to show them " self.showTooltips = switchOn return def columnCount(self, parent=QModelIndex()): " Provides the number of columns " if parent.isValid(): return parent.internalPointer().columnCount() return self.rootItem.columnCount() def updateRootData(self, column, value): " Updates the root entry, i.e. header " self.rootItem.setData(column, value) self.headerDataChanged.emit(Qt.Horizontal, column, column) return def data(self, index, role): " Provides data of an item " if not index.isValid(): return QVariant() column = index.column() if role == Qt.DisplayRole: item = index.internalPointer() if column < item.columnCount(): return QVariant(item.data(column)) if column == item.columnCount() and \ column < self.columnCount( self.parent( index ) ): # This is for the case when an item under a multi-column # parent doesn't have a value for all the columns return QVariant("") elif role == Qt.DecorationRole: if column == 0: return QVariant(index.internalPointer().getIcon()) elif role == Qt.ToolTipRole: item = index.internalPointer() if column == 1 and item.path is not None: return QVariant(item.path) if self.showTooltips and column == 0 and item.toolTip != "": return QVariant(item.toolTip) return QVariant() def flags(self, index): " Provides the item flags " if not index.isValid(): return Qt.ItemIsEnabled return Qt.ItemIsEnabled | Qt.ItemIsSelectable def headerData(self, section, orientation, role=Qt.DisplayRole): " Provides the header data " if orientation == Qt.Horizontal and role == Qt.DisplayRole: if section >= self.rootItem.columnCount(): return QVariant("") return self.rootItem.data(section) return QVariant() def index(self, row, column, parent=QModelIndex()): " Creates an index " # The model/view framework considers negative values out-of-bounds, # however in python they work when indexing into lists. So make sure # we return an invalid index for out-of-bounds row/col if row < 0 or column < 0 or \ row >= self.rowCount( parent ) or \ column >= self.columnCount( parent ): return QModelIndex() if parent.isValid(): parentItem = parent.internalPointer() else: parentItem = self.rootItem try: if not parentItem.populated: self.populateItem(parentItem) childItem = parentItem.child(row) except IndexError: return QModelIndex() if childItem: return self.createIndex(row, column, childItem) return QModelIndex() def buildIndex(self, rowPath): " Builds index for the path (path is like [ 1, 2, 1, 16 ]) " result = QModelIndex() for row in rowPath: result = self.index(row, 0, result) return result def parent(self, index): " Provides the index of the parent object " if not index.isValid(): return QModelIndex() childItem = index.internalPointer() parentItem = childItem.parent() if parentItem == self.rootItem: return QModelIndex() return self.createIndex(parentItem.row(), 0, parentItem) def totalRowCount(self): " Provides the total number of rows " return self.rootItem.childCount() def rowCount(self, parent=QModelIndex()): " Provides the number of rows " # Only the first column should have children if parent.column() > 0: return 0 if not parent.isValid(): return self.rootItem.childCount() parentItem = parent.internalPointer() if not parentItem.populated: # lazy population self.populateItem(parentItem) return parentItem.childCount() def hasChildren(self, parent=QModelIndex()): " Returns True if the parent has children " # Only the first column should have children if parent.column() > 0: return False if not parent.isValid(): return self.rootItem.childCount() > 0 if parent.internalPointer().lazyPopulation: return True return parent.internalPointer().childCount() > 0 def clear(self): " Clears the model " self.rootItem.removeChildren() self.reset() return def item(self, index): " Provides a reference to an item " if not index.isValid(): return None return index.internalPointer() @staticmethod def _addItem(itm, parentItem): " Adds an item " parentItem.appendChild(itm) return def addItem(self, itm, parent=QModelIndex()): " Adds an item " if not parent.isValid(): parentItem = self.rootItem else: parentItem = parent.internalPointer() cnt = parentItem.childCount() self.beginInsertRows(parent, cnt, cnt) self._addItem(itm, parentItem) self.endInsertRows() return def populateItem(self, parentItem, repopulate=False): " Populates an item's subtree " if parentItem.itemType == DirectoryItemType: self.populateDirectoryItem(parentItem, repopulate) elif parentItem.itemType == SysPathItemType: self.populateSysPathItem(parentItem, repopulate) elif parentItem.itemType == FileItemType: self.populateFileItem(parentItem, repopulate) elif parentItem.itemType == GlobalsItemType: self.populateGlobalsItem(parentItem, repopulate) elif parentItem.itemType == ImportsItemType: self.populateImportsItem(parentItem, repopulate) elif parentItem.itemType == FunctionsItemType: self.populateFunctionsItem(parentItem, repopulate) elif parentItem.itemType == ClassesItemType: self.populateClassesItem(parentItem, repopulate) elif parentItem.itemType == ClassItemType: self.populateClassItem(parentItem, repopulate) elif parentItem.itemType == StaticAttributesItemType: self.populateStaticAttributesItem(parentItem, repopulate) elif parentItem.itemType == InstanceAttributesItemType: self.populateInstanceAttributesItem(parentItem, repopulate) elif parentItem.itemType == FunctionItemType: self.populateFunctionItem(parentItem, repopulate) elif parentItem.itemType == ImportItemType: self.populateImportItem(parentItem, repopulate) parentItem.populated = True return def populateDirectoryItem(self, parentItem, repopulate=False): " Populates a directory item's subtree " path = parentItem.getPath() if not os.path.exists(path): return QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) try: items = os.listdir(path) except Exception, exc: QApplication.restoreOverrideCursor() logging.error("Cannot populate directory. " + str(exc)) return excludes = ['.svn', '.cvs', '.hg', '.git'] items = [itm for itm in items if itm not in excludes] if parentItem.needVCSStatus: # That's the project browser. Filter out what not needed. excludeFunctor = GlobalData().project.shouldExclude items = [itm for itm in items if not excludeFunctor(itm)] pathsToRequest = [] if items: infoSrc = self.globalData.briefModinfoCache if repopulate: self.beginInsertRows( self.createIndex(parentItem.row(), 0, parentItem), 0, len(items) - 1) path = os.path.realpath(path) + os.path.sep for item in items: fullPath = path + item if os.path.isdir(fullPath): node = TreeViewDirectoryItem(parentItem, fullPath, False) if parentItem.needVCSStatus: pathsToRequest.append(fullPath + os.path.sep) else: node = TreeViewFileItem(parentItem, fullPath) if parentItem.needVCSStatus: pathsToRequest.append(fullPath) if node.fileType in [PythonFileType, Python3FileType]: modInfo = infoSrc.get(fullPath) node.toolTip = "" if modInfo.docstring is not None: node.toolTip = modInfo.docstring.text if modInfo.isOK == False: # Substitute icon and change the tooltip node.icon = PixmapCache().getIcon( 'filepythonbroken.png') if node.toolTip != "": node.toolTip += "\n\n" node.toolTip += "Parsing errors:\n" + \ "\n".join( modInfo.lexerErrors + \ modInfo.errors ) node.parsingErrors = True if modInfo.encoding is None and \ not modInfo.imports and \ not modInfo.globals and \ not modInfo.functions and \ not modInfo.classes: node.populated = True node.lazyPopulation = False node.needVCSStatus = parentItem.needVCSStatus self._addItem(node, parentItem) if repopulate: self.endInsertRows() parentItem.populated = True # Request statuses of the populated items. The request must be sent # after the items are added, otherwise the status received by the model # before the items are populated thus not updated properly. for path in pathsToRequest: GlobalData().mainWindow.vcsManager.requestStatus(path) QApplication.restoreOverrideCursor() return