Main Page | Packages | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | Related Pages

RunControlMain.py

00001 #!/usr/bin/env 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__ = "GLAST LAT main run control class"
00012 __author__   = "R. Claus <Claus@SLAC.Stanford.edu> SLAC - GLAST LAT I&T/Online"
00013 __date__     = ("$Date: 2006/05/04 19:48:31 $").split(' ')[1]
00014 __version__  = "$Revision: 2.57 $"
00015 __release__  = "$Name: R04-12-00 $"
00016 __credits__  = "SLAC"
00017 
00018 import LATTE.copyright_SLAC
00019 
00020 import                              os
00021 import                              sys
00022 import                              atexit
00023 import                              threading
00024 import logging               as     log
00025 import types
00026 import time
00027 import gc
00028 import string
00029 
00030 from   qt                    import *
00031 import sip
00032 
00033 from   Queue                 import Queue
00034 from   RunControlFSM         import RunControlFSM
00035 from   RunControlMainGUIImpl import RunControlMainGUIImpl
00036 from   rcEndRunDlgImpl       import rcEndRunDlgImpl
00037 
00038 # Modules here are imported to prevent them from being reloaded
00039 # See rcUtil for more info
00040 
00041 import Pyana
00042 import LDF
00043 
00044 try:
00045   import cfitsio
00046 except ImportError, e:
00047   pass
00048 
00049 try:
00050   import Numeric
00051 except ImportError, e:
00052   pass
00053 
00054 import rcUtil
00055 import rcReportGen
00056 import rcRunIdHelper
00057 import rcArchiver
00058 
00059 from LATTE.tools.taskEngine   import TaskEngine
00060 from LATTE.tools.guiBridges   import GUIbridge, QtThreadBridge, PyThreadBridge
00061 from LATTE.client.gLog        import logException
00062 from LATTE.database.gVersions import Gversions, ROOT_DIR_ENVS
00063 from LATTE.database.gPlumber  import Plumber
00064 
00065 class ConnectState:
00066   Disconnected = 0
00067   Waiting      = 1
00068   Connected    = 2
00069 
00070 class RunControlMain(RunControlMainGUIImpl):
00071   """Class for providing a run control framework
00072   """
00073 
00074   def __init__(self, common, parent = None, name = "RunControl", fl = 0):
00075     RunControlMainGUIImpl.__init__(self, common, parent, name, fl)
00076 
00077     self.__common       = common
00078     self.__fsm          = None
00079     self.__actionEngine = None
00080     self.__app          = None
00081     self.__browser      = None
00082     self.__hwVersions   = None
00083     self.__queue        = None
00084     self.__engine       = None
00085     self.__guiThread    = threading.currentThread()
00086     self.__guiBridge    = GUIbridge(self.__guiThread)
00087 
00088     # Set this object to be the client handler
00089     common.getCmdCli().handler(self)
00090     self.__connection_state = ConnectState.Disconnected
00091     self.ResetButton.setEnabled(False)
00092     self.StopButton.setEnabled(False)
00093     self.RunButton.setEnabled(False)
00094     self.PauseButton.setEnabled(False)
00095 
00096     self.__actionEngine = TaskEngine("FSMactionEngine")
00097     self.__actionEngine.start()
00098 
00099     self.commandSynch = TaskEngine("CommandSynch")
00100     self.commandSynch.start()
00101 
00102     self.eventHandler = TaskEngine("EventHandler")
00103     self.eventHandler.start()
00104 
00105     # Pick an operator
00106     operator = common.prefMan().preferences()["operatorobj"]
00107     self.cmbOperator.setCurrentText(operator.getName())
00108 
00109     self.__endRunDlg = rcEndRunDlgImpl(parent=self)
00110 
00111     # Clean up at exit
00112     self.inShutdown = False
00113     atexit.register(self.__shutdown)
00114 
00115     # Preload modules specified in preferences
00116     preload = common.prefMan().preferences()["preload"]
00117     if preload.strip() != "":
00118       preloadList = map(string.strip, preload.split(','))
00119       for m in preloadList:
00120         exec 'import ' + m
00121 
00122   def disconnected(self):
00123     self.__disconnected()
00124 
00125   def timedout(self):
00126     self.__disconnected()
00127 
00128   def __connection_notthere(self): # GUI thread
00129     if self.__connection_state == ConnectState.Connected:
00130       self.StopButton.setEnabled(False)
00131       self.RunButton.setEnabled(False)
00132       self.PauseButton.setEnabled(False)
00133       log.error("OCS server disconnected, trying to reconnect")
00134       # As per LTE-311, return the run to RESET state
00135       self.__resetStoppedApp()
00136       self.__connection_state = ConnectState.Waiting
00137       self.__common.disconnect()
00138       self.__connect()
00139 
00140   def __connection_established(self): # GUI thread
00141     log.info("OCS server is now connected")
00142     if self.__app is not None:
00143       self.StopButton.setEnabled(True)
00144       self.RunButton.setEnabled(True)
00145       self.PauseButton.setEnabled(True)
00146     self.__connection_state = ConnectState.Connected
00147 
00148   def __resetStoppedApp(self):
00149     if (self.__app.__class__.__name__ == 'userSuite' \
00150          and not self.__app.isRunning()
00151        ) or (
00152         self.__app.__class__.__name__ == 'userApplication' and \
00153         self.__fsm.current_state == 'STOPPED'
00154        ):
00155       log.warn("Returning the run to RESET state.")
00156       self.doReset()
00157 
00158   def __connection_failed(self, msg): # GUI thread
00159     if self.__tries == 0:
00160       log.error(msg)
00161     self.__tries += 1
00162     return self.__connection_state
00163 
00164   def connectClicked(self): # GUI thread
00165     if self.__connection_state is ConnectState.Disconnected:
00166       self.fileConnectAction.setMenuText("Disconnect")
00167       self.__connection_state = ConnectState.Waiting
00168       self.__tries = 0
00169       self.__connect()
00170     else:
00171       self.fileConnectAction.setMenuText("Connect")
00172       self.__connection_state = ConnectState.Disconnected
00173       self.__common.disconnect()
00174       self.StopButton.setEnabled(False)
00175       self.RunButton.setEnabled(False)
00176       self.PauseButton.setEnabled(False)
00177       log.info("OCS server is now disconnected")
00178       # As per LTE-311, return the run to RESET state
00179       self.__resetStoppedApp()
00180 
00181   def __connect(self):
00182     connecthdlr = threading.Thread(None, self.__connection_handler, 'ConnectHandler',())
00183     connecthdlr.setDaemon(True)
00184     connecthdlr.start()
00185 
00186   def __disconnected(self):
00187     self.execGUImethod(self.__connection_notthere)
00188 
00189   def __connection_handler(self):
00190     while (True):
00191       try:
00192         force = (self.__common.options().oesforce != None)
00193         self.__common.connect(force)
00194         self.__plumb()
00195         self.execGUImethod(self.__connection_established)
00196         break
00197       except RuntimeError, msg:
00198         state = self.execGUImethod(self.__connection_failed, msg)
00199         if state == ConnectState.Disconnected: break
00200         time.sleep(3)
00201 
00202   def __plumb(self):
00203     if self.__common.options().noplumbing is not None:
00204       return
00205     if self.__common.getLAT() is not None:
00206       if self.__common.options().fswmsglevel is not None:
00207         msglevel = int(self.__common.options().fswmsglevel)
00208       else:
00209         msglevel = 3
00210       verbose = (self.__common.options().ocsverbose != None)
00211       force = (self.__common.options().initforce != None)
00212       plumber = Plumber(self.__common.getLAT(), self.__common.getXBRD())
00213       plumber.initialize(msglevel, verbose, force)
00214 
00215   def isConnected(self):
00216     """\brief Return the connection state.
00217 
00218     Used by the WatchItem class in rcStatusMonitor.
00219 
00220     \return Connection state
00221     """
00222     return self.__connection_state == ConnectState.Connected
00223 
00224   def schemaChanged(self):
00225     if self.__connection_state is ConnectState.Connected:
00226       self.__plumb()
00227 
00228   def applyPermissions(self, operator):
00229     adminOverride = operator.isAdministrator()
00230     if adminOverride:
00231       self.fileExitAction.setEnabled(1)
00232     else:
00233       self.fileExitAction.setEnabled(0)
00234     if 'allow_python_shell' in operator.getPermissions() or adminOverride:
00235       self.viewPythonShell.setEnabled(1)
00236     else:
00237       self.viewPythonShell.setEnabled(0)
00238     if 'set_particle_type' in operator.getPermissions() or adminOverride:
00239       self.comboParticleType.setEnabled(1)
00240     else:
00241       self.comboParticleType.setEnabled(0)
00242     if 'set_orientation' in operator.getPermissions() or adminOverride:
00243       self.comboOrientation.setEnabled(1)
00244     else:
00245       self.comboOrientation.setEnabled(0)
00246 
00247     if 'edit_preferences' in operator.getPermissions() or adminOverride:
00248       self.editPreferencesAction.setEnabled(1)
00249     else:
00250       self.editPreferencesAction.setEnabled(0)
00251 
00252     for (panelLabel, panel) in self.panels().items():
00253       if 'enable_' + panelLabel.lower() + '_panel' in operator.getPermissions() or adminOverride:
00254         self.setEnabledTabPage(panelLabel, 1)
00255       else:
00256         self.setEnabledTabPage(panelLabel, 0)
00257       if "applyPermissions" in dir(panel):
00258         panel.applyPermissions(operator)
00259 
00260     if self.__common.getMSGLogger() is not None:
00261       if adminOverride:
00262         self.__common.getMSGLogger().setSecure(0)
00263       else:
00264         self.__common.getMSGLogger().setSecure(1)
00265       self.__common.getMSGLogger().show()
00266 
00267     self.__common.prefGUI().applyPermissions(operator)
00268 
00269 
00270   def setEnabledTabPage(self, panelLabel, enable):
00271     """Find the tabPage belonging to panel identified by panelLabel
00272     """
00273     for i in range(self.RunControlTab.count()):
00274       tabPage = self.RunControlTab.page(i)
00275       if panelLabel == str(self.RunControlTab.tabLabel(tabPage)):
00276         tabPage.setEnabled(enable)
00277         break
00278 
00279   def setOperator(self, operator):
00280     self.cmbOperator.setCurrentText(operator)
00281     self.__common.prefMan().setOperator(operator)
00282 
00283   def setParticleType(self, particleType):
00284     self.__common.prefMan().setParticleType(particleType)
00285 
00286   def setOrientation(self, orientation):
00287     self.__common.prefMan().setOrientation(orientation)
00288 
00289   def getName(self):
00290     return "RunControlMain"
00291 
00292   def __statusMsg(self, msg, tmo):
00293     self.execGUImethodNR(self.statusBar().message, msg, tmo)
00294 
00295   def __shutdown(self):
00296     """\brief Clean up and shut down the various threads.
00297     """
00298     # This method expects to be executed from the GUI thread.
00299 
00300     self.inShutdown = True
00301 
00302     # Bring the system into the RESET state
00303     self.doReset()
00304 
00305     # Use the following non-NR call to wait for the reset to finish
00306     self.execGUImethod(self.statusBar().message, "Exiting")
00307 
00308     # Shut down the task engines
00309     self.__actionEngine.shutdown()
00310     self.eventHandler.shutdown()  # RiC: timeout not needed with above wait
00311     self.commandSynch.shutdown()
00312 
00313     # After the FSM Action Engine has shut down we can delete the FSM
00314     if self.__fsm:
00315       del self.__fsm
00316       self.__fsm = None
00317 
00318     # Disconnect from the command and event servers
00319     self.__common.disconnect()
00320 
00321     # Stop the data distribution server
00322     dds = self.__common.getDDS()
00323     if dds is not None:
00324       dds.disconnect()
00325 
00326     # Stop the GUI bridge
00327     #self.__qtBridge.terminate()
00328     self.__guiBridge.shutdown()
00329 
00330 
00331   def initApp(self):
00332     """\brief Method usually invoked by the GUI to load a new application
00333     """
00334     applName = self.OpenAppl.currentText()
00335     if str(applName) == "":  return     # Operator cancelled
00336     self.loadApp(str(applName))
00337 
00338   def loadApp(self, applName):
00339     """\brief Method that can be invoked from code to load a new application
00340 
00341     \param applName  Name of an application to load
00342     """
00343     if self.__fsm is not None:
00344       self.ResetClicked()
00345     if applName is None:
00346       self.__statusMsg('Loading aborted', 0)
00347       return
00348 
00349     # Start the application in its own thread after the reset from above
00350     # (if any) completes.
00351     self.__actionEngine.spawn(self.__startApp, str(applName))
00352 
00353     self.ResetButton.setEnabled(True)
00354     self.StopButton.setEnabled(True)
00355     self.RunButton.setEnabled(True)
00356     self.PauseButton.setEnabled(True)
00357 
00358   def loadModule(self, module):
00359     """\brief Method that can be invoked from code to load a new module
00360 
00361     \param module  Pointer to module to load
00362     """
00363     if self.__fsm is not None:
00364       self.ResetClicked()
00365     self.__actionEngine.spawn(self.__startModule, module)
00366 
00367   def __initAppCommon(self, appType, app, appName, filename):
00368     msg = "%s %s loaded from %s" % (appType, app.getName(), filename)
00369     log.info(msg)
00370 
00371     # Update the application history list box.
00372     self.execGUImethod(self.__updateAppListBox, appName)
00373     if self.__common.options().securedir is None and self.__common.options().norcoverride is None:
00374       self.execGUImethod(self.__updateRunConditions, 'NOT-DEFINED')
00375 
00376     return msg
00377 
00378   def __updateRunConditions(self, undef):
00379     prefMan = self.__common.prefMan()
00380     self.cmbOperator.setCurrentText(undef)
00381     prefMan.setOperator(undef)
00382     self.comboParticleType.setCurrentText(undef)
00383     prefMan.setParticleType(undef)
00384     self.comboOrientation.setCurrentText(undef)
00385     prefMan.setOrientation(undef)
00386     prefMan.setSite(undef)
00387     prefMan.setPhase(undef)
00388     prefMan.setInstrumentType(undef)
00389 
00390   def __updateAppListBox(self, appName):
00391     if self.OpenAppl.listBox().findItem(appName) is None:
00392       self.OpenAppl.insertItem(appName)
00393 
00394   def __startApp(self, appName):
00395     try:
00396       self.execGUImethod(self.statusMonitor().stopWatch)
00397       if self.__common.options().noreload is not None:
00398         dontReloadList = self.__common.getDBN()["_dontReload"]
00399       else:
00400         dontReloadList = []
00401 
00402       prefs = self.__common.prefMan().preferences()
00403       if prefs['dontreload'].strip() != "":
00404         dontReloadPrefs = map(string.strip, prefs['dontreload'].split(','))
00405       else:
00406         dontReloadPrefs = []
00407       dontReloadList += dontReloadPrefs
00408 
00409       (module, filename) = rcUtil.importModule(appName=appName,
00410                                                reload=not prefs["disablereload"],
00411                                                dontReloadList=dontReloadList,
00412                                                showUnloadedModules=prefs["showunloaded"] )
00413     except Exception, e:
00414       logException()
00415       if type(e) == types.ListType:
00416         self.__statusMsg(e[0], 0)
00417       else:
00418         self.__statusMsg(str(e), 0)
00419       return
00420     self.__clearPreviousApp()
00421     self.__setupApp(module, appName, filename)
00422 
00423   def __startModule(self, module):
00424     self.__clearPreviousApp()
00425     appName = module.userModuleName
00426     filename = module.__file__
00427     self.__setupApp(module, filename, filename)
00428 
00429   def __clearPreviousApp(self):
00430     del self.__app
00431     self.__app = None
00432     gc.collect()
00433     if len(gc.garbage) != 0:
00434       log.error("RunControlMain: Found garbage: %s" % gc.garbage)
00435 
00436   def __setupApp(self, module, appName, filename):
00437     userid = self.__common.prefMan().userId()
00438     evtdebug = self.__common.options().evtdebug is not None
00439     if 'userApplication' in dir(module):
00440       self.__app = module.userApplication(self, userid, evtdebug)
00441       msg = self.__initAppCommon('Application', self.__app, appName, filename)
00442       self.__fsm = RunControlFSM(self.__app)
00443       self.execGUImethodNR(self.__updateGUI, self.__fsm.current_state, False)
00444       self.execGUImethodNR(self.handleComments, None, self.__fsm.current_state)
00445       self.execGUImethod(self.statusMonitor().startWatch)
00446     elif 'userSuite' in dir(module):
00447       # Set the FSM to None so that we don't check for current state
00448       # in the case of a suite run. Fixes LTE-343
00449       self.__fsm = None
00450       self.__app = module.userSuite(self, userid, evtdebug)
00451       msg = self.__initAppCommon('Suite', self.__app, appName, filename)
00452       if self.__app.rcSetupSuite() is None:
00453         msg = "Suite setup failed...Aborting suite %s" % appName
00454         log.error(msg)
00455       else:
00456         self.execGUImethodNR(self.State.setText, "SUITE SETUP")
00457     else:
00458       msg = '%s is not a recognized user script.  userApplication or userSuite class is missing.' % appName
00459       log.error(msg)
00460     self.__common.getDBN()['_app'] = self.__app
00461     self.__statusMsg(msg, 0)
00462 
00463   def __updateGUI(self, state, enabled):
00464     """\brief Method for updating the GUI
00465     """
00466     # This method may complete asynchronously to the application's activities
00467     # since the application doesn't depend on the results.  Should this ever
00468     # change, be sure to change the execGUImethodNR() calls below to
00469     # execGUImethod() calls so that the fsmActionEngine waits for __updateGUI()
00470     # to complete before continuing.
00471     prefGUI = self.__common.prefGUI()
00472     self.State.setText(state)
00473     operator = self.__common.prefMan().preferences()["operatorobj"]
00474     if self.__common.options().securedir is not None and 'administrator' not in operator.getRoles():
00475       permissions = operator.getPermissions()
00476       self.cmbOperator.setEnabled(0)
00477       if 'set_particle_type' in permissions:
00478         self.comboParticleType.setEnabled(enabled)
00479       if 'set_orientation' in permissions:
00480         self.comboOrientation.setEnabled(enabled)
00481       if 'set_site_run_condition' in permissions:
00482         prefGUI.comboSite.setEnabled(enabled)
00483       if 'set_instrument_type_run_condition' in permissions:
00484         prefGUI.comboInstrumentType.setEnabled(enabled)
00485       if 'set_phase_run_condition' in permissions:
00486         prefGUI.comboPhase.setEnabled(enabled)
00487     else:
00488       self.cmbOperator.setEnabled(enabled)
00489       self.comboParticleType.setEnabled(enabled)
00490       self.comboOrientation.setEnabled(enabled)
00491       prefGUI.comboSite.setEnabled(enabled)
00492       prefGUI.comboInstrumentType.setEnabled(enabled)
00493       prefGUI.comboPhase.setEnabled(enabled)
00494 
00495   def ResetClicked(self):
00496     RunControlMainGUIImpl.ResetClicked(self)
00497     if self.__app.__class__.__name__ == 'userSuite' and not self.__app.isRunning():
00498       if self.__app.rcSetupSuite() is None:
00499         log.error("Suite setup failed...Aborting suite %s" % self.__app.getName())
00500       else:
00501         self.execGUImethodNR(self.State.setText, "SUITE SETUP")
00502     else:
00503       self.waitCursor()
00504       self.__actionEngine.spawn(self.__reset)
00505       self.normalCursor()
00506 
00507   def __reset(self):
00508     if self.__fsm is not None:
00509       curState = self.__fsm.current_state
00510       if curState == "STOPPED":
00511         self.execGUImethodNR(self.State.setText, "TEARING DOWN")
00512         self.__fsm.process('TEARDOWN')
00513         self.execGUImethodNR(self.handleComments, curState, self.__fsm.current_state)
00514 
00515       elif curState == "RUNNING":
00516         self.execGUImethodNR(self.State.setText, "STOPPING RUN")
00517         status = self.__fsm.process('STOP_RUN')
00518         if status is None:
00519           self.execGUImethodNR(self.State.setText, "TEARING DOWN")
00520           self.__fsm.process('TEARDOWN')
00521         self.execGUImethodNR(self.handleComments, curState, self.__fsm.current_state)
00522 
00523       elif curState == "PAUSED":
00524         self.execGUImethodNR(self.State.setText, "STOPPING RUN")
00525         self.execGUImethodNR(QToolTip.add, self.PauseButton, "Pause")
00526         self.execGUImethodNR(QToolTip.add, self.RunButton, "Run")
00527         status = self.__fsm.process('STOP')
00528         if status is None:
00529           self.execGUImethodNR(self.State.setText, "TEARING DOWN")
00530           self.__fsm.process('TEARDOWN')
00531         self.execGUImethodNR(self.handleComments, curState, self.__fsm.current_state)
00532 
00533       self.execGUImethodNR(self.__updateGUI, self.__fsm.current_state, True)
00534 
00535   def StopClicked(self):
00536     if self.__app.__class__.__name__ == 'userSuite':
00537       self.execGUImethodNR(self.State.setText, "STOPPING SUITE")
00538       self.__app.rcStopSuite()
00539       self.execGUImethodNR(self.__updateGUI, "SUITE STOPPED", True)
00540     else:
00541       RunControlMainGUIImpl.StopClicked(self)
00542 
00543       self.waitCursor()
00544       self.__actionEngine.spawn(self.__stop)
00545       self.normalCursor()
00546 
00547 # New code that spawns StopSuite -- not fully tested
00548 #  def StopClicked(self):
00549 #    if self.__app.__class__.__name__ == 'userSuite':
00550 #      self.__actionEngine.spawn(self.__stopSuite)
00551 #    else:
00552 #      RunControlMainGUIImpl.StopClicked(self)
00553 #
00554 #      self.waitCursor()
00555 #      self.__actionEngine.spawn(self.__stop)
00556 #      self.normalCursor()
00557 
00558 #  def __stopSuite(self):
00559 #    self.execGUImethodNR(self.State.setText, "STOPPING SUITE")
00560 #    self.__app.rcStopSuite()
00561 #    self.execGUImethodNR(self.__updateGUI, "SUITE STOPPED", True)
00562 
00563   def __stop(self):
00564     if self.__fsm is not None:
00565       curState = self.__fsm.current_state
00566       if curState == "PAUSED":
00567         self.execGUImethodNR(self.State.setText, "STOPPING RUN")
00568         self.execGUImethodNR(QToolTip.add, self.PauseButton, "Pause")
00569         self.execGUImethodNR(QToolTip.add, self.RunButton, "Run")
00570         self.__fsm.process('STOP')
00571         self.execGUImethodNR(self.handleComments, curState, self.__fsm.current_state)
00572 
00573       elif curState == "RUNNING":
00574         self.execGUImethodNR(self.State.setText, "STOPPING RUN")
00575         self.__fsm.process('STOP_RUN')
00576         self.execGUImethodNR(self.handleComments, curState, self.__fsm.current_state)
00577 
00578       elif curState == "RESET":
00579         self.execGUImethodNR(self.State.setText, "SETTING UP")
00580         self.__fsm.process('SETUP')
00581         self.execGUImethodNR(self.handleComments, curState, self.__fsm.current_state)
00582 
00583       self.execGUImethodNR(self.__updateGUI, self.__fsm.current_state, True)
00584 
00585   def RunClicked(self):
00586     if self.__app.__class__.__name__ == 'userSuite':
00587       if self.__app.isRunning() and not self.__app.isPaused():
00588         return
00589       curText = self.execGUImethod(self.State.text)
00590       if self.__app.isPaused():
00591         text = "RESUMING SUITE"
00592       else:
00593         text = "STARTING SUITE"
00594       self.execGUImethodNR(self.__updateGUI, text, False)
00595       if self.__app.rcStartSuite() is not None:
00596         text = curText
00597       else:
00598         text = "SUITE RUNNING"
00599       self.execGUImethodNR(self.__updateGUI, text, False)
00600     else:
00601       RunControlMainGUIImpl.RunClicked(self)
00602 
00603       self.waitCursor()
00604       self.__actionEngine.spawn(self.__run)
00605       self.normalCursor()
00606 
00607   def __run(self):
00608     if self.__fsm is not None:
00609       curState = self.__fsm.current_state
00610       if curState == "PAUSED":
00611         self.execGUImethodNR(self.State.setText, "RESUMING RUN")
00612         self.execGUImethodNR(QToolTip.add, self.PauseButton, "Pause")
00613         self.execGUImethodNR(QToolTip.add, self.RunButton, "Run")
00614         self.__fsm.process('RESUME')
00615 
00616       elif curState == "STOPPED":
00617         self.execGUImethodNR(self.State.setText, "STARTING RUN")
00618         self.__fsm.process('START_RUN')
00619 
00620       elif curState == "RESET":
00621         self.execGUImethodNR(self.State.setText, "SETTING UP")
00622         status = self.__fsm.process('SETUP')
00623         if status is None:
00624           self.execGUImethodNR(self.State.setText, "STARTING RUN")
00625           self.execGUImethodNR(self.State.setText, self.__fsm.current_state)
00626           self.__fsm.process('START_RUN')
00627       self.execGUImethodNR(self.handleComments, curState, self.__fsm.current_state)
00628 
00629       self.execGUImethodNR(self.__updateGUI, self.__fsm.current_state, False)
00630 
00631   def PauseClicked(self):
00632     if self.__app.__class__.__name__ == 'userSuite':
00633       text = self.execGUImethod(self.State.text)
00634       if self.__app.isPaused():
00635         return
00636       self.execGUImethodNR(self.State.setText, "PAUSING SUITE")
00637       if self.__app.rcPauseSuite() is None:
00638         self.execGUImethodNR(self.State.setText, "SUITE PAUSED")
00639       else:
00640         self.execGUImethodNR(self.State.setText, text)
00641     else:
00642       RunControlMainGUIImpl.PauseClicked(self)
00643 
00644       self.waitCursor()
00645       self.__actionEngine.spawn(self.__pause)
00646       self.normalCursor()
00647 
00648   def __pause(self):
00649     if self.__fsm is not None:
00650       curState = self.__fsm.current_state
00651       if curState == "RUNNING":
00652         self.execGUImethodNR(self.State.setText, "PAUSING RUN")
00653         self.execGUImethodNR(QToolTip.add, self.PauseButton, "Resume")
00654         self.execGUImethodNR(QToolTip.add, self.RunButton, "Resume")
00655         self.__fsm.process('PAUSE')
00656         self.execGUImethodNR(self.handleComments, curState, self.__fsm.current_state)
00657       elif curState == "PAUSED":
00658         self.execGUImethodNR(self.State.setText, "RESUMING UP")
00659         self.execGUImethodNR(QToolTip.add, self.PauseButton, "Pause")
00660         self.execGUImethodNR(QToolTip.add, self.RunButton, "Run")
00661         self.__fsm.process('RESUME')
00662         self.execGUImethodNR(self.handleComments, curState, self.__fsm.current_state)
00663 
00664       self.execGUImethodNR(self.State.setText, self.__fsm.current_state)
00665 
00666   def doReset(self):
00667     """Emit a Reset button click under program control.
00668     Can be done from a subthread."""
00669     if self.__app.__class__.__name__ == 'userSuite':
00670       if self.__app.isRunning():
00671         self.doSuiteReset()
00672     self.doEmit(self.ResetButton)
00673 
00674   def doSuiteReset(self):
00675     """Notify rcSuite that there was an exception in the suite script
00676     This gives rcSuite a chance to do its own doReset on the running script.
00677     """
00678     app = self.__app
00679     while app.getApp().__class__.__name__ != 'userApplication':
00680       app = app.getApp()
00681     app.resetSuiteScript()
00682 
00683   def doStop(self):
00684     """Emit a Stop button click under program control.
00685     Can be done from a subthread."""
00686     self.doEmit(self.StopButton)
00687 
00688   def doStopRun(self):
00689     """Depricated version of doStop()."""
00690     self.doStop()
00691 
00692   def doRun(self):
00693     """Emit a Run button click under program control.
00694     Can be done from a subthread."""
00695     self.doEmit(self.RunButton)
00696 
00697   def doPause(self):
00698     """Emit a Pause button click under program control.
00699     Can be done from a subthread."""
00700     self.doEmit(self.PauseButton)
00701 
00702   def doEmit(self, obj, signal = SIGNAL("clicked()"), args = ()):
00703     """Emit a signal, possibly from a subthread.
00704     By default the signal is 'clicked()' with no arguments."""
00705     if self.isGUIthread():
00706       obj.emit(signal, args)
00707     else:
00708       self.execGUImethodNR(obj.emit, signal, args)
00709 
00710   def normalCursor(self):
00711     self.execGUImethodNR(self.setCursor, QCursor(QWidget.ArrowCursor))
00712 
00713   def waitCursor(self):
00714     self.execGUImethodNR(self.setCursor, QCursor(QWidget.WaitCursor))
00715 
00716   def handleEndRunDlg(self):
00717     prefs = self.__common.prefMan().preferences()
00718     secMan = self.getSecurityMan()
00719     loginId = prefs["operatorobj"].getLoginId()
00720     self.__endRunDlg.initialize(secMan, loginId)
00721     if self.__endRunDlg.exec_loop() == QDialog.Accepted:
00722       app = self.__app
00723       while app.__class__.__name__ != 'userApplication':
00724         app = app.getApp()
00725       curComplStatusStr = app.getCompletionStatusStr()
00726       (cv, cs) = self.__endRunDlg.getNewCompletionStatus(curComplStatusStr)
00727       if cv is not None:
00728         app.setCompletionStatus(cv)
00729         msg = ("Completion Status '%s' is overridden with status '%s' by operator %s" %
00730               (curComplStatusStr, cs, prefs["operator"]))
00731         log.info(msg)
00732         self.__endRunDlg.enterComment(msg, addToHistory=1)
00733     else:
00734       self.__endRunDlg.clearHistory()
00735 
00736   def getEndRunComments(self):
00737     return self.__endRunDlg.comments.getWidget()
00738 
00739   def handleComments(self, fromState, toState):
00740     cw = self.getCommentWidget()
00741     if toState == 'STOPPED' and fromState != 'RESET':
00742       if cw.isReadOnly():
00743         cw.setReadOnly(0)
00744         self.showComments()
00745         cw.enterComment("Comment entry enabled.")
00746       cw.enterComment("Note: Comments entered after this point will apply to the next run",0)
00747       cw.clearHistory()
00748     elif toState == 'RUNNING':
00749       if cw.isReadOnly():
00750         cw.setReadOnly(0)
00751         self.showComments()
00752         cw.enterComment("Comment entry enabled.")
00753       #if fromState != 'PAUSED' and fromState != 'RESET':
00754       #  cw.clearDisplay()
00755     elif toState == 'RESET':
00756       if fromState is None: # Application has been loaded
00757         cw.clearHistory()
00758         cw.setReadOnly(0)
00759         self.showComments()
00760         cw.enterComment("Comment entry enabled.")
00761       else:
00762         if not self.inShutdown:
00763           cw.clearHistory()
00764           cw.setReadOnly(1)
00765           self.hideComments()
00766           cw.enterComment("Comment entry disabled.")
00767 
00768   def showHidePythonShell(self):
00769     if self.viewPythonShell.isOn():
00770       self.showPythonShell()
00771       if self.__fsm is None:
00772         self.getPythonShellWidget().redirectIO()
00773       elif self.__fsm.current_state != 'RUNNING':
00774           self.getPythonShellWidget().redirectIO()
00775     else:
00776       self.hidePythonShell()
00777       if self.__fsm is None:
00778         self.getPythonShellWidget().restoreIO()
00779       elif self.__fsm.current_state == 'RUNNING':
00780         self.getPythonShellWidget().restoreIO()
00781 
00782   def verifySoftware(self):
00783     for env in ROOT_DIR_ENVS:
00784       if os.environ.has_key(env):
00785         self.waitCursor()
00786         qApp.processEvents()
00787         (release, failedFiles) = Gversions.verifyFileDigests(rootDirEnv=env)
00788         self.normalCursor()
00789         strFailed = ""
00790         i = 0
00791         for filename in failedFiles:
00792           i += 1
00793           if i % 5 == 0:
00794             strFailed += '\n'
00795           strFailed += filename + ' '
00796         subsys = env[:env.find("_ROOT")]
00797         if len(failedFiles) == 0:
00798           mb = QMessageBox.information( None, "Software Verification Results",
00799                                         "%s Release = %s\n\n" % (subsys, release) +
00800                                         "Verification completed successfully",
00801                                         QMessageBox.Ok + QMessageBox.Default,
00802                                         QMessageBox.Cancel)
00803         else:
00804           mb = QMessageBox.warning    ( None, "Software Verification Results",
00805                                         "%s release = %s\n\n" % (subsys, release) +
00806                                         "Verification found the following " +
00807                                         "inconsistent files:\n" + strFailed,
00808                                         QMessageBox.Ok + QMessageBox.Default,
00809                                         QMessageBox.Cancel)
00810         if mb == QMessageBox.Cancel:
00811           break
00812 
00813   def elogWebsite(self):
00814     self.__common.elogWebsite()
00815 
00816   def warnFreeSpace(self, warn_level):
00817     mess = "Low Disk Space Warning!\n" + \
00818            "The space available for data writing\n" + \
00819            "is below %u Megabytes.  Continue?" % (warn_level / (1024*1024))
00820     mb = QMessageBox.warning(None, '', mess,
00821                              QMessageBox.Yes | QMessageBox.Default,
00822                              QMessageBox.No  | QMessageBox.Escape,
00823                              QMessageBox.NoButton );
00824     return mb is not QMessageBox.No
00825 
00826   def warnDirectoryExist(self, directory):
00827     mess = "Directory write error!\n" + \
00828            "The directory chosen for data writing:\n" + \
00829            "%s does not exist.  Continue?" % (directory)
00830     mb = QMessageBox.warning(None, '', mess,
00831                              QMessageBox.Yes | QMessageBox.Default,
00832                              QMessageBox.No  | QMessageBox.Escape,
00833                              QMessageBox.NoButton );
00834     return mb is not QMessageBox.No
00835 
00836   def aboutRunControl(self):
00837     release = Gversions.getReleaseFromDigest()
00838     message = "RunControl System\n\nLATTE Release: %s" % release
00839     if sys.modules.has_key('sihippo'):
00840       message = message + "\n\nHippoDraw Release: %s" % sys.modules['sihippo'].__version__
00841     message = message + "\n\nQt Version: %s" % qVersion()
00842     message = message + "\n\nPyQt Version: %s" % PYQT_VERSION_STR
00843     if 'SIP_VERSION' in dir(sip):
00844       message = message + "\n\nSIP Version: %s" % hex(sip.SIP_VERSION)
00845     subsysReleases = {}
00846     for subsysRoot in ROOT_DIR_ENVS:
00847       if subsysRoot != 'LATTE_ROOT' and os.environ.has_key(subsysRoot):
00848         release = Gversions.getReleaseFromDigest(digestDataFile=None, rootDirEnv=subsysRoot)
00849         subsysReleases[subsysRoot[:subsysRoot.find("_ROOT")]] = release
00850     if len(subsysReleases) > 0:
00851       message = message + "\n\nSubsystem Releases:"
00852       subSysList = subsysReleases.keys()
00853       subSysList.sort()
00854       for subSys in subSysList:
00855         message = message + "\n  %s\t%s" % (subSys, subsysReleases[subSys])
00856     QMessageBox.about(self,'LATTE RunControl', message)
00857 
00858 
00859   def fileLogout(self):
00860    if not self.login():
00861      self.inShutdown = True
00862      self.close()
00863 
00864   def closeEvent(self, e):
00865     if self.__common.options().securedir is not None and not self.inShutdown and \
00866        not self.__common.prefMan().preferences()["operatorobj"].isAdministrator():
00867       e.ignore()
00868     else:
00869       RunControlMainGUIImpl.closeEvent(self, e)
00870 
00871   def login(self):
00872     # Write the modified preferences to the cfg file
00873     loginResult = -1
00874     while loginResult == -1:
00875       loginResult = self.__common.showLogin(self)
00876       if loginResult == -1:
00877         QMessageBox.critical(self, "Authentication Failed",
00878                                    "Invalid user id or password")
00879       elif loginResult == -2:
00880         QMessageBox.critical(self, "Authentication Failed",
00881                                    "Password database is not available")
00882       if loginResult == -1:
00883         continue
00884       elif loginResult != 1:
00885         return loginResult
00886       # Set the operator based on login
00887       operator = self.__common.prefMan().preferences()["users"].getUserByLoginId(self.__common.getLoginId())
00888       if operator is None:
00889         QMessageBox.critical(self, "Authentication Failed",
00890                                   "Can not find the user under preferences")
00891         log.error("User authentication failed, can not find the user %s under preferences"
00892                   % self.__common.getLoginId())
00893         loginResult = -1
00894         continue
00895       else:
00896         self.cmbOperator.setCurrentText(operator.getName())
00897         self.cmbOperator.setEnabled(0)
00898         self.__common.prefMan().setOperator(operator.getName())
00899         self.applyPermissions(operator)
00900         return 1
00901 
00902   def getHardwareVersions(self, lat=None, xbrd=None):
00903     # Deprecated. Use the version in RunControlCommon to be
00904     # compatible with standalone scripts and suites.
00905     if self.__hwVersions is None:
00906       if lat is None: lat = self.__common.getLAT()
00907       if xbrd is None: xbrd = self.__common.getXBRD()
00908       self.__hwVersions = Gversions.getHardwareVersions(lat, xbrd)
00909     return self.__hwVersions
00910 
00911   def clearHardwareVersionsCache(self):
00912     # Deprecated. Use the version in RunControlCommon to be
00913     # compatible with standalone scripts and suites.
00914     self.__hwVersions = None
00915 
00916   def getFSM(self):
00917     return self.__fsm
00918 
00919   def getApp(self):
00920     return self.__app
00921 
00922   def isGUIthread(self):
00923     """Returns True if this method is being called from the GUI thread.
00924     """
00925     return threading.currentThread() == self.__guiThread
00926 
00927   def customEvent(self, e):
00928     """This method overrides the QObject base class's.  There is generally
00929     no reason to call this method directly.  It is called by the Qt
00930     infrastructure whenever the custom event is posted, e.g. by the following
00931     three methods of this class: createGUI, execGUImethodNR and execGUImethod.
00932     """
00933     self.__guiBridge.handleCustomEvent(e)
00934 
00935   def createGUI(self, obj, *args, **kwargs):
00936     """Method used for instantiating a GUI from a non-GUI subthread"""
00937     return self.__guiBridge.createGUI(self, obj, *args, **kwargs)
00938 
00939   def execGUImethodNR(self, func, *args, **kwargs):
00940     """Method used for executing a GUI function from a non-GUI thread.
00941     Use this method when no (useful) response is expected or
00942     when waiting for one could cause a deadlock.  Any response from the
00943     function is lost."""
00944     if self.inShutdown:  return # Don't try to update the GUI during shutdown
00945 
00946     return self.__guiBridge.execGUImethodNR(self, func, *args, **kwargs)
00947 
00948   def execGUImethod(self, func, *args, **kwargs):
00949     """Method used for executing a GUI function from a non-GUI thread.
00950     Use this method when a response is expected from the function and
00951     when it is appropriate to wait for it (no deadlock arises)"""
00952     if self.inShutdown:  return # Don't try to update the GUI during shutdown
00953 
00954     return self.__guiBridge.execGUImethod(self, func, *args, **kwargs)
00955 
00956   def getSecurityMan(self):
00957     return self.__common.getSecurityMan()
00958 

Generated on Fri Jul 21 13:26:32 2006 for LATTE R04-12-00 by doxygen 1.4.3