#!/usr/bin/env python3 # -*- coding: utf-8 -*- # # GUI de launch.py - version Qt # # NOTE UNICODE [RB]: # PyQt5 convertit les QString en "unicode" automatiquement. On essaye donc de garder la possibilite d'utiliser # des parametres "unicode". Ceci permettra une transition plus aisee vers python3 et une gestion correcte des accents # et caracteres speciaux. # Lorsqu'on veut appeler une fonction qui ne supporte pas des unicode, on encode en ascii avec # unicodestr.encode('ascii','ignore') # import os,sys from prmClassesGui import * from launch import * #======================================================================================== class LaunchGui(QWidget): app = QApplication(sys.argv) def __init__(self, launch, parent = None): # association du launcher avec ici launch.setLaunchGui(self) # parent constructor QWidget.__init__(self, parent) # -----------guis datas ---------------- self.guiPRM={} self.sf={} # --------- redirection Stream to console ------------------ self.process = None #self.outFile = None # ---------- load launch options --------------------- self.launch = launch self.launch.configActions() self.launch.applyDependencies() # ---------- draw frames ------------------------------- # |---------------------------------------------| # | BaseDir | # |---------------------------------------------| # | | Options : | # | | - Launch | # | | - runOptions | # | Console | - AT/Batch | # | | - SGE | # | | - FTP | # | | - Email | # | | Run Buttons | # |---------------------------------------------| # # main division (Vertical Layout) mainVBox = QVBoxLayout() mainVBox.setContentsMargins(2,2,2,2) self.setLayout(mainVBox) # baseDir GroupBox self.baseDirGrpBox = QGroupBox("Base Dir") mainVBox.addWidget(self.baseDirGrpBox) baseDirGridLayout = QGridLayout() self.baseDirGrpBox.setLayout(baseDirGridLayout) #grp0.setHeight(1) # gui is not starter from base dir => ... self.baseDir = BaseDirMultiPRM(self.guiPRM, 'launchGui.cfg') self.gBaseDir = BaseMultiDirPathLine(self, baseDirGridLayout, self.baseDir, 0, 0) # cadre commun : console + Options coFrame = QFrame() mainVBox.addWidget(coFrame) # division console/options (Horizontal Layout) hbox = QHBoxLayout() hbox.setContentsMargins(2,2,2,2) coFrame.setLayout(hbox) # Ajout de la console #hbox.addWidget(self.myStream.console) self.buildConsole() hbox.addWidget(self.console) # Ajout du frame d'options scroll = QScrollArea() scroll.setMinimumSize(QSize(500,500)) scroll.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding) hbox.addWidget(scroll) optFrame = QFrame() optVBox = QVBoxLayout() optFrame.setLayout(optVBox) #Ajout des Widgets d'options self.buildParametersFrame(optVBox) #Ajout des Widgets d'action self.buildButtonFrame(optVBox) scroll.setWidget(optFrame) # -------------------------------- self.resize(1100, 600) # -------------------------------- self.setWindowTitle('%s for Metafor' % sys.argv[0]) #print "window defined" try: iconFile = os.path.join(os.path.dirname(os.path.realpath(__file__)), "./Metafor.png") self.setWindowIcon(QIcon(iconFile)) #print "icon added" except: pass def buildParametersFrame(self, vbox): ''' rappel : CheckBoxLine(_win, _grpLayout, _prm, nrow, ncol) TextLine(_win, _grpLayout, _prm, nrow, ncol, ncolSpan=1, validator = None) PathLine(_win, _grpLayout, _prm, nrow, ncol, ncolSpan=1) FileLine(_win, _grpLayout, _prm, _fileType, nrow, ncol, ncolSpan=1) MultiPMRLine(_win, _grpLayout, _prm, nrow, ncol, ncolSpan=1) MultiPathLine(_win, _grpLayout, _prm, nrow, ncol, ncolSpan=1) ''' self.launchGrpBox = QGroupBox("Launch") vbox.addWidget(self.launchGrpBox) grplay1 = QGridLayout() self.launchGrpBox.setLayout(grplay1) grplay1.setColumnStretch(2,1) if isUnix(): self.sf['EXEC_NAME'] = FileLine(self, grplay1, self.launch.pars['EXEC_NAME'], "Exe files (*)", 0, 0, 4) else: self.sf['EXEC_NAME'] = FileLine(self, grplay1, self.launch.pars['EXEC_NAME'], "Exe files (*.exe)", 0, 0, 4) self.sf['TEST_NAME'] = FileLine(self, grplay1, self.launch.pars['TEST_NAME'], "Py files (*.py)", 1, 0, 4) self.sf['TEST_DIR'] = PathLine(self, grplay1, self.launch.pars['TEST_DIR'], 2, 0, 4) self.sf['ALGORITHM'] = MultiPMRLine(self, grplay1, self.launch.pars['ALGORITHM'],3,0) self.sf['MULTITEST'] = CheckBoxLine(self, grplay1, self.launch.pars['MULTITEST'], 3, 3) self.sf['RESTART_STEP'] = TextLine(self, grplay1, self.launch.pars['RESTART_STEP'], 4, 3, 1, QIntValidator(-1,100000)) self.sf['OUTFILE'] = TextLine(self, grplay1, self.launch.pars['OUTFILE'], 4, 0) # RUN OPTIONS self.runOptGrpBox = QGroupBox("Run Options") vbox.addWidget(self.runOptGrpBox) grplay2 = QGridLayout() self.runOptGrpBox.setLayout(grplay2) grplay2.setColumnStretch(2,1) import multiprocessing nbProcs = multiprocessing.cpu_count() self.sf['NB_TASKS'] = TextLine(self, grplay2, self.launch.pars['NB_TASKS'], 0, 0, 1, QIntValidator(1,nbProcs)) self.sf['NB_THREADS'] = TextLine(self, grplay2, self.launch.pars['NB_THREADS'], 0, 3, 1, QIntValidator(1,nbProcs)) self.sf['PRIORITY'] = TextLine(self, grplay2, self.launch.pars['PRIORITY'], 1, 0, 1) #, QIntValidator(1,5)) self.sf['AFFINITY'] = TextLine(self, grplay2, self.launch.pars['AFFINITY'], 1, 3, 1) self.sf['RUNMETHOD'] = MultiPMRLine(self, grplay2, self.launch.pars['RUNMETHOD'],2,0) # AT OPTION self.atOptGrpBox = QGroupBox("AT Option") vbox.addWidget(self.atOptGrpBox) grplay6 = QGridLayout() self.atOptGrpBox.setLayout(grplay6) grplay6.setColumnStretch(2,1) self.sf['AT_TIME'] = TextLine(self, grplay6, self.launch.pars['AT_TIME'], 0, 0, 1) # SGE OPTIONS self.sgeOptGrpBox = QGroupBox("Queue Options (SGE / SLURM / PBS)") vbox.addWidget(self.sgeOptGrpBox) grplay4 = QGridLayout() self.sgeOptGrpBox.setLayout(grplay4) grplay4.setColumnStretch(2,1) self.sf['QUEUE'] = TextLine(self, grplay4, self.launch.pars['QUEUE'], 0, 0, 1) self.sf['LOCALDISK'] = CheckBoxLine(self, grplay4, self.launch.pars['LOCALDISK'], 0, 3) self.sf['MEMORY'] = TextLine(self, grplay4, self.launch.pars['MEMORY'], 1, 0, 1) self.sf['TIME'] = TextLine(self, grplay4, self.launch.pars['TIME'], 1, 3, 1) self.sf['SGE_PE'] = TextLine(self, grplay4, self.launch.pars['SGE_PE'], 2, 0, 1) self.sf['SGEARGS'] = TextLine(self, grplay4, self.launch.pars['SGEARGS'], 2, 3, 1) self.sf['MODEL'] = MultiPMRLine(self, grplay4, self.launch.pars['MODEL'], 3, 0) # SGE OPTIONS # FTP OPTIONS self.ftpOptGrpBox = QGroupBox("FTP Options") vbox.addWidget(self.ftpOptGrpBox) grplay5 = QGridLayout() self.ftpOptGrpBox.setLayout(grplay5) grplay5.setColumnStretch(2,1) self.sf['ENABLE_FTP'] = CheckBoxLine(self, grplay5, self.launch.pars['ENABLE_FTP'], 0, 1) self.sf['FTP_HOST'] = TextLine(self, grplay5, self.launch.pars['FTP_HOST'], 1, 0, 1) self.sf['FTP_PORT'] = TextLine(self, grplay5, self.launch.pars['FTP_PORT'], 1, 3, 1, QIntValidator(0,1023)) self.sf['FTP_USER'] = TextLine(self, grplay5, self.launch.pars['FTP_USER'], 2, 0, 1) self.sf['FTP_PASS'] = TextLine(self, grplay5, self.launch.pars['FTP_PASS'], 2, 3, 1) self.sf['FTP_DIR'] = TextLine(self, grplay5, self.launch.pars['FTP_DIR'], 3, 0, 1) # MAIL OPTIONS self.mailOptGrpBox = QGroupBox("Mail Options") vbox.addWidget(self.mailOptGrpBox) grplay3 = QGridLayout() self.mailOptGrpBox.setLayout(grplay3) self.sf['SEND_MAIL'] = CheckBoxLine(self, grplay3, self.launch.pars['SEND_MAIL'], 0, 1) self.sf['MAIL_ADDR'] = TextLine(self, grplay3, self.launch.pars['MAIL_ADDR'], 1, 0, 1) grplay3.setColumnStretch(2,1) self.sf['SMTP_SERV'] = TextLine(self, grplay3, self.launch.pars['SMTP_SERV'], 1, 3, 1) def buildButtonFrame(self, vbox): # == Buttons Frame == butframe = QFrame() vbox.addWidget(butframe) butlayout = QHBoxLayout(); butlayout.setContentsMargins(0,0,0,0) butframe.setLayout(butlayout) self.goButton = QPushButton(self.tr("Go !!!")) butlayout.addWidget(self.goButton) self.goButton.pressed.connect(self.go) self.stopButton = QPushButton(self.tr("Stop !!!")) butlayout.addWidget(self.stopButton) self.stopButton.pressed.connect(self.interrupt) self.stopButton.setEnabled(False) butlayout.addStretch(1) ''' button = QPushButton(self.tr("LoadDefaults")) ; butlayout.addWidget(button) self.connect(button, SIGNAL("pressed()"), self.loadDef) butlayout.addStretch(1) ''' self.saveButton = QPushButton(self.tr("Save")) butlayout.addWidget(self.saveButton) self.saveButton.pressed.connect(self.save) self.quitButton = QPushButton(self.tr("Quit")) butlayout.addWidget(self.quitButton) self.quitButton.pressed.connect(self.quit) def guiEnable(self,boolVal): self.baseDirGrpBox.setEnabled(boolVal) self.launchGrpBox.setEnabled(boolVal) self.runOptGrpBox.setEnabled(boolVal) self.sgeOptGrpBox.setEnabled(boolVal) self.ftpOptGrpBox.setEnabled(boolVal) self.mailOptGrpBox.setEnabled(boolVal) self.goButton.setEnabled(boolVal) self.stopButton.setEnabled(not boolVal) self.saveButton.setEnabled(boolVal) self.quitButton.setEnabled(boolVal) # ---------------------------------------------------------------------------------- def go(self): print("Go pressed") # disable the gui modifications during run self.guiEnable(False) try: self.baseDir.savePars() self.launch.savePars() if self.launch.debug : self.launch.printPars() self.process = QProcess(self) self.process.setProcessChannelMode(QProcess.MergedChannels) self.process.setWorkingDirectory(self.baseDir.val) # evite de chercher a charger .pythonrc #env = self.process.processEnvironment() env = QProcessEnvironment.systemEnvironment() env.remove('PYTHONSTARTUP') # add mtfdir in the LD_LIBRARY_PATH (to allow process to find mt*.so...) if isUnix(): mtfdir, mtfexe = os.path.split(self.launch.pars['EXEC_NAME'].val) ldlp = mtfdir+':'+env.value('LD_LIBRARY_PATH','') env.insert('LD_LIBRARY_PATH',ldlp) self.process.setProcessEnvironment(env) # self.process.readyReadStandardOutput.connect(self.readStdOutput) # launch.go() ... self.launch.go() except Exception as e: QMessageBox.information(self, 'Error', str(e)) # re enable the gui modifications self.guiEnable(True) def interrupt(self): print("interrupt pressed") self.process.kill() print("interrupt done") # Boucle d'execution du Qprocess avec recuperation des events def waitQProcessForFinish(self): while self.process.waitForFinished(1000): self.app.processEvents() self.process.waitForFinished(-1) self.app.processEvents() retcode = self.process.ExitStatus() print("Finished: " + str(retcode)) self.process.close() return retcode def save(self): print("Save pressed") self.baseDir.savePars() #self.launch.printPars() self.launch.savePars() def quit(self): print("Quit pressed") sys.exit() def updateWidgetsValues(self): self.launch.applyDependencies() if self.launch.debug : print("updateWidgetsValues") for var in self.sf: self.sf[var].setParamValue() def updateWidgetsVisibility(self): if self.launch.debug : print("updateWidgetsVisibility") # update enabled/disabled of options self.launch.configActions() for var in self.sf: self.sf[var].setEnabled(self.launch.pars[var].enabled) #@pyqtSlot() def readStdOutput(self): out = self.process.readAllStandardOutput() out = bytes(out.data()) out = out.decode() out = out.replace('>>> >>> ... ... ... ... ... >>>','') out = out.replace('>>> ','') out = out.replace('\r\n','\n') self.write(out) #self.console.append(QString(out)) ''' self.console.moveCursor (QTextCursor.End) self.console.insertPlainText (QString(out)) self.console.moveCursor (QTextCursor.End) ''' if self.launch.outFile: self.launch.outFile.write(out) def buildConsole(self): self.stdout, sys.stdout = sys.stdout, self self.buf='' self.console = QTextEdit() self.console.setReadOnly(True) font = QFont("Lucida", 9) font.setStyleHint(QFont.TypeWriter) self.console.setFont(font) self.console.setLineWrapMode(QTextEdit.NoWrap) self.console.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) def write(self, stuff): if '\n' in stuff: list(map( self.writeLine, stuff.split("\n") )) else: self.buf += stuff self.app.processEvents() def writeLine(self, stuff): if len(self.buf): stuff = self.buf + stuff self.buf='' self.console.append(stuff) else: if stuff != '': self.console.append(stuff) def flush(self): pass #==================================================================================== def main(): #define launcher launch = LaunchJob() if launch.debug : print("launch defined") # create gui launchGui = LaunchGui(launch) # opening Gui launchGui.show() # signal pour cloturer proprement l'application PyQt quand on ferme la fenetre launchGui.app.lastWindowClosed.connect(launchGui.app.quit) print("ready.") sys.exit(launchGui.app.exec_()) if __name__=="__main__": main()