Source code for taurus.qt.qtcore.model.taurusdatabasemodel

#!/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
"""
# TODO: tango-centric

from taurus.external.qt import Qt
from taurus.core.taurusbasetypes import TaurusElementType, TaurusDevState
import taurus.qt.qtcore.mimetypes
from .taurusmodel import (
    TaurusBaseTreeItem,
    TaurusBaseModel,
    TaurusBaseProxyModel,
)


__docformat__ = "restructuredtext"


ElemType = TaurusElementType


def getElementTypeIcon(*args, **kwargs):
    """Wrapper to prevent loading qtgui when this module is imported"""
    from taurus.qt.qtgui.icon import getElementTypeIcon

    return getElementTypeIcon(*args, **kwargs)


def getElementTypeToolTip(*args, **kwargs):
    """Wrapper to prevent loading qtgui when this module is imported"""
    from taurus.qt.qtgui.icon import getElementTypeToolTip

    return getElementTypeToolTip(*args, **kwargs)


def getElementTypeSize(*args, **kwargs):
    """Wrapper to prevent loading qtgui when this module is imported"""
    from taurus.qt.qtgui.icon import getElementTypeSize

    return getElementTypeSize(*args, **kwargs)


def getDevStateIcon(*args, **kwargs):
    """Wrapper to prevent loading qtgui when this module is imported"""
    from taurus.qt.qtgui.icon import getDevStateIcon

    return getDevStateIcon(*args, **kwargs)


def getDevStateToolTip(*args, **kwargs):
    """Wrapper to prevent loading qtgui when this module is imported"""
    from taurus.qt.qtgui.icon import getDevStateToolTip

    return getDevStateToolTip(*args, **kwargs)


class TaurusTreeDbBaseItem(TaurusBaseTreeItem):
    try:
        # TODO: tango-centric
        import taurus.core.tango

        @staticmethod
        def DisplayFunc(obj):
            from taurus.core.tango.tangodatabase import TangoInfo

            return TangoInfo.name(obj)

    except Exception:
        pass


[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.state() 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"""
[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 data.state() != TaurusDevState.Ready: return False return True
[docs] def childCount(self): nb = super(TaurusTreeDeviceItem, self).childCount() if nb > 0: return nb data = self.itemData() if data.state() != TaurusDevState.Ready: 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.state() 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 toolTip(self, index): if index.column() > 0: return TaurusTreeDbBaseItem.toolTip(self, index) data = self.itemData() di = data.info() if di is None: return data.name() ret = '<TABLE border="0" cellpadding="1" cellspacing="0">' items = dict( name="'" + di.label + "' (" + data.name() + ")", description=di.description.replace("<", "&lt;").replace( ">", "&gt;" ), unit=di.unit, limits="[%s, %s]" % (di.min_value, di.max_value), alarms="[%s, %s]" % (di.alarms.min_alarm, di.alarms.max_alarm), warnings="[%s, %s]" % (di.alarms.min_warning, di.alarms.max_warning), ) for id, value in items.items(): ret += ( '<TR><TD WIDTH="80" ALIGN="RIGHT" VALIGN="MIDDLE">' + "<B>%s:</B></TD><TD>%s</TD></TR>" ) % (id.capitalize(), value) ret += "</TABLE>" 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.state() 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.state() 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 roleToolTip(self, taurus_role): return getElementTypeToolTip(taurus_role)
[docs] def columnToolTip(self, column): return self.roleToolTip(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(bytes(mime_data_item, encoding="utf8")) ret.setData( taurus.qt.qtcore.mimetypes.TAURUS_MODEL_LIST_MIME_TYPE, b"\r\n".join(data), ) ret.setText(", ".join(map(str, data))) if len(data) == 1: ret.setData( taurus.qt.qtcore.mimetypes.TAURUS_MODEL_MIME_TYPE, data[0] ) return ret
[docs] def pyData(self, index, role): if not index.isValid(): return None item = index.internalPointer() column, depth = 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: state = item.data(index) ret = getDevStateIcon(state) 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 = getDevStateToolTip(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 from taurus.core.tango.tangodatabase import TangoDatabase if isinstance(data, TangoDatabase): 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 from taurus.core.tango.tangodatabase import TangoDatabase if isinstance(data, TangoDatabase): 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 from taurus.core.tango.tangodatabase import TangoDatabase if isinstance(data, TangoDatabase): 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 in 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 try: # TODO: Tango-centric # TODO: is this try needed? from taurus.core.tango.tangodatabase import TangoDatabase except ImportError: return if isinstance(data, TangoDatabase): data = data.deviceTree() rootItem = self._rootItem for domain in data: families = data[domain] domainItem = TaurusTreeDeviceDomainItem( self, domain.upper(), rootItem ) for family in families: members = families[family] familyItem = TaurusTreeDeviceFamilyItem( self, family.upper(), domainItem ) for member in members: 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 from taurus.core.tango.tangodatabase import TangoDatabase if isinstance(data, TangoDatabase): 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 from taurus.core.tango.tangodatabase import TangoDatabase if isinstance(data, TangoDatabase): 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 = server.serverName() # keep an instance instance = server.serverInstance() # noqa: F841 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 from taurus.core.tango.tangodatabase import TangoDatabase if isinstance(data, TangoDatabase): 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 regexp.indexIn(name) != -1: return True name = device.alias() if name is None: return False 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 regexp.indexIn(serverInstance.name()) != -1: return True return False if isinstance(treeItem, TaurusTreeServerItem): # return treeItem.qdisplay().contains(regexp) return regexp.indexIn(treeItem.display()) != -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.display()) != -1