1# -*- coding: utf-8 -*- 2 3# Copyright (c) 2003 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> 4# 5 6""" 7Module implementing a dialog to show the output of the ericapi process. 8""" 9 10import os.path 11 12from PyQt5.QtCore import QProcess, QTimer 13from PyQt5.QtWidgets import QDialog, QDialogButtonBox 14 15from E5Gui import E5MessageBox 16 17from .Ui_EricapiExecDialog import Ui_EricapiExecDialog 18 19import Preferences 20 21 22class EricapiExecDialog(QDialog, Ui_EricapiExecDialog): 23 """ 24 Class implementing a dialog to show the output of the ericapi process. 25 26 This class starts a QProcess and displays a dialog that 27 shows the output of the documentation command process. 28 """ 29 def __init__(self, cmdname, parent=None): 30 """ 31 Constructor 32 33 @param cmdname name of the ericapi generator (string) 34 @param parent parent widget of this dialog (QWidget) 35 """ 36 super().__init__(parent) 37 self.setModal(True) 38 self.setupUi(self) 39 40 self.buttonBox.button( 41 QDialogButtonBox.StandardButton.Close).setEnabled(False) 42 self.buttonBox.button( 43 QDialogButtonBox.StandardButton.Cancel).setDefault(True) 44 45 self.process = None 46 self.cmdname = cmdname 47 48 def start(self, args, fn): 49 """ 50 Public slot to start the ericapi command. 51 52 @param args commandline arguments for ericapi program (list of strings) 53 @param fn filename or dirname to be processed by ericapi program 54 (string) 55 @return flag indicating the successful start of the process (boolean) 56 """ 57 self.errorGroup.hide() 58 59 self.filename = fn 60 if os.path.isdir(self.filename): 61 dname = os.path.abspath(self.filename) 62 fname = "." 63 if os.path.exists(os.path.join(dname, "__init__.py")): 64 fname = os.path.basename(dname) 65 dname = os.path.dirname(dname) 66 else: 67 dname = os.path.dirname(self.filename) 68 fname = os.path.basename(self.filename) 69 70 self.contents.clear() 71 self.errors.clear() 72 73 program = args[0] 74 del args[0] 75 args.append(fname) 76 77 self.process = QProcess() 78 self.process.setWorkingDirectory(dname) 79 80 self.process.readyReadStandardOutput.connect(self.__readStdout) 81 self.process.readyReadStandardError.connect(self.__readStderr) 82 self.process.finished.connect(self.__finish) 83 84 self.setWindowTitle( 85 self.tr('{0} - {1}').format(self.cmdname, self.filename)) 86 self.process.start(program, args) 87 procStarted = self.process.waitForStarted(5000) 88 if not procStarted: 89 E5MessageBox.critical( 90 self, 91 self.tr('Process Generation Error'), 92 self.tr( 93 'The process {0} could not be started. ' 94 'Ensure, that it is in the search path.' 95 ).format(program)) 96 return procStarted 97 98 def on_buttonBox_clicked(self, button): 99 """ 100 Private slot called by a button of the button box clicked. 101 102 @param button button that was clicked (QAbstractButton) 103 """ 104 if button == self.buttonBox.button( 105 QDialogButtonBox.StandardButton.Close 106 ): 107 self.accept() 108 elif button == self.buttonBox.button( 109 QDialogButtonBox.StandardButton.Cancel 110 ): 111 self.__finish() 112 113 def __finish(self): 114 """ 115 Private slot called when the process finished. 116 117 It is called when the process finished or 118 the user pressed the button. 119 """ 120 if ( 121 self.process is not None and 122 self.process.state() != QProcess.ProcessState.NotRunning 123 ): 124 self.process.terminate() 125 QTimer.singleShot(2000, self.process.kill) 126 self.process.waitForFinished(3000) 127 128 self.buttonBox.button( 129 QDialogButtonBox.StandardButton.Close).setEnabled(True) 130 self.buttonBox.button( 131 QDialogButtonBox.StandardButton.Cancel).setEnabled(False) 132 self.buttonBox.button( 133 QDialogButtonBox.StandardButton.Close).setDefault(True) 134 135 self.process = None 136 137 self.contents.insertPlainText( 138 self.tr('\n{0} finished.\n').format(self.cmdname)) 139 self.contents.ensureCursorVisible() 140 141 def __readStdout(self): 142 """ 143 Private slot to handle the readyReadStandardOutput signal. 144 145 It reads the output of the process, formats it and inserts it into 146 the contents pane. 147 """ 148 self.process.setReadChannel(QProcess.ProcessChannel.StandardOutput) 149 150 while self.process.canReadLine(): 151 s = str(self.process.readLine(), 152 Preferences.getSystem("IOEncoding"), 153 'replace') 154 self.contents.insertPlainText(s) 155 self.contents.ensureCursorVisible() 156 157 def __readStderr(self): 158 """ 159 Private slot to handle the readyReadStandardError signal. 160 161 It reads the error output of the process and inserts it into the 162 error pane. 163 """ 164 self.process.setReadChannel(QProcess.ProcessChannel.StandardError) 165 166 while self.process.canReadLine(): 167 self.errorGroup.show() 168 s = str(self.process.readLine(), 169 Preferences.getSystem("IOEncoding"), 170 'replace') 171 self.errors.insertPlainText(s) 172 self.errors.ensureCursorVisible() 173