#!/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 widgets that display the database in a tree format"""
__all__ = ["TaurusTreeDevicePartItem", "TaurusTreeDeviceDomainItem",
"TaurusTreeDeviceFamilyItem", "TaurusTreeDeviceMemberItem", "TaurusTreeSimpleDeviceItem",
"TaurusTreeDeviceItem", "TaurusTreeAttributeItem", "TaurusTreeServerNameItem",
"TaurusTreeServerItem", "TaurusTreeDeviceClassItem", "TaurusDbBaseModel",
"TaurusDbSimpleDeviceModel", "TaurusDbPlainDeviceModel", "TaurusDbDeviceModel",
"TaurusDbSimpleDeviceAliasModel",
"TaurusDbPlainServerModel", "TaurusDbServerModel",
"TaurusDbDeviceClassModel",
"TaurusDbBaseProxyModel",
"TaurusDbDeviceProxyModel", "TaurusDbServerProxyModel", "TaurusDbDeviceClassProxyModel"]
__docformat__ = 'restructuredtext'
from taurus.external.qt import Qt
from taurus.core.taurusbasetypes import TaurusElementType, TaurusSWDevHealth
from taurus.core.taurusdatabase import TaurusInfo, TaurusDatabase
import taurus.qt.qtcore.mimetypes
from .taurusmodel import TaurusBaseTreeItem, TaurusBaseModel, TaurusBaseProxyModel
ElemType = TaurusElementType
DevHealth = TaurusSWDevHealth
def getElementTypeIcon(*args, **kwargs):
"""Wrapper to prevent loading qtgui when this module is imported"""
import taurus.qt.qtgui.resource
return taurus.qt.qtgui.resource.getElementTypeIcon(*args, **kwargs)
def getElementTypeToolTip(*args, **kwargs):
"""Wrapper to prevent loading qtgui when this module is imported"""
import taurus.qt.qtgui.resource
return taurus.qt.qtgui.resource.getElementTypeToolTip(*args, **kwargs)
def getElementTypeSize(*args, **kwargs):
"""Wrapper to prevent loading qtgui when this module is imported"""
import taurus.qt.qtgui.resource
return taurus.qt.qtgui.resource.getElementTypeSize(*args, **kwargs)
def getSWDevHealthIcon(*args, **kwargs):
"""Wrapper to prevent loading qtgui when this module is imported"""
import taurus.qt.qtgui.resource
return taurus.qt.qtgui.resource.getSWDevHealthIcon(*args, **kwargs)
def getSWDevHealthToolTip(*args, **kwargs):
"""Wrapper to prevent loading qtgui when this module is imported"""
import taurus.qt.qtgui.resource
return taurus.qt.qtgui.resource.getSWDevHealthToolTip(*args, **kwargs)
class TaurusTreeDbBaseItem(TaurusBaseTreeItem):
DisplayFunc = TaurusInfo.name
[docs]class TaurusTreeDevicePartItem(TaurusTreeDbBaseItem):
"""A node designed to represent a 'part' (or totality) of a device name"""
[docs] def data(self, index):
column = index.column()
if column > 0: return
model = index.model()
role = model.role(column, self.depth())
if role == self.role():
return self._itemData
[docs] def role(self):
return ElemType.Device
[docs]class TaurusTreeDeviceDomainItem(TaurusTreeDevicePartItem):
"""A node designed to represent a the domain part of a device name"""
DisplayFunc = str
[docs] def role(self):
return ElemType.Domain
[docs]class TaurusTreeDeviceFamilyItem(TaurusTreeDevicePartItem):
"""A node designed to represent a the family part of a device name"""
DisplayFunc = str
[docs] def role(self):
return ElemType.Family
[docs]class TaurusTreeDeviceMemberItem(TaurusTreeDevicePartItem):
"""A node designed to represent a the member part of a device name"""
DisplayFunc = str
[docs] def role(self):
return ElemType.Member
[docs]class TaurusTreeSimpleDeviceItem(TaurusTreeDbBaseItem):
"""A node designed to represent a device (without any child nodes)"""
[docs] def hasChildren(self):
return False
[docs] def childCount(self):
return 0
[docs] def data(self, index):
column, model = index.column(), index.model()
role = model.role(column, self.depth())
obj = self.itemData()
if role == ElemType.Device or role == ElemType.Name:
return obj.name()
elif role == ElemType.DeviceAlias:
return obj.alias()
elif role == ElemType.Server:
return obj.server().name()
elif role == ElemType.DeviceClass:
return obj.klass().name()
elif role == ElemType.Exported:
return obj.health()
elif role == ElemType.Host:
return obj.host()
elif role == ElemType.Domain:
return obj.domain()
elif role == ElemType.Family:
return obj.family()
elif role == ElemType.Member:
return obj.member()
[docs] def mimeData(self, index):
return self.itemData().name()
[docs] def role(self):
return ElemType.Device
[docs]class TaurusTreeDeviceItem(TaurusTreeDbBaseItem):
"""A node designed to represent a device"""
SearchForAttributeHealth = DevHealth.Exported, DevHealth.ExportedAlive, \
DevHealth.NotExportedAlive
[docs] def child(self, row):
self.updateChilds()
return super(TaurusTreeDeviceItem, self).child(row)
[docs] def hasChildren(self):
return True
nb = super(TaurusTreeDeviceItem, self).childCount()
if nb > 0:
return True
data = self.itemData()
if not data.health() in self.SearchForAttributeHealth:
return False
return True
[docs] def childCount(self):
nb = super(TaurusTreeDeviceItem, self).childCount()
if nb > 0:
return nb
data = self.itemData()
if not data.health() in self.SearchForAttributeHealth:
return 0
self.updateChilds()
return super(TaurusTreeDeviceItem, self).childCount()
[docs] def updateChilds(self):
if len(self._childItems) > 0:
return
for attr in self._itemData.attributes():
c = TaurusTreeAttributeItem(self._model, attr, self)
self.appendChild(c)
return
[docs] def data(self, index):
column, model = index.column(), index.model()
role = model.role(column, self.depth())
obj = self.itemData()
if role == ElemType.Device or role == ElemType.Name:
return obj.name()
elif role == ElemType.DeviceAlias:
return obj.alias()
elif role == ElemType.Server:
return obj.server().name()
elif role == ElemType.DeviceClass:
return obj.klass().name()
elif role == ElemType.Exported:
return obj.health()
elif role == ElemType.Host:
return obj.host()
elif role == ElemType.Domain:
return obj.domain()
elif role == ElemType.Family:
return obj.family()
elif role == ElemType.Member:
return obj.member()
[docs] def mimeData(self, index):
return self.itemData().fullName()
[docs] def role(self):
return ElemType.Device
[docs]class TaurusTreeAttributeItem(TaurusTreeDbBaseItem):
"""A node designed to represent an attribute"""
[docs] def data(self, index):
column, model = index.column(), index.model()
role = model.role(column, self.depth())
if role == ElemType.Attribute or role == ElemType.Name:
data = self.itemData()
data_info = data.info()
ret = data.name()
if data_info and hasattr(data_info, 'label'):
ret = "'" + data_info.label + "' (" + ret + ")"
return ret
[docs] def mimeData(self, index):
return self.itemData().fullName()
[docs] def role(self):
return ElemType.Attribute
[docs]class TaurusTreeServerNameItem(TaurusTreeDbBaseItem):
"""A node designed to represent the server name part of a server"""
DisplayFunc = str
[docs] def data(self, index):
column, model = index.column(), index.model()
role = model.role(column, self.depth())
if role == ElemType.ServerName or role == ElemType.Name:
return self._itemData
[docs] def role(self):
return ElemType.ServerName
[docs]class TaurusTreeServerItem(TaurusTreeDbBaseItem):
"""A node designed to represent a server"""
[docs] def data(self, index):
column, model = index.column(), index.model()
role = model.role(column, self.depth())
if role == ElemType.Server or role == ElemType.Name:
return self._itemData.name()
elif role == ElemType.ServerName:
return self._itemData.serverName()
elif role == ElemType.ServerInstance:
return self._itemData.serverInstance()
elif role == ElemType.Exported:
return self._itemData.health()
elif role == ElemType.Host:
return self._itemData.host()
[docs] def mimeData(self, index):
return self.itemData().fullName()
[docs] def role(self):
return ElemType.Server
class TaurusTreeFullServerItem(TaurusTreeDbBaseItem):
"""A node designed to represent a server"""
def data(self, index):
column, model = index.column(), index.model()
role = model.role(column, self.depth())
if role == ElemType.Server or role == ElemType.Name:
return self._itemData.fullName()
elif role == ElemType.ServerName:
return self._itemData.serverName()
elif role == ElemType.ServerInstance:
return self._itemData.fullName()
elif role == ElemType.Exported:
return self._itemData.health()
elif role == ElemType.Host:
return self._itemData.host()
def mimeData(self, index):
return self.itemData().fullName()
def role(self):
return ElemType.Server
[docs]class TaurusTreeDeviceClassItem(TaurusTreeDbBaseItem):
"""A node designed to represent a device class"""
[docs] def data(self, index):
column, model = index.column(), index.model()
role = model.role(column, self.depth())
if role == ElemType.Name or role == ElemType.DeviceClass:
return self._itemData.name()
[docs] def mimeData(self, index):
return self.itemData().fullName()
[docs] def role(self):
return ElemType.DeviceClass
[docs]class TaurusDbBaseModel(TaurusBaseModel):
"""The base class for all Taurus database Qt models.
By default, this model represents a plain device perspective of the underlying
database."""
ColumnNames = "Device", "Alias", "Server", "Class", "Alive", "Host"
ColumnRoles = (ElemType.Device, ElemType.Device), ElemType.DeviceAlias, ElemType.Server, ElemType.DeviceClass, ElemType.Exported, ElemType.Host
[docs] def createNewRootItem(self):
return TaurusTreeDbBaseItem(self, self.ColumnNames)
[docs] def refresh(self, refresh_source=False):
data = self.dataSource()
if refresh_source and data is not None:
data.refreshCache()
TaurusBaseModel.refresh(self, refresh_source=refresh_source)
[docs] def roleIcon(self, taurus_role):
return getElementTypeIcon(taurus_role)
[docs] def columnIcon(self, column):
return self.roleIcon(self.role(column))
[docs] def roleSize(self, taurus_role):
return getElementTypeSize(taurus_role)
[docs] def columnSize(self, column):
taurus_role = self.role(column)
s = self.roleSize(taurus_role)
return s
[docs] def mimeTypes(self):
return ["text/plain", taurus.qt.qtcore.mimetypes.TAURUS_MODEL_LIST_MIME_TYPE, taurus.qt.qtcore.mimetypes.TAURUS_MODEL_MIME_TYPE]
[docs] def mimeData(self, indexes):
ret = Qt.QMimeData()
data = []
for index in indexes:
if not index.isValid(): continue
#item = index.internalPointer()
#data = item.mimeData(index)
#stream << item.mimeData(index)
tree_item = index.internalPointer()
mime_data_item = tree_item.mimeData(index)
if mime_data_item is None:
continue
data.append(mime_data_item)
ret.setData(taurus.qt.qtcore.mimetypes.TAURUS_MODEL_LIST_MIME_TYPE, "\r\n".join(data))
ret.setText(", ".join(data))
if len(data)==1:
ret.setData(taurus.qt.qtcore.mimetypes.TAURUS_MODEL_MIME_TYPE, str(data[0]))
return ret
[docs] def pyData(self, index, role):
if not index.isValid():
return None
item = index.internalPointer()
row, column, depth = index.row(), index.column(), item.depth()
taurus_role = self.role(column, depth)
ret = None
if role == Qt.Qt.DisplayRole:
if taurus_role != ElemType.Exported:
ret = item.data(index)
elif role == Qt.Qt.DecorationRole:
if column == 0:
ret = self.roleIcon(taurus_role)
if taurus_role == ElemType.Exported:
health = item.data(index)
ret = getSWDevHealthIcon(health)
elif role == Qt.Qt.ToolTipRole:
ret = item.toolTip(index)
if ret is None:
data = item.data(index)
if data is not None:
if taurus_role == ElemType.Exported:
ret = getSWDevHealthToolTip(data)
else:
ret = self.roleToolTip(taurus_role)
#elif role == Qt.Qt.SizeHintRole:
# ret = self.columnSize(column)
elif role == Qt.Qt.FontRole:
ret = self.DftFont
return ret
[docs] def setupModelData(self, data):
if data is None:
return
if isinstance(data, TaurusDatabase):
data = data.cache()
devices = data.devices()
rootItem = self._rootItem
for dev_name in data.getDeviceNames():
dev = devices[dev_name]
devItem = TaurusTreeSimpleDeviceItem(self, dev, rootItem)
rootItem.appendChild(devItem)
[docs]class TaurusDbSimpleDeviceModel(TaurusDbBaseModel):
"""A Qt model that structures device elements in 1 level tree with
device name as node leafs. This model contains only 1 column."""
ColumnNames = "Device",
ColumnRoles = (ElemType.Device, ElemType.Device),
[docs]class TaurusDbSimpleDeviceAliasModel(TaurusDbBaseModel):
"""A Qt model that structures device elements in 1 level tree with
device alias as node leafs. This model contains only 1 column."""
ColumnNames = "Alias",
ColumnRoles = (ElemType.DeviceAlias, ElemType.DeviceAlias),
[docs] def setupModelData(self, data):
if data is None:
return
if isinstance(data, TaurusDatabase):
data = data.cache()
devices = data.devices()
rootItem = self._rootItem
for dev_name in data.getDeviceNames():
dev = devices[dev_name]
if dev.alias() is not None:
devItem = TaurusTreeSimpleDeviceItem(self, dev, rootItem)
rootItem.appendChild(devItem)
[docs]class TaurusDbPlainDeviceModel(TaurusDbBaseModel):
"""A Qt model that structures device elements in 1 level tree. Device
nodes will have attribute child nodes if the device is running."""
ColumnNames = "Device", "Alias", "Server", "Class", "Alive", "Host"
ColumnRoles = (ElemType.Device, ElemType.Device, ElemType.Attribute), ElemType.DeviceAlias, ElemType.Server, ElemType.DeviceClass, ElemType.Exported, ElemType.Host
[docs] def setupModelData(self, data):
if data is None:
return
if isinstance(data, TaurusDatabase):
data = data.cache()
devices = data.devices()
rootItem = self._rootItem
for dev_name in data.getDeviceNames():
dev = devices[dev_name]
devItem = TaurusTreeDeviceItem(self, dev, rootItem)
rootItem.appendChild(devItem)
[docs]class TaurusDbDeviceModel(TaurusDbBaseModel):
"""A Qt model that structures device elements is a 3 level tree organized
as:
- <domain>
- <family>
- <member>"""
ColumnRoles = (ElemType.Device, ElemType.Domain, ElemType.Family, ElemType.Member, ElemType.Attribute), ElemType.DeviceAlias, ElemType.Server, ElemType.DeviceClass, ElemType.Exported, ElemType.Host
[docs] def setupModelData(self, data):
if data is None:
return
if isinstance(data, TaurusDatabase):
data = data.deviceTree()
rootItem = self._rootItem
for domain in data.keys():
families = data[domain]
domainItem = TaurusTreeDeviceDomainItem(self, domain.upper(), rootItem)
for family in families.keys():
members = families[family]
familyItem = TaurusTreeDeviceFamilyItem(self, family.upper(), domainItem)
for member in members.keys():
dev = members[member]
memberItem = TaurusTreeDeviceItem(self, dev, parent=familyItem)
familyItem.appendChild(memberItem)
domainItem.appendChild(familyItem)
rootItem.appendChild(domainItem)
[docs]class TaurusDbPlainServerModel(TaurusDbBaseModel):
ColumnNames = "Server", "Alive", "Host"
ColumnRoles = (ElemType.Server, ElemType.ServerInstance), ElemType.Exported, ElemType.Host
[docs] def setupModelData(self, data):
if data is None:
return
if isinstance(data, TaurusDatabase):
data = data.cache()
servers = data.servers()
rootItem = self._rootItem
for server_name, server in servers.items():
serverInstanceItem = TaurusTreeFullServerItem(self, server, rootItem)
rootItem.appendChild(serverInstanceItem)
[docs]class TaurusDbServerModel(TaurusDbBaseModel):
"""A Qt model that structures server elements in a tree organized
as:
- <Server name>
- <Server instance>
- <Class>
- <Device>
- <Attribute>"""
ColumnNames = "Server", "Alive", "Host"
ColumnRoles = (ElemType.Server, ElemType.ServerName, ElemType.ServerInstance, ElemType.DeviceClass, ElemType.Device, ElemType.Attribute), ElemType.Exported, ElemType.Host
[docs] def setupModelData(self, data):
if data is None:
return
if isinstance(data, TaurusDatabase):
data = data.cache()
servers, klasses, devices = data.servers(), data.klasses(), data.devices()
rootItem = self._rootItem
server_dict = {}
server_names = data.getServerNames()
for server_name in server_names:
server = servers[server_name]
name, instance = server.serverName(), server.serverInstance()
serverNameItem = server_dict.get(name)
if serverNameItem is None:
serverNameItem = TaurusTreeServerNameItem(self, name, rootItem)
rootItem.appendChild(serverNameItem)
server_dict[name] = serverNameItem
#rootItem.appendChild(serverNameItem)
serverInstanceItem = TaurusTreeServerItem(self, server, serverNameItem)
serverNameItem.appendChild(serverInstanceItem)
klass_names = server.getClassNames()
device_names = server.getDeviceNames()
for klass_name in klass_names:
klass = klasses[klass_name]
klassItem = TaurusTreeDeviceClassItem(self, klass, serverInstanceItem)
serverInstanceItem.appendChild(klassItem)
for dev_name in device_names:
dev = devices[dev_name]
if dev.klass() == klass:
devItem = TaurusTreeDeviceItem(self, dev, klassItem)
klassItem.appendChild(devItem)
[docs]class TaurusDbDeviceClassModel(TaurusDbBaseModel):
"""A Qt model that structures class elements in a tree organized as:
* <Class>
* <Device>
* <Attribute>"""
ColumnNames = "Class", "Alive", "Host"
ColumnRoles = (ElemType.DeviceClass, ElemType.DeviceClass, ElemType.Device, ElemType.Attribute), ElemType.Exported, ElemType.Host
[docs] def setupModelData(self, data):
if data is None:
return
if isinstance(data, TaurusDatabase):
data = data.cache()
rootItem = self._rootItem
klasses, devices = data.klasses(), data.devices()
dev_nb = 0
for klass_name in data.getClassNames():
klass = klasses[klass_name]
klassItem = TaurusTreeDeviceClassItem(self, klass, rootItem)
for dev_name in klass.getDeviceNames():
dev_nb+=1
dev = devices[dev_name]
devItem = TaurusTreeDeviceItem(self, dev, klassItem)
klassItem.appendChild(devItem)
rootItem.appendChild(klassItem)
[docs]class TaurusDbBaseProxyModel(TaurusBaseProxyModel):
pass
[docs]class TaurusDbDeviceProxyModel(TaurusDbBaseProxyModel):
"""A Qt filter & sort model for model for the taurus models:
- TaurusDbBaseModel
- TaurusDbDeviceModel
- TaurusDbSimpleDeviceModel
- TaurusDbPlainDeviceModel"""
[docs] def filterAcceptsRow(self, sourceRow, sourceParent):
sourceModel = self.sourceModel()
idx = sourceModel.index(sourceRow, 0, sourceParent)
treeItem = idx.internalPointer()
regexp = self.filterRegExp()
# if domain node, check if it will potentially have any children
if isinstance(treeItem, TaurusTreeDeviceDomainItem):
domain = treeItem.display()
devices = sourceModel.getDomainDevices(domain)
for device in devices:
if self.deviceMatches(device, regexp):
return True
return False
# if family node, check if it will potentially have any children
if isinstance(treeItem, TaurusTreeDeviceFamilyItem):
domain = treeItem.parent().display()
family = treeItem.display()
devices = sourceModel.getFamilyDevices(domain, family)
for device in devices:
if self.deviceMatches(device, regexp):
return True
return False
if isinstance(treeItem, TaurusTreeDeviceItem) or \
isinstance(treeItem, TaurusTreeSimpleDeviceItem) or \
isinstance(treeItem, TaurusTreeDeviceMemberItem):
device = treeItem.itemData()
return self.deviceMatches(device, regexp)
return True
[docs] def deviceMatches(self, device, regexp):
name = device.name()
# if Qt.QString(name).contains(regexp):
if regexp.indexIn(name) != -1:
return True
name = device.alias()
if name is None:
return False
#return Qt.QString(name).contains(regexp)
return regexp.indexIn(name) != -1
[docs]class TaurusDbServerProxyModel(TaurusDbBaseProxyModel):
"""A Qt filter & sort model for the TaurusDbServerModel"""
[docs] def filterAcceptsRow(self, sourceRow, sourceParent):
sourceModel = self.sourceModel()
idx = sourceModel.index(sourceRow, 0, sourceParent)
treeItem = idx.internalPointer()
regexp = self.filterRegExp()
# if server name node, check if it will potentially have any children
if isinstance(treeItem, TaurusTreeServerNameItem):
serverName = treeItem.display()
serverInstances = sourceModel.getServerNameInstances(serverName)
for serverInstance in serverInstances:
#if Qt.QString(serverInstance.name()).contains(regexp):
if regexp.indexIn(serverInstance.name()) != -1:
return True
return False
if isinstance(treeItem, TaurusTreeServerItem):
#return treeItem.qdisplay().contains(regexp)
return regexp.indexIn(treeItem.qdisplay()) != -1
return True
[docs]class TaurusDbDeviceClassProxyModel(TaurusDbBaseProxyModel):
"""A Qt filter & sort model for the TaurusDbDeviceClassModel"""
[docs] def filterAcceptsRow(self, sourceRow, sourceParent):
sourceModel = self.sourceModel()
idx = sourceModel.index(sourceRow, 0, sourceParent)
treeItem = idx.internalPointer()
if not isinstance(treeItem, TaurusTreeDeviceClassItem):
return True
regexp = self.filterRegExp()
#return treeItem.qdisplay().contains(regexp)
return regexp.indexIn(treeItem.qdisplay()) != -1