Source code for panic.widgets
"""
This file belongs to the PANIC Alarm Suite, developed by ALBA Synchrotron for Tango Control System
GPL Licensed
Enjoy,
Sergi Rubio, 2010
"""
import sys, os, taurus, fandango, PyTango, getpass, traceback, time
from PyQt4 import Qt, QtCore, QtGui
from taurus.qt.qtgui.base.taurusbase import TaurusBaseComponent
from taurus.qt.qtgui.base.taurusbase import TaurusBaseWidget
try:
from taurus.qt.qtgui.display.taurusvaluelabel import TaurusValueLabel
except:
from taurus.qt.qtgui.display.tauruslabel import TaurusLabel as TaurusValueLabel
from taurus.qt.qtgui.container import TaurusMainWindow
from taurus.qt.qtgui.panel import TaurusForm
import panic
from panic import AlarmAPI
try:
#if available, this module will try to load the full AlarmGUI
from panic.gui import AlarmGUI
except: AlarmGUI = None
###############################################################################
[docs]def getThemeIcon(icon):
if 3 == int(taurus.Release().version_info[0]):
from taurus.qt.qtgui import resource
if ':' in icon:
icon = resource.getIcon(icon)
else:
icon = resource.getThemeIcon(icon)
else:
if ':' in icon:
icon = icon.replace('/',':').strip(':')
icon = Qt.QIcon(icon)
else:
icon = Qt.QIcon.fromTheme(icon)
return icon
###############################################################################
[docs]class GuiWidget(QtGui.QWidget):
def __init__(self,parent=None):
QtGui.QWidget.__init__(self,parent)
self._gui = AlarmGUI()
self._gui.setRowModels()
[docs] def editAlarm(self, alarm):
item=self._gui._ui.listWidget.findItems(alarm, QtCore.Qt.MatchStartsWith)
item[0].setSelected(True)
pos=self._gui._ui.listWidget.row(item[0])
self._gui.setAlarmData(pos)
self._gui.onEdit()
[docs] def show(self):
self._gui.show()
self._gui.raise_()
self._gui.activateWindow()
##############################################################################
[docs]class AlarmValueLabel(TaurusValueLabel):
[docs] def setModel(self,model):
if fandango.isString(model) and '/' not in model:
model = str(model)
model = panic.AlarmAPI(model)[model]
if isinstance(model,panic.Alarm):
model = model.device + '/' + model.get_attribute()
TaurusValueLabel.setModel(self,model)
[docs] def updateStyle(self,extra=''):
self.setAlignment(QtCore.Qt.AlignCenter)
value = getattr(self.getModelValueObj(), 'value', None)
if value:
self.ss = "background-color:red; color:black;"
self.setText("ALARM")
elif value is None:
self.ss = "background-color:grey; color:black;"
self.setText("NONE")
else:
self.ss = "background-color:lightgreen; color:black;"
self.setText("OK")
self.setStyleSheet(self.ss)
TaurusBaseWidget.updateStyle(self)
###############################################################################
[docs]class ToolbarActionButton(TaurusBaseComponent, Qt.QPushButton):
SHOW_FAILED_ALARMS = False
LEDS = {
'OFF':':/leds/images24/ledblueoff.png',
'OK':':/leds/images24/ledgreen.png',
'ALARM':':/leds/images24/ledred.png',
'WARNING':':/leds/images24/ledorange.png',
'DEBUG':':/leds/images24/ledyellow.png',
'ERROR':':/leds/images24/ledredoff.png',
'CHANGING':':/leds/images24/ledblue.png'
}
def __init__(self,gui,api,parent=None):
TaurusBaseComponent.__init__(self,parent)
Qt.QPushButton.__init__(self,parent)
self.guiApp = gui
self.api = api
self.value = None
self.setIconSize(Qt.QSize(25,25))
[docs] def setAlarmModel(self,tag):
attr = self.api[tag].get_attribute(full=True)
print('In PanicToolbarAction.setAlarmModel(%s = %s)'%(tag,attr))
self.tag = tag
self.setModel(attr)
[docs] def setModel(self,model):
print('In PanicToolbarAction.setModel(%s)'%model)
TaurusBaseComponent.setModel(self,model)
self.setIcon(self.getIcon('OFF'))
[docs] def getIcon(self,url):
print "ToolbarAction.getIcon(%s)"%url
if url in self.LEDS: url = self.LEDS[url]
icon = taurus.qt.qtgui.resource.getIcon(url)
return icon
[docs] def handleEvent(self,evt_src,evt_type,evt_value):
print('In PanicToolbarAction.handleEvent(%s)'%self.getModel())
TaurusBaseComponent.handleEvent(self, evt_src, evt_type, evt_value)
if all(hasattr(evt_value,a) for a in ('value','quality')):
self.value = evt_value.value
self.api[self.tag].active = (time.time() if evt_value.value else 0)
if evt_value.quality == PyTango.AttrQuality.ATTR_INVALID:
self.setIcon(getThemeIcon("software-update-urgent"))
elif not evt_value.value:
self.setIcon(self.getIcon('OK'))
elif evt_value.quality == PyTango.AttrQuality.ATTR_VALID:
self.setIcon(getThemeIcon("applications-development"))
elif evt_value.quality == PyTango.AttrQuality.ATTR_WARNING:
self.setIcon(getThemeIcon("emblem-important"))
elif evt_value.quality == PyTango.AttrQuality.ATTR_ALARM:
self.setIcon(getThemeIcon("software-update-urgent"))
elif evt_value.quality == PyTango.AttrQuality.ATTR_CHANGING:
self.setIcon(self.getIcon('CHANGING'))
else:
self.setIcon(getThemeIcon("dialog-error"))
self.setVisible(self.SHOW_FAILED_ALARMS) #!!!
pass
[docs] def buildMenu(self):
self.popMenu = Qt.QMenu()
tooltip = str(self.toolTip())
name,date = tuple(tooltip.split('\n')[:2]) if '\n' in tooltip else (tooltip,'')
q0 = Qt.QAction(name,self.popMenu)
f =q0.font()
f.setBold(True)
q0.setFont(f)
self.popMenu.addAction(q0)
if date:
q1 = Qt.QAction(date,self.popMenu)
q1.setFont(f)
self.popMenu.addAction(q1)
self.popMenu.addAction(getThemeIcon("media-playback-pause"), "Acknowledge",self.onAcknowledge)
self.popMenu.addAction(getThemeIcon("dialog-error"), "Disable",self.onDisable)
self.popMenu.addAction(getThemeIcon("edit-undo"), "Reset Alarm",self.onReset)
self.popMenu.addAction(getThemeIcon("accessories-text-editor"), "Edit Alarm",self.onEdit)
self.popMenu.addAction(getThemeIcon("office-calendar"), "View History",self.onHistory)
self.setMenu(self.popMenu)
[docs] def onAcknowledge(self):
print('onAcknowledge')
self.name=str(self.getModel().split('/')[-1]).strip(' ')
print(self.name)
if not taurus.Device(self.getModel().rsplit('/',1)[0]).command_inout('CheckAcknowledged',str(self.name)):
prompt=QtGui.QInputDialog
comment, ok=prompt.getText(self,'Input dialog','This will prevent reminders from sending.\nType a comment to continue:')
if ok and len(str(comment)) > 3:
try:
comment=str(getpass.getuser())+': '+comment
print('acknowledging %s with comment: %s !' %(self.name, comment))
taurus.Device(self.getModel().rsplit('/',1)[0]).command_inout('Acknowledge',[str(self.name), str(comment)])
except:
print traceback.format_exc()
else:
Qt.QMessageBox.critical(self,"Error!",'Comment too short.\nAlarm not acknowledged.', QtGui.QMessageBox.AcceptRole, QtGui.QMessageBox.AcceptRole)
elif not ok:
pass
else:
Qt.QMessageBox.information(self,"Info!",'Alarm already acknowldged.', QtGui.QMessageBox.AcceptRole, QtGui.QMessageBox.AcceptRole)
[docs] def onDisable(self):
print('onDisable')
self.name=str(self.getModel().split('/')[-1]).strip(' ')
print(self.name)
if not taurus.Device(self.getModel().rsplit('/',1)[0]).command_inout('CheckDisabled',str(self.name)):
reply=Qt.QMessageBox.question(self,"Warning!","Alarm will be disabled.\nDo you want to continue?", QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.Yes)
if reply == QtGui.QMessageBox.Yes:
print('disable %s !' %self.name)
comment='DISABLED by '+str(getpass.getuser())
taurus.Device(self.getModel().rsplit('/',1)[0]).command_inout('Disable', [str(self.name), str(comment)])
else:
Qt.QMessageBox.information(self,"Info!",'Alarm already disabled.', QtGui.QMessageBox.AcceptRole, QtGui.QMessageBox.AcceptRole)
[docs] def onReset(self):
print('onReset')
self.name=str(self.getModel().split('/')[-1]).strip(' ')
print(self.name)
prompt=QtGui.QInputDialog
comment, ok=prompt.getText(self,'Input dialog','This will reset the alarm.\nType a comment to continue:')
if ok and len(str(comment)) > 3:
try:
comment=str(getpass.getuser())+': '+comment
print('reseting %s with comment: %s !' %(self.name, comment))
taurus.Device(self.getModel().rsplit('/',1)[0]).command_inout('ResetAlarm',[str(self.name), str(comment)])
except:
print traceback.format_exc()
elif not ok:
pass
else:
Qt.QMessageBox.critical(self,"Error!",'Comment too short.\nAlarm not reseted.', QtGui.QMessageBox.AcceptRole, QtGui.QMessageBox.AcceptRole)
[docs] def onEdit(self):
print('onEdit')
self.name=str(self.getModel().split('/')[-1]).strip(' ')
if self.guiApp is None: self.parent().showGui()
self.guiApp.editAlarm(self.name)
self.guiApp.show()
[docs] def onHistory(self):
print('onHistory')
self.name=str(self.getModel().split('/')[-1]).strip(' ')
self.ahApp = ahWidget()
self.ahApp.setAlarmCombo(alarm=self.name)
self.ahApp.show()
[docs]class PanicToolbar(TaurusBaseWidget, Qt.QToolBar):
def __init__(self,parent=None,container=None,filters=None,max_visible=16,refresh=10000):
Qt.QToolBar.__init__(self,parent)
self.api = None
self.filters = filters
self.max_visible = max_visible
self.filters = filters or []
self.buttons = {}
self.setIconSize(Qt.QSize(25,25))
self.gui = None
self.setup()
self.refresh()
self.refreshTimer = QtCore.QTimer()
QtCore.QObject.connect(self.refreshTimer, QtCore.SIGNAL("timeout()"), self.refresh)
self.refreshTimer.start(refresh)
def _get_alarm_date(self, device, alarm):
res=''
try:
attr = taurus.Attribute(device+'/ActiveAlarms').read().value
for line in attr:
if line.startswith(alarm+':'):
res = line.split(':')
break
except Exception,e:
print ('Cant get the alarm date!')
return res
[docs] def showGui(self):
try:
if self.gui is None: self.gui = GuiWidget()
self.gui.show()
except:
print traceback.format_exc()
print 'AlarmGUI not available in PYTHONPATH'
import os
os.system('panic &')
return self.gui
[docs] def setup(self,filters=None,api=None):#, alarms=None):
print "In PanicToolbar.setup(%s)"%filters
self.setMovable(True)
self.setFloatable(True)
filters = filters or self.filters
if not self.api: self.api = api or AlarmAPI(filters)
else: self.api.load(filters)
self.alarms = [] #dict((a,) for a in self.api) #Alarms must be set here and not in refresh;
#We should never clear this list again
if filters and filters not in self.filters:
if isinstance(filters,basestring): self.filters.append(filters)
else: self.filters.extend(filters)
self.filter_alarms()
return
[docs] def filter_alarms(self):
te = fandango.TangoEval()
for alarm in self.api:
if alarm in self.alarms: continue
try:
if not self.filters:
self.alarms.append(alarm)
else:
attrs = ['%s/%s'%(v[0],v[1]) for v in te.parse_variables(self.api[alarm].formula)]
tags = [alarm]+self.api.parse_alarms(self.api[alarm].formula)
if any(fandango.functional.matchCl(f,a) for f in self.filters for a in (attrs if '/' in f else tags)):
self.alarms.append(alarm)
except:
print 'In PanicToolbar.filter_alarms(): Unable to parse %s:\n%s'%(alarm,traceback.format_exc())
if self.alarms: print 'In PanicToolbar.refresh(): %d alarms out of %d matches filters'%(len(self.alarms),len(self.api.keys()))
else: print 'In PanicToolbar.refresh(): no Alarm matches %s'%self.filters
return self.alarms
[docs] def refresh(self):
print 'In PanicToolbar.refresh(): filters = %s'%self.filters
if not self.filters: #(alarms!='*'):
self.filters=[]
factory = taurus.Factory()
for a in factory.getExistingAttributes():
self.filters.append(str(a).split('/',1)[1])
self.filter_alarms()
visible=0
def sorter(obj):
print '%s -> %s' % (obj.tag, obj.active)
quality = self.api[obj.tag].get_quality()
#full_attr_name = obj.device+'/'+obj.get_attribute()
#try:
#quality = taurus.Attribute(full_attr_name).read().quality
#except:
#quality = PyTango.AttrQuality.ATTR_INVALID
if quality==PyTango.AttrQuality.ATTR_ALARM:
return '%d,%d,%s'%(1-bool(obj.active), 0, obj.tag)
elif quality==PyTango.AttrQuality.ATTR_WARNING:
return '%d,%d,%s'%(1-bool(obj.active), 1, obj.tag)
elif quality==PyTango.AttrQuality.ATTR_VALID:
return '%d,%d,%s'%(1-bool(obj.active), 2, obj.tag)
elif quality==PyTango.AttrQuality.ATTR_INVALID:
return '%d,%d,%s'%(1-bool(obj.active), 3, obj.tag)
l = [(a,self.api[a]) for a in self.alarms]
print('Sorting ...')
qualities = dict((k,sorter(x)) for k,x in l)
ordered = sorted(l,key=(lambda k: qualities[k[0]]))
[v.setModel('') for v in self.buttons.values()]
self.buttons.clear()
self.clear()
label = Qt.QLabel("Alarms:")
self.addWidget(label)
self.setToolTip("PanicToolbar: %s"%str(self.filters))
url = os.path.dirname(panic.__file__)+'/'+"panic-icon.gif"
print '\t%s'%url
self.addAction(Qt.QIcon(url),'',self.showGui)
for a,alarm in ordered:
if (visible>=self.max_visible): break
if a in self.buttons: continue
print 'In PanicToolbar.refresh(): adding %s'%alarm
self.buttons[a] = ToolbarActionButton(self.gui,self.api)
model = alarm.device+'/'+alarm.get_attribute()
self.buttons[a].setAlarmModel(a)
taurus.Attribute(model).changePollingPeriod(60000)
if self._get_alarm_date(alarm.device, alarm.tag):
tip = self._get_alarm_date(alarm.device, alarm.tag)
delimiter=':'
tooltip=tip[0]+':'+alarm.severity+'\n'+delimiter.join(tip[1:4])+'\n'+tip[4]
else:
tooltip=alarm.tag
self.buttons[a].setToolTip(str(tooltip))
self.buttons[a].buildMenu()
self.addWidget(self.buttons[a])
visible=visible+1
return
if __name__ == '__main__':
qapp = Qt.QApplication([])
devices = sys.argv[1:]
if any('/' in d for d in devices):
filters = None
attr_list = ['%s/%s'%(d,a) for d in devices for a in PyTango.DeviceProxy(d).get_attribute_list()]
else:
filters = devices
attr_list = []
if attr_list:
import taurus
taurus.setLogLevel('WARNING')
tmw = TaurusMainWindow()
taurusForm = TaurusForm(tmw)
taurusForm.setModel(attr_list)
tmw.setCentralWidget(taurusForm)
tmw.statusBar().showMessage('Ready')
tmw.show()
s=tmw.splashScreen()
s.finish(tmw)
else:
tmw = Qt.QMainWindow()
label = Qt.QLabel('Select any alarm from the toolbar')
tmw.setCentralWidget(label)
tmw.show()
tmw.setMinimumWidth(600)
print '*'*80
tmw.setWindowTitle('Alarm Toolbar')
toolbar = PanicToolbar(tmw,filters=filters)
tmw.addToolBar(toolbar)
sys.exit(qapp.exec_())
try:
from fandango.doc import get_fn_autodoc
__doc__ = get_fn_autodoc(__name__,vars())
except:
import traceback
traceback.print_exc()