#!/usr/bin/env python
# -*- coding: utf-8 -*-
# ###########################################################################
#
# 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 a set of basic Taurus widgets based on QLed
"""
import weakref
from collections.abc import Sequence
from taurus.external.qt import Qt
from taurus.core import DataFormat, AttrQuality, DataType
from taurus.core.taurusbasetypes import TaurusEventType
from taurus.qt.qtgui.base import TaurusBaseWidget
from .qled import QLed
__docformat__ = "restructuredtext"
_QT_PLUGIN_INFO = {
"module": "taurus.qt.qtgui.display",
"group": "Taurus Display",
"icon": "designer:ledgreen.png",
}
class _TaurusLedController(object):
# key status, color, inTrouble
LedMap = {
True: (True, "green", False),
False: (False, "black", False),
None: (False, "black", True),
}
LedQualityMap = {
AttrQuality.ATTR_ALARM: (True, "orange", False),
AttrQuality.ATTR_CHANGING: (True, "blue", False),
AttrQuality.ATTR_INVALID: (True, "red", False),
AttrQuality.ATTR_VALID: (True, "green", False),
AttrQuality.ATTR_WARNING: (True, "orange", False),
None: (False, "black", True),
}
def __init__(self, widget):
self._widget = weakref.ref(widget)
def widget(self):
return self._widget()
def modelObj(self):
return self.widget().getModelObj()
def value(self):
widget, obj = self.widget(), self.modelObj()
fgRole = widget.fgRole
value = None
if fgRole == "rvalue":
value = obj.rvalue
elif fgRole == "wvalue":
value = obj.wvalue
elif fgRole == "quality":
return obj.quality
# handle 1D and 2D values
if obj.data_format is not DataFormat._0D:
idx = widget.getModelIndexValue()
if idx:
for i in idx:
value = value[i]
return value if value is None else bool(value)
def usePreferedColor(self, widget):
return True
def handleEvent(self, evt_src, evt_type, evt_value):
self.update()
def update(self):
widget = self.widget()
self._updateDisplay(widget)
self._updateToolTip(widget)
def _updateDisplay(self, widget):
key = None
try:
key = self.value()
except Exception:
pass
ledMap = self.LedMap
if widget.fgRole == "quality":
ledMap = self.LedQualityMap
try:
status, color, trouble = ledMap[key]
except Exception:
status, color, trouble = False, "red", True
if self.usePreferedColor(widget) and not trouble:
if status:
color = widget.onColor
else:
color = widget.offColor
widget.ledStatus = status
widget.ledColor = color
if trouble:
widget.setAutoFillBackground(True)
bg_brush = Qt.QBrush(Qt.Qt.BDiagPattern)
palette = widget.palette()
palette.setBrush(Qt.QPalette.Window, bg_brush)
palette.setBrush(Qt.QPalette.Base, bg_brush)
widget.setPalette(palette)
else:
widget.setAutoFillBackground(False)
def _updateToolTip(self, widget):
widget.setToolTip(widget.getFormatedToolTip())
class _TaurusLedControllerBool(_TaurusLedController):
def usePreferedColor(self, widget):
# use prefered widget color if representing the boolean read or write
# value. If representing the quality, use the quality map
return widget.fgRole != "quality"
try:
from taurus.core.tango import DevState # TODO: Tango-centric
class _TaurusLedControllerState(_TaurusLedController):
# key status, color, inTrouble
LedMap = {
DevState.ON: (True, "green", False),
DevState.OFF: (False, "black", False),
DevState.CLOSE: (True, "white", False),
DevState.OPEN: (True, "green", False),
DevState.INSERT: (True, "white", False),
DevState.EXTRACT: (True, "green", False),
DevState.MOVING: (True, "blue", False),
DevState.STANDBY: (True, "yellow", False),
DevState.FAULT: (True, "red", False),
DevState.INIT: (True, "yellow", False),
DevState.RUNNING: (True, "blue", False),
DevState.ALARM: (True, "orange", False),
DevState.DISABLE: (True, "magenta", False),
DevState.UNKNOWN: (False, "black", False),
None: (False, "black", True),
}
def value(self):
widget, obj = self.widget(), self.modelObj()
fgRole = widget.fgRole
value = None
if fgRole == "rvalue":
value = obj.rvalue
elif fgRole == "wvalue":
value = obj.wvalue
elif fgRole == "quality":
value = obj.quality
return value
def usePreferedColor(self, widget):
# never use prefered widget color. Use always the map
return False
except Exception:
pass
class _TaurusLedControllerDesignMode(_TaurusLedController):
def _updateDisplay(self, widget):
widget.ledStatus = True
if widget.ledStatus:
widget.ledColor = widget.onColor
else:
widget.ledColor = widget.offColor
widget.setAutoFillBackground(False)
def _updateToolTip(self, widget):
widget.setToolTip("Design mode TaurusLed")
[docs]
class TaurusLed(QLed, TaurusBaseWidget):
"""A widget designed to represent with a LED image the state of a device,
the value of a boolean attribute or the quality of an attribute.
"""
DefaultModelIndex = None
DefaultFgRole = "rvalue"
DefaultOnColor = "green"
DefaultOffColor = "green"
_deprecatedRoles = dict(value="rvalue", w_value="wvalue")
def __init__(self, parent=None, designMode=False):
name = self.__class__.__name__
self._designMode = designMode
self._modelIndex = self.DefaultModelIndex
self._modelIndexStr = ""
self._fgRole = self.DefaultFgRole
self._onColor = self.DefaultOnColor
self._offColor = self.DefaultOffColor
self._controller = None
self.call__init__wo_kw(QLed, parent)
self.call__init__(TaurusBaseWidget, name, designMode=designMode)
self.controller().update()
def _calculate_controller_class(self):
model = self.getModelObj()
klass = _TaurusLedController
if self._designMode:
klass = _TaurusLedControllerDesignMode
elif model is None:
klass = _TaurusLedController
elif model.isBoolean():
klass = _TaurusLedControllerBool
elif model.type == DataType.DevState:
klass = _TaurusLedControllerState # TODO: tango-centric
return klass
[docs]
def controller(self):
ctrl = self._controller
# if there is a controller object and it is not the base controller...
if ctrl is not None and not ctrl.__class__ == _TaurusLedController:
return ctrl
# if there is a controller object and it is still the same class...
ctrl_klass = self._calculate_controller_class()
if ctrl is not None and ctrl.__class__ == ctrl_klass:
return ctrl
self._controller = ctrl = ctrl_klass(self)
return ctrl
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
# TaurusBaseWidget overwriting
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
[docs]
def handleEvent(self, evt_src, evt_type, evt_value):
if evt_type in (TaurusEventType.Change, TaurusEventType.Periodic):
self.emitValueChanged()
self.controller().handleEvent(evt_src, evt_type, evt_value)
[docs]
def isReadOnly(self):
return True
[docs]
def setModel(self, m, **kwargs):
# force to build another controller
self._controller = None
TaurusBaseWidget.setModel(self, m, **kwargs)
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
# QT property definition
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
[docs]
def getFgRole(self):
return self._fgRole
[docs]
def setFgRole(self, fgRole):
role = self._deprecatedRoles.get(fgRole, fgRole)
if fgRole != role:
self.deprecated(
rel="4.0",
dep="setFgRole(%s)" % fgRole,
alt="setFgRole(%s)" % role,
)
self._fgRole = str(role)
self.controller().update()
[docs]
def resetFgRole(self):
self.setFgRole(self.DefaultFgRole)
[docs]
def getOnColor(self):
"""Returns the preferred led on color
:return: led on color
:rtype: str
"""
return self._onColor
[docs]
def setOnColor(self, color):
"""Sets the preferred led on color
:param status: the new on color
:type status: str
"""
color = str(color).lower()
if not self.isLedColorValid(color):
raise Exception("Invalid color '%s'" % color)
self._onColor = color
self.controller().update()
[docs]
def resetOnColor(self):
"""Resets the preferred led on color"""
self.setOnColor(self.DefaultOnColor)
[docs]
def getOffColor(self):
"""Returns the preferred led off color
:return: led off color
:rtype: str
"""
return self._offColor
[docs]
def setOffColor(self, color):
"""Sets the preferred led off color
:param status: the new off color
:type status: str
"""
color = str(color).lower()
if not self.isLedColorValid(color):
raise Exception("Invalid color '%s'" % color)
self._offColor = color
self.controller().update()
[docs]
def resetOffColor(self):
"""Resets the preferred led color"""
self.setOffColor(self.DefaultOffColor)
[docs]
def getModelIndexValue(self):
return self._modelIndex
[docs]
def getModelIndex(self):
return self._modelIndexStr
[docs]
def setModelIndex(self, modelIndex):
mi = str(modelIndex)
if len(mi) == 0:
self._modelIndex = None
else:
try:
mi_value = eval(str(mi))
except Exception:
return
if type(mi_value) == int:
mi_value = (mi_value,)
if not isinstance(mi_value, Sequence):
return
self._modelIndex = mi_value
self._modelIndexStr = mi
self.controller().update()
[docs]
def resetModelIndex(self):
self.setModelIndex(self.DefaultModelIndex)
[docs]
@classmethod
def getQtDesignerPluginInfo(cls):
d = TaurusBaseWidget.getQtDesignerPluginInfo()
d.update(_QT_PLUGIN_INFO)
return d
#: This property holds the unique URI string representing the model name
#: with which this widget will get its data from. The convention used for
#: the string can be found :ref:`here <model-concept>`.
#:
#: **Access functions:**
#:
#: * :meth:`TaurusBaseWidget.getModel`
#: * :meth:`TaurusLabel.setModel`
#: * :meth:`TaurusBaseWidget.resetModel`
#:
#: .. seealso:: :ref:`model-concept`
model = Qt.pyqtProperty(
"QString",
TaurusBaseWidget.getModel,
setModel,
TaurusBaseWidget.resetModel,
)
#: (deprecated))
useParentModel = Qt.pyqtProperty(
"bool",
TaurusBaseWidget.getUseParentModel,
TaurusBaseWidget.setUseParentModel,
TaurusBaseWidget.resetUseParentModel,
)
#: This property holds the index inside the model value that should be
#: displayed
#:
#: **Access functions:**
#:
#: * :meth:`TaurusLed.getModelIndex`
#: * :meth:`TaurusLed.setModelIndex`
#: * :meth:`TaurusLed.resetModelIndex`
#:
#: .. seealso:: :ref:`model-concept`
modelIndex = Qt.pyqtProperty(
"QString", getModelIndex, setModelIndex, resetModelIndex
)
#: This property holds the foreground role.
#: Valid values are:
#:
#: #. 'value' - the value is used
#: #. 'w_value' - the write value is used
#: #. 'quality' - the quality is used
#:
#: **Access functions:**
#:
#: * :meth:`TaurusLed.getFgRole`
#: * :meth:`TaurusLed.setFgRole`
#: * :meth:`TaurusLed.resetFgRole`
fgRole = Qt.pyqtProperty(
"QString", getFgRole, setFgRole, resetFgRole, doc="foreground role"
)
#: This property holds the preferred led color
#: This value is used for the cases where the model value does not contain
#: enough information to distinguish between different On colors.
#: For example, a bool attribute, when it is False it is displayed with the
#: off led but when it is true it may be displayed On in any color. The
#: prefered color would be used in this case.
#:
#: **Access functions:**
#:
#: * :meth:`TaurusLed.getOnColor`
#: * :meth:`TaurusLed.setOnColor`
#: * :meth:`TaurusLed.resetOnColor`
onColor = Qt.pyqtProperty(
"QString",
getOnColor,
setOnColor,
resetOnColor,
doc="preferred led On color",
)
#: This property holds the preferred led color
#: This value is used for the cases where the model value does not contain
#: enough information to distinguish between different Off colors.
#: For example, a bool attribute, when it is False it is displayed with the
#: off led but when it is true it may be displayed On in any color. The
#: prefered color would be used in this case.
#:
#: **Access functions:**
#:
#: * :meth:`TaurusLed.getOffColor`
#: * :meth:`TaurusLed.setOffColor`
#: * :meth:`TaurusLed.resetOffColor`
offColor = Qt.pyqtProperty(
"QString",
getOffColor,
setOffColor,
resetOffColor,
doc="preferred led Off color",
)
def demo():
"Led"
from .demo import taurusleddemo
return taurusleddemo.main()
def main():
import sys
import taurus.qt.qtgui.application
Application = taurus.qt.qtgui.application.TaurusApplication
app = Application.instance()
owns_app = app is None
if owns_app:
import taurus.core.util.argparse
parser = taurus.core.util.argparse.get_taurus_parser()
parser.usage = "%prog [options] <full_attribute_name(s)>"
app = Application(
sys.argv,
cmd_line_parser=parser,
app_name="Taurus led demo",
app_version="1.0",
org_domain="Taurus",
org_name="Tango community",
)
args = app.get_command_line_args()
if len(args) == 0:
w = demo()
else:
models = map(str.lower, args)
w = Qt.QWidget()
layout = Qt.QGridLayout()
w.setLayout(layout)
for model in models:
led = TaurusLed()
led.model = model
layout.addWidget(led)
w.show()
if owns_app:
sys.exit(app.exec_())
else:
return w
if __name__ == "__main__":
main()