00001 #!/usr/local/bin/python 00002 # 00003 # Copyright 2002 00004 # by 00005 # The Board of Trustees of the 00006 # Leland Stanford Junior University. 00007 # All rights reserved. 00008 # 00009 00010 __facility__ = "Online" 00011 __abstract__ = "Status Monitor for Run Control" 00012 __author__ = "Selim Tuvi <stuvi@slac.stanford.edu> SLAC - GLAST I&T/Online" 00013 __date__ = ("$Date: 2005/10/26 01:57:29 $").split(' ')[1] 00014 __version__ = "$Revision: 2.11 $" 00015 __release__ = "$Name: R04-12-00 $" 00016 __credits__ = "SLAC" 00017 00018 import LATTE.copyright_SLAC 00019 00020 00021 from qt import * 00022 import logging as log 00023 00024 class ListViewToolTip(QToolTip): 00025 def __init__(self, view, column, truncatedOnly=0): 00026 QToolTip.__init__(self, view.viewport()) 00027 self.__view = view 00028 self.__col = column 00029 00030 def maybeTip(self, pos): 00031 item = self.__view.itemAt(pos) 00032 if item is not None: 00033 #if self.__view.header().sectionSize(self.__col) >= \ 00034 # item.width(self.__view.fontMetrics(), self.__view, self.__col): 00035 # return 00036 cp = self.__view.viewportToContents(pos) 00037 tipString = item.text(self.__col) 00038 cr = self.__view.itemRect(item) 00039 headerPos = self.__view.header().sectionPos(self.__col) 00040 cr.setLeft(headerPos) 00041 cr.setRight(headerPos + self.__view.header().sectionSize(self.__col)) 00042 self.tip(cr, tipString) 00043 00044 class StatusItem(QListViewItem): 00045 def __init__(self, *args): 00046 QListViewItem.__init__(self, *args) 00047 self.alarmExpr = None 00048 00049 def paintCell(self, p, cg, column, width, align): 00050 g = QColorGroup(cg) 00051 g.setColor( QColorGroup.Base, Qt.white) 00052 g.setColor( QColorGroup.Foreground, Qt.black) 00053 if self.alarmExpr is not None: 00054 # If alarm expr starts with '@' then treat the monitored 00055 # value as a string in the expression. 00056 if self.alarmExpr.startswith("@"): expr = "'"+str(self.text(1))+"'" + self.alarmExpr[1:] 00057 else: 00058 expr = str(self.text(1)) + self.alarmExpr 00059 try: 00060 if eval(expr): 00061 g.setColor( QColorGroup.Text, Qt.red) 00062 else: 00063 g.setColor( QColorGroup.Text, Qt.black) 00064 except: 00065 log.exception("Error evaluating expression \"%s\"" % expr) 00066 00067 00068 # Do the standard painting 00069 QListViewItem.paintCell(self,p,g,column,width,align) 00070 00071 p.setPen( QPen( cg.dark(), 1 ) ) 00072 p.drawLine( 0, self.height() - 1, width, self.height() - 1 ) 00073 p.drawLine( width - 1, 0, width - 1, self.height() ) 00074 00075 def setText(self, column, value): 00076 QListViewItem.setText(self, column, value) 00077 00078 def setAlarmExpr(self, alarmExpr): 00079 self.alarmExpr = alarmExpr 00080 00081 00082 class WatchItem(object): 00083 def __init__(self, accessor, key, label, alarmExpr, offBoard): 00084 self.__accessor = accessor 00085 self.__statusItem = None 00086 self.__key = key 00087 self.__label = label 00088 self.__alarmExpr = alarmExpr 00089 self.__inView = 0 00090 self.__offBoard = offBoard 00091 00092 def evaluate(self): 00093 if self.__key is not None: 00094 if self.__accessor.has_key(self.__key): 00095 return self.__accessor[self.__key] 00096 else: 00097 return 'N/A' 00098 else: 00099 val = self.__accessor() 00100 if val is None: 00101 return 'N/A' 00102 else: 00103 return val 00104 00105 def getLabel(self): 00106 return self.__label 00107 00108 def getAlarmExpr(self): 00109 return self.__alarmExpr 00110 00111 def getStatusItem(self): 00112 return self.__statusItem 00113 00114 def setStatusItem(self, si): 00115 self.__statusItem = si 00116 00117 def isInView(self): 00118 return self.__inView 00119 00120 def setInView(self): 00121 self.__inView = 1 00122 00123 def setAccessor(self, accessor, key): 00124 self.__accessor = accessor 00125 self.__key = key 00126 00127 def isOffBoard(self): 00128 return self.__offBoard 00129 00130 class rcStatusPanel(QWidget): 00131 def __init__(self,parent = None,name = None,fl = 0): 00132 QWidget.__init__(self,parent,name,fl) 00133 00134 self.contextMenu = QPopupMenu( self ) 00135 self.contextMenu.insertItem( "&Copy", self.copyToClipboard, Qt.CTRL+Qt.Key_C) 00136 00137 self.clip = QApplication.clipboard() 00138 00139 if not name: 00140 self.setName("rcStatusPanel") 00141 00142 00143 rcStatusPanelLayout = QGridLayout(self,1,1,0,6,"rcStatusPanelLayout") 00144 00145 self.statusView = QListView(self,"statusView") 00146 self.statusView.addColumn(self.tr("Data")) 00147 self.statusView.addColumn(self.tr("Value")) 00148 self.statusView.setAllColumnsShowFocus(1) 00149 self.statusViewTip = ListViewToolTip(view=self.statusView, column=1, 00150 truncatedOnly=1) 00151 00152 rcStatusPanelLayout.addWidget(self.statusView,0,0) 00153 00154 QObject.connect(self.statusView, 00155 SIGNAL("contextMenuRequested(QListViewItem*,const QPoint&,int)"), 00156 self.contextMenuShow 00157 ) 00158 00159 def contextMenuShow(self, item, point, column): 00160 self.selectedItem = item 00161 self.contextMenu.exec_loop(point) 00162 00163 def copyToClipboard(self): 00164 if self.statusView.selectedItem() is not None: 00165 self.clip.setText(self.statusView.selectedItem().text(1)) 00166 00167 00168 class rcStatusMonitor(object): 00169 def __init__(self, interval, gui=None): 00170 self.__interval = interval 00171 self.__gui = gui 00172 self.__watchList = {} 00173 self.__labelSeq = [] 00174 self.__timer = QTimer(gui) 00175 self.__lastItem = None 00176 QObject.connect(self.__timer, SIGNAL("timeout()"), self.updateWatchItems) 00177 00178 def startWatch(self): 00179 if not self.__timer.isActive(): 00180 self.__timer.start(self.__interval) 00181 00182 def stopWatch(self): 00183 if self.__timer.isActive(): 00184 self.__timer.stop() 00185 00186 def addWatchItem(self, label, accessor, key=None, alarmExpr=None, offBoard=False): 00187 if not self.__watchList.has_key(label): 00188 self.__watchList[label] = WatchItem(accessor, key, label, alarmExpr, offBoard) 00189 self.__labelSeq.append(label) 00190 else: 00191 self.__watchList[label].setAccessor(accessor, key) 00192 00193 def updateWatchItems(self): 00194 for label in self.__labelSeq: 00195 wi = self.__watchList[label] 00196 if self.__gui is None: 00197 print label, wi.evaluate() 00198 else: 00199 if not wi.isInView(): 00200 if self.__lastItem is None: 00201 si = StatusItem(self.__gui.statusView, label) 00202 else: 00203 si = StatusItem(self.__gui.statusView, self.__lastItem, label) 00204 si.setAlarmExpr(wi.getAlarmExpr()) 00205 self.__lastItem = si 00206 wi.setStatusItem(si) 00207 wi.setInView() 00208 else: 00209 si = wi.getStatusItem() 00210 app = self.__gui.getApp() 00211 fsm = self.__gui.getFSM() 00212 evaluateOffBoard = True 00213 if app is not None and fsm is not None: 00214 if fsm.current_state == 'RESET': 00215 evaluateOffBoard = False 00216 if evaluateOffBoard or not wi.isOffBoard(): 00217 si.setText(1, str(wi.evaluate())) 00218 else: 00219 si.setAlarmExpr(None) 00220 00221 00222 00223 #~ if __name__ == '__main__': 00224 00225 #~ from random import random 00226 #~ import sys 00227 #~ from RunControlMainGUIImpl import * 00228 #~ from RunControlCommon import * 00229 00230 #~ class Dummy(object): 00231 #~ def __init__(self): 00232 #~ pass 00233 00234 #~ def getValue(self): 00235 #~ return random() 00236 00237 #~ app = QApplication(sys.argv) 00238 00239 #~ rcCommon = RunControlCommon() 00240 00241 #~ gui = RunControlMainGUIImpl(rcCommon) 00242 00243 #~ #statMon = rcStatusMonitor(1000) 00244 #~ statMon = rcStatusMonitor(1000, gui) 00245 #~ dummy = Dummy() 00246 #~ statMon.addWatchItem('TestValue', dummy.getValue) 00247 #~ statMon.startWatch() 00248 #~ app.setMainWidget(gui) 00249 #~ gui.show() 00250 #~ app.exec_loop() 00251 00252 00253