class ProcessThread(QObject): _ProcssOutput = pyqtSignal(object) def __init__(self,cmd,): QObject.__init__(self) self.cmd = cmd def getNameThread(self): return '[New Thread {} ({})]'.format(self.procThread.pid(),self.objectName()) @pyqtSlot() def readProcessOutput(self): self.data = str(self.procThread.readAllStandardOutput()) self._ProcssOutput.emit(self.data) def start(self): self.procThread = QProcess(self) self.procThread.setProcessChannelMode(QProcess.MergedChannels) QObject.connect(self.procThread, SIGNAL('readyReadStandardOutput()'), self, SLOT('readProcessOutput()')) self.procThread.start(self.cmd.keys()[0],self.cmd[self.cmd.keys()[0]]) print '[New Thread {} ({})]'.format(self.procThread.pid(),self.objectName()) def stop(self): print 'Thread::[{}] successfully stopped.'.format(self.objectName()) if hasattr(self,'procThread'): self.procThread.terminate() self.procThread.waitForFinished() self.procThread.kill()
class ProcessHostapd(QObject): statusAP_connected = pyqtSignal(object) def __init__(self,cmd): QObject.__init__(self) self.cmd = cmd def getNameThread(self): return '[New Thread {} ({})]'.format(self.procHostapd.pid(),self.objectName()) @pyqtSlot() def read_OutputCommand(self): self.data = str(self.procHostapd.readAllStandardOutput()) if 'AP-STA-DISCONNECTED' in self.data.rstrip() or 'inactivity (timer DEAUTH/REMOVE)' in self.data.rstrip(): self.statusAP_connected.emit(self.data.split()[2]) def start(self): self.makeLogger() self.procHostapd = QProcess(self) self.procHostapd.setProcessChannelMode(QProcess.MergedChannels) QObject.connect(self.procHostapd, SIGNAL('readyReadStandardOutput()'), self, SLOT('read_OutputCommand()')); self.procHostapd.start(self.cmd.keys()[0],self.cmd[self.cmd.keys()[0]]) print '[New Thread {} ({})]'.format(self.procHostapd.pid(),self.objectName()) def makeLogger(self): setup_logger('hostapd', './Logs/AccessPoint/requestAP.log') self.log_hostapd = logging.getLogger('hostapd') def stop(self): print 'Thread::[{}] successfully stopped.'.format(self.objectName()) if hasattr(self,'procHostapd'): self.procHostapd.terminate() self.procHostapd.waitForFinished() self.procHostapd.kill()
class ThreadDNSspoofNF(QObject): DnsReq = pyqtSignal(object) def __init__(self,domains,interface,redirect,APmode=True,parent=None): super(ThreadDNSspoofNF, self).__init__(parent) self.domains = domains self.interface = interface self.redirect = redirect self.APmode = APmode self.desc = 'DNS spoof Module::NetFilter' @pyqtSlot() def readProcessOutput(self): self.data = str(self.procThreadDNS.readAllStandardOutput()) self.DnsReq.emit(self.data) def start(self): self.setIptables(self.APmode,option='A') self.procThreadDNS = QProcess(self) self.procThreadDNS.setProcessChannelMode(QProcess.MergedChannels) QObject.connect(self.procThreadDNS, SIGNAL('readyReadStandardOutput()'), self, SLOT('readProcessOutput()')) self.procThreadDNS.start('python',['core/packets/dnsspoofNF.py','-r',self.redirect, '-d',','.join(self.domains)]) def setIptables(self,APMode=True, option=str()): if APMode: system('iptables -{} INPUT -i {} -p udp --dport 53 -s {} -j ACCEPT'.format(option,self.interface,self.redirect)) system('iptables -{} INPUT -i {} -p udp --dport 53 -j DROP'.format(option,self.interface)) system('iptables -t nat -{} PREROUTING -p udp --dport 53 -j NFQUEUE'.format(option)) def stop(self): self.setIptables(self.APmode,option='D') if hasattr(self,'procThreadDNS'): self.procThreadDNS.terminate() self.procThreadDNS.waitForFinished() self.procThreadDNS.kill()
class ProcessThread(QObject): _ProcssOutput = pyqtSignal(object) def __init__( self, cmd, ): QObject.__init__(self) self.cmd = cmd def getNameThread(self): return '[New Thread {} ({})]'.format(self.procThread.pid(), self.objectName()) @pyqtSlot() def readProcessOutput(self): self.data = str(self.procThread.readAllStandardOutput()) self._ProcssOutput.emit(self.data) def start(self): self.procThread = QProcess(self) self.procThread.setProcessChannelMode(QProcess.MergedChannels) QObject.connect(self.procThread, SIGNAL('readyReadStandardOutput()'), self, SLOT('readProcessOutput()')) self.procThread.start(self.cmd.keys()[0], self.cmd[self.cmd.keys()[0]]) print '[New Thread {} ({})]'.format(self.procThread.pid(), self.objectName()) def stop(self): print 'Thread::[{}] successfully stopped.'.format(self.objectName()) if hasattr(self, 'procThread'): self.procThread.terminate() self.procThread.waitForFinished() self.procThread.kill()
class ThreadDNSspoofNF(QObject): DnsReq = pyqtSignal(object) def __init__(self,domains,interface,redirect,APmode=True,parent=None): super(ThreadDNSspoofNF, self).__init__(parent) self.domains = domains self.interface = interface self.redirect = redirect self.APmode = APmode self.desc = 'DNS spoof Module::NetFilter' @pyqtSlot() def readProcessOutput(self): self.data = str(self.procThreadDNS.readAllStandardOutput()) self.DnsReq.emit(self.data) def start(self): self.setIptables(self.APmode,option='A') self.procThreadDNS = QProcess(self) self.procThreadDNS.setProcessChannelMode(QProcess.MergedChannels) QObject.connect(self.procThreadDNS, SIGNAL('readyReadStandardOutput()'), self, SLOT('readProcessOutput()')) self.procThreadDNS.start('python',['Core/packets/dnsspoofNF.py','-r',self.redirect, '-d',','.join(self.domains)]) def setIptables(self,APMode=True, option=str()): if APMode: system('iptables -{} INPUT -i {} -p udp --dport 53 -s {} -j ACCEPT'.format(option,self.interface,self.redirect)) system('iptables -{} INPUT -i {} -p udp --dport 53 -j DROP'.format(option,self.interface)) system('iptables -t nat -{} PREROUTING -p udp --dport 53 -j NFQUEUE'.format(option)) def stop(self): self.setIptables(self.APmode,option='D') if hasattr(self,'procThreadDNS'): self.procThreadDNS.terminate() self.procThreadDNS.waitForFinished() self.procThreadDNS.kill()
class ThreadLogger(QObject): def __init__(self, logger_path=str): QObject.__init__(self) self.logger_path = logger_path @pyqtSlot() def readProcessOutput(self): try: self.emit( SIGNAL('Activated( QString )'), str(self.procLogger.readAllStandardOutput()).rstrip().split( ' : ')[1]) except Exception: pass def start(self): self.procLogger = QProcess(self) self.procLogger.setProcessChannelMode(QProcess.MergedChannels) QObject.connect(self.procLogger, SIGNAL('readyReadStandardOutput()'), self, SLOT('readProcessOutput()')) self.procLogger.start('tail', ['-f', self.logger_path]) def stop(self): if hasattr(self, 'procLogger'): self.procLogger.terminate() self.procLogger.waitForFinished() self.procLogger.kill()
class ProcessThread(QObject): def __init__(self,cmd,): QObject.__init__(self) self.cmd = cmd def getNameThread(self): return 'Starting Thread:' + self.objectName() @pyqtSlot() def readProcessOutput(self): self.data = str(self.procThread.readAllStandardOutput()) def start(self): print 'Starting Thread:' + self.objectName() self.procThread = QProcess(self) self.procThread.setProcessChannelMode(QProcess.MergedChannels) QObject.connect(self.procThread, SIGNAL('readyReadStandardOutput()'), self, SLOT('readProcessOutput()')) self.procThread.start(self.cmd.keys()[0],self.cmd[self.cmd.keys()[0]]) def stop(self): print 'Stop thread:' + self.objectName() if hasattr(self,'procThread'): self.procThread.terminate() self.procThread.waitForFinished() self.procThread.kill()
class QProcessTransport(Transport): '''A Transport communicating with a child process. Start the process using .start(). Sent data is written to the process' stdin. Data is received from the process's stdout and processed on the Qt mainloop thread. ''' shorthand='qprocess' @classmethod def fromstring(cls, expression): '''qprocess:(<commandline>)''' _, _, expr = expression.partition(':') cmdline, _, _ = paren_partition(expr) return cls(cmdline, sendername=expression) def __init__(self, cmdline, sendername='qprocess'): self.cmdline = cmdline self.sendername = sendername self.leftover = b'' self.process = QProcess() self.process.readyRead.connect(self.on_ready_read) self.process.finished.connect(self.on_finished) def start(self): L().debug('starting: %r'%self.cmdline) self.process.start(self.cmdline) def stop(self, kill=False): if kill: self.process.kill() else: self.process.terminate() self.process.waitForFinished() def send(self, data, receivers=None): if receivers is not None and self.sendername not in receivers: return L().debug('message to child processs: %s'%data) self.process.write(data.decode('utf8')) def on_ready_read(self): data = self.process.readAllStandardOutput().data() errors = self.process.readAllStandardError().data().decode('utf8') if errors: L().error('Error from child process:\n%s' % errors) pdata = data.decode('utf8') if len(pdata) > 100: pdata = pdata[:100] + '...' #if pdata.startswith('{'): L().debug('message from child process: %s'%pdata) self.leftover = self.received( sender=self.sendername, data=self.leftover + data ) def on_finished(self): L().info('Child process exited.')
class PROCESS(QObject): queue_finished = pyqtSignal(int) prog_finished = pyqtSignal(tuple) stoped = pyqtSignal(int, int) # 1: start, 0: finished, 2: error | queue state = pyqtSignal(int, str) def __init__(self, parent=None): QObject.__init__(self, parent) self.process = QProcess() self.process.setProcessChannelMode(QProcess.MergedChannels) self.process.finished.connect(self.emit_finished) self.process.stateChanged.connect(self.emit_state) self.process_type = 0 # 0 process, 1 runnable self.threadpool = QThreadPool() self.worker = Worker() self.worker.signals.state.connect(self.emit_state) self.queue = None def emit_state(self, state): self.state.emit(state, self.prog_name) def emit_finished(self, exitcode, exitstatus): self.prog_finished.emit((self.prog_name, exitcode, exitstatus)) def set_queue(self, queue): self.queue = queue def start_process(self): try: obj = self.queue.get(False) self.prog_name = obj.keys()[0] if callable(obj.values()[0][0]): self.process_type = 1 funct = obj.values()[0][0] args = obj.values()[0][1] self.worker.insert_function(funct, args, self.prog_name) self.threadpool.start(self.worker) else: self.process_type = 0 self.process.start(obj.values()[0][0], obj.values()[0][1]) except Queue.Empty: self.queue_finished.emit(self.queue.name) def force_finished(self): # for process (programs) self.stoped.emit(1, self.queue.name) if self.process_type == 0: self.process.terminate() if not self.process.waitForFinished(1000): self.process.kill() else: if self.threadpool.activeThreadCount(): self.threadpool.clear() self.threadpool.waitForDone() with self.queue.mutex: self.queue.queue.clear() self.stoped.emit(0, self.queue.name)
class WorkThread(QThread): def __init__(self): QThread.__init__(self) self.process = QProcess() self.cmd = None self.process.readyReadStandardOutput.connect(self.readOutput) self.process.readyReadStandardError.connect(self.readErrors) self.process.finished.connect(self.fini) def fini(self,no): self.emit(SIGNAL("fini"),no,self.cmd) def setCmd(self,val): self.cmd = val def kill_process(self): self.process.kill() def close_process(self): self.process.close() def run(self): if(self.process.isOpen()): self.process.close() #print "open" #self.process.kill() self.process.start(self.cmd) else: #print "strgin" self.process.start(self.cmd) self.exec_() self.process.waitForFinished() self.process.kill() #self.procDone.emit(True) def run2(self): if(self.process.isOpen()): self.process.close() #print "open" #self.process.kill() self.process.start(self.cmd) else: #print "strgin" self.process.start(self.cmd) self.exec_() #self.process.kill() def readOutput(self): self.emit(SIGNAL("update"),str(self.process.readAllStandardOutput())) def readErrors(self): self.emit(SIGNAL("update"),str(self.process.readAllStandardError())) def __del__(self): self.wait()
class RunWidget(QPlainTextEdit): def __init__(self): QWidget.__init__(self) self.setReadOnly(True) styles.set_style(self, 'editor') self.setPlainText( 'For the moment NINJA only show output when the Program ends.') self.overlay = Overlay(self) self.overlay.hide() self.proc = QProcess(self) #self.proc.setProcessChannelMode(QProcess.ForwardedChannels) self.connect(self.proc, SIGNAL("readyReadStandardOutput()"), self.refresh_output) self.connect(self.proc, SIGNAL("readyReadStandardError()"), self.refresh_error) self.connect(self.proc, SIGNAL("finished(int, QProcess::ExitStatus)"), self._finish_process) def start_process(self, fileName, pythonPath=False): self.setPlainText('Running: ' + fileName + '\n'\ + 'For the moment NINJA only show output when the Program ends.' + '\n\n') self.moveCursor(QTextCursor.Down) self.moveCursor(QTextCursor.Down) self.moveCursor(QTextCursor.Down) #runner.run_code_from_file(fileName) if not pythonPath: pythonPath = resources.python_path self.proc.start(pythonPath, [fileName]) self.overlay.show() def kill_process(self): self.proc.kill() def refresh_output(self): text = str(self.proc.readAllStandardOutput().data()) self.textCursor().insertText(text) def refresh_error(self): text = str(self.proc.readAllStandardError().data()) self.textCursor().insertText(text) def _finish_process(self): self.overlay.killTimer(self.overlay.timer) self.overlay.hide() def resizeEvent(self, event): self.overlay.resize(event.size()) event.accept()
class ProcessHostapd(QObject): statusAP_connected = pyqtSignal(object) statusAPError = pyqtSignal(object) def __init__(self, cmd, session): QObject.__init__(self) self.cmd = cmd self.session = session self.errorAPDriver = ('AP-DISABLED', 'Failed to initialize interface', 'nl80211 driver initialization failed.', 'errors found in configuration file') def getNameThread(self): return '[New Thread {} ({})]'.format(self.procHostapd.pid(), self.objectName()) @pyqtSlot() def read_OutputCommand(self): self.data = str(self.procHostapd.readAllStandardOutput()) if 'AP-STA-DISCONNECTED' in self.data.rstrip( ) or 'inactivity (timer DEAUTH/REMOVE)' in self.data.rstrip(): self.statusAP_connected.emit(self.data.split()[2]) self.log_hostapd.info(self.data) for error in self.errorAPDriver: if self.data.find(error) != -1: return self.statusAPError.emit(self.data) def start(self): self.makeLogger() self.procHostapd = QProcess(self) self.procHostapd.setProcessChannelMode(QProcess.MergedChannels) QObject.connect(self.procHostapd, SIGNAL('readyReadStandardOutput()'), self, SLOT('read_OutputCommand()')) self.procHostapd.start(self.cmd.keys()[0], self.cmd[self.cmd.keys()[0]]) print '[New Thread {} ({})]'.format(self.procHostapd.pid(), self.objectName()) def makeLogger(self): setup_logger('hostapd', C.LOG_HOSTAPD, self.session) self.log_hostapd = logging.getLogger('hostapd') def stop(self): print 'Thread::[{}] successfully stopped.'.format(self.objectName()) if hasattr(self, 'procHostapd'): QObject.disconnect(self.procHostapd, SIGNAL('readyReadStandardOutput()'), self, SLOT('read_OutputCommand()')) self.procHostapd.terminate() self.procHostapd.waitForFinished() self.procHostapd.kill()
def runProcess(self, args): self.logDb( u"BEFEHL: '%s'" % ( u"' '".join(args) ) ) currout = "" currerr = "" p = QProcess() p.start( args[0], args[1:] ) i=0 while not p.waitForFinished(500): i += 1 self.alive.setText( self.alive.text()[:-1] + ("-\|/")[i%4] ) app.processEvents() currout = self.processOutput( currout, p.readAllStandardOutput() ) currerr = self.processOutput( currerr, p.readAllStandardError() ) if p.state()<>QProcess.Running: if self.canceled: self.log( u"Prozeß abgebrochen." ) break if self.canceled: self.log( u"Prozeß wird abgebrochen." ) p.kill() currout = self.processOutput( currout, p.readAllStandardOutput() ) if currout and currout!="": self.log( "E %s" % currout ) currerr = self.processOutput( currerr, p.readAllStandardError() ) if currerr and currerr!="": self.log( "E %s" % currerr ) ok = False if p.exitStatus()==QProcess.NormalExit: if p.exitCode()==0: ok = True else: self.log( u"Fehler bei Prozeß: %d" % p.exitCode() ) else: self.log( u"Prozeß abgebrochen: %d" % p.exitCode() ) self.logDb( "EXITCODE: %d" % p.exitCode() ) p.close() return ok
def runProcess(self, args): self.logDb(u"BEFEHL: '%s'" % (u"' '".join(args))) currout = "" currerr = "" p = QProcess() p.start(args[0], args[1:]) i = 0 while not p.waitForFinished(500): i += 1 self.alive.setText(self.alive.text()[:-1] + ("-\|/")[i % 4]) app.processEvents() currout = self.processOutput(currout, p.readAllStandardOutput()) currerr = self.processOutput(currerr, p.readAllStandardError()) if p.state() <> QProcess.Running: if self.canceled: self.log(u"Prozeß abgebrochen.") break if self.canceled: self.log(u"Prozeß wird abgebrochen.") p.kill() currout = self.processOutput(currout, p.readAllStandardOutput()) if currout and currout != "": self.log("E %s" % currout) currerr = self.processOutput(currerr, p.readAllStandardError()) if currerr and currerr != "": self.log("E %s" % currerr) ok = False if p.exitStatus() == QProcess.NormalExit: if p.exitCode() == 0: ok = True else: self.log(u"Fehler bei Prozeß: %d" % p.exitCode()) else: self.log(u"Prozeß abgebrochen: %d" % p.exitCode()) self.logDb("EXITCODE: %d" % p.exitCode()) p.close() return ok
class RunWidget(QPlainTextEdit): def __init__(self): QWidget.__init__(self) self.setReadOnly(True) styles.set_style(self, 'editor') self.setPlainText('For the moment NINJA only show output when the Program ends.') self.overlay = Overlay(self) self.overlay.hide() self.proc = QProcess(self) #self.proc.setProcessChannelMode(QProcess.ForwardedChannels) self.connect(self.proc, SIGNAL("readyReadStandardOutput()"), self.refresh_output) self.connect(self.proc, SIGNAL("readyReadStandardError()"), self.refresh_error) self.connect(self.proc, SIGNAL("finished(int, QProcess::ExitStatus)"), self._finish_process) def start_process(self, fileName, pythonPath=False): self.setPlainText('Running: ' + fileName + '\n'\ + 'For the moment NINJA only show output when the Program ends.' + '\n\n') self.moveCursor(QTextCursor.Down) self.moveCursor(QTextCursor.Down) self.moveCursor(QTextCursor.Down) #runner.run_code_from_file(fileName) if not pythonPath: pythonPath = resources.python_path self.proc.start(pythonPath, [fileName]) self.overlay.show() def kill_process(self): self.proc.kill() def refresh_output(self): text = str(self.proc.readAllStandardOutput().data()) self.textCursor().insertText(text) def refresh_error(self): text = str(self.proc.readAllStandardError().data()) self.textCursor().insertText(text) def _finish_process(self): self.overlay.killTimer(self.overlay.timer) self.overlay.hide() def resizeEvent(self, event): self.overlay.resize(event.size()) event.accept()
class XTerm(QX11EmbedContainer): def __init__(self, parent, xterm_cmd="xterm"): QX11EmbedContainer.__init__(self, parent) self.xterm_cmd = xterm_cmd self.process = QProcess(self) self.connect(self.process, SIGNAL("finished(int, QProcess::ExitStatus)"), self.on_term_close) atexit.register(self.kill) self.show_term() def kill(self): self.process.kill() self.process.waitForFinished() def sizeHint(self): size = QSize(400, 300) return size.expandedTo(QApplication.globalStrut()) def show_term(self): args = [ "-into", str(self.winId()), "-bg", "#000000", # self.palette().color(QPalette.Background).name(), "-fg", "#f0f0f0", # self.palette().color(QPalette.Foreground).name(), # border "-b", "0", "-w", "0", # blink cursor "-bc", '-e', 'tmux', 'new', '-s', 'my_session' ] self.process.start(self.xterm_cmd, args) if self.process.error() == QProcess.FailedToStart: print("xterm not installed") def on_term_close(self, exit_code, exit_status): print("close", exit_code, exit_status) self.close()
class ProcessHostapd(QObject): statusAP_connected = pyqtSignal(object) statusAPError = pyqtSignal(object) def __init__(self,cmd,session): QObject.__init__(self) self.cmd = cmd self.session = session self.errorAPDriver = ('AP-DISABLED', 'Failed to initialize interface', 'nl80211 driver initialization failed.', 'errors found in configuration file') def getNameThread(self): return '[New Thread {} ({})]'.format(self.procHostapd.pid(),self.objectName()) @pyqtSlot() def read_OutputCommand(self): self.data = str(self.procHostapd.readAllStandardOutput()) if 'AP-STA-DISCONNECTED' in self.data.rstrip() or 'inactivity (timer DEAUTH/REMOVE)' in self.data.rstrip(): self.statusAP_connected.emit(self.data.split()[2]) self.log_hostapd.info(self.data) for error in self.errorAPDriver: if self.data.find(error) != -1: return self.statusAPError.emit(self.data) def start(self): self.makeLogger() self.procHostapd = QProcess(self) self.procHostapd.setProcessChannelMode(QProcess.MergedChannels) QObject.connect(self.procHostapd, SIGNAL('readyReadStandardOutput()'), self, SLOT('read_OutputCommand()')); self.procHostapd.start(self.cmd.keys()[0],self.cmd[self.cmd.keys()[0]]) print '[New Thread {} ({})]'.format(self.procHostapd.pid(),self.objectName()) def makeLogger(self): setup_logger('hostapd', './logs/AccessPoint/hostapd.log',self.session) self.log_hostapd = logging.getLogger('hostapd') def stop(self): print 'Thread::[{}] successfully stopped.'.format(self.objectName()) if hasattr(self,'procHostapd'): QObject.disconnect(self.procHostapd, SIGNAL('readyReadStandardOutput()'), self, SLOT('read_OutputCommand()')) self.procHostapd.terminate() self.procHostapd.waitForFinished() self.procHostapd.kill()
class InoProcess(QtCore.QThread): def __init__(self,project,command): QtCore.QThread.__init__(self,project.parent()) self.project=project self.command=command def run(self): self.project.newMessage.emit() self.project.addMessage.emit("# running: "+self.command+"\n") start_time=time.time() self.proc = QProcess(None) self.proc.readyReadStandardError.connect(self.stdErrReady) self.proc.readyReadStandardOutput.connect(self.stdOutReady) self.proc.setWorkingDirectory(self.project.path) commands = self.command.split(' ') args=QStringList() for cmd in commands[1:]: args.append(cmd) self.proc.start(QString(commands[0]), args, mode=QIODevice.ReadOnly) self.proc.waitForFinished() end_time=time.time() if (self.proc.exitCode()==0): self.project.statusChanged.emit("SUCCESS") self.project.addMessage.emit("# \""+self.command+"\" finished in "+str(end_time-start_time)+"sec\n") else: self.project.statusChanged.emit("FAILED") self.project.addErrorMessage.emit("# \""+self.command+"\" finished in "+str(end_time-start_time)+ "sec with status:"+str(self.proc.exitCode())+"\n") def stop(self): if self.proc!=None and self.proc.state()!=QProcess.NotRunning: self.project.addErrorMessage.emit("# Received stop process command\n") self.proc.kill() def stdErrReady(self): #Reading possible errors errors=unicode(self.proc.readAllStandardError().data(),errors='ignore') if (errors!=None and len(errors)>0): self.project.addErrorMessage.emit(QString(errors)) def stdOutReady(self): msg=unicode(self.proc.readAllStandardOutput().data(),errors='ignore') if (msg!=None and len(msg)>0): self.project.addMessage.emit(QString(msg))
class ProcessHostapd(QObject): statusAP_connected = pyqtSignal(object) def __init__(self, cmd, session): QObject.__init__(self) self.cmd = cmd self.session = session def getNameThread(self): return '[New Thread {} ({})]'.format(self.procHostapd.pid(), self.objectName()) @pyqtSlot() def read_OutputCommand(self): self.data = str(self.procHostapd.readAllStandardOutput()) if 'AP-STA-DISCONNECTED' in self.data.rstrip( ) or 'inactivity (timer DEAUTH/REMOVE)' in self.data.rstrip(): self.statusAP_connected.emit(self.data.split()[2]) self.log_hostapd.info(self.data) def start(self): self.makeLogger() self.procHostapd = QProcess(self) self.procHostapd.setProcessChannelMode(QProcess.MergedChannels) QObject.connect(self.procHostapd, SIGNAL('readyReadStandardOutput()'), self, SLOT('read_OutputCommand()')) self.procHostapd.start(self.cmd.keys()[0], self.cmd[self.cmd.keys()[0]]) print '[New Thread {} ({})]'.format(self.procHostapd.pid(), self.objectName()) def makeLogger(self): setup_logger('hostapd', './Logs/AccessPoint/hostapd.log', self.session) self.log_hostapd = logging.getLogger('hostapd') def stop(self): print 'Thread::[{}] successfully stopped.'.format(self.objectName()) if hasattr(self, 'procHostapd'): self.procHostapd.terminate() self.procHostapd.waitForFinished() self.procHostapd.kill()
class ThreadLogger(QObject): def __init__(self,logger_path=str): QObject.__init__(self) self.logger_path = logger_path @pyqtSlot() def readProcessOutput(self): try: self.emit(SIGNAL('Activated( QString )'), str(self.procLogger.readAllStandardOutput()).rstrip().split(' : ')[1]) except Exception: pass def start(self): self.procLogger = QProcess(self) self.procLogger.setProcessChannelMode(QProcess.MergedChannels) QObject.connect(self.procLogger, SIGNAL('readyReadStandardOutput()'), self, SLOT('readProcessOutput()')) self.procLogger.start('tail',['-f',self.logger_path]) def stop(self): if hasattr(self,'procLogger'): self.procLogger.terminate() self.procLogger.waitForFinished() self.procLogger.kill()
class HostWindow(QMainWindow): # signals SIGTERM = pyqtSignal() SIGUSR1 = pyqtSignal() # -------------------------------------------------------------------------------------------------------- def __init__(self): QMainWindow.__init__(self) self.ui = Ui_HostWindow() self.ui.setupUi(self) # ---------------------------------------------------------------------------------------------------- # Internal stuff # Current mod-ui title #self.fCurrentBundle = "" self.fCurrentTitle = "" # Next bundle to load (done by startup arguments) self.fNextBundle = "" # first attempt of auto-start backend doesn't show an error self.fFirstBackendInit = True # need to call session reconnect after connecting the 1st time self.fNeedsSessionReconnect = False # Qt idle timer self.fIdleTimerId = 0 # Qt web frame, used for evaluating javascript self.fWebFrame = None # to be filled with key-value pairs of current settings self.fSavedSettings = {} # List of pedalboards self.fPedalboards = get_all_pedalboards() # List of current-pedalboard presets self.fPresetMenuList = [] # Process that runs the backend self.fProccessBackend = QProcess(self) self.fProccessBackend.setProcessChannelMode(QProcess.MergedChannels) self.fProccessBackend.setReadChannel(QProcess.StandardOutput) self.fStoppingBackend = False # Thread for managing the webserver self.fWebServerThread = WebServerThread(self) # ---------------------------------------------------------------------------------------------------- # Set up GUI self.ui.webview = QWebView(self.ui.swp_webview) self.ui.webview.setMinimumWidth(980) self.ui.swp_webview.layout().addWidget(self.ui.webview) self.ui.webpage = HostWebPage(self) self.ui.webpage.setViewportSize(QSize(980, 600)) self.ui.webview.setPage(self.ui.webpage) self.ui.webinspector = QWebInspector(None) self.ui.webinspector.resize(800, 600) self.ui.webinspector.setPage(self.ui.webpage) self.ui.webinspector.setVisible(False) self.ui.act_file_connect.setEnabled(False) self.ui.act_file_connect.setVisible(False) self.ui.act_file_disconnect.setEnabled(False) self.ui.act_file_disconnect.setVisible(False) self.ui.label_app.setText("MOD Application v%s" % config["version"]) # disable file menu self.ui.act_file_refresh.setEnabled(False) self.ui.act_file_inspect.setEnabled(False) # disable pedalboard menu self.ui.act_pedalboard_new.setEnabled(False) self.ui.act_pedalboard_open.setEnabled(False) self.ui.act_pedalboard_save.setEnabled(False) self.ui.act_pedalboard_save_as.setEnabled(False) self.ui.act_pedalboard_share.setEnabled(False) self.ui.menu_Pedalboard.setEnabled(False) # disable presets menu self.ui.act_presets_new.setEnabled(False) self.ui.act_presets_save.setEnabled(False) self.ui.act_presets_save_as.setEnabled(False) self.ui.menu_Presets.setEnabled(False) # initial stopped state self.slot_backendFinished(-1, -1) # Qt needs this so it properly creates & resizes the webview self.ui.stackedwidget.setCurrentIndex(1) self.ui.stackedwidget.setCurrentIndex(0) # FIXME #self.ui.act_backend_stop.setVisible(False) #self.ui.act_backend_restart.setVisible(False) # ---------------------------------------------------------------------------------------------------- # Set up GUI (special stuff for Mac OS) if MACOS: self.ui.act_file_quit.setMenuRole(QAction.QuitRole) self.ui.act_settings_configure.setMenuRole(QAction.PreferencesRole) self.ui.act_help_about.setMenuRole(QAction.AboutRole) #self.ui.menu_Settings.setTitle("Panels") #self.ui.menu_Help.hide() # ---------------------------------------------------------------------------------------------------- # Load Settings self.loadSettings(True) # ---------------------------------------------------------------------------------------------------- # Connect actions to functions self.SIGUSR1.connect(self.slot_handleSIGUSR1) self.SIGTERM.connect(self.slot_handleSIGTERM) self.fProccessBackend.error.connect(self.slot_backendError) self.fProccessBackend.started.connect(self.slot_backendStarted) self.fProccessBackend.finished.connect(self.slot_backendFinished) self.fProccessBackend.readyRead.connect(self.slot_backendRead) self.fWebServerThread.running.connect(self.slot_webServerRunning) self.fWebServerThread.finished.connect(self.slot_webServerFinished) self.ui.act_file_refresh.triggered.connect(self.slot_fileRefresh) self.ui.act_file_inspect.triggered.connect(self.slot_fileInspect) self.ui.act_settings_configure.triggered.connect(self.slot_configure) self.ui.act_help_about.triggered.connect(self.slot_about) self.ui.act_help_project.triggered.connect(self.slot_showProject) self.ui.act_help_website.triggered.connect(self.slot_showWebsite) self.ui.b_start.clicked.connect(self.slot_backendStart) self.ui.b_configure.clicked.connect(self.slot_configure) self.ui.b_about.clicked.connect(self.slot_about) # force our custom refresh webReloadAction = self.ui.webpage.action(QWebPage.Reload) webReloadAction.triggered.disconnect() webReloadAction.triggered.connect(self.slot_fileRefresh) # ---------------------------------------------------------------------------------------------------- # Final setup self.setProperWindowTitle() SESSION.setupApp(self._pedal_changed_callback) if not "--no-autostart" in sys.argv: QTimer.singleShot(0, self.slot_backendStart) QTimer.singleShot(1, self.fixWebViewSize) def __del__(self): self.stopAndWaitForWebServer() self.stopAndWaitForBackend() def _pedal_changed_callback(self, ok, bundlepath, title): #self.fCurrentBundle = bundlepath self.fCurrentTitle = title or "" #self.updatePresetsMenu() self.setProperWindowTitle() # -------------------------------------------------------------------------------------------------------- # Files (menu actions) @pyqtSlot() def slot_fileRefresh(self): if self.fWebFrame is None: return self.ui.label_progress.setText(self.tr("Refreshing UI...")) self.ui.stackedwidget.setCurrentIndex(0) QTimer.singleShot(0, self.ui.webview.reload) @pyqtSlot() def slot_fileInspect(self): self.ui.webinspector.show() # -------------------------------------------------------------------------------------------------------- # Settings (menu actions) @pyqtSlot() def slot_configure(self): dialog = SettingsWindow(self, True) if not dialog.exec_(): return self.loadSettings(False) # -------------------------------------------------------------------------------------------------------- # About (menu actions) @pyqtSlot() def slot_about(self): QMessageBox.about( self, self.tr("About"), self.tr(""" <b>MOD Desktop Application</b><br/> <br/> A software to have the complete MOD environment running in your desktop.<br/> (C) 2015-2016 - The MOD Team<br/> <br/> Publications, products, content or services referenced herein or on the website are the exclusive trademarks or servicemarks of MOD.<br/> Other product and company names mentioned in the site may be the trademarks of their respective owners.<br/> <br/> All software is available under the <a href="https://www.gnu.org/licenses/gpl-2.0.html">GPL license</a>.<br/> """)) @pyqtSlot() def slot_showProject(self): QDesktopServices.openUrl(QUrl("https://github.com/moddevices/mod-app")) @pyqtSlot() def slot_showWebsite(self): QDesktopServices.openUrl(QUrl("http://moddevices.com/")) # -------------------------------------------------------------------------------------------------------- # Backend (menu actions) @pyqtSlot() def slot_backendInformation(self): table = """ <table><tr> <td> MOD-UI port: <td></td> %s </td> </tr></table> """ % (config["port"], ) QMessageBox.information(self, self.tr("information"), table) @pyqtSlot() def slot_backendStart(self): if self.fProccessBackend.state() != QProcess.NotRunning: print("slot_backendStart ignored") return print("slot_backendStart in progress...") hostPath = self.fSavedSettings[MOD_KEY_HOST_PATH] if hostPath.endswith("ingen"): hostPath = MOD_DEFAULT_HOST_PATH hostArgs = ["-p", "5555", "-f", "5556"] if self.fSavedSettings[MOD_KEY_HOST_VERBOSE]: hostArgs.append("-v") else: hostArgs.append("-n") self.fProccessBackend.start(hostPath, hostArgs) @pyqtSlot() def slot_backendStop(self): #if self.fPluginCount > 0: #if not forced: #ask = QMessageBox.question(self, self.tr("Warning"), self.tr("There are still some plugins loaded, you need to remove them to stop the engine.\n" #"Do you want to do this now?"), #QMessageBox.Yes | QMessageBox.No, QMessageBox.No) #if ask != QMessageBox.Yes: #return #self.removeAllPlugins() #self.host.set_engine_about_to_close() #self.host.remove_all_plugins() # testing red color for server stopped self.ui.webview.blockSignals(True) self.ui.webview.setHtml("<html><body bgcolor='green'></body></html>") self.ui.webview.blockSignals(False) self.stopAndWaitForWebServer() self.stopAndWaitForBackend() @pyqtSlot() def slot_backendRestart(self): self.slot_backendStop() self.slot_backendStart() # -------------------------------------------------------------------------------------------------------- @pyqtSlot() def slot_backendStarted(self): self.ui.act_backend_start.setEnabled(False) self.ui.act_backend_stop.setEnabled(True) self.ui.act_backend_restart.setEnabled(True) self.ui.w_buttons.setEnabled(False) self.ui.label_progress.setText(self.tr("Loading backend...")) @pyqtSlot(int, QProcess.ExitStatus) def slot_backendFinished(self, exitCode, exitStatus): self.fFirstBackendInit = False self.fStoppingBackend = False self.ui.act_backend_start.setEnabled(True) self.ui.act_backend_stop.setEnabled(False) self.ui.act_backend_restart.setEnabled(False) self.ui.w_buttons.setEnabled(True) self.ui.label_progress.setText("") self.ui.stackedwidget.setCurrentIndex(0) # stop webserver self.stopAndWaitForWebServer() @pyqtSlot(QProcess.ProcessError) def slot_backendError(self, error): firstBackendInit = self.fFirstBackendInit self.fFirstBackendInit = False # stop webserver self.stopAndWaitForWebServer() # crashed while stopping, ignore if error == QProcess.Crashed and self.fStoppingBackend: return errorStr = self.tr("Could not start host backend.\n" ) + self.getProcessErrorAsString(error) qWarning(errorStr) # don't show error if this is the first time starting the host or using live-iso if firstBackendInit: return # show the error message QMessageBox.critical(self, self.tr("Error"), errorStr) @pyqtSlot() def slot_backendRead(self): #if self.fProccessBackend.state() != QProcess.Running: #return for line in str( self.fProccessBackend.readAllStandardOutput().trimmed(), encoding="utf-8", errors="ignore").strip().split("\n"): line = line.replace("\x1b[0m", "").replace("\x1b[0;31m", "").replace("\x1b[0;33m", "").strip() if not line: continue if self.fSavedSettings[MOD_KEY_HOST_VERBOSE]: print("BACKEND:", line) if line == "mod-host ready!" or line == "mod-host is running.": QTimer.singleShot(0, self.slot_backendStartPhase2) #elif "Listening on socket " in line: #QTimer.singleShot(1000, self.slot_ingenStarted) ##elif "Activated Jack client " in line: ##QTimer.singleShot(1000, self.fWebServerThread.start) #elif "Failed to create UNIX socket" in line or "Could not activate Jack client" in line: ## need to wait for ingen to create sockets so it can delete them on termination #QTimer.singleShot(1000, self.slot_ingenStartError) @pyqtSlot() def slot_backendStartPhase2(self): if self.fProccessBackend.state() == QProcess.NotRunning: return if not self.fNeedsSessionReconnect: # we'll need it for next time self.fNeedsSessionReconnect = True else: # we need it now SESSION.reconnectApp() self.fWebServerThread.start() @pyqtSlot() def slot_backendStartError(self): self.stopAndWaitForBackend() self.slot_backendError(-2) # -------------------------------------------------------------------------------------------------------- # Web Server @pyqtSlot() def slot_webServerRunning(self): self.ui.webview.loadStarted.connect(self.slot_webviewLoadStarted) self.ui.webview.loadProgress.connect(self.slot_webviewLoadProgress) self.ui.webview.loadFinished.connect(self.slot_webviewLoadFinished) print("webserver running with URL:", config["addr"]) self.ui.webview.load(QUrl(config["addr"])) @pyqtSlot() def slot_webServerFinished(self): try: self.ui.webview.loadStarted.disconnect( self.slot_webviewLoadStarted) self.ui.webview.loadProgress.disconnect( self.slot_webviewLoadProgress) self.ui.webview.loadFinished.disconnect( self.slot_webviewLoadFinished) except: pass print("webserver finished") # testing red color for server finished self.ui.webview.blockSignals(True) self.ui.webview.setHtml("<html><body bgcolor='red'></body></html>") self.ui.webview.blockSignals(False) # -------------------------------------------------------------------------------------------------------- # Web View @pyqtSlot() def slot_webviewLoadStarted(self): self.ui.label_progress.setText(self.tr("Loading UI...")) print("load started") @pyqtSlot(int) def slot_webviewLoadProgress(self, progress): self.ui.label_progress.setText(self.tr("Loading UI... %i%%" % progress)) @pyqtSlot(bool) def slot_webviewLoadFinished(self, ok): self.ui.webview.loadStarted.disconnect(self.slot_webviewLoadStarted) self.ui.webview.loadProgress.disconnect(self.slot_webviewLoadProgress) self.ui.webview.loadFinished.disconnect(self.slot_webviewLoadFinished) if ok: # message self.ui.label_progress.setText(self.tr("Loading UI... finished!")) # enable file menu self.ui.act_file_refresh.setEnabled(True) self.ui.act_file_inspect.setEnabled(True) # for js evaulation self.fWebFrame = self.ui.webpage.currentFrame() # postpone app stuff QTimer.singleShot(100, self.slot_webviewPostFinished) else: # message self.ui.label_progress.setText(self.tr("Loading UI... failed!")) # disable file menu self.ui.act_file_refresh.setEnabled(False) self.ui.act_file_inspect.setEnabled(False) # disable pedalboard menu self.ui.act_pedalboard_new.setEnabled(False) self.ui.act_pedalboard_open.setEnabled(False) self.ui.act_pedalboard_save.setEnabled(False) self.ui.act_pedalboard_save_as.setEnabled(False) self.ui.act_pedalboard_share.setEnabled(False) self.ui.menu_Pedalboard.setEnabled(False) # stop js evaulation self.fWebFrame = None # stop backend&server self.stopAndWaitForWebServer() self.stopAndWaitForBackend() print("load finished") @pyqtSlot() def slot_webviewPostFinished(self): if self.fNextBundle: bundle = self.fNextBundle self.fNextBundle = "" self.fWebFrame.evaluateJavaScript( "desktop.loadPedalboard(\"%s\")" % bundle) QTimer.singleShot(0, self.slot_webviewPostFinished2) @pyqtSlot() def slot_webviewPostFinished2(self): self.ui.stackedwidget.setCurrentIndex(1) # -------------------------------------------------------------------------------------------------------- # Settings def saveSettings(self): settings = QSettings() settings.setValue("Geometry", self.saveGeometry()) def loadSettings(self, firstTime): qsettings = QSettings() websettings = self.ui.webview.settings() self.fSavedSettings = { # Main MOD_KEY_MAIN_PROJECT_FOLDER: qsettings.value(MOD_KEY_MAIN_PROJECT_FOLDER, MOD_DEFAULT_MAIN_PROJECT_FOLDER, type=str), MOD_KEY_MAIN_REFRESH_INTERVAL: qsettings.value(MOD_KEY_MAIN_REFRESH_INTERVAL, MOD_DEFAULT_MAIN_REFRESH_INTERVAL, type=int), # Host MOD_KEY_HOST_VERBOSE: qsettings.value(MOD_KEY_HOST_VERBOSE, MOD_DEFAULT_HOST_VERBOSE, type=bool), MOD_KEY_HOST_PATH: qsettings.value(MOD_KEY_HOST_PATH, MOD_DEFAULT_HOST_PATH, type=str), # WebView MOD_KEY_WEBVIEW_INSPECTOR: qsettings.value(MOD_KEY_WEBVIEW_INSPECTOR, MOD_DEFAULT_WEBVIEW_INSPECTOR, type=bool), MOD_KEY_WEBVIEW_VERBOSE: qsettings.value(MOD_KEY_WEBVIEW_VERBOSE, MOD_DEFAULT_WEBVIEW_VERBOSE, type=bool), MOD_KEY_WEBVIEW_SHOW_INSPECTOR: qsettings.value(MOD_KEY_WEBVIEW_SHOW_INSPECTOR, MOD_DEFAULT_WEBVIEW_SHOW_INSPECTOR, type=bool) } inspectorEnabled = self.fSavedSettings[MOD_KEY_WEBVIEW_INSPECTOR] websettings.setAttribute(QWebSettings.DeveloperExtrasEnabled, inspectorEnabled) if firstTime: if qsettings.contains("Geometry"): self.restoreGeometry(qsettings.value("Geometry", "")) else: self.setWindowState(self.windowState() | Qt.WindowMaximized) if inspectorEnabled and self.fSavedSettings[ MOD_KEY_WEBVIEW_SHOW_INSPECTOR]: QTimer.singleShot(1000, self.ui.webinspector.show) self.ui.act_file_inspect.setVisible(inspectorEnabled) if self.fIdleTimerId != 0: self.killTimer(self.fIdleTimerId) self.fIdleTimerId = self.startTimer( self.fSavedSettings[MOD_KEY_MAIN_REFRESH_INTERVAL]) # -------------------------------------------------------------------------------------------------------- # Misc @pyqtSlot() def slot_handleSIGUSR1(self): print("Got SIGUSR1 -> Saving project now") self.slot_pedalboardSave() @pyqtSlot() def slot_handleSIGTERM(self): print("Got SIGTERM -> Closing now") self.close() # -------------------------------------------------------------------------------------------------------- # Qt events def closeEvent(self, event): if self.fIdleTimerId != 0: self.killTimer(self.fIdleTimerId) self.fIdleTimerId = 0 self.saveSettings() self.slot_backendStop() QMainWindow.closeEvent(self, event) # Needed in case the web inspector is still alive #self.ui.webinspector.close() QApplication.instance().quit() def timerEvent(self, event): if event.timerId() == self.fIdleTimerId: pass QMainWindow.timerEvent(self, event) def resizeEvent(self, event): QMainWindow.resizeEvent(self, event) self.fixWebViewSize() # -------------------------------------------------------------------------------------------------------- # Internal stuff def getProcessErrorAsString(self, error): if error == -2: return self.tr("Ingen failed to create UNIX socket.") if error == QProcess.FailedToStart: return self.tr("Process failed to start.") if error == QProcess.Crashed: return self.tr("Process crashed.") if error == QProcess.Timedout: return self.tr("Process timed out.") if error == QProcess.WriteError: return self.tr("Process write error.") return self.tr("Unkown error.") def fixWebViewSize(self): if self.ui.stackedwidget.currentIndex() == 1: return size = self.ui.swp_intro.size() self.ui.swp_webview.resize(size) self.ui.webview.resize(size) self.ui.webpage.setViewportSize(size) def stopAndWaitForBackend(self): SESSION.host.close_jack() if self.fProccessBackend.state() == QProcess.NotRunning: return self.fStoppingBackend = True self.fProccessBackend.terminate() if not self.fProccessBackend.waitForFinished(2000): qWarning("Backend failed top stop cleanly, forced kill") self.fProccessBackend.kill() def stopAndWaitForWebServer(self): if not self.fWebServerThread.isRunning(): return if not self.fWebServerThread.stopWait(): qWarning( "WebServer Thread failed top stop cleanly, forced terminate") self.fWebServerThread.terminate() def setProperWindowTitle(self): title = "MOD Application" if self.fCurrentTitle: title += " - %s" % self.fCurrentTitle self.setWindowTitle(title)
class EjecutarWidget(QWidget): _script = '%s -e "bash -c ./%s;echo;echo;echo;echo -n Presione \<Enter\> '\ 'para salir.;read I"' def __init__(self): super(EjecutarWidget, self).__init__() self.compilado = False self.tiempo = 0.0 layoutV = QVBoxLayout(self) layoutV.setContentsMargins(0, 0, 0, 0) layoutV.setSpacing(0) self.output = salida.SalidaCompilador(self) layoutV.addWidget(self.output) self.setLayout(layoutV) # Procesos self.proceso_compilacion = QProcess(self) self.proceso_ejecucion = QProcess(self) # Conexión self.output.ir_a_linea.connect(self._emitir_ir_a_linea) self.proceso_compilacion.readyReadStandardError.connect( self.output.parsear_salida_stderr) self.proceso_compilacion.finished[int, QProcess.ExitStatus].connect( self.ejecucion_terminada) self.proceso_compilacion.error[QProcess.ProcessError].connect( self._error_compilacion) self.proceso_ejecucion.error[QProcess.ProcessError].connect( self._ejecucion_terminada) def _emitir_ir_a_linea(self, linea): self.emit(SIGNAL("ir_a_linea(int)"), linea) def _ejecucion_terminada(self, codigo_error): """ Éste método es ejecutado cuando la ejecución es frenada por el usuario o algún otro error. """ self.output.clear() if codigo_error == 1: error1 = salida.Item(self.tr("El proceso ha sido frenado")) error1.setForeground(Qt.blue) self.output.addItem(error1) else: error = salida.Item(self.tr("Ha ocurrido un error en la ejecución. " "Código de error: %s" % codigo_error)) error.setForeground(Qt.red) self.output.addItem(error) def correr_compilacion(self, nombre_archivo=''): """ Se corre el comando gcc para la compilación """ # Ejecutable directorio = QDir.fromNativeSeparators(nombre_archivo) self.ejecutable = directorio.split('/')[-1].split('.')[0] # Generar el ejecutable en el directorio del código fuente directorio_ejecutable = os.path.dirname(directorio) self.proceso_compilacion.setWorkingDirectory(directorio_ejecutable) self.output.clear() item = salida.Item(self.tr( "Compilando archivo: %s ( %s )" % (directorio.split('/')[-1], nombre_archivo))) self.output.addItem(item) gcc = GCC parametros_gcc = ['-Wall', '-o'] self.proceso_compilacion.start(gcc, parametros_gcc + [self.ejecutable] + [nombre_archivo]) self.proceso_compilacion.waitForFinished() def ejecucion_terminada(self, codigoError, exitStatus): """ Cuando la compilación termina @codigoError toma dos valores: 0 = La compilación ha terminado de forma correcta 1 = La compilación ha fallado """ if exitStatus == QProcess.NormalExit and codigoError == 0: item_ok = salida.Item(self.tr("¡COMPILACIÓN EXITOSA!")) item_ok.setForeground(QColor("#0046cc")) self.output.addItem(item_ok) else: item_error = salida.Item(self.tr("¡LA COMPILACIÓN HA FALLADO!")) item_error.setForeground(Qt.red) self.output.addItem(item_error) count = self.output.count() self.output.setCurrentRow(count - 1, QItemSelectionModel.NoUpdate) def _error_compilacion(self, error): """ Éste método se ejecuta cuando el inicio del proceso de compilación falla. Una de las causas puede ser la ausencia del compilador. """ texto = salida.Item(self.tr("Ha ocurrido un error: quizás el compilador" " no está instalado.")) texto.setForeground(Qt.red) self.output.addItem(texto) def correr_programa(self, archivo): """ Ejecuta el binario generado por el compilador """ #FIXME: Agregar terminal por defecto direc = os.path.dirname(archivo) self.proceso_ejecucion.setWorkingDirectory(direc) if configuracion.LINUX: proceso = 'xterm -T "%s" -e /usr/bin/cb_console_runner "%s"' \ % (self.ejecutable, os.path.join(direc, self.ejecutable)) # Run ! self.proceso_ejecucion.start(proceso) else: #FIXME: Usar QProcess Popen([os.path.join(direc, self.ejecutable)], creationflags=CREATE_NEW_CONSOLE) def compilar_ejecutar(self, archivo): self.correr_compilacion(archivo) self.correr_programa(archivo) def limpiar(self, archivo): """ Elimina el binario generado por la compilación """ if archivo is None: return binario = archivo.split('.')[0] if configuracion.WINDOWS: binario = binario + '.exe' os.remove(binario) def terminar_proceso(self): """ Termina el proceso """ self.proceso_ejecucion.kill()
class PylintWidget(QWidget): """ Pylint widget """ DATAPATH = get_conf_path('.pylint.results') VERSION = '1.0.2' def __init__(self, parent, max_entries=100): QWidget.__init__(self, parent) self.output = None self.error_output = None self.max_entries = max_entries self.data = [self.VERSION] if osp.isfile(self.DATAPATH): try: data = cPickle.load(file(self.DATAPATH)) if data[0] == self.VERSION: self.data = data except EOFError: pass self.filecombo = PythonModulesComboBox(self) if self.data: self.remove_obsolete_items() self.filecombo.addItems(self.get_filenames()) self.start_button = create_toolbutton(self, get_icon('run.png'), translate('Pylint', "Analyze"), tip=translate('Pylint', "Run analysis"), triggered=self.start) self.stop_button = create_toolbutton(self, get_icon('terminate.png'), translate('Pylint', "Stop"), tip=translate('Pylint', "Stop current analysis")) self.connect(self.filecombo, SIGNAL('valid(bool)'), self.start_button.setEnabled) self.connect(self.filecombo, SIGNAL('valid(bool)'), self.show_data) browse_button = create_toolbutton(self, get_icon('fileopen.png'), tip=translate('Pylint', 'Select Python script'), triggered=self.select_file) self.ratelabel = QLabel() self.datelabel = QLabel() self.log_button = create_toolbutton(self, get_icon('log.png'), translate('Pylint', "Output"), tip=translate('Pylint', "Complete Pylint output"), triggered=self.show_log) self.treewidget = ResultsTree(self) hlayout1 = QHBoxLayout() hlayout1.addWidget(self.filecombo) hlayout1.addWidget(browse_button) hlayout1.addWidget(self.start_button) hlayout1.addWidget(self.stop_button) hlayout2 = QHBoxLayout() hlayout2.addWidget(self.ratelabel) hlayout2.addStretch() hlayout2.addWidget(self.datelabel) hlayout2.addStretch() hlayout2.addWidget(self.log_button) layout = QVBoxLayout() layout.addLayout(hlayout1) layout.addLayout(hlayout2) layout.addWidget(self.treewidget) self.setLayout(layout) self.process = None self.set_running_state(False) if not is_pylint_installed(): for widget in (self.treewidget, self.filecombo, self.start_button, self.stop_button): widget.setDisabled(True) text = translate('Pylint', 'Please install <b>pylint</b>:') url = 'http://www.logilab.fr' text += ' <a href=%s>%s</a>' % (url, url) self.ratelabel.setText(text) else: self.show_data() def analyze(self, filename): if not is_pylint_installed(): return filename = unicode(filename) # filename is a QString instance self.kill_if_running() index, _data = self.get_data(filename) if index is None: self.filecombo.addItem(filename) self.filecombo.setCurrentIndex(self.filecombo.count()-1) else: self.filecombo.setCurrentIndex(index) self.filecombo.selected() if self.filecombo.is_valid(): self.start() def select_file(self): self.emit(SIGNAL('redirect_stdio(bool)'), False) filename = QFileDialog.getOpenFileName(self, translate('Pylint', "Select Python script"), os.getcwdu(), translate('Pylint', "Python scripts")+" (*.py ; *.pyw)") self.emit(SIGNAL('redirect_stdio(bool)'), False) if filename: self.analyze(filename) def remove_obsolete_items(self): """Removing obsolete items""" self.data = [self.VERSION] + \ [(filename, data) for filename, data in self.data[1:] if is_module_or_package(filename)] def get_filenames(self): return [filename for filename, _data in self.data[1:]] def get_data(self, filename): filename = osp.abspath(filename) for index, (fname, data) in enumerate(self.data[1:]): if fname == filename: return index, data else: return None, None def set_data(self, filename, data): filename = osp.abspath(filename) index, _data = self.get_data(filename) if index is not None: self.data.pop(index) self.data.append( (filename, data) ) self.save() def set_max_entries(self, max_entries): self.max_entries = max_entries self.save() def save(self): while len(self.data) > self.max_entries+1: self.data.pop(1) cPickle.dump(self.data, file(self.DATAPATH, 'w')) def show_log(self): if self.output: TextEditor(self.output, title=translate('Pylint', "Pylint output"), readonly=True, size=(700, 500)).exec_() def start(self): filename = unicode(self.filecombo.currentText()) self.process = QProcess(self) self.process.setProcessChannelMode(QProcess.SeparateChannels) self.process.setWorkingDirectory(osp.dirname(filename)) self.connect(self.process, SIGNAL("readyReadStandardOutput()"), self.read_output) self.connect(self.process, SIGNAL("readyReadStandardError()"), lambda: self.read_output(error=True)) self.connect(self.process, SIGNAL("finished(int,QProcess::ExitStatus)"), self.finished) self.connect(self.stop_button, SIGNAL("clicked()"), self.process.kill) self.output = '' self.error_output = '' p_args = [osp.basename(filename)] self.process.start(PYLINT_PATH, p_args) running = self.process.waitForStarted() self.set_running_state(running) if not running: QMessageBox.critical(self, translate('Pylint', "Error"), translate('Pylint', "Process failed to start")) def set_running_state(self, state=True): self.start_button.setEnabled(not state) self.stop_button.setEnabled(state) def read_output(self, error=False): if error: self.process.setReadChannel(QProcess.StandardError) else: self.process.setReadChannel(QProcess.StandardOutput) bytes = QByteArray() while self.process.bytesAvailable(): if error: bytes += self.process.readAllStandardError() else: bytes += self.process.readAllStandardOutput() text = unicode( QString.fromLocal8Bit(bytes.data()) ) if error: self.error_output += text else: self.output += text def finished(self): self.set_running_state(False) if not self.output: return # Convention, Refactor, Warning, Error results = {'C:': [], 'R:': [], 'W:': [], 'E:': []} txt_module = '************* Module ' module = '' # Should not be needed - just in case something goes wrong for line in self.output.splitlines(): if line.startswith(txt_module): # New module module = line[len(txt_module):] continue for prefix in results: if line.startswith(prefix): break else: continue i1 = line.find(':') if i1 == -1: continue i2 = line.find(':', i1+1) if i2 == -1: continue line_nb = line[i1+1:i2].strip() if not line_nb: continue line_nb = int(line_nb) message = line[i2+1:] item = (module, line_nb, message) results[line[:i1+1]].append(item) # Rate rate = None txt_rate = 'Your code has been rated at ' i_rate = self.output.find(txt_rate) if i_rate > 0: i_rate_end = self.output.find('/10', i_rate) if i_rate_end > 0: rate = self.output[i_rate+len(txt_rate):i_rate_end] # Previous run previous = '' if rate is not None: txt_prun = 'previous run: ' i_prun = self.output.find(txt_prun, i_rate_end) if i_prun > 0: i_prun_end = self.output.find('/10', i_prun) previous = self.output[i_prun+len(txt_prun):i_prun_end] filename = unicode(self.filecombo.currentText()) self.set_data(filename, (time.localtime(), rate, previous, results)) self.output = self.error_output + self.output self.show_data(justanalyzed=True) def kill_if_running(self): if self.process is not None: if self.process.state() == QProcess.Running: self.process.kill() self.process.waitForFinished() def show_data(self, justanalyzed=False): if not justanalyzed: self.output = None self.log_button.setEnabled(self.output is not None \ and len(self.output) > 0) self.kill_if_running() filename = unicode(self.filecombo.currentText()) if not filename: return _index, data = self.get_data(filename) if data is None: text = translate('Pylint', 'Source code has not been rated yet.') self.treewidget.clear() date_text = '' else: datetime, rate, previous_rate, results = data if rate is None: text = translate('Pylint', 'Analysis did not succeed ' '(see output for more details).') self.treewidget.clear() date_text = '' else: text_style = "<span style=\'color: #444444\'><b>%s </b></span>" rate_style = "<span style=\'color: %s\'><b>%s</b></span>" prevrate_style = "<span style=\'color: #666666\'>%s</span>" color = "#FF0000" if float(rate) > 5.: color = "#22AA22" elif float(rate) > 3.: color = "#EE5500" text = translate('Pylint', 'Global evaluation:') text = (text_style % text)+(rate_style % (color, ('%s/10' % rate))) if previous_rate: text_prun = translate('Pylint', 'previous run:') text_prun = ' (%s %s/10)' % (text_prun, previous_rate) text += prevrate_style % text_prun self.treewidget.set_results(filename, results) date_text = text_style % time.strftime("%d %b %Y %H:%M", datetime) self.ratelabel.setText(text) self.datelabel.setText(date_text)
class RunWidget(QWidget): """Widget that show the execution output in the MiscContainer.""" def __init__(self): QWidget.__init__(self) vbox = QVBoxLayout(self) vbox.setSpacing(0) vbox.setContentsMargins(0, 0, 0, 0) self.output = OutputWidget(self) hbox = QHBoxLayout() self.input = QLineEdit() self.lblInput = QLabel(self.tr("Input:")) vbox.addWidget(self.output) hbox.addWidget(self.lblInput) hbox.addWidget(self.input) vbox.addLayout(hbox) #process self.currentProcess = None self.__preScriptExecuted = False self._proc = QProcess(self) self._preExecScriptProc = QProcess(self) self._postExecScriptProc = QProcess(self) self.connect(self._proc, SIGNAL("readyReadStandardOutput()"), self.output._refresh_output) self.connect(self._proc, SIGNAL("readyReadStandardError()"), self.output._refresh_error) self.connect(self._proc, SIGNAL("finished(int, QProcess::ExitStatus)"), self.finish_execution) self.connect(self._proc, SIGNAL("error(QProcess::ProcessError)"), self.process_error) self.connect(self.input, SIGNAL("returnPressed()"), self.insert_input) self.connect(self._preExecScriptProc, SIGNAL("finished(int, QProcess::ExitStatus)"), self.__main_execution) self.connect(self._preExecScriptProc, SIGNAL("readyReadStandardOutput()"), self.output._refresh_output) self.connect(self._preExecScriptProc, SIGNAL("readyReadStandardError()"), self.output._refresh_error) self.connect(self._postExecScriptProc, SIGNAL("finished(int, QProcess::ExitStatus)"), self.__post_execution_message) self.connect(self._postExecScriptProc, SIGNAL("readyReadStandardOutput()"), self.output._refresh_output) self.connect(self._postExecScriptProc, SIGNAL("readyReadStandardError()"), self.output._refresh_error) def process_error(self, error): """Listen to the error signals from the running process.""" self.lblInput.hide() self.input.hide() self._proc.kill() format_ = QTextCharFormat() format_.setAnchor(True) format_.setForeground(Qt.red) if error == 0: self.output.textCursor().insertText(self.tr('Failed to start'), format_) else: self.output.textCursor().insertText( self.tr('Error during execution, QProcess error: %d' % error), format_) def finish_execution(self, exitCode, exitStatus): """Print a message and hide the input line when the execution ends.""" self.lblInput.hide() self.input.hide() format_ = QTextCharFormat() format_.setAnchor(True) self.output.textCursor().insertText('\n\n') if exitStatus == QProcess.NormalExit: format_.setForeground(Qt.green) self.output.textCursor().insertText( self.tr("Execution Successful!"), format_) else: format_.setForeground(Qt.red) self.output.textCursor().insertText( self.tr("Execution Interrupted"), format_) self.output.textCursor().insertText('\n\n') self.__post_execution() def insert_input(self): """Take the user input and send it to the process.""" text = self.input.text() + '\n' self._proc.writeData(text) self.output.textCursor().insertText(text, self.output.plain_format) self.input.setText("") def start_process(self, fileName, pythonPath=False, PYTHONPATH=None, programParams='', preExec='', postExec=''): """Prepare the output widget and start the process.""" self.lblInput.show() self.input.show() self.fileName = fileName self.pythonPath = pythonPath # FIXME, this is python interpreter self.programParams = programParams self.preExec = preExec self.postExec = postExec self.PYTHONPATH = PYTHONPATH self.__pre_execution() def __main_execution(self): """Execute the project.""" self.output.setCurrentCharFormat(self.output.plain_format) message = '' if self.__preScriptExecuted: self.__preScriptExecuted = False message = self.tr( "Pre Execution Script Successfully executed.\n\n") self.output.setPlainText(message + 'Running: %s (%s)\n\n' % (self.fileName, unicode(time.ctime()))) self.output.moveCursor(QTextCursor.Down) self.output.moveCursor(QTextCursor.Down) self.output.moveCursor(QTextCursor.Down) #runner.run_code_from_file(fileName) if not self.pythonPath: self.pythonPath = settings.PYTHON_PATH #change the working directory to the fileName dir file_directory = file_manager.get_folder(self.fileName) self._proc.setWorkingDirectory(file_directory) #force python to unbuffer stdin and stdout options = ['-u'] + settings.EXECUTION_OPTIONS.split() self.currentProcess = self._proc if self.PYTHONPATH: envpaths = [path for path in self.PYTHONPATH.splitlines()] env = QProcessEnvironment() system_environemnt = self._proc.systemEnvironment() for e in system_environemnt: key, value = unicode(e).split('=', 1) env.insert(key, value) for path in envpaths: env.insert('PYTHONPATH', path) self._proc.setProcessEnvironment(env) self._proc.start(self.pythonPath, options + [self.fileName] + [p.strip() for p in self.programParams.split(',') if p]) def __pre_execution(self): """Execute a script before executing the project.""" filePreExec = QFile(self.preExec) if filePreExec.exists() and \ bool(QFile.ExeUser & filePreExec.permissions()): ext = file_manager.get_file_extension(self.preExec) if not self.pythonPath: self.pythonPath = settings.PYTHON_PATH self.currentProcess = self._preExecScriptProc self.__preScriptExecuted = True if ext == 'py': self._preExecScriptProc.start(self.pythonPath, [self.preExec]) else: self._preExecScriptProc.start(self.preExec) else: self.__main_execution() def __post_execution(self): """Execute a script after executing the project.""" filePostExec = QFile(self.postExec) if filePostExec.exists() and \ bool(QFile.ExeUser & filePostExec.permissions()): ext = file_manager.get_file_extension(self.postExec) if not self.pythonPath: self.pythonPath = settings.PYTHON_PATH self.currentProcess = self._postExecScriptProc if ext == 'py': self._postExecScriptProc.start(self.pythonPath, [self.postExec]) else: self._postExecScriptProc.start(self.postExec) def __post_execution_message(self): """Print post execution message.""" self.output.textCursor().insertText('\n\n') format_ = QTextCharFormat() format_.setAnchor(True) format_.setForeground(Qt.green) self.output.textCursor().insertText( self.tr("Post Execution Script Successfully executed."), format_) def kill_process(self): """Kill the running process.""" self._proc.kill()
class RunWidget(QWidget): def __init__(self): QWidget.__init__(self) vbox = QVBoxLayout(self) vbox.setSpacing(0) vbox.setContentsMargins(0, 0, 0, 0) self.output = OutputWidget(self) hbox = QHBoxLayout() self.input = QLineEdit() self.lblInput = QLabel(self.tr("Input:")) vbox.addWidget(self.output) hbox.addWidget(self.lblInput) hbox.addWidget(self.input) vbox.addLayout(hbox) #process self._proc = QProcess(self) self.connect(self._proc, SIGNAL("readyReadStandardOutput()"), self.output._refresh_output) self.connect(self._proc, SIGNAL("readyReadStandardError()"), self.output._refresh_error) self.connect(self._proc, SIGNAL("finished(int, QProcess::ExitStatus)"), self.finish_execution) self.connect(self.input, SIGNAL("returnPressed()"), self.insert_input) def finish_execution(self, exitCode, exitStatus): self.lblInput.hide() self.input.hide() format = QTextCharFormat() format.setAnchor(True) self.output.textCursor().insertText('\n\n') if exitStatus == QProcess.NormalExit: format.setForeground(Qt.green) self.output.textCursor().insertText( self.tr("Execution Successful!"), format) else: format.setForeground(Qt.red) self.output.textCursor().insertText( self.tr("Execution Interrupted"), format) def insert_input(self): text = self.input.text() + '\n' self._proc.writeData(text) self.input.setText("") def start_process(self, fileName, pythonPath=False, programParams=''): self.lblInput.show() self.input.show() self.output.setCurrentCharFormat(self.output.plain_format) self.output.setPlainText('Running: %s (%s)\n\n' % (fileName, unicode(time.ctime()))) self.output.moveCursor(QTextCursor.Down) self.output.moveCursor(QTextCursor.Down) self.output.moveCursor(QTextCursor.Down) #runner.run_code_from_file(fileName) if not pythonPath: pythonPath = settings.PYTHON_PATH #change the working directory to the fileName dir file_directory = file_manager.get_folder(fileName) self._proc.setWorkingDirectory(file_directory) #force python to unbuffer stdin and stdout options = ['-u'] + settings.EXECUTION_OPTIONS.split() self._proc.start(pythonPath, options + [fileName] + \ [p.strip() for p in programParams.split(',') if p]) def kill_process(self): self._proc.kill()
class IPOPProcess(QtCore.QObject): #Signals ipop_started = pyqtSignal() controller_started = pyqtSignal() ipop_stopped = pyqtSignal() controller_stopped = pyqtSignal() started = pyqtSignal() stopped = pyqtSignal() stop_this_inst = pyqtSignal() is_admingvpn = False def __init__(self): super(IPOPProcess, self).__init__() self.ipop_process = QProcess() self.controller_process = QProcess() self.ipop_kill_process = QProcess() self.running = False self.makeConnections() self.heartbeat = QTimer() self.heartbeat.timeout.connect(self.beat) def startIPOP(self): self.ipop_process.setWorkingDirectory(os.environ['WORKING_DIR']) self.ipop_process.start("sudo", ['./script.sh']) self.ipop_process.readyRead.connect(self.ipop_started.emit) self.ipoplogupdater = LogUpdater('ipop.log', 60) def startGVPN(self): self.controller_process.setWorkingDirectory(os.environ['WORKING_DIR']) #self.controller_process.setStandardOutputFile(os.environ['WORKING_DIR'] + 'LOG.txt') self.controller_process.setStandardErrorFile( os.environ['WORKING_DIR'] + 'gvpn.log') if self.is_admingvpn: self.controller_process.start("./admin_gvpn.py", ['-c', 'conff.json']) else: self.controller_process.start("./gvpn_controller.py", ['-c', 'conff.json']) self.controller_process.started.connect(self.controller_started.emit) self.controller_process.started.connect(self.started.emit) self.gvpnlogupdater = LogUpdater('gvpn.log', 60) self.heartbeat.start(HEARTBEAT_CYCLE) def beat(self): try: connect.instance.setStatus(connect.jid, connect.vpnname, 'running') except: return def start(self): self.startIPOP() self.running = True def stop(self): self.stopIPOP() def stopIPOP(self): self.ipop_kill_process.start("sudo", ['pkill', 'ipop-tincan-x86']) del self.ipoplogupdater self.ipop_kill_process.finished.connect(self.ipop_stopped.emit) def stopGVPN(self): self.controller_process.kill() self.controller_stopped.emit() try: del self.gvpnlogupdater except AttributeError: pass # gives out error while restarting IPOP due to changed IP self.stopped.emit() self.running = False self.heartbeat.stop() def setAdminGVPN(self, is_admingvpn=False): self.is_admingvpn = is_admingvpn def makeConnections(self): self.connect(self, SIGNAL("ipop_started()"), self.startGVPN) self.connect(self, SIGNAL("ipop_stopped()"), self.stopGVPN) self.connect(self, SIGNAL("stop_this_inst()"), self.stop)
class GdalToolsBaseDialog(QDialog, Ui_Dialog): def __init__(self, parent, iface, pluginBase, pluginName, pluginCommand): QDialog.__init__(self, parent) self.setAttribute(Qt.WA_DeleteOnClose) self.iface = iface self.process = QProcess(self) Utils.setProcessEnvironment(self.process) self.connect(self.process, SIGNAL("error(QProcess::ProcessError)"), self.processError) self.connect(self.process, SIGNAL("finished(int, QProcess::ExitStatus)"), self.processFinished) self.setupUi(self) self.arguments = [] self.editCmdBtn.setIcon(QIcon(":/icons/edit.png")) self.connect(self.editCmdBtn, SIGNAL("toggled(bool)"), self.editCommand) self.resetCmdBtn.setIcon(QIcon(":/icons/reset.png")) self.connect(self.resetCmdBtn, SIGNAL("clicked()"), self.resetCommand) self.editCommand(False) self.connect(self.buttonBox, SIGNAL("rejected()"), self.reject) self.connect(self.buttonBox, SIGNAL("accepted()"), self.accept) self.connect(self.buttonBox, SIGNAL("helpRequested()"), self.help) self.buttonBox.button(QDialogButtonBox.Ok).setDefault(True) self.plugin = pluginBase self.connect(self.plugin, SIGNAL("valuesChanged(PyQt_PyObject)"), self.refreshArgs) self.pluginLayout.addWidget(self.plugin) self.plugin.setFocus() self.setWindowTitle(pluginName) self.setPluginCommand(pluginCommand) def setPluginCommand(self, cmd): # on Windows replace the .py with .bat extension if platform.system() == "Windows" and cmd[-3:] == ".py": self.command = cmd[:-3] + ".bat" else: self.command = cmd if cmd[-3:] == ".py": self.helpFileName = cmd[:-3] + ".html" else: self.helpFileName = cmd + ".html" def editCommand(self, enabled): if not self.commandIsEnabled(): return self.editCmdBtn.setChecked(enabled) self.resetCmdBtn.setEnabled(enabled) self.textEditCommand.setReadOnly(not enabled) self.controlsWidget.setEnabled(not enabled) self.emit(SIGNAL("refreshArgs()")) def resetCommand(self): if not self.commandIsEditable(): return self.emit(SIGNAL("refreshArgs()")) def commandIsEditable(self): return self.commandIsEnabled() and self.editCmdBtn.isChecked() def setCommandViewerEnabled(self, enable): if not enable: self.editCommand(False) self.commandWidget.setEnabled(enable) def commandIsEnabled(self): return self.commandWidget.isEnabled() def reject(self): if self.process.state() != QProcess.NotRunning: ret = QMessageBox.warning( self, self.tr("Warning"), self. tr("The command is still running. \nDo you want terminate it anyway?" ), QMessageBox.Yes | QMessageBox.No) if ret == QMessageBox.No: return self.disconnect(self.process, SIGNAL("error(QProcess::ProcessError)"), self.processError) self.disconnect(self.process, SIGNAL("finished(int, QProcess::ExitStatus)"), self.processFinished) self.emit(SIGNAL("closeClicked()")) def accept(self): self.emit(SIGNAL("okClicked()")) def help(self): self.emit(SIGNAL("helpClicked()")) def processError(self, error): self.emit(SIGNAL("processError(QProcess::ProcessError)"), error) def processFinished(self, exitCode, status): self.emit(SIGNAL("processFinished(int, QProcess::ExitStatus)"), exitCode, status) # show the online tool documentation in the default browser def onHelp(self): helpPath = Utils.getHelpPath() if helpPath == '': url = QUrl("http://www.gdal.org/" + self.helpFileName) else: url = QUrl.fromLocalFile(helpPath + '/' + self.helpFileName) QDesktopServices.openUrl(url) # called when a value in the plugin widget interface changed def refreshArgs(self, args): self.arguments = [unicode(a) for a in args] if not self.commandIsEnabled(): self.textEditCommand.setPlainText(self.command) else: self.textEditCommand.setPlainText( self.command + " " + Utils.escapeAndJoin(self.arguments)) # enables the OK button def enableRun(self, enable=True): self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(enable) # start the command execution def onRun(self): self.enableRun(False) self.setCursor(Qt.WaitCursor) if not self.commandIsEditable(): #print(self.command+' '+unicode(self.arguments)) self.process.start(self.command, self.arguments, QIODevice.ReadOnly) else: self.process.start(self.textEditCommand.toPlainText(), QIODevice.ReadOnly) # stop the command execution def stop(self): self.enableRun(True) self.setCursor(Qt.ArrowCursor) self.process.kill() # called on closing the dialog, stop the process if it's running def onClosing(self): self.stop() QDialog.reject(self) # called if an error occurs when the command has not already finished, shows the occurred error message def onError(self, error): if error == QProcess.FailedToStart: msg = QCoreApplication.translate( "GdalTools", "The process failed to start. Either the invoked program is missing, or you may have insufficient permissions to invoke the program." ) elif error == QProcess.Crashed: msg = QCoreApplication.translate( "GdalTools", "The process crashed some time after starting successfully.") else: msg = QCoreApplication.translate("GdalTools", "An unknown error occurred.") QErrorMessage(self).showMessage(msg) QApplication.processEvents() # give the user chance to see the message self.stop() # called when the command finished its execution, shows an error message if there's one # and, if required, load the output file in canvas def onFinished(self, exitCode, status): if status == QProcess.CrashExit: self.stop() return if self.command.find("gdalinfo") != -1 and exitCode == 0: self.emit(SIGNAL("finished(bool)"), self.loadCheckBox.isChecked()) self.stop() return # show the error message if there's one, otherwise show the process output message msg = unicode(self.process.readAllStandardError()) if msg == '': outMessages = unicode( self.process.readAllStandardOutput()).splitlines() # make sure to not show the help for m in outMessages: m = string.strip(m) if m == '': continue # TODO fix this #if m.contains( QRegExp( "^(?:[Uu]sage:\\s)?" + QRegExp.escape(self.command) + "\\s" ) ): # if msg.isEmpty(): # msg = self.tr ( "Invalid parameters." ) # break #if m.contains( QRegExp( "0(?:\\.+[1-9]0{1,2})+" ) ): # continue if msg: msg += "\n" msg += m QErrorMessage(self).showMessage(msg.replace("\n", "<br>")) if exitCode == 0: self.emit(SIGNAL("finished(bool)"), self.loadCheckBox.isChecked()) self.stop()
class skkn_tool: def __init__(self, iface): # Save reference to the QGIS interface self.iface = iface # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) # initialize locale locale = QSettings().value('locale/userLocale')[0:2] locale_path = os.path.join( self.plugin_dir, 'i18n', 'skkn_tool_{}.qm'.format(locale)) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) if qVersion() > '4.3.3': QCoreApplication.installTranslator(self.translator) # Create the dialog (after translation) and keep reference self.dlg = skkn_toolDialog() # Declare instance attributes self.actions = [] self.menu = self.tr(u'&SKKN tool') # TODO: We are going to let the user set this up in a future iteration self.toolbar = self.iface.addToolBar(u'skkn_tool') self.toolbar.setObjectName(u'skkn_tool') # data self.dlg.buttonConvert.setEnabled(False) self.dlg.lineData.clear() self.dlg.buttonData.clicked.connect(self.select_data) # database and schema self.dlg.dataBase.setEnabled(False) self.dlg.comboBox_2.currentIndexChanged.connect(self.db_changed) # conversation self.dlg.progressBarData.setMinimum(0) self.dlg.progressBarData.setMaximum(100) self._active = False self.dlg.buttonConvert.clicked.connect(self.convertData) # ukoncenie konverzie self.dlg.buttonKill.clicked.connect(self.stopConvert) self.dlg.buttonKill.setEnabled(False) # about message self.dlg.buttonAbout.clicked.connect(self.showError) self.dlg.buttonClear.clicked.connect(self.clear) # nieco ako Popen, nativne pre Qt self.process = QProcess(self.dlg) self.process.readyRead.connect(self.writeData) # vytvorenie schemy self.dlg.buttonCreate.clicked.connect(self.db_createSchema) # import dat do schemy self.dlg.buttonImport.clicked.connect(self.db_importToSchema) # vymazanie schemy self.dlg.buttonDelete.clicked.connect(self.db_deleteSchema) # test self.dlg.buttonTest.setEnabled(False) self.dlg.buttonTest.clicked.connect(self.testImport) # cancel self.dlg.buttonCancel.clicked.connect(self.closelt) # noinspection PyMethodMayBeStatic def tr(self, message): # noinspection PyTypeChecker,PyArgumentList,PyCallByClass return QCoreApplication.translate('skkn_tool', message) def add_action( self, icon_path, text, callback, enabled_flag=True, add_to_menu=True, add_to_toolbar=True, status_tip=None, whats_this=None, parent=None): icon = QIcon(icon_path) action = QAction(icon, text, parent) action.triggered.connect(callback) action.setEnabled(enabled_flag) if status_tip is not None: action.setStatusTip(status_tip) if whats_this is not None: action.setWhatsThis(whats_this) if add_to_toolbar: self.toolbar.addAction(action) if add_to_menu: self.iface.addPluginToMenu( self.menu, action) self.actions.append(action) return action def initGui(self): """Create the menu entries and toolbar icons inside the QGIS GUI.""" icon_path = ':/plugins/skkn_tool/icons/icon.png' self.add_action( icon_path, text=self.tr(u'SKKN tool'), callback=self.run, parent=self.iface.mainWindow()) def unload(self): """Removes the plugin menu item and icon from QGIS GUI.""" for action in self.actions: self.iface.removePluginMenu( self.tr(u'&SKKN tool'), action) self.iface.removeToolBarIcon(action) # remove the toolbarself.dlg.dataBase.setEnabled(False) del self.toolbar def select_data(self): self.foldername = QFileDialog.getExistingDirectory(self.dlg, "Select data folder with SPI and VGI data","/home") # nahradenie v pripade medzery # self.foldername = re.sub('\s+', '', self.foldername) # self.foldername = os.rename(self.foldername,self.foldername) self.dlg.lineData.setText(self.foldername) self.buttonConvertName() self.dlg.buttonConvert.setEnabled(True) self.dlg.progressBarData.setValue(0) self.clear() def convertData(self): #self.dlg.textEditData.setText(self.foldername) ## spustenie pomocou call a Popen # subprocess.call([os.path.join(self.plugin_dir,'kataster-import','kt-sql'),self.foldername]) # subprocess.Popen([os.path.join(self.plugin_dir,'kataster-import','kt-sql'),self.foldername],shell = True) self.clear() self.process.start(os.path.join(self.plugin_dir,'kataster-import','kt-sql'),[self.foldername]) self.dlg.buttonConvert.setText('Converting ...') self.dlg.buttonKill.setEnabled(True) #funkcia na zapisovanie do GUI okna, vola funkciu insertText def writeData(self): text=str(self.process.readAll()) for line in text.splitlines(): if len(line)==0: continue if not line.startswith('PROGRESS'): self.insertText(line + os.linesep) else: try: self.pvalue=int(line.split(':',1)[1].strip()) except: return self.dlg.progressBarData.setValue(self.pvalue) if self.pvalue==100: self.dlg.buttonConvert.setText('Conversation successfully completed') self.dlg.buttonConvert.setEnabled(False) self.dlg.buttonKill.setEnabled(False) self.dlg.dataBase.setEnabled(True) def insertText(self,text): cursor = self.dlg.textEditData.textCursor() cursor.movePosition(cursor.End) cursor.insertText(text) self.dlg.textEditData.ensureCursorVisible() def stopConvert(self): self.process.kill() self.clear() self.insertText('Conversation interrupted!') self.buttonConvertName() self.dlg.buttonKill.setEnabled(False) self.dlg.progressBarData.setValue(0) def buttonConvertName(self): self.dlg.buttonConvert.setText('Convert all data') def db_changed(self,index): self.dlg.comboBox_3.clear() self.clear() self.dlg.comboBox_3.addItems(self.db_getSchema(index)) # naplnenie comboboxu schemami def db_getSchema(self,index): schemas = [] self.dbconn = self.dbconnections[index] self.dbconn.connect() # zabraniene zobrazeniu schem public a topology for schema in self.dbconn.database().schemas(): if schema.name in ('public','topology'): continue schemas.append(schema.name) return schemas # vytvorenie novej schemy kataster def db_createSchema(self): self.clear() db = self.dlg.comboBox_2.currentText() schema = self.dlg.comboBox_3.currentText() if not schema =='kataster': s = os.path.join(self.plugin_dir,'kataster-import','kt-vytvor_db')+' | '+'psql'+ ' ' +db call(s,shell=True) self.insertText('New schema and related SQL statements have been created successfully.\nTo see schema in combo box refresh database connection!\n\n') else: self.insertText('Schema already exists.') def db_importToSchema(self): self.clear() db = self.dlg.comboBox_2.currentText() s = self.dlg.comboBox_3.currentText() gsql = os.path.join(self.foldername,'sql','graficke_udaje.sql') psql = os.path.join(self.foldername,'sql','popisne_udaje.sql') glog = os.path.join(self.plugin_dir,'kataster-import','info_g.log') plog = os.path.join(self.plugin_dir,'kataster-import','info_p.log') self.goptions = "PGOPTIONS='-c search_path=%s,public' psql %s -f %s 2>%s" % (s,db,gsql,glog) call(self.goptions,shell=True) #self.insertText(os.path.join(self.plugin_dir,'kataster-import') + self.goptions) self.poptions = "PGOPTIONS='-c search_path=%s,public' psql %s -f %s 2>%s" % (s,db,psql,plog) call(self.poptions,shell=True) self.writeLog() self.dlg.buttonTest.setEnabled(True) #funkcia na výpis log do GUI pri tvorbe schemy def writeLog(self): gfilelog = os.path.join(self.plugin_dir,'kataster-import','info_g.log') gtext=open(gfilelog).read() pfilelog = os.path.join(self.plugin_dir,'kataster-import','info_p.log') ptext=open(pfilelog).read() self.insertText('GRAPHICAL DATA LOG:\n**********************\n') self.logText(gfilelog,gtext) self.insertText('\nATTRIBUTIVE DATA LOG:\n************************\n') self.logText(pfilelog,ptext) # vymazanie LOG pre graficke a popisne data os.remove(gfilelog) os.remove(pfilelog) # testovanie prazdneho log suboru def logText(self,file,opfile): if (os.stat(file).st_size==0 or os.stat(file).st_size==1): self.insertText('Import has been successfully finished with no message.') else: for line in opfile.splitlines(): if len(line)==0: continue else: self.insertText(line + os.linesep) def testImport(self): self.clear() db = self.dlg.comboBox_2.currentText() s = self.dlg.comboBox_3.currentText() tsql = os.path.join(self.plugin_dir,'kataster-import','katastertools','sql','test-import.sql') tlog = os.path.join(self.plugin_dir,'kataster-import','info_t.log') self.toptions = "PGOPTIONS='-c search_path=%s,public' psql %s -f %s > %s 2>&1" % (s,db,tsql,tlog) call(self.toptions,shell=True) tfilelog = os.path.join(self.plugin_dir,'kataster-import','info_t.log') ttext=open(tfilelog).read() self.insertText('TEST LOG related to imported data:\n**********************************\n') if (os.stat(tfilelog).st_size==0 or os.stat(tfilelog).st_size==1): self.insertText('Unfortunately, there are no results.') else: for line in ttext.splitlines(): if len(line)==0: continue else: self.insertText(line + os.linesep) # vymazanie TEST LOG os.remove(tfilelog) # vymazanie schemy def db_deleteSchema(self): # vycistenie dialógu so správami self.clear() index = self.dlg.comboBox_3.currentIndex() schema = self.dlg.comboBox_3.currentText() db = self.dbconn.database() # vlozenie chybovej hlasky v pripade problemu try: db.sqlResultModel('DROP schema {0} CASCADE'.format(schema), db) except DbError as e: self.insertText(str(e)) # vymazanie z comboboxu self.dlg.comboBox_3.removeItem(index) def showError(self): QMessageBox.about(None,"About SKKN Plugin","This tool helps users to use Slovak land \ registry data (cadastral data) in exchange formats created by The Geodesy, Cartography and \ Cadastre Authority of Slovak republic, in QGIS. \nIt is only usefull and dedicated for processing \ in Slovak republic for people having access to Cadastre data. \nThere is no reason to use it for \ other purposes.") def clear(self): self.dlg.textEditData.clear() def closelt(self): self.dlg.close() def run(self): # add connections to combobox self.dlg.comboBox_2.clear() dbpluginclass = createDbPlugin('postgis') connection_list = [] self.dbconnections = dbpluginclass.connections() for c in self.dbconnections: connection_list.append(unicode(c.connectionName())) c.connect() self.dlg.comboBox_2.addItems(connection_list) dbpluginclass.typeName() # show the dialog self.dlg.show() # Run the dialog event loop result = self.dlg.exec_() # See if OK was pressed if result: # Do something useful here - delete the line containing pass and # substitute with your code. pass
class EjecutarWidget(QWidget): def __init__(self): super(EjecutarWidget, self).__init__() layoutV = QVBoxLayout(self) layoutV.setContentsMargins(0, 0, 0, 0) layoutV.setSpacing(0) self.output = output_compiler.SalidaCompilador(self) layoutV.addWidget(self.output) self.setLayout(layoutV) # Flag self._compilation_failed = False # Procesos self.build_process = QProcess(self) if not sys.platform.startswith('linux'): self._envgcc = QProcessEnvironment.systemEnvironment() self._envgcc.insert("PATH", ENV_GCC) self.build_process.setProcessEnvironment(self._envgcc) self.execution_process = QProcess(self) # Conexiones self.build_process.readyReadStandardError.connect( self.output.stderr_output) self.build_process.finished[int, QProcess.ExitStatus].connect( self._compilation_finished) self.build_process.error[QProcess.ProcessError].connect( self._compilation_error) self.execution_process.finished[int, QProcess.ExitStatus].connect( self._execution_finished) def _execution_finished(self, code, status): if status == QProcess.CrashExit: text = output_compiler.Item( self.tr("La ejecución se ha interrumpido")) text.setForeground(Qt.red) self.output.addItem(text) else: text = output_compiler.Item(self.tr("Ejecución Exitosa!")) text.setForeground(QColor("#7FE22A")) self.output.addItem(text) def run_compilation(self, sources): """ Se corre el comando gcc para la compilación """ # Ejecutable filename, files = sources if not files: # No es un proyecto files = [filename] path = QDir.fromNativeSeparators(filename) self.exe = os.path.splitext(os.path.basename(path))[0] # Generar el ejecutable en el directorio del código fuente exe_path = os.path.dirname(path) self.build_process.setWorkingDirectory(exe_path) # Se limpia el QListWidget self.output.clear() flags = settings.COMPILER_FLAGS.split() params = ['-o', self.exe] + flags gcc = 'gcc' if not sys.platform.startswith("linux"): gcc = os.path.join(self._environment, 'gcc') item = output_compiler.Item( self.tr(">>> Compilando: {0} ( en directorio {1} )").format( path.split('/')[-1], exe_path)) self.output.addItem(item) self.output.addItem( output_compiler.Item( self.tr(">>> Comando: {0}").format(gcc + ' ' + ' '.join(params) + ' ' + ' '.join(files)))) # Se inicia el proceso self.build_process.start(gcc, params + files) self.build_process.waitForFinished() def _compilation_finished(self, code, status): """ Cuando la compilación termina @codigoError toma dos valores: 0 = La compilación ha terminado de forma correcta 1 = La compilación ha fallado """ if status == QProcess.NormalExit and code == 0: self._compilation_failed = False item_ok = output_compiler.Item( self.tr("¡LA COMPILACIÓN HA SIDO EXITOSA!")) self.output.addItem(item_ok) item_ok.setForeground(QColor("#7FE22A")) else: self._compilation_failed = True item_error = output_compiler.Item( self.tr("¡LA COMPILACIÓN HA FALLADO!")) item_error.setForeground(QColor("#E20000")) self.output.addItem(item_error) syntax_ok = True if code == 0 else False self.emit(SIGNAL("updateSyntaxCheck(bool)"), syntax_ok) code_status = output_compiler.Item( self.tr("Proceso terminado con código: {0}").format(code), italic=True) self.output.addItem(code_status) count = self.output.count() self.output.setCurrentRow(count - 1, QItemSelectionModel.NoUpdate) def _compilation_error(self, error): """ Éste método se ejecuta cuando el inicio del proceso de compilación falla. Una de las causas puede ser la ausencia del compilador. """ text = output_compiler.Item( self.tr("Se ha producido un error. Compilador no encontrado.")) text.setForeground(Qt.red) self.output.addItem(text) def run_program(self, sources): """ Ejecuta el binario generado por el compilador """ path = os.path.dirname(sources[0]) self.execution_process.setWorkingDirectory(path) # Path ejecutable path_exe = os.path.join(path, self.exe) if not settings.IS_LINUX: path_exe += '.exe' # Si no existe se termina el proceso if not self._check_file_exists(path_exe): text = output_compiler.Item( self.tr("El archivo no existe: {0}").format(path_exe)) text.setForeground(Qt.red) self.output.addItem(text) return # Texto en la salida text = output_compiler.Item( self.tr("Ejecutando... {0}").format(path_exe)) self.output.addItem(text) if settings.IS_LINUX: # Run ! terminal = settings.get_setting('terminal') arguments = [ os.path.join(paths.PATH, "tools", "run_script.sh %s" % path_exe) ] self.execution_process.start(terminal, ['-e'] + arguments) else: pauser = os.path.join(paths.PATH, "tools", "pauser", "system_pause.exe") process = [pauser] + ["\"%s\"" % path_exe] Popen(process, creationflags=CREATE_NEW_CONSOLE) def _check_file_exists(self, exe): """ Comprueba si el ejecutable existe """ exists = True if not os.path.exists(exe): exists = False return exists @property def _environment(self): """ Devuelve la variable de entorno gcc """ return self._envgcc.value("PATH", "") def build_and_run(self, archivo): self.run_compilation(archivo) if not self._compilation_failed: self.run_program(archivo) def clean(self, exe): """ Elimina el binario generado por la compilación """ if exe is None: return binary = exe.split('.')[0] if not settings.IS_LINUX: binary += '.exe' os.remove(binary) def kill_process(self): """ Termina el proceso """ self.execution_process.kill()
class skkn_tool: def __init__(self, iface): # Save reference to the QGIS interface self.iface = iface # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) # initialize locale locale = QSettings().value('locale/userLocale')[0:2] locale_path = os.path.join(self.plugin_dir, 'i18n', 'skkn_tool_{}.qm'.format(locale)) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) if qVersion() > '4.3.3': QCoreApplication.installTranslator(self.translator) # Create the dialog (after translation) and keep reference self.dlg = skkn_toolDialog() # Declare instance attributes self.actions = [] self.menu = self.tr(u'&SKKN tool') # TODO: We are going to let the user set this up in a future iteration self.toolbar = self.iface.addToolBar(u'skkn_tool') self.toolbar.setObjectName(u'skkn_tool') # data self.dlg.buttonConvert.setEnabled(False) self.dlg.lineData.clear() self.dlg.buttonData.clicked.connect(self.select_data) # database and schema self.dlg.dataBase.setEnabled(False) self.dlg.comboBox_2.currentIndexChanged.connect(self.db_changed) # conversation self.dlg.progressBarData.setMinimum(0) self.dlg.progressBarData.setMaximum(100) self._active = False self.dlg.buttonConvert.clicked.connect(self.convertData) # ukoncenie konverzie self.dlg.buttonKill.clicked.connect(self.stopConvert) self.dlg.buttonKill.setEnabled(False) # about message self.dlg.buttonAbout.clicked.connect(self.showError) self.dlg.buttonClear.clicked.connect(self.clear) # nieco ako Popen, nativne pre Qt self.process = QProcess(self.dlg) self.process.readyRead.connect(self.writeData) # vytvorenie schemy self.dlg.buttonCreate.clicked.connect(self.db_createSchema) # import dat do schemy self.dlg.buttonImport.clicked.connect(self.db_importToSchema) # vymazanie schemy self.dlg.buttonDelete.clicked.connect(self.db_deleteSchema) # test self.dlg.buttonTest.setEnabled(False) self.dlg.buttonTest.clicked.connect(self.testImport) # cancel self.dlg.buttonCancel.clicked.connect(self.closelt) # noinspection PyMethodMayBeStatic def tr(self, message): # noinspection PyTypeChecker,PyArgumentList,PyCallByClass return QCoreApplication.translate('skkn_tool', message) def add_action(self, icon_path, text, callback, enabled_flag=True, add_to_menu=True, add_to_toolbar=True, status_tip=None, whats_this=None, parent=None): icon = QIcon(icon_path) action = QAction(icon, text, parent) action.triggered.connect(callback) action.setEnabled(enabled_flag) if status_tip is not None: action.setStatusTip(status_tip) if whats_this is not None: action.setWhatsThis(whats_this) if add_to_toolbar: self.toolbar.addAction(action) if add_to_menu: self.iface.addPluginToMenu(self.menu, action) self.actions.append(action) return action def initGui(self): """Create the menu entries and toolbar icons inside the QGIS GUI.""" icon_path = ':/plugins/skkn_tool/icons/icon.png' self.add_action(icon_path, text=self.tr(u'SKKN tool'), callback=self.run, parent=self.iface.mainWindow()) def unload(self): """Removes the plugin menu item and icon from QGIS GUI.""" for action in self.actions: self.iface.removePluginMenu(self.tr(u'&SKKN tool'), action) self.iface.removeToolBarIcon(action) # remove the toolbarself.dlg.dataBase.setEnabled(False) del self.toolbar def select_data(self): self.foldername = QFileDialog.getExistingDirectory( self.dlg, "Select data folder with SPI and VGI data", "/home") # nahradenie v pripade medzery # self.foldername = re.sub('\s+', '', self.foldername) # self.foldername = os.rename(self.foldername,self.foldername) self.dlg.lineData.setText(self.foldername) self.buttonConvertName() self.dlg.buttonConvert.setEnabled(True) self.dlg.progressBarData.setValue(0) self.clear() def convertData(self): #self.dlg.textEditData.setText(self.foldername) ## spustenie pomocou call a Popen # subprocess.call([os.path.join(self.plugin_dir,'kataster-import','kt-sql'),self.foldername]) # subprocess.Popen([os.path.join(self.plugin_dir,'kataster-import','kt-sql'),self.foldername],shell = True) self.clear() self.process.start( os.path.join(self.plugin_dir, 'kataster-import', 'kt-sql'), [self.foldername]) self.dlg.buttonConvert.setText('Converting ...') self.dlg.buttonKill.setEnabled(True) #funkcia na zapisovanie do GUI okna, vola funkciu insertText def writeData(self): text = str(self.process.readAll()) for line in text.splitlines(): if len(line) == 0: continue if not line.startswith('PROGRESS'): self.insertText(line + os.linesep) else: try: self.pvalue = int(line.split(':', 1)[1].strip()) except: return self.dlg.progressBarData.setValue(self.pvalue) if self.pvalue == 100: self.dlg.buttonConvert.setText( 'Conversation successfully completed') self.dlg.buttonConvert.setEnabled(False) self.dlg.buttonKill.setEnabled(False) self.dlg.dataBase.setEnabled(True) def insertText(self, text): cursor = self.dlg.textEditData.textCursor() cursor.movePosition(cursor.End) cursor.insertText(text) self.dlg.textEditData.ensureCursorVisible() def stopConvert(self): self.process.kill() self.clear() self.insertText('Conversation interrupted!') self.buttonConvertName() self.dlg.buttonKill.setEnabled(False) self.dlg.progressBarData.setValue(0) def buttonConvertName(self): self.dlg.buttonConvert.setText('Convert all data') def db_changed(self, index): self.dlg.comboBox_3.clear() self.clear() self.dlg.comboBox_3.addItems(self.db_getSchema(index)) # naplnenie comboboxu schemami def db_getSchema(self, index): schemas = [] self.dbconn = self.dbconnections[index] self.dbconn.connect() # zabraniene zobrazeniu schem public a topology for schema in self.dbconn.database().schemas(): if schema.name in ('public', 'topology'): continue schemas.append(schema.name) return schemas # vytvorenie novej schemy kataster def db_createSchema(self): self.clear() db = self.dlg.comboBox_2.currentText() schema = self.dlg.comboBox_3.currentText() if not schema == 'kataster': s = os.path.join(self.plugin_dir, 'kataster-import', 'kt-vytvor_db') + ' | ' + 'psql' + ' ' + db call(s, shell=True) self.insertText( 'New schema and related SQL statements have been created successfully.\nTo see schema in combo box refresh database connection!\n\n' ) else: self.insertText('Schema already exists.') def db_importToSchema(self): self.clear() db = self.dlg.comboBox_2.currentText() s = self.dlg.comboBox_3.currentText() gsql = os.path.join(self.foldername, 'sql', 'graficke_udaje.sql') psql = os.path.join(self.foldername, 'sql', 'popisne_udaje.sql') glog = os.path.join(self.plugin_dir, 'kataster-import', 'info_g.log') plog = os.path.join(self.plugin_dir, 'kataster-import', 'info_p.log') self.goptions = "PGOPTIONS='-c search_path=%s,public' psql %s -f %s 2>%s" % ( s, db, gsql, glog) call(self.goptions, shell=True) #self.insertText(os.path.join(self.plugin_dir,'kataster-import') + self.goptions) self.poptions = "PGOPTIONS='-c search_path=%s,public' psql %s -f %s 2>%s" % ( s, db, psql, plog) call(self.poptions, shell=True) self.writeLog() self.dlg.buttonTest.setEnabled(True) #funkcia na výpis log do GUI pri tvorbe schemy def writeLog(self): gfilelog = os.path.join(self.plugin_dir, 'kataster-import', 'info_g.log') gtext = open(gfilelog).read() pfilelog = os.path.join(self.plugin_dir, 'kataster-import', 'info_p.log') ptext = open(pfilelog).read() self.insertText('GRAPHICAL DATA LOG:\n**********************\n') self.logText(gfilelog, gtext) self.insertText('\nATTRIBUTIVE DATA LOG:\n************************\n') self.logText(pfilelog, ptext) # vymazanie LOG pre graficke a popisne data os.remove(gfilelog) os.remove(pfilelog) # testovanie prazdneho log suboru def logText(self, file, opfile): if (os.stat(file).st_size == 0 or os.stat(file).st_size == 1): self.insertText( 'Import has been successfully finished with no message.') else: for line in opfile.splitlines(): if len(line) == 0: continue else: self.insertText(line + os.linesep) def testImport(self): self.clear() db = self.dlg.comboBox_2.currentText() s = self.dlg.comboBox_3.currentText() tsql = os.path.join(self.plugin_dir, 'kataster-import', 'katastertools', 'sql', 'test-import.sql') tlog = os.path.join(self.plugin_dir, 'kataster-import', 'info_t.log') self.toptions = "PGOPTIONS='-c search_path=%s,public' psql %s -f %s > %s 2>&1" % ( s, db, tsql, tlog) call(self.toptions, shell=True) tfilelog = os.path.join(self.plugin_dir, 'kataster-import', 'info_t.log') ttext = open(tfilelog).read() self.insertText( 'TEST LOG related to imported data:\n**********************************\n' ) if (os.stat(tfilelog).st_size == 0 or os.stat(tfilelog).st_size == 1): self.insertText('Unfortunately, there are no results.') else: for line in ttext.splitlines(): if len(line) == 0: continue else: self.insertText(line + os.linesep) # vymazanie TEST LOG os.remove(tfilelog) # vymazanie schemy def db_deleteSchema(self): # vycistenie dialógu so správami self.clear() index = self.dlg.comboBox_3.currentIndex() schema = self.dlg.comboBox_3.currentText() db = self.dbconn.database() # vlozenie chybovej hlasky v pripade problemu try: db.sqlResultModel('DROP schema {0} CASCADE'.format(schema), db) except DbError as e: self.insertText(str(e)) # vymazanie z comboboxu self.dlg.comboBox_3.removeItem(index) def showError(self): QMessageBox.about( None, "About SKKN Plugin", "This tool helps users to use Slovak land \ registry data (cadastral data) in exchange formats created by The Geodesy, Cartography and \ Cadastre Authority of Slovak republic, in QGIS. \nIt is only usefull and dedicated for processing \ in Slovak republic for people having access to Cadastre data. \nThere is no reason to use it for \ other purposes.") def clear(self): self.dlg.textEditData.clear() def closelt(self): self.dlg.close() def run(self): # add connections to combobox self.dlg.comboBox_2.clear() dbpluginclass = createDbPlugin('postgis') connection_list = [] self.dbconnections = dbpluginclass.connections() for c in self.dbconnections: connection_list.append(unicode(c.connectionName())) c.connect() self.dlg.comboBox_2.addItems(connection_list) dbpluginclass.typeName() # show the dialog self.dlg.show() # Run the dialog event loop result = self.dlg.exec_() # See if OK was pressed if result: # Do something useful here - delete the line containing pass and # substitute with your code. pass
def _performMonitor(self): """ Protected method implementing the monitoring action. This method populates the statusList member variable with a list of strings giving the status in the first column and the path relative to the project directory starting with the third column. The allowed status flags are: <ul> <li>"A" path was added but not yet comitted</li> <li>"M" path has local changes</li> <li>"O" path was removed</li> <li>"R" path was deleted and then re-added</li> <li>"U" path needs an update</li> <li>"Z" path contains a conflict</li> <li>" " path is back at normal</li> </ul> @return tuple of flag indicating successful operation (boolean) and a status message in case of non successful operation (QString) """ self.shouldUpdate = False process = QProcess() args = QStringList() args.append('status') if not Preferences.getVCS("MonitorLocalStatus"): args.append('--show-updates') args.append('--non-interactive') args.append('.') process.setWorkingDirectory(self.projectDir) process.start('svn', args) procStarted = process.waitForStarted() if procStarted: finished = process.waitForFinished(300000) if finished and process.exitCode() == 0: output = \ unicode(process.readAllStandardOutput(), self.__ioEncoding, 'replace') states = {} for line in output.splitlines(): if self.rx_status1.exactMatch(line): flags = str(self.rx_status1.cap(1)) path = self.rx_status1.cap(3).trimmed() elif self.rx_status2.exactMatch(line): flags = str(self.rx_status2.cap(1)) path = self.rx_status2.cap(5).trimmed() else: continue if flags[0] in "ACDMR" or \ (flags[0] == " " and flags[-1] == "*"): if flags[-1] == "*": status = "U" else: status = flags[0] if status == "C": status = "Z" # give it highest priority elif status == "D": status = "O" if status == "U": self.shouldUpdate = True name = unicode(path) states[name] = status try: if self.reportedStates[name] != status: self.statusList.append("%s %s" % (status, name)) except KeyError: self.statusList.append("%s %s" % (status, name)) for name in self.reportedStates.keys(): if name not in states: self.statusList.append(" %s" % name) self.reportedStates = states return True, \ self.trUtf8("Subversion status checked successfully (using svn)") else: process.kill() process.waitForFinished() return False, QString(process.readAllStandardError()) else: process.kill() process.waitForFinished() return False, self.trUtf8("Could not start the Subversion process.")
class EjecutarWidget(QWidget): def __init__(self): super(EjecutarWidget, self).__init__() layoutV = QVBoxLayout(self) layoutV.setContentsMargins(0, 0, 0, 0) layoutV.setSpacing(0) self.output = output_compiler.SalidaCompilador(self) layoutV.addWidget(self.output) self.setLayout(layoutV) # Flag self._compilation_failed = False # Procesos self.build_process = QProcess(self) if not sys.platform.startswith('linux'): self._envgcc = QProcessEnvironment.systemEnvironment() self._envgcc.insert("PATH", ENV_GCC) self.build_process.setProcessEnvironment(self._envgcc) self.execution_process = QProcess(self) # Conexiones self.build_process.readyReadStandardError.connect( self.output.stderr_output) self.build_process.finished[int, QProcess.ExitStatus].connect( self._compilation_finished) self.build_process.error[QProcess.ProcessError].connect( self._compilation_error) self.execution_process.finished[int, QProcess.ExitStatus].connect( self._execution_finished) def _execution_finished(self, code, status): if status == QProcess.CrashExit: text = output_compiler.Item( self.tr("La ejecución se ha interrumpido")) text.setForeground(Qt.red) self.output.addItem(text) else: text = output_compiler.Item( self.tr("Ejecución Exitosa!")) text.setForeground(QColor("#7FE22A")) self.output.addItem(text) def run_compilation(self, sources): """ Se corre el comando gcc para la compilación """ # Ejecutable filename, files = sources if not files: # No es un proyecto files = [filename] path = QDir.fromNativeSeparators(filename) self.exe = os.path.splitext(os.path.basename(path))[0] # Generar el ejecutable en el directorio del código fuente exe_path = os.path.dirname(path) self.build_process.setWorkingDirectory(exe_path) # Se limpia el QListWidget self.output.clear() flags = settings.COMPILER_FLAGS.split() params = ['-o', self.exe] + flags gcc = 'gcc' if not sys.platform.startswith("linux"): gcc = os.path.join(self._environment, 'gcc') item = output_compiler.Item( self.tr(">>> Compilando: {0} ( en directorio {1} )").format( path.split('/')[-1], exe_path)) self.output.addItem(item) self.output.addItem(output_compiler.Item( self.tr(">>> Comando: {0}").format( gcc + ' ' + ' '.join(params) + ' ' + ' '.join(files)))) # Se inicia el proceso self.build_process.start(gcc, params + files) self.build_process.waitForFinished() def _compilation_finished(self, code, status): """ Cuando la compilación termina @codigoError toma dos valores: 0 = La compilación ha terminado de forma correcta 1 = La compilación ha fallado """ if status == QProcess.NormalExit and code == 0: self._compilation_failed = False item_ok = output_compiler.Item( self.tr("¡LA COMPILACIÓN HA SIDO EXITOSA!")) self.output.addItem(item_ok) item_ok.setForeground(QColor("#7FE22A")) else: self._compilation_failed = True item_error = output_compiler.Item( self.tr("¡LA COMPILACIÓN HA FALLADO!")) item_error.setForeground(QColor("#E20000")) self.output.addItem(item_error) syntax_ok = True if code == 0 else False self.emit(SIGNAL("updateSyntaxCheck(bool)"), syntax_ok) code_status = output_compiler.Item( self.tr("Proceso terminado con código: {0}").format(code), italic=True) self.output.addItem(code_status) count = self.output.count() self.output.setCurrentRow(count - 1, QItemSelectionModel.NoUpdate) def _compilation_error(self, error): """ Éste método se ejecuta cuando el inicio del proceso de compilación falla. Una de las causas puede ser la ausencia del compilador. """ text = output_compiler.Item( self.tr("Se ha producido un error. Compilador no encontrado.")) text.setForeground(Qt.red) self.output.addItem(text) def run_program(self, sources): """ Ejecuta el binario generado por el compilador """ path = os.path.dirname(sources[0]) self.execution_process.setWorkingDirectory(path) # Path ejecutable path_exe = os.path.join(path, self.exe) if not settings.IS_LINUX: path_exe += '.exe' # Si no existe se termina el proceso if not self._check_file_exists(path_exe): text = output_compiler.Item( self.tr("El archivo no existe: {0}").format(path_exe)) text.setForeground(Qt.red) self.output.addItem(text) return # Texto en la salida text = output_compiler.Item( self.tr("Ejecutando... {0}").format(path_exe)) self.output.addItem(text) if settings.IS_LINUX: # Run ! terminal = settings.get_setting('terminal') arguments = [os.path.join(paths.PATH, "tools", "run_script.sh %s" % path_exe)] self.execution_process.start(terminal, ['-e'] + arguments) else: pauser = os.path.join(paths.PATH, "tools", "pauser", "system_pause.exe") process = [pauser] + ["\"%s\"" % path_exe] Popen(process, creationflags=CREATE_NEW_CONSOLE) def _check_file_exists(self, exe): """ Comprueba si el ejecutable existe """ exists = True if not os.path.exists(exe): exists = False return exists @property def _environment(self): """ Devuelve la variable de entorno gcc """ return self._envgcc.value("PATH", "") def build_and_run(self, archivo): self.run_compilation(archivo) if not self._compilation_failed: self.run_program(archivo) def clean(self, exe): """ Elimina el binario generado por la compilación """ if exe is None: return binary = exe.split('.')[0] if not settings.IS_LINUX: binary += '.exe' os.remove(binary) def kill_process(self): """ Termina el proceso """ self.execution_process.kill()
class RunWidget(QWidget): def __init__(self): QWidget.__init__(self) vbox = QVBoxLayout(self) vbox.setSpacing(0) vbox.setContentsMargins(0, 0, 0, 0) self.output = OutputWidget(self) hbox = QHBoxLayout() self.input = QLineEdit() self.lblInput = QLabel(self.tr("Input:")) vbox.addWidget(self.output) hbox.addWidget(self.lblInput) hbox.addWidget(self.input) vbox.addLayout(hbox) #process self._proc = QProcess(self) self.connect(self._proc, SIGNAL("readyReadStandardOutput()"), self.output._refresh_output) self.connect(self._proc, SIGNAL("readyReadStandardError()"), self.output._refresh_error) self.connect(self._proc, SIGNAL("finished(int, QProcess::ExitStatus)"), self.finish_execution) self.connect(self._proc, SIGNAL("error(QProcess::ProcessError)"), self.process_error) self.connect(self.input, SIGNAL("returnPressed()"), self.insert_input) def process_error(self, error): self.lblInput.hide() self.input.hide() self._proc.kill() format = QTextCharFormat() format.setAnchor(True) format.setForeground(Qt.red) if error == 0: self.output.textCursor().insertText(self.tr('Failed to start'), format) else: self.output.textCursor().insertText( self.tr('Error during execution, QProcess error: %d' % error), format) def finish_execution(self, exitCode, exitStatus): self.lblInput.hide() self.input.hide() format = QTextCharFormat() format.setAnchor(True) self.output.textCursor().insertText('\n\n') if exitStatus == QProcess.NormalExit: format.setForeground(Qt.green) self.output.textCursor().insertText( self.tr("Execution Successful!"), format) else: format.setForeground(Qt.red) self.output.textCursor().insertText( self.tr("Execution Interrupted"), format) def insert_input(self): text = self.input.text() + '\n' self._proc.writeData(text) self.input.setText("") def start_process(self, fileName, pythonPath=False, programParams=''): self.lblInput.show() self.input.show() self.output.setCurrentCharFormat(self.output.plain_format) self.output.setPlainText('Running: %s (%s)\n\n' % (fileName, unicode(time.ctime()))) self.output.moveCursor(QTextCursor.Down) self.output.moveCursor(QTextCursor.Down) self.output.moveCursor(QTextCursor.Down) #runner.run_code_from_file(fileName) if not pythonPath: pythonPath = settings.PYTHON_PATH #change the working directory to the fileName dir file_directory = file_manager.get_folder(fileName) self._proc.setWorkingDirectory(file_directory) #force python to unbuffer stdin and stdout options = ['-u'] + settings.EXECUTION_OPTIONS.split() self._proc.start(pythonPath, options + [fileName] + \ [p.strip() for p in programParams.split(',') if p]) def kill_process(self): self._proc.kill()
class Streaming(QObject): """ Class for keeping track of stream chunks and providing methods for handling and visualizing them """ # Define SIGNALS/SLOTS playlistHandled = pyqtSignal(dict) urlReady = pyqtSignal(str, int, str) dataReady = pyqtSignal(str, int) def __init__(self, parent, iface, chunks, playlistUrl, mimeType, encoding): super(Streaming, self).__init__() self.DEBUG = True # Variables from other classes self.parent = parent # For GUI access self.iface = iface self.chunks = chunks self.playlistUrl = playlistUrl self.mimeType = mimeType self.encoding = encoding # Internal variables self.__endTag = "#PLAYLIST-END" self.__exceptionTag = "#EXCEPTION" self.__exceptionUrl = "" self.__exceptionFound = False self.__playlistFinished = False # Did the end tag appeared? self.__bytesInlastReply = 0 # To compare last and current reply sizes self.__loadedChunks = 0 # For keeping track of # of loaded (to local vars) chunks self.__deliveredChunks = 0 # For keeping track of # of loaded (to the map) chunks self.__bFirstChunk = True self.__features = {} # {0:[f0,f1,f2], 1:[f0,f1]} self.__bGeomMulti = False # Is the geometry multi{point|line|polygon} self.__geometryType = "" # Values: "Point","LineString","Polygon","Unknown", "NoGeometry" self.__tmpGeometry = {} # For visualization purposes {chunkId1: rb1, chunkId2: rb2 } self.__memoryLayer = None # The whole merged data # For rasters only self.__legend = self.iface.legendInterface() self.__groupIndex = 0 self.__chunksDir = None self.__virtualFile = "" # Virtual raster file path if isMimeTypeRaster(self.mimeType, True) != None: self.__chunksDir = tempfile.mkdtemp(prefix="tmpChunks") # Other objects self.timer = QTimer() self.timer.setInterval(1 * 1000) # 1 second self.QNAM4Playlist = QNetworkAccessManager() self.QNAM4Chunks = QNetworkAccessManager() self.QNAM4Exception = QNetworkAccessManager() # SIGNAL/SLOT connections self.playlistHandled.connect(self.fetchChunks) self.urlReady.connect(self.fetchResult) self.dataReady.connect(self.loadData) self.timer.timeout.connect(partial(self.fetchPlaylist, self.playlistUrl)) self.QNAM4Playlist.finished.connect(self.handlePlaylist) self.QNAM4Chunks.finished.connect(self.handleChunk) self.QNAM4Exception.finished.connect(self.handleException) #self.QNAM4Playlist = QgsNetworkAccessManager.instance() #theReply2.error.connect(self.handleErrors) # GUI self.parent.progressBar.setRange(0,0) self.parent.lblProcess.setText("Reading output playlist...") def start(self): """ Start fetching """ self.fetchPlaylist(self.playlistUrl) # First call def stop(self): """ Stop fetching """ self.timer.stop() self.QNAM4Playlist.finished.disconnect(self.handlePlaylist) self.QNAM4Chunks.finished.disconnect(self.handleChunk) self.removeTempGeometry(self.__geometryType) if self.DEBUG: print "Stop streaming!" def validateCompletedStream(self): """ Is the stream complete (Did the end tag appeared?) """ #return (self.__loadedChunks >= self.chunks and self.chunks != 0) return self.__playlistFinished def allChunksDelivered(self): """ Are all chunks already loaded into the map? """ return ((self.__loadedChunks == self.__deliveredChunks and self.__playlistFinished) or self.__exceptionFound) def fetchPlaylist(self, playlistLink): url = QUrl(playlistLink) self.QNAM4Playlist.get(QNetworkRequest(url)) # SLOT: handlePlaylist def handlePlaylist(self, reply): """ Parse the chunk URLs and update the loadedChunks counter """ # Check if there is redirection reDir = reply.attribute(QNetworkRequest.RedirectionTargetAttribute).toUrl() if not reDir.isEmpty(): self.fetchPlaylist(reDir.toString()) return # Parse URLs only if there is new data in the reply if reply.bytesAvailable() > self.__bytesInlastReply: if self.DEBUG: print " Parsing the playlist..." startFrom = reply.bytesAvailable() - self.__bytesInlastReply # Delta in bytes self.__bytesInlastReply = reply.bytesAvailable() newURLs = self.parseURLs(reply, startFrom) else: if self.DEBUG: print " No new data in the playlist..." newURLs = {} # Store new URLs if len(newURLs) > 0: self.__loadedChunks += len(newURLs) if self.chunks: self.parent.progressBar.setRange(0,self.chunks) if self.DEBUG: print str(self.__loadedChunks) + " chunks loaded" + ((" out of " + str(self.chunks)) if self.chunks else "") # If not complete, make additional calls if not self.validateCompletedStream(): if not self.timer.isActive(): self.timer.start() if self.DEBUG: print "Timer started..." else: self.timer.stop() self.QNAM4Playlist.finished.disconnect(self.handlePlaylist) if self.DEBUG: print "Playlist finished!" if self.allChunksDelivered(): self.finishLoading() if self.__exceptionFound: self.fetchException() if len(newURLs) > 0: self.playlistHandled.emit(newURLs) # SLOT: fetchChunks def parseURLs(self, reply, startFrom): """ Get a dict of new IDs:URLs from the current playlist (newURLs) """ newURLs = {} # {0:URL0, 1:URL1, ...} count = 0 #Get the delta and start reading it allData = reply.readAll() allData = allData.right(startFrom) # Get rid of old data response = QTextStream(allData, QIODevice.ReadOnly) data = response.readLine() # Parse while (data): data = str(data.split("\n")[0]) if data: if "#" in data: # It's a playlist comment if self.__endTag in data: self.__playlistFinished = True elif self.__exceptionTag in data: if self.DEBUG: print "Exception found!" self.__exceptionFound = True self.__exceptionUrl = data.split(":",1)[1].strip() else: newURLs[count+self.__loadedChunks] = data count += 1 data = response.readLine() return newURLs def fetchChunks(self, newURLs): """ Fetch each url """ for chunkId in newURLs: self.urlReady.emit(self.encoding, chunkId, newURLs[chunkId]) # SLOT: fetchResult def fetchResult(self, encoding, chunkId, fileLink): """ Send the GET request """ url = QUrl(fileLink) theReply2 = self.QNAM4Chunks.get(QNetworkRequest(url)) theReply2.setProperty("chunkId", chunkId ) theReply2.setProperty("encoding", encoding ) def handleErrors(self, error): # TODO connect it if self.DEBUG: print "ERROR!!!", error def fetchException(self): """ Send the GET request for the exception """ url = QUrl(self.__exceptionUrl) theReply3 = self.QNAM4Exception.get(QNetworkRequest(url)) def handleException(self, reply): """ Display the exception """ # Check if there is redirection reDir = reply.attribute(QNetworkRequest.RedirectionTargetAttribute).toUrl() if not reDir.isEmpty(): self.__exceptionUrl = reDir.toString() self.fetchException() return resultXML = reply.readAll().data() self.parent.setStatusLabel('error') self.parent.progressBar.setMinimum(0) self.parent.progressBar.setMaximum(100) self.parent.errorHandler(resultXML) def handleChunk(self, reply): """ Store the file received """ #reply.deleteLater() # Recommended way to delete the reply chunkId = reply.property("chunkId").toInt()[0] encoding = reply.property("encoding").toString() # Check if there is redirection reDir = reply.attribute(QNetworkRequest.RedirectionTargetAttribute).toUrl() if not reDir.isEmpty(): self.urlReady.emit(encoding, chunkId, reDir.toString()) return if self.DEBUG: print "GET chunk", chunkId # Update progressBar if self.chunks: self.parent.progressBar.setValue(self.__deliveredChunks + 1) self.parent.lblProcess.setText("Downloading chunks... ("+str(self.__deliveredChunks + 1)+"/"+str(self.chunks)+")") # Get a unique temporary file name tmpFile = tempfile.NamedTemporaryFile(prefix="base64", suffix=getFileExtension(self.mimeType), dir=self.__chunksDir, delete=False ) # TODO: Check if the file name already exists!!! # Write the data to the temporary file outFile = QFile(tmpFile.name) outFile.open(QIODevice.WriteOnly) outFile.write(reply.readAll()) outFile.close() # Decode? if encoding == "base64": resultFile = decodeBase64(tmpFile.name, self.mimeType, self.__chunksDir) else: resultFile = tmpFile.name # Finally, load the data if self.DEBUG: print "READY to be loaded (", resultFile, ", chunkId:", chunkId, ")" self.dataReady.emit(resultFile, chunkId) # SLOT: loadData def loadData(self, resultFile, chunkId): """ Load data to the map """ if isMimeTypeVector(self.mimeType, True) != None: # Memory layer: geometryTypes = ["Point","LineString","Polygon","Unknown", "NoGeometry"] vlayer = QgsVectorLayer(resultFile, "chunk", "ogr") if self.__bFirstChunk: self.__bFirstChunk = False self.__geometryType = geometryTypes[vlayer.geometryType()] self.__bGeomMulti = vlayer.wkbType() in [4,5,6,11,12,13] self.__memoryLayer = QgsVectorLayer(self.__geometryType,"Streamed data","memory") self.__memoryLayer.dataProvider().addAttributes(vlayer.pendingFields().values()) self.__memoryLayer.updateFieldMap() provider = vlayer.dataProvider() allAttrs = provider.attributeIndexes() vlayer.select(allAttrs) # Visualize temporal geometries during the downloading process # Don't add temporal geometries if last chunk if self.DEBUG: print "Loaded chunkId:",chunkId res = self.__memoryLayer.dataProvider().addFeatures( [feat for feat in vlayer] ) self.__deliveredChunks += 1 if not self.allChunksDelivered(): inFeat = QgsFeature() inGeom = QgsGeometry() self.createTempGeometry(chunkId, self.__geometryType) while provider.nextFeature( inFeat ): inGeom = inFeat.geometry() featList = self.extractAsSingle(self.__geometryType, inGeom) if self.__bGeomMulti else [inGeom] for geom in featList: self.addTempGeometry(chunkId, self.__geometryType, geom) else: self.finishLoading() # Raster data elif isMimeTypeRaster(self.mimeType, True) != None: # We can directly attach the new layer if self.__bFirstChunk: self.__bFirstChunk = False self.__groupIndex = self.__legend.addGroup("Streamed-raster") rLayer = QgsRasterLayer(resultFile, "raster_"+str(chunkId)) bLoaded = QgsMapLayerRegistry.instance().addMapLayer(rLayer) self.stretchRaster(rLayer) self.__legend.moveLayer(rLayer, self.__groupIndex + 1) self.__deliveredChunks += 1 if self.allChunksDelivered(): self.finishLoading() def finishLoading(self): """ Finish the loading process, load the definite assembled layer """ if self.DEBUG: print "DONE!" if not self.__bFirstChunk: if isMimeTypeVector(self.mimeType, True) != None: self.removeTempGeometry(self.__geometryType) QgsMapLayerRegistry.instance().addMapLayer(self.__memoryLayer) elif isMimeTypeRaster(self.mimeType, True) != None: self.parent.lblProcess.setText("All tiles are loaded. Merging them...") # Generate gdal virtual raster # Code adapted from GdalTools (C) 2009 by L. Masini and G. Sucameli (Faunalia) self.process = QProcess(self) self.connect(self.process, SIGNAL("finished(int, QProcess::ExitStatus)"), self.loadVirtualRaster) #self.setProcessEnvironment(self.process) Required in Windows? cmd = "gdalbuildvrt" arguments = [] if platform.system() == "Windows" and cmd[-3:] == ".py": command = cmd[:-3] + ".bat" else: command = cmd tmpFile = tempfile.NamedTemporaryFile(prefix="virtual", suffix=".vrt") self.__virtualFile = tmpFile.name arguments.append(self.__virtualFile) rasters = self.getRasterFiles(self.__chunksDir, getFileExtension(self.mimeType)) for raster in rasters: arguments.append(raster) self.process.start(command, arguments, QIODevice.ReadOnly) if not self.__exceptionFound: self.parent.setStatusLabel('finished') self.parent.progressBar.setRange(0,100) self.parent.progressBar.setValue(100) def createTempGeometry(self, chunkId, geometryType): """ Create rubber bands for rapid visualization of geometries """ if geometryType == "Polygon": self.__tmpGeometry[chunkId] = QgsRubberBand(self.iface.mapCanvas(), True) self.__tmpGeometry[chunkId].setColor( QColor( 0,255,0,255 ) ) self.__tmpGeometry[chunkId].setWidth( 2 ) if self.DEBUG: print "rubberBand created" elif geometryType == "LineString": self.__tmpGeometry[chunkId] = QgsRubberBand(self.iface.mapCanvas(), False) self.__tmpGeometry[chunkId].setColor( QColor( 255,121,48,255 ) ) self.__tmpGeometry[chunkId].setWidth( 3 ) elif geometryType == "Point": # In the case of points, they will be added as vertex objects later self.__tmpGeometry[chunkId] = [] def addTempGeometry(self, chunkId, geometryType, geometry): """ Add geometries as rubber bands or vertex objects """ if geometryType == "Polygon" or geometryType == "LineString": self.__tmpGeometry[chunkId].addGeometry(geometry, None) elif geometryType == "Point": vertex = QgsVertexMarker(self.iface.mapCanvas()) vertex.setCenter(geometry.asPoint()) vertex.setColor(QColor(0,255,0)) vertex.setIconSize(6) vertex.setIconType(QgsVertexMarker.ICON_BOX) # or ICON_CROSS, ICON_X vertex.setPenWidth(3) self.__tmpGeometry[chunkId].append(vertex) def removeTempGeometry(self, geometryType): """ Remove rubber bands or vertex objects from the map """ if geometryType == "Polygon" or geometryType == "LineString": for chunkId in self.__tmpGeometry.keys(): self.iface.mapCanvas().scene().removeItem(self.__tmpGeometry[chunkId]) del self.__tmpGeometry[chunkId] elif geometryType == "Point": for chunkId in self.__tmpGeometry.keys(): if len( self.__tmpGeometry[chunkId] ) > 0: for vertex in self.__tmpGeometry[chunkId]: self.iface.mapCanvas().scene().removeItem(vertex) del vertex def extractAsSingle(self, geometryType, geom): """ Extract multi geometries as single ones. Required because of a QGIS bug regarding multipolygons and rubber bands """ # Code adapted from QGIS fTools plugin, (C) 2008-2011 Carson Farmer multi_geom = QgsGeometry() temp_geom = [] if geometryType == "Point": multi_geom = geom.asMultiPoint() for i in multi_geom: temp_geom.append( QgsGeometry().fromPoint ( i ) ) elif geometryType == "LineString": multi_geom = geom.asMultiPolyline() for i in multi_geom: temp_geom.append( QgsGeometry().fromPolyline( i ) ) elif geometryType == "Polygon": multi_geom = geom.asMultiPolygon() for i in multi_geom: temp_geom.append( QgsGeometry().fromPolygon( i ) ) return temp_geom def loadVirtualRaster(self, exitCode, status): """ Load a virtual raster to QGIS """ if exitCode == 0: self.__legend.setGroupVisible( self.__groupIndex, False ) rLayer = QgsRasterLayer(self.__virtualFile, "virtual") bLoaded = QgsMapLayerRegistry.instance().addMapLayer(rLayer) self.stretchRaster(rLayer) self.process.kill() def stretchRaster(self, raster): raster.setMinimumMaximumUsingLastExtent() raster.setContrastEnhancementAlgorithm(1) raster.triggerRepaint() def setProcessEnvironment(self, process): """ From GdalTools. Set environment variables for running gdalbuildvrt """ envvar_list = { "PATH" : self.getGdalBinPath(), "PYTHONPATH" : self.getGdalPymodPath() } if self.DEBUG: print envvar_list sep = os.pathsep for name, val in envvar_list.iteritems(): if val == None or val == "": continue envval = os.getenv(name) if envval == None or envval == "": envval = str(val) elif val.lower() not in [ x.lower() for x in envval.split( sep ) ]: envval += "%s%s" % (sep, str(val)) else: envval = None if envval != None: os.putenv( name, envval ) if False: # not needed because os.putenv() has already updated the environment for new child processes env = QProcess.systemEnvironment() if env.contains( QRegExp( "^%s=(.*)" % name, Qt.CaseInsensitive ) ): env.replaceInStrings( QRegExp( "^%s=(.*)" % name, Qt.CaseInsensitive ), "%s=\\1%s%s" % (name, sep, gdalPath) ) else: env << "%s=%s" % (name, val) process.setEnvironment( env ) def getRasterFiles(self, dir, extension): rasters = [] for name in glob.glob(dir + '/*' + extension): rasters.append(name) return rasters def getGdalBinPath(self): """ Retrieves GDAL binaries location """ settings = QSettings() return settings.value( "/GdalTools/gdalPath", "" ) def getGdalPymodPath(self): """ Retrieves GDAL python modules location """ settings = QSettings() return settings.value( "/GdalTools/gdalPymodPath", "" )
class BatchFileSync(SyncProvider): def __init__(self, name, project, **kwargs): super(BatchFileSync, self).__init__(name, project) self.cmd = kwargs['cmd'] if self.project: self.rootfolder = os.path.abspath(self.project.folder) else: self.rootfolder = kwargs['rootfolder'] self.project = project self.closeproject = kwargs.get("close_project", False) self.process = QProcess() self.parser = kwargs.get("parser", None) self.parsermodule = None variables = kwargs.get("variables", {}) env = QProcessEnvironment.systemEnvironment() for varname, value in variables.iteritems(): env.insert(varname, str(value)) self.process.setProcessEnvironment(env) self.process.setWorkingDirectory(os.path.dirname(os.path.realpath(self.cmd))) self.process.finished.connect(self.complete) self.process.started.connect(self.syncStarted) self.process.readyReadStandardError.connect(self.error) self.process.readyReadStandardOutput.connect(self.readOutput) self._output = "" self.haserror = False def import_parser_module(self): import imp name = self.parser module = imp.find_module(name, [self.rootfolder]) module = imp.load_module(name, *module) self.parsermodule = module print self.parsermodule def start(self): if not self.parsermodule and self.parser: self.import_parser_module() self._output = "" self.haserror = False self.process.start(self.cmd, []) @property def output(self): return self._output @output.setter def output(self, value): self._output = value def error(self): self.haserror = True def complete(self, error, status): if error > 0 or self.haserror: stderr = self.process.readAllStandardError().data() self.syncError.emit(stderr) else: self.syncComplete.emit() self.syncFinished.emit() def readOutput(self): output = str(self.process.readAll()) ok = True if self.parsermodule: ok, output = self.parsermodule.sync_output(output) if not ok: self.haserror = True self.process.kill() self.syncError.emit(output) else: if output: self.syncMessage.emit(output)
class HostWindow(QMainWindow): # signals SIGTERM = pyqtSignal() SIGUSR1 = pyqtSignal() # -------------------------------------------------------------------------------------------------------- def __init__(self): QMainWindow.__init__(self) self.ui = Ui_HostWindow() self.ui.setupUi(self) # ---------------------------------------------------------------------------------------------------- # Internal stuff # Current mod-ui title #self.fCurrentBundle = "" self.fCurrentTitle = "" # Next bundle to load (done by startup arguments) self.fNextBundle = "" # first attempt of auto-start backend doesn't show an error self.fFirstBackendInit = True # need to call session reconnect after connecting the 1st time self.fNeedsSessionReconnect = False # Qt idle timer self.fIdleTimerId = 0 # Qt web frame, used for evaluating javascript self.fWebFrame = None # to be filled with key-value pairs of current settings self.fSavedSettings = {} # List of pedalboards self.fPedalboards = get_all_pedalboards() # List of current-pedalboard presets self.fPresetMenuList = [] # Process that runs the backend self.fProccessBackend = QProcess(self) self.fProccessBackend.setProcessChannelMode(QProcess.MergedChannels) self.fProccessBackend.setReadChannel(QProcess.StandardOutput) self.fStoppingBackend = False # Thread for managing the webserver self.fWebServerThread = WebServerThread(self) # ---------------------------------------------------------------------------------------------------- # Set up GUI self.ui.webview = QWebView(self.ui.swp_webview) self.ui.webview.setMinimumWidth(980) self.ui.swp_webview.layout().addWidget(self.ui.webview) self.ui.webpage = HostWebPage(self) self.ui.webpage.setViewportSize(QSize(980, 600)) self.ui.webview.setPage(self.ui.webpage) self.ui.webinspector = QWebInspector(None) self.ui.webinspector.resize(800, 600) self.ui.webinspector.setPage(self.ui.webpage) self.ui.webinspector.setVisible(False) self.ui.act_file_connect.setEnabled(False) self.ui.act_file_connect.setVisible(False) self.ui.act_file_disconnect.setEnabled(False) self.ui.act_file_disconnect.setVisible(False) self.ui.label_app.setText("MOD Application v%s" % config["version"]) # disable file menu self.ui.act_file_refresh.setEnabled(False) self.ui.act_file_inspect.setEnabled(False) # disable pedalboard menu self.ui.act_pedalboard_new.setEnabled(False) self.ui.act_pedalboard_open.setEnabled(False) self.ui.act_pedalboard_save.setEnabled(False) self.ui.act_pedalboard_save_as.setEnabled(False) self.ui.act_pedalboard_share.setEnabled(False) self.ui.menu_Pedalboard.setEnabled(False) # disable presets menu self.ui.act_presets_new.setEnabled(False) self.ui.act_presets_save.setEnabled(False) self.ui.act_presets_save_as.setEnabled(False) self.ui.menu_Presets.setEnabled(False) # initial stopped state self.slot_backendFinished(-1, -1) # Qt needs this so it properly creates & resizes the webview self.ui.stackedwidget.setCurrentIndex(1) self.ui.stackedwidget.setCurrentIndex(0) # FIXME #self.ui.act_backend_stop.setVisible(False) #self.ui.act_backend_restart.setVisible(False) # ---------------------------------------------------------------------------------------------------- # Set up GUI (special stuff for Mac OS) if MACOS: self.ui.act_file_quit.setMenuRole(QAction.QuitRole) self.ui.act_settings_configure.setMenuRole(QAction.PreferencesRole) self.ui.act_help_about.setMenuRole(QAction.AboutRole) #self.ui.menu_Settings.setTitle("Panels") #self.ui.menu_Help.hide() # ---------------------------------------------------------------------------------------------------- # Set up GUI (special stuff for Live-MOD ISO) if USING_LIVE_ISO: self.ui.menubar.hide() self.ui.b_start.hide() self.ui.b_configure.hide() self.ui.b_about.hide() # ---------------------------------------------------------------------------------------------------- # Load Settings self.loadSettings(True) # ---------------------------------------------------------------------------------------------------- # Connect actions to functions self.SIGUSR1.connect(self.slot_handleSIGUSR1) self.SIGTERM.connect(self.slot_handleSIGTERM) self.fProccessBackend.error.connect(self.slot_backendError) self.fProccessBackend.started.connect(self.slot_backendStarted) self.fProccessBackend.finished.connect(self.slot_backendFinished) self.fProccessBackend.readyRead.connect(self.slot_backendRead) self.fWebServerThread.running.connect(self.slot_webServerRunning) self.fWebServerThread.finished.connect(self.slot_webServerFinished) self.ui.menu_Pedalboard.aboutToShow.connect(self.slot_pedalboardCheckOnline) self.ui.act_file_refresh.triggered.connect(self.slot_fileRefresh) self.ui.act_file_inspect.triggered.connect(self.slot_fileInspect) self.ui.act_backend_information.triggered.connect(self.slot_backendInformation) self.ui.act_backend_start.triggered.connect(self.slot_backendStart) self.ui.act_backend_stop.triggered.connect(self.slot_backendStop) self.ui.act_backend_restart.triggered.connect(self.slot_backendRestart) self.ui.act_pedalboard_new.triggered.connect(self.slot_pedalboardNew) self.ui.act_pedalboard_open.triggered.connect(self.slot_pedalboardOpen) self.ui.act_pedalboard_save.triggered.connect(self.slot_pedalboardSave) self.ui.act_pedalboard_save_as.triggered.connect(self.slot_pedalboardSaveAs) self.ui.act_pedalboard_share.triggered.connect(self.slot_pedalboardShare) self.ui.act_settings_configure.triggered.connect(self.slot_configure) self.ui.act_help_about.triggered.connect(self.slot_about) self.ui.act_help_project.triggered.connect(self.slot_showProject) self.ui.act_help_website.triggered.connect(self.slot_showWebsite) self.ui.b_start.clicked.connect(self.slot_backendStart) self.ui.b_configure.clicked.connect(self.slot_configure) self.ui.b_about.clicked.connect(self.slot_about) # force our custom refresh webReloadAction = self.ui.webpage.action(QWebPage.Reload) webReloadAction.triggered.disconnect() webReloadAction.triggered.connect(self.slot_fileRefresh) # ---------------------------------------------------------------------------------------------------- # Final setup self.setProperWindowTitle() SESSION.setupApp(self._pedal_changed_callback) if not "--no-autostart" in sys.argv: QTimer.singleShot(0, self.slot_backendStart) QTimer.singleShot(1, self.fixWebViewSize) def __del__(self): self.stopAndWaitForWebServer() self.stopAndWaitForBackend() def _pedal_changed_callback(self, ok, bundlepath, title): #self.fCurrentBundle = bundlepath self.fCurrentTitle = title or "" #self.updatePresetsMenu() self.setProperWindowTitle() # -------------------------------------------------------------------------------------------------------- # Files (menu actions) @pyqtSlot() def slot_fileRefresh(self): if self.fWebFrame is None: return self.ui.label_progress.setText(self.tr("Refreshing UI...")) self.ui.stackedwidget.setCurrentIndex(0) QTimer.singleShot(0, self.slot_fileRefreshPost) @pyqtSlot() def slot_fileRefreshPost(self): self.ui.webview.loadStarted.connect(self.slot_webviewLoadStarted) self.ui.webview.loadProgress.connect(self.slot_webviewLoadProgress) self.ui.webview.loadFinished.connect(self.slot_webviewLoadFinished) self.ui.webview.reload() @pyqtSlot() def slot_fileInspect(self): self.ui.webinspector.show() # -------------------------------------------------------------------------------------------------------- # Pedalboard (menu actions) @pyqtSlot() def slot_pedalboardCheckOnline(self): if self.fWebFrame is None: return isOnline = self.fWebFrame.evaluateJavaScript("$('#mod-cloud').hasClass('logged')") if isOnline is None: return print("isOnline is None") self.ui.act_pedalboard_share.setEnabled(isOnline) @pyqtSlot() def slot_pedalboardNew(self): if self.fWebFrame is None: return self.fWebFrame.evaluateJavaScript("desktop.reset()") # -------------------------------------------------------------------------------------------------------- @pyqtSlot() def slot_pedalboardOpen(self): if len(self.fPedalboards) == 0: return QMessageBox.information(self, self.tr("information"), "No pedalboards found") dialog = OpenPedalboardWindow(self, self.fPedalboards) if not dialog.exec_(): return pedalboard = dialog.getSelectedURI() if not pedalboard: return QMessageBox.information(self, self.tr("information"), "Invalid pedalboard selected") try: bundle = get_bundle_dirname(pedalboard) except: return if self.fWebFrame is None: return self.fWebFrame.evaluateJavaScript("desktop.loadPedalboard(\"%s\")" % bundle) def openPedalboardLater(self, filename): try: self.fNextBundle = QFileInfo(filename).absoluteFilePath() self.fCurrentTitle = get_pedalboard_info(self.fNextBundle)['name'] except: self.fNextBundle = "" self.fCurrentTitle = "" # -------------------------------------------------------------------------------------------------------- @pyqtSlot() def slot_pedalboardSave(self, saveAs=False): if self.fWebFrame is None: return self.fWebFrame.evaluateJavaScript("desktop.saveCurrentPedalboard(%s)" % ("true" if saveAs else "false")) @pyqtSlot() def slot_pedalboardSaveAs(self): self.slot_pedalboardSave(True) # -------------------------------------------------------------------------------------------------------- @pyqtSlot() def slot_pedalboardShare(self): if self.fWebFrame is None: return self.fWebFrame.evaluateJavaScript("desktop.shareCurrentPedalboard()") # -------------------------------------------------------------------------------------------------------- # Presets (menu actions) @pyqtSlot() def slot_presetClicked(self): print(self.sender().data()) # -------------------------------------------------------------------------------------------------------- # Settings (menu actions) @pyqtSlot() def slot_configure(self): dialog = SettingsWindow(self, True) if not dialog.exec_(): return self.loadSettings(False) # -------------------------------------------------------------------------------------------------------- # About (menu actions) @pyqtSlot() def slot_about(self): QMessageBox.about(self, self.tr("About"), self.tr(""" <b>MOD Desktop Application</b><br/> <br/> A software to have the complete MOD environment running in your desktop.<br/> (C) 2015-2016 - The MOD Team<br/> <br/> Publications, products, content or services referenced herein or on the website are the exclusive trademarks or servicemarks of MOD.<br/> Other product and company names mentioned in the site may be the trademarks of their respective owners.<br/> <br/> All software is available under the <a href="https://www.gnu.org/licenses/gpl-2.0.html">GPL license</a>.<br/> """)) @pyqtSlot() def slot_showProject(self): QDesktopServices.openUrl(QUrl("https://github.com/moddevices/mod-app")) @pyqtSlot() def slot_showWebsite(self): QDesktopServices.openUrl(QUrl("http://moddevices.com/")) # -------------------------------------------------------------------------------------------------------- # Backend (menu actions) @pyqtSlot() def slot_backendInformation(self): table = """ <table><tr> <td> MOD-UI port: <td></td> %s </td> </tr><tr> <td> Backend address: <td></td> %s </td> </tr></table> """ % (config["port"], "unix:///tmp/mod-app-%s.sock" % config["port"]) QMessageBox.information(self, self.tr("information"), table) @pyqtSlot() def slot_backendStart(self): if self.fProccessBackend.state() != QProcess.NotRunning: print("slot_backendStart ignored") return print("slot_backendStart in progress...") if USING_LIVE_ISO: os.system("jack_wait -w") os.system("jack_load mod-monitor") hostPath = "jack_load" hostArgs = ["-w", "-a", "mod-host"] else: hostPath = self.fSavedSettings[MOD_KEY_HOST_PATH] if hostPath.endswith("ingen"): hostPath = MOD_DEFAULT_HOST_PATH hostArgs = ["-n"] self.fProccessBackend.start(hostPath, hostArgs) @pyqtSlot() def slot_backendStop(self, forced = False): #if self.fPluginCount > 0: #if not forced: #ask = QMessageBox.question(self, self.tr("Warning"), self.tr("There are still some plugins loaded, you need to remove them to stop the engine.\n" #"Do you want to do this now?"), #QMessageBox.Yes | QMessageBox.No, QMessageBox.No) #if ask != QMessageBox.Yes: #return #self.removeAllPlugins() #self.host.set_engine_about_to_close() #self.host.remove_all_plugins() # testing red color for server stopped self.ui.webview.blockSignals(True) self.ui.webview.setHtml("<html><body bgcolor='green'></body></html>") self.ui.webview.blockSignals(False) self.stopAndWaitForWebServer() self.stopAndWaitForBackend() @pyqtSlot() def slot_backendRestart(self): #self.ui.stackedwidget.setCurrentIndex(0) self.slot_backendStop() #QApplication.instance().processEvents() self.slot_backendStart() # -------------------------------------------------------------------------------------------------------- @pyqtSlot() def slot_backendStarted(self): self.ui.act_backend_start.setEnabled(False) self.ui.act_backend_stop.setEnabled(True) self.ui.act_backend_restart.setEnabled(True) self.ui.w_buttons.setEnabled(False) self.ui.label_progress.setText(self.tr("Loading backend...")) @pyqtSlot(int, QProcess.ExitStatus) def slot_backendFinished(self, exitCode, exitStatus): self.fFirstBackendInit = False self.fStoppingBackend = False self.ui.act_backend_start.setEnabled(True) self.ui.act_backend_stop.setEnabled(False) self.ui.act_backend_restart.setEnabled(False) self.ui.w_buttons.setEnabled(True) self.ui.label_progress.setText("") self.ui.stackedwidget.setCurrentIndex(0) # stop webserver self.stopAndWaitForWebServer() @pyqtSlot(QProcess.ProcessError) def slot_backendError(self, error): firstBackendInit = self.fFirstBackendInit self.fFirstBackendInit = False # stop webserver self.stopAndWaitForWebServer() # crashed while stopping, ignore if error == QProcess.Crashed and self.fStoppingBackend: return errorStr = self.tr("Could not start host backend.\n") + self.getProcessErrorAsString(error) qWarning(errorStr) # don't show error if this is the first time starting the host or using live-iso if firstBackendInit or USING_LIVE_ISO: return # show the error message QMessageBox.critical(self, self.tr("Error"), errorStr) @pyqtSlot() def slot_backendRead(self): #if self.fProccessBackend.state() != QProcess.Running: #return for line in str(self.fProccessBackend.readAllStandardOutput().trimmed(), encoding="utf-8", errors="ignore").strip().split("\n"): line = line.replace("\x1b[0m","").replace("\x1b[0;31m","").replace("\x1b[0;33m","").strip() if not line: continue if self.fSavedSettings[MOD_KEY_HOST_VERBOSE]: print("BACKEND:", line) if line == "mod-host ready!" or line == "mod-host is running.": QTimer.singleShot(0, self.slot_backendStartPhase2) #elif "Listening on socket " in line: #QTimer.singleShot(1000, self.slot_ingenStarted) ##elif "Activated Jack client " in line: ##QTimer.singleShot(1000, self.fWebServerThread.start) #elif "Failed to create UNIX socket" in line or "Could not activate Jack client" in line: ## need to wait for ingen to create sockets so it can delete them on termination #QTimer.singleShot(1000, self.slot_ingenStartError) @pyqtSlot() def slot_backendStartPhase2(self): if self.fProccessBackend.state() == QProcess.NotRunning: return if not self.fNeedsSessionReconnect: # we'll need it for next time self.fNeedsSessionReconnect = True else: # we need it now SESSION.reconnectApp() self.fWebServerThread.start() @pyqtSlot() def slot_backendStartError(self): self.stopAndWaitForBackend() self.slot_backendError(-2) # -------------------------------------------------------------------------------------------------------- # Web Server @pyqtSlot() def slot_webServerRunning(self): try: self.ui.webview.loadStarted.connect(self.slot_webviewLoadStarted) self.ui.webview.loadProgress.connect(self.slot_webviewLoadProgress) self.ui.webview.loadFinished.connect(self.slot_webviewLoadFinished) except: pass print("webserver running") self.ui.webview.load(QUrl(config["addr"])) @pyqtSlot() def slot_webServerFinished(self): try: self.ui.webview.loadStarted.connect(self.slot_webviewLoadStarted) self.ui.webview.loadProgress.connect(self.slot_webviewLoadProgress) self.ui.webview.loadFinished.connect(self.slot_webviewLoadFinished) except: pass print("webserver finished") # testing red color for server finished self.ui.webview.blockSignals(True) self.ui.webview.setHtml("<html><body bgcolor='red'></body></html>") self.ui.webview.blockSignals(False) # -------------------------------------------------------------------------------------------------------- # Web View @pyqtSlot() def slot_webviewLoadStarted(self): self.ui.label_progress.setText(self.tr("Loading UI...")) print("load started") @pyqtSlot(int) def slot_webviewLoadProgress(self, progress): self.ui.label_progress.setText(self.tr("Loading UI... %i%%" % progress)) @pyqtSlot(bool) def slot_webviewLoadFinished(self, ok): self.ui.webview.loadStarted.disconnect(self.slot_webviewLoadStarted) self.ui.webview.loadProgress.disconnect(self.slot_webviewLoadProgress) self.ui.webview.loadFinished.disconnect(self.slot_webviewLoadFinished) if ok: # message self.ui.label_progress.setText(self.tr("Loading UI... finished!")) # enable file menu self.ui.act_file_refresh.setEnabled(True) self.ui.act_file_inspect.setEnabled(True) # for js evaulation self.fWebFrame = self.ui.webpage.currentFrame() # postpone app stuff QTimer.singleShot(100, self.slot_webviewPostFinished) else: # message self.ui.label_progress.setText(self.tr("Loading UI... failed!")) # disable file menu self.ui.act_file_refresh.setEnabled(False) self.ui.act_file_inspect.setEnabled(False) # disable pedalboard menu self.ui.act_pedalboard_new.setEnabled(False) self.ui.act_pedalboard_open.setEnabled(False) self.ui.act_pedalboard_save.setEnabled(False) self.ui.act_pedalboard_save_as.setEnabled(False) self.ui.act_pedalboard_share.setEnabled(False) self.ui.menu_Pedalboard.setEnabled(False) # stop js evaulation self.fWebFrame = None # stop backend&server self.stopAndWaitForWebServer() self.stopAndWaitForBackend() print("load finished") @pyqtSlot() def slot_webviewPostFinished(self): if self.fNextBundle: bundle = self.fNextBundle self.fNextBundle = "" self.fWebFrame.evaluateJavaScript("desktop.loadPedalboard(\"%s\")" % bundle) QTimer.singleShot(0, self.slot_webviewPostFinished2) @pyqtSlot() def slot_webviewPostFinished2(self): self.ui.stackedwidget.setCurrentIndex(1) # -------------------------------------------------------------------------------------------------------- # Settings def saveSettings(self): settings = QSettings() settings.setValue("Geometry", self.saveGeometry()) def loadSettings(self, firstTime): qsettings = QSettings() websettings = self.ui.webview.settings() self.fSavedSettings = { # Main MOD_KEY_MAIN_PROJECT_FOLDER: qsettings.value(MOD_KEY_MAIN_PROJECT_FOLDER, MOD_DEFAULT_MAIN_PROJECT_FOLDER, type=str), MOD_KEY_MAIN_REFRESH_INTERVAL: qsettings.value(MOD_KEY_MAIN_REFRESH_INTERVAL, MOD_DEFAULT_MAIN_REFRESH_INTERVAL, type=int), # Host MOD_KEY_HOST_VERBOSE: qsettings.value(MOD_KEY_HOST_VERBOSE, MOD_DEFAULT_HOST_VERBOSE, type=bool), MOD_KEY_HOST_PATH: qsettings.value(MOD_KEY_HOST_PATH, MOD_DEFAULT_HOST_PATH, type=str), # WebView MOD_KEY_WEBVIEW_INSPECTOR: qsettings.value(MOD_KEY_WEBVIEW_INSPECTOR, MOD_DEFAULT_WEBVIEW_INSPECTOR, type=bool), MOD_KEY_WEBVIEW_VERBOSE: qsettings.value(MOD_KEY_WEBVIEW_VERBOSE, MOD_DEFAULT_WEBVIEW_VERBOSE, type=bool), MOD_KEY_WEBVIEW_SHOW_INSPECTOR: qsettings.value(MOD_KEY_WEBVIEW_SHOW_INSPECTOR, MOD_DEFAULT_WEBVIEW_SHOW_INSPECTOR, type=bool) } inspectorEnabled = self.fSavedSettings[MOD_KEY_WEBVIEW_INSPECTOR] and not USING_LIVE_ISO websettings.setAttribute(QWebSettings.DeveloperExtrasEnabled, inspectorEnabled) if firstTime: if qsettings.contains("Geometry"): self.restoreGeometry(qsettings.value("Geometry", "")) else: self.setWindowState(self.windowState() | Qt.WindowMaximized) if inspectorEnabled and self.fSavedSettings[MOD_KEY_WEBVIEW_SHOW_INSPECTOR]: QTimer.singleShot(1000, self.ui.webinspector.show) self.ui.act_file_inspect.setVisible(inspectorEnabled) if self.fIdleTimerId != 0: self.killTimer(self.fIdleTimerId) self.fIdleTimerId = self.startTimer(self.fSavedSettings[MOD_KEY_MAIN_REFRESH_INTERVAL]) # -------------------------------------------------------------------------------------------------------- # Misc @pyqtSlot() def slot_handleSIGUSR1(self): print("Got SIGUSR1 -> Saving project now") self.slot_pedalboardSave() @pyqtSlot() def slot_handleSIGTERM(self): print("Got SIGTERM -> Closing now") self.close() # -------------------------------------------------------------------------------------------------------- # Qt events def closeEvent(self, event): if self.fIdleTimerId != 0: self.killTimer(self.fIdleTimerId) self.fIdleTimerId = 0 self.saveSettings() self.slot_backendStop(True) QMainWindow.closeEvent(self, event) # Needed in case the web inspector is still alive #self.ui.webinspector.close() QApplication.instance().quit() def timerEvent(self, event): if event.timerId() == self.fIdleTimerId: pass QMainWindow.timerEvent(self, event) def resizeEvent(self, event): QMainWindow.resizeEvent(self, event) self.fixWebViewSize() # -------------------------------------------------------------------------------------------------------- # Internal stuff def getProcessErrorAsString(self, error): if error == -2: return self.tr("Ingen failed to create UNIX socket.") if error == QProcess.FailedToStart: return self.tr("Process failed to start.") if error == QProcess.Crashed: return self.tr("Process crashed.") if error == QProcess.Timedout: return self.tr("Process timed out.") if error == QProcess.WriteError: return self.tr("Process write error.") return self.tr("Unkown error.") def fixWebViewSize(self): if self.ui.stackedwidget.currentIndex() == 1: return size = self.ui.swp_intro.size() self.ui.swp_webview.resize(size) self.ui.webview.resize(size) self.ui.webpage.setViewportSize(size) def stopAndWaitForBackend(self): if self.fProccessBackend.state() == QProcess.NotRunning: return self.fStoppingBackend = True self.fProccessBackend.terminate() if not self.fProccessBackend.waitForFinished(2000): qWarning("Backend failed top stop cleanly, forced kill") self.fProccessBackend.kill() def stopAndWaitForWebServer(self): if not self.fWebServerThread.isRunning(): return if not self.fWebServerThread.stopWait(): qWarning("WebServer Thread failed top stop cleanly, forced terminate") self.fWebServerThread.terminate() def setProperWindowTitle(self): title = "MOD Application" if self.fCurrentTitle: title += " - %s" % self.fCurrentTitle self.setWindowTitle(title)
class GdalToolsBaseDialog(QDialog, Ui_Dialog): def __init__(self, parent, iface, pluginBase, pluginName, pluginCommand): QDialog.__init__(self, parent) self.setAttribute(Qt.WA_DeleteOnClose) self.iface = iface self.process = QProcess(self) Utils.setProcessEnvironment(self.process) self.connect(self.process, SIGNAL("error(QProcess::ProcessError)"), self.processError) self.connect(self.process, SIGNAL("finished(int, QProcess::ExitStatus)"), self.processFinished) self.setupUi(self) self.arguments = [] self.editCmdBtn.setIcon(QIcon(":/icons/edit.png")) self.connect(self.editCmdBtn, SIGNAL("toggled(bool)"), self.editCommand) self.resetCmdBtn.setIcon(QIcon(":/icons/reset.png")) self.connect(self.resetCmdBtn, SIGNAL("clicked()"), self.resetCommand) self.editCommand(False) self.connect(self.buttonBox, SIGNAL("rejected()"), self.reject) self.connect(self.buttonBox, SIGNAL("accepted()"), self.accept) self.connect(self.buttonBox, SIGNAL("helpRequested()"), self.help) self.buttonBox.button(QDialogButtonBox.Ok).setDefault(True) self.plugin = pluginBase self.connect(self.plugin, SIGNAL("valuesChanged(PyQt_PyObject)"), self.refreshArgs) self.pluginLayout.addWidget(self.plugin) self.plugin.setFocus() self.setWindowTitle(pluginName) self.setPluginCommand(pluginCommand) def setPluginCommand(self, cmd): # on Windows replace the .py with .bat extension if platform.system() == "Windows" and cmd[-3:] == ".py": self.command = cmd[:-3] + ".bat" else: self.command = cmd if cmd[-3:] == ".py": self.helpFileName = cmd[:-3] + ".html" else: self.helpFileName = cmd + ".html" def editCommand(self, enabled): if not self.commandIsEnabled(): return self.editCmdBtn.setChecked(enabled) self.resetCmdBtn.setEnabled(enabled) self.textEditCommand.setReadOnly(not enabled) self.controlsWidget.setEnabled(not enabled) self.emit(SIGNAL("refreshArgs()")) def resetCommand(self): if not self.commandIsEditable(): return self.emit(SIGNAL("refreshArgs()")) def commandIsEditable(self): return self.commandIsEnabled() and self.editCmdBtn.isChecked() def setCommandViewerEnabled(self, enable): if not enable: self.editCommand(False) self.commandWidget.setEnabled(enable) def commandIsEnabled(self): return self.commandWidget.isEnabled() def reject(self): if self.process.state() != QProcess.NotRunning: ret = QMessageBox.warning(self, self.tr("Warning"), self.tr("The command is still running. \nDo you want terminate it anyway?"), QMessageBox.Yes | QMessageBox.No) if ret == QMessageBox.No: return self.disconnect(self.process, SIGNAL("error(QProcess::ProcessError)"), self.processError) self.disconnect(self.process, SIGNAL("finished(int, QProcess::ExitStatus)"), self.processFinished) self.emit(SIGNAL("closeClicked()")) def accept(self): self.emit(SIGNAL("okClicked()")) def help(self): self.emit(SIGNAL("helpClicked()")) def processError(self, error): self.emit(SIGNAL("processError(QProcess::ProcessError)"), error) def processFinished(self, exitCode, status): self.emit(SIGNAL("processFinished(int, QProcess::ExitStatus)"), exitCode, status) # show the online tool documentation in the default browser def onHelp(self): helpPath = Utils.getHelpPath() if helpPath == '': url = QUrl("http://www.gdal.org/" + self.helpFileName) else: url = QUrl.fromLocalFile(helpPath + '/' + self.helpFileName) QDesktopServices.openUrl(url) # called when a value in the plugin widget interface changed def refreshArgs(self, args): self.arguments = [unicode(a) for a in args] if not self.commandIsEnabled(): self.textEditCommand.setPlainText(self.command) else: self.textEditCommand.setPlainText(self.command + " " + Utils.escapeAndJoin(self.arguments)) # enables the OK button def enableRun(self, enable=True): self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(enable) # start the command execution def onRun(self): self.enableRun(False) self.setCursor(Qt.WaitCursor) if not self.commandIsEditable(): #print(self.command+' '+unicode(self.arguments)) self.process.start(self.command, self.arguments, QIODevice.ReadOnly) else: self.process.start(self.textEditCommand.toPlainText(), QIODevice.ReadOnly) # stop the command execution def stop(self): self.enableRun(True) self.setCursor(Qt.ArrowCursor) self.process.kill() # called on closing the dialog, stop the process if it's running def onClosing(self): self.stop() QDialog.reject(self) # called if an error occurs when the command has not already finished, shows the occurred error message def onError(self, error): if error == QProcess.FailedToStart: msg = QCoreApplication.translate("GdalTools", "The process failed to start. Either the invoked program is missing, or you may have insufficient permissions to invoke the program.") elif error == QProcess.Crashed: msg = QCoreApplication.translate("GdalTools", "The process crashed some time after starting successfully.") else: msg = QCoreApplication.translate("GdalTools", "An unknown error occurred.") QErrorMessage(self).showMessage(msg) QApplication.processEvents() # give the user chance to see the message self.stop() # called when the command finished its execution, shows an error message if there's one # and, if required, load the output file in canvas def onFinished(self, exitCode, status): if status == QProcess.CrashExit: self.stop() return if self.command.find("gdalinfo") != -1 and exitCode == 0: self.emit(SIGNAL("finished(bool)"), self.loadCheckBox.isChecked()) self.stop() return # show the error message if there's one, otherwise show the process output message msg = unicode(self.process.readAllStandardError()) if msg == '': outMessages = unicode(self.process.readAllStandardOutput()).splitlines() # make sure to not show the help for m in outMessages: m = string.strip(m) if m == '': continue # TODO fix this #if m.contains( QRegExp( "^(?:[Uu]sage:\\s)?" + QRegExp.escape(self.command) + "\\s" ) ): # if msg.isEmpty(): # msg = self.tr ( "Invalid parameters." ) # break #if m.contains( QRegExp( "0(?:\\.+[1-9]0{1,2})+" ) ): # continue if msg: msg += "\n" msg += m QErrorMessage(self).showMessage(msg.replace("\n", "<br>")) if exitCode == 0: self.emit(SIGNAL("finished(bool)"), self.loadCheckBox.isChecked()) self.stop()
class Main(plugin.Plugin): " Main Class " def initialize(self, *args, **kwargs): " Init Main Class " super(Main, self).initialize(*args, **kwargs) self.completer, self.dirs = QCompleter(self), QDirModel(self) self.dirs.setFilter(QDir.AllEntries | QDir.NoDotAndDotDot) self.completer.setModel(self.dirs) self.completer.setCaseSensitivity(Qt.CaseInsensitive) self.completer.setCompletionMode(QCompleter.PopupCompletion) self.desktop, self.project, menu = '', '', QMenu('Vagrant') menu.addAction('UP', lambda: self.vagrant_c('up')) menu.addAction('HALT', lambda: self.vagrant_c('halt')) menu.addAction('RELOAD', lambda: self.vagrant_c('reload')) menu.addAction('STATUS', lambda: self.vagrant_c('status')) menu.addAction('SUSPEND', lambda: self.vagrant_c('suspend')) menu.addAction('RESUME', lambda: self.vagrant_c('resume')) menu.addAction('PROVISION', lambda: self.vagrant_c('provision')) menu.addAction('PACKAGE', lambda: self.vagrant_c('package')) menu.addAction('INIT', lambda: self.vagrant_c('init')) menu.addSeparator() menu.addAction('DESTROY (!!!)', lambda: self.vagrant_c('destroy')) self.locator.get_service('explorer').add_project_menu(menu, lang='all') self.process = QProcess() self.process.readyReadStandardOutput.connect(self.readOutput) self.process.readyReadStandardError.connect(self.readErrors) self.process.finished.connect(self._process_finished) self.process.error.connect(self._process_finished) # Proxy support, by reading http_proxy os env variable proxy_url = QUrl(environ.get('http_proxy', '')) QNetworkProxy.setApplicationProxy(QNetworkProxy(QNetworkProxy.HttpProxy if str(proxy_url.scheme()).startswith('http') else QNetworkProxy.Socks5Proxy, proxy_url.host(), proxy_url.port(), proxy_url.userName(), proxy_url.password())) \ if 'http_proxy' in environ else None self.mainwidget = QTabWidget() self.mainwidget.tabCloseRequested.connect(lambda: self.mainwidget.setTabPosition(1) if self.mainwidget.tabPosition() == 0 else self.mainwidget.setTabPosition(0)) self.mainwidget.setStyleSheet('QTabBar{font-weight:bold;}') self.mainwidget.setMovable(True) self.mainwidget.setTabsClosable(True) self.dock, self.scrollable = QDockWidget(), QScrollArea() self.scrollable.setWidgetResizable(True) self.scrollable.setWidget(self.mainwidget) self.dock.setWindowTitle(__doc__) self.dock.setStyleSheet('QDockWidget::title{text-align: center;}') self.dock.setWidget(self.scrollable) self.locator.get_service('misc').add_widget(self.dock, QIcon.fromTheme("virtualbox"), __doc__) self.tab1, self.tab2, self.tab3 = QGroupBox(), QGroupBox(), QGroupBox() self.tab4, self.tab5, self.tab6 = QGroupBox(), QGroupBox(), QGroupBox() for a, b in ((self.tab1, 'Basics'), (self.tab2, 'General Options'), (self.tab3, 'VM Package Manager'), (self.tab4, 'VM Provisioning'), (self.tab5, 'VM Desktop GUI'), (self.tab6, 'Run')): a.setTitle(b) a.setToolTip(b) self.mainwidget.addTab(a, QIcon.fromTheme("virtualbox"), b) QPushButton(QIcon.fromTheme("help-about"), 'About', self.dock ).clicked.connect(lambda: QMessageBox.information(self.dock, __doc__, HELPMSG)) self.vmname = QLineEdit(self.get_name()) self.vmname.setPlaceholderText('type_your_VM_name_here_without_spaces') self.vmname.setToolTip('Type VM name, no spaces or special characters') self.target = QLabel('<b>Vagrant Target Folder: ' + path.join(BASE, self.vmname.text())) self.vmname.textChanged.connect(lambda: self.target.setText( '<b>Vagrant Target Folder: ' + path.join(BASE, self.vmname.text()))) self.btn1 = QPushButton(QIcon.fromTheme("face-smile-big"), 'Suggestion') self.btn1.setToolTip('Suggest me a Random VM name !') self.btn1.clicked.connect(lambda: self.vmname.setText(self.get_name())) self.vmcode, self.vmarch = QComboBox(), QComboBox() self.vmcode.addItems(['saucy', 'raring', 'quantal', 'precise']) self.vmarch.addItems(['x86_64 (amd64) 64-Bits', 'x86 (i386) 32-Bits']) vboxg1 = QVBoxLayout(self.tab1) for each_widget in (QLabel('<b>Name for VM'), self.vmname, self.btn1, QLabel('<b>Choose Ubuntu Codename for the VM:</b>'), self.vmcode, QLabel('<b>Choose Architecture for VM:'), self.vmarch, self.target): vboxg1.addWidget(each_widget) self.chrt = QCheckBox('LOW CPU priority for Backend Process') self.chttps = QComboBox() self.chttps.addItems(['https', 'http']) try: self.vinfo1 = QLabel('''<b> Vagrant Backend Version: </b> {}, <b> VirtualBox Backend Version: </b> {}. '''.format( getoutput('vagrant --version', shell=1).strip(), getoutput('vboxmanage --version', shell=1).strip())) except: self.vinfo1 = QLabel('<b>Warning: Failed to query Vagrant Backend!') self.qckb1 = QCheckBox(' Open target directory later') self.qckb1.setToolTip('Open the target directory when finished') self.qckb2 = QCheckBox(' Save a LOG file to target later') self.qckb2.setToolTip('Save a read-only .LOG file to target') self.qckb3 = QCheckBox(' NO run Headless Mode, use a Window') self.qckb3.setToolTip('Show the VM on a Window GUI instead of Headless') self.cpu, self.ram = QSpinBox(), QSpinBox() self.cpu.setRange(25, 99) self.cpu.setValue(99) self.ram.setRange(512, 4096) self.ram.setValue(1024) vboxg2 = QVBoxLayout(self.tab2) for each_widget in (self.qckb1, self.qckb2, self.qckb3, self.chrt, QLabel('<b>Max CPU Limit for VM:</b>'), self.cpu, QLabel('<b>Max RAM Limit for VM:</b>'), self.ram, QLabel('<b>Download Protocol Type:</b>'), self.chttps, self.vinfo1): vboxg2.addWidget(each_widget) self.qckb10 = QCheckBox('Run apt-get update on the created VM') self.qckb11 = QCheckBox('Run apt-get dist-upgrade on the created VM') self.qckb12 = QCheckBox('Run apt-get check on the created VM') self.qckb12 = QCheckBox('Run apt-get clean on the created VM') self.qckb13 = QCheckBox('Run apt-get autoremove on the created VM') self.qckb14 = QCheckBox('Try to Fix Broken packages if any on the VM') self.aptproxy, self.portredirect = QLineEdit(), QLineEdit('8000, 9000') self.aptproxy.setPlaceholderText(' user:password@proxyaddress:port ') vboxg3 = QVBoxLayout(self.tab3) for each_widget in (self.qckb10, self.qckb11, self.qckb12, self.qckb13, self.qckb14, QLabel('<b>Network Proxy for apt-get on the VM'), self.aptproxy, QLabel('<b>Network Port Redirects for the VM'), self.portredirect): vboxg3.addWidget(each_widget) self.aptpkg = QTextEdit('build-essential git python-pip vim mc wget') self.aptppa, self.pippkg = QLineEdit(), QTextEdit('virtualenv yolk') self.aptppa.setPlaceholderText(' ppa:ninja-ide-developers/daily ') self.requirements = QLineEdit() self.requirements.setPlaceholderText(' /full/path/to/requirements.txt ') self.requirements.setCompleter(self.completer) vboxg4 = QVBoxLayout(self.tab4) for each_widget in (QLabel('<b>Custom APT Ubuntu package'), self.aptpkg, QLabel('<b>Custom APT Ubuntu PPA:</b> '), self.aptppa, QLabel('<b>Custom PIP Python packages:</b> '), self.pippkg, QLabel('<b>Custom PIP Python requirements: '), self.requirements): vboxg4.addWidget(each_widget) self.buttonGroup = QButtonGroup() self.buttonGroup.buttonClicked[QAbstractButton].connect(self.get_de_pkg) vboxg5 = QVBoxLayout(self.tab5) for i, d in enumerate(('Ubuntu Unity', 'KDE Plasma', 'LXDE', 'XFCE')): button = QPushButton(d) button.setCheckable(True) button.setMinimumSize(75, 50) button.setToolTip(d) vboxg5.addWidget(button) self.buttonGroup.addButton(button) self.output = QTextEdit(''' We have persistent objects, they are called files. -Ken Thompson. ''') self.runbtn = QPushButton(QIcon.fromTheme("media-playback-start"), 'Start Vagrant Instrumentation Now !') self.runbtn.setMinimumSize(75, 50) self.runbtn.clicked.connect(self.build) glow = QGraphicsDropShadowEffect(self) glow.setOffset(0) glow.setBlurRadius(99) glow.setColor(QColor(99, 255, 255)) self.runbtn.setGraphicsEffect(glow) self.stopbt = QPushButton(QIcon.fromTheme("media-playback-stop"), 'Stop Vagrant') self.stopbt.clicked.connect(lambda: self.process.stop()) self.killbt = QPushButton(QIcon.fromTheme("application-exit"), 'Force Kill Vagrant') self.killbt.clicked.connect(lambda: self.process.kill()) vboxg6 = QVBoxLayout(self.tab6) for each_widget in (QLabel('<b>Multiprocess Output Logs'), self.output, self.runbtn, self.stopbt, self.killbt): vboxg6.addWidget(each_widget) [a.setChecked(True) for a in (self.qckb1, self.qckb2, self.qckb3, self.qckb10, self.qckb11, self.qckb12, self.qckb13, self.qckb14, self.chrt)] self.mainwidget.setCurrentIndex(5) def get_de_pkg(self, button): ' get package from desktop name ' if button.text() in 'Ubuntu Unity': self.desktop = 'ubuntu-desktop' elif button.text() in 'KDE Plasma': self.desktop = 'kubuntu-desktop' elif button.text() in 'LXDE': self.desktop = 'lubuntu-desktop' else: self.desktop = 'xubuntu-desktop' return self.desktop def get_name(self): ' return a random name of stars, planets and moons of solar system ' return choice((getuser(), 'sun', 'mercury', 'venus', 'earth', 'mars', 'neptun', 'ceres', 'pluto', 'haumea', 'makemake', 'eris', 'moon', 'saturn', 'europa', 'ganymede', 'callisto', 'mimas', 'enceladus', 'tethys', 'dione', 'rhea', 'titan', 'iapetus', 'miranda', 'ariel', 'umbriel', 'titania', 'oberon', 'triton', 'charon', 'orcus', 'io', 'ixion', 'varuna', 'quaoar', 'sedna', 'methone', 'jupiter', )) def readOutput(self): """Read and append output to the logBrowser""" self.output.append(str(self.process.readAllStandardOutput())) def readErrors(self): """Read and append errors to the logBrowser""" self.output.append(self.formatErrorMsg(str( self.process.readAllStandardError()))) def formatErrorMsg(self, msg): """Format error messages in red color""" return self.formatMsg(msg, 'red') def formatInfoMsg(self, msg): """Format informative messages in blue color""" return self.formatMsg(msg, 'green') def formatMsg(self, msg, color): """Format message with the given color""" return '<font color="{}">{}</font>'.format(color, msg) def build(self): """Main function calling vagrant to generate the vm""" self.output.setText('') self.output.append(self.formatInfoMsg('INFO:{}'.format(datetime.now()))) self.runbtn.setDisabled(True) base = path.join(BASE, self.vmname.text()) try: self.output.append(self.formatInfoMsg('INFO: Dir: {}'.format(base))) makedirs(base) except: self.output.append(self.formatErrorMsg('ERROR:Target Folder Exist')) self.output.append(self.formatInfoMsg('INFO: Changed {}'.format(base))) chdir(base) try: self.output.append(self.formatInfoMsg('INFO:Removing Vagrant file')) remove(path.join(base, 'Vagrantfile')) except: self.output.append(self.formatErrorMsg('ERROR:Remove Vagrant file')) self.output.append(self.formatInfoMsg(' INFO: OK: Runing Vagrant Init')) cmd1 = getoutput('chrt --verbose -i 0 vagrant init', shell=True) self.output.append(self.formatInfoMsg('INFO:OK:Completed Vagrant Init')) self.output.append(self.formatInfoMsg('INFO: Command: {}'.format(cmd1))) cfg = CONFIG.format(self.vmname.text(), self.vmname.text(), self.chttps.currentText(), self.vmcode.currentText(), self.vmcode.currentText(), 'amd64' if self.vmarch.currentIndex() is 0 else 'i386', '\n'.join(([ ' config.vm.network :forwarded_port, host: {}, guest: {}'.format( a, a) for a in str(self.portredirect.text()).split(',')])), VBOXGUI.format(self.ram.value(), self.cpu.value()) if self.qckb3.isChecked() is True else '') self.output.append(self.formatInfoMsg('INFO:OK:Config: {}'.format(cfg))) with open(path.join(base, 'Vagrantfile'), 'w') as f: f.write(cfg) self.output.append(self.formatInfoMsg('INFO: Writing Vagrantfile')) f.close() proxy = APTGET_PROXY.format(self.aptproxy.text(), self.aptproxy.text(), self.aptproxy.text(), self.aptproxy.text(), self.aptproxy.text(), self.aptproxy.text()) prv = '\n'.join(('#!/usr/bin/env bash', '# -*- coding: utf-8 -*-', linesep * 2, "PS1='\[\e[1;32m\][\u@\h \W]\$\[\e[0m\] ' ; HISTSIZE=5000", '# Vagrant Bootstrap Provisioning generated by Vagrant Ninja!', linesep, proxy if len(self.aptproxy.text()) >= 5 else '', 'add-apt-repository -s -y {}'.format(str(self.aptppa.text()).strip()), 'apt-get -V -u -m -y update' if self.qckb10.isChecked() is True else '', 'apt-get -y -m dist-upgrade' if self.qckb11.isChecked() is True else '', 'apt-get -y -m autoremove' if self.qckb11.isChecked() is True else '', 'apt-get -y clean' if self.qckb11.isChecked() is True else '', 'dpkg --configure -a' if self.qckb11.isChecked() is True else '', 'apt-get -y -f install' if self.qckb11.isChecked() is True else '', 'apt-get -y check' if self.qckb11.isChecked() is True else '', 'apt-get -y --force-yes install {}'.format(self.aptpkg.toPlainText()), 'pip install --verbose {}'.format(self.pippkg.toPlainText()), 'pip install --verbose -r {}'.format(self.requirements.text()), 'apt-get -y --force-yes -m install {}'.format(self.desktop), linesep, 'git config --global user.name "{}"'.format(getuser()), 'git config --global color.branch auto', 'git config --global color.diff auto', 'git config --global color.interactive auto', 'git config --global color.status auto', 'git config --global credential.helper cache', 'git config --global user.email "{}@gmail.com"'.format(getuser()), 'git config --global push.default simple', 'ufw status ; service ufw stop ; ufw disable ; swapoff --verbose --all', 'export LANGUAGE=en_US.UTF-8', 'export LANG=en_US.UTF-8', 'export LC_ALL=en_US.UTF-8', 'locale-gen en_US.UTF-8', 'dpkg-reconfigure locales', )) self.output.append(self.formatInfoMsg('INFO:OK:Script: {}'.format(prv))) with open(path.join(base, 'bootstrap.sh'), 'w') as f: f.write(prv) self.output.append(self.formatInfoMsg('INFO: Writing bootstrap.sh')) f.close() try: chmod('bootstrap.sh', 0775) # Py2 self.output.append(self.formatInfoMsg('INFO: bootstrap.sh is 775')) except: chmod('bootstrap.sh', 0o775) # Py3 self.output.append(self.formatInfoMsg('INFO: bootstrap.sh is o775')) self.output.append(self.formatInfoMsg(''' INFO: OK: Vagrant Up needs time, depends on your Internet Connection Speed !''')) self.output.append(self.formatInfoMsg('INFO: OK: Running Vagrant Up !')) self.process.start('{}vagrant up'.format('chrt --verbose -i 0 ' if self.chrt.isChecked() is True else '')) if not self.process.waitForStarted(): self.output.append(self.formatErrorMsg('ERROR: FAIL: Vagrant Fail')) self.runbtn.setEnabled(True) return self.runbtn.setEnabled(True) chdir(path.expanduser("~")) def _process_finished(self): """finished sucessfully""" self.output.append(self.formatInfoMsg('INFO:{}'.format(datetime.now()))) if self.qckb2.isChecked() is True: LOG_FILE = path.join(BASE, self.vmname.text(), 'vagrant_ninja.log') with open(LOG_FILE, 'w') as f: self.output.append(self.formatInfoMsg('INFO: OK: Writing .LOG')) f.write(self.output.toPlainText()) f.close() if self.qckb1.isChecked() is True: self.output.append(self.formatInfoMsg('INFO:Opening Target Folder')) try: startfile(BASE) except: Popen(["xdg-open", BASE]) chdir(path.expanduser("~")) def vagrant_c(self, option): ' run the choosed menu option, kind of quick-mode ' self.output.setText('') self.output.append(self.formatInfoMsg('INFO:{}'.format(datetime.now()))) self.runbtn.setDisabled(True) chdir(path.abspath( self.locator.get_service('explorer').get_current_project_item().path)) self.process.start('chrt --verbose -i 0 vagrant {}'.format(option)) if not self.process.waitForStarted(): self.output.append(self.formatErrorMsg('ERROR: FAIL: Vagrant Fail')) self.runbtn.setEnabled(True) return self.runbtn.setEnabled(True) self.output.append(self.formatInfoMsg('INFO:{}'.format(datetime.now()))) chdir(path.expanduser("~")) def finish(self): ' clear when finish ' self.process.kill()
class ProfilerWidget(QWidget): """ Profiler widget """ DATAPATH = get_conf_path('.profiler.results') VERSION = '0.0.1' def __init__(self, parent, max_entries=100): QWidget.__init__(self, parent) self.setWindowTitle("Profiler") self.output = None self.error_output = None self.filecombo = PythonModulesComboBox(self) self.start_button = create_toolbutton(self, icon=get_icon('run.png'), text=translate('Profiler', "Profile"), tip=translate('Profiler', "Run profiler"), triggered=self.start, text_beside_icon=True) self.stop_button = create_toolbutton(self, icon=get_icon('terminate.png'), text=translate('Profiler', "Stop"), tip=translate('Profiler', "Stop current profiling"), text_beside_icon=True) self.connect(self.filecombo, SIGNAL('valid(bool)'), self.start_button.setEnabled) #self.connect(self.filecombo, SIGNAL('valid(bool)'), self.show_data) # FIXME: The combobox emits this signal on almost any event # triggering show_data() too early, too often. browse_button = create_toolbutton(self, icon=get_icon('fileopen.png'), tip=translate('Profiler', 'Select Python script'), triggered=self.select_file) self.datelabel = QLabel() self.log_button = create_toolbutton(self, icon=get_icon('log.png'), text=translate('Profiler', "Output"), text_beside_icon=True, tip=translate('Profiler', "Show program's output"), triggered=self.show_log) self.datatree = ProfilerDataTree(self) self.collapse_button = create_toolbutton(self, icon=get_icon('collapse.png'), triggered=lambda dD=-1:self.datatree.change_view(dD), tip='Collapse one level up') self.expand_button = create_toolbutton(self, icon=get_icon('expand.png'), triggered=lambda dD=1:self.datatree.change_view(dD), tip='Expand one level down') hlayout1 = QHBoxLayout() hlayout1.addWidget(self.filecombo) hlayout1.addWidget(browse_button) hlayout1.addWidget(self.start_button) hlayout1.addWidget(self.stop_button) hlayout2 = QHBoxLayout() hlayout2.addWidget(self.collapse_button) hlayout2.addWidget(self.expand_button) hlayout2.addStretch() hlayout2.addWidget(self.datelabel) hlayout2.addStretch() hlayout2.addWidget(self.log_button) layout = QVBoxLayout() layout.addLayout(hlayout1) layout.addLayout(hlayout2) layout.addWidget(self.datatree) self.setLayout(layout) self.process = None self.set_running_state(False) if not is_profiler_installed(): for widget in (self.datatree, self.filecombo, self.start_button, self.stop_button): widget.setDisabled(True) if os.name == 'nt' \ and programs.is_module_installed("profile"): # The following is a comment from the pylint plugin: # Module is installed but script is not in PATH # (AFAIK, could happen only on Windows) text = translate('Profiler', 'Profiler script was not found. Please add "%s" to PATH.') text = unicode(text) % os.path.join(sys.prefix, "Scripts") else: text = translate('Profiler', ('Please install the modules '+ '<b>profile</b> and <b>pstats</b>:')) # FIXME: need the actual website url = 'http://www.python.org' text += ' <a href=%s>%s</a>' % (url, url) self.datelabel.setText(text) else: pass # self.show_data() def analyze(self, filename): if not is_profiler_installed(): return filename = unicode(filename) # filename is a QString instance self.kill_if_running() #index, _data = self.get_data(filename) index=None # FIXME: storing data is not implemented yet if index is None: self.filecombo.addItem(filename) self.filecombo.setCurrentIndex(self.filecombo.count()-1) else: self.filecombo.setCurrentIndex(self.filecombo.findText(filename)) self.filecombo.selected() if self.filecombo.is_valid(): self.start() def select_file(self): self.emit(SIGNAL('redirect_stdio(bool)'), False) filename = QFileDialog.getOpenFileName(self, translate('Profiler', "Select Python script"), os.getcwdu(), translate('Profiler', "Python scripts")+" (*.py ; *.pyw)") self.emit(SIGNAL('redirect_stdio(bool)'), False) if filename: self.analyze(filename) def show_log(self): if self.output: TextEditor(self.output, title=translate('Profiler', "Profiler output"), readonly=True, size=(700, 500)).exec_() def show_errorlog(self): if self.error_output: TextEditor(self.error_output, title=translate('Profiler', "Profiler output"), readonly=True, size=(700, 500)).exec_() def start(self): self.datelabel.setText('Profiling, please wait...') filename = unicode(self.filecombo.currentText()) self.process = QProcess(self) self.process.setProcessChannelMode(QProcess.SeparateChannels) self.process.setWorkingDirectory(os.path.dirname(filename)) self.connect(self.process, SIGNAL("readyReadStandardOutput()"), self.read_output) self.connect(self.process, SIGNAL("readyReadStandardError()"), lambda: self.read_output(error=True)) self.connect(self.process, SIGNAL("finished(int,QProcess::ExitStatus)"), self.finished) self.connect(self.stop_button, SIGNAL("clicked()"), self.process.kill) self.output = '' self.error_output = '' p_args = [os.path.basename(filename)] # FIXME: Use the system path to 'python' as opposed to hardwired p_args = ['-m', PROFILER_PATH, '-o', self.DATAPATH, os.path.basename(filename)] self.process.start('python', p_args) running = self.process.waitForStarted() self.set_running_state(running) if not running: QMessageBox.critical(self, translate('Profiler', "Error"), translate('Profiler', "Process failed to start")) def set_running_state(self, state=True): self.start_button.setEnabled(not state) self.stop_button.setEnabled(state) def read_output(self, error=False): if error: self.process.setReadChannel(QProcess.StandardError) else: self.process.setReadChannel(QProcess.StandardOutput) bytes = QByteArray() while self.process.bytesAvailable(): if error: bytes += self.process.readAllStandardError() else: bytes += self.process.readAllStandardOutput() text = unicode( QString.fromLocal8Bit(bytes.data()) ) if error: self.error_output += text else: self.output += text def finished(self): self.set_running_state(False) self.show_errorlog() # If errors occurred, show them. self.output = self.error_output + self.output # FIXME: figure out if show_data should be called here or # as a signal from the combobox self.show_data(justanalyzed=True) def kill_if_running(self): if self.process is not None: if self.process.state() == QProcess.Running: self.process.kill() self.process.waitForFinished() def show_data(self, justanalyzed=False): if not justanalyzed: self.output = None self.log_button.setEnabled(self.output is not None \ and len(self.output) > 0) self.kill_if_running() filename = unicode(self.filecombo.currentText()) if not filename: return self.datatree.load_data(self.DATAPATH) self.datatree.show_tree() text_style = "<span style=\'color: #444444\'><b>%s </b></span>" date_text = text_style % time.strftime("%d %b %Y %H:%M",time.localtime()) self.datelabel.setText(date_text)
class Main(plugin.Plugin): " Main Class " def initialize(self, *args, **kwargs): " Init Main Class " super(Main, self).initialize(*args, **kwargs) self.completer, self.dirs = QCompleter(self), QDirModel(self) self.dirs.setFilter(QDir.AllEntries | QDir.NoDotAndDotDot) self.completer.setModel(self.dirs) self.completer.setCaseSensitivity(Qt.CaseInsensitive) self.completer.setCompletionMode(QCompleter.PopupCompletion) self.process, self.mainwidget = QProcess(), QTabWidget() self.process.readyReadStandardOutput.connect(self.readOutput) self.process.readyReadStandardError.connect(self.readErrors) self.process.finished.connect(self._process_finished) self.process.error.connect(self._process_finished) self.mainwidget.tabCloseRequested.connect(lambda: self.mainwidget.setTabPosition(1) if self.mainwidget.tabPosition() == 0 else self.mainwidget.setTabPosition(0)) self.mainwidget.setStyleSheet('QTabBar{font-weight:bold;}') self.mainwidget.setMovable(True) self.mainwidget.setTabsClosable(True) self.dock, self.scrollable = QDockWidget(), QScrollArea() self.scrollable.setWidgetResizable(True) self.scrollable.setWidget(self.mainwidget) self.dock.setWindowTitle(__doc__) self.dock.setStyleSheet('QDockWidget::title{text-align: center;}') self.dock.setWidget(self.scrollable) self.locator.get_service('misc').add_widget(self.dock, QIcon.fromTheme("face-sad"), __doc__) self.tab1, self.tab2, self.tab3 = QGroupBox(), QGroupBox(), QGroupBox() self.tab4, self.tab5, self.tab6 = QGroupBox(), QGroupBox(), QGroupBox() for a, b in ((self.tab1, 'Basics'), (self.tab2, 'Coverage'), (self.tab3, 'Extensions'), (self.tab5, 'Regex'), (self.tab4, 'Paths'), (self.tab6, 'Run')): a.setTitle(b) a.setToolTip(b) self.mainwidget.addTab(a, QIcon.fromTheme("face-sad"), b) QPushButton(QIcon.fromTheme("help-about"), 'About', self.dock ).clicked.connect(lambda: QMessageBox.information(self.dock, __doc__, ''.join((__doc__, __version__, __license__, 'by', __author__)))) groupl, groupr, co = QWidget(), QWidget(), QGroupBox() self.qckb1 = QCheckBox('Open target directory later') self.qckb2 = QCheckBox('Save a LOG file to target later') self.qckb3 = QCheckBox('Verbose operation') self.qckb4 = QCheckBox('Force Stop on Error') self.qckb5 = QCheckBox('Scan Executable files for Tests') vboxgl, vboxgr = QVBoxLayout(groupl), QVBoxLayout(groupr) for a in (self.qckb1, self.qckb2, self.qckb3, self.qckb4, self.qckb5): vboxgl.addWidget(a) a.setToolTip(a.text()) self.qckb6 = QCheckBox('No Byte Compile to .PYC or Delete .PYC later') self.qckb7 = QCheckBox('Dont touch sys.path when running tests') self.qckb8 = QCheckBox('Traverse all paths of a package') self.qckb9 = QCheckBox('Dont capture STDOUT, print STDOUT on the fly') self.qckb10 = QCheckBox('Clear all Logging handlers') for a in (self.qckb6, self.qckb7, self.qckb8, self.qckb9, self.qckb10): vboxgr.addWidget(a) a.setToolTip(a.text()) vboxcon, self.framew = QHBoxLayout(co), QComboBox() [vboxcon.addWidget(a) for a in (groupl, groupr)] self.chrt = QCheckBox('LOW CPU priority for Backend Process') self.framew.addItems(['nosetests', 'PyTest', 'DocTest', 'Unittest', 'Django_Test', 'Django-Nose', 'None']) self.framew.currentIndexChanged.connect(lambda: #FIXME refactor for 3 QMessageBox.information(self.dock, __doc__, '<b>Only Nose for now')) self.framew.currentIndexChanged.connect(lambda: #FIXME refactor for 3 self.framew.setCurrentIndex(0)) vboxg1 = QVBoxLayout(self.tab1) for each_widget in (QLabel('<b>Framework'), self.framew, self.chrt, co): vboxg1.addWidget(each_widget) self.t2ck1, self.t2sp1 = QCheckBox('Activate Coverage'), QSpinBox() self.t2ck2 = QCheckBox('Erase previously collected Coverage before run') self.t2ck3 = QCheckBox('Include all tests modules in Coverage reports') self.t2ck4 = QCheckBox('Include all python files on working directory') self.t2ck5 = QCheckBox('Produce HTML Coverage reports information') self.t2ck6 = QCheckBox('Include Branch Coverage in Coverage reports') self.t2sp1.setRange(10, 90) self.t2sp1.setValue(75) vboxg2 = QVBoxLayout(self.tab2) for each_widget in (QLabel('<b>Min Percentage'), self.t2sp1, self.t2ck1, self.t2ck2, self.t2ck3, self.t2ck4, self.t2ck5, self.t2ck6): vboxg2.addWidget(each_widget) groupi, groupd, vbxg3 = QGroupBox(), QGroupBox(), QHBoxLayout(self.tab3) vboxgi, vboxgd = QVBoxLayout(groupi), QVBoxLayout(groupd) self.t3ck1 = QCheckBox('Activate DocTest to find and run doctests') self.t3ck2 = QCheckBox('Look for any doctests in tests modules too') self.t3ck3 = QCheckBox('Activate isolation (Do Not use with Coverage!)') self.t3ck4 = QCheckBox('Use Detailed Errors, evaluate failed asserts') for a in (self.t3ck1, self.t3ck2, self.t3ck3, self.t3ck4): vboxgi.addWidget(a) a.setToolTip(a.text()) self.t3ck5 = QCheckBox('Disable special handling of SkipTest exception') self.t3ck6 = QCheckBox('Run the tests that failed in the last test run') self.t3ck7 = QCheckBox('Use AllModules, Collect tests from all modules') self.t3ck8 = QCheckBox('Collect tests names only, do Not run any tests') for a in (self.t3ck5, self.t3ck6, self.t3ck7, self.t3ck8): vboxgd.addWidget(a) a.setToolTip(a.text()) [vbxg3.addWidget(a) for a in (groupi, groupd)] self.t4le1, self.t4le2 = QLineEdit(), QLineEdit(path.expanduser("~")) self.t4le1.setCompleter(self.completer) self.t4le2.setCompleter(self.completer) self.t4le1.setPlaceholderText(' /full/path/to/a/folder/ ') self.t4le2.setPlaceholderText(' /full/path/to/a/folder/ ') le1b = QPushButton(QIcon.fromTheme("folder-open"), 'Open') le1b.setMinimumSize(50, 50) le1b.clicked.connect(lambda: self.t4le1.setText( QFileDialog.getExistingDirectory(None, '', path.expanduser("~")))) le2b = QPushButton(QIcon.fromTheme("folder-open"), 'Open') le2b.clicked.connect(lambda: self.t4le2.setText( QFileDialog.getExistingDirectory(None, '', path.expanduser("~")))) vboxg4 = QVBoxLayout(self.tab4) for a in (QLabel('<b>Directory to look for Tests'), self.t4le1, le1b, QLabel('<b>Directory to generate HTML Coverage'), self.t4le2, le2b): vboxg4.addWidget(a) a.setToolTip(a.text()) self.t5le1 = QLineEdit(r'(?:^|[\b_\./-])[Tt]est') self.t5le2 = QLineEdit() self.t5le3, vboxg5 = QLineEdit(), QVBoxLayout(self.tab5) r = QPushButton('Reset') r.clicked.connect(lambda: self.t5le1.setText(r'(?:^|[\b_\./-])[Tt]est')) for a in (QLabel('<b>Matching Name Regex to be test'), self.t5le1, r, QLabel('<b>Force Include Regex Tests'), self.t5le2, QLabel('<b>Force Exclude Regex Tests'), self.t5le3): vboxg5.addWidget(a) a.setToolTip(a.text()) self.output = QTextEdit(''' Engineering is the art of making what you want from things you can get. -Dhobi''') self.runbtn = QPushButton(QIcon.fromTheme("face-sad"), 'Start Testing!') self.runbtn.setMinimumSize(75, 50) self.runbtn.clicked.connect(self.run) glow = QGraphicsDropShadowEffect(self) glow.setOffset(0) glow.setBlurRadius(99) glow.setColor(QColor(99, 255, 255)) self.runbtn.setGraphicsEffect(glow) self.kbt = QPushButton(QIcon.fromTheme("application-exit"), 'Kill') self.kbt.clicked.connect(lambda: self.process.kill()) vboxg6 = QVBoxLayout(self.tab6) for each_widget in (QLabel('Logs'), self.output, self.runbtn, self.kbt): vboxg6.addWidget(each_widget) [a.setChecked(True) for a in (self.chrt, self.qckb2, self.qckb3, self.qckb10, self.t2ck1, self.t2ck2, self.t2ck5, self.t3ck1, self.t3ck4)] self.mainwidget.setCurrentIndex(4) def readOutput(self): """Read and append output to the logBrowser""" self.output.append(str(self.process.readAllStandardOutput())) def readErrors(self): """Read and append errors to the logBrowser""" self.output.append(str(self.process.readAllStandardError())) def run(self): """Main function calling vagrant to generate the vm""" if not len(self.t4le1.text()): QMessageBox.information(self.dock, __doc__, '<b style="color:red">ERROR: Target Folder can not be Empty !') return self.output.clear() self.output.append('INFO: OK: Starting at {}'.format(datetime.now())) self.runbtn.setDisabled(True) #nose = True if self.framew.currentText() in 'nosetests' else False cmd = ' '.join(('chrt -i 0' if self.chrt.isChecked() else '', # tab 1 self.framew.currentText(), '--verbose' if self.qckb3.isChecked() else '--quiet', '--stop' if self.qckb4.isChecked() else '', '--exe' if self.qckb5.isChecked() else '--noexe', '--no-byte-compile' if self.qckb6.isChecked() else '', '--no-path-adjustment' if self.qckb7.isChecked() else '', '--traverse-namespace' if self.qckb8.isChecked() else '', '--nocapture' if self.qckb9.isChecked() else '', '--logging-clear-handlers' if self.qckb10.isChecked() else '', # tab 2 '--with-coverage' if self.t2ck1.isChecked() else '', '--cover-erase' if self.t2ck2.isChecked() else '', '--cover-tests' if self.t2ck3.isChecked() else '', '--cover-inclusive' if self.t2ck4.isChecked() else '', '--cover-html' if self.t2ck5.isChecked() else '--cover-xml', '--cover-branches' if self.t2ck6.isChecked() else '', '--cover-min-percentage={}'.format(self.t2sp1.value()), # tab 3 '--with-doctest' if self.t3ck1.isChecked() else '', '--doctest-tests' if self.t3ck2.isChecked() else '', '--with-isolation' if self.t3ck3.isChecked() else '', '--detailed-errors' if self.t3ck4.isChecked() else '', '--no-skip' if self.t3ck5.isChecked() else '', '--failed' if self.t3ck6.isChecked() else '', '--all-modules' if self.t3ck7.isChecked() else '', '--collect-only' if self.t3ck8.isChecked() else '', # tab 4 '--where="{}"'.format(self.t4le1.text()), '--cover-html-dir="{}"'.format(self.t4le2.text()) if self.t2ck5.isChecked() else '--cover-xml-file={}'.format(path.join(self.t4le2.text(), 'coverage_ninja.xml')), # tab 5 '--match="{}"'.format(self.t5le1.text().encode('utf-8')) if len(self.t5le1.text()) else '', '--include="{}"'.format(self.t5le2.text()) if len(self.t5le2.text()) else '', '--exclude="{}"'.format(self.t5le3.text()) if len(self.t5le3.text()) else '', )) self.output.append('INFO: OK: Command: {}'.format(cmd)) with open(path.join(self.t4le2.text(), 'tests_run_ninja.sh'), 'w') as f: self.output.append('INFO: OK : Writing tests_run_ninja.sh') f.write('#!/usr/bin/env bash\n# -*- coding: utf-8 -*-\n\n' + cmd) try: chmod(path.join(self.t4le2.text(), 'tests_run_ninja.sh'), 0775) except: chmod(path.join(self.t4le2.text(), 'tests_run_ninja.sh'), 0o775) self.output.append('INFO: OK: Running Tests !') self.process.start(cmd) if not self.process.waitForStarted(): self.output.append('ERROR: FAIL: Unkown Error !') self.runbtn.setEnabled(True) return self.runbtn.setEnabled(True) def _process_finished(self): """finished sucessfully""" self.output.append('INFO: OK: Finished at {}'.format(datetime.now())) if self.qckb2.isChecked() is True: with open(path.join(self.t4le2.text(), 'test_ninja.log'), 'w') as f: self.output.append('INFO: OK: Writing .LOG') f.write(self.output.toPlainText()) if self.qckb1.isChecked() is True: self.output.append('INFO:Opening Target Folder') try: startfile(self.t4le2.text()) except: Popen(["xdg-open", self.t4le2.text()]) def finish(self): ' clear when finish ' self.process.kill()
class RunWidget(QWidget): """Widget that show the execution output in the MiscContainer.""" def __init__(self): QWidget.__init__(self) vbox = QVBoxLayout(self) vbox.setSpacing(0) vbox.setContentsMargins(0, 0, 0, 0) self.output = OutputWidget(self) hbox = QHBoxLayout() self.input = QLineEdit() self.lblInput = QLabel(self.tr("Input:")) vbox.addWidget(self.output) hbox.addWidget(self.lblInput) hbox.addWidget(self.input) vbox.addLayout(hbox) #process self.currentProcess = None self.__preScriptExecuted = False self._proc = QProcess(self) self._preExecScriptProc = QProcess(self) self._postExecScriptProc = QProcess(self) self.connect(self._proc, SIGNAL("readyReadStandardOutput()"), self.output._refresh_output) self.connect(self._proc, SIGNAL("readyReadStandardError()"), self.output._refresh_error) self.connect(self._proc, SIGNAL("finished(int, QProcess::ExitStatus)"), self.finish_execution) self.connect(self._proc, SIGNAL("error(QProcess::ProcessError)"), self.process_error) self.connect(self.input, SIGNAL("returnPressed()"), self.insert_input) self.connect(self._preExecScriptProc, SIGNAL("finished(int, QProcess::ExitStatus)"), self.__main_execution) self.connect(self._preExecScriptProc, SIGNAL("readyReadStandardOutput()"), self.output._refresh_output) self.connect(self._preExecScriptProc, SIGNAL("readyReadStandardError()"), self.output._refresh_error) self.connect(self._postExecScriptProc, SIGNAL("finished(int, QProcess::ExitStatus)"), self.__post_execution_message) self.connect(self._postExecScriptProc, SIGNAL("readyReadStandardOutput()"), self.output._refresh_output) self.connect(self._postExecScriptProc, SIGNAL("readyReadStandardError()"), self.output._refresh_error) def process_error(self, error): """Listen to the error signals from the running process.""" self.lblInput.hide() self.input.hide() self._proc.kill() format_ = QTextCharFormat() format_.setAnchor(True) format_.setForeground(Qt.red) if error == 0: self.output.textCursor().insertText(self.tr('Failed to start'), format_) else: self.output.textCursor().insertText( self.tr('Error during execution, QProcess error: %d' % error), format_) def finish_execution(self, exitCode, exitStatus): """Print a message and hide the input line when the execution ends.""" self.lblInput.hide() self.input.hide() format_ = QTextCharFormat() format_.setAnchor(True) self.output.textCursor().insertText('\n\n') if exitStatus == QProcess.NormalExit: format_.setForeground(Qt.green) self.output.textCursor().insertText( self.tr("Execution Successful!"), format_) else: format_.setForeground(Qt.red) self.output.textCursor().insertText( self.tr("Execution Interrupted"), format_) self.output.textCursor().insertText('\n\n') self.__post_execution() def insert_input(self): """Take the user input and send it to the process.""" text = self.input.text() + '\n' self._proc.writeData(text) self.output.textCursor().insertText(text, self.output.plain_format) self.input.setText("") def start_process(self, fileName, pythonPath=False, PYTHONPATH=None, programParams='', preExec='', postExec=''): """Prepare the output widget and start the process.""" self.lblInput.show() self.input.show() self.fileName = fileName self.pythonPath = pythonPath # FIXME, this is python interpreter self.programParams = programParams self.preExec = preExec self.postExec = postExec self.PYTHONPATH = PYTHONPATH self.__pre_execution() def __main_execution(self): """Execute the project.""" self.output.setCurrentCharFormat(self.output.plain_format) message = '' if self.__preScriptExecuted: self.__preScriptExecuted = False message = self.tr( "Pre Execution Script Successfully executed.\n\n") self.output.setPlainText(message + 'Running: %s (%s)\n\n' % (self.fileName, time.ctime())) self.output.moveCursor(QTextCursor.Down) self.output.moveCursor(QTextCursor.Down) self.output.moveCursor(QTextCursor.Down) #runner.run_code_from_file(fileName) if not self.pythonPath: self.pythonPath = settings.PYTHON_PATH #change the working directory to the fileName dir file_directory = file_manager.get_folder(self.fileName) self._proc.setWorkingDirectory(file_directory) #force python to unbuffer stdin and stdout options = ['-u'] + settings.EXECUTION_OPTIONS.split() self.currentProcess = self._proc if self.PYTHONPATH: envpaths = [path for path in self.PYTHONPATH.splitlines()] env = QProcessEnvironment() system_environemnt = self._proc.systemEnvironment() for e in system_environemnt: key, value = e.split('=', 1) env.insert(key, value) for path in envpaths: env.insert('PYTHONPATH', path) self._proc.setProcessEnvironment(env) self._proc.start(self.pythonPath, options + [self.fileName] + [p.strip() for p in self.programParams.split(',') if p]) def __pre_execution(self): """Execute a script before executing the project.""" filePreExec = QFile(self.preExec) if filePreExec.exists() and \ bool(QFile.ExeUser & filePreExec.permissions()): ext = file_manager.get_file_extension(self.preExec) if not self.pythonPath: self.pythonPath = settings.PYTHON_PATH self.currentProcess = self._preExecScriptProc self.__preScriptExecuted = True if ext == 'py': self._preExecScriptProc.start(self.pythonPath, [self.preExec]) else: self._preExecScriptProc.start(self.preExec) else: self.__main_execution() def __post_execution(self): """Execute a script after executing the project.""" filePostExec = QFile(self.postExec) if filePostExec.exists() and \ bool(QFile.ExeUser & filePostExec.permissions()): ext = file_manager.get_file_extension(self.postExec) if not self.pythonPath: self.pythonPath = settings.PYTHON_PATH self.currentProcess = self._postExecScriptProc if ext == 'py': self._postExecScriptProc.start(self.pythonPath, [self.postExec]) else: self._postExecScriptProc.start(self.postExec) def __post_execution_message(self): """Print post execution message.""" self.output.textCursor().insertText('\n\n') format_ = QTextCharFormat() format_.setAnchor(True) format_.setForeground(Qt.green) self.output.textCursor().insertText( self.tr("Post Execution Script Successfully executed."), format_) def kill_process(self): """Kill the running process.""" self._proc.kill()
class Main(plugin.Plugin): ' main class for plugin ' def initialize(self, *args, **kwargs): ' class init ' super(Main, self).initialize(*args, **kwargs) self.process = QProcess() self.process.readyReadStandardOutput.connect(self.readOutput) self.process.readyReadStandardError.connect(self.readErrors) self.process.finished.connect(self._process_finished) self.process.error.connect(self._process_finished) # directory auto completer self.completer, self.dirs = QCompleter(self), QDirModel(self) self.dirs.setFilter(QDir.Dirs | QDir.NoDotAndDotDot) self.completer.setModel(self.dirs) self.completer.setCaseSensitivity(Qt.CaseInsensitive) self.completer.setCompletionMode(QCompleter.PopupCompletion) # menu menu = QMenu('VirtualEnv') menu.addAction('Make VirtualEnv here', lambda: self.make_virtualenv()) self.locator.get_service('explorer').add_project_menu(menu, lang='all') self.group1 = QGroupBox() self.group1.setTitle(' Paths ') self.outdir = QLineEdit(path.expanduser("~")) self.outdir.setPlaceholderText('Target Directory for Virtualenv files') self.outdir.setCompleter(self.completer) self.btn1 = QPushButton(QIcon.fromTheme("document-open"), ' Open ') self.btn1.clicked.connect(lambda: self.outdir.setText(str( QFileDialog.getExistingDirectory(self.dock, 'Please, Open a Target Directory for the Python VirtualEnv...', path.expanduser("~"))))) self.srcdir, self.prefx = QLineEdit(), QLineEdit() self.srcdir.setPlaceholderText( 'Extra search path to look for setuptools/distribute/pip') self.srcdir.setToolTip(''' Specify Extra search path to look for setuptools/distribute/pip. Defaults to Empty, then the setting is ignored.Defaults are OK.''') self.srcdir.setCompleter(self.completer) self.btn2 = QPushButton(QIcon.fromTheme("document-open"), ' Open ') self.btn2.setToolTip( 'Specify Extra search path to look for setuptools/distribute/pip') self.btn2.clicked.connect(lambda: self.srcdir.setText(str( QFileDialog.getExistingDirectory(self.dock, 'Please, Open a Extra search path to look for setuptools/pip...', path.expanduser("~"))))) self.prefx.setPlaceholderText('Prompt prefix for this environment') self.prefx.setToolTip(''' Specify a custom alternative prompt prefix for this environment. Defaults to Empty,this is optional,short prefix are recommended.''') self.btn3 = QPushButton(QIcon.fromTheme("face-smile-big"), 'Suggestion') self.btn3.setToolTip('Suggest me a Random CLI prompt prefix !') self.btn3.clicked.connect(lambda: self.prefx.setText(choice((getuser(), 'tesla', 'einstein', 'turing', 'ritchie', 'darwin', 'curie', 'planck', 'lovelace', 'dijsktra', 'galileo', 'schroedinger', 'perlman', 'hopper', 'newton', 'pasteur', 'maxwell', 'aristotle‎', 'volta', 'mendelev', 'bohr', 'crick', 'watson', 'archimedes', 'nash', 'fermi', 'dirac', 'feynman', 'kepler', 'copernicus', 'lorentz', 'faraday', 'heisenberg', )))) vboxg1 = QVBoxLayout(self.group1) for each_widget in ( QLabel(' Target directory dath: '), self.outdir, self.btn1, QLabel(' Extra search path: '), self.srcdir, self.btn2, QLabel(' CLI Prompt prefix (Optional): '), self.prefx, self.btn3): vboxg1.addWidget(each_widget) self.group2 = QGroupBox() self.group2.setTitle(' Options ') self.group2.setCheckable(True) self.group2.setGraphicsEffect(QGraphicsBlurEffect(self)) self.group2.graphicsEffect().setEnabled(False) self.group2.toggled.connect(self.toggle_options_group) self.qckb1, self.combo1 = QCheckBox(' Use Debug'), QDoubleSpinBox() self.qckb2 = QCheckBox(' Clear out the target directory') self.qckb3 = QCheckBox(' System-wide Python Packages') self.qckb4 = QCheckBox(' Unzip Setuptool or Distribute to virtualenv') self.qckb5 = QCheckBox(' Force the use of SetupTools') self.qckb6 = QCheckBox(' Never download packages') self.qckb7 = QCheckBox(' Delete .PYC files from virtualenv') self.qckb8 = QCheckBox(' Open target directory later') self.qckb9 = QCheckBox(' Save a LOG file to target later') self.qckb10 = QCheckBox(' No install PIP in the new virtualenv') self.qckb11 = QCheckBox('Save Bash script to reproduce virtenv later') self.chrt = QCheckBox('LOW CPU priority for Backend Process') self.combo1.setValue(2.7) self.combo1.setMaximum(3.4) self.combo1.setMinimum(2.4) self.combo1.setDecimals(1) self.combo1.setSingleStep(0.1) try: self.vinfo = QLabel('<small><b> Virtualenv Version: </b>' + getoutput('virtualenv --version', shell=1).strip()) except: self.vinfo = QLabel('Warning: Failed to query Virtualenv Backend!') [a.setChecked(True) for a in (self.qckb1, self.qckb4, self.qckb7, self.chrt, self.qckb8, self.qckb9, self.qckb11)] vboxg2 = QVBoxLayout(self.group2) for each_widget in (self.qckb1, self.qckb2, self.qckb3, self.qckb4, self.qckb5, self.qckb6, self.qckb7, self.qckb8, self.qckb9, self.qckb10, self.qckb11, QLabel(' Python interpreter version: '), self.combo1, QLabel(' Backend CPU priority: '), self.chrt): vboxg2.addWidget(each_widget) self.button = QPushButton(' Make Virtualenv ') self.button.setCursor(QCursor(Qt.PointingHandCursor)) self.button.setMinimumSize(75, 50) self.button.clicked.connect(self.run) glow = QGraphicsDropShadowEffect(self) glow.setOffset(0) glow.setBlurRadius(99) glow.setColor(QColor(99, 255, 255)) self.button.setGraphicsEffect(glow) self.output = QTextEdit(''' " Let the future tell the truth, and evaluate each one according to his work and accomplishments. The present is theirs; the future, for which I really worked, is mine. " -Nikola Tesla. ''') class TransientWidget(QWidget): ' persistant widget thingy ' def __init__(self, widget_list): ' init sub class ' super(TransientWidget, self).__init__() vbox = QVBoxLayout(self) for each_widget in widget_list: vbox.addWidget(each_widget) tw = TransientWidget((self.group1, self.group2, QLabel('Backend Logs'), self.output, self.vinfo, self.button)) self.scrollable, self.dock = QScrollArea(), QDockWidget() self.scrollable.setWidgetResizable(True) self.scrollable.setWidget(tw) self.dock.setWindowTitle(__doc__) self.dock.setStyleSheet('QDockWidget::title{text-align: center;}') self.dock.setWidget(self.scrollable) ExplorerContainer().addTab(self.dock, "Virtualenv") QPushButton(QIcon.fromTheme("help-about"), 'About', self.dock ).clicked.connect(lambda: QMessageBox.information(self.dock, __doc__, HELPMSG)) def readOutput(self): """Read and append sphinx-build output to the logBrowser""" self.output.append(str(self.process.readAllStandardOutput()).strip()) def readErrors(self): """Read and append sphinx-build errors to the logBrowser""" self.output.append(self.formatErrorMsg(str( self.process.readAllStandardError()))) def formatErrorMsg(self, msg): """Format error messages in red color""" return self.formatMsg(msg, 'red') def formatInfoMsg(self, msg): """Format informative messages in blue color""" return self.formatMsg(msg, 'green') def formatMsg(self, msg, color): """Format message with the given color""" return '<font color="{}">{}</font>'.format(color, msg) def make_virtualenv(self): ' make virtualenv from contextual sub menu ' self.outdir.setText(self.ex_locator.get_current_project_item().path) self.run() def run(self): ' run the actions ' self.output.clear() self.output.append(self.formatInfoMsg( 'INFO: OK: Starting at {}'.format(datetime.now()))) self.button.setDisabled(True) # Parse Values arg0 = '' if self.qckb10.isChecked() is False else '--no-pip ' arg1 = '--quiet ' if self.qckb1.isChecked() is False else '--verbose ' arg2 = '' if self.qckb2.isChecked() is False else '--clear ' arg3 = '' if self.qckb3.isChecked() is False else '--system-site-packages ' arg4 = '' if self.qckb4.isChecked() is False else '--unzip-setuptools ' arg5 = '' if self.qckb5.isChecked() is False else '--setuptools ' arg6 = '' if self.qckb6.isChecked() is False else '--never-download ' # if the target is empty return if not len(str(self.outdir.text()).strip()): self.output.append(self.formatErrorMsg('ERROR: FAIL: Target empty')) self.button.setEnabled(True) return else: self.output.append(self.formatInfoMsg( 'INFO: OK: Output Directory is {}'.format(self.outdir.text()))) # prefix prf = str(self.prefx.text()).upper().strip().replace(' ', '') arg10 = '' if prf is '' else '--prompt="{}_" '.format(prf) self.output.append(self.formatInfoMsg('INFO: Prefix: {}'.format(arg10))) # extra search dir src = str(self.srcdir.text()).strip() arg11 = '' if src is '' else '--extra-search-dir="{}" '.format(src) self.output.append(self.formatInfoMsg(' INFO: Extra: {}'.format(arg11))) self.output.append(self.formatInfoMsg( ' INFO: OK: Write Logs ?: {} '.format(self.qckb9.isChecked()))) self.output.append(self.formatInfoMsg( ' INFO: OK: Open Directory ?: {} '.format(self.qckb8.isChecked()))) # run the subprocesses cmd = '{}virtualenv {}{}{}{}{}{}{}-p python{} {}{} {}'.format( 'chrt --verbose -i 0 ' if self.chrt.isChecked() is True else '', arg0, arg1, arg2, arg3, arg4, arg5, arg6, self.combo1.value(), arg11, arg10, str(self.outdir.text()).strip()) self.output.append(self.formatInfoMsg('INFO:OK:Command:{}'.format(cmd))) self.process.start(cmd) if not self.process.waitForStarted(): self.output.append(self.formatErrorMsg(' ERROR: FAIL: Meh. ')) self.output.append(self.formatErrorMsg( 'ERROR: FAIL: Failed with Arguments: {} '.format(cmd))) self.button.setEnabled(True) return # write a .sh bash script file on target if self.qckb11.isChecked() is True: sh_file = 'create_virtualenv.sh' with open(path.join(str(self.outdir.text()), sh_file), 'w') as _sh: self.output.append(self.formatInfoMsg('''INFO: OK: Writing Bash: {}'''.format(path.join(str(self.outdir.text()), sh_file)))) _sh.write('#!/usr/bin/env bash' + linesep + cmd) _sh.close() self.output.append(self.formatInfoMsg('INFO: OK: Bash chmod: 775')) try: chmod(path.join(str(self.outdir.text()), sh_file), 0775) # Py2 except: chmod(path.join(str(self.outdir.text()), sh_file), 0o775) # Py3 self.readOutput() self.readErrors() self.button.setEnabled(True) def _process_finished(self): """ finished sucessfully """ self.output.append(self.formatInfoMsg( 'INFO: OK: Finished at {}'.format(datetime.now()))) # remove all *.PYC bytecode if self.qckb7.isChecked() is True: self.output.append(self.formatInfoMsg(' INFO: OK: Removing *.PYC ')) self.output.append(self.formatInfoMsg(' INFO: This takes a moment')) [remove(path.join(root, f)) for root, f in list(itertools.chain(* [list(itertools.product([root], files)) for root, dirs, files in walk(str(self.outdir.text()).strip())])) if f.endswith(('.pyc', '.PYC')) and not f.startswith('.')] # write a .log file on target if self.qckb9.isChecked() is True: log_file = 'virtualenv_gui.log' with open(path.join(str(self.outdir.text()), log_file), 'w') as log: self.output.append(self.formatInfoMsg('''INFO: OK: Writing Logs: {}'''.format(path.join(str(self.outdir.text()), log_file)))) log.write(self.output.toPlainText()) log.close() # open target dir if self.qckb8.isChecked() is True: try: startfile(str(self.outdir.text())) except: Popen(["xdg-open", str(self.outdir.text())]) self.output.selectAll() self.output.setFocus() def toggle_options_group(self): ' toggle on off the options group ' if self.group2.isChecked() is True: [a.setChecked(True) for a in (self.qckb1, self.qckb4, self.qckb7, self.chrt, self.qckb8, self.qckb9, self.qckb11)] self.combo1.setValue(2.7) self.group2.graphicsEffect().setEnabled(False) else: [a.setChecked(False) for a in (self.qckb1, self.qckb4, self.qckb7, self.chrt, self.qckb8, self.qckb9, self.qckb11)] self.group2.graphicsEffect().setEnabled(True) def finish(self): ' clear when finish ' self.process.kill()
class BatchFileSync(SyncProvider): def __init__(self, name, project, **kwargs): super(BatchFileSync, self).__init__(name, project) self.cmd = kwargs['cmd'] if self.project: self.rootfolder = os.path.abspath(self.project.folder) else: self.rootfolder = kwargs['rootfolder'] self.project = project self.closeproject = kwargs.get("close_project", False) self.process = QProcess() self.parser = kwargs.get("parser", None) self.parsermodule = None variables = kwargs.get("variables", {}) env = QProcessEnvironment.systemEnvironment() for varname, value in variables.iteritems(): env.insert(varname, str(value)) self.process.setProcessEnvironment(env) self.process.setWorkingDirectory( os.path.dirname(os.path.realpath(self.cmd))) self.process.finished.connect(self.complete) self.process.started.connect(self.syncStarted) self.process.readyReadStandardError.connect(self.error) self.process.readyReadStandardOutput.connect(self.readOutput) self._output = "" self.haserror = False def import_parser_module(self): import imp name = self.parser module = imp.find_module(name, [self.rootfolder]) module = imp.load_module(name, *module) self.parsermodule = module print self.parsermodule def start(self): if not self.parsermodule and self.parser: self.import_parser_module() self._output = "" self.haserror = False self.process.start(self.cmd, []) @property def output(self): return self._output @output.setter def output(self, value): self._output = value def error(self): self.haserror = True def complete(self, error, status): if error > 0 or self.haserror: stderr = self.process.readAllStandardError().data() self.syncError.emit(stderr) else: self.syncComplete.emit() self.syncFinished.emit() def readOutput(self): output = str(self.process.readAll()) ok = True if self.parsermodule: ok, output = self.parsermodule.sync_output(output) if not ok: self.haserror = True self.process.kill() self.syncError.emit(output) else: if output: self.syncMessage.emit(output)
class PylintWidget(QWidget): """ Pylint widget """ DATAPATH = get_conf_path('.pylint.results') VERSION = '1.0.2' def __init__(self, parent, max_entries=100): QWidget.__init__(self, parent) self.output = None self.error_output = None self.max_entries = max_entries self.data = [self.VERSION] if osp.isfile(self.DATAPATH): try: data = cPickle.load(file(self.DATAPATH)) if data[0] == self.VERSION: self.data = data except EOFError: pass self.filecombo = PythonModulesComboBox(self) if self.data: self.remove_obsolete_items() self.filecombo.addItems(self.get_filenames()) self.start_button = create_toolbutton(self, get_icon('run.png'), translate('Pylint', "Analyze"), tip=translate( 'Pylint', "Run analysis"), triggered=self.start) self.stop_button = create_toolbutton(self, get_icon('terminate.png'), translate('Pylint', "Stop"), tip=translate( 'Pylint', "Stop current analysis")) self.connect(self.filecombo, SIGNAL('valid(bool)'), self.start_button.setEnabled) self.connect(self.filecombo, SIGNAL('valid(bool)'), self.show_data) browse_button = create_toolbutton(self, get_icon('fileopen.png'), tip=translate( 'Pylint', 'Select Python script'), triggered=self.select_file) self.ratelabel = QLabel() self.datelabel = QLabel() self.log_button = create_toolbutton(self, get_icon('log.png'), translate('Pylint', "Output"), tip=translate( 'Pylint', "Complete Pylint output"), triggered=self.show_log) self.treewidget = ResultsTree(self) hlayout1 = QHBoxLayout() hlayout1.addWidget(self.filecombo) hlayout1.addWidget(browse_button) hlayout1.addWidget(self.start_button) hlayout1.addWidget(self.stop_button) hlayout2 = QHBoxLayout() hlayout2.addWidget(self.ratelabel) hlayout2.addStretch() hlayout2.addWidget(self.datelabel) hlayout2.addStretch() hlayout2.addWidget(self.log_button) layout = QVBoxLayout() layout.addLayout(hlayout1) layout.addLayout(hlayout2) layout.addWidget(self.treewidget) self.setLayout(layout) self.process = None self.set_running_state(False) if not is_pylint_installed(): for widget in (self.treewidget, self.filecombo, self.start_button, self.stop_button): widget.setDisabled(True) text = translate('Pylint', 'Please install <b>pylint</b>:') url = 'http://www.logilab.fr' text += ' <a href=%s>%s</a>' % (url, url) self.ratelabel.setText(text) else: self.show_data() def analyze(self, filename): if not is_pylint_installed(): return filename = unicode(filename) # filename is a QString instance self.kill_if_running() index, _data = self.get_data(filename) if index is None: self.filecombo.addItem(filename) self.filecombo.setCurrentIndex(self.filecombo.count() - 1) else: self.filecombo.setCurrentIndex(index) self.filecombo.selected() if self.filecombo.is_valid(): self.start() def select_file(self): self.emit(SIGNAL('redirect_stdio(bool)'), False) filename = QFileDialog.getOpenFileName( self, translate('Pylint', "Select Python script"), os.getcwdu(), translate('Pylint', "Python scripts") + " (*.py ; *.pyw)") self.emit(SIGNAL('redirect_stdio(bool)'), False) if filename: self.analyze(filename) def remove_obsolete_items(self): """Removing obsolete items""" self.data = [self.VERSION] + \ [(filename, data) for filename, data in self.data[1:] if is_module_or_package(filename)] def get_filenames(self): return [filename for filename, _data in self.data[1:]] def get_data(self, filename): filename = osp.abspath(filename) for index, (fname, data) in enumerate(self.data[1:]): if fname == filename: return index, data else: return None, None def set_data(self, filename, data): filename = osp.abspath(filename) index, _data = self.get_data(filename) if index is not None: self.data.pop(index) self.data.append((filename, data)) self.save() def set_max_entries(self, max_entries): self.max_entries = max_entries self.save() def save(self): while len(self.data) > self.max_entries + 1: self.data.pop(1) cPickle.dump(self.data, file(self.DATAPATH, 'w')) def show_log(self): if self.output: TextEditor(self.output, title=translate('Pylint', "Pylint output"), readonly=True, size=(700, 500)).exec_() def start(self): filename = unicode(self.filecombo.currentText()) self.process = QProcess(self) self.process.setProcessChannelMode(QProcess.SeparateChannels) self.process.setWorkingDirectory(osp.dirname(filename)) self.connect(self.process, SIGNAL("readyReadStandardOutput()"), self.read_output) self.connect(self.process, SIGNAL("readyReadStandardError()"), lambda: self.read_output(error=True)) self.connect(self.process, SIGNAL("finished(int,QProcess::ExitStatus)"), self.finished) self.connect(self.stop_button, SIGNAL("clicked()"), self.process.kill) self.output = '' self.error_output = '' p_args = [osp.basename(filename)] self.process.start(PYLINT_PATH, p_args) running = self.process.waitForStarted() self.set_running_state(running) if not running: QMessageBox.critical( self, translate('Pylint', "Error"), translate('Pylint', "Process failed to start")) def set_running_state(self, state=True): self.start_button.setEnabled(not state) self.stop_button.setEnabled(state) def read_output(self, error=False): if error: self.process.setReadChannel(QProcess.StandardError) else: self.process.setReadChannel(QProcess.StandardOutput) bytes = QByteArray() while self.process.bytesAvailable(): if error: bytes += self.process.readAllStandardError() else: bytes += self.process.readAllStandardOutput() text = unicode(QString.fromLocal8Bit(bytes.data())) if error: self.error_output += text else: self.output += text def finished(self): self.set_running_state(False) if not self.output: return # Convention, Refactor, Warning, Error results = {'C:': [], 'R:': [], 'W:': [], 'E:': []} txt_module = '************* Module ' module = '' # Should not be needed - just in case something goes wrong for line in self.output.splitlines(): if line.startswith(txt_module): # New module module = line[len(txt_module):] continue for prefix in results: if line.startswith(prefix): break else: continue i1 = line.find(':') if i1 == -1: continue i2 = line.find(':', i1 + 1) if i2 == -1: continue line_nb = line[i1 + 1:i2].strip() if not line_nb: continue line_nb = int(line_nb) message = line[i2 + 1:] item = (module, line_nb, message) results[line[:i1 + 1]].append(item) # Rate rate = None txt_rate = 'Your code has been rated at ' i_rate = self.output.find(txt_rate) if i_rate > 0: i_rate_end = self.output.find('/10', i_rate) if i_rate_end > 0: rate = self.output[i_rate + len(txt_rate):i_rate_end] # Previous run previous = '' if rate is not None: txt_prun = 'previous run: ' i_prun = self.output.find(txt_prun, i_rate_end) if i_prun > 0: i_prun_end = self.output.find('/10', i_prun) previous = self.output[i_prun + len(txt_prun):i_prun_end] filename = unicode(self.filecombo.currentText()) self.set_data(filename, (time.localtime(), rate, previous, results)) self.output = self.error_output + self.output self.show_data(justanalyzed=True) def kill_if_running(self): if self.process is not None: if self.process.state() == QProcess.Running: self.process.kill() self.process.waitForFinished() def show_data(self, justanalyzed=False): if not justanalyzed: self.output = None self.log_button.setEnabled(self.output is not None \ and len(self.output) > 0) self.kill_if_running() filename = unicode(self.filecombo.currentText()) if not filename: return _index, data = self.get_data(filename) if data is None: text = translate('Pylint', 'Source code has not been rated yet.') self.treewidget.clear() date_text = '' else: datetime, rate, previous_rate, results = data if rate is None: text = translate( 'Pylint', 'Analysis did not succeed ' '(see output for more details).') self.treewidget.clear() date_text = '' else: text_style = "<span style=\'color: #444444\'><b>%s </b></span>" rate_style = "<span style=\'color: %s\'><b>%s</b></span>" prevrate_style = "<span style=\'color: #666666\'>%s</span>" color = "#FF0000" if float(rate) > 5.: color = "#22AA22" elif float(rate) > 3.: color = "#EE5500" text = translate('Pylint', 'Global evaluation:') text = (text_style % text) + (rate_style % (color, ('%s/10' % rate))) if previous_rate: text_prun = translate('Pylint', 'previous run:') text_prun = ' (%s %s/10)' % (text_prun, previous_rate) text += prevrate_style % text_prun self.treewidget.set_results(filename, results) date_text = text_style % time.strftime("%d %b %Y %H:%M", datetime) self.ratelabel.setText(text) self.datelabel.setText(date_text)
class Main(plugin.Plugin): ' main class for plugin ' def initialize(self, *args, **kwargs): ' class init ' super(Main, self).initialize(*args, **kwargs) self.process = QProcess() self.process.readyReadStandardOutput.connect(self.readOutput) self.process.readyReadStandardError.connect(self.readErrors) self.process.finished.connect(self._process_finished) self.process.error.connect(self._process_finished) # directory auto completer self.completer, self.dirs = QCompleter(self), QDirModel(self) self.dirs.setFilter(QDir.Dirs | QDir.NoDotAndDotDot) self.completer.setModel(self.dirs) self.completer.setCaseSensitivity(Qt.CaseInsensitive) self.completer.setCompletionMode(QCompleter.PopupCompletion) menu = QMenu('Clones') menu.addAction('Analyze for Code Clones here', lambda: self.make_clon()) self.locator.get_service('explorer').add_project_menu(menu, lang='all') self.group1 = QGroupBox() self.group1.setTitle(' Target ') self.outdir, self.igndir = QLineEdit(path.expanduser("~")), QLineEdit() self.outdir.setCompleter(self.completer) self.btn1 = QPushButton(QIcon.fromTheme("document-open"), ' Open ') self.btn1.clicked.connect(lambda: self.outdir.setText(str( QFileDialog.getExistingDirectory(self.dock, 'Please, Open a Target Directory...', path.expanduser("~"))))) self.btn1a = QPushButton(QIcon.fromTheme("face-smile"), 'Get from Ninja active project') self.btn1a.clicked.connect(lambda: self.outdir.setText( self.locator.get_service('explorer').get_current_project_item().path)) self.ignckb, self.ignmor = QComboBox(), QTextEdit() self.ignckb.addItems(['Single Directory', 'Multiple Directories CSV']) self.ignckb.currentIndexChanged.connect(self.on_ignore_changed) self.ignmor.hide() self.igndir.setPlaceholderText('Exclude directory') self.igndir.setCompleter(self.completer) self.btn2 = QPushButton(QIcon.fromTheme("document-open"), ' Open ') self.btn2.clicked.connect(lambda: self.igndir.setText(str( QFileDialog.getExistingDirectory(self.dock, 'Please, Open a Ignore Directory...', path.expanduser("~"))))) vboxg1 = QVBoxLayout(self.group1) for each_widget in (QLabel('<b>Target directory path: '), self.outdir, self.btn1, self.btn1a, QLabel('<b>Ignore directory path: '), self.ignckb, self.ignmor, self.igndir, self.btn2, ): vboxg1.addWidget(each_widget) self.group2 = QGroupBox() self.group2.setTitle(' Output ') self.outfle = QLineEdit(path.join(path.expanduser("~"), 'output.html')) self.outfle.setPlaceholderText('Exclude directory') self.outfle.setCompleter(self.completer) self.btn3 = QPushButton(QIcon.fromTheme("document-save"), ' Save ') self.btn3.clicked.connect(lambda: self.outfle.setText( QFileDialog.getSaveFileName(self.dock, 'Save', path.expanduser("~"), 'XML(*.xml)' if self.xmlo.isChecked() is True else 'HTML(*.html)'))) vboxg2 = QVBoxLayout(self.group2) for each_widget in (QLabel('<b>Output report file path:'), self.outfle, self.btn3): vboxg2.addWidget(each_widget) self.group3 = QGroupBox() self.group3.setTitle(' Options ') self.group3.setCheckable(True) self.group3.setGraphicsEffect(QGraphicsBlurEffect(self)) self.group3.graphicsEffect().setEnabled(False) self.group3.toggled.connect(self.toggle_options_group) self.qckb1, self.qckb2 = QCheckBox('Recursive'), QCheckBox('Time-less') self.qckb3, self.qckb4 = QCheckBox('Force Diff'), QCheckBox('Fast Mode') self.qckb5, self.tm = QCheckBox('Save a LOG file to target'), QLabel('') self.xmlo = QCheckBox('XML Output instead of HTML') self.opeo = QCheckBox('Open Clones Report when done') self.chrt = QCheckBox('LOW CPU priority for Backend Process') self.mdist, self.hdep, self.output = QSpinBox(), QSpinBox(), QTextEdit() self.ign_func = QLineEdit('test, forward, backward, Migration') self.mdist.setValue(5) self.hdep.setValue(1) self.mdist.setToolTip('''<b>Maximum amount of difference between pair of sequences in clone pair (5 default).Larger value more false positive''') self.hdep.setToolTip('''<b>Computation can be speeded up by increasing this value, but some clones can be missed (1 default)''') [a.setChecked(True) for a in (self.qckb1, self.qckb3, self.qckb5, self.chrt, self.opeo)] vboxg3 = QVBoxLayout(self.group3) for each_widget in (self.qckb1, self.qckb2, self.qckb3, self.qckb4, self.qckb5, self.chrt, self.xmlo, self.opeo, QLabel('<b>Max Distance Threshold:'), self.mdist, QLabel('<b>Max Hashing Depth:'), self.hdep, QLabel('<b>Ignore code block prefix:'), self.ign_func): vboxg3.addWidget(each_widget) self.group4, self.auto = QGroupBox(), QComboBox() self.group4.setTitle(' Automation ') self.group4.setCheckable(True) self.group4.setToolTip('<font color="red"><b>WARNING:Advanced Setting!') self.group4.toggled.connect(lambda: self.group4.hide()) self.auto.addItems(['Never run automatically', 'Run when File Saved', 'Run when File Executed', 'Run when Tab Changed', 'Run when File Opened', 'Run before File Saved']) self.auto.currentIndexChanged.connect(self.on_auto_changed) QVBoxLayout(self.group4).addWidget(self.auto) self.button = QPushButton(' Analyze for Clones ') self.button.setMinimumSize(75, 50) self.button.clicked.connect(self.run) glow = QGraphicsDropShadowEffect(self) glow.setOffset(0) glow.setBlurRadius(99) glow.setColor(QColor(99, 255, 255)) self.button.setGraphicsEffect(glow) self.butkil = QPushButton(' Force Kill Clones ') self.butkil.clicked.connect(lambda: self.process.kill()) class TransientWidget(QWidget): ' persistant widget thingy ' def __init__(self, widget_list): ' init sub class ' super(TransientWidget, self).__init__() vbox = QVBoxLayout(self) for each_widget in widget_list: vbox.addWidget(each_widget) tw = TransientWidget((QLabel('<i>D.R.Y. principle analyzer'), self.group1, self.group2, self.group3, self.group4, QLabel('<b>Backend Logs'), self.output, self.tm, self.button, self.butkil)) self.scrollable, self.dock = QScrollArea(), QDockWidget() self.scrollable.setWidgetResizable(True) self.scrollable.setWidget(tw) self.dock.setWindowTitle(__doc__) self.dock.setStyleSheet('QDockWidget::title{text-align: center;}') self.dock.setWidget(self.scrollable) ExplorerContainer().addTab(self.dock, "Clones") QPushButton(QIcon.fromTheme("help-about"), 'About', self.dock ).clicked.connect(lambda: QMessageBox.information(self.dock, __doc__, HELPMSG)) def readOutput(self): """Read and append output to the logBrowser""" self.output.append(str(self.process.readAllStandardOutput()).strip()) def readErrors(self): """Read and append errors to the logBrowser""" self.output.append(self.formatErrorMsg(str( self.process.readAllStandardError()))) def formatErrorMsg(self, msg): """Format error messages in red color""" return self.formatMsg(msg, 'red') def formatInfoMsg(self, msg): """Format informative messages in blue color""" return self.formatMsg(msg, 'green') def formatMsg(self, msg, color): """Format message with the given color""" return '<font color="{}">{}</font>'.format(color, msg) def make_clon(self): ' make clones analyze from contextual sub menu ' self.outdir.setText( self.locator.get_service('explorer').get_current_project_item().path) self.run() def run(self): ' run the actions ' self.output.clear() self.output.append(self.formatInfoMsg('INFO:{}'.format(datetime.now()))) self.tm.setText('<center><b>Last Clone: </b>' + datetime.now().isoformat().split('.')[0]) self.button.setDisabled(True) if not len(self.outdir.text()) and not len(self.outfle.text()): self.output.append(self.formatErrorMsg('ERROR: FAIL: Target empty')) self.button.setEnabled(True) return # run the subprocesses cmd = ' '.join(( 'chrt -i 0' if self.chrt.isChecked() is True else '', 'clonedigger', '' if self.qckb1.isChecked() is True else '--no-recursion', '--dont-print-time' if self.qckb2.isChecked() is True else '', '--force' if self.qckb3.isChecked() is True else '', '--fast' if self.qckb4.isChecked() is True else '', '--cpd-output' if self.xmlo.isChecked() is True else '', '' if self.xmlo.isChecked() is True else '--report-unifiers', '--distance-threshold={}'.format(self.mdist.value()), '--hashing-depth={}'.format(self.hdep.value()), '--ignore-dir="{}"'.format(self.igndir.text() if self.ignckb.currentIndex() is 0 else self.ignmor.toPlainText()), '--func-prefixes="{}"'.format(self.ign_func.text()), '--output="{}"'.format(self.outfle.text()), '--language=python', path.abspath(self.outdir.text()), )) self.output.append(self.formatInfoMsg('INFO:OK:Command:{}'.format(cmd))) self.process.start(cmd) if not self.process.waitForStarted(): self.output.append(self.formatErrorMsg(' ERROR: FAIL: Meh. ')) self.output.append(self.formatErrorMsg('ERROR:FAIL:{}'.format(cmd))) self.button.setEnabled(True) return self.readOutput() self.readErrors() self.button.setEnabled(True) def _process_finished(self): """ finished sucessfully """ self.output.append(self.formatInfoMsg('INFO:{}'.format(datetime.now()))) # write a .log file on target if self.qckb5.isChecked() is True: log_file = 'ninja_clones.log' with open(path.join(str(self.outdir.text()), log_file), 'w') as log: self.output.append(self.formatInfoMsg('''INFO: OK: Writing Logs: {}'''.format(path.join(str(self.outdir.text()), log_file)))) log.write(self.output.toPlainText()) log.close() # open target output if self.opeo.isChecked() is True and self.xmlo.isChecked() is False: try: startfile(self.outfle.text()) except: Popen(["xdg-open", self.outfle.text()]) self.output.selectAll() self.output.setFocus() def toggle_options_group(self): ' toggle on off the options group ' if self.group3.isChecked() is True: [a.setChecked(True) for a in (self.qckb1, self.qckb3, self.qckb5, self.chrt, self.opeo)] self.mdist.setValue(5) self.hdep.setValue(1) self.group3.graphicsEffect().setEnabled(False) else: [a.setChecked(False) for a in (self.qckb1, self.qckb3, self.qckb5, self.chrt, self.opeo)] self.group3.graphicsEffect().setEnabled(True) def on_ignore_changed(self): 'hide or show one widget or another depending what kind of input need' if self.ignckb.currentIndex() is 0: self.igndir.show() self.btn2.show() self.ignmor.hide() else: self.igndir.hide() self.btn2.hide() self.ignmor.show() def on_auto_changed(self): ' automation connects ' if self.auto.currentIndex() is 1: self.locator.get_service('editor').fileSaved.connect(lambda: self.run()) QMessageBox.information(self.dock, __doc__, '<b>Now Actions will Run Automatically when any File is Saved !') elif self.auto.currentIndex() is 2: self.locator.get_service('editor').fileExecuted.connect(lambda: self.run()) QMessageBox.information(self.dock, __doc__, '<b>Now Actions will Run Automatically when any File is Executed !') elif self.auto.currentIndex() is 3: self.locator.get_service('editor').currentTabChanged.connect(lambda: self.run()) QMessageBox.information(self.dock, __doc__, '<b>Now Actions will Run Automatically when current Tab is Changed') elif self.auto.currentIndex() is 4: self.locator.get_service('editor').fileOpened.connect(lambda: self.run()) QMessageBox.information(self.dock, __doc__, '<b>Now Actions will Run Automatically when any File is Opened !') elif self.auto.currentIndex() is 5: self.locator.get_service('editor').beforeFileSaved.connect(lambda: self.run()) QMessageBox.information(self.dock, __doc__, '<b>Now Actions will Run Automatically before any File is Saved !') self.group4.setDisabled(True) def finish(self): ' clear when finish ' self.process.kill()
class MPStreamer(QObject): RUN_BIT = 1 FIN_BIT = 2 ERROR_BIT = 4 _READY = 0 _RUNNING = RUN_BIT _FINISHED_SUC = FIN_BIT _FINISHED_ERR = ERROR_BIT | FIN_BIT _current_id = 0 changedStatus = pyqtSignal(int) @classmethod def nextId(cls): """Generates unique id's. This class method is used to generate unique id's for all MPStreamer instances. (Not thread safe) :param cls: The 'class' object that called this method. """ cid = cls._current_id cls._current_id += 1 return cid def __init__(self, dlinfo, name="worker", mp_path="mplayer", wget="wget"): """Creates and initializes a new streamer object. :param dlinfo: Download info container :param name: Optional name of this streamer (This name will be used in debug messages...). :param mp_path: Optional path to the mplayer (used to download the stream). :param wget: Optional path to the wget utility (to download the stream). """ QObject.__init__(self) self._info = dlinfo self._mplayer = mp_path self._wget = wget self._name = "%s_%02d" % (name, self.nextId()) self._proc = QProcess() self._status = self._READY self._lerror = None self._doConnections() self._play_proc = QProcess() self._stream_proc = QProcess() def __str__(self): return self._info.getFilename() def _doConnections(self): self._proc.finished.connect(self._qprocessFinished) self._proc.stateChanged.connect(self._qprocessStateChanged) def _exists(self, filename): for i in os.listdir(self._info.destDir): basename = splitext(i)[0] if filename == basename: return True return False def start(self, overwrite=False, wget=False): # TODO: check if path exists and is accessible self._lerror = None self._info.setExtension(None) # remove extension if self._status & self.RUN_BIT: raise AlreadyRunningError(self._info.getPath()) elif self._exists(self._info.getFilename()) and (not overwrite): raise FileExistsError(self._info.getPath()) else: if self._status & self.FIN_BIT: _log.debug("Restarting Download of file '%s'" % self._info.getPath()) if wget: args = ["-c", self._info.getSourceURL(), "-O", self._info.getPath()] _log.debug("Starting download using wget (%s)" % " ".join(args)) self._proc.start(self._wget, args) else: args = ["-nolirc", "-dumpstream", "-dumpfile", self._info.getPath(), self._info.getSourceURL()] _log.debug("Starting download using mplayer (%s)" % " ".join(args)) self._proc.start(self._mplayer, args) def _decode_state(self, state): """Helper function to decode numeric state :param state: Numeric state to decode :return: Textual state string This function is used for verbose debugging messages. """ tokens = [] if state & self.RUN_BIT: tokens.append("run") if state & self.ERROR_BIT: tokens.append("error") if state & self.FIN_BIT: tokens.append("fin") if len(tokens) == 0: return "none" else: return " | ".join(tokens) def _qprocessStateChanged(self, new_state): old_status = self._status _log.info("QProcess::stateChanged '%s'" % str(new_state)) if new_state != QProcess.NotRunning: self._status = self._RUNNING _log.debug("QProcess is running!") else: self._status &= ~(self.RUN_BIT) _log.debug("QProcess has stopped!") if old_status != self._status: _log.debug( "Emit status change from '%s' to '%s'" % (self._decode_state(old_status), self._decode_state(self._status)) ) self.changedStatus.emit(self._status) def _receivedProcessErrorMsg(self): # BAD: I should find some better way to check... if self._lerror.find("Failed to open") != -1: return True else: return False def _qprocessFinished(self, exit_code, exit_status): _log.info("QProcess::finished code='%s', status='%s'" % (str(exit_code), str(exit_status))) _log.debug("stdout: '%s'" % str(self._proc.readAllStandardOutput())) self._lerror = str(self._proc.readAllStandardError()) _log.debug("stderr: '%s'" % self._lerror) succeeded = False old_status = self._status self._status |= self.FIN_BIT if exit_status != QProcess.NormalExit: _log.debug("Process most likly crashed!") self._status |= self.ERROR_BIT elif exit_code != 0: # This doesn't really indicate an error... :( _log.debug("mplayer failed (exit-code: %d)!" % exit_code) self._status |= self.ERROR_BIT elif self._receivedProcessErrorMsg(): _log.debug("mplayer couldn't open url") self._status |= self.ERROR_BIT else: path = self._info.getPath() try: ext = filetype.ExtGuesser(path).get() except filetype.InvalidPathError as ex: _log.critical("Downloaded file '%s' seems to not exist." % ex.path) self._status = self._FINISHED_ERR except filetype.ExternalProgramError: _log.critical("External program to guess ext. failed!") self._status = self._FINISHED_ERR else: newpath = "%s.%s" % (path, ext) _log.debug("Renaming '%s' to '%s'." % (path, newpath)) os.rename(path, newpath) self._info.setExtension(ext) succeeded = True if self._status != old_status: self.changedStatus.emit(self._status) self._info.finished.emit(succeeded) def playStream(self): # TODO: # maybe check QProcess::state() should be QProcess::NotRunning _log.debug("Trying to start mplayer and play stream") self._stream_proc.setStandardInputFile(self._info.getPath()) self._stream_proc.start(self._mplayer, ["-fs", "-"]) def playFile(self): # TODO: # maybe check QProcess::state() should be QProcess::NotRunning _log.debug("Trying to start mplayer and play a file") args = ["-fs", self._info.getPath()] _log.debug("mplayer start argument: %s" % str(args)) self._play_proc.start(self._mplayer, args) def getSize(self, inc_unit=False): path = self._info.getPath() try: size = getsize(path) except os.error as ex: _log.debug("Couldn't retrieve file size for '%s' -> %s" % (path, str(ex))) else: if inc_unit: idx = 0 for (i, v) in enumerate(_SIZE_MAX): if (size // v) > 0: return u"%d %s" % ((size / v), _SIZE_PREFIX[i]) def kill(self): self._proc.kill() def discard(self): self._info.removed.emit() def getStatus(self): return self._status