00001
00002
00003
00004
00005
00006
00007
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
00042
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
00099
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
00113 operator = common.prefMan().preferences()["operatorobj"]
00114 self.cmbOperator.setCurrentText(operator.getName())
00115
00116 self.__endRunDlg = rcEndRunDlgImpl(parent=self)
00117
00118
00119 self.inShutdown = False
00120 atexit.register(self.__shutdown)
00121
00122
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):
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
00236
00237 self.inShutdown = True
00238
00239 self.__currentState = "RESET"
00240
00241
00242 self.execGUImethod(self.statusBar().message, "Exiting")
00243
00244
00245 self.__actionEngine.shutdown()
00246 self.__scriptEngine.shutdown()
00247
00248
00249 self.__common.disconnect()
00250
00251
00252 dds = self.__common.getDDS()
00253 if dds is not None:
00254 dds.disconnect()
00255
00256
00257
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
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
00283
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
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
00412
00413
00414
00415
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
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
00629
00630
00631
00632
00633 else:
00634
00635
00636
00637
00638
00639
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
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
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
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
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