Skip to content
Snippets Groups Projects
trees.py 11.7 KiB
Newer Older
  • Learn to ignore specific revisions
  • # -*- coding: utf-8 -*-
    """
    ***************************************************************************
        trees
        ---------------------
        Date                 : November 2017
        Copyright            : (C) 2017 by Benjamin Jakimow
        Email                : benjamin.jakimow@geo.hu-berlin.de
    ***************************************************************************
    *                                                                         *
    *   This program is free software; you can redistribute it and/or modify  *
    *   it under the terms of the GNU General Public License as published by  *
    *   the Free Software Foundation; either version 2 of the License, or     *
    *   (at your option) any later version.                                   *
    *                                                                         *
    ***************************************************************************
    """
    # noinspection PyPep8Naming
    
    
    import os, pickle
    
    from collections import OrderedDict
    
    from qgis.core import *
    from qgis.gui import *
    from PyQt4.QtCore import *
    from PyQt4.QtGui import *
    
    from osgeo import gdal, osr
    
    
    class TreeNode(QObject):
        sigWillAddChildren = pyqtSignal(QObject, int, int)
        sigAddedChildren = pyqtSignal(QObject, int, int)
        sigWillRemoveChildren = pyqtSignal(QObject, int, int)
        sigRemovedChildren = pyqtSignal(QObject, int, int)
        sigUpdated = pyqtSignal(QObject)
    
        def __init__(self, parentNode, name=None, values=None):
            super(TreeNode, self).__init__()
            self.mParent = parentNode
    
            self.mChildren = []
            self.mName = name
            self.mValues = []
            self.mIcon = None
            self.mToolTip = None
    
            if name:
                self.setName(name)
    
            if values:
                self.setValues(values)
    
            if isinstance(parentNode, TreeNode):
                parentNode.appendChildNodes(self)
    
        def nodeIndex(self):
            return self.mParent.mChildren.index(self)
    
        def next(self):
            i = self.nodeIndex()
            if i < len(self.mChildren.mChildren):
                return self.mParent.mChildren[i + 1]
            else:
                return None
    
        def previous(self):
            i = self.nodeIndex()
            if i > 0:
                return self.mParent.mChildren[i - 1]
            else:
                return None
    
        def detach(self):
            """
            Detaches this TreeNode from its parent TreeNode
            :return:
            """
            if isinstance(self.mParent, TreeNode):
                self.mParent.mChildren.remove(self)
                self.setParentNode(None)
    
        def appendChildNodes(self, listOfChildNodes):
            self.insertChildNodes(len(self.mChildren), listOfChildNodes)
    
        def insertChildNodes(self, index, listOfChildNodes):
            assert index <= len(self.mChildren)
            if isinstance(listOfChildNodes, TreeNode):
                listOfChildNodes = [listOfChildNodes]
            assert isinstance(listOfChildNodes, list)
            l = len(listOfChildNodes)
            idxLast = index + l - 1
            self.sigWillAddChildren.emit(self, index, idxLast)
            for i, node in enumerate(listOfChildNodes):
                assert isinstance(node, TreeNode)
                node.mParent = self
                # connect node signals
                node.sigWillAddChildren.connect(self.sigWillAddChildren)
                node.sigAddedChildren.connect(self.sigAddedChildren)
                node.sigWillRemoveChildren.connect(self.sigWillRemoveChildren)
                node.sigRemovedChildren.connect(self.sigRemovedChildren)
                node.sigUpdated.connect(self.sigUpdated)
    
                self.mChildren.insert(index + i, node)
    
            self.sigAddedChildren.emit(self, index, idxLast)
    
        def removeChildNode(self, node):
            assert node in self.mChildren
            i = self.mChildren.index(node)
            self.removeChildNodes(i, 1)
    
        def removeChildNodes(self, row, count):
    
            if row < 0 or count <= 0:
                return False
    
            rowLast = row + count - 1
    
            if rowLast >= self.childCount():
                return False
    
            self.sigWillRemoveChildren.emit(self, row, rowLast)
            to_remove = self.childNodes()[row:rowLast + 1]
            for n in to_remove:
                self.mChildren.remove(n)
                # n.mParent = None
    
            self.sigRemovedChildren.emit(self, row, rowLast)
    
        def setToolTip(self, toolTip):
            self.mToolTip = toolTip
    
        def toolTip(self):
            return self.mToolTip
    
        def parentNode(self):
            return self.mParent
    
        def setParentNode(self, treeNode):
            assert isinstance(treeNode, TreeNode)
            self.mParent = treeNode
    
        def setIcon(self, icon):
            self.mIcon = icon
    
        def icon(self):
            return self.mIcon
    
        def setName(self, name):
            self.mName = name
    
        def name(self):
            return self.mName
    
        def contextMenu(self):
            return None
    
        def setValues(self, listOfValues):
            if not isinstance(listOfValues, list):
                listOfValues = [listOfValues]
            self.mValues = listOfValues[:]
    
        def values(self):
            return self.mValues[:]
    
        def childCount(self):
            return len(self.mChildren)
    
        def childNodes(self):
            return self.mChildren[:]
    
        def findChildNodes(self, type, recursive=True):
            results = []
            for node in self.mChildren:
                if isinstance(node, type):
                    results.append(node)
                if recursive:
                    results.extend(node.findChildNodes(type, recursive=True))
            return results
    
    
    class TreeModel(QAbstractItemModel):
        def __init__(self, parent=None, rootNode=None):
            super(TreeModel, self).__init__(parent)
    
            self.mColumnNames = ['Node', 'Value']
            self.mRootNode = rootNode if isinstance(rootNode, TreeNode) else TreeNode(None)
            self.mRootNode.sigWillAddChildren.connect(self.nodeWillAddChildren)
            self.mRootNode.sigAddedChildren.connect(self.nodeAddedChildren)
            self.mRootNode.sigWillRemoveChildren.connect(self.nodeWillRemoveChildren)
            self.mRootNode.sigRemovedChildren.connect(self.nodeRemovedChildren)
            self.mRootNode.sigUpdated.connect(self.nodeUpdated)
    
            self.mTreeView = None
            if isinstance(parent, QTreeView):
                self.connectTreeView(parent)
    
        def nodeWillAddChildren(self, node, idx1, idxL):
            idxNode = self.node2idx(node)
            self.beginInsertRows(idxNode, idx1, idxL)
    
        def nodeAddedChildren(self, node, idx1, idxL):
            self.endInsertRows()
            # for i in range(idx1, idxL+1):
            for n in node.childNodes():
                # self.setColumnSpan(node)
                pass
    
        def nodeWillRemoveChildren(self, node, idx1, idxL):
            idxNode = self.node2idx(node)
            self.beginRemoveRows(idxNode, idx1, idxL)
    
        def nodeRemovedChildren(self, node, idx1, idxL):
            self.endRemoveRows()
    
        def nodeUpdated(self, node):
            idxNode = self.node2idx(node)
            self.dataChanged.emit(idxNode, idxNode)
            self.setColumnSpan(node)
    
        def headerData(self, section, orientation, role):
            if orientation == Qt.Horizontal and role == Qt.DisplayRole:
    
                if len(self.mColumnNames) > section:
                    return self.mColumnNames[section]
                else:
                    return ''
    
            else:
                return None
    
        def parent(self, index):
            if not index.isValid():
                return QModelIndex()
            node = self.idx2node(index)
            if not isinstance(node, TreeNode):
                return QModelIndex()
    
            parentNode = node.parentNode()
            if not isinstance(parentNode, TreeNode):
                return QModelIndex()
    
            return self.node2idx(parentNode)
    
            if node not in parentNode.mChildren:
                return QModelIndex
            row = parentNode.mChildren.index(node)
            return self.createIndex(row, 0, parentNode)
    
        def rowCount(self, index):
    
            node = self.idx2node(index)
            return len(node.mChildren) if isinstance(node, TreeNode) else 0
    
        def hasChildren(self, index):
            node = self.idx2node(index)
            return isinstance(node, TreeNode) and len(node.mChildren) > 0
    
        def columnNames(self):
            return self.mColumnNames
    
        def columnCount(self, index):
    
            return len(self.mColumnNames)
    
        def connectTreeView(self, treeView):
            self.mTreeView = treeView
    
        def setColumnSpan(self, node, span=None):
            if isinstance(self.mTreeView, QTreeView) \
                    and isinstance(node, TreeNode) \
                    and isinstance(node.parentNode(), TreeNode):
                idxNode = self.node2idx(node)
                idxParent = self.node2idx(node.parentNode())
                if not isinstance(span, bool):
                    span = len(node.values()) == 0
                self.mTreeView.setFirstColumnSpanned(idxNode.row(), idxParent, span)
                for n in node.childNodes():
                    self.setColumnSpan(n)
    
        def index(self, row, column, parentIndex=None):
    
            if parentIndex is None:
                parentNode = self.mRootNode
            else:
                parentNode = self.idx2node(parentIndex)
    
            if row < 0 or row >= parentNode.childCount():
                return QModelIndex()
            if column < 0 or column >= len(self.mColumnNames):
                return QModelIndex()
    
            if isinstance(parentNode, TreeNode) and row < len(parentNode.mChildren):
                return self.createIndex(row, column, parentNode.mChildren[row])
            else:
                return QModelIndex()
    
        def findParentNode(self, node, parentNodeType):
            assert isinstance(node, TreeNode)
            while True:
                if isinstance(node, parentNodeType):
                    return node
                if not isinstance(node.parentNode(), TreeNode):
                    return None
                node = node.parentNode()
    
        def indexes2nodes(self, indexes):
            assert isinstance(indexes, list)
            nodes = []
            for idx in indexes:
                n = self.idx2node(idx)
                if n not in nodes:
                    nodes.append(n)
            return nodes
    
        def expandNode(self, node, expand=True, recursive=True):
            assert isinstance(node, TreeNode)
            if isinstance(self.mTreeView, QTreeView):
                idx = self.node2idx(node)
                self.mTreeView.setExpanded(idx, expand)
    
                if recursive:
                    for n in node.childNodes():
                        self.expandNode(n, expand=expand, recursive=recursive)
    
        def nodes2indexes(self, nodes):
            return [self.node2idx(n) for n in nodes]
    
        def idx2node(self, index):
            if not index.isValid():
                return self.mRootNode
            else:
                return index.internalPointer()
    
        def node2idx(self, node):
            assert isinstance(node, TreeNode)
            if node == self.mRootNode:
                return QModelIndex()
            else:
                parentNode = node.parentNode()
                assert isinstance(parentNode, TreeNode)
                if node not in parentNode.mChildren:
                    return QModelIndex()
                r = parentNode.mChildren.index(node)
                return self.createIndex(r, 0, node)
    
        def data(self, index, role):
            node = self.idx2node(index)
            col = index.column()
            if role == Qt.UserRole:
                return node
    
            if col == 0:
                if role in [Qt.DisplayRole, Qt.EditRole]:
                    return node.name()
                if role == Qt.DecorationRole:
                    return node.icon()
                if role == Qt.ToolTipRole:
                    return node.toolTip()
            if col > 0:
                i = col - 1
                if role in [Qt.DisplayRole, Qt.EditRole] and len(node.values()) > i:
                    return str(node.values()[i])
    
        def flags(self, index):
            if not index.isValid():
                return Qt.NoItemFlags
            node = self.idx2node(index)
            return Qt.ItemIsEnabled | Qt.ItemIsSelectable
    
    
    
    class TreeView(QTreeView):
        def __init__(self, *args, **kwds):
            super(TreeView, self).__init__(*args, **kwds)