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 QgisModelBakerUtils(QObject): def __init__(self): QObject.__init__(self) self.logger = Logger() from asistente_ladm_col.config.config_db_supported import ConfigDBsSupported self._dbs_supported = ConfigDBsSupported() self.translatable_config_strings = TranslatableConfigStrings() def get_generator(self, db): if 'QgisModelBaker' in qgis.utils.plugins: tool = self._dbs_supported.get_db_factory( db.engine).get_model_baker_db_ili_mode() QgisModelBaker = qgis.utils.plugins["QgisModelBaker"] generator = QgisModelBaker.get_generator()( tool, db.uri, "smart2", db.schema, pg_estimated_metadata=False) return generator else: self.logger.critical( __name__, QCoreApplication.translate( "AsistenteLADMCOLPlugin", "The QGIS Model Baker plugin is a prerequisite, install it before using LADM-COL Assistant." )) return None def get_model_baker_db_connection(self, db): generator = self.get_generator(db) if generator is not None: return generator._db_connector return None def load_layers(self, db, layer_list): """ Load a selected list of layers from qgis model baker. This call should configure relations and bag of enums between layers being loaded, but not when a layer already loaded has a relation or is part of a bag of enum. For that case, we use a cached set of relations and bags of enums that we get only once per session and configure in the Asistente LADM-COL. """ translated_strings = self.translatable_config_strings.get_translatable_config_strings( ) if 'QgisModelBaker' in qgis.utils.plugins: QgisModelBaker = qgis.utils.plugins["QgisModelBaker"] tool = self._dbs_supported.get_db_factory( db.engine).get_model_baker_db_ili_mode() generator = QgisModelBaker.get_generator()( tool, db.uri, "smart2", db.schema, pg_estimated_metadata=False) layers = generator.layers(layer_list) relations, bags_of_enum = generator.relations(layers, layer_list) legend = generator.legend( layers, ignore_node_names=[translated_strings[ERROR_LAYER_GROUP]]) QgisModelBaker.create_project(layers, relations, bags_of_enum, legend, auto_transaction=False) else: self.logger.critical( __name__, QCoreApplication.translate( "AsistenteLADMCOLPlugin", "The QGIS Model Baker plugin is a prerequisite, install it before using LADM-COL Assistant." )) def get_required_layers_without_load(self, layer_list, db): """ Gets a list of layers from a list of layer names using QGIS Model Baker. Layers are register in QgsProject, but not loaded to the canvas! :param layer_list: list of layers names (e.g., ['lc_terreno', 'lc_lindero']) :param db: db connection :return: list of QgsVectorLayers registered in the project """ layers = list() if 'QgisModelBaker' in qgis.utils.plugins: QgisModelBaker = qgis.utils.plugins["QgisModelBaker"] tool = self._dbs_supported.get_db_factory( db.engine).get_model_baker_db_ili_mode() generator = QgisModelBaker.get_generator()( tool, db.uri, "smart2", db.schema, pg_estimated_metadata=False) model_baker_layers = generator.layers(layer_list) for model_baker_layer in model_baker_layers: layer = model_baker_layer.create( ) # Convert Model Baker layer to QGIS layer QgsProject.instance().addMapLayer( layer, False) # Do not load it to canvas layers.append(layer) else: self.logger.critical( __name__, QCoreApplication.translate( "AsistenteLADMCOLPlugin", "The QGIS Model Baker plugin is a prerequisite, install it before using LADM-COL Assistant." )) return layers def get_layers_and_relations_info(self, db): """ Called once per session, this is used to get information of all relations and bags of enums in the DB and cache it in the Asistente LADM-COL. """ if 'QgisModelBaker' in qgis.utils.plugins: generator = self.get_generator(db) layers = generator.get_tables_info_without_ignored_tables() relations = [ relation for relation in generator.get_relations_info() ] self.logger.debug( __name__, "Relationships before filter: {}".format(len(relations))) self.filter_relations(relations) self.logger.debug( __name__, "Relationships after filter: {}".format(len(relations))) return (layers, relations, {}) else: self.logger.critical( __name__, QCoreApplication.translate( "AsistenteLADMCOLPlugin", "The QGIS Model Baker plugin is a prerequisite, install it before using LADM-COL Assistant." )) return (list(), list(), dict()) def filter_relations(self, relations): """ Modifies the input list of relations, removing elements that meet a condition. :param relations: List of a dict of relations. :return: Nothing, changes the input list of relations. """ to_delete = list() for relation in relations: if relation[QueryNames.REFERENCING_FIELD].startswith( 'uej2_') or relation[ QueryNames.REFERENCING_FIELD].startswith('ue_'): to_delete.append(relation) for idx in to_delete: relations.remove(idx) def get_tables_info_without_ignored_tables(self, db): if 'QgisModelBaker' in qgis.utils.plugins: generator = self.get_generator(db) return generator.get_tables_info_without_ignored_tables() else: self.logger.critical( __name__, QCoreApplication.translate( "AsistenteLADMCOLPlugin", "The QGIS Model Baker plugin is a prerequisite, install it before using LADM-COL Assistant." )) def get_first_index_for_layer_type( self, layer_type, group=QgsProject.instance().layerTreeRoot()): if 'QgisModelBaker' in qgis.utils.plugins: import QgisModelBaker return QgisModelBaker.utils.qgis_utils.get_first_index_for_layer_type( layer_type, group) return None @staticmethod def get_suggested_index_for_layer(layer, group): if 'QgisModelBaker' in qgis.utils.plugins: import QgisModelBaker return QgisModelBaker.utils.qgis_utils.get_suggested_index_for_layer( layer, group) return None
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 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 ConnectionManager(QObject): """ Access point to get and set DB Connectors used by the plugin. The plugin uses a DB Connector for Cadastral data collection (barrido) and one for the Supplies cadastral data. Other connections might be needed (e.g., while retrieving databases for the server in the settings dialog, but they are not handled by this class). """ db_connection_changed = pyqtSignal(DBConnector, bool, str) # dbconn, ladm_col_db, db_source def __init__(self): QObject.__init__(self) self.logger = Logger() self.dbs_supported = ConfigDBsSupported() self._db_sources = { # Values are DB Connectors COLLECTED_DB_SOURCE: None, SUPPLIES_DB_SOURCE: None } self.encrypter_decrypter = EncrypterDecrypter() def get_db_connection_from_qsettings(self, db_source=COLLECTED_DB_SOURCE): db_connection_engine = QSettings().value('Asistente-LADM-COL/db/{db_source}/db_connection_engine'.format(db_source=db_source)) if db_connection_engine: db_factory = self.dbs_supported.get_db_factory(db_connection_engine) dict_conn = db_factory.get_parameters_conn(db_source) db = db_factory.get_db_connector(dict_conn) db.open_connection() # Open db connection else: # Use the default connector db_factory = self.dbs_supported.get_db_factory(self.dbs_supported.id_default_db) db = db_factory.get_db_connector() # When the connection parameters are not filled we use empty values return db def update_db_connector_for_source(self, db_source=COLLECTED_DB_SOURCE): db = self.get_db_connection_from_qsettings(db_source) self.set_db_connector_for_source(db, db_source) def get_db_connector_from_source(self, db_source=COLLECTED_DB_SOURCE): if self._db_sources[db_source] is None: # Obtain the connection of the database on demand self.update_db_connector_for_source(db_source) return self._db_sources[db_source] def set_db_connector_for_source(self, db_connector, db_source=COLLECTED_DB_SOURCE): try: if self._db_sources[db_source]: self._db_sources[db_source].close_connection() self._db_sources[db_source] = db_connector except: self.logger.info(__name__, QCoreApplication.translate("ConnectionManager", "An error occurred while trying to close the connection.")) def close_db_connections(self): for _db_source in self._db_sources: if self._db_sources[_db_source]: self._db_sources[_db_source].close_connection() def get_opened_db_connector_for_tests(self, db_engine, conn_dict): """ This function is implemented for tests. Connection to non-LADM databases. """ db_factory = self.dbs_supported.get_db_factory(db_engine) db = db_factory.get_db_connector(conn_dict) db.open_connection() return db def get_encrypted_db_connector(self, db_engine, conn_dict): """ Receives encrypted connection parameters and returns a DB connector from them. :param db_engine: Example: 'pg' or 'gpkg' :param conn_dict: Connection dict with Encrypted values. :return: DB Connector object """ decrypted_conn_dict = {} for k, v in conn_dict.items(): decrypted_conn_dict[k] = self.encrypter_decrypter.decrypt_with_AES(v) db_factory = self.dbs_supported.get_db_factory(db_engine) db = db_factory.get_db_connector(decrypted_conn_dict) return db def save_parameters_conn(self, db, db_source): """ Save db connection parameters from a DB connector to QSettings :param db: DB Connector :param db_source: """ self.dbs_supported.get_db_factory(db.engine).save_parameters_conn(db.dict_conn_params, db_source) self.update_db_connector_for_source(db_source) # Update db connection with new parameters
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)
class QgisModelBakerUtils(QObject): def __init__(self): QObject.__init__(self) self.logger = Logger() from asistente_ladm_col.config.config_db_supported import ConfigDBsSupported self._dbs_supported = ConfigDBsSupported() self.__mb_lib = QgisModelBakerPluginLib() def get_generator(self, db): tool = self._dbs_supported.get_db_factory( db.engine).get_model_baker_db_ili_mode() return self.__mb_lib.get_generator()(tool, db.uri, "smart2", db.schema, pg_estimated_metadata=False) def load_layers(self, db, layer_list, group=None): """ Load a selected list of layers from qgis model baker. This call should configure relations and bag of enums between layers being loaded, but not when a layer already loaded has a relation or is part of a bag of enum. For that case, we use a cached set of relations and bags of enums that we get only once per session and configure in the Asistente LADM-COL. """ generator = self.get_generator(db) layers = generator.layers(layer_list) layers = self._filter_layers(layers) relations, bags_of_enum = generator.relations(layers, layer_list) legend = generator.legend(layers, ignore_node_names=QualityErrorDBUtils. get_quality_error_group_names()) self.__mb_lib.create_project(layers, relations, bags_of_enum, legend, auto_transaction=False, group=group) def get_required_layers_without_load(self, layer_list, db): """ Gets a list of layers from a list of layer names using QGIS Model Baker. Layers are register in QgsProject, but not loaded to the canvas! :param layer_list: list of layers names (e.g., ['lc_terreno', 'lc_lindero']) :param db: db connection :return: list of QgsVectorLayers registered in the project """ layers = list() tool = self._dbs_supported.get_db_factory( db.engine).get_model_baker_db_ili_mode() generator = self.get_generator(db) model_baker_layers = generator.layers(layer_list) model_baker_layers = self._filter_layers(model_baker_layers) for model_baker_layer in model_baker_layers: layer = model_baker_layer.create( ) # Convert Model Baker layer to QGIS layer QgsProject.instance().addMapLayer( layer, False) # Do not load it to canvas layers.append(layer) return layers @staticmethod def _filter_layers(layers): """ Modifies the input list of MB layers, removing elements that meet a condition. :param layers: List of Model Baker Layer objects of list of layer info dicts. :return: Filtered list of layers. """ if layers: if isinstance(layers[0], dict): layers = [ layer for layer in layers if not "_nu_" in layer["tablename"].lower() ] elif isinstance(layers[0], list): layers = [ layer for layer in layers if not "_nu_" in layer.name.lower() ] return layers def get_layers_and_relations_info(self, db): """ Called once per session, this is used to get information of all relations and bags of enums in the DB and cache it in the Asistente LADM-COL. """ generator = self.get_generator(db) layers = generator.get_tables_info_without_ignored_tables() layers = self._filter_layers(layers) relations = [relation for relation in generator.get_relations_info()] QgisModelBakerUtils._filter_relations(relations) return (layers, relations, {}) @staticmethod def _filter_relations(relations): """ Modifies the input list of relations, removing elements that meet a condition. :param relations: List of a dict of relations. :return: Nothing, changes the input list of relations. """ to_delete = list() for relation in relations: if relation[QueryNames.REFERENCING_FIELD].startswith('uej2_') or \ relation[QueryNames.REFERENCING_FIELD].startswith('ue_') or \ '_nu_' in relation[QueryNames.REFERENCING_LAYER].lower() or \ '_nu_' in relation[QueryNames.REFERENCED_LAYER].lower(): to_delete.append(relation) for idx in to_delete: relations.remove(idx) def get_tables_info_without_ignored_tables(self, db): generator = self.get_generator(db) return generator.get_tables_info_without_ignored_tables() @staticmethod def get_suggested_index_for_layer(layer, group): return get_suggested_index_for_layer(layer, group)