#!/usr/bin/env python
# ###########################################################################
#
# This file is part of Taurus
#
# http://taurus-scada.org
#
# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain
#
# Taurus is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Taurus is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Taurus. If not, see <http://www.gnu.org/licenses/>.
#
# ###########################################################################
"""This module provides base taurus tree item and a base tree model
"""
from taurus.external.qt import Qt
from taurus.core.taurusbasetypes import TaurusElementType
from taurus.core.util.log import Logger, deprecation_decorator
QtQt = Qt.Qt
__docformat__ = "restructuredtext"
[docs]
class TaurusBaseTreeItem(object):
"""A generic node"""
DisplayFunc = str
def __init__(self, model, data, parent=None):
self._model = model
self._itemData = data
self._parentItem = parent
self._childItems = []
self._depth = self._calcDepth()
[docs]
def itemData(self):
"""The internal itemData object
:return: object holding the data of this item
:rtype: object
"""
return self._itemData
[docs]
def depth(self):
"""Depth of the node in the hierarchy
:return: the node depth
:rtype: int
"""
return self._depth
[docs]
def appendChild(self, child):
"""Adds a new child node
:param child: child to be added
:type child: TaurusTreeBaseItem
"""
self._childItems.append(child)
[docs]
def child(self, row):
"""Returns the child in the given row
:return: the child node for the given row
:rtype: TaurusTreeBaseItem
"""
return self._childItems[row]
[docs]
def childCount(self):
"""Returns the number of childs for this node
:return: number of childs for this node
:rtype: int
"""
return len(self._childItems)
[docs]
def hasChildren(self):
return len(self._childItems) > 0
[docs]
def data(self, index):
"""Returns the data of this node for the given index
:return: the data for the given index
:rtype: object
"""
return self._itemData[index.column()]
[docs]
def icon(self, index):
return None
[docs]
def setData(self, index, data):
"""Sets the node data
:param data: the data to be associated with this node
:type data: object
"""
self._itemData = data
[docs]
def parent(self):
"""Returns the parent node or None if no parent exists
:return: the parent node
:rtype: TaurusTreeBaseItem
"""
return self._parentItem
[docs]
def row(self):
"""Returns the row for this node
:return: row number for this node
:rtype: int
"""
if self._parentItem is None:
return 0
return self._parentItem._childItems.index(self)
def _calcDepth(self):
d = 0
n = self.parent()
while n is not None:
n = n.parent()
d += 1
return d
[docs]
def display(self):
"""Returns the display string for this node
:return: the node's display string
:rtype: str
"""
if not hasattr(self, "_display"):
if self._itemData is None:
return None
self._display = self.DisplayFunc(self._itemData)
return self._display
@deprecation_decorator(alt="display", rel="4.5")
def qdisplay(self):
return str(self.display())
[docs]
def mimeData(self, index):
return self.data(index)
[docs]
def role(self):
"""Returns the prefered role for the item. This implementation returns
taurus.core.taurusbasetypes.TaurusElementType.Unknown
This method should be able to return any kind of python object as long
as the model that is used is compatible.
:return: the role in form of element type
:rtype: taurus.core.taurusbasetypes.TaurusElementType
"""
return TaurusElementType.Unknown
def __str__(self):
return self.display()
[docs]
class TaurusBaseModel(Qt.QAbstractItemModel, Logger):
"""The base class for all Taurus Qt models."""
ColumnNames = ()
ColumnRoles = ((),)
DftFont = Qt.QFont("Mono", 8)
def __init__(self, parent=None, data=None):
Qt.QAbstractItemModel.__init__(self, parent)
Logger.__init__(self)
self._data_src = None
self._rootItem = None
self._filters = []
self._selectables = [self.ColumnRoles[0][-1]]
self.setDataSource(data)
def __getattr__(self, name):
return getattr(self.dataSource(), name)
[docs]
def createNewRootItem(self):
return TaurusBaseTreeItem(self, self.ColumnNames)
[docs]
def refresh(self, refresh_source=False):
self.beginResetModel()
self._rootItem = self.createNewRootItem()
self.setupModelData(self.dataSource())
self.endResetModel()
[docs]
def setupModelData(self, data):
raise NotImplementedError(
"setupModelData must be implemented "
"in %s" % self.__class__.__name__
)
[docs]
def roleIcon(self, role):
raise NotImplementedError(
"roleIcon must be implemented " "in %s" % self.__class__.__name__
)
[docs]
def roleSize(self, role):
raise NotImplementedError(
"roleSize must be implemented " "in %s" % self.__class__.__name__
)
[docs]
def setDataSource(self, data_src):
self._data_src = data_src
self.refresh()
[docs]
def dataSource(self):
return self._data_src
[docs]
def setSelectables(self, seq_elem_types):
self._selectables = seq_elem_types
[docs]
def selectables(self):
return self._selectables
[docs]
def role(self, column, depth=0):
cr = self.ColumnRoles
if column == 0:
return cr[0][depth]
return self.ColumnRoles[column]
[docs]
def columnCount(self, parent=Qt.QModelIndex()):
return len(self.ColumnRoles)
[docs]
def columnIcon(self, column):
return self.roleIcon(self.role(column))
[docs]
def columnSize(self, column):
role = self.role(column)
s = self.roleSize(role)
return s
[docs]
def pyData(self, index, role=QtQt.DisplayRole):
if not index.isValid():
return None
item = index.internalPointer()
ret = None
if role == QtQt.DisplayRole or role == QtQt.EditRole:
ret = item.data(index)
# elif role == QtQt.CheckStateRole:
# data = item.data(index)
# if type(data) != bool:
# data = str(data).lower() == 'true'
# ret = QtQt.Unchecked
# if data == True:
# ret = QtQt.Checked
elif role == QtQt.DecorationRole:
ret = item.icon(index)
elif role == QtQt.ToolTipRole:
ret = item.toolTip(index)
# elif role == QtQt.SizeHintRole:
# ret = self.columnSize(column)
elif role == QtQt.FontRole:
ret = self.DftFont
elif role == QtQt.UserRole:
ret = item
return ret
[docs]
def data(self, index, role=QtQt.DisplayRole):
ret = self.pyData(index, role)
return ret
def _setData(self, index, qvalue, role=QtQt.EditRole):
item = index.internalPointer()
item.setData(index, qvalue)
return True
[docs]
def flags(self, index):
if not index.isValid():
return 0
ret = QtQt.ItemIsEnabled | QtQt.ItemIsDragEnabled
item = index.internalPointer()
column, depth = index.column(), item.depth()
taurus_role = self.role(column, depth)
if taurus_role in self.selectables():
ret |= QtQt.ItemIsSelectable
return ret
[docs]
def index(self, row, column, parent=Qt.QModelIndex()):
if not self.hasIndex(row, column, parent):
return Qt.QModelIndex()
if not parent.isValid():
parentItem = self._rootItem
else:
parentItem = parent.internalPointer()
childItem = parentItem.child(row)
if childItem:
return self.createIndex(row, column, childItem)
return Qt.QModelIndex()
[docs]
def parent(self, index):
if not index.isValid():
return Qt.QModelIndex()
childItem = index.internalPointer()
parentItem = childItem.parent()
if parentItem is None or parentItem == self._rootItem:
return Qt.QModelIndex()
return self.createIndex(parentItem.row(), 0, parentItem)
[docs]
def rowCount(self, parent=Qt.QModelIndex()):
if parent.column() > 0:
return 0
if not parent.isValid():
parentItem = self._rootItem
else:
parentItem = parent.internalPointer()
if parentItem is None:
return 0
return parentItem.childCount()
[docs]
def hasChildren(self, parent=Qt.QModelIndex()):
if parent.column() > 0:
return 0
if not parent.isValid():
parentItem = self._rootItem
else:
parentItem = parent.internalPointer()
if parentItem is None:
return False
return parentItem.hasChildren()
[docs]
class TaurusBaseProxyModel(Qt.QSortFilterProxyModel):
"""A taurus base Qt filter & sort model"""
def __init__(self, parent=None):
Qt.QSortFilterProxyModel.__init__(self, parent)
# filter configuration
self.setFilterCaseSensitivity(QtQt.CaseInsensitive)
self.setFilterKeyColumn(0)
self.setFilterRole(QtQt.DisplayRole)
# sort configuration
self.setSortCaseSensitivity(QtQt.CaseInsensitive)
self.setSortRole(QtQt.DisplayRole)
# general configuration
self.setDynamicSortFilter(True)
def __getattr__(self, name):
return getattr(self.sourceModel(), name)