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 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))
if doRunNow: if firstStart: firstStart = False print("cadence-aloop-daemon started, using %s and %i channels" % ("zita-a2j/j2a" if useZita else "alsa_in/out", channels)) run_alsa_bridge() doRunNow = False elif isKernelGood and reactivateCounter >= 0: if reactivateCounter == 5: reactivateCounter = -1 doRunNow = True else: reactivateCounter += 1 sleep(1) # Close JACK client jacklib.deactivate(client) jacklib.client_close(client) if os.path.exists(checkFile): os.remove(checkFile) if procIn.state() != QProcess.NotRunning: procIn.terminate() procIn.waitForFinished(1000) if procOut.state() != QProcess.NotRunning: procOut.terminate() procOut.waitForFinished(1000)
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 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 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 serverwidget(QtGui.QFrame): def __init__(self, aname, apath): super(serverwidget, self).__init__() self.process = None self.path = apath self.name = aname self.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Sunken) title = QtGui.QLabel(self.name) startbutton = QtGui.QPushButton('START') killbutton = QtGui.QPushButton('TERMINATE') pingbutton = QtGui.QPushButton('PING') self.textfield = QtGui.QTextEdit() self.textfield.setReadOnly(True) startbutton.pressed.connect(self.start_server) killbutton.pressed.connect(self.kill_server) pingbutton.pressed.connect(self.ping_server) sublayout = QtGui.QVBoxLayout() sublayout.addWidget(title) sublayout.addWidget(startbutton) sublayout.addWidget(killbutton) sublayout.addWidget(pingbutton) sublayout.addWidget(self.textfield) self.setLayout(sublayout) def start_server(self): if self.process is None: self.process = QProcess() self.process.readyReadStandardOutput.connect(self.read_output) self.process.started.connect( lambda: self.write_message('Server started')) self.process.finished.connect( lambda: self.write_message('Server stopped')) self.process.setProcessChannelMode(QProcess.MergedChannels) self.process.setWorkingDirectory(os.path.dirname(self.path)) self.process.start('python', [self.path]) else: self.textfield.append( 'Cannot start "{:}", as it is already running'.format( self.name)) def kill_server(self): if self.process is not None: self.process.terminate() self.process = None else: self.textfield.append( 'Cannot terminate "{:}", as it is not running'.format( self.name)) def ping_server(self): if self.process is not None: state = self.process.state() msg = "PING: " if state == 0: msg += 'Process died' elif state == 1: msg += 'Process is starting up' elif state == 2: msg += 'Process is alive' self.textfield.append(msg) cnx = labrad.connect() labradserver = eval('cnx.{:}'.format(self.name)) msg = 'PING: Labradserver is ' + labradserver.echo('alive') self.textfield.append(msg) cnx.disconnect() else: self.textfield.append('Cannot ping a server that is not started') def read_output(self): data = self.process.readAllStandardOutput() self.textfield.append(str(data)) def write_message(self, message): self.textfield.append(message)
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 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 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 Kitty(QObject): """manage kitty process (terminals)""" exe_name = 'kitty' DELAY = 150 def __init__(self, ip, port, protocol, name, log_path, window_title, log_name, parent=None): QObject.__init__(self, parent) self.ip = ip self.port = port self.protocol = protocol self.log_path = log_path self.log_name = log_name self.id = str(os.getpid()) + name self.window_title = window_title self.terminal = QProcess() self.terminal.finished.connect(self.close) self.terminal.stateChanged.connect(self.state) self.send_process = QProcess() self.send_process.finished.connect(self.end_send) def open(self): """ kitty -telnet -P 9696 hostname """ if self.terminal.state() == QProcess.Running: return file_name = utils.set_log_name(self.log_name, self.log_path, ext='.txt') args = [ '-{}'.format(self.protocol), self.ip, '-P', self.port, '-log', os.path.join(self.log_path, file_name), '-title', self.window_title, '-classname', self.id ] while self.terminal.state() == QProcess.NotRunning: self.terminal.start(os.path.join(dep_dir, Kitty.exe_name), args) self.terminal.waitForStarted() QThread.msleep(Kitty.DELAY) def send(self, text): if self.send_process.state() == QProcess.Running: self.send_process.close() self.show_terminal() args = ['-classname', self.id, '-sendcmd', text] self.send_process.start(os.path.join(dep_dir, Kitty.exe_name), args) self.send_process.waitForStarted() self.send_process.waitForFinished() QThread.msleep(Kitty.DELAY) def show_terminal(self): if self.terminal.state() == QProcess.NotRunning: return autowin.show_window(autowin.get_qprocess_pid(self.terminal.pid())) QThread.msleep(Kitty.DELAY) @staticmethod def show_main(): autowin.show_window(os.getpid()) def end_send(self): pass def close(self): self.terminal.close() def state(self, st): print(st)
class SvnChangeListsDialog(QDialog, Ui_SvnChangeListsDialog): """ Class implementing a dialog to browse the change lists. """ def __init__(self, vcs, parent=None): """ Constructor @param vcs reference to the vcs object @param parent parent widget (QWidget) """ QDialog.__init__(self, parent) self.setupUi(self) self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False) self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True) self.process = None self.vcs = vcs self.rx_status = \ QRegExp('(.{8,9})\\s+([0-9-]+)\\s+([0-9?]+)\\s+(\\S+)\\s+(.+)\\s*') # flags (8 or 9 anything), revision, changed rev, author, path self.rx_status2 = \ QRegExp('(.{8,9})\\s+(.+)\\s*') # flags (8 or 9 anything), path self.rx_changelist = \ QRegExp('--- \\S+ .([\\w\\s]+).:\\s+') # three dashes, Changelist (translated), quote, # changelist name, quote, : @pyqtSignature("QListWidgetItem*, QListWidgetItem*") def on_changeLists_currentItemChanged(self, current, previous): """ Private slot to handle the selection of a new item. @param current current item (QListWidgetItem) @param previous previous current item (QListWidgetItem) """ self.filesList.clear() if current is not None: changelist = unicode(current.text()) if changelist in self.changeListsDict: self.filesList.addItems(sorted(self.changeListsDict[changelist])) def start(self, path): """ Public slot to populate the data. @param path directory name to show change lists for (string) """ self.changeListsDict = {} self.filesLabel.setText(self.trUtf8("Files (relative to %1):").arg(path)) self.errorGroup.hide() self.intercept = False self.path = path self.currentChangelist = "" self.process = QProcess() self.process.finished.connect(self.__procFinished) self.process.readyReadStandardOutput.connect(self.__readStdout) self.process.readyReadStandardError.connect(self.__readStderr) args = [] args.append('status') self.vcs.addArguments(args, self.vcs.options['global']) self.vcs.addArguments(args, self.vcs.options['status']) if '--verbose' not in self.vcs.options['global'] and \ '--verbose' not in self.vcs.options['status']: args.append('--verbose') if isinstance(path, list): self.dname, fnames = self.vcs.splitPathList(path) self.vcs.addArguments(args, fnames) else: self.dname, fname = self.vcs.splitPath(path) args.append(fname) self.process.setWorkingDirectory(self.dname) self.process.start('svn', args) procStarted = self.process.waitForStarted() if not procStarted: self.inputGroup.setEnabled(False) self.inputGroup.hide() KQMessageBox.critical(self, self.trUtf8('Process Generation Error'), self.trUtf8( 'The process %1 could not be started. ' 'Ensure, that it is in the search path.' ).arg('svn')) else: self.inputGroup.setEnabled(True) self.inputGroup.show() def __finish(self): """ Private slot called when the process finished or the user pressed the button. """ if self.process is not None and \ self.process.state() != QProcess.NotRunning: self.process.terminate() QTimer.singleShot(2000, self.process.kill) self.process.waitForFinished(3000) self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True) self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False) self.buttonBox.button(QDialogButtonBox.Close).setDefault(True) self.inputGroup.setEnabled(False) self.inputGroup.hide() if len(self.changeListsDict) == 0: self.changeLists.addItem(self.trUtf8("No changelists found")) self.buttonBox.button(QDialogButtonBox.Close).setFocus(Qt.OtherFocusReason) else: self.changeLists.addItems(sorted(self.changeListsDict.keys())) self.changeLists.setCurrentRow(0) self.changeLists.setFocus(Qt.OtherFocusReason) def on_buttonBox_clicked(self, button): """ Private slot called by a button of the button box clicked. @param button button that was clicked (QAbstractButton) """ if button == self.buttonBox.button(QDialogButtonBox.Close): self.close() elif button == self.buttonBox.button(QDialogButtonBox.Cancel): self.__finish() def __procFinished(self, exitCode, exitStatus): """ Private slot connected to the finished signal. @param exitCode exit code of the process (integer) @param exitStatus exit status of the process (QProcess.ExitStatus) """ self.__finish() def __readStdout(self): """ Private slot to handle the readyReadStandardOutput signal. It reads the output of the process, formats it and inserts it into the contents pane. """ if self.process is not None: self.process.setReadChannel(QProcess.StandardOutput) while self.process.canReadLine(): s = unicode(self.process.readLine(), Preferences.getSystem("IOEncoding"), 'replace') if self.currentChangelist != "" and self.rx_status.exactMatch(s): file = unicode(self.rx_status.cap(5)).strip() filename = file.replace(self.path + os.sep, "") if filename not in self.changeListsDict[self.currentChangelist]: self.changeListsDict[self.currentChangelist].append(filename) elif self.currentChangelist != "" and self.rx_status2.exactMatch(s): file = unicode(self.rx_status2.cap(2)).strip() filename = file.replace(self.path + os.sep, "") if filename not in self.changeListsDict[self.currentChangelist]: self.changeListsDict[self.currentChangelist].append(filename) elif self.rx_changelist.exactMatch(s): self.currentChangelist = unicode(self.rx_changelist.cap(1)) if self.currentChangelist not in self.changeListsDict: self.changeListsDict[self.currentChangelist] = [] def __readStderr(self): """ Private slot to handle the readyReadStandardError signal. It reads the error output of the process and inserts it into the error pane. """ if self.process is not None: self.errorGroup.show() s = QString(self.process.readAllStandardError()) self.errors.insertPlainText(s) self.errors.ensureCursorVisible() def on_passwordCheckBox_toggled(self, isOn): """ Private slot to handle the password checkbox toggled. @param isOn flag indicating the status of the check box (boolean) """ if isOn: self.input.setEchoMode(QLineEdit.Password) else: self.input.setEchoMode(QLineEdit.Normal) @pyqtSignature("") def on_sendButton_clicked(self): """ Private slot to send the input to the subversion process. """ input = self.input.text() input += os.linesep if self.passwordCheckBox.isChecked(): self.errors.insertPlainText(os.linesep) self.errors.ensureCursorVisible() else: self.errors.insertPlainText(input) self.errors.ensureCursorVisible() self.process.write(input) self.passwordCheckBox.setChecked(False) self.input.clear() def on_input_returnPressed(self): """ Private slot to handle the press of the return key in the input field. """ self.intercept = True self.on_sendButton_clicked() def keyPressEvent(self, evt): """ Protected slot to handle a key press event. @param evt the key press event (QKeyEvent) """ if self.intercept: self.intercept = False evt.accept() return QDialog.keyPressEvent(self, evt)
firstStart = False print( "cadence-aloop-daemon started, using %s and %i channels" % ("zita-a2j/j2a" if useZita else "alsa_in/out", channels)) run_alsa_bridge() doRunNow = False elif isKernelGood and reactivateCounter >= 0: if reactivateCounter == 5: reactivateCounter = -1 doRunNow = True else: reactivateCounter += 1 sleep(1) # Close JACK client jacklib.deactivate(client) jacklib.client_close(client) if os.path.exists(checkFile): os.remove(checkFile) if procIn.state() != QProcess.NotRunning: procIn.terminate() procIn.waitForFinished(1000) if procOut.state() != QProcess.NotRunning: procOut.terminate() procOut.waitForFinished(1000)
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)