class EncrypterDecrypter(): def __init__(self): self._secret_key = 'dnREVzd3Y1NMaA==' # 'c2VjcmV0MTIz' self._salt = 'bGpEVzM2dU8=' # 'c2FsdDEyMw==' self.logger = Logger() self.java_dependency = JavaDependency() self.crypto_dependency = CryptoDependency() def run(self, mode, value): java_home_set = self.java_dependency.set_java_home() if not java_home_set: self.java_dependency.get_java_on_demand() return if not self.crypto_dependency.check_if_dependency_is_valid(): self.crypto_dependency.download_dependency(URL_CRYPTO_LIBRARY) return java_path = self.java_dependency.get_full_java_exe_path() args = ["-jar", CRYPTO_LIBRARY_PATH] args += [mode, self._secret_key, self._salt, value] proc = QProcess() proc.setProcessChannelMode(QProcess.MergedChannels) proc.start(java_path, args) proc.waitForReadyRead() output = bytearray(proc.readAllStandardOutput()) output = output.decode("ascii") return output.strip() def encrypt_with_AES(self, value): return self.run('--encrypt', value) def decrypt_with_AES(self, value): return self.run('--decrypt', value)
class DialogImportData(QDialog, DIALOG_UI): open_dlg_import_schema = pyqtSignal(dict) # dict with key-value params BUTTON_NAME_IMPORT_DATA = QCoreApplication.translate( "DialogImportData", "Import data") BUTTON_NAME_GO_TO_CREATE_STRUCTURE = QCoreApplication.translate( "DialogImportData", "Go to Create Structure...") def __init__(self, iface, conn_manager, context, link_to_import_schema=True, parent=None): QDialog.__init__(self, parent) self.setupUi(self) QgsGui.instance().enableAutoGeometryRestore(self) self.iface = iface self.conn_manager = conn_manager self.db_source = context.get_db_sources()[0] self.link_to_import_schema = link_to_import_schema self.db = self.conn_manager.get_db_connector_from_source( self.db_source) self.base_configuration = BaseConfiguration() self.logger = Logger() self.app = AppInterface() self.__ladmcol_models = LADMColModelRegistry() self.java_dependency = JavaDependency() self.java_dependency.download_dependency_completed.connect( self.download_java_complete) self.java_dependency.download_dependency_progress_changed.connect( self.download_java_progress_change) self.ilicache = IliCache(self.base_configuration) self.ilicache.refresh() self._dbs_supported = ConfigDBsSupported() self._running_tool = False # There may be 1 case where we need to emit a db_connection_changed from the Import Data dialog: # 1) Connection Settings was opened and the DB conn was changed. self._db_was_changed = False # To postpone calling refresh gui until we close this dialog instead of settings # Similarly, we could call a refresh on layers and relations cache in 1 case: # 1) If the ID dialog was called for the COLLECTED source: opening Connection Settings and changing the DB # connection. self._schedule_layers_and_relations_refresh = False # We need bar definition above calling clear_messages self.bar = QgsMessageBar() self.bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed) self.layout().addWidget(self.bar, 0, 0, Qt.AlignTop) self.xtf_file_browse_button.clicked.connect( make_file_selector( self.xtf_file_line_edit, title=QCoreApplication.translate( "DialogImportData", "Open Transfer or Catalog File"), file_filter=QCoreApplication.translate( "DialogImportData", 'Transfer File (*.xtf *.itf);;Catalogue File (*.xml *.xls *.xlsx)' ))) self.validators = Validators() self.xtf_file_line_edit.setPlaceholderText( QCoreApplication.translate("DialogImportData", "[Name of the XTF to be imported]")) fileValidator = FileValidator(pattern=['*.xtf', '*.itf', '*.xml']) self.xtf_file_line_edit.setValidator(fileValidator) self.xtf_file_line_edit.textChanged.connect(self.update_import_models) self.xtf_file_line_edit.textChanged.emit( self.xtf_file_line_edit.text()) # db self.connection_setting_button.clicked.connect(self.show_settings) self.connection_setting_button.setText( QCoreApplication.translate("DialogImportData", "Connection Settings")) # LOG self.log_config.setTitle( QCoreApplication.translate("DialogImportData", "Show log")) self.buttonBox.accepted.disconnect() self.buttonBox.clicked.connect(self.accepted_import_data) self.buttonBox.clear() self.buttonBox.addButton(QDialogButtonBox.Cancel) self._accept_button = self.buttonBox.addButton( self.BUTTON_NAME_IMPORT_DATA, QDialogButtonBox.AcceptRole) self.buttonBox.addButton(QDialogButtonBox.Help) self.buttonBox.helpRequested.connect(self.show_help) self.update_connection_info() self.restore_configuration() def accepted_import_data(self, button): if self.buttonBox.buttonRole(button) == QDialogButtonBox.AcceptRole: if button.text() == self.BUTTON_NAME_IMPORT_DATA: self.accepted() elif button.text() == self.BUTTON_NAME_GO_TO_CREATE_STRUCTURE: self.close() # Close import data dialog self.open_dlg_import_schema.emit({ 'selected_models': self.get_ili_models() }) # Emit signal to open import schema dialog def reject(self): if self._running_tool: QMessageBox.information( self, QCoreApplication.translate("DialogImportData", "Warning"), QCoreApplication.translate( "DialogImportData", "The Import Data tool is still running. Please wait until it finishes." )) else: self.close_dialog() def close_dialog(self): """ We use this method to be safe when emitting the db_connection_changed, otherwise we could trigger slots that unload the plugin, destroying dialogs and thus, leading to crashes. """ if self._schedule_layers_and_relations_refresh: self.conn_manager.db_connection_changed.connect( self.app.core.cache_layers_and_relations) if self._db_was_changed: # If the db was changed, it implies it complies with ladm_col, hence the second parameter self.conn_manager.db_connection_changed.emit( self.db, True, self.db_source) if self._schedule_layers_and_relations_refresh: self.conn_manager.db_connection_changed.disconnect( self.app.core.cache_layers_and_relations) self.logger.info(__name__, "Dialog closed.") self.done(QDialog.Accepted) def update_connection_info(self): db_description = self.db.get_description_conn_string() if db_description: self.db_connect_label.setText(db_description) self.db_connect_label.setToolTip(self.db.get_display_conn_string()) self._accept_button.setEnabled(True) else: self.db_connect_label.setText( QCoreApplication.translate("DialogImportData", "The database is not defined!")) self.db_connect_label.setToolTip('') self._accept_button.setEnabled(False) def update_import_models(self): self.clear_messages() error_msg = None if not self.xtf_file_line_edit.text().strip(): color = '#ffd356' # Light orange self.import_models_qmodel = QStandardItemModel() self.import_models_list_view.setModel(self.import_models_qmodel) else: if os.path.isfile(self.xtf_file_line_edit.text().strip()): color = '#fff' # White self.import_models_qmodel = QStandardItemModel() model_names = get_models_from_xtf( self.xtf_file_line_edit.text().strip()) for model in self.__ladmcol_models.supported_models(): if not model.hidden() and model.full_name() in model_names: item = QStandardItem(model.full_alias()) item.setData(model.full_name(), Qt.UserRole) item.setCheckable(False) item.setEditable(False) self.import_models_qmodel.appendRow(item) if self.import_models_qmodel.rowCount() > 0: self.import_models_list_view.setModel( self.import_models_qmodel) else: error_msg = QCoreApplication.translate( "DialogImportData", "No models were found in the XTF. Is it a valid file?") color = '#ffd356' # Light orange self.import_models_qmodel = QStandardItemModel() self.import_models_list_view.setModel( self.import_models_qmodel) else: error_msg = QCoreApplication.translate( "DialogImportData", "Please set a valid XTF file") color = '#ffd356' # Light orange self.import_models_qmodel = QStandardItemModel() self.import_models_list_view.setModel( self.import_models_qmodel) self.xtf_file_line_edit.setStyleSheet( 'QLineEdit {{ background-color: {} }}'.format(color)) if error_msg: self.txtStdout.setText(error_msg) self.show_message(error_msg, Qgis.Warning) self.import_models_list_view.setFocus() return def get_ili_models(self): ili_models = list() for index in range(self.import_models_qmodel.rowCount()): item = self.import_models_qmodel.item(index) ili_models.append(item.data(Qt.UserRole)) return ili_models def show_settings(self): # We only need those tabs related to Model Baker/ili2db operations dlg = SettingsDialog(self.conn_manager, parent=self) dlg.setWindowTitle( QCoreApplication.translate("DialogImportData", "Target DB Connection Settings")) dlg.show_tip( QCoreApplication.translate( "DialogImportData", "Configure where do you want the XTF data to be imported.")) dlg.set_db_source(self.db_source) dlg.set_tab_pages_list( [SETTINGS_CONNECTION_TAB_INDEX, SETTINGS_MODELS_TAB_INDEX]) # Connect signals (DBUtils, Core) dlg.db_connection_changed.connect(self.db_connection_changed) if self.db_source == COLLECTED_DB_SOURCE: self._schedule_layers_and_relations_refresh = True dlg.set_action_type(EnumDbActionType.IMPORT) if dlg.exec_(): self.db = dlg.get_db_connection() self.update_connection_info() def db_connection_changed(self, db, ladm_col_db, db_source): self._db_was_changed = True self.clear_messages() def accepted(self): self._running_tool = True self.txtStdout.clear() self.progress_bar.setValue(0) self.bar.clearWidgets() if not os.path.isfile(self.xtf_file_line_edit.text().strip()): self._running_tool = False error_msg = QCoreApplication.translate( "DialogImportData", "Please set a valid XTF file before importing data. XTF file does not exist." ) self.txtStdout.setText(error_msg) self.show_message(error_msg, Qgis.Warning) self.xtf_file_line_edit.setFocus() return java_home_set = self.java_dependency.set_java_home() if not java_home_set: message_java = QCoreApplication.translate( "DialogImportData", """Configuring Java {}...""").format(JAVA_REQUIRED_VERSION) self.txtStdout.setTextColor(QColor('#000000')) self.txtStdout.clear() self.txtStdout.setText(message_java) self.java_dependency.get_java_on_demand() self.disable() return configuration = self.update_configuration() if configuration.disable_validation: # If data validation at import is disabled, we ask for confirmation self.msg = QMessageBox() self.msg.setIcon(QMessageBox.Question) self.msg.setText( QCoreApplication.translate( "DialogImportData", "Are you sure you want to import your data without validation?" )) self.msg.setWindowTitle( QCoreApplication.translate("DialogImportData", "Import XTF without validation?")) self.msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No) res = self.msg.exec_() if res == QMessageBox.No: self._running_tool = False return if not self.xtf_file_line_edit.validator().validate( configuration.xtffile, 0)[0] == QValidator.Acceptable: self._running_tool = False error_msg = QCoreApplication.translate( "DialogImportData", "Please set a valid XTF before importing data.") self.txtStdout.setText(error_msg) self.show_message(error_msg, Qgis.Warning) self.xtf_file_line_edit.setFocus() return if not self.get_ili_models(): self._running_tool = False error_msg = QCoreApplication.translate( "DialogImportData", "The selected XTF file does not have information according to the LADM-COL model to import." ) self.txtStdout.setText(error_msg) self.show_message(error_msg, Qgis.Warning) self.import_models_list_view.setFocus() return # Get list of models present in the XTF file, in the DB and in the list of required models (by the plugin) ili_models = set([ili_model for ili_model in self.get_ili_models()]) supported_models_in_ili = set([ m.full_name() for m in self.__ladmcol_models.supported_models() ]).intersection(ili_models) if not supported_models_in_ili: self._running_tool = False error_msg = QCoreApplication.translate("DialogImportData", "The selected XTF file does not have data from any LADM-COL model supported by the LADM-COL Assistant. " \ "Therefore, you cannot import it! These are the models supported:\n\n * {}").format(" \n * ".join([m.full_alias() for m in self.__ladmcol_models.supported_models()])) self.txtStdout.setText(error_msg) self.show_message(error_msg, Qgis.Warning) self.import_models_list_view.setFocus() return db_models = set(self.db.get_models()) suggested_models = sorted(ili_models.difference(db_models)) if not ili_models.issubset(db_models): self._running_tool = False error_msg = QCoreApplication.translate("DialogImportData", "IMPORT ERROR: The XTF file to import does not have the same models as the target database schema. " \ "Please create a schema that also includes the following missing modules:\n\n * {}").format( " \n * ".join(suggested_models)) self.txtStdout.clear() self.txtStdout.setTextColor(QColor('#000000')) self.txtStdout.setText(error_msg) self.show_message(error_msg, Qgis.Warning) self.xtf_file_line_edit.setFocus() # button is removed to define order in GUI for button in self.buttonBox.buttons(): if button.text() == self.BUTTON_NAME_IMPORT_DATA: self.buttonBox.removeButton(button) # Check if button was previously added self.remove_create_structure_button() if self.link_to_import_schema: self.buttonBox.addButton( self.BUTTON_NAME_GO_TO_CREATE_STRUCTURE, QDialogButtonBox.AcceptRole).setStyleSheet( "color: #aa2222;") self.buttonBox.addButton(self.BUTTON_NAME_IMPORT_DATA, QDialogButtonBox.AcceptRole) return with OverrideCursor(Qt.WaitCursor): self.progress_bar.show() self.disable() self.txtStdout.setTextColor(QColor('#000000')) self.txtStdout.clear() dataImporter = iliimporter.Importer(dataImport=True) db_factory = self._dbs_supported.get_db_factory(self.db.engine) dataImporter.tool = db_factory.get_model_baker_db_ili_mode() dataImporter.configuration = configuration self.save_configuration(configuration) dataImporter.stdout.connect(self.print_info) dataImporter.stderr.connect(self.on_stderr) dataImporter.process_started.connect(self.on_process_started) dataImporter.process_finished.connect(self.on_process_finished) self.progress_bar.setValue(25) try: if dataImporter.run() != iliimporter.Importer.SUCCESS: self._running_tool = False self.show_message( QCoreApplication.translate( "DialogImportData", "An error occurred when importing the data. For more information see the log..." ), Qgis.Warning) return except JavaNotFoundError: self._running_tool = False error_msg_java = QCoreApplication.translate( "DialogImportData", "Java {} could not be found. You can configure the JAVA_HOME environment variable manually, restart QGIS and try again." ).format(JAVA_REQUIRED_VERSION) self.txtStdout.setTextColor(QColor('#000000')) self.txtStdout.clear() self.txtStdout.setText(error_msg_java) self.show_message(error_msg_java, Qgis.Warning) return self._running_tool = False self.buttonBox.clear() self.buttonBox.setEnabled(True) self.buttonBox.addButton(QDialogButtonBox.Close) self.progress_bar.setValue(100) self.show_message( QCoreApplication.translate( "DialogImportData", "Import of the data was successfully completed"), Qgis.Success) def download_java_complete(self): self.accepted() def download_java_progress_change(self, progress): self.progress_bar.setValue(progress / 2) if (progress % 20) == 0: self.txtStdout.append('...') def remove_create_structure_button(self): for button in self.buttonBox.buttons(): if button.text() == self.BUTTON_NAME_GO_TO_CREATE_STRUCTURE: self.buttonBox.removeButton(button) def save_configuration(self, configuration): settings = QSettings() settings.setValue( 'Asistente-LADM-COL/QgisModelBaker/ili2pg/xtffile_import', configuration.xtffile) settings.setValue('Asistente-LADM-COL/QgisModelBaker/show_log', not self.log_config.isCollapsed()) def restore_configuration(self): settings = QSettings() self.xtf_file_line_edit.setText( settings.value( 'Asistente-LADM-COL/QgisModelBaker/ili2pg/xtffile_import')) # Show log value_show_log = settings.value( 'Asistente-LADM-COL/QgisModelBaker/show_log', False, type=bool) self.log_config.setCollapsed(not value_show_log) # set model repository # if there is no option by default use online model repository self.use_local_models = settings.value( 'Asistente-LADM-COL/models/custom_model_directories_is_checked', DEFAULT_USE_CUSTOM_MODELS, type=bool) if self.use_local_models: self.custom_model_directories = settings.value( 'Asistente-LADM-COL/models/custom_models', DEFAULT_MODELS_DIR) def update_configuration(self): """ Get the configuration that is updated with the user configuration changes on the dialog. :return: Configuration """ db_factory = self._dbs_supported.get_db_factory(self.db.engine) configuration = ImportDataConfiguration() db_factory.set_ili2db_configuration_params(self.db.dict_conn_params, configuration) configuration.xtffile = self.xtf_file_line_edit.text().strip() configuration.delete_data = False configuration.srs_auth = QSettings().value( 'Asistente-LADM-COL/QgisModelBaker/srs_auth', DEFAULT_SRS_AUTH, str) configuration.srs_code = QSettings().value( 'Asistente-LADM-COL/QgisModelBaker/srs_code', int(DEFAULT_SRS_CODE), int) configuration.inheritance = ILI2DBNames.DEFAULT_INHERITANCE configuration.create_basket_col = ILI2DBNames.CREATE_BASKET_COL configuration.create_import_tid = ILI2DBNames.CREATE_IMPORT_TID configuration.stroke_arcs = ILI2DBNames.STROKE_ARCS configuration.with_importtid = True full_java_exe_path = JavaDependency.get_full_java_exe_path() if full_java_exe_path: self.base_configuration.java_path = full_java_exe_path # User could have changed the default values self.use_local_models = QSettings().value( 'Asistente-LADM-COL/models/custom_model_directories_is_checked', DEFAULT_USE_CUSTOM_MODELS, type=bool) self.custom_model_directories = QSettings().value( 'Asistente-LADM-COL/models/custom_models', DEFAULT_MODELS_DIR) # Check custom model directories if self.use_local_models: if not self.custom_model_directories: self.base_configuration.custom_model_directories_enabled = False else: self.base_configuration.custom_model_directories = self.custom_model_directories self.base_configuration.custom_model_directories_enabled = True configuration.base_configuration = self.base_configuration if self.get_ili_models(): configuration.ilimodels = ';'.join(self.get_ili_models()) configuration.disable_validation = not QSettings().value( 'Asistente-LADM-COL/models/validate_data_importing_exporting', True, bool) return configuration def print_info(self, text, text_color='#000000', clear=False): self.txtStdout.setTextColor(QColor(text_color)) self.txtStdout.append(text) QCoreApplication.processEvents() def on_stderr(self, text): color_log_text(text, self.txtStdout) self.advance_progress_bar_by_text(text) def on_process_started(self, command): self.disable() self.txtStdout.setTextColor(QColor('#000000')) self.txtStdout.clear() self.txtStdout.setText(command) QCoreApplication.processEvents() def on_process_finished(self, exit_code, result): color = '#004905' if exit_code == 0 else '#aa2222' self.txtStdout.setTextColor(QColor(color)) self.txtStdout.append('Finished ({})'.format(exit_code)) if result == iliimporter.Importer.SUCCESS: self.buttonBox.clear() self.buttonBox.setEnabled(True) self.buttonBox.addButton(QDialogButtonBox.Close) else: self.show_message( QCoreApplication.translate("DialogImportData", "Error when importing data"), Qgis.Warning) # Open log if self.log_config.isCollapsed(): self.log_config.setCollapsed(False) def advance_progress_bar_by_text(self, text): if text.strip() == 'Info: compile models...': self.progress_bar.setValue(50) QCoreApplication.processEvents() elif text.strip() == 'Info: create table structure...': self.progress_bar.setValue(55) QCoreApplication.processEvents() elif text.strip() == 'Info: first validation pass...': self.progress_bar.setValue(60) QCoreApplication.processEvents() elif text.strip() == 'Info: second validation pass...': self.progress_bar.setValue(80) QCoreApplication.processEvents() def clear_messages(self): self.bar.clearWidgets( ) # Remove previous messages before showing a new one self.txtStdout.clear() # Clear previous log messages self.progress_bar.setValue(0) # Initialize progress bar def show_help(self): show_plugin_help("import_data") def disable(self): self.source_config.setEnabled(False) self.target_config.setEnabled(False) self.buttonBox.setEnabled(False) def enable(self): self.source_config.setEnabled(True) self.target_config.setEnabled(True) self.buttonBox.setEnabled(True) def show_message(self, message, level): if level == Qgis.Warning: self.enable() self.bar.clearWidgets( ) # Remove previous messages before showing a new one self.bar.pushMessage("Asistente LADM-COL", message, level, duration=0)
class BasketExporter(QObject): total_progress_updated = pyqtSignal(int) # percentage def __init__(self, db, basket_dict, export_dir): QObject.__init__(self) self._db = db self._basket_dict = basket_dict # {t_ili_tids: receiver_name} self._export_dir = export_dir self.logger = Logger() self.log = '' self.java_dependency = JavaDependency() self.java_dependency.download_dependency_completed.connect(self.download_java_complete) self._dbs_supported = ConfigDBsSupported() def export_baskets(self): java_home_set = self.java_dependency.set_java_home() if not java_home_set: message_java = QCoreApplication.translate("BasketExporter", """Configuring Java {}...""").format( JAVA_REQUIRED_VERSION) self.logger.status(message_java) self.java_dependency.get_java_on_demand() return self.base_configuration = BaseConfiguration() self.ilicache = IliCache(self.base_configuration) db_factory = self._dbs_supported.get_db_factory(self._db.engine) self.configuration = ExportConfiguration() db_factory.set_ili2db_configuration_params(self._db.dict_conn_params, self.configuration) self.configuration.with_exporttid = True full_java_exe_path = JavaDependency.get_full_java_exe_path() if full_java_exe_path: self.base_configuration.java_path = full_java_exe_path # Check custom model directories if QSettings().value('Asistente-LADM-COL/models/custom_model_directories_is_checked', DEFAULT_USE_CUSTOM_MODELS, type=bool): custom_model_directories = QSettings().value('Asistente-LADM-COL/models/custom_models', DEFAULT_MODELS_DIR) if not custom_model_directories: self.base_configuration.custom_model_directories_enabled = False else: self.base_configuration.custom_model_directories = custom_model_directories self.base_configuration.custom_model_directories_enabled = True self.ilicache.refresh() # Always call it after setting custom_model_directories self.configuration.base_configuration = self.base_configuration if self.get_ili_models(): self.configuration.ilimodels = ';'.join(self.get_ili_models()) self.exporter = iliexporter.Exporter() self.exporter.tool = db_factory.get_model_baker_db_ili_mode() self.exporter.process_started.connect(self.on_process_started) self.exporter.stderr.connect(self.on_stderr) #self.exporter.process_finished.connect(self.on_process_finished) res = dict() count = 0 total = len(self._basket_dict) with OverrideCursor(Qt.WaitCursor): for basket,name in self._basket_dict.items(): self.log = '' self.configuration.xtffile = os.path.join(self._export_dir, "{}.xtf".format(name)) self.configuration.baskets = basket self.exporter.configuration = self.configuration try: if self.exporter.run() != iliexporter.Exporter.SUCCESS: msg = QCoreApplication.translate("BasketExporter", "An error occurred when exporting the data for '{}' (check the QGIS log panel).").format(name) res[basket] = (False, msg) QgsMessageLog.logMessage(self.log, QCoreApplication.translate("BasketExporter", "Allocate to coordinators"), Qgis.Critical) else: res[basket] = (True, QCoreApplication.translate("BasketExporter", "XTF export for '{}' successful!").format(name) ) except JavaNotFoundError: msg = QCoreApplication.translate("BasketExporter", "Java {} could not be found. You can configure the JAVA_HOME environment variable manually, restart QGIS and try again.").format(JAVA_REQUIRED_VERSION) res[basket] = (False, msg) count += 1 self.total_progress_updated.emit(count/total*100) return res def get_ili_models(self): ili_models = list() model_names = self._db.get_models() if model_names: for model in LADMColModelRegistry().supported_models(): if not model.hidden() and model.full_name() in model_names: ili_models.append(model.full_name()) return ili_models def download_java_complete(self): self.export_baskets() #def on_process_finished(self): # self.run_export() #if self._basket_dict: # basket, = self._basket_dict.popitem() def on_process_started(self, command): self.log += command + '\n' def on_stderr(self, text): self.log += text
class ReportGenerator(QObject): LOG_TAB = 'LADM-COL Reports' enable_action_requested = pyqtSignal(str, bool) def __init__(self, ladm_data): QObject.__init__(self) self.ladm_data = ladm_data self.logger = Logger() self.app = AppInterface() self.java_dependency = JavaDependency() self.java_dependency.download_dependency_completed.connect( self.download_java_complete) self.report_dependency = ReportDependency() self.report_dependency.download_dependency_completed.connect( self.download_report_complete) self.encoding = locale.getlocale()[1] # This might be unset if not self.encoding: self.encoding = 'UTF8' self._downloading = False def stderr_ready(self, proc): text = bytes(proc.readAllStandardError()).decode(self.encoding) self.logger.critical(__name__, text, tab=self.LOG_TAB) def stdout_ready(self, proc): text = bytes(proc.readAllStandardOutput()).decode(self.encoding) self.logger.info(__name__, text, tab=self.LOG_TAB) def update_yaml_config(self, db, config_path): text = '' qgs_uri = QgsDataSourceUri(db.uri) with open(os.path.join(config_path, 'config_template.yaml')) as f: text = f.read() text = text.format('{}', DB_USER=qgs_uri.username(), DB_PASSWORD=qgs_uri.password(), DB_HOST=qgs_uri.host(), DB_PORT=qgs_uri.port(), DB_NAME=qgs_uri.database()) new_file_path = os.path.join( config_path, self.get_tmp_filename('yaml_config', 'yaml')) with open(new_file_path, 'w') as new_yaml: new_yaml.write(text) return new_file_path def get_layer_geojson(self, db, layer_name, plot_id, report_type): if report_type == ANNEX_17_REPORT: if layer_name == 'terreno': return db.get_annex17_plot_data(plot_id, 'only_id') elif layer_name == 'terrenos': return db.get_annex17_plot_data(plot_id, 'all_but_id') elif layer_name == 'terrenos_all': return db.get_annex17_plot_data(plot_id, 'all') elif layer_name == 'construcciones': return db.get_annex17_building_data() else: return db.get_annex17_point_data(plot_id) else: #report_type == ANT_MAP_REPORT: if layer_name == 'terreno': return db.get_ant_map_plot_data(plot_id, 'only_id') elif layer_name == 'terrenos': return db.get_ant_map_plot_data(plot_id, 'all_but_id') elif layer_name == 'terrenos_all': return db.get_annex17_plot_data(plot_id, 'all') elif layer_name == 'construcciones': return db.get_annex17_building_data() elif layer_name == 'puntoLindero': return db.get_annex17_point_data(plot_id) else: #layer_name == 'cambio_colindancia': return db.get_ant_map_neighbouring_change_data(plot_id) def update_json_data(self, db, json_spec_file, plot_id, tmp_dir, report_type): json_data = dict() with open(json_spec_file) as f: json_data = json.load(f) json_data['attributes']['id'] = plot_id json_data['attributes']['datasetName'] = db.schema layers = json_data['attributes']['map']['layers'] for layer in layers: layer['geoJson'] = self.get_layer_geojson(db, layer['name'], plot_id, report_type) overview_layers = json_data['attributes']['overviewMap']['layers'] for layer in overview_layers: layer['geoJson'] = self.get_layer_geojson(db, layer['name'], plot_id, report_type) new_json_file_path = os.path.join( tmp_dir, self.get_tmp_filename('json_data_{}'.format(plot_id), 'json')) with open(new_json_file_path, 'w') as new_json: new_json.write(json.dumps(json_data)) return new_json_file_path def get_tmp_dir(self, create_random=True): if create_random: return tempfile.mkdtemp() return tempfile.gettempdir() def get_tmp_filename(self, basename, extension='gpkg'): return "{}_{}.{}".format(basename, str(time.time()).replace(".", ""), extension) def generate_report(self, db, report_type): # Check if mapfish and Jasper are installed, otherwise show where to # download them from and return if not self.report_dependency.check_if_dependency_is_valid(): self.report_dependency.download_dependency(URL_REPORTS_LIBRARIES) return java_home_set = self.java_dependency.set_java_home() if not java_home_set: self.java_dependency.get_java_on_demand() self.logger.info_msg( __name__, QCoreApplication.translate( "ReportGenerator", "Java is a prerequisite. Since it was not found, it is being configured..." )) return plot_layer = self.app.core.get_layer(db, db.names.LC_PLOT_T, load=True) if not plot_layer: return selected_plots = plot_layer.selectedFeatures() if not selected_plots: self.logger.warning_msg( __name__, QCoreApplication.translate( "ReportGenerator", "To generate reports, first select at least a plot!")) return # Where to store the reports? previous_folder = QSettings().value( "Asistente-LADM-COL/reports/save_into_dir", ".") save_into_folder = QFileDialog.getExistingDirectory( None, QCoreApplication.translate( "ReportGenerator", "Select a folder to save the reports to be generated"), previous_folder) if not save_into_folder: self.logger.warning_msg( __name__, QCoreApplication.translate( "ReportGenerator", "You need to select a folder where to save the reports before continuing." )) return QSettings().setValue("Asistente-LADM-COL/reports/save_into_dir", save_into_folder) config_path = os.path.join(DEPENDENCY_REPORTS_DIR_NAME, report_type) json_spec_file = os.path.join(config_path, 'spec_json_file.json') script_name = '' if os.name == 'posix': script_name = 'print' elif os.name == 'nt': script_name = 'print.bat' script_path = os.path.join(DEPENDENCY_REPORTS_DIR_NAME, 'bin', script_name) if not os.path.isfile(script_path): self.logger.warning( __name__, "Script file for reports wasn't found! {}".format(script_path)) return self.enable_action_requested.emit(report_type, False) # Update config file yaml_config_path = self.update_yaml_config(db, config_path) self.logger.debug( __name__, "Config file for reports: {}".format(yaml_config_path)) total = len(selected_plots) step = 0 count = 0 tmp_dir = self.get_tmp_dir() # Progress bar setup progress = QProgressBar() if total == 1: progress.setRange(0, 0) else: progress.setRange(0, 100) progress.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) self.app.gui.create_progress_message_bar( QCoreApplication.translate("ReportGenerator", "Generating {} report{}...").format( total, '' if total == 1 else 's'), progress) polygons_with_holes = [] multi_polygons = [] for selected_plot in selected_plots: plot_id = selected_plot[db.names.T_ID_F] geometry = selected_plot.geometry() abstract_geometry = geometry.get() if abstract_geometry.ringCount() > 1: polygons_with_holes.append(str(plot_id)) self.logger.warning( __name__, QCoreApplication.translate( "ReportGenerator", "Skipping Annex 17 for plot with {}={} because it has holes. The reporter module does not support such polygons." ).format(db.names.T_ID_F, plot_id)) continue if abstract_geometry.numGeometries() > 1: multi_polygons.append(str(plot_id)) self.logger.warning( __name__, QCoreApplication.translate( "ReportGenerator", "Skipping Annex 17 for plot with {}={} because it is a multi-polygon. The reporter module does not support such polygons." ).format(db.names.T_ID_F, plot_id)) continue # Generate data file json_file = self.update_json_data(db, json_spec_file, plot_id, tmp_dir, report_type) self.logger.debug(__name__, "JSON file for reports: {}".format(json_file)) # Run sh/bat passing config and data files proc = QProcess() proc.readyReadStandardError.connect( functools.partial(self.stderr_ready, proc=proc)) proc.readyReadStandardOutput.connect( functools.partial(self.stdout_ready, proc=proc)) parcel_number = self.ladm_data.get_parcels_related_to_plots( db, [plot_id], db.names.LC_PARCEL_T_PARCEL_NUMBER_F) or [''] file_name = '{}_{}_{}.pdf'.format(report_type, plot_id, parcel_number[0]) current_report_path = os.path.join(save_into_folder, file_name) proc.start(script_path, [ '-config', yaml_config_path, '-spec', json_file, '-output', current_report_path ]) if not proc.waitForStarted(): # Grant execution permissions os.chmod( script_path, stat.S_IXOTH | stat.S_IXGRP | stat.S_IXUSR | stat.S_IRUSR | stat.S_IRGRP) proc.start(script_path, [ '-config', yaml_config_path, '-spec', json_file, '-output', current_report_path ]) if not proc.waitForStarted(): proc = None self.logger.warning( __name__, "Couldn't execute script to generate report...") else: loop = QEventLoop() proc.finished.connect(loop.exit) loop.exec() self.logger.debug(__name__, "{}:{}".format(plot_id, proc.exitCode())) if proc.exitCode() == 0: count += 1 step += 1 progress.setValue(step * 100 / total) os.remove(yaml_config_path) self.enable_action_requested.emit(report_type, True) self.logger.clear_message_bar() if total == count: if total == 1: msg = QCoreApplication.translate( "ReportGenerator", "The report <a href='file:///{}'>{}</a> was successfully generated!" ).format(normalize_local_url(save_into_folder), file_name) else: msg = QCoreApplication.translate( "ReportGenerator", "All reports were successfully generated in folder <a href='file:///{path}'>{path}</a>!" ).format(path=normalize_local_url(save_into_folder)) self.logger.success_msg(__name__, msg) else: details_msg = '' if polygons_with_holes: details_msg += QCoreApplication.translate( "ReportGenerator", " The following polygons were skipped because they have holes and are not supported: {}." ).format(", ".join(polygons_with_holes)) if multi_polygons: details_msg += QCoreApplication.translate( "ReportGenerator", " The following polygons were skipped because they are multi-polygons and are not supported: {}." ).format(", ".join(multi_polygons)) if total == 1: msg = QCoreApplication.translate( "ReportGenerator", "The report for plot {} couldn't be generated!{} See QGIS log (tab '{}') for details." ).format(plot_id, details_msg, self.LOG_TAB) else: if count == 0: msg = QCoreApplication.translate( "ReportGenerator", "No report could be generated!{} See QGIS log (tab '{}') for details." ).format(details_msg, self.LOG_TAB) else: msg = QCoreApplication.translate( "ReportGenerator", "At least one report couldn't be generated!{details_msg} See QGIS log (tab '{log_tab}') for details. Go to <a href='file:///{path}'>{path}</a> to see the reports that were generated." ).format(details_msg=details_msg, path=normalize_local_url(save_into_folder), log_tab=self.LOG_TAB) self.logger.warning_msg(__name__, msg) def download_java_complete(self): if self.java_dependency.fetcher_task and not self.java_dependency.fetcher_task.isCanceled( ): if self.java_dependency.check_if_dependency_is_valid(): self.logger.info_msg( __name__, QCoreApplication.translate( "ReportGenerator", "Java was successfully configured!"), 5) else: self.logger.warning_msg( __name__, QCoreApplication.translate( "ReportGenerator", "You have just canceled the Java dependency download."), 5) def download_report_complete(self): if self.report_dependency.fetcher_task and not self.report_dependency.fetcher_task.isCanceled( ): if self.report_dependency.check_if_dependency_is_valid(): self.logger.info_msg( __name__, QCoreApplication.translate( "ReportGenerator", "Report dependency was successfully configured!"), 5) else: self.logger.warning_msg( __name__, QCoreApplication.translate( "ReportGenerator", "You have just canceled the report dependency download."), 5)
class Ili2DB(QObject): """ Execute ili2db operations via Model Baker API """ stdout = pyqtSignal(str) stderr = pyqtSignal(str) process_started = pyqtSignal(str) process_finished = pyqtSignal(int, int) def __init__(self): QObject.__init__(self) self.logger = Logger() self._java_path = '' self._java_dependency = JavaDependency() self.dbs_supported = ConfigDBsSupported() self._base_configuration = None self._ilicache = None self._log = '' def get_full_java_exe_path(self): if not self._java_path: self._java_path = JavaDependency.get_full_java_exe_path() return self._java_path def configure_java(self): if not self._java_dependency.set_java_home(): message_java = QCoreApplication.translate( "Ili2DB", """Configuring Java {}...""").format(JAVA_REQUIRED_VERSION) self.logger.status(message_java) self._java_dependency.get_java_on_demand(asynchronous=False) res = True msg = 'Success!' java_path = self.get_full_java_exe_path() if not java_path: res = False msg = QCoreApplication.translate( "Ili2DB", "Java {} could not be confiured for you. You can configure the JAVA_HOME environment variable manually, restart QGIS and try again." ).format(JAVA_REQUIRED_VERSION) return res, msg def _get_base_configuration(self): """ :return: BaseConfiguration object. If it's already configured, it returns the existing object, so that it can be shared among chained operations (e.g., export DB1-->schema import DB2-->import DB2). """ if not self._base_configuration: self._base_configuration = BaseConfiguration() self._ilicache = IliCache(self._base_configuration) self._base_configuration.java_path = self.get_full_java_exe_path( ) # It is well configured at this point! # Check custom model directories if QSettings().value( 'Asistente-LADM-COL/models/custom_model_directories_is_checked', DEFAULT_USE_CUSTOM_MODELS, type=bool): custom_model_directories = QSettings().value( 'Asistente-LADM-COL/models/custom_models', DEFAULT_MODELS_DIR) if not custom_model_directories: self._base_configuration.custom_model_directories_enabled = False else: self._base_configuration.custom_model_directories = custom_model_directories self._base_configuration.custom_model_directories_enabled = True # Debug mode self._base_configuration.debugging_enabled = \ QSettings().value('Asistente-LADM-COL/models/debug', DEFAULT_ILI2DB_DEBUG_MODE, type=bool) self._base_configuration.logfile_path = QSettings().value( 'Asistente-LADM-COL/models/log_file_path', '') self._ilicache.refresh( ) # Always call it after setting custom_model_directories return self._base_configuration def _get_ili_models(self, db): ili_models = list() model_names = db.get_models() if model_names: for model in LADMColModelRegistry().supported_models(): if not model.hidden() and model.full_name() in model_names: ili_models.append(model.full_name()) return ili_models def get_import_schema_configuration(self, db, ili_models=list(), create_basket_col=False): db_factory = self.dbs_supported.get_db_factory(db.engine) configuration = SchemaImportConfiguration() db_factory.set_ili2db_configuration_params(db.dict_conn_params, configuration) configuration.inheritance = ILI2DBNames.DEFAULT_INHERITANCE configuration.create_basket_col = create_basket_col configuration.create_import_tid = ILI2DBNames.CREATE_IMPORT_TID configuration.stroke_arcs = ILI2DBNames.STROKE_ARCS configuration.tomlfile = TOML_FILE_DIR configuration.base_configuration = self._get_base_configuration() configuration.ilimodels = ';'.join(ili_models) if db.engine == 'gpkg': # EPSG:9377 support for GPKG (Ugly, I know) We need to send known parameters, we'll fix this in the post_script configuration.srs_auth = 'EPSG' configuration.srs_code = 3116 configuration.post_script = CTM12_GPKG_SCRIPT_PATH elif db.engine == 'pg': configuration.srs_auth = 'EPSG' configuration.srs_code = 9377 configuration.pre_script = CTM12_PG_SCRIPT_PATH return configuration def get_import_data_configuration(self, db, xtf_path, dataset='', baskets=list(), disable_validation=False): db_factory = self.dbs_supported.get_db_factory(db.engine) configuration = ImportDataConfiguration() db_factory.set_ili2db_configuration_params(db.dict_conn_params, configuration) configuration.with_importtid = True configuration.xtffile = xtf_path configuration.disable_validation = disable_validation configuration.dataset = dataset configuration.baskets = baskets # list with basket UUIDs configuration.base_configuration = self._get_base_configuration() ili_models = self._get_ili_models(db) if ili_models: configuration.ilimodels = ';'.join(ili_models) return configuration def get_export_configuration(self, db, xtf_path, dataset='', baskets=list(), disable_validation=False): db_factory = self.dbs_supported.get_db_factory(db.engine) configuration = ExportConfiguration() db_factory.set_ili2db_configuration_params(db.dict_conn_params, configuration) configuration.with_exporttid = True configuration.xtffile = xtf_path configuration.disable_validation = disable_validation configuration.dataset = dataset configuration.baskets = baskets # List with basket UUIDs configuration.base_configuration = self._get_base_configuration() ili_models = self._get_ili_models(db) if ili_models: configuration.ilimodels = ';'.join(ili_models) return configuration def get_update_configuration(self, db_factory, db, xtf_path, dataset_name): configuration = UpdateDataConfiguration() db_factory.set_ili2db_configuration_params(db.dict_conn_params, configuration) configuration.base_configuration = self._get_base_configuration() ili_models = self._get_ili_models(db) if ili_models: configuration.ilimodels = ';'.join(ili_models) configuration.dataset = dataset_name configuration.with_importbid = True configuration.with_importtid = True configuration.xtffile = xtf_path return configuration def get_validate_configuration(self, db_factory, db, model_names, xtflog_path, configfile_path): configuration = ValidateDataConfiguration() db_factory.set_ili2db_configuration_params(db.dict_conn_params, configuration) configuration.base_configuration = self._get_base_configuration() # Since BaseConfiguration can be shared, avoid a --trace in --validate operation (not supported by ili2db) configuration.base_configuration.debugging_enabled = False if model_names: configuration.ilimodels = ';'.join(model_names) if xtflog_path: configuration.xtflogfile = xtflog_path if configfile_path: configuration.configfile = configfile_path return configuration @with_override_cursor def import_schema(self, db, configuration: SchemaImportConfiguration): # Check prerequisite if not self.get_full_java_exe_path(): res_java, msg_java = self.configure_java() if not res_java: return res_java, msg_java # Configure command parameters db_factory = self.dbs_supported.get_db_factory(db.engine) # Configure run importer = iliimporter.Importer() importer.tool = db_factory.get_model_baker_db_ili_mode() importer.configuration = configuration self._connect_ili_executable_signals(importer) # Run! res = True msg = QCoreApplication.translate("Ili2DB", "Schema import ran successfully!") self._log = '' self.logger.status( QCoreApplication.translate( "Ili2Db", "Creating LADM-COL structure into {}...").format( db.engine.upper())) try: if importer.run() != iliimporter.Importer.SUCCESS: msg = QCoreApplication.translate( "Ili2DB", "An error occurred when importing a schema into a DB (check the QGIS log panel)." ) res = False QgsMessageLog.logMessage( self._log, QCoreApplication.translate("Ili2DB", "DB Schema Import"), Qgis.Critical) except JavaNotFoundError: msg = QCoreApplication.translate( "Ili2DB", "Java {} could not be found. You can configure the JAVA_HOME environment variable manually, restart QGIS and try again." ).format(JAVA_REQUIRED_VERSION) res = False self._disconnect_ili_executable_signals(importer) self.logger.clear_status() return res, msg @with_override_cursor def import_data(self, db, configuration: ImportDataConfiguration): # Check prerequisite if not self.get_full_java_exe_path(): res_java, msg_java = self.configure_java() if not res_java: return res_java, msg_java # Configure command parameters db_factory = self.dbs_supported.get_db_factory(db.engine) # Configure run importer = iliimporter.Importer(dataImport=True) importer.tool = db_factory.get_model_baker_db_ili_mode() importer.configuration = configuration self._connect_ili_executable_signals(importer) # Run! res = True msg = QCoreApplication.translate( "Ili2DB", "XTF '{}' imported successfully!").format(configuration.xtffile) self._log = '' self.logger.status( QCoreApplication.translate("Ili2Db", "Importing XTF into {}...").format( db.engine.upper())) try: if importer.run() != iliimporter.Importer.SUCCESS: msg = QCoreApplication.translate( "Ili2DB", "An error occurred when importing from XTF (check the QGIS log panel)." ) res = False QgsMessageLog.logMessage( self._log, QCoreApplication.translate("Ili2DB", "Import from XTF"), Qgis.Critical) except JavaNotFoundError: msg = QCoreApplication.translate( "Ili2DB", "Java {} could not be found. You can configure the JAVA_HOME environment variable manually, restart QGIS and try again." ).format(JAVA_REQUIRED_VERSION) res = False self._disconnect_ili_executable_signals(importer) self.logger.clear_status() return res, msg @with_override_cursor def export(self, db, configuration: ExportConfiguration): # Check prerequisite if not self.get_full_java_exe_path(): res_java, msg_java = self.configure_java() if not res_java: return res_java, msg_java # Configure command parameters db_factory = self.dbs_supported.get_db_factory(db.engine) # Configure run exporter = iliexporter.Exporter() exporter.tool = db_factory.get_model_baker_db_ili_mode() exporter.configuration = configuration self._connect_ili_executable_signals(exporter) # Run! res = True msg = QCoreApplication.translate( "Ili2DB", "XTF '{}' exported successfully!").format(configuration.xtffile) self._log = '' self.logger.status( QCoreApplication.translate("Ili2Db", "Exporting from {} to XTF...").format( db.engine.upper())) try: if exporter.run() != iliexporter.Exporter.SUCCESS: msg = QCoreApplication.translate( "Ili2DB", "An error occurred when exporting data to XTF (check the QGIS log panel)." ) res = False QgsMessageLog.logMessage( self._log, QCoreApplication.translate("Ili2DB", "Export to XTF"), Qgis.Critical) else: self.logger.info(__name__, msg) except JavaNotFoundError: msg = QCoreApplication.translate( "Ili2DB", "Java {} could not be found. You can configure the JAVA_HOME environment variable manually, restart QGIS and try again." ).format(JAVA_REQUIRED_VERSION) res = False self._disconnect_ili_executable_signals(exporter) self.logger.clear_status() return res, msg @with_override_cursor def update(self, db, xtf_path, dataset_name): # Check prerequisite if not self.get_full_java_exe_path(): res_java, msg_java = self.configure_java() if not res_java: return res_java, msg_java # Configure command parameters db_factory = self.dbs_supported.get_db_factory(db.engine) configuration = self.get_update_configuration(db_factory, db, xtf_path, dataset_name) # Configure run updater = iliupdater.Updater() updater.tool = db_factory.get_model_baker_db_ili_mode() updater.configuration = configuration self._connect_ili_executable_signals(updater) # Run! res = True msg = QCoreApplication.translate( "Ili2DB", "DB updated successfully from XTF file '{}'!").format(xtf_path) self._log = '' self.logger.status( QCoreApplication.translate( "Ili2Db", "Updating {} DB from XTF '{}'...").format( db.engine.upper(), xtf_path)) try: if updater.run() != iliupdater.Updater.SUCCESS: msg = QCoreApplication.translate( "Ili2DB", "An error occurred when updating the DB from an XTF (check the QGIS log panel)." ) res = False QgsMessageLog.logMessage( self._log, QCoreApplication.translate("Ili2DB", "Update DB from XTF"), Qgis.Critical) else: self.logger.info(__name__, msg) except JavaNotFoundError: msg = QCoreApplication.translate( "Ili2DB", "Java {} could not be found. You can configure the JAVA_HOME environment variable manually, restart QGIS and try again." ).format(JAVA_REQUIRED_VERSION) res = False self._disconnect_ili_executable_signals(updater) self.logger.clear_status() return res, msg @with_override_cursor def validate(self, db, model_names=list(), xtflog_path='', configfile_path=''): # Check prerequisite if not self.get_full_java_exe_path(): res_java, msg_java = self.configure_java() if not res_java: return res_java, msg_java # Configure command parameters db_factory = self.dbs_supported.get_db_factory(db.engine) configuration = self.get_validate_configuration( db_factory, db, model_names, xtflog_path, configfile_path) # Configure run validator = ili2dbvalidator.Ili2DBValidator() validator.tool = db_factory.get_model_baker_db_ili_mode() validator.process_started.connect(self.on_process_started) validator.stderr.connect(self.on_stderr) validator.configuration = configuration # Run! res = True msg = QCoreApplication.translate( "Ili2DB", "Data successfully validated from DB '{}'!").format( db.get_description_conn_string()) self._log = '' self.logger.status( QCoreApplication.translate( "Ili2Db", "Validating data from '{}' DB...").format( db.get_description_conn_string())) try: res_validation = validator.run() if (res_validation != ili2dbvalidator.Ili2DBValidator.SUCCESS and res_validation != ili2dbvalidator.Ili2DBValidator. SUCCESS_WITH_VALIDATION_ERRORS): msg = QCoreApplication.translate( "Ili2DB", "An error occurred when validating data from a DB (check the QGIS log panel)." ) res = False QgsMessageLog.logMessage( self._log, QCoreApplication.translate("Ili2DB", "Validate data from DB"), Qgis.Critical) else: self.logger.info(__name__, msg) except JavaNotFoundError: msg = QCoreApplication.translate( "Ili2DB", "Java {} could not be found. You can configure the JAVA_HOME environment variable manually, restart QGIS and try again." ).format(JAVA_REQUIRED_VERSION) res = False self.logger.clear_status() return res, msg def on_process_started(self, command): self._log += command + '\n' def on_stderr(self, text): self._log += text def _connect_ili_executable_signals(self, ili_executable: IliExecutable): ili_executable.process_started.connect(self.process_started) ili_executable.stderr.connect(self.stderr) ili_executable.stdout.connect(self.stdout) ili_executable.process_finished.connect(self.process_finished) ili_executable.process_started.connect(self.on_process_started) ili_executable.stderr.connect(self.on_stderr) def _disconnect_ili_executable_signals(self, ili_executable: IliExecutable): ili_executable.process_started.disconnect(self.process_started) ili_executable.stderr.disconnect(self.stderr) ili_executable.stdout.disconnect(self.stdout) ili_executable.process_finished.disconnect(self.process_finished) ili_executable.process_started.disconnect(self.on_process_started) ili_executable.stderr.disconnect(self.on_stderr)
class DialogExportData(QDialog, DIALOG_UI): on_result = pyqtSignal( bool) # whether the tool was run successfully or not ValidExtensions = ['xtf', 'itf', 'gml', 'xml'] current_row_schema = 0 def __init__(self, iface, conn_manager, context, parent=None): QDialog.__init__(self, parent) self.setupUi(self) QgsGui.instance().enableAutoGeometryRestore(self) self.iface = iface self.conn_manager = conn_manager self.db_source = context.get_db_sources()[0] self.db = self.conn_manager.get_db_connector_from_source( self.db_source) self.logger = Logger() self.app = AppInterface() self.java_dependency = JavaDependency() self.java_dependency.download_dependency_completed.connect( self.download_java_complete) self.java_dependency.download_dependency_progress_changed.connect( self.download_java_progress_change) self.base_configuration = BaseConfiguration() self.ilicache = IliCache(self.base_configuration) self.ilicache.refresh() self._dbs_supported = ConfigDBsSupported() self._running_tool = False # There may be 1 case where we need to emit a db_connection_changed from the Export Data dialog: # 1) Connection Settings was opened and the DB conn was changed. self._db_was_changed = False # To postpone calling refresh gui until we close this dialog instead of settings # Similarly, we could call a refresh on layers and relations cache in 1 case: # 1) If the ED dialog was called for the COLLECTED source: opening Connection Settings and changing the DB # connection. self._schedule_layers_and_relations_refresh = False # We need bar definition above calling clear_messages self.bar = QgsMessageBar() self.bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed) self.layout().addWidget(self.bar, 0, 0, Qt.AlignTop) self.xtf_file_browse_button.clicked.connect( make_save_file_selector( self.xtf_file_line_edit, title=QCoreApplication.translate("DialogExportData", "Save in XTF Transfer File"), file_filter=QCoreApplication.translate( "DialogExportData", "XTF Transfer File (*.xtf);;Interlis 1 Transfer File (*.itf);;XML (*.xml);;GML (*.gml)" ), extension='.xtf', extensions=['.' + ext for ext in self.ValidExtensions])) self.xtf_file_browse_button.clicked.connect( self.xtf_browser_opened_to_true) self.xtf_browser_was_opened = False self.validators = Validators() fileValidator = FileValidator( pattern=['*.' + ext for ext in self.ValidExtensions], allow_non_existing=True) self.xtf_file_line_edit.setPlaceholderText( QCoreApplication.translate("DialogExportData", "[Name of the XTF to be created]")) self.xtf_file_line_edit.setValidator(fileValidator) self.xtf_file_line_edit.textChanged.connect( self.validators.validate_line_edits) self.xtf_file_line_edit.textChanged.connect( self.xtf_browser_opened_to_false) self.xtf_file_line_edit.textChanged.emit( self.xtf_file_line_edit.text()) self.connection_setting_button.clicked.connect(self.show_settings) self.connection_setting_button.setText( QCoreApplication.translate("DialogExportData", "Connection Settings")) # LOG self.log_config.setTitle( QCoreApplication.translate("DialogExportData", "Show log")) self.log_config.setFlat(True) self.buttonBox.accepted.disconnect() self.buttonBox.accepted.connect(self.accepted) self.buttonBox.clear() self.buttonBox.addButton(QDialogButtonBox.Cancel) self._accept_button = self.buttonBox.addButton( QCoreApplication.translate("DialogExportData", "Export data"), QDialogButtonBox.AcceptRole) self.buttonBox.addButton(QDialogButtonBox.Help) self.buttonBox.helpRequested.connect(self.show_help) self.update_connection_info() self.update_model_names() self.restore_configuration() def update_connection_info(self): db_description = self.db.get_description_conn_string() if db_description: self.db_connect_label.setText(db_description) self.db_connect_label.setToolTip(self.db.get_display_conn_string()) self._accept_button.setEnabled(True) else: self.db_connect_label.setText( QCoreApplication.translate("DialogExportData", "The database is not defined!")) self.db_connect_label.setToolTip('') self._accept_button.setEnabled(False) def update_model_names(self): self.export_models_qmodel = QStandardItemModel() model_names = self.db.get_models() if model_names: for model in LADMColModelRegistry().supported_models(): if not model.hidden() and model.full_name() in model_names: item = QStandardItem(model.full_alias()) item.setData(model.full_name(), Qt.UserRole) item.setCheckable(False) item.setEditable(False) self.export_models_qmodel.appendRow(item) self.export_models_list_view.setModel(self.export_models_qmodel) def reject(self): if self._running_tool: QMessageBox.information( self, QCoreApplication.translate("DialogExportData", "Warning"), QCoreApplication.translate( "DialogExportData", "The Export Data tool is still running. Please wait until it finishes." )) else: self.close_dialog() def close_dialog(self): """ We use this method to be safe when emitting the db_connection_changed, otherwise we could trigger slots that unload the plugin, destroying dialogs and thus, leading to crashes. """ if self._schedule_layers_and_relations_refresh: self.conn_manager.db_connection_changed.connect( self.app.core.cache_layers_and_relations) if self._db_was_changed: # If the db was changed, it implies it complies with ladm_col, hence the second parameter self.conn_manager.db_connection_changed.emit( self.db, True, self.db_source) if self._schedule_layers_and_relations_refresh: self.conn_manager.db_connection_changed.disconnect( self.app.core.cache_layers_and_relations) self.logger.info(__name__, "Dialog closed.") self.done(QDialog.Accepted) def get_ili_models(self): ili_models = list() for index in range(self.export_models_qmodel.rowCount()): item = self.export_models_qmodel.item(index) ili_models.append(item.data(Qt.UserRole)) return ili_models def show_settings(self): # We only need those tabs related to Model Baker/ili2db operations dlg = SettingsDialog(self.conn_manager, parent=self) dlg.setWindowTitle( QCoreApplication.translate("DialogExportData", "Source DB Connection Settings")) dlg.show_tip( QCoreApplication.translate( "DialogExportData", "Configure which DB you want to export data from.")) dlg.set_db_source(self.db_source) dlg.set_tab_pages_list( [SETTINGS_CONNECTION_TAB_INDEX, SETTINGS_MODELS_TAB_INDEX]) # Connect signals (DBUtils, Core) dlg.db_connection_changed.connect(self.db_connection_changed) if self.db_source == COLLECTED_DB_SOURCE: self._schedule_layers_and_relations_refresh = True dlg.set_action_type(EnumDbActionType.EXPORT) if dlg.exec_(): self.db = dlg.get_db_connection() self.update_model_names() self.update_connection_info() def db_connection_changed(self, db, ladm_col_db, db_source): self._db_was_changed = True self.clear_messages() def accepted(self): self._running_tool = True self.txtStdout.clear() self.progress_bar.setValue(0) self.bar.clearWidgets() java_home_set = self.java_dependency.set_java_home() if not java_home_set: message_java = QCoreApplication.translate( "DialogExportData", """Configuring Java {}...""").format(JAVA_REQUIRED_VERSION) self.txtStdout.setTextColor(QColor('#000000')) self.txtStdout.clear() self.txtStdout.setText(message_java) self.java_dependency.get_java_on_demand() self.disable() return configuration = self.update_configuration() if configuration.disable_validation: # If data validation at export is disabled, we ask for confirmation self.msg = QMessageBox() self.msg.setIcon(QMessageBox.Question) self.msg.setText( QCoreApplication.translate( "DialogExportData", "Are you sure you want to export your data without validation?" )) self.msg.setWindowTitle( QCoreApplication.translate("DialogExportData", "Export XTF without validation?")) self.msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No) res = self.msg.exec_() if res == QMessageBox.No: self._running_tool = False return if not self.xtf_file_line_edit.validator().validate( configuration.xtffile, 0)[0] == QValidator.Acceptable: self._running_tool = False message_error = QCoreApplication.translate( "DialogExportData", "Please set a valid XTF file before exporting data.") self.txtStdout.setText(message_error) self.show_message(message_error, Qgis.Warning) self.xtf_file_line_edit.setFocus() return if not self.get_ili_models(): self._running_tool = False message_error = QCoreApplication.translate( "DialogExportData", "Please set a valid schema to export. This schema does not have information to export." ) self.txtStdout.setText(message_error) self.show_message(message_error, Qgis.Warning) self.export_models_list_view.setFocus() return # If xtf browser was opened and the file exists, the user already chose # to overwrite the file if os.path.isfile(self.xtf_file_line_edit.text().strip() ) and not self.xtf_browser_was_opened: self.msg = QMessageBox() self.msg.setIcon(QMessageBox.Warning) self.msg.setText( QCoreApplication.translate( "DialogExportData", "{filename} already exists.\nDo you want to replace it?"). format(filename=os.path.basename( self.xtf_file_line_edit.text().strip()))) self.msg.setWindowTitle( QCoreApplication.translate("DialogExportData", "Save in XTF Transfer File")) self.msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No) msg_box = self.msg.exec_() if msg_box == QMessageBox.No: self._running_tool = False return with OverrideCursor(Qt.WaitCursor): self.progress_bar.show() self.disable() self.txtStdout.setTextColor(QColor('#000000')) self.txtStdout.clear() exporter = iliexporter.Exporter() db_factory = self._dbs_supported.get_db_factory(self.db.engine) exporter.tool = db_factory.get_model_baker_db_ili_mode() exporter.configuration = configuration self.save_configuration(configuration) exporter.stdout.connect(self.print_info) exporter.stderr.connect(self.on_stderr) exporter.process_started.connect(self.on_process_started) exporter.process_finished.connect(self.on_process_finished) self.progress_bar.setValue(25) try: if exporter.run() != iliexporter.Exporter.SUCCESS: self._running_tool = False self.show_message( QCoreApplication.translate( "DialogExportData", "An error occurred when exporting the data. For more information see the log..." ), Qgis.Warning) self.on_result.emit( False ) # Inform other classes that the execution was not successful return except JavaNotFoundError: self._running_tool = False message_error_java = QCoreApplication.translate( "DialogExportData", "Java {} could not be found. You can configure the JAVA_HOME environment variable manually, restart QGIS and try again." ).format(JAVA_REQUIRED_VERSION) self.txtStdout.setTextColor(QColor('#000000')) self.txtStdout.clear() self.txtStdout.setText(message_error_java) self.show_message(message_error_java, Qgis.Warning) return self._running_tool = False self.buttonBox.clear() self.buttonBox.setEnabled(True) self.buttonBox.addButton(QDialogButtonBox.Close) self.progress_bar.setValue(100) self.show_message( QCoreApplication.translate( "DialogExportData", "Export of the data was successfully completed."), Qgis.Success) self.on_result.emit( True) # Inform other classes that the execution was successful def download_java_complete(self): self.accepted() def download_java_progress_change(self, progress): self.progress_bar.setValue(progress / 2) if (progress % 20) == 0: self.txtStdout.append('...') def save_configuration(self, configuration): settings = QSettings() settings.setValue( 'Asistente-LADM-COL/QgisModelBaker/ili2pg/xtffile_export', configuration.xtffile) settings.setValue('Asistente-LADM-COL/QgisModelBaker/show_log', not self.log_config.isCollapsed()) def restore_configuration(self): settings = QSettings() self.xtf_file_line_edit.setText( settings.value( 'Asistente-LADM-COL/QgisModelBaker/ili2pg/xtffile_export')) # Show log value_show_log = settings.value( 'Asistente-LADM-COL/QgisModelBaker/show_log', False, type=bool) self.log_config.setCollapsed(not value_show_log) # set model repository # if there is no option by default use online model repository custom_model_is_checked = settings.value( 'Asistente-LADM-COL/models/custom_model_directories_is_checked', DEFAULT_USE_CUSTOM_MODELS, type=bool) if custom_model_is_checked: self.custom_model_directories = settings.value( 'Asistente-LADM-COL/models/custom_models', DEFAULT_MODELS_DIR) def update_configuration(self): """ Get the configuration that is updated with the user configuration changes on the dialog. :return: Configuration """ db_factory = self._dbs_supported.get_db_factory(self.db.engine) configuration = ExportConfiguration() db_factory.set_ili2db_configuration_params(self.db.dict_conn_params, configuration) configuration.xtffile = self.xtf_file_line_edit.text().strip() configuration.with_exporttid = True full_java_exe_path = JavaDependency.get_full_java_exe_path() if full_java_exe_path: self.base_configuration.java_path = full_java_exe_path # User could have changed the default values self.use_local_models = QSettings().value( 'Asistente-LADM-COL/models/custom_model_directories_is_checked', DEFAULT_USE_CUSTOM_MODELS, type=bool) self.custom_model_directories = QSettings().value( 'Asistente-LADM-COL/models/custom_models', DEFAULT_MODELS_DIR) # Check custom model directories if self.use_local_models: if not self.custom_model_directories: self.base_configuration.custom_model_directories_enabled = False else: self.base_configuration.custom_model_directories = self.custom_model_directories self.base_configuration.custom_model_directories_enabled = True configuration.base_configuration = self.base_configuration if self.get_ili_models(): configuration.ilimodels = ';'.join(self.get_ili_models()) configuration.disable_validation = not QSettings().value( 'Asistente-LADM-COL/models/validate_data_importing_exporting', True, bool) return configuration def print_info(self, text, text_color='#000000', clear=False): self.txtStdout.setTextColor(QColor(text_color)) self.txtStdout.append(text) QCoreApplication.processEvents() def on_stderr(self, text): color_log_text(text, self.txtStdout) self.advance_progress_bar_by_text(text) def on_process_started(self, command): self.disable() self.txtStdout.setTextColor(QColor('#000000')) self.txtStdout.clear() self.txtStdout.setText(command) QCoreApplication.processEvents() def on_process_finished(self, exit_code, result): color = '#004905' if exit_code == 0 else '#aa2222' self.txtStdout.setTextColor(QColor(color)) self.txtStdout.append( QCoreApplication.translate("DialogExportData", "Finished ({})").format(exit_code)) if result == iliexporter.Exporter.SUCCESS: self.buttonBox.clear() self.buttonBox.setEnabled(True) self.buttonBox.addButton(QDialogButtonBox.Close) else: self.enable() # Open log if self.log_config.isCollapsed(): self.log_config.setCollapsed(False) def advance_progress_bar_by_text(self, text): if text.strip() == 'Info: compile models...': self.progress_bar.setValue(50) QCoreApplication.processEvents() elif text.strip() == 'Info: process data...': self.progress_bar.setValue(55) QCoreApplication.processEvents() elif text.strip() == 'Info: first validation pass...': self.progress_bar.setValue(70) QCoreApplication.processEvents() elif text.strip() == 'Info: second validation pass...': self.progress_bar.setValue(85) QCoreApplication.processEvents() def clear_messages(self): self.bar.clearWidgets( ) # Remove previous messages before showing a new one self.txtStdout.clear() # Clear previous log messages self.progress_bar.setValue(0) # Initialize progress bar def show_help(self): show_plugin_help("export_data") def disable(self): self.source_config.setEnabled(False) self.target_config.setEnabled(False) self.buttonBox.setEnabled(False) def enable(self): self.source_config.setEnabled(True) self.target_config.setEnabled(True) self.buttonBox.setEnabled(True) def show_message(self, message, level): if level == Qgis.Warning: self.enable() self.bar.clearWidgets( ) # Remove previous messages before showing a new one self.bar.pushMessage("Asistente LADM-COL", message, level, duration=0) def xtf_browser_opened_to_true(self): """ Slot. Sets a flag to true to eventually avoid asking a user whether to overwrite a file. """ self.xtf_browser_was_opened = True def xtf_browser_opened_to_false(self): """ Slot. Sets a flag to false to eventually ask a user whether to overwrite a file. """ self.xtf_browser_was_opened = False self.clear_messages()
class DialogImportSchema(QDialog, DIALOG_UI): open_dlg_import_data = pyqtSignal(dict) # dict with key-value params on_result = pyqtSignal( bool) # whether the tool was run successfully or not BUTTON_NAME_CREATE_STRUCTURE = QCoreApplication.translate( "DialogImportSchema", "Create LADM-COL structure") BUTTON_NAME_GO_TO_IMPORT_DATA = QCoreApplication.translate( "DialogImportData", "Go to Import Data...") def __init__(self, iface, conn_manager, context, selected_models=list(), link_to_import_data=True, parent=None): QDialog.__init__(self, parent) self.iface = iface self.conn_manager = conn_manager self.selected_models = selected_models self.link_to_import_data = link_to_import_data self.logger = Logger() self.app = AppInterface() self.__ladmcol_models = LADMColModelRegistry() self.java_dependency = JavaDependency() self.java_dependency.download_dependency_completed.connect( self.download_java_complete) self.java_dependency.download_dependency_progress_changed.connect( self.download_java_progress_change) self.db_source = context.get_db_sources()[0] self.db = self.conn_manager.get_db_connector_from_source( self.db_source) self.base_configuration = BaseConfiguration() self.ilicache = IliCache(self.base_configuration) self._dbs_supported = ConfigDBsSupported() self._running_tool = False # There may be two cases where we need to emit a db_connection_changed from the Schema Import dialog: # 1) Connection Settings was opened and the DB conn was changed. # 2) Connection Settings was never opened but the Schema Import ran successfully, in a way that new models may # convert a db/schema LADM-COL compliant. self._db_was_changed = False # To postpone calling refresh gui until we close this dialog instead of settings # Similarly, we could call a refresh on layers and relations cache in two cases: # 1) If the SI dialog was called for the COLLECTED source: opening Connection Settings and changing the DB # connection. # 2) Not opening the Connection Settings, but running a successful Schema Import on the COLLECTED DB, which # invalidates the cache as models change. self._schedule_layers_and_relations_refresh = False self.setupUi(self) self.validators = Validators() self.update_import_models() self.previous_item = QListWidgetItem() self.connection_setting_button.clicked.connect(self.show_settings) self.connection_setting_button.setText( QCoreApplication.translate("DialogImportSchema", "Connection Settings")) # CRS Setting self.srs_auth = DEFAULT_SRS_AUTH self.srs_code = DEFAULT_SRS_CODE self.crsSelector.crsChanged.connect(self.crs_changed) # LOG self.log_config.setTitle( QCoreApplication.translate("DialogImportSchema", "Show log")) self.buttonBox.accepted.disconnect() self.buttonBox.clicked.connect(self.accepted_import_schema) self.buttonBox.clear() self.buttonBox.addButton(QDialogButtonBox.Cancel) self._accept_button = self.buttonBox.addButton( self.BUTTON_NAME_CREATE_STRUCTURE, QDialogButtonBox.AcceptRole) self.buttonBox.addButton(QDialogButtonBox.Help) self.buttonBox.helpRequested.connect(self.show_help) self.import_models_list_widget.setDisabled(bool( selected_models)) # If we got models from params, disable panel self.update_connection_info() self.restore_configuration() self.bar = QgsMessageBar() self.bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed) self.layout().addWidget(self.bar, 0, 0, Qt.AlignTop) def accepted_import_schema(self, button): if self.buttonBox.buttonRole(button) == QDialogButtonBox.AcceptRole: if button.text() == self.BUTTON_NAME_CREATE_STRUCTURE: self.accepted() elif button.text() == self.BUTTON_NAME_GO_TO_IMPORT_DATA: self.close( ) # Close import schema dialog and open import open dialog self.open_dlg_import_data.emit({"db_source": self.db_source}) def reject(self): if self._running_tool: QMessageBox.information( self, QCoreApplication.translate("DialogImportSchema", "Warning"), QCoreApplication.translate( "DialogImportSchema", "The Import Schema tool is still running. Please wait until it finishes." )) else: self.close_dialog() def close_dialog(self): """ We use this method to be safe when emitting the db_connection_changed, otherwise we could trigger slots that unload the plugin, destroying dialogs and thus, leading to crashes. """ if self._schedule_layers_and_relations_refresh: self.conn_manager.db_connection_changed.connect( self.app.core.cache_layers_and_relations) if self._db_was_changed: self.conn_manager.db_connection_changed.emit( self.db, self.db.test_connection()[0], self.db_source) if self._schedule_layers_and_relations_refresh: self.conn_manager.db_connection_changed.disconnect( self.app.core.cache_layers_and_relations) self.logger.info(__name__, "Dialog closed.") self.done(QDialog.Accepted) def update_connection_info(self): db_description = self.db.get_description_conn_string() if db_description: self.db_connect_label.setText(db_description) self.db_connect_label.setToolTip(self.db.get_display_conn_string()) self._accept_button.setEnabled(True) else: self.db_connect_label.setText( QCoreApplication.translate("DialogImportSchema", "The database is not defined!")) self.db_connect_label.setToolTip('') self._accept_button.setEnabled(False) def update_import_models(self): for model in self.__ladmcol_models.supported_models(): if not model.hidden(): item = QListWidgetItem(model.full_alias()) item.setData(Qt.UserRole, model.full_name()) item.setFlags(item.flags() | Qt.ItemIsUserCheckable) if self.selected_models: # From parameters item.setCheckState(Qt.Checked if model.id() in self.selected_models else Qt.Unchecked) else: # By default item.setCheckState( Qt.Checked if model.checked() else Qt.Unchecked) self.import_models_list_widget.addItem(item) self.import_models_list_widget.itemClicked.connect( self.on_item_clicked_import_model) self.import_models_list_widget.itemChanged.connect( self.on_itemchanged_import_model) def on_item_clicked_import_model(self, item): # disconnect signal to do changes in the items self.import_models_list_widget.itemChanged.disconnect( self.on_itemchanged_import_model) if self.previous_item.text() != item.text(): item.setCheckState(Qt.Unchecked if item.checkState() == Qt.Checked else Qt.Checked) # connect signal to check when the items change self.import_models_list_widget.itemChanged.connect( self.on_itemchanged_import_model) self.previous_item = item def on_itemchanged_import_model(self, item): if self.previous_item.text() != item.text(): item.setSelected(True) self.previous_item = item def get_checked_models(self): checked_models = list() for index in range(self.import_models_list_widget.count()): item = self.import_models_list_widget.item(index) if item.checkState() == Qt.Checked: checked_models.append(item.data(Qt.UserRole)) return checked_models def show_settings(self): # We only need those tabs related to Model Baker/ili2db operations dlg = SettingsDialog(self.conn_manager, parent=self) dlg.setWindowTitle( QCoreApplication.translate("DialogImportSchema", "Target DB Connection Settings")) dlg.show_tip( QCoreApplication.translate( "DialogImportSchema", "Configure where do you want the LADM-COL structure to be created." )) dlg.set_db_source(self.db_source) dlg.set_tab_pages_list( [SETTINGS_CONNECTION_TAB_INDEX, SETTINGS_MODELS_TAB_INDEX]) # Connect signals (DBUtils, Core) dlg.db_connection_changed.connect(self.db_connection_changed) if self.db_source == COLLECTED_DB_SOURCE: self._schedule_layers_and_relations_refresh = True dlg.set_action_type(EnumDbActionType.SCHEMA_IMPORT) if dlg.exec_(): self.db = dlg.get_db_connection() self.update_connection_info() def db_connection_changed(self, db, ladm_col_db, db_source): # We dismiss parameters here, after all, we already have the db, and the ladm_col_db may change from this moment # until we close the import schema dialog self._db_was_changed = True self.clear_messages() # Clean GUI messages if db connection changed def accepted(self): self._running_tool = True self.txtStdout.clear() self.progress_bar.setValue(0) self.bar.clearWidgets() java_home_set = self.java_dependency.set_java_home() if not java_home_set: message_java = QCoreApplication.translate( "DialogImportSchema", """Configuring Java {}...""").format(JAVA_REQUIRED_VERSION) self.txtStdout.setTextColor(QColor('#000000')) self.txtStdout.clear() self.txtStdout.setText(message_java) self.java_dependency.get_java_on_demand() self.disable() return configuration = self.update_configuration() configuration = self.apply_role_model_configuration(configuration) if not self.get_checked_models(): self._running_tool = False message_error = QCoreApplication.translate( "DialogImportSchema", "You should select a valid model(s) before creating the LADM-COL structure." ) self.txtStdout.setText(message_error) self.show_message(message_error, Qgis.Warning) self.import_models_list_widget.setFocus() return self.save_configuration(configuration) with OverrideCursor(Qt.WaitCursor): self.progress_bar.show() self.disable() self.txtStdout.setTextColor(QColor('#000000')) self.txtStdout.clear() importer = iliimporter.Importer() db_factory = self._dbs_supported.get_db_factory(self.db.engine) importer.tool = db_factory.get_model_baker_db_ili_mode() importer.configuration = configuration importer.stdout.connect(self.print_info) importer.stderr.connect(self.on_stderr) importer.process_started.connect(self.on_process_started) importer.process_finished.connect(self.on_process_finished) try: if importer.run() != iliimporter.Importer.SUCCESS: self._running_tool = False self.show_message( QCoreApplication.translate( "DialogImportSchema", "An error occurred when creating the LADM-COL structure. For more information see the log..." ), Qgis.Warning) self.on_result.emit( False ) # Inform other classes that the execution was not successful return except JavaNotFoundError: self._running_tool = False message_error_java = QCoreApplication.translate( "DialogImportSchema", "Java {} could not be found. You can configure the JAVA_HOME environment variable manually, restart QGIS and try again." ).format(JAVA_REQUIRED_VERSION) self.txtStdout.setTextColor(QColor('#000000')) self.txtStdout.clear() self.txtStdout.setText(message_error_java) self.show_message(message_error_java, Qgis.Warning) return self._running_tool = False self.buttonBox.clear() if self.link_to_import_data: self.buttonBox.addButton( self.BUTTON_NAME_GO_TO_IMPORT_DATA, QDialogButtonBox.AcceptRole).setStyleSheet( "color: #007208;") self.buttonBox.setEnabled(True) self.buttonBox.addButton(QDialogButtonBox.Close) self.progress_bar.setValue(100) self.print_info( QCoreApplication.translate("DialogImportSchema", "\nDone!"), '#004905') self.show_message( QCoreApplication.translate( "DialogImportSchema", "LADM-COL structure was successfully created!"), Qgis.Success) self.on_result.emit( True) # Inform other classes that the execution was successful self._db_was_changed = True # Schema could become LADM compliant after a schema import if self.db_source == COLLECTED_DB_SOURCE: self.logger.info( __name__, "Schedule a call to refresh db relations cache since a Schema Import was run on the current 'collected' DB." ) self._schedule_layers_and_relations_refresh = True def download_java_complete(self): self.accepted() def download_java_progress_change(self, progress): self.progress_bar.setValue(progress / 2) if (progress % 20) == 0: self.txtStdout.append('...') def save_configuration(self, configuration): settings = QSettings() settings.setValue('Asistente-LADM-COL/QgisModelBaker/show_log', not self.log_config.isCollapsed()) settings.setValue('Asistente-LADM-COL/QgisModelBaker/srs_auth', self.srs_auth) settings.setValue('Asistente-LADM-COL/QgisModelBaker/srs_code', self.srs_code) def restore_configuration(self): settings = QSettings() # CRS srs_auth = settings.value('Asistente-LADM-COL/QgisModelBaker/srs_auth', DEFAULT_SRS_AUTH, str) srs_code = settings.value('Asistente-LADM-COL/QgisModelBaker/srs_code', int(DEFAULT_SRS_CODE), int) self.crsSelector.setCrs(get_crs_from_auth_and_code(srs_auth, srs_code)) self.crs_changed() # Show log value_show_log = settings.value( 'Asistente-LADM-COL/QgisModelBaker/show_log', False, type=bool) self.log_config.setCollapsed(not value_show_log) # set model repository # if there is no option by default use online model repository self.use_local_models = settings.value( 'Asistente-LADM-COL/models/custom_model_directories_is_checked', DEFAULT_USE_CUSTOM_MODELS, type=bool) if self.use_local_models: self.custom_model_directories = settings.value( 'Asistente-LADM-COL/models/custom_models', DEFAULT_MODELS_DIR) def crs_changed(self): self.srs_auth, self.srs_code = get_crs_authid( self.crsSelector.crs()).split(":") if self.srs_code != DEFAULT_SRS_CODE or self.srs_auth != DEFAULT_SRS_AUTH: self.crs_label.setStyleSheet('color: orange') self.crs_label.setToolTip( QCoreApplication.translate( "DialogImportSchema", "The {} (Colombian National Origin) is recommended,<br>since official models were created for that projection." ).format(DEFAULT_SRS_AUTHID)) else: self.crs_label.setStyleSheet('') self.crs_label.setToolTip( QCoreApplication.translate("DialogImportSchema", "Coordinate Reference System")) def update_configuration(self): db_factory = self._dbs_supported.get_db_factory(self.db.engine) configuration = SchemaImportConfiguration() db_factory.set_ili2db_configuration_params(self.db.dict_conn_params, configuration) # set custom toml file configuration.tomlfile = TOML_FILE_DIR configuration.inheritance = ILI2DBNames.DEFAULT_INHERITANCE configuration.create_basket_col = ILI2DBNames.CREATE_BASKET_COL configuration.create_import_tid = ILI2DBNames.CREATE_IMPORT_TID configuration.stroke_arcs = ILI2DBNames.STROKE_ARCS # CTM12 support configuration.srs_auth = self.srs_auth configuration.srs_code = self.srs_code if self.srs_auth == DEFAULT_SRS_AUTH and self.srs_code == DEFAULT_SRS_CODE: if self.db.engine == 'pg': configuration.pre_script = CTM12_PG_SCRIPT_PATH elif self.db.engine == 'gpkg': # (Ugly, I know) We need to send known parameters, we'll fix this in the post_script configuration.srs_auth = 'EPSG' configuration.srs_code = 3116 configuration.post_script = CTM12_GPKG_SCRIPT_PATH full_java_exe_path = JavaDependency.get_full_java_exe_path() if full_java_exe_path: self.base_configuration.java_path = full_java_exe_path # User could have changed the default values self.use_local_models = QSettings().value( 'Asistente-LADM-COL/models/custom_model_directories_is_checked', DEFAULT_USE_CUSTOM_MODELS, type=bool) self.custom_model_directories = QSettings().value( 'Asistente-LADM-COL/models/custom_models', DEFAULT_MODELS_DIR) # Check custom model directories if self.use_local_models: if not self.custom_model_directories: self.base_configuration.custom_model_directories_enabled = False else: self.base_configuration.custom_model_directories = self.custom_model_directories self.base_configuration.custom_model_directories_enabled = True configuration.base_configuration = self.base_configuration if self.get_checked_models(): configuration.ilimodels = ';'.join(self.get_checked_models()) return configuration def apply_role_model_configuration(self, configuration): """ Applies the configuration that the active role has set over checked models. Important: Note that this works better if the checked models are limited to one (e.g. Field Data Capture) or limited to a group of related models (e.g., the 3 supplies models). When the checked models are heterogeneous, results start to be unpredictable, as the configuration for a single model may affect the others. :param configuration: SchemaImportConfiguration object :return: configuration object updated """ for checked_model in self.get_checked_models(): model = self.__ladmcol_models.model_by_full_name(checked_model) params = model.get_ili2db_params() if ILI2DB_SCHEMAIMPORT in params: for param in params[ILI2DB_SCHEMAIMPORT]: # List of tuples if param[ 0] == ILI2DB_CREATE_BASKET_COL_KEY: # param: (option, value) configuration.create_basket_col = True self.logger.debug( __name__, "Schema Import createBasketCol enabled! (taken from role config)" ) return configuration def print_info(self, text, text_color='#000000', clear=False): self.txtStdout.setTextColor(QColor(text_color)) self.txtStdout.append(text) QCoreApplication.processEvents() def on_stderr(self, text): color_log_text(text, self.txtStdout) self.advance_progress_bar_by_text(text) def on_process_started(self, command): self.txtStdout.setText(command) QCoreApplication.processEvents() def on_process_finished(self, exit_code, result): if exit_code == 0: color = '#004905' message = QCoreApplication.translate( "DialogImportSchema", "Model(s) successfully imported into the database!") else: color = '#aa2222' message = QCoreApplication.translate("DialogImportSchema", "Finished with errors!") # Open log if self.log_config.isCollapsed(): self.log_config.setCollapsed(False) self.txtStdout.setTextColor(QColor(color)) self.txtStdout.append(message) def advance_progress_bar_by_text(self, text): if text.strip() == 'Info: compile models…': self.progress_bar.setValue(20) QCoreApplication.processEvents() elif text.strip() == 'Info: create table structure…': self.progress_bar.setValue(70) QCoreApplication.processEvents() def clear_messages(self): self.bar.clearWidgets( ) # Remove previous messages before showing a new one self.txtStdout.clear() # Clear previous log messages self.progress_bar.setValue(0) # Initialize progress bar def show_help(self): show_plugin_help("import_schema") def disable(self): self.db_config.setEnabled(False) self.ili_config.setEnabled(False) self.buttonBox.setEnabled(False) def enable(self): self.db_config.setEnabled(True) self.ili_config.setEnabled(True) self.buttonBox.setEnabled(True) def show_message(self, message, level): if level == Qgis.Warning: self.enable() self.bar.clearWidgets( ) # Remove previous messages before showing a new one self.bar.pushMessage("Asistente LADM-COL", message, level, duration=0)