ScriptEngineMain.py

Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 #
00003 #                               Copyright 2005
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 script engine class - modified from RunControlMain for LICOS"
00012 __author__   = "S. Tuvi <stuvi@SLAC.Stanford.edu> SLAC - GLAST LAT I&T/Online"
00013 __date__     = "2005/07/23 00:08:27"
00014 __updated__  = "$Date: 2006/04/26 20:44:40 $"
00015 __version__  = "$Revision: 1.14 $"
00016 __release__  = "$Name: HEAD $"
00017 __credits__  = "SLAC"
00018 
00019 import LICOS.copyright_SLAC
00020 
00021 import                              os
00022 import                              sys
00023 import                              atexit
00024 import                              threading
00025 import logging               as     log
00026 import types
00027 import time
00028 import gc
00029 import string
00030 
00031 from   qt                    import *
00032 import sip
00033 
00034 from   Queue                 import Queue
00035 
00036 from   LICOS.lib.LATconstants                     import *
00037 from   LICOS.scriptEngine.ScriptEngineMainGUIImpl import ScriptEngineMainGUIImpl
00038 from   LICOS.scriptEngine.rcEndRunDlgImpl         import rcEndRunDlgImpl
00039 from   LICOS.lib.scriptEngine.TextMsgBox          import TextMsgBox
00040 
00041 # Modules here are imported to prevent them from being reloaded
00042 # See rcUtil for more info
00043 
00044 import Pyana
00045 import LDF
00046 
00047 try:
00048   import cfitsio
00049 except ImportError, e:
00050   pass
00051 
00052 try:
00053   import Numeric
00054 except ImportError, e:
00055   pass
00056 
00057 import rcUtil
00058 
00059 from rcReportGen   import rcReportGen
00060 from rcRunIdHelper import rcRunIdHelper
00061 
00062 from LICOS.core.thread.taskEngine   import TaskEngine
00063 from LICOS.core.thread.guiBridges   import GUIbridge, QtThreadBridge, PyThreadBridge
00064 from LICOS.util.gVersions           import Gversions, ROOT_DIRS
00065 
00066 
00067 class ConnectState:
00068   Disconnected = 0
00069   Waiting      = 1
00070   Connected    = 2
00071 
00072 class ScriptEngineMain(ScriptEngineMainGUIImpl):
00073   """!\brief Class for providing a script engine framework.
00074 
00075   """
00076 
00077   def __init__(self, common, parent = None, name = "RunControl", fl = 0):
00078     """!\brief ScriptEngineMain constructor.
00079 
00080     \param common ScriptEngineCommon instance
00081     \param parent Parent GUI
00082     \param name   GUI name
00083     \param fl     GUI flags
00084     """
00085     ScriptEngineMainGUIImpl.__init__(self, common, parent, name, fl)
00086 
00087     self.__common       = common
00088     self.__currentState = None
00089     self.__actionEngine = None
00090     self.__app          = None
00091     self.__browser      = None
00092     self.__hwVersions   = None
00093     self.__queue        = None
00094     self.__engine       = None
00095     self.__guiThread    = threading.currentThread()
00096     self.__guiBridge    = GUIbridge(self.__guiThread)
00097 
00098     # Set this object to be the client handler
00099     #common.getCmdCli().handler(self)
00100     self.__connection_state = ConnectState.Disconnected
00101     self.ResetButton.setEnabled(False)
00102     self.RunButton.setEnabled(False)
00103     self.StopButton.setEnabled(False)
00104     self.PauseButton.setEnabled(False)
00105 
00106     self.__actionEngine = TaskEngine("FSMactionEngine")
00107     self.__actionEngine.start()
00108 
00109     self.__scriptEngine = TaskEngine("ScriptEngine")
00110     self.__scriptEngine.start()
00111 
00112     # Pick an operator
00113     operator = common.prefMan().preferences()["operatorobj"]
00114     self.cmbOperator.setCurrentText(operator.getName())
00115 
00116     self.__endRunDlg = rcEndRunDlgImpl(parent=self)
00117 
00118     # Clean up at exit
00119     self.inShutdown = False
00120     atexit.register(self.__shutdown)
00121 
00122     # Preload modules specified in preferences
00123     preload = common.prefMan().preferences()["preload"]
00124     if preload.strip() != "":
00125       preloadList = map(string.strip, preload.split(','))
00126       for m in preloadList:
00127         exec 'import ' + m
00128     self.__common.setGUI(self)
00129 
00130   def connectClicked(self): # GUI thread
00131     """!\brief Slot for the connect menu option.
00132 
00133     """
00134     self.__common.connect()
00135 
00136   def applyPermissions(self, operator):
00137     """!\brief Apply the permissions for the current operator.
00138 
00139     \param operator rcUser instance
00140     """
00141     adminOverride = operator.isAdministrator()
00142     if adminOverride:
00143       self.fileExitAction.setEnabled(1)
00144     else:
00145       self.fileExitAction.setEnabled(0)
00146     if 'allow_python_shell' in operator.getPermissions() or adminOverride:
00147       self.viewPythonShell.setEnabled(1)
00148     else:
00149       self.viewPythonShell.setEnabled(0)
00150     if 'set_particle_type' in operator.getPermissions() or adminOverride:
00151       self.comboParticleType.setEnabled(1)
00152     else:
00153       self.comboParticleType.setEnabled(0)
00154     if 'set_orientation' in operator.getPermissions() or adminOverride:
00155       self.comboOrientation.setEnabled(1)
00156     else:
00157       self.comboOrientation.setEnabled(0)
00158 
00159     if 'edit_preferences' in operator.getPermissions() or adminOverride:
00160       self.editPreferencesAction.setEnabled(1)
00161     else:
00162       self.editPreferencesAction.setEnabled(0)
00163 
00164     for (panelLabel, panel) in self.panels().items():
00165       if 'enable_' + panelLabel.lower() + '_panel' in operator.getPermissions() or adminOverride:
00166         self.setEnabledTabPage(panelLabel, 1)
00167       else:
00168         self.setEnabledTabPage(panelLabel, 0)
00169       if "applyPermissions" in dir(panel):
00170         panel.applyPermissions(operator)
00171 
00172     if self.__common.getMSGLogger() is not None:
00173       if adminOverride:
00174         self.__common.getMSGLogger().setSecure(0)
00175       else:
00176         self.__common.getMSGLogger().setSecure(1)
00177       self.__common.getMSGLogger().show()
00178 
00179     self.__common.prefGUI().applyPermissions(operator)
00180 
00181 
00182   def setEnabledTabPage(self, panelLabel, enable):
00183     """!\brief Find the tabPage belonging to panel identified by \a panelLabel.
00184 
00185     \param panelLabel Panel label
00186     \param enable     Enable/disable flag
00187     """
00188     for i in range(self.ScriptEngineTab.count()):
00189       tabPage = self.ScriptEngineTab.page(i)
00190       if panelLabel == str(self.ScriptEngineTab.tabLabel(tabPage)):
00191         tabPage.setEnabled(enable)
00192         break
00193 
00194   def setOperator(self, operator):
00195     """!\brief Set the current operator.
00196 
00197     \param operator rcUser instance
00198     """
00199     self.cmbOperator.setCurrentText(operator)
00200     self.__common.prefMan().setOperator(operator)
00201 
00202   def setParticleType(self, particleType):
00203     """!\brief Set the particle type.
00204 
00205     \param particleType Particle type
00206     """
00207     self.__common.prefMan().setParticleType(particleType)
00208 
00209   def setOrientation(self, orientation):
00210     """!\brief Set the orientation.
00211 
00212     \param orientation Orientation
00213     """
00214     self.__common.prefMan().setOrientation(orientation)
00215 
00216   def getName(self):
00217     """!\brief Retrieve the name of the main script engine class.
00218 
00219     \return Main script engine class name
00220     """
00221     return "ScriptEngineMain"
00222 
00223   def __statusMsg(self, msg, tmo):
00224     """!\brief Update the status bar with the message \a msg
00225 
00226     \param msg Message
00227     \param tmo Display duration
00228     """
00229     self.execGUImethodNR(self.statusBar().message, msg, tmo)
00230 
00231   def __shutdown(self):
00232     """!\brief Clean up and shut down the various threads.
00233 
00234     """
00235     # This method expects to be executed from the GUI thread.
00236 
00237     self.inShutdown = True
00238 
00239     self.__currentState = "RESET"
00240 
00241     # Use the following non-NR call to wait for the reset to finish
00242     self.execGUImethod(self.statusBar().message, "Exiting")
00243 
00244     # Shut down the task engines
00245     self.__actionEngine.shutdown()
00246     self.__scriptEngine.shutdown()
00247 
00248     # Disconnect from the command and event servers
00249     self.__common.disconnect()
00250 
00251     # Stop the data distribution server
00252     dds = self.__common.getDDS()
00253     if dds is not None:
00254       dds.disconnect()
00255 
00256     # Stop the GUI bridge
00257     #self.__qtBridge.terminate()
00258     self.__guiBridge.shutdown()
00259 
00260     archiver = self.__common.getCmdCli().getArchiver()
00261     if archiver is not None:
00262       archiver.abort()
00263 
00264 
00265   def initApp(self):
00266     """!\brief Method usually invoked by the GUI to load a new application.
00267 
00268     """
00269     applName = self.OpenAppl.currentText()
00270     if str(applName) == "":  return     # Operator cancelled
00271     self.loadApp(str(applName))
00272 
00273   def loadApp(self, applName):
00274     """!\brief Method that can be invoked from code to load a new application.
00275 
00276     \param applName  Name of an application to load
00277     """
00278     if applName is None:
00279       self.__statusMsg('Loading aborted', 0)
00280       return
00281 
00282     # Start the application in its own thread after the reset from above
00283     # (if any) completes.
00284     self.__actionEngine.spawn(self.__startApp, str(applName))
00285 
00286     self.RunButton.setEnabled(True)
00287 
00288     self.__currentState = "RESET"
00289     self.execGUImethodNR(self.State.setText, self.__currentState)
00290     self.execGUImethodNR(self.handleComments, self.__currentState)
00291 
00292   def loadModule(self, module):
00293     """!\brief Method that can be invoked from code to load a new module.
00294 
00295     \param module  Pointer to module to load
00296     """
00297     self.__actionEngine.spawn(self.__startModule, module)
00298 
00299   def __initAppCommon(self, app, appName, filename):
00300     """!\brief Initialize the GUI based on the loaded application.
00301 
00302     \param app      Application module object
00303     \param appName  Application name
00304     \param filename Filename for the loaded application module
00305 
00306     \return Application loaded message
00307     """
00308     msg = "%s %s loaded from %s" % (app.getType(), app.getName(), filename)
00309     log.info(msg)
00310 
00311     # Update the application history list box.
00312     self.execGUImethod(self.__updateAppListBox, appName)
00313     if self.__common.options().securedir is None and self.__common.options().norcoverride is None:
00314       self.execGUImethod(self.__updateRunConditions, 'NOT-DEFINED')
00315 
00316     return msg
00317 
00318   def __updateRunConditions(self, undef):
00319     """!\brief Set the run conditions to the NOT-DEFINED value.
00320 
00321     \param undef Undefined value string
00322     """
00323     prefMan = self.__common.prefMan()
00324     self.cmbOperator.setCurrentText(undef)
00325     prefMan.setOperator(undef)
00326     self.comboParticleType.setCurrentText(undef)
00327     prefMan.setParticleType(undef)
00328     self.comboOrientation.setCurrentText(undef)
00329     prefMan.setOrientation(undef)
00330     prefMan.setSite(undef)
00331     prefMan.setPhase(undef)
00332     prefMan.setInstrumentType(undef)
00333 
00334   def __updateAppListBox(self, appName):
00335     """!\brief Update the application combo box with the loaded application.
00336 
00337     \brief appName Full path for the application.
00338     """
00339     if self.OpenAppl.listBox().findItem(appName) is None:
00340       self.OpenAppl.insertItem(appName)
00341 
00342   def __startApp(self, appName):
00343     """!\brief Load and instantiate the application.
00344 
00345     \param appName Full path for the application.
00346     """
00347     try:
00348       self.execGUImethod(self.statusMonitor().stopWatch)
00349       self.execGUImethod(self.statusMonitor().restoreWatch)
00350       (module, filename, app) = rcUtil.scriptLoad(appName, self.__common)
00351       self.updateState(app.current_state)
00352     except Exception, e:
00353       log.exception(e)
00354       if type(e) == types.ListType:
00355         self.__statusMsg(e[0], 0)
00356       else:
00357         self.__statusMsg(str(e), 0)
00358       return
00359     self.__clearPreviousApp()
00360     self.__setupApp(app, appName, filename)
00361 
00362   def __startModule(self, module):
00363     """!\brief Clear previous app, force garbage collection and setup the GUI.
00364 
00365     \param module Module object for the loaded application.
00366     """
00367     self.__clearPreviousApp()
00368     appName = module.userModuleName
00369     filename = module.__file__
00370     self.__setupApp(module, filename, filename)
00371 
00372   def __clearPreviousApp(self):
00373     """!\brief Delete the previous app and force garbage collection.
00374 
00375     """
00376     del self.__app
00377     self.__app = None
00378     gc.collect()
00379     if len(gc.garbage) != 0:
00380       log.error("ScriptEngineMain: Found garbage: %s" % gc.garbage)
00381 
00382   def __setupApp(self, app, appName, filename):
00383     """!\brief Setup the GUI for the loaded app.
00384 
00385     \param app      Application object
00386     \param appName  Full path for the application Python source
00387     \param filename Name of the file that the module is loaded from
00388     """
00389     self.StopButton.setEnabled(True)
00390     if 'doPause' in dir(app):
00391       self.PauseButton.setEnabled(True)
00392     else:
00393       self.PauseButton.setEnabled(False)
00394     if 'doReset' in dir(app):
00395       self.ResetButton.setEnabled(True)
00396     else:
00397       self.ResetButton.setEnabled(False)
00398     self.__app = app
00399     msg = self.__initAppCommon(self.__app, appName, filename)
00400     self.execGUImethodNR(self.__updateGUI, False)
00401     self.execGUImethodNR(self.handleComments, self.__currentState)
00402     self.execGUImethod(self.statusMonitor().startWatch)
00403     self.__common.getDBN()['_app'] = self.__app
00404     self.__statusMsg(msg, 0)
00405 
00406   def __updateGUI(self, enabled):
00407     """!\brief Method for updating the GUI.
00408 
00409     \param enabled Run conditions enabled/disabled flag.
00410     """
00411     # This method may complete asynchronously to the application's activities
00412     # since the application doesn't depend on the results.  Should this ever
00413     # change, be sure to change the execGUImethodNR() calls below to
00414     # execGUImethod() calls so that the fsmActionEngine waits for __updateGUI()
00415     # to complete before continuing.
00416     prefGUI = self.__common.prefGUI()
00417     operator = self.__common.preferences()["operatorobj"]
00418     if self.__common.options().securedir is not None and 'administrator' not in operator.getRoles():
00419       permissions = operator.getPermissions()
00420       self.cmbOperator.setEnabled(0)
00421       if 'set_particle_type' in permissions:
00422         self.comboParticleType.setEnabled(enabled)
00423       if 'set_orientation' in permissions:
00424         self.comboOrientation.setEnabled(enabled)
00425       if 'set_site_run_condition' in permissions:
00426         prefGUI.comboSite.setEnabled(enabled)
00427       if 'set_instrument_type_run_condition' in permissions:
00428         prefGUI.comboInstrumentType.setEnabled(enabled)
00429       if 'set_phase_run_condition' in permissions:
00430         prefGUI.comboPhase.setEnabled(enabled)
00431     else:
00432       self.cmbOperator.setEnabled(enabled)
00433       self.comboParticleType.setEnabled(enabled)
00434       self.comboOrientation.setEnabled(enabled)
00435       prefGUI.comboSite.setEnabled(enabled)
00436       prefGUI.comboInstrumentType.setEnabled(enabled)
00437       prefGUI.comboPhase.setEnabled(enabled)
00438 
00439   def updateState(self, state):
00440     """!\brief Update the GUI to reflect the state of the current application.
00441 
00442     \param state State string from the application's FSM
00443     """
00444     self.execGUImethodNR(self.State.setText, state)
00445 
00446   def RunClicked(self):
00447     """!\brief Slot for the run button.
00448 
00449     """
00450     ScriptEngineMainGUIImpl.RunClicked(self)
00451     if 'doResume' in dir(self.__app) and self.__app.isPaused():
00452       self.__actionEngine.spawn(self.__resume)
00453     else:
00454       self.waitCursor()
00455       self.__scriptEngine.spawn(self.__run)
00456       self.normalCursor()
00457 
00458   def __run(self):
00459     """!\brief Start the execution of the application.
00460 
00461     """
00462     rcUtil.scriptRun(self.__app)
00463     self.execGUImethodNR(self.updateState, self.__app.current_state)
00464 
00465   def __resume(self):
00466     """!\brief Resume the paused script.
00467 
00468     """
00469     self.__app.doResume()
00470 
00471   def ResetClicked(self):
00472     """!\brief Slot for the reset button.
00473 
00474     """
00475     ScriptEngineMainGUIImpl.ResetClicked(self)
00476     self.waitCursor()
00477     self.__actionEngine.spawn(self.__reset)
00478     self.normalCursor()
00479 
00480   def __reset(self):
00481     """!\brief Reset the script.
00482 
00483     """
00484     if self.__app is not None and 'doReset' in dir(self.__app):
00485       self.__app.doReset()
00486 
00487   def StopClicked(self):
00488     """!\brief Slot for the stop button.
00489 
00490     """
00491     ScriptEngineMainGUIImpl.StopClicked(self)
00492     self.waitCursor()
00493     self.__actionEngine.spawn(self.__abort)
00494     self.normalCursor()
00495 
00496   def __abort(self):
00497     """!\brief Abort the running script.
00498 
00499     """
00500     if self.__app is not None:
00501       self.__app.doAbort()
00502 
00503   def PauseClicked(self):
00504     """!\brief Slot for the pause button.
00505 
00506     """
00507     ScriptEngineMainGUIImpl.PauseClicked(self)
00508     self.waitCursor()
00509     self.__actionEngine.spawn(self.__pause)
00510     self.normalCursor()
00511 
00512   def __pause(self):
00513     """!\brief Pause the running script (if supported).
00514 
00515     """
00516     if self.__app is not None:
00517       if 'doPause' in dir(self.__app):
00518         self.__app.doPause()
00519 
00520   def doRun(self):
00521     """!\brief Emit a Run button click under program control.
00522 
00523     Can be done from a subthread.
00524     """
00525     self.doEmit(self.RunButton)
00526 
00527   def doReset(self):
00528     """!\brief Emit a Reset button click under program control.
00529 
00530     Can be done from a subthread.
00531     """
00532     self.doEmit(self.ResetButton)
00533 
00534   def doEmit(self, obj, signal = SIGNAL("clicked()"), args = ()):
00535     """!\brief Emit a signal, possibly from a subthread.
00536 
00537     By default the signal is 'clicked()' with no arguments.
00538 
00539     \param obj    GUI widget that will receive the signal
00540     \param signal Signal
00541     \param args   Arguments to the slot method
00542     """
00543     if self.isGUIthread():
00544       obj.emit(signal, args)
00545     else:
00546       self.execGUImethodNR(obj.emit, signal, args)
00547 
00548   def normalCursor(self):
00549     """!\brief Set the mouse cursor to normal.
00550 
00551     """
00552     self.execGUImethodNR(self.setCursor, QCursor(QWidget.ArrowCursor))
00553 
00554   def waitCursor(self):
00555     """!\brief Set the mouse cursor to hourglass.
00556 
00557     """
00558     self.execGUImethodNR(self.setCursor, QCursor(QWidget.WaitCursor))
00559 
00560   def getEndRunComments(self):
00561     """!\brief Retrieve the end run comments widget.
00562 
00563     \return rcCommentPanel instance
00564     """
00565     return self.__endRunDlg.comments.getWidget()
00566 
00567   def handleComments(self, currentState):
00568     """!\brief Based on the current state hide or show the comment panel.
00569 
00570     \param currentState Script run state.
00571     """
00572     cw = self.getCommentWidget()
00573     if currentState == 'STOPPED':
00574       if cw.isReadOnly():
00575         cw.setReadOnly(0)
00576         self.showComments()
00577         cw.enterComment("Comment entry enabled.")
00578       cw.enterComment("Note: Comments entered after this point will apply to the next run",0)
00579       cw.clearHistory()
00580     elif currentState == 'RUNNING':
00581       if cw.isReadOnly():
00582         cw.setReadOnly(0)
00583         self.showComments()
00584         cw.enterComment("Comment entry enabled.")
00585     elif currentState == 'RESET':
00586       cw.clearHistory()
00587       cw.setReadOnly(0)
00588       self.showComments()
00589       cw.enterComment("Comment entry enabled.")
00590 
00591   def showHidePythonShell(self):
00592     """!\brief Toggle the Python shell window.
00593 
00594     """
00595     if self.viewPythonShell.isOn():
00596       self.showPythonShell()
00597       self.getPythonShellWidget().redirectIO()
00598     else:
00599       self.hidePythonShell()
00600       self.getPythonShellWidget().restoreIO()
00601 
00602   def verifySoftware(self):
00603     """!\brief Perform software verification.
00604 
00605     """
00606     mb = TextMsgBox(self)
00607     mb.setCaption("Verify Software")
00608     mb.labelData.setText("Software Verification Results:")
00609     for rootDir in ROOT_DIRS:
00610       if os.path.exists(os.path.join(ONLINE_ROOT, rootDir)):
00611         qApp.setOverrideCursor(QCursor(QWidget.WaitCursor))
00612         qApp.processEvents()
00613         (release, failedFiles) = Gversions.verifyFileDigests(rootDir)
00614         qApp.restoreOverrideCursor()
00615         qApp.processEvents()
00616         strFailed = ""
00617         i = 0
00618         for filename in failedFiles:
00619           i += 1
00620           #if i % 5 == 0:
00621           if i % 1 == 0:
00622             strFailed += '\n'
00623           strFailed += filename + ' '
00624         if len(failedFiles) == 0:
00625           msg = "%s Release = %s\n\n" % (rootDir, release) + \
00626                                "Verification completed successfully"
00627           log.info(msg)
00628           #mb = QMessageBox.information( None, "Software Verification Results",
00629           #                              "%s Release = %s\n\n" % (rootDir, release) +
00630           #                              "Verification completed successfully",
00631           #                              QMessageBox.Ok + QMessageBox.Default,
00632           #                              QMessageBox.Cancel)
00633         else:
00634           #mb = QMessageBox.warning    ( None, "Software Verification Results",
00635           #                              "%s release = %s\n\n" % (rootDir, release) +
00636           #                              "Verification found the following " +
00637           #                              "inconsistent files:\n" + strFailed,
00638           #                              QMessageBox.Ok + QMessageBox.Default,
00639           #                              QMessageBox.Cancel)
00640           msg = "%s release = %s\n\n" % (rootDir, release) + \
00641                               "Verification found the following " + \
00642                               "inconsistent files:\n" + strFailed
00643           log.warn(msg)
00644         mb.textData.setText(msg)
00645         result = mb.exec_loop()
00646         if not result:
00647           break
00648     mb.deleteLater()
00649 
00650   def elogWebsite(self):
00651     """!\brief Launch the E-Logbook web site.
00652 
00653     """
00654     self.__common.elogWebsite()
00655 
00656   def warnFreeSpace(self, warn_level):
00657     """!\brief Display a low disk space warning.
00658 
00659     \param warn_level Disk space in bytes.
00660 
00661     """
00662     mess = "Low Disk Space Warning!\n" + \
00663            "The space available for data writing\n" + \
00664            "is below %u Megabytes.  Continue?" % (warn_level / (1024*1024))
00665     mb = QMessageBox.warning(None, '', mess,
00666                              QMessageBox.Yes | QMessageBox.Default,
00667                              QMessageBox.No  | QMessageBox.Escape,
00668                              QMessageBox.NoButton );
00669     return mb is not QMessageBox.No
00670 
00671   def warnDirectoryExist(self, directory):
00672     """!\brief Warn if a directory does not exist.
00673 
00674     \param directory Non-existant directory.
00675     """
00676     mess = "Directory write error!\n" + \
00677            "The directory chosen for data writing:\n" + \
00678            "%s does not exist.  Continue?" % (directory)
00679     mb = QMessageBox.warning(None, '', mess,
00680                              QMessageBox.Yes | QMessageBox.Default,
00681                              QMessageBox.No  | QMessageBox.Escape,
00682                              QMessageBox.NoButton );
00683     return mb is not QMessageBox.No
00684 
00685   def aboutScriptEngine(self):
00686     """!\brief The About dialog box for the Script Engine.
00687 
00688     Displays version information for Hippo, Qt, PyQt, SIP and
00689     subsystem releases.
00690 
00691     """
00692     release = Gversions.getReleaseFromDigest()
00693     message = "ScriptEngine System\n\nLICOS Release: %s" % release
00694     if sys.modules.has_key('sihippo'):
00695       message = message + "\n\nHippoDraw Release: %s" % sys.modules['sihippo'].__version__
00696     message = message + "\n\nQt Version: %s" % qVersion()
00697     message = message + "\n\nPyQt Version: %s" % PYQT_VERSION_STR
00698     if 'SIP_VERSION_STR' in dir(sip):
00699       message = message + "\n\nSIP Version: %s" % sip.SIP_VERSION_STR
00700     elif 'SIP_VERSION' in dir(sip):
00701       message = message + "\n\nSIP Version: %s" % hex(sip.SIP_VERSION)
00702     subsysReleases = {}
00703     for rootDir in ROOT_DIRS:
00704       if rootDir != 'LICOS' and os.path.exists(os.path.join(ONLINE_ROOT, rootDir)):
00705         release = Gversions.getReleaseFromDigest(digestDataFile=None, rootDir=rootDir)
00706         subsysReleases[rootDir] = release
00707     if len(subsysReleases) > 0:
00708       message = message + "\n\nSubsystem Releases:"
00709       subSysList = subsysReleases.keys()
00710       subSysList.sort()
00711       for subSys in subSysList:
00712         message = message + "\n  %s\t%s" % (subSys, subsysReleases[subSys])
00713     QMessageBox.about(self,'LICOS ScriptEngine', message)
00714 
00715 
00716   def fileLogout(self):
00717     """!\brief Log the current user off.
00718 
00719     """
00720     if not self.login():
00721       self.inShutdown = True
00722       self.close()
00723 
00724   def closeEvent(self, e):
00725     """!\brief Trap the close event of the main GUI.
00726 
00727     In secure mode, only administrators can close the main GUI while logged in.
00728     Other users need to logout first in order to exit the Script Engine.
00729 
00730     \param e A QEvent object.
00731     """
00732     if self.__common.options().securedir is not None and not self.inShutdown and \
00733        not self.__common.prefMan().preferences()["operatorobj"].isAdministrator():
00734       e.ignore()
00735     else:
00736       ScriptEngineMainGUIImpl.closeEvent(self, e)
00737 
00738   def login(self):
00739     """!\brief Login to the script engine.
00740 
00741     """
00742     # Write the modified preferences to the cfg file
00743     loginResult = -1
00744     while loginResult == -1:
00745       loginResult = self.__common.showLogin(self)
00746       if loginResult == -1:
00747         QMessageBox.critical(self, "Authentication Failed",
00748                                    "Invalid user id or password")
00749       elif loginResult == -2:
00750         QMessageBox.critical(self, "Authentication Failed",
00751                                    "Password database is not available")
00752       if loginResult == -1:
00753         continue
00754       elif loginResult != 1:
00755         return loginResult
00756       # Set the operator based on login
00757       operator = self.__common.prefMan().preferences()["users"].getUserByLoginId(self.__common.getLoginId())
00758       if operator is None:
00759         QMessageBox.critical(self, "Authentication Failed",
00760                                   "Can not find the user under preferences")
00761         log.error("User authentication failed, can not find the user %s under preferences"
00762                   % self.__common.getLoginId())
00763         loginResult = -1
00764         continue
00765       else:
00766         self.cmbOperator.setCurrentText(operator.getName())
00767         self.cmbOperator.setEnabled(0)
00768         self.__common.prefMan().setOperator(operator.getName())
00769         self.applyPermissions(operator)
00770         return 1
00771 
00772   def isGUIthread(self):
00773     """!\brief Returns True if this method is being called from the GUI thread.
00774 
00775     \return Boolean indicating whether the current thread is the GUI thread.
00776     """
00777     return threading.currentThread() == self.__guiThread
00778 
00779   def customEvent(self, e):
00780     """!\brief Post an event to the GUI thread.
00781 
00782     This method overrides the QObject base class's.  There is generally
00783     no reason to call this method directly.  It is called by the Qt
00784     infrastructure whenever the custom event is posted, e.g. by the following
00785     three methods of this class: createGUI, execGUImethodNR and execGUImethod.
00786 
00787     \param e A QEvent object
00788     """
00789     self.__guiBridge.handleCustomEvent(e)
00790 
00791   def createGUI(self, obj, *args, **kwargs):
00792     """!\brief Method used for instantiating a GUI from a non-GUI subthread
00793 
00794     \param obj    Class of the object that is being created
00795     \param args   Positional arguments to the constructor of the object
00796     \param kwargs Keyword arguments to the constructor of the object
00797 
00798     \return Object instance
00799     """
00800     resp = self.__guiBridge.createGUI(self, obj, *args, **kwargs)
00801     return resp
00802 
00803   def execGUImethodNR(self, func, *args, **kwargs):
00804     """!\brief Method used for executing a GUI function from a non-GUI thread.
00805 
00806     Use this method when no (useful) response is expected or
00807     when waiting for one could cause a deadlock.  Any response from the
00808     function is lost.
00809 
00810     \param func The method whose execution in the GUI thread is being requested
00811     \param args   Positional arguments to the constructor of the object
00812     \param kwargs Keyword arguments to the constructor of the object
00813 
00814     \return None
00815     """
00816     if self.inShutdown:  return # Don't try to update the GUI during shutdown
00817 
00818     return self.__guiBridge.execGUImethodNR(self, func, *args, **kwargs)
00819 
00820   def execGUImethod(self, func, *args, **kwargs):
00821     """!\brief Method used for executing a GUI function from a non-GUI thread.
00822 
00823     Use this method when a response is expected from the function and
00824     when it is appropriate to wait for it (no deadlock arises)
00825 
00826     \param func The method whose execution in the GUI thread is being requested
00827     \param args   Positional arguments to the constructor of the object
00828     \param kwargs Keyword arguments to the constructor of the object
00829 
00830     \return None if in shut down otherwise
00831             the return value from the method
00832     """
00833     if self.inShutdown:  return # Don't try to update the GUI during shutdown
00834 
00835     return self.__guiBridge.execGUImethod(self, func, *args, **kwargs)
00836 
00837   def getEndRunDlg(self):
00838     """!\brief Retrieve reference to the End Run Dialog.
00839 
00840     \return rcEndRunDlgImpl instance
00841     """
00842     return self.__endRunDlg

Generated on Thu Apr 27 20:52:43 2006 for LICOS L02-01-00 by doxygen 1.4.6-NO