#!/usr/local/bin/python
#
#                               Copyright 2002
#                                     by
#                        The Board of Trustees of the
#                     Leland Stanford Junior University.
#                            All rights reserved.
#

__facility__ = "Online"
__abstract__ = "Status Monitor for Run Control"
__author__   = "Selim Tuvi <stuvi@slac.stanford.edu> SLAC - GLAST I&T/Online"
__date__     = ("$Date: 2004/09/07 20:52:54 $").split(' ')[1]
__version__  = "$Revision: 2.4 $"
__release__  = "$Name:  $"
__credits__  = "SLAC"

from qt import *

class StatusItem(QListViewItem):
  def __init__(self, *args):
    QListViewItem.__init__(self, *args)
    self.alarmExpr = None

  #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  # Comment out the whole method and the memory leak goes away
  #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  def paintCell(self, p, cg, column, width, align):
    QListViewItem.paintCell(self, p, cg, column, width, align)
#    g = QColorGroup(cg)
#    g.setColor( QColorGroup.Base, Qt.white)
#    g.setColor( QColorGroup.Foreground, Qt.black)
#    if self.alarmExpr is not None:
#      # If alarm expr starts with '@' then treat the monitored
#      # value as a string in the expression.
#      if self.alarmExpr.startswith("@"):
#        expr = "'"+str(self.text(1))+"'" + self.alarmExpr[1:]
#      else:
#        expr = str(self.text(1)) + self.alarmExpr
#      if eval(expr):
#        g.setColor( QColorGroup.Text, Qt.red)
#      else:
#        g.setColor( QColorGroup.Text, Qt.black)


#    # Do the standard painting
#    #QListViewItem.paintCell(self,p,g,column,width,align)

#    #p.setPen( QPen( cg.dark(), 1 ) )
#    #p.drawLine( 0, self.height() - 1, width, self.height() - 1 )
#    #p.drawLine( width - 1, 0, width - 1, self.height() )

#  def setText(self, column, value):
#    QListViewItem.setText(self, column, value)

  def setAlarmExpr(self, alarmExpr):
    self.alarmExpr = alarmExpr


class WatchItem(object):
  def __init__(self, accessor, key, label, alarmExpr):
    self.__accessor = accessor
    self.__statusItem = None
    self.__key = key
    self.__label = label
    self.__alarmExpr = alarmExpr
    self.__inView = 0
    self.__cnt = 0


  def evaluate(self):
    if self.__key is not None:
      if self.__accessor.has_key(self.__key):
        return self.__accessor[self.__key]
      else:
        return 'N/A'
    else:
      val = self.__accessor()
      if val is None:
        return 'N/A'
      else:
        return val

  def getLabel(self):
    return self.__label

  def getAlarmExpr(self):
    return self.__alarmExpr

  def getStatusItem(self):
    return self.__statusItem

  def setStatusItem(self, si):
    self.__statusItem = si

  def isInView(self):
    return self.__inView

  def setInView(self):
    self.__inView = 1

  def setAccessor(self, accessor, key):
    self.__accessor = accessor
    self.__key      = key


class rcStatusPanel(QWidget):
  def __init__(self,parent = None,name = None,fl = 0):
    QWidget.__init__(self,parent,name,fl)

    self.contextMenu = QPopupMenu( self )
    self.contextMenu.insertItem( "&Copy", self.copyToClipboard, Qt.CTRL+Qt.Key_C)

    self.clip = QApplication.clipboard()

    if not name:
      self.setName("rcStatusPanel")


    rcStatusPanelLayout = QGridLayout(self,1,1,0,6,"rcStatusPanelLayout")

    self.statusView = QListView(self,"statusView")
    self.statusView.addColumn(self.tr("Data"))
    self.statusView.addColumn(self.tr("Value"))
    self.statusView.setAllColumnsShowFocus(1)

    rcStatusPanelLayout.addWidget(self.statusView,0,0)

    self.resize(QSize(151,271).expandedTo(self.minimumSizeHint()))
    QObject.connect(self.statusView,
                    SIGNAL("contextMenuRequested(QListViewItem*,const QPoint&,int)"),
                    self.contextMenuShow
                   )

  def contextMenuShow(self, item, point, column):
    self.selectedItem = item
    self.contextMenu.exec_loop(point)

  def copyToClipboard(self):
    self.clip.setText(self.statusView.selectedItem().text(1))


class rcStatusMonitor(object):
  def __init__(self, interval, gui=None):
    self.__interval = interval
    self.__gui = gui
    self.__watchList = {}
    self.__labelSeq = []
    self.__timer = QTimer(gui)
    self.__lastItem = None
    QObject.connect(self.__timer, SIGNAL("timeout()"), self.updateWatchItems)

  def startWatch(self):
    self.__timer.start(self.__interval)

  def stopWatch(self):
    self.__timer.stop()

  def addWatchItem(self, label, accessor, key=None, alarmExpr=None):
    if not self.__watchList.has_key(label):
      self.__watchList[label] = WatchItem(accessor, key, label, alarmExpr)
      self.__labelSeq.append(label)
    else:
      self.__watchList[label].setAccessor(accessor, key)

  def updateWatchItems(self):
    for label in self.__labelSeq:
      wi = self.__watchList[label]
      if self.__gui is None:
        print label, wi.evaluate()
      else:
        if not wi.isInView():
          if self.__lastItem is None:
            si = StatusItem(self.__gui.statusView, label)
          else:
            si = StatusItem(self.__gui.statusView, self.__lastItem, label)
          si.setAlarmExpr(wi.getAlarmExpr())
          self.__lastItem = si
          wi.setStatusItem(si)
          wi.setInView()
        else:
          si = wi.getStatusItem()
        si.setText(1, str(wi.evaluate()))



if __name__ == '__main__':

  from random import random
  import sys

  class Dummy(object):
    def __init__(self):
      pass

    def getValue(self):
      return random()

  app = QApplication(sys.argv)

  gui = rcStatusPanel()

  statMon = rcStatusMonitor(1, gui)
  dummy = Dummy()
  for i in range(100):
    statMon.addWatchItem('TestValue %02d ' % i, dummy.getValue)
  statMon.startWatch()
  app.setMainWidget(gui)
  gui.show()
  app.exec_loop()


