Ejemplo n.º 1
0
class TreeModel(QAbstractItemModel):
    checkChanged = Signal(int, str)
    def __init__(self, headers, data, tablemodel, parent=None):
        super(TreeModel, self).__init__(parent)

        rootData = [header for header in headers]
        self.rootItem = TreeItem(rootData)
        self.treeDict = data
        self.tablemodel = tablemodel
        self.setupModelData(data, self.rootItem)
        self.examingParents = False
        self.examiningChildren = False

    def changeLeafCheck(self, source):
        curNode = self.rootItem.child(0)
        keyNames = source.split("/")
        curRow = 0
        for key in keyNames:
            for i in range(curNode.childCount()):
                if curNode.child(i).itemData[0] == key:
                        curNode = curNode.child(i)
                        curRow = i
                        break
        anIndex = self.createIndex(curRow, curNode.columnCount(), curNode)
        self.setData(anIndex, 0, Qt.CheckStateRole)



    def columnCount(self, parent=QModelIndex()):
        return self.rootItem.columnCount()

    def data(self, index, role):
        if not index.isValid():
            return None

        item = self.getItem(index)
        if role == Qt.DisplayRole:
            return item.data(index.column())
        elif role == Qt.CheckStateRole:
            return item.checked

        return None


    def flags(self, index):
        if not index.isValid():
            return 0

        return Qt.ItemIsUserCheckable | super(TreeModel, self).flags(index)

    def getItem(self, index):
        if index.isValid():
            item = index.internalPointer()
            if item:
                return item

        return self.rootItem

    def headerData(self, section, orientation, role=Qt.DisplayRole):
        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
            return self.rootItem.data(section)

        return None

    def index(self, row, column, parent=QModelIndex()):
        if parent.isValid() and parent.column() != 0:
            return QModelIndex()

        parentItem = self.getItem(parent)
        childItem = parentItem.child(row)
        if childItem:
            return self.createIndex(row, column, childItem)
        else:
            return QModelIndex()

    def insertColumns(self, position, columns, parent=QModelIndex()):
        self.beginInsertColumns(parent, position, position + columns - 1)
        success = self.rootItem.insertColumns(position, columns)
        self.endInsertColumns()

        return success

    def insertRows(self, position, rows, parent=QModelIndex()):
        parentItem = self.getItem(parent)
        self.beginInsertRows(parent, position, position + rows - 1)
        success = parentItem.insertChildren(position, rows,
                self.rootItem.columnCount())
        self.endInsertRows()

        return success

    def parent(self, index):
        if not index.isValid():
            return QModelIndex()

        childItem = self.getItem(index)
        parentItem = childItem.parent()

        if parentItem == self.rootItem:
            return QModelIndex()

        return self.createIndex(parentItem.childNumber(), 0, parentItem)

    def removeColumns(self, position, columns, parent=QModelIndex()):
        self.beginRemoveColumns(parent, position, position + columns - 1)
        success = self.rootItem.removeColumns(position, columns)
        self.endRemoveColumns()

        if self.rootItem.columnCount() == 0:
            self.removeRows(0, self.rowCount())

        return success

    def removeRows(self, position, rows, parent=QModelIndex()):
        parentItem = self.getItem(parent)

        self.beginRemoveRows(parent, position, position + rows - 1)
        success = parentItem.removeChildren(position, rows)
        self.endRemoveRows()

        return success

    def rowCount(self, parent=QModelIndex()):
        parentItem = self.getItem(parent)

        return parentItem.childCount()

    def setData(self, index, value, role=Qt.EditRole):
        if role == Qt.EditRole:
           item = self.getItem(index)
           result = item.setData(index.column(), value)
           if result:
               self.dataChanged.emit(index, index)
               return result
        elif role == Qt.CheckStateRole:
            item = self.getItem(index)
            item.checked = value
            checked = item.checked
            source=""
            sourceList= []

            while item.parentItem:
                sourceList.insert(0,item.itemData[0]+"/")
                item = item.parentItem
            if self.examingParents == False:
                self.checkChanged.emit(checked,source.join(sourceList)[:-1])
            self.checkChildren(index,value)
            self.checkParent(index)
            self.dataChanged.emit(index, index)
            return True
        return False


    def setHeaderData(self, section, orientation, value, role=Qt.EditRole):
        if role != Qt.EditRole or orientation != Qt.Horizontal:
            return False

        result = self.rootItem.setData(section, value)
        if result:
            self.headerDataChanged.emit(orientation, section, section)

        return result

    def setupModelData(self, data, parent):
             visited={}
             queue=[]
             grandParents = {}

             for key in data.keys():
                 visited[(parent.itemData[0])]=[key]
                 queue.append((key,parent,""))
                 grandParents[key] = (data[key],parent)
             curDict = data
             tempSource= ""
             while queue:
                 poppedItem = queue.pop(0)
                 child = poppedItem[0]
                 parentOfChild = poppedItem[1]
                 childSource = poppedItem[2]
                 parent = parentOfChild
                 parent.insertChildren(parent.childCount(),1,self.rootItem.columnCount())
                 parent.child(parent.childCount() -1).setData(0,child)

                 if child in grandParents:

                     curDict =  grandParents[child][0]
                     tempSource = childSource+child+"/"
                     for curChild in range(grandParents[child][1].childCount()):
                         if child == grandParents[child][1].child(curChild).itemData[0]:
                            parent = grandParents[child][1].child(curChild)
                            visited[(parent.itemData[0])]=[]

                 if isinstance(curDict, dict):
                     for key in curDict.keys():
                         if key not in visited[(parent.itemData[0])]:
                             visited[(parent.itemData[0])].append(key)
                             queue.append((key,parent,tempSource))
                             if (isinstance(curDict[key],dict)):
                                grandParents[key]= (curDict[key],parent)
                             else:
                                self.tablemodel.addRow(curDict,tempSource,key)

    def checkChildren(self,index,value):
        self.examingChildren = True
        if not index.isValid() or self.examingParents:
            self.examingChildren = False
            return
        else:
            childCount = self.rowCount(index)
            for i in range(childCount):
                child = index.child(i, 0)
                if value == 1:
                    return
                self.setData(child, value, Qt.CheckStateRole)
                self.checkChildren(child,value)

    def checkParent(self,index):
        self.examingParents = True
        if not index.isValid() or self.examiningChildren:
            self.examingParents = False
            return
        else:
            parent = index.parent()
            if parent.data() == None:
                self.examingParents = False
                return
            value = self.checkChildrenStates(parent)
            self.setData(parent, value, Qt.CheckStateRole)

    def checkChildrenStates(self, index):
        childCount = self.rowCount(index)
        checkedChildrenCount = 0
        for i in range(childCount):
            child = index.child(i, 0)
            if child.data(Qt.CheckStateRole) == Qt.Checked or child.data(Qt.CheckStateRole) == Qt.PartiallyChecked:
                checkedChildrenCount += 1
        if checkedChildrenCount == 0:
            return 0
        elif checkedChildrenCount == childCount:
            return 2
        else:
            return 1
Ejemplo n.º 2
0
class TreeModel(QAbstractItemModel):
    #Roles to filter input and output view
    Item_Role = Qt.UserRole

    def __init__(self, headers, data, parent=None) -> None:
        super(TreeModel, self).__init__(parent)

        rootData = []
        for header in headers:
            rootData.append(header)

        self._rootItem = TreeItem(rootData)

        #self._setupModelData(data.split('\n'), self._rootItem)

    def rootItem(self) -> TreeItem:
        """
        Return the root item of this model
        """
        return self._rootItem

    def getItem(self, index) -> TreeItem:
        """
        Return the TreeItem from model using the index
        """
        if index.isValid():
            item = index.internalPointer()
            if item:
                return item
        return self._rootItem

    def data(self, index, role) -> object:
        """
        Return data from model to the view
        """
        if not index.isValid():
            return None

        item = self.getItem(index)

        if role == Qt.DisplayRole or role == Qt.EditRole:
            return item.data(index.column())

        if role == TreeModel.Item_Role:
            return item

        return QVariant()

    def headerData(self, section, orientation, role) -> object:
        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
            return self._rootItem.data(section)

    def index(self, row, column, parent=QModelIndex()) -> QModelIndex:
        """
        Obtain model indexes corresponding to children of given parent item
        """
        #Only return model indexes for child items if the parent index in invalid (root item)
        #or if it has a zero column number
        if parent.isValid() and parent.column() != 0:
            return QModelIndex()

        parentItem = self.getItem(parent)
        if not parentItem:
            return QModelIndex()

        #Create a model index to uniquely with the row and column numbers
        #and a pointer to the item
        childItem = parentItem.child(row)
        if childItem:
            return self.createIndex(row, column, childItem)

        return QModelIndex()

    def parent(self, index) -> QModelIndex:
        """
        Return the model indexes for parents of item by finding the correspoinding item for a
        give model index, using its parent() function to obtain its parent item, then
        creating a model index to represent the parent.

        Item without parents, including the root item, are handled by returning a null model index.
        Otherwise, a model index ins created and returned as in the index() function, with a suitable row number,
        but with a zero column
        """
        if not index.isValid():
            return QModelIndex()

        childItem = self.getItem(index)
        parentItem = None
        if childItem:
            parentItem = childItem.parent()

        if parentItem == self._rootItem or not parentItem:
            return QModelIndex()

        return self.createIndex(parentItem.childNumber(), 0, parentItem)

    def rowCount(self, parent=QModelIndex()) -> int:
        """
        Return the children that parent has
        """
        parentItem = self.getItem(parent)

        if parentItem:
            return parentItem.childCount()
        else:
            return 0

    def columnCount(self, parent=QModelIndex()) -> int:
        """
        All items are defined to have the same number of columns associated with them
        """
        return self._rootItem.columnCount()

    def flags(self, index) -> Qt.ItemFlags:
        """
        Return flags ItemIsEditable, ItemIsSelectable and ItemIsEnable to be able to edit and select item
        """
        if not index.isValid():
            return Qt.NoItemFlags

        return Qt.ItemIsEditable | Qt.ItemIsSelectable | Qt.ItemIsEnabled

    def setData(self, index, value, role=Qt.EditRole) -> bool:
        """
        Set data from view back to the model
        """
        if role != Qt.EditRole:
            return False

        item = self.getItem(index)
        result = item.setData(index.column(), value)

        if result:
            self.dataChanged.emit(index, index, [Qt.DisplayRole, Qt.EditRole])

        return result

    def setHeaderData(self,
                      section,
                      orientation,
                      value,
                      role=Qt.EditRole) -> bool:
        if role != Qt.EditRole or orientation != Qt.Horizontal:
            return False

        result = self._rootItem.setData(section, value)

        if result:
            self.headerDataChanged.emit(orientation, section, section)

        return result

    def insertColumns(self, position, columns, parent=QModelIndex()) -> bool:
        """
        Insert columns into the model
        """
        self.beginInsertColumns(parent, position, position + columns - 1)
        success = self._rootItem.insertColumns(position, columns)
        self.endInsertColumns()

        return success

    def removeColumns(self, position, columns, parent=QModelIndex()) -> bool:
        """
        Remove columns from the model
        """
        self.beginRemoveColumns(parent, position, position + columns - 1)
        success = self._rootItem.removeColumns(position, columns)
        self.endRemoveColumns()

        if self._rootItem.columnCount() == 0:
            self.removeRows(0, self.rowCount())

        return success

    def insertRows(self, position, rows, parent=QModelIndex()) -> bool:
        """
        Insert rows into model
        """
        parentItem = self.getItem(parent)
        if not parentItem:
            return False

        self.beginInsertRows(parent, position, position + rows - 1)
        success = parentItem.insertChildren(position, rows,
                                            self._rootItem.columnCount())
        self.endInsertRows()

        return success

    def removeRows(self, position, rows, parent=QModelIndex()) -> bool:
        """
        Remove rows from model
        """
        parentItem = self.getItem(parent)
        if not parentItem:
            return False

        self.beginRemoveRows(parent, position, position + rows - 1)
        success = parentItem.removeChildren(position, rows)
        self.endRemoveRows()

        return success