Source code for taurus.qt.qtgui.display.taurusled

#!/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.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): 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()