class ImportProjectDialog(QDialog, Ui_ImportProject): projectsDatabaseHasChanged = pyqtSignal() def __init__(self, iface, parent=None): QDialog.__init__(self, parent) self.setupUi(self) self.iface = iface self.message_bar = self.iface.messageBar() self.okButton = self.buttonBox.button(QDialogButtonBox.Ok) self.okButton.setText("Import") self.settings = QSettings("CatAIS", "VeriSO") self.input_itf_path = QFileInfo( self.settings.value("file/import/input_itf_path")).absolutePath() # members self.modules = None self.app_module = None self.app_module_name = None self.ili = None self.epsg = None self.itf = None self.data_date = None self.notes = None self.db_host = None self.db_name = None self.db_schema = None self.db_port = None self.db_user = None self.db_pwd = None self.db_admin = None self.db_admin_pwd = None self.projects_database = None self.projects_root_directory = None self.process = None def init_gui(self): """Initialize the dialog: Set the current date. Accept only lower characters as project name (= database schema). Fill modules combobox. """ today = QDateTime.currentDateTime() self.dateTimeEdit.setDateTime(today) self.dateTimeEdit.setCalendarPopup(True) # You are only allowed to use lower case characters as project name ( # = database schema). self.lineEditDbSchema.setValidator( QRegExpValidator(QRegExp("^[a-z][a-z0-9_]+"), self.lineEditDbSchema)) # Fill out the modules combobox. try: modules_dir = os.path.join(get_modules_dir()) modules = [] for module_name in get_subdirs(modules_dir): module_file = os.path.join(modules_dir, module_name, 'module.yml') if os.path.isfile(module_file): module = yaml_load_file(module_file) module['dirname'] = module_name modules.append(module) if modules: sorted_modules_list = sorted(modules, key=lambda k: k['displayname']) self.cmbBoxAppModule.clear() for module in sorted_modules_list: self.cmbBoxAppModule.addItem(str(module["displayname"]), module) self.cmbBoxAppModule.insertItem(0, "", None) self.cmbBoxAppModule.setCurrentIndex(0) except Exception as e: message = "Error while parsing the available modules." self.message_bar.pushMessage("VeriSO", tr(message), QgsMessageBar.CRITICAL, duration=0) QgsMessageLog.logMessage(str(e), "VeriSO", QgsMessageLog.CRITICAL) return self.cmbBoxIliModelName.insertItem(0, "", None) return True # noinspection PyPep8Naming @pyqtSignature("on_btnProjectName_clicked()") def on_btnProjectName_clicked(self): """Check wether the project (=database schema) already exists. """ project_name = self.lineEditDbSchema.text().strip() if len(project_name) <= 0: self.lineEditDbSchema.setPlaceholderText(tr('Enter a valid name')) else: project_found = self.check_project_name(project_name) if project_found == -1: message = "An error occured while connecting the database." self.message_bar.pushMessage("VeriSO", tr(message), QgsMessageBar.CRITICAL, duration=0) return elif project_found == 1: message = "Project name already exists." self.message_bar.pushWarning("VeriSO", tr(message)) return elif project_found == 0: message = "Project name is valid." self.message_bar.pushSuccess("VeriSO", tr(message)) return True def check_project_name(self, project_name): """Makes a database request and checks if the given schema already exists. Returns: -1 if an error occured. 0 if schema was not found. 1 if schema already exists. """ self.db_host = self.settings.value("options/db/host") self.db_name = self.settings.value("options/db/name") self.db_port = self.settings.value("options/db/port") self.db_user = self.settings.value("options/db/user") self.db_pwd = self.settings.value("options/db/pwd") self.db_admin = self.settings.value("options/db/admin") self.db_admin_pwd = self.settings.value("options/db/adminpwd") # 'public' will not be found with the query. if project_name == "public": return 1 try: db = open_psql_db(self.db_host, self.db_name, self.db_port, self.db_admin, self.db_admin_pwd) sql = "SELECT schema_name FROM information_schema.schemata WHERE " \ "schema_name = '%s';" % self.lineEditDbSchema.text().strip() query = db.exec_(sql) if query.isActive(): count = query.size() db.close del db if count > 0: return 1 else: return 0 except Exception as e: QgsMessageLog.logMessage(str(e), "VeriSO", QgsMessageLog.CRITICAL) return -1 # noinspection PyPep8Naming @pyqtSignature("on_cmbBoxAppModule_currentIndexChanged(int)") def on_cmbBoxAppModule_currentIndexChanged(self, idx): """Fill out the model name combobox with all interlis models you can use with a specific module. """ self.cmbBoxIliModelName.clear() module_data = self.cmbBoxAppModule.itemData(idx) if module_data: ilimodels = module_data["ilimodels"] self.app_module = module_data["dirname"] self.app_module_name = self.cmbBoxAppModule.currentText() for i in range(len(ilimodels)): model_name = ilimodels[i]["ilimodel"] reference_frame = ilimodels[i]["referenceframe"] self.cmbBoxIliModelName.insertItem( self.cmbBoxIliModelName.count(), str(model_name), ilimodels[i]) self.cmbBoxIliModelName.insertItem(0, "", None) if len(ilimodels) == 1: self.cmbBoxIliModelName.setCurrentIndex(1) self.cmbBoxIliModelName.setEnabled(False) else: self.cmbBoxIliModelName.setCurrentIndex(0) self.cmbBoxIliModelName.setEnabled(True) else: self.app_module = "" self.app_module_name = "" # noinspection PyPep8Naming,PyPep8Naming @pyqtSignature("on_cmbBoxIliModelName_currentIndexChanged(int)") def on_cmbBoxIliModelName_currentIndexChanged(self, idx): """Fill out the reference frame lineedit (read only). """ module_data = self.cmbBoxIliModelName.itemData(idx) if module_data: self.ili = module_data["ilimodel"] self.epsg = module_data["epsg"] reference_frame = module_data["referenceframe"] self.lineEditRefFrame.setText( str(reference_frame) + " (EPSG:" + str(self.epsg) + ")") else: self.ili = "" self.epsg = "" self.lineEditRefFrame.clear() # noinspection PyPep8Naming,PyPep8Naming @pyqtSignature("on_btnBrowseInputFile_clicked()") def on_btnBrowseInputFile_clicked(self): file_path = QFileDialog.getOpenFileName( self, tr("Choose interlis transfer file"), self.input_itf_path, "ITF (*.itf *.ITF)") file_info = QFileInfo(file_path) self.lineEditInputFile.setText(file_info.absoluteFilePath()) def accept(self): """Collecting all the stuff we need to know to start the import process. """ # Save the settings. self.settings.setValue("file/import/input_itf_path", self.lineEditInputFile.text()) self.settings.setValue("file/import/ili", self.ili) # Check if project name (db schema) already exists. project_name = self.lineEditDbSchema.text().strip() if len(project_name) > 0: project_found = self.check_project_name(project_name) if project_found == -1: message = "An error occured while connecting the database." self.message_bar.pushMessage("VeriSO", tr(message), QgsMessageBar.CRITICAL, duration=0) return elif project_found == 1: message = "Project name already exists." self.message_bar.pushWarning("VeriSO", tr(message)) QgsMessageLog.logMessage(tr(message), "VeriSO", QgsMessageLog.WARNING) return # Gather all data/information for ili2pg arguments. self.itf = self.lineEditInputFile.text().strip() self.db_schema = self.lineEditDbSchema.text().strip() self.data_date = self.dateTimeEdit.date().toString("yyyy-MM-dd") self.notes = self.textEditNotes.toPlainText().strip() if len(self.notes) > 10000: message = "Notes are to big (allowed 10000 characters): " self.message_bar.pushMessage("VeriSO", tr(message) + str(len(self.notes)), QgsMessageBar.CRITICAL, duration=0) QgsMessageLog.logMessage( str(message) + str(len(self.notes)), "VeriSO", QgsMessageLog.WARNING) return self.projects_database = self.settings.value( "options/general/projects_database", "") self.projects_root_directory = self.settings.value( "options/general/projects_root_directory", "") import_jar = self.settings.value("options/import/jar", "") import_vm_arguments = self.settings.value( "options/import/vm_arguments", "") # Check if we have everything we need. if not os.path.isfile( self.projects_database) and self.projects_database != "": self.message_bar.pushWarning( "VeriSO", tr("Projects database not " "found: ") + str(self.projects_database)) return if self.itf == "": self.message_bar.pushWarning( "VeriSO", tr("No Interlis transfer file " "set.")) return if self.ili == "": self.message_bar.pushWarning("VeriSO", tr("No Interlis model name set.")) return if self.db_schema == "": self.message_bar.pushWarning("VeriSO", tr("No project name set.")) return if self.cmbBoxAppModule.currentIndex() == 0: self.message_bar.pushWarning( "VeriSO", tr("No application module " "chosen.")) return if not self.db_host: self.message_bar.pushWarning( "VeriSO", tr("Missing database host " "parameter.")) return if not self.db_name: self.message_bar.pushWarning( "VeriSO", tr("Missing database name " "parameter.")) return if not self.db_port: self.message_bar.pushWarning( "VeriSO", tr("Missing database port " "parameter.")) return if not self.db_user: self.message_bar.pushWarning( "VeriSO", tr("Missing database user " "parameter.")) return if not self.db_pwd: self.message_bar.pushWarning( "VeriSO", tr("Missing database password " "parameter.")) return if not self.db_admin: self.message_bar.pushWarning( "VeriSO", tr("Missing database administrator parameter.")) return if not self.db_admin_pwd: self.message_bar.pushWarning( "VeriSO", tr("Missing database administrator password parameter.")) return if self.projects_root_directory == "": self.message_bar.pushWarning( "VeriSO", tr("No root directory for " "projects " "set.")) return if self.projects_database == "": self.message_bar.pushInfo( "VeriSO", tr("No projects database found. Will create one in the " "project root directory.")) if import_jar == "": self.message_bar.pushWarning("VeriSO", tr("No jar file set for import.")) return self.textEditImportOutput.clear() # Set all the arguments for ili2pg. arguments = [] vm_arguments_list = import_vm_arguments.split(" ") for arg in vm_arguments_list: arguments.append(arg) arguments.append("-jar") arguments.append(import_jar) arguments.append("--import") arguments.append("--dbhost") arguments.append(self.db_host) arguments.append("--dbport") arguments.append(self.db_port) arguments.append("--dbdatabase") arguments.append(self.db_name) arguments.append("--dbschema") arguments.append(self.db_schema) arguments.append("--dbusr") arguments.append(self.db_admin) arguments.append("--dbpwd") arguments.append(self.db_admin_pwd) arguments.append("--modeldir") model_dir = ';'.join( self.settings.value("options/model_repositories/repositories")) arguments.append(model_dir) arguments.append("--models") arguments.append(self.ili) arguments.append("--defaultSrsAuth") arguments.append("EPSG") arguments.append("--defaultSrsCode") arguments.append(self.epsg) # TODO: ili2pg has a lot of options. At least some of them should be # exposed to the user. arguments.append("--t_id_Name") arguments.append("ogc_fid") arguments.append("--importTid") arguments.append("--createGeomIdx") arguments.append("--createEnumTabs") arguments.append("--createEnumTxtCol") arguments.append("--createEnumColAsItfCode") arguments.append("--nameByTopic") arguments.append("--strokeArcs") arguments.append(self.itf) self.process = QProcess() self.process.readyReadStandardOutput.connect(self.read_output) self.process.readyReadStandardError.connect(self.read_error) self.process.finished.connect(self.finish_import) QApplication.setOverrideCursor(Qt.WaitCursor) self.buttonBox.setEnabled(False) self.report_progress("Info: Starting ili2pg") self.report_progress("Info: java %s" % ' '.join(arguments)) try: self.process.start("java", arguments) except Exception as e: self.restore_cursor() message = "Could not start import process." self.message_bar.pushMessage("VeriSO", tr(message), QgsMessageBar.CRITICAL, duration=0) QgsMessageLog.logMessage(str(e), "VeriSO", QgsMessageLog.CRITICAL) def restore_cursor(self): QApplication.restoreOverrideCursor() self.buttonBox.setEnabled(True) def read_output(self): output = self.process.readAllStandardOutput() self.show_output(output) def read_error(self): error = self.process.readAllStandardError() self.show_output(error) def show_output(self, byte_array): unicode_text = byte_array.data().decode('utf-8') self.report_progress(unicode_text) def finish_import(self, exit_code): """ Check if import was successful. :param exitCode: the exit code of the process :return: None """ try: # read the output of ili2pg self.read_import_output() # Get the postprocessing queries that are stored in a sqlite # database. # Placeholder (e.g. $$DBSCHEMA, $$EPSG etc ) will be replaced. sql_queries = self.get_postprocessing_queries() # Do the postprocessing in the postgresql database. self.postprocess_data(sql_queries) # Update the projects database self.update_projects_database() # Create the project directory in the root directory. directory = self.create_project_directory() except VerisoError as e: self.message_bar.pushMessage("VeriSO", tr(str(e)), QgsMessageBar.CRITICAL, duration=0) return finally: self.restore_cursor() # When we reach here we can claim a successful import. message = "Import process finished." self.report_progress(message, 'green') self.message_bar.pushInfo("VeriSO", tr(message)) def read_import_output(self): """ Reads the output of the ili2pg conversion :return: """ output = self.textEditImportOutput.toPlainText() if output.find("Info: ...import done") < 0 or output.find( "compiler failed") >= 0: message = "Import process not successfully finished." raise VerisoError(message) def create_project_directory(self): """Creates a directory with the same name as the project (db schema) in the project root directory. This will be for exports, maps etc. It emits a projects database changed signal. Returns: False: If the directory could not be created. Otherwise True. """ try: os.makedirs( os.path.join(str(self.projects_root_directory), str(self.db_schema))) return True except Exception as e: message = "Something went wrong while creating project directory." raise VerisoError(message, e) def update_projects_database(self): """Updates the sqlite projects database. Returns: False: When there an error occured. Otherswise True. """ error_message = ("Something went wrong while updating projects " "database. You need to delete the database schema " "manually.") try: # Create a new projects database if there is none (copy one from # the templates). if self.projects_database == "": template = QDir.convertSeparators( QDir.cleanPath( QgsApplication.qgisSettingsDirPath() + "/python/plugins/veriso/templates/template_projects" ".db")) self.projects_database = QDir.convertSeparators( QDir.cleanPath(self.projects_root_directory + "/projects.db")) shutil.copyfile(template, self.projects_database) self.settings.setValue("options/general/projects_database", self.projects_database) db = get_projects_db() project_root_directory = QDir.convertSeparators( QDir.cleanPath(self.projects_root_directory + "/" + str(self.db_schema))) values = (self.db_schema, self.db_schema, self.db_host, self.db_name, self.db_port, self.db_schema, self.db_user, self.db_pwd, self.db_admin, self.db_admin_pwd, self.epsg, self.ili, self.app_module, self.app_module_name, self.projects_root_directory, project_root_directory, self.data_date, self.notes, self.itf) values = "VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s'," \ "'%s', '%s', 'postgres', '%s', '%s', '%s', '%s', '%s', " \ "'%s', '%s', '%s', '%s')" % values sql = "INSERT INTO projects (id, displayname, dbhost, dbname, " \ "dbport, dbschema, dbuser, dbpwd, dbadmin, dbadminpwd, " \ "provider, epsg, ilimodelname, appmodule, appmodulename, " \ "projectrootdir, projectdir, datadate, notes, itf)" + values query = db.exec_(sql) if not query.isActive(): message = "Error while updating projects database." raise VerisoError( message, long_message=QSqlQuery.lastError(query).text()) db.close() self.projectsDatabaseHasChanged.emit() return True except Exception as e: raise VerisoError(error_message, e) def postprocess_data(self, queries): """Does the postprocessing in the postgresql/postgis database. Returns: -1: If the process fails (e.g. no db connection etc.). Otherwise number of errors occured while postprocessing. """ try: db = open_psql_db(self.db_host, self.db_name, self.db_port, self.db_admin, self.db_admin_pwd) errors = 0 self.report_progress("\n\nInfo: Starting postprocessing...") for sql in queries: self.report_progress("\n\n%s" % sql) query = db.exec_(str(sql)) if not query.isActive(): errors += 1 message = "Error while postprocessing data:" QgsMessageLog.logMessage(tr(message), "VeriSO", QgsMessageLog.CRITICAL) QgsMessageLog.logMessage( str(QSqlQuery.lastError(query).text()), "VeriSO", QgsMessageLog.CRITICAL) self.report_progress("--> error, see log", 'orange') if errors > 0: self.report_progress( "Error: ...postprocessing completed with errors", "red") raise Exception() self.report_progress("Info: ...postprocessing completed") db.close del db except Exception as e: message = "Something went wrong while postprocessing data. You " \ "need to delete the database schema manually." raise VerisoError(message, e) def get_postprocessing_queries(self): """Gets the SQL queries that are stored in the sqlite database for the postprocessing process which is done in postgis. Language support: Everything that is not french or italian will be german. Returns: False: If the queries could not be fetched from the sqlite database. Otherwise a list with the SQL queries. """ # originial """ filename = QDir.convertSeparators(QDir.cleanPath( QgsApplication.qgisSettingsDirPath() + "/python/plugins/veriso/modules/" + self.app_module + "/postprocessing/postprocessing.db"))""" # Hack filename = QDir.convertSeparators( QDir.cleanPath((os.path.realpath(__file__)).split("python")[0] + "/python/plugins/veriso/modules/" + self.app_module + "/postprocessing/postprocessing.db")) self.report_progress("Info: getting postprocessing queries...") try: # This is NOT the project db connection_name = 'postprocessing_' + self.app_module db = open_sqlite_db(filename, connection_name) locale = QSettings().value('locale/userLocale')[0:2] if locale == "fr": lang = locale elif locale == "it": lang = locale else: lang = "de" sql = "SELECT * FROM postprocessing " \ "WHERE (lang = '%s' " \ "OR lang IS NULL) AND apply = 1 " \ "ORDER BY 'order', ogc_fid;" % lang query = db.exec_(sql) if not query.isActive(): message = "Database query not active." raise VerisoError( message, long_message=QSqlQuery.lastError(query).text()) queries = [] record = query.record() while next(query): sql_query = str(query.value(record.indexOf("sql_query"))) sql_query = sql_query.replace("$$DBSCHEMA", self.db_schema) sql_query = sql_query.replace("$$USER", self.db_user) sql_query = sql_query.replace("$$EPSG", self.epsg) queries.append(sql_query) db.close() del db return queries except Exception as e: message = "Something went wrong while catching postprocessing " \ "queries from sqlite database. You need to delete the " \ "database schema manually." raise VerisoError(message, e) def report_progress(self, text, color=None): """ Print the text in the output window :param text: str :return: None """ if color is None: if text.lower().startswith('warning'): color = 'orange' elif text.lower().startswith('error'): color = 'red' elif text.lower().startswith('info'): color = 'blue' if color is not None: self.textEditImportOutput.appendHtml( "<span style='color:%s'>%s</span>" % (color, text)) else: self.textEditImportOutput.appendPlainText("%s\n" % text.rstrip("\n ")) self.textEditImportOutput.ensureCursorVisible()
class GdalToolsBaseDialog(QDialog, Ui_Dialog): refreshArgs = pyqtSignal() okClicked = pyqtSignal() closeClicked = pyqtSignal() helpClicked = pyqtSignal() processError = pyqtSignal(QProcess.ProcessError) processFinished = pyqtSignal(int, QProcess.ExitStatus) finished = pyqtSignal(bool) valuesChanged = pyqtSignal(list) 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.process.error.connect(self.processError) self.process.finished.connect(self.processFinished) self.setupUi(self) self.arguments = [] self.editCmdBtn.setIcon(QIcon(":/icons/edit.png")) self.editCmdBtn.toggled.connect(self.editCommand) self.resetCmdBtn.setIcon(QIcon(":/icons/reset.png")) self.resetCmdBtn.clicked.connect(self.resetCommand) self.editCommand(False) self.buttonBox.rejected.connect(self.reject) self.buttonBox.accepted.connect(self.accept) self.buttonBox.helpRequested.connect(self.help) self.buttonBox.button(QDialogButtonBox.Ok).setDefault(True) self.plugin = pluginBase self.valuesChanged.connect(self.handleRefreshArgs) 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.refreshArgs.emit() def resetCommand(self): if not self.commandIsEditable(): return self.refreshArgs.emit() 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.process.error.disconnect(self.processError) self.process.finished.disconnect(self.processFinished) self.closeClicked.emit() def accept(self): self.okClicked.emit() def help(self): self.helpClicked.emit() # 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 handleRefreshArgs(self, args): self.arguments = [str(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.finished.emit(self.loadCheckBox.isChecked()) self.stop() return # show the error message if there's one, otherwise show the process output message msg = str(self.process.readAllStandardError()) if msg == '': outMessages = str(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.finished.emit(self.loadCheckBox.isChecked()) self.stop()
class ExportProjectDialog(QDialog, FORM_CLASS): projectsDatabaseHasChanged = pyqtSignal() def __init__(self, iface, parent=None): QDialog.__init__(self, parent) self.setupUi(self) self.iface = iface self.message_bar = self.iface.messageBar() self.okButton = self.buttonBox.button(QDialogButtonBox.Ok) self.okButton.setText("Export") self.settings = QSettings("CatAIS", "VeriSO") # members self.modules = None self.app_module = None self.app_module_name = None self.ili = None self.epsg = None self.itf = None self.data_date = None self.notes = None self.db_host = None self.db_name = None self.db_port = None self.db_schema = None self.db_admin = None self.db_admin_pwd = None self.project_index = None self.projects = None self.db_user = None self.db_pwd = None self.btnBrowseOutputFile.clicked.connect( self.btnBrowseOutputFile_clicked) def init_gui(self): projects = get_projects() self.cBoxProject.clear() if not projects: return self.projects = projects sorted_projects = sorted(self.projects, key=lambda k: k['displayname']) for project in sorted_projects: self.cBoxProject.addItem(str(project["displayname"]), project["dbschema"]) self.cBoxProject.insertItem(0, "", None) self.cBoxProject.setCurrentIndex(0) return True # noinspection PyPep8Naming,PyPep8Naming def btnBrowseOutputFile_clicked(self): file_path = QFileDialog.getSaveFileName( self, tr("Choose interlis transfer file"), "", # self.input_itf_path, "ITF (*.itf *.ITF)")[0] file_info = QFileInfo(file_path) self.lineEditOutputFile.setText(file_info.absoluteFilePath()) def accept(self): """Collecting all the stuff we need to know to start the import process. """ # Save the settings. self.settings.value("file/export/output_itf_path", self.lineEditOutputFile.text()) # Gather all data/information for ili2pg arguments. self.itf = self.lineEditOutputFile.text().strip() current_index = self.cBoxProject.currentIndex() if current_index == 0: return db_schema = str(self.cBoxProject.itemData(current_index)) # Get the connections parameters from the projects list we created in # the init_gui method. i = 0 for project in self.projects: if db_schema == str(project["dbschema"]): self.db_host = str(project["dbhost"]) self.db_name = str(project["dbname"]) self.db_port = str(project["dbport"]) self.db_schema = db_schema self.db_admin = str(project["dbadmin"]) self.db_admin_pwd = str(project["dbadminpwd"]) self.app_module = str(project["appmodule"]) self.app_module_name = str(project["appmodulename"]) self.db_user = str(project["dbuser"]) self.db_pwd = str(project["dbpwd"]) self.ili = str(project["ilimodelname"]) self.project_index = i break i += 1 import_vm_arguments = self.settings.value( "options/import/vm_arguments", "") # Check if we have everything we need. if self.itf == "": self.message_bar.pushWarning("VeriSO", tr("No Interlis transfer file " "set.")) return if self.ili == "": self.message_bar.pushWarning("VeriSO", tr("No Interlis model name set.")) return if self.db_schema == "": self.message_bar.pushWarning("VeriSO", tr("No project name set.")) return if self.app_module == "": self.message_bar.pushWarning("VeriSO", tr("No application module " "set.")) return if not self.db_host: self.message_bar.pushWarning("VeriSO", tr("Missing database host " "parameter.")) return if not self.db_name: self.message_bar.pushWarning("VeriSO", tr("Missing database name " "parameter.")) return if not self.db_port: self.message_bar.pushWarning("VeriSO", tr("Missing database port " "parameter.")) return if not self.db_user: self.message_bar.pushWarning("VeriSO", tr("Missing database user " "parameter.")) return if not self.db_pwd: self.message_bar.pushWarning("VeriSO", tr("Missing database password " "parameter.")) return if not self.db_admin: self.message_bar.pushWarning("VeriSO", tr( "Missing database administrator parameter.")) return if not self.db_admin_pwd: self.message_bar.pushWarning("VeriSO", tr( "Missing database administrator password parameter.")) return if jre_version() is None: self.message_bar.pushWarning("VeriSO", tr("No java runtime detected.")) return self.textEditExportOutput.clear() # Set all the arguments for ili2pg. arguments = [] vm_arguments_list = import_vm_arguments.split(" ") for arg in vm_arguments_list: arguments.append(arg) import_jar = os.path.dirname(__file__) + '/../../lib/ili2pg-3.6.1/ili2pg.jar' arguments.append("-Duser.country=CH") arguments.append("-Duser.language=de") arguments.append("-jar") arguments.append(import_jar) arguments.append("--export") arguments.append("--dbhost") arguments.append(self.db_host) arguments.append("--dbport") arguments.append(self.db_port) arguments.append("--dbdatabase") arguments.append(self.db_name) arguments.append("--dbschema") arguments.append(self.db_schema) arguments.append("--dbusr") arguments.append(self.db_admin) arguments.append("--dbpwd") arguments.append(self.db_admin_pwd) arguments.append("--modeldir") model_dir = ';'.join(self.settings.value( "options/model_repositories/repositories")) arguments.append(model_dir) arguments.append("--models") arguments.append(self.ili) arguments.append("--defaultSrsAuth") arguments.append("EPSG") arguments.append(self.itf) self.process = QProcess() self.process.readyReadStandardOutput.connect(self.read_output) self.process.readyReadStandardError.connect(self.read_error) self.process.finished.connect(self.finish_import) QApplication.setOverrideCursor(Qt.WaitCursor) self.buttonBox.setEnabled(False) self.report_progress("Info: Starting ili2pg") self.report_progress("Info: java %s" % ' '.join(arguments)) try: if(sys.platform == 'win32'): j = win_which('java.exe') self.process.start(j, arguments) else: self.process.start("java", arguments) except Exception as e: self.restore_cursor() message = "Could not start export process." self.message_bar.pushMessage("VeriSO", tr(message), Qgis.Critical, duration=0) QgsMessageLog.logMessage(str(e), tag="VeriSO", level=Qgis.Critical) def read_output(self): output = self.process.readAllStandardOutput() self.show_output(output) def read_error(self): error = self.process.readAllStandardError() self.show_output(error) def show_output(self, byte_array): if(sys.platform == 'win32'): unicode_text = byte_array.data().decode('ISO-8859-1') else: unicode_text = byte_array.data().decode('utf-8') self.report_progress(unicode_text) def finish_import(self, exit_code): """ Check if import was successful. :param exitCode: the exit code of the process :return: None """ try: # read the output of ili2pg self.read_import_output() except VerisoError as e: self.message_bar.pushMessage("VeriSO", tr(str(e)), Qgis.Critical, duration=0) return finally: self.restore_cursor() # When we reach here we can claim a successful import. message = "Export process finished." self.report_progress(message, 'green') self.message_bar.pushInfo("VeriSO", tr(message)) def read_import_output(self): """ Reads the output of the ili2pg conversion :return: """ output = self.textEditExportOutput.toPlainText() if output.find("Info: ...export done") < 0 or output.find( "compiler failed") >= 0: message = "Export process not successfully finished." raise VerisoError(message) def report_progress(self, text, color=None): """ Print the text in the output window :param text: str :return: None """ if color is None: if text.lower().startswith('warning'): color = 'orange' elif text.lower().startswith('error'): color = 'red' elif text.lower().startswith('info'): color = 'blue' if color is not None: self.textEditExportOutput.appendHtml( "<span style='color:%s'>%s</span>" % (color, text)) else: self.textEditExportOutput.appendPlainText( "%s\n" % text.rstrip("\n ")) self.textEditExportOutput.ensureCursorVisible() def restore_cursor(self): QApplication.restoreOverrideCursor() self.buttonBox.setEnabled(True)
class GdalToolsBaseDialog(QDialog, Ui_Dialog): refreshArgs = pyqtSignal() okClicked = pyqtSignal() closeClicked = pyqtSignal() helpClicked = pyqtSignal() processError = pyqtSignal(QProcess.ProcessError) processFinished = pyqtSignal(int, QProcess.ExitStatus) finished = pyqtSignal(bool) valuesChanged = pyqtSignal(list) 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.process.error.connect(self.processError) self.process.finished.connect(self.processFinished) self.setupUi(self) self.arguments = [] self.editCmdBtn.setIcon(QIcon(":/icons/edit.png")) self.editCmdBtn.toggled.connect(self.editCommand) self.resetCmdBtn.setIcon(QIcon(":/icons/reset.png")) self.resetCmdBtn.clicked.connect(self.resetCommand) self.editCommand(False) self.buttonBox.rejected.connect(self.reject) self.buttonBox.accepted.connect(self.accept) self.buttonBox.helpRequested.connect(self.help) self.buttonBox.button(QDialogButtonBox.Ok).setDefault(True) self.plugin = pluginBase self.valuesChanged.connect(self.handleRefreshArgs) 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.refreshArgs.emit() def resetCommand(self): if not self.commandIsEditable(): return self.refreshArgs.emit() 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.process.error.disconnect(self.processError) self.process.finished.disconnect(self.processFinished) self.closeClicked.emit() def accept(self): self.okClicked.emit() def help(self): self.helpClicked.emit() # 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 handleRefreshArgs(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.finished.emit(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.finished.emit(self.loadCheckBox.isChecked()) self.stop()
class BatchFileSync(SyncProvider): def __init__(self, name, project, **kwargs): super(BatchFileSync, self).__init__(name, project) self.cmd = kwargs['cmd'] if self.project: self.rootfolder = os.path.abspath(self.project.folder) else: self.rootfolder = kwargs['rootfolder'] self.project = project self.closeproject = kwargs.get("close_project", False) self.process = QProcess() self.parser = kwargs.get("parser", None) self.parsermodule = None variables = kwargs.get("variables", {}) variables["ROAM_PROJECT_ROOT"] = project.folder variables["ROAM_PROJECT_DATA"] = project.datafolder() variables['ROAM_PROJECTS_HOME'] = os.path.abspath( os.path.join(project.folder, "..")) variables['ROAM_MASTER_DATA_FOLDER'] = os.path.abspath( os.path.join(project.folder, "..", "_data")) env = QProcessEnvironment.systemEnvironment() for varname, value in variables.items(): env.insert(varname, str(value)) self.process.setProcessEnvironment(env) self.process.setWorkingDirectory( os.path.dirname(os.path.realpath(self.cmd))) self.process.finished.connect(self.complete) self.process.started.connect(self.syncStarted) self.process.readyReadStandardError.connect(self.error) self.process.readyReadStandardOutput.connect(self.readOutput) self._output = "" self.haserror = False def import_parser_module(self): import imp name = self.parser module = imp.find_module(name, [self.rootfolder]) module = imp.load_module(name, *module) self.parsermodule = module print(self.parsermodule) def start(self): if not self.parsermodule and self.parser: self.import_parser_module() self._output = "" self.haserror = False self.process.start(self.cmd, []) @property def output(self): return self._output @output.setter def output(self, value): self._output = value def error(self): self.haserror = True def complete(self, error, status): if error > 0 or self.haserror: stderr = self.process.readAllStandardError().data() self.syncError.emit(stderr.decode("utf-8")) else: self.syncComplete.emit() self.syncFinished.emit() def readOutput(self): output = self.process.readAll().data().decode("utf-8") ok = True if self.parsermodule: ok, output = self.parsermodule.sync_output(output) if not ok: self.haserror = True self.process.kill() self.syncError.emit(output) else: if output: self.syncMessage.emit(output)