#!/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 the set of base class taurus controllers."""
from builtins import str
from builtins import object
import weakref
from taurus.external.qt import Qt
from taurus.core.taurusbasetypes import DataFormat, TaurusEventType
from taurus.qt.qtgui.util import QT_ATTRIBUTE_QUALITY_PALETTE
from taurus.qt.qtgui.util import QT_DEVICE_STATE_PALETTE
__all__ = ["TaurusBaseController", "TaurusAttributeControllerHelper",
"TaurusScalarAttributeControllerHelper",
"TaurusConfigurationControllerHelper",
"updateLabelBackground"]
__docformat__ = 'restructuredtext'
[docs]class TaurusBaseController(object):
"""Base class for all taurus controllers"""
def __init__(self, widget, updateAsPalette=True):
self._widget = weakref.ref(widget)
self._updateAsPalette = updateAsPalette
self._stateObj = None
self._last_value = None
self._last_config_value = None
self._last_error_value = None
self._setStyle()
def _setStyle(self):
pass
[docs] def usePalette(self):
return self._updateAsPalette
[docs] def modelObj(self):
return self.widget().getModelObj()
attrObj = configObj = deviceObj = modelObj
[docs] def valueObj(self):
value = self._last_value
if value is None:
modelObj = self.modelObj()
if modelObj is None:
return None
value = modelObj.getValueObj()
return value
[docs] def value(self):
valueObj = self.valueObj()
return getattr(valueObj, "value", None)
[docs] def w_value(self): # TODO: adapt to tep14
valueObj = self.valueObj()
return getattr(valueObj, "w_value", None)
[docs] def quality(self):
valueObj = self.valueObj()
return getattr(valueObj, "quality", None)
[docs] def state(self):
return self._stateObj.state
[docs] def getDisplayValue(self, write=False):
return self.widget().getDisplayValue()
[docs] def handleEvent(self, evt_src, evt_type, evt_value):
# update the "_last" values only if the event source is the model
# (it could be the background...)
if evt_src == self.modelObj():
if evt_type in (TaurusEventType.Change, TaurusEventType.Periodic):
if self._last_value is None:
# reset the format so that it gets updated by displayValue
self.widget().resetFormat()
self._last_value = evt_value
elif evt_type == TaurusEventType.Config: # TODO: adapt to tep14
self._last_config_value = evt_value
self.widget().resetFormat()
else:
self._last_error_value = evt_value
# In case of error, modify the last_value as well
try:
self._last_value = self.modelObj().getValueObj()
except:
self._last_value = None
self.update()
[docs] def eventReceived(self, evt_src, evt_type, evt_value):
# should handle the state event here. Because this is invoked by a random
# thread, we pass it to the widget, which will forward to the proper
# thread
#@todo: sometimes we get this method called but self.widget() is None. Check why.
# For the moment I just protect it by substituting the following line by the ones after it
#self.widget().eventReceived(evt_src, evt_type, evt_value)
w = self.widget()
if w is not None:
w.eventReceived(evt_src, evt_type, evt_value)
[docs] def update(self):
widget = self.widget()
self._updateConnections(widget)
self._updateForeground(widget)
self._updateBackground(widget)
self._updateToolTip(widget)
def _needsStateConnection(self):
return False
def _updateConnections(self, widget):
stateObj, newStateObj = self._stateObj, None
if self._needsStateConnection():
newStateObj = self.deviceObj()
if stateObj != newStateObj:
if stateObj is not None:
stateObj.removeListener(self)
if newStateObj is not None:
newStateObj.addListener(self)
else:
if stateObj is not None:
stateObj.removeListener(self)
self._stateObj = newStateObj
def _updateForeground(self, widget):
pass
def _updateBackground(self, widget):
pass
def _updateToolTip(self, widget):
if widget.getAutoTooltip():
widget.setToolTip(widget.getFormatedToolTip())
[docs]class TaurusAttributeControllerHelper(object):
[docs] def configObj(self):
return self.attrObj() # they are the same object since tep14
# attrObj = self.attrObj()
# if attrObj is None: return None
# return attrObj.getConfig()
[docs] def deviceObj(self):
attrObj = self.attrObj()
if attrObj is None:
return None
return attrObj.getParentObj()
[docs]class TaurusScalarAttributeControllerHelper(TaurusAttributeControllerHelper):
[docs] def getDisplayValue(self, write=False):
valueObj = self.valueObj()
widget = self.widget()
if valueObj is None or valueObj.rvalue is None:
return widget.getDisplayValue()
format = self.attrObj().data_format
if format == DataFormat._0D:
return self._getDisplayValue(widget, valueObj, None, write)
idx = widget.getModelIndexValue()
return self._getDisplayValue(widget, valueObj, idx, write)
def _getDisplayValue(self, widget, valueObj, idx, write):
try:
if write:
value = valueObj.wvalue
else:
value = valueObj.rvalue
if idx is not None and len(idx):
for i in idx:
value = value[i]
return widget.displayValue(value)
except Exception as e:
return widget.getNoneValue()
[docs] def displayValue(self, value):
if value is None:
return None
ret = None
try:
if self.isScalar():
format = self.getFormat()
if self.isNumeric() and format is not None:
format = self.getFormat()
ret = self.getFormat() % value
else:
ret = str(value)
elif self.isSpectrum():
ret = str(value)
else:
ret = str(value)
except:
# if cannot calculate value based on the format just return the
# value
raise
ret = str(value)
return ret
[docs]class TaurusConfigurationControllerHelper(object):
#TODO: Check if this is used. If so, rename to avoid "Configuration"
def __init__(self):
self._configParam = None
[docs] def attrObj(self):
return self.configObj() # they are the same object since tep14
[docs] def deviceObj(self):
attrObj = self.attrObj()
if attrObj is None:
return None
return attrObj.getParentObj()
@property
def configParam(self):
if self._configParam is None:
self._configParam = self.widget().modelFragmentName or ''
return self._configParam
[docs] def getDisplayValue(self, write=False):
widget = self.widget()
model = self.configObj()
if model is None:
return widget.getNoneValue()
param = self.configParam
try:
val = widget.getModelFragmentObj()
try:
no_val = getattr(model, "no_" + param) # TODO: Tango-centric
if val.lower() == no_val.lower():
val = widget.getNoneValue()
except:
pass
except AttributeError:
if param:
val = str(param)
attr = self.attrObj()
if attr is not None:
val = val.replace('<label>', attr.label or '---')
val = val.replace('<attr_name>', attr.name or '---')
val = val.replace('<attr_fullname>', attr.getFullName() or
'---')
dev = self.deviceObj()
if dev is not None:
val = val.replace('<dev_fullname>', dev.getFullName() or
'---')
val = val.replace('<dev_alias>', dev.getSimpleName() or
'---')
val = val.replace('<dev_name>', dev.getNormalName() or
'---')
else:
val = widget.getNoneValue()
except:
widget.debug("Invalid configuration parameter '%s'" % param)
val = widget.getNoneValue()
if val is None:
val = widget.getNoneValue()
return val
StyleSheetTemplate = """border-style: outset; border-width: 2px; border-color: {0}; {1}"""
def _updatePaletteColors(widget, bgBrush, fgBrush, frameBrush):
qt_palette = widget.palette()
qt_palette.setBrush(Qt.QPalette.Window, bgBrush)
qt_palette.setBrush(Qt.QPalette.Base, bgBrush)
qt_palette.setBrush(Qt.QPalette.WindowText, fgBrush)
qt_palette.setBrush(Qt.QPalette.Light, frameBrush)
qt_palette.setBrush(Qt.QPalette.Dark, frameBrush)
widget.setPalette(qt_palette)
[docs]def updateLabelBackground(ctrl, widget):
"""Helper method to setup background of taurus labels and lcds"""
bgRole = widget.bgRole
if ctrl.usePalette():
widget.setAutoFillBackground(True)
if bgRole in ('', 'none', 'None'):
transparentBrush = Qt.QBrush(Qt.Qt.transparent)
frameBrush = transparentBrush
bgBrush, fgBrush = transparentBrush, Qt.QBrush(Qt.Qt.black)
else:
frameBrush = Qt.QBrush(Qt.QColor(255, 255, 255, 128))
bgItem, palette = None, QT_DEVICE_STATE_PALETTE
if bgRole == 'quality':
palette = QT_ATTRIBUTE_QUALITY_PALETTE
bgItem = ctrl.quality()
elif bgRole == 'state':
bgItem = ctrl.state()
elif bgRole == 'value':
bgItem = ctrl.value()
else:
# TODO: this is an *experimental* extension of the bgRole API
# added in v 4.1.2-alpha. It may change in future versions
modelObj = widget.getModelObj()
try:
bgItem = modelObj.getFragmentObj(bgRole)
except:
widget.warning('Invalid bgRole "%s"', bgRole)
bgBrush, fgBrush = palette.qbrush(bgItem)
_updatePaletteColors(widget, bgBrush, fgBrush, frameBrush)
else:
if bgRole in ('', 'none', 'None'):
ss = StyleSheetTemplate.format("rgba(0,0,0,0)", "")
else:
bgItem, palette = None, QT_DEVICE_STATE_PALETTE
if bgRole == 'quality':
palette = QT_ATTRIBUTE_QUALITY_PALETTE
bgItem = ctrl.quality()
elif bgRole == 'state':
bgItem = ctrl.state()
elif bgRole == 'value':
bgItem = ctrl.value()
else:
# TODO: this is an *experimental* extension of the bgRole API
# added in v 4.1.2-alpha. It may change in future versions
modelObj = widget.getModelObj()
try:
bgItem = modelObj.getFragmentObj(bgRole)
except:
widget.warning('Invalid bgRole "%s"', bgRole)
color_ss = palette.qtStyleSheet(bgItem)
ss = StyleSheetTemplate.format("rgba(255,255,255,128)", color_ss)
widget.setStyleSheet(ss)
widget.update() # necessary in pyqt <= 4.4