예제 #1
0
    def __init__(self, headerData, parent=None):
        QAbstractItemModel.__init__(self, parent)

        self.rootItem = TreeViewItem(None, headerData)
        self.globalData = GlobalData()
        self.projectTopLevelDirs = []
        self.showTooltips = True
        return
예제 #2
0
    def __init__( self, headerData, parent = None ):
        QAbstractItemModel.__init__( self, parent )

        self.rootItem = TreeViewItem( None, headerData )
        self.globalData = GlobalData()
        self.projectTopLevelDirs = []
        self.showTooltips = True
        return
예제 #3
0
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
예제 #4
0
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